diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/002564bb43f116e36f8c4c.jpg b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/002564bb43f116e36f8c4c.jpg deleted file mode 100644 index 5fe56b1..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/002564bb43f116e36f8c4c.jpg and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/1.log b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/1.log deleted file mode 100644 index e69de29..0000000 diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/DownloadTask.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/DownloadTask.h deleted file mode 100644 index 915dc8d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/DownloadTask.h +++ /dev/null @@ -1,249 +0,0 @@ -/************************************************ - * - * file : DownloadTask.h - * author: bobding - * date : 2014-09-25 - * detail: - * -************************************************/ - -#ifndef _DOWNLOADTASK_H_ -#define _DOWNLOADTASK_H_ - -#include "TcpSocket.h" -#include "HttpUtils.h" - -#define MAXBUFFERSIZE 2048 - -//TcpSocket* socket; -/* -void initDownloadTask() -{ - //socket = 0; - initTcpSocket(); - //socket = new TcpSocket(); -} - -void destroyDownloadTask() -{ - if (0 != socket) - { - free(socket); - } - - socket = 0; -} -*/ - -int taskStart(const char* url, char** buffer, unsigned int* length) -{ - /*if (0 == socket) - { - LogError("[DownloadTask::Start] invalid socket, url: %s.\n", url); - return -1; - }*/ - - int ret = socketOpen(); - if (ret < 0) - { - return -1; - } - - struct HttpUrl httpUrl = ParseUrl(url); - - ret = socketConnect(httpUrl.host, httpUrl.port); - if (ret < 0) - { - return -1; - } - - ret = socketSend(httpUrl.request, strlen(httpUrl.request)); - if (ret < 0) - { - return -1; - } - - char dummy[MAXBUFFERSIZE]; - ret = socketRecv(dummy, MAXBUFFERSIZE); // receive 1st package. - if (ret <= 0) - { - LogError("[DownloadTask::Start] recv head 0 bytes, url: %s.\n", url); - return -1; - } - - dummy[ret] = '\0'; - - struct HttpHead httpHead = ParseHead(dummy, strlen(dummy)); - if (HS_FAIL == httpHead.httpState) - { - LogError("[DownloadTask::Start] recv failed, url: %s.\n", url); - return -1; - } - else if (HS_RETRY == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] retry, url: %s.\n", url); - return taskStart(url, buffer, length); - } - else if (HS_REDIR == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] redir, url: %s, location: %s.\n", url, httpHead.location); - return taskStart(httpHead.location, buffer, length); - } - - *length = httpHead.contentLength; - *buffer = (char *)malloc(*length * sizeof(char*)); - //*buffer = new char[*length]; - memset(*buffer, 0, *length); - unsigned int offset = 0; - - if (ret > httpHead.headLength) - { - memcpy((*buffer) + offset, dummy + httpHead.headLength, ret - httpHead.headLength); - offset += ret - httpHead.headLength; - } - - while ((ret = socketRecv(dummy, MAXBUFFERSIZE)) >= 0) - { - LogPrompt("[DownloadTask::Start] received: %d, %d / %d bytes.\n", ret, offset, *length); - - if (offset >= *length) - { - break; - } - - if (0 == ret) - { - continue; - } - - if (offset + ret > *length) - { - ret = *length - offset; - } - - memcpy((*buffer) + offset, dummy, ret); - - offset += ret; - } - return 0; -} - - -/* -class DownloadTask -{ -public: - DownloadTask() - { - socket = 0; - socket = new TcpSocket(); - } - - ~DownloadTask() - { - if (0 != socket) - { - delete socket; - } - - socket = 0; - } - - int Start(const char* url, char** buffer, unsigned int* length) - { - if (0 == socket) - { - LogError("[DownloadTask::Start] invalid socket, url: %s.\n", url); - return -1; - } - - int ret = socket->Open(); - if (ret < 0) - { - return -1; - } - - HttpUrl httpUrl = HttpUtils::ParseUrl(url); - - ret = socket->Connect(httpUrl.host, httpUrl.port); - if (ret < 0) - { - return -1; - } - - ret = socket->Send(httpUrl.request, strlen(httpUrl.request)); - if (ret < 0) - { - return -1; - } - - char dummy[MAXBUFFERSIZE]; - ret = socket->Recv(dummy, MAXBUFFERSIZE); // receive 1st package. - if (ret <= 0) - { - LogError("[DownloadTask::Start] recv head 0 bytes, url: %s.\n", url); - return -1; - } - - dummy[ret] = '\0'; - - HttpHead httpHead = HttpUtils::ParseHead(dummy, strlen(dummy)); - if (HS_FAIL == httpHead.httpState) - { - LogError("[DownloadTask::Start] recv failed, url: %s.\n", url); - return -1; - } - else if (HS_RETRY == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] retry, url: %s.\n", url); - return Start(url, buffer, length); - } - else if (HS_REDIR == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] redir, url: %s, location: %s.\n", url, httpHead.location); - return Start(httpHead.location, buffer, length); - } - - *length = httpHead.contentLength; - *buffer = new char[*length]; - memset(*buffer, 0, *length); - unsigned int offset = 0; - - if (ret > httpHead.headLength) - { - memcpy((*buffer) + offset, dummy + httpHead.headLength, ret - httpHead.headLength); - offset += ret - httpHead.headLength; - } - - while ((ret = socket->Recv(dummy, MAXBUFFERSIZE)) >= 0) - { - LogPrompt("[DownloadTask::Start] received: %d, %d / %d bytes.\n", ret, offset, *length); - - if (offset >= *length) - { - break; - } - - if (0 == ret) - { - continue; - } - - if (offset + ret > *length) - { - ret = *length - offset; - } - - memcpy((*buffer) + offset, dummy, ret); - - offset += ret; - } - - return 0; - } - -private: - TcpSocket* socket; -}; -*/ -#endif // _DOWNLOADTASK_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/HttpUtils.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/HttpUtils.h deleted file mode 100644 index b65d435..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/HttpUtils.h +++ /dev/null @@ -1,249 +0,0 @@ -/************************************************ - * - * file : HttpUtils.h - * author: bobding - * date : 2014-09-25 - * detail: - * -************************************************/ - -#ifndef _HTTPUTILS_H_ -#define _HTTPUTILS_H_ - -#define MAXURLLENGTH 1024 - -struct HttpUrl -{ - char host[MAXURLLENGTH]; // host - char file[MAXURLLENGTH]; // file - unsigned short port; // port - char request[MAXURLLENGTH]; // request -}; - -enum HttpState -{ - HS_FAIL, - HS_SUCC, - HS_RETRY, - HS_REDIR, -}; - -struct HttpHead -{ - unsigned int httpCode; // http code - enum HttpState httpState; // state - unsigned int contentLength; // content length - unsigned int headLength; // head length - char location[MAXURLLENGTH];// redirection -}; - -static struct HttpUrl ParseUrl(const char* url) -{ - struct HttpUrl httpUrl; - memset(&httpUrl, 0, sizeof(struct HttpUrl)); - - unsigned int length = strlen(url); - if (length > MAXURLLENGTH) - { - LogError("[HttpUtils::ParseUrl] url is too long, url: %s.\n", url); - return httpUrl; - } - - memcpy(httpUrl.host, url, strlen(url)); - - const char* s = strchr(httpUrl.host, '/'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - memcpy(httpUrl.file, s, strlen(s)); - } - - s = strchr(httpUrl.host, ':'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - httpUrl.port = (unsigned short)atoi(s); - } - else - { - httpUrl.port = 80; - } - - snprintf(httpUrl.request, MAXURLLENGTH - 1, - "GET /%s HTTP/1.1\r\n" - "Host: %s\r\n\r\n", - httpUrl.file, httpUrl.host); - - LogPrompt("[HttpUtils::ParseUrl] host: %s, file: %s, port: %d.\n", httpUrl.host, httpUrl.file, httpUrl.port); - return httpUrl; -} - -static struct HttpHead ParseHead(const char* buffer, unsigned int length) -{ - struct HttpHead httpHead; - memset(&httpHead, 0, sizeof(struct HttpHead)); - - const char* s = strstr(buffer, "HTTP/1.1 "); - if (0 != s) - { - httpHead.httpCode = (unsigned int)atoi(s + strlen("HTTP/1.1 ")); - } - - if (200 == httpHead.httpCode || 206 == httpHead.httpCode) - { - httpHead.httpState = HS_SUCC; - } - else if (201 == httpHead.httpCode) - { - httpHead.httpState = HS_REDIR; - } - else if (202 == httpHead.httpCode) - { - httpHead.httpState = HS_RETRY; - } - else if (httpHead.httpCode >= 300 && httpHead.httpCode < 400) - { - httpHead.httpState = HS_REDIR; - } - else - { - httpHead.httpState = HS_FAIL; - } - - if (HS_REDIR == httpHead.httpState && 0 != (s = strstr(buffer, "Location: "))) - { - const char* e = strstr(s, "\r\n"); - s += strlen("Location: "); - memcpy(httpHead.location, s, (0 == e) ? strlen(s) : (e - s)); - } - - s = strstr(buffer, "Content-Length: "); - if (0 != s) - { - httpHead.contentLength = (unsigned int)atoi(s + strlen("Content-Length: ")); - } - - s = strstr(buffer, "\r\n\r\n"); - if (0 != s) - { - httpHead.headLength = s + strlen("\r\n\r\n") - buffer; - } - - LogPrompt("[HttpUtils::ParseHead] httpCode: %d, contentLength: %d, headLength: %d.\n", - httpHead.httpCode, httpHead.contentLength, httpHead.headLength); - - return httpHead; -} - - - -/* -class HttpUtils -{ -public: - static HttpUrl ParseUrl(const char* url) - { - HttpUrl httpUrl; - memset(&httpUrl, 0, sizeof(HttpUrl)); - - unsigned int length = strlen(url); - if (length > MAXURLLENGTH) - { - LogError("[HttpUtils::ParseUrl] url is too long, url: %s.\n", url); - return httpUrl; - } - - memcpy(httpUrl.host, url, strlen(url)); - - const char* s = strchr(httpUrl.host, '/'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - memcpy(httpUrl.file, s, strlen(s)); - } - - s = strchr(httpUrl.host, ':'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - httpUrl.port = (unsigned short)atoi(s); - } - else - { - httpUrl.port = 80; - } - - snprintf(httpUrl.request, MAXURLLENGTH - 1, - "GET /%s HTTP/1.1\r\n" - "Host: %s\r\n\r\n", - httpUrl.file, httpUrl.host); - - LogPrompt("[HttpUtils::ParseUrl] host: %s, file: %s, port: %d.\n", httpUrl.host, httpUrl.file, httpUrl.port); - - return httpUrl; - } - - static HttpHead ParseHead(const char* buffer, unsigned int length) - { - HttpHead httpHead; - memset(&httpHead, 0, sizeof(HttpHead)); - - const char* s = strstr(buffer, "HTTP/1.1 "); - if (0 != s) - { - httpHead.httpCode = (unsigned int)atoi(s + strlen("HTTP/1.1 ")); - } - - if (200 == httpHead.httpCode || 206 == httpHead.httpCode) - { - httpHead.httpState = HS_SUCC; - } - else if (201 == httpHead.httpCode) - { - httpHead.httpState = HS_REDIR; - } - else if (202 == httpHead.httpCode) - { - httpHead.httpState = HS_RETRY; - } - else if (httpHead.httpCode >= 300 && httpHead.httpCode < 400) - { - httpHead.httpState = HS_REDIR; - } - else - { - httpHead.httpState = HS_FAIL; - } - - if (HS_REDIR == httpHead.httpState && 0 != (s = strstr(buffer, "Location: "))) - { - const char* e = strstr(s, "\r\n"); - s += strlen("Location: "); - memcpy(httpHead.location, s, (0 == e) ? strlen(s) : (e - s)); - } - - s = strstr(buffer, "Content-Length: "); - if (0 != s) - { - httpHead.contentLength = (unsigned int)atoi(s + strlen("Content-Length: ")); - } - - s = strstr(buffer, "\r\n\r\n"); - if (0 != s) - { - httpHead.headLength = s + strlen("\r\n\r\n") - buffer; - } - - LogPrompt("[HttpUtils::ParseHead] httpCode: %d, contentLength: %d, headLength: %d.\n", - httpHead.httpCode, httpHead.contentLength, httpHead.headLength); - - return httpHead; - } -}; -*/ - -#endif // _HTTPUTILS_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/Log.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/Log.h deleted file mode 100644 index 28be3f8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/Log.h +++ /dev/null @@ -1,322 +0,0 @@ -/************************************************ - * - * file : Log.h - * author: bobding - * date : 2014-09-24 - * detail: - * -************************************************/ - -#ifndef _LOG_H_ -#define _LOG_H_ - -#include -#include -#include -#include -#include -#include - -#define LogCritical Critical -#define LogError Error -#define LogWarn Warn -#define LogPrompt Prompt - -#define LOGPATH "./1.log" - -FILE* handle; -/* -static Log* Instance() -{ - static Log instance; - return &instance; -} -*/ - -const char* FormatedTime() -{ - static char strDate[128]; - memset(strDate, 0, sizeof(strDate)); - - struct timeval tv; - int ret = gettimeofday(&tv, 0); - if (ret < 0) - { - return strDate; - } - - struct tm* pt = localtime(&tv.tv_sec); - snprintf(strDate, 127, "%d-%02d-%02d %02d:%02d:%02d.%03d", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec, (int)(tv.tv_usec / 1000)); - - return strDate; -} - -void initLog() -{ - handle = 0; - if (-1 != access(LOGPATH, F_OK)) - { - remove(LOGPATH); - } - handle = fopen(LOGPATH, "w"); -} - -void destroyLog() -{ - if (0 != handle) - { - fclose(handle); - } - - handle = 0; -} - -// flush every item -int Critical(const char* fmt, ...) -{ - initLog(); - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Critical"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - destroyLog(); - return length; -} - -// flush every item -int Error(const char* fmt, ...) -{ - initLog(); - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Error"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - destroyLog(); - return length; -} - -// flush every 100 items, careless lost -int Warn(const char* fmt, ...) -{ - initLog(); - static unsigned int maxCnt = 100; - static unsigned int curCnt = 0; - - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Warn"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - - if (++curCnt >= maxCnt) - { - fflush(handle); - curCnt = 0; - } - - printf("%s", buffer); - destroyLog(); - return length; -} - -// stdout -int Prompt(const char* fmt, ...) -{ - initLog(); - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Prompt"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - printf("%s", buffer); - destroyLog(); - return length; -} - -/* -class Log -{ -private: - FILE* handle; - -public: - static Log* Instance() - { - static Log instance; - return &instance; - } - -public: - Log() : handle(0) - { - if (-1 != access(LOGPATH, F_OK)) - { - remove(LOGPATH); - } - - handle = fopen(LOGPATH, "w"); - } - - ~Log() - { - if (0 != handle) - { - fclose(handle); - } - - handle = 0; - } - - // flush every item - int Critical(const char* fmt, ...) - { - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Critical"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - - return length; - } - - // flush every item - int Error(const char* fmt, ...) - { - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Error"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - - return length; - } - - // flush every 100 items, careless lost - int Warn(const char* fmt, ...) - { - static unsigned int maxCnt = 100; - static unsigned int curCnt = 0; - - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Warn"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - - if (++curCnt >= maxCnt) - { - fflush(handle); - curCnt = 0; - } - - printf("%s", buffer); - - return length; - } - - // stdout - int Prompt(const char* fmt, ...) - { - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Prompt"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - printf("%s", buffer); - - return length; - } - -protected: - const char* FormatedTime() - { - static char strDate[128]; - memset(strDate, 0, sizeof(strDate)); - - struct timeval tv; - int ret = gettimeofday(&tv, 0); - if (ret < 0) - { - return strDate; - } - - struct tm* pt = localtime(&tv.tv_sec); - snprintf(strDate, 127, "%d-%02d-%02d %02d:%02d:%02d.%03d", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec, (int)(tv.tv_usec / 1000)); - - return strDate; - } -}; -*/ -#endif // _LOG_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/README.md b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/README.md deleted file mode 100644 index 793f61c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/README.md +++ /dev/null @@ -1,11 +0,0 @@ -http-download -============= - -download demo use http get implement by socket programmed in cpp. - -dev env: ubuntu 64 -run env: ubuntu 64 - -todo list: -1. multi-threading supported -2. continue download diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/TcpSocket.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/TcpSocket.h deleted file mode 100644 index fc20b00..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/TcpSocket.h +++ /dev/null @@ -1,246 +0,0 @@ -/************************************************ - * - * file : TcpSocket.h - * author: bobding - * date : 2014-09-25 - * detail: - * -************************************************/ - -#ifndef _TCPSOCKET_H_ -#define _TCPSOCKET_H_ - -#include -#include -#include -#include -#include -#include "Log.h" - -int sockfd; - -void initTcpSocket(){ - sockfd = -1; -} - -// return >=0 means success, otherwise failed. -int socketOpen(){ - sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sockfd < 0) - { - LogError("[Socket::Open] create socket failed: %s.\n", strerror(errno)); - } - return sockfd; -} - -// host: 127.0.0.1 or www.qq.com -// return 0 means success, otherwise failed. -int socketConnect(const char* host, unsigned short port) -{ - if (sockfd < 0) - { - LogError("[Socket::Connect] invalid sockfd.\n"); - return -1; - } - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - struct hostent* h = gethostbyname(host); - if (0 == h) - { - LogError("[Socket::Connect] gethostbyname failed: %s.\n", strerror(errno)); - return -1; - } - - addr.sin_addr = *(struct in_addr*)h->h_addr_list[0]; - - int ret = connect(sockfd, (const struct sockaddr*)&addr, sizeof(addr)); - if (ret < 0) - { - LogError("[Socket::Connect] connect failed: %s.\n", strerror(errno)); - return -1; - } - - return 0; -} - -// return send bytes, -1 means failed. -int socketSend(const char* buffer, unsigned int length) -{ - if (sockfd < 0) - { - LogError("[Socket::Send] invalid sockfd.\n"); - return -1; - } - - int ret = send(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Send] send failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; -} - -// return recv bytes, -1 means failed. -int socketRecv(char* buffer, unsigned int length) -{ - if (sockfd < 0) - { - LogError("[Socket::Recv] invalid sockfd.\n"); - return -1; - } - - int ret = recv(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Recv] recv failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; -} - -// return 0 success, otherwise failed. -int Close() -{ - int ret = close(sockfd); - if (ret < 0) - { - LogError("[Socket::Close] close socket failed: %s.\n", strerror(errno)); - } - - sockfd = -1; - - return ret; -} - -int GetSocket() -{ - return sockfd; -} - -/* -class TcpSocket -{ -public: - TcpSocket() - { - sockfd = -1; - } - - // return >=0 means success, otherwise failed. - int Open() - { - sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sockfd < 0) - { - LogError("[Socket::Open] create socket failed: %s.\n", strerror(errno)); - } - - return sockfd; - } - - // host: 127.0.0.1 or www.qq.com - // return 0 means success, otherwise failed. - int Connect(const char* host, unsigned short port) - { - if (sockfd < 0) - { - LogError("[Socket::Connect] invalid sockfd.\n"); - return -1; - } - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - struct hostent* h = gethostbyname(host); - if (0 == h) - { - LogError("[Socket::Connect] gethostbyname failed: %s.\n", strerror(errno)); - return -1; - } - - addr.sin_addr = *(struct in_addr*)h->h_addr_list[0]; - - int ret = connect(sockfd, (const struct sockaddr*)&addr, sizeof(addr)); - if (ret < 0) - { - LogError("[Socket::Connect] connect failed: %s.\n", strerror(errno)); - return -1; - } - - return 0; - } - - // return send bytes, -1 means failed. - int Send(const char* buffer, unsigned int length) - { - if (sockfd < 0) - { - LogError("[Socket::Send] invalid sockfd.\n"); - return -1; - } - - int ret = send(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Send] send failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; - } - - // return recv bytes, -1 means failed. - int Recv(char* buffer, unsigned int length) - { - if (sockfd < 0) - { - LogError("[Socket::Recv] invalid sockfd.\n"); - return -1; - } - - int ret = recv(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Recv] recv failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; - } - - // return 0 success, otherwise failed. - int Close() - { - int ret = close(sockfd); - if (ret < 0) - { - LogError("[Socket::Close] close socket failed: %s.\n", strerror(errno)); - } - - sockfd = -1; - - return ret; - } - - int GetSocket() - { - return sockfd; - } - -private: - int sockfd; -}; -*/ - -#endif // _TCPSOCKET_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/main b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/main deleted file mode 100755 index 29c9f46..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/main and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/main.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/main.c deleted file mode 100644 index 2c694a4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/main.c +++ /dev/null @@ -1,66 +0,0 @@ -/************************************************ - * - * file : main.cpp - * author: bobding - * date : 2014-09-25 - * detail: - * -************************************************/ - -#include "TcpSocket.h" -#include "DownloadTask.h" - -int main() -{ - /* - TcpSocket* socket = new TcpSocket(); - - int ret = socket->Open(); - - ret = socket->Connect("image.modoomarble.qq.com", 80); - //ret = socket->Connect("14.17.32.211"); - - const char* s = "GET /modoomarble/data610_spr_1.zip HTTP/1.1\r\n" - "Host: image.modoomarble.qq.com\r\n\r\n"; - - ret = socket->Send(s, strlen(s)); - - char buffer[512]; - ret = socket->Recv(buffer, 512); - buffer[ret] = 0; - printf("length: %d\n %s\n", ret, buffer); - - ret = socket->Close(); - - ret = socket->Open(); - - ret = socket->Connect("www.qq.com", 80); - - s = "GET / HTTP/1.1\r\n" - "Host: www.qq.com\r\n\r\n"; - - ret = socket->Send(s, strlen(s)); - - ret = socket->Recv(buffer, 512); - buffer[ret] = 0; - printf("length: %d\n %s\n", ret, buffer); - */ - - char* buffer = 0; - unsigned int length = 0; - - //DownloadTask task; - //int ret = task.Start("image.modoomarble.qq.com/modoomarble/data610_spr_1.zip", &buffer, &length); - int ret = taskStart("images.china.cn/attachement/jpg/site1000/20150611/002564bb43f116e36f8c4c.jpg", &buffer, &length); - - if (ret >= 0) - { - FILE* fp = fopen("002564bb43f116e36f8c4c.jpg", "w"); - fwrite(buffer, length, 1, fp); - fclose(fp); - } - - free(buffer); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/make.sh b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/make.sh deleted file mode 100755 index 98c9be9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/make.sh +++ /dev/null @@ -1 +0,0 @@ -gcc -o main main.c diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/tags b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/tags deleted file mode 100644 index 4c25bb9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/!.http-download/tags +++ /dev/null @@ -1,61 +0,0 @@ -!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ -!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ -!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ -!_TAG_PROGRAM_NAME Exuberant Ctags // -!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ -!_TAG_PROGRAM_VERSION 5.9~svn20110310 // -Close TcpSocket.h /^ int Close()$/;" f class:TcpSocket -Connect TcpSocket.h /^ int Connect(const char* host, unsigned short port)$/;" f class:TcpSocket -Critical Log.h /^ int Critical(const char* fmt, ...)$/;" f class:Log -DownloadTask DownloadTask.h /^ DownloadTask() : socket(0)$/;" f class:DownloadTask -DownloadTask DownloadTask.h /^class DownloadTask$/;" c -Error Log.h /^ int Error(const char* fmt, ...)$/;" f class:Log -FormatedTime Log.h /^ const char* FormatedTime()$/;" f class:Log -GetSocket TcpSocket.h /^ int GetSocket()$/;" f class:TcpSocket -HS_FAIL HttpUtils.h /^ HS_FAIL,$/;" e enum:HttpState -HS_REDIR HttpUtils.h /^ HS_REDIR,$/;" e enum:HttpState -HS_RETRY HttpUtils.h /^ HS_RETRY,$/;" e enum:HttpState -HS_SUCC HttpUtils.h /^ HS_SUCC,$/;" e enum:HttpState -HttpHead HttpUtils.h /^struct HttpHead$/;" s -HttpState HttpUtils.h /^enum HttpState$/;" g -HttpUrl HttpUtils.h /^struct HttpUrl$/;" s -HttpUtils HttpUtils.h /^class HttpUtils$/;" c -Instance Log.h /^ static Log* Instance()$/;" f class:Log -LOGPATH Log.h 25;" d -Log Log.h /^ Log() : handle(0)$/;" f class:Log -Log Log.h /^class Log$/;" c -LogCritical Log.h 20;" d -LogError Log.h 21;" d -LogPrompt Log.h 23;" d -LogWarn Log.h 22;" d -MAXBUFFERSIZE DownloadTask.h 16;" d -MAXURLLENGTH HttpUtils.h 13;" d -Open TcpSocket.h /^ int Open()$/;" f class:TcpSocket -ParseHead HttpUtils.h /^ static HttpHead ParseHead(const char* buffer, unsigned int length)$/;" f class:HttpUtils -ParseUrl HttpUtils.h /^ static HttpUrl ParseUrl(const char* url)$/;" f class:HttpUtils -Prompt Log.h /^ int Prompt(const char* fmt, ...)$/;" f class:Log -Recv TcpSocket.h /^ int Recv(char* buffer, unsigned int length)$/;" f class:TcpSocket -Send TcpSocket.h /^ int Send(const char* buffer, unsigned int length)$/;" f class:TcpSocket -Start DownloadTask.h /^ int Start(const char* url, char** buffer, unsigned int* length)$/;" f class:DownloadTask -TcpSocket TcpSocket.h /^ TcpSocket() : sockfd(-1)$/;" f class:TcpSocket -TcpSocket TcpSocket.h /^class TcpSocket$/;" c -Warn Log.h /^ int Warn(const char* fmt, ...)$/;" f class:Log -_DOWNLOADTASK_H_ DownloadTask.h 11;" d -_HTTPUTILS_H_ HttpUtils.h 11;" d -_LOG_H_ Log.h 11;" d -_TCPSOCKET_H_ TcpSocket.h 11;" d -contentLength HttpUtils.h /^ unsigned int contentLength; \/\/ content length$/;" m struct:HttpHead -file HttpUtils.h /^ char file[MAXURLLENGTH]; \/\/ file$/;" m struct:HttpUrl -handle Log.h /^ FILE* handle;$/;" m class:Log -headLength HttpUtils.h /^ unsigned int headLength; \/\/ head length$/;" m struct:HttpHead -host HttpUtils.h /^ char host[MAXURLLENGTH]; \/\/ host$/;" m struct:HttpUrl -httpCode HttpUtils.h /^ unsigned int httpCode; \/\/ http code$/;" m struct:HttpHead -httpState HttpUtils.h /^ HttpState httpState; \/\/ state$/;" m struct:HttpHead -location HttpUtils.h /^ char location[MAXURLLENGTH];\/\/ redirection$/;" m struct:HttpHead -main main.cpp /^int main()$/;" f -port HttpUtils.h /^ unsigned short port; \/\/ port$/;" m struct:HttpUrl -request HttpUtils.h /^ char request[MAXURLLENGTH]; \/\/ request$/;" m struct:HttpUrl -socket DownloadTask.h /^ TcpSocket* socket;$/;" m class:DownloadTask -sockfd TcpSocket.h /^ int sockfd;$/;" m class:TcpSocket -~DownloadTask DownloadTask.h /^ ~DownloadTask()$/;" f class:DownloadTask -~Log Log.h /^ ~Log()$/;" f class:Log diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/CHANGE b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/CHANGE deleted file mode 100644 index 3857478..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/CHANGE +++ /dev/null @@ -1 +0,0 @@ -[Oct-27-2012] fix a nonexitent address cause segmentation fault (core dumped) \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/Makefile deleted file mode 100644 index 389e047..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# -# "Makefile" -# Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> -# -# This program 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 3 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . - -SUBDIRS = src - -subdirs: - @for n in $(SUBDIRS); do $(MAKE) -C $$n || exit 1; done - -clean: - @for n in $(SUBDIRS); do $(MAKE) -C $$n clean; done - @$(RM) download - -debug: - @for n in $(SUBDIRS); do $(MAKE) -C $$n debug; done \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/README b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/README deleted file mode 100644 index ad83cf8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/README +++ /dev/null @@ -1,11 +0,0 @@ -downloader - -a simple http protocol download app, for learn linux c and socket program. - -make -./downloader [http file address] - -make debug -for debuging. - -Mark Deng <2010.tpk@gmail.com> \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/dofix b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/dofix deleted file mode 100644 index 2dc9108..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/dofix +++ /dev/null @@ -1,7 +0,0 @@ -find bugs: - -3. a nonexitent address whill cause segmentation fault (core dumped) - -2. can't parse path like this "hcd-1.imgbox.com/adbdxjtx.png?st=c86KOgBzkJbADDS5XzB_bQ&e=1351172248" - -1. HTTP/1.1 302 Found can not reset download path. \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/download b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/download deleted file mode 100755 index f7604cc..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/download and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/Makefile deleted file mode 100644 index 0fbf120..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# "Makefile" -# Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> -# -# This program 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 3 of the License, or -# (at your option) any later version. -# -# This program 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 this program. If not, see . - -CC = gcc -CFLAGS = -O2 -Wall -objects = download.o http.o parse.o - -all:download - @mv download .. -debug: CFLAGS += -g -debug: download - @mv download .. -download:$(objects) - $(CC) -o download $(objects) $(CFLAGS) - -.PHONY:clean -clean: - $(RM) *.o diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/dbg.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/dbg.h deleted file mode 100644 index bbb9a20..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/dbg.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - "dbg.h" - Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> - - This program 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 3 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - - -#ifndef __DBG_H -#define __DBG_H - -#include - -#define CHECK_MEM(A) do { if (!(A)) { fprintf (stderr, "memery calloc error!"); goto error;} } while (0) - -#endif /* __DBG_H */ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.c deleted file mode 100644 index d989c1b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - "download.c" - Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> - - This program 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 3 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - - -#include -#include -#include "http.h" -#include "parse.h" -#include "download.h" -#include "dbg.h" - -static struct path * parse_path (char **argv); -static void free_path (struct path *download_path); - -int main(int argc, char *argv[]) -{ - struct path *download_path; - struct ip_list *ips; - if (argc != 2) exit (1); - - download_path = parse_path (argv); - - ips = parse_addr (download_path->hostname); - - download (ips->ipstr, download_path->port, download_path->path, download_path->file_name); - - free_path (download_path); - free_ip_list (ips); - return 0; -} - - -static struct path * parse_path (char **argv) -{ - struct path *download_path = NULL; - volatile int len; - char *path_start = NULL; - char *path_end = NULL; - - len = strlen (argv[1]); - - download_path = (struct path *) malloc (sizeof (struct path)); - if (download_path == NULL) exit (1); - bzero (download_path, sizeof (struct path)); - - download_path->hostname = (char *) calloc ((size_t)len, sizeof (char)); - download_path->path = (char *) calloc ((size_t)len, sizeof (char)); - download_path->file_name = (char *) calloc ((size_t)len, sizeof(char)); - - CHECK_MEM(download_path->hostname); - CHECK_MEM(download_path->path); - CHECK_MEM(download_path->file_name); - - path_start = strchr (argv[1], '/'); - path_end = strrchr (argv[1], '/'); - - if (path_start == NULL || path_end == NULL) - { - strncpy (download_path->hostname, argv[1], strlen (argv[1])); - strncpy (download_path->path, "/", strlen ("/")); - strncpy (download_path->file_name, "index.html", strlen ("index.html")); - return download_path; - } - else - { - memcpy (download_path->hostname, argv[1], len - strlen (path_start)); - memcpy (download_path->path, path_start, strlen (path_start) - strlen (path_end)+1); - memcpy (download_path->file_name, path_end + 1, strlen (path_end)); - return download_path; - } - - -error: - return NULL; -} - -static void free_path (struct path *download_path) -{ - free (download_path->hostname); - free (download_path->path); - free (download_path->file_name); - - download_path->hostname = NULL; - download_path->path = NULL; - download_path->file_name = NULL; - - free (download_path); - download_path = NULL; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.h deleted file mode 100644 index dcff7af..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - "download.h" - Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> - - This program 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 3 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - -#ifndef __DOWNLOAD_H -#define __DOWNLOAD_H - - -struct path { - char *hostname; - char *path; - char *file_name; - int port; -}; - -#endif /* __DOWNLOAD_H */ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.o deleted file mode 100644 index 7bdf0cd..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/download.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.c deleted file mode 100644 index ff892b0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - "http.c" - Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> - - This program 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 3 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "http.h" -#include "dbg.h" - -extern int download (char const *ipstr, int port, char const *path, char const *file_name) -{ - int socketfd; - char http_protol[BUFFER]; - int ret; - float http_ver = 0.0; - int status; - int write_length; - int file_len; - char recvbuf[BUFFER]; /* recieves http server http protol HEAD */ - char buffer[BUFFER]; - FILE *fp = NULL; - void *start = NULL; - struct sockaddr_in download_addr; - - if (port == 0) port = PORT; - - if ((socketfd = socket (AF_INET, SOCK_STREAM, 0)) == -1) - { - printf ("socket error:%d\n", errno); - return -1; - } - - bzero (&download_addr, sizeof (download_addr)); - - download_addr.sin_family = AF_INET; - download_addr.sin_port = htons (port); - /* download_addr.sin_addr.s_addr = inet_addr("10.0.0.21"); */ - inet_pton (AF_INET, ipstr, &download_addr.sin_addr.s_addr); - - if (connect (socketfd, (struct sockaddr *)&download_addr, (socklen_t)sizeof (download_addr)) == -1) - { - printf ("connect error:%d\n", errno); - exit (1); - } - - bzero (http_protol, sizeof (http_protol)); - bzero (recvbuf, sizeof (recvbuf)); - - sprintf (http_protol, "GET %s%s HTTP/1.1\n" \ - "From: 2010.tpk@gmail.com\n" \ - "Host: mark@\n" \ - "User-agent: downloadApp(beta-0.1, i386-pc-linux)\n" \ - "Conection: Keep-Alive\n\n", - path, file_name); - - - ret = write (socketfd, http_protol, strlen (http_protol)); - if (ret == -1) - { - printf ("write failed:%d\n", errno); - exit (1); - } - - ret = read (socketfd, recvbuf, sizeof (recvbuf)); - if (ret == 0) - { - printf ("server closed:%d\n", errno); - exit (1); - } - else if (ret == -1) - { - printf ("read failed:%d\n", errno); - exit (1); - } - - printf ("%s", recvbuf); - sscanf (strstr (recvbuf, "HTTP/"), "HTTP/%f %d", &http_ver, &status); - sscanf (strstr (recvbuf, "Content-Length"), "Content-Length: %d", &file_len); - - if (status != 200 || file_len == 0) - { - printf ("http connect failed!\n"); - exit (1); - } - - - fp = fopen (file_name, "wb"); - if (fp == NULL) - { - printf ("File:%s Can not open:%d\n", file_name, errno); - exit (1); - } - - bzero (buffer, sizeof (buffer)); - - /* download file's address start here whithout http protol HEAD */ - start = (void *) strstr(recvbuf, "\r\n\r\n") + sizeof ("\r\n\r\n")-1; - fwrite (start, sizeof (char), ret - ((void *)start - (void *)&recvbuf), fp); - - while (1) - { - ret = read (socketfd, buffer, sizeof (buffer)); - - if (ret == 0) break; /* download finish */ - - if (ret < 0) - { - printf ("Recieve data from server [%s] failed!\n", ipstr); - break; - } - - write_length = fwrite (buffer, sizeof (char), ret, fp); - if (write_length < ret) - { - printf ("File: %s write failed.\n", file_name); - break; - } - bzero (buffer, sizeof (buffer)); - } - - printf ("\ndownload %s file finish.\n", file_name); - - close (socketfd); - fclose (fp); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.h deleted file mode 100644 index 078d418..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - "http.h" - Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> - - This program 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 3 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - - -#ifndef __HTTP_H -#define __HTTP_H - -#define PORT 80 -#define BUFFER 1024 -#define NAME_LEN 255 - -extern int download (char const *ipstr, int port, char const *path, char const *file_name); - -#endif /* __HTTP_H */ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.o deleted file mode 100644 index 06b0296..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/http.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.c deleted file mode 100644 index ecf99b8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - "parse.c" - Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> - - This program 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 3 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "parse.h" -#include "dbg.h" - -static void add2list (struct ip_list * const ips,char const *ipstr); - -extern struct ip_list *parse_addr (char const *hostname) -{ - - struct addrinfo *answer, hint, *curr; - char ipstr[16] = {'\0'}; - volatile int ret; - - struct ip_list *ips = NULL; - ips = (struct ip_list *) calloc (1, sizeof (struct ip_list)); - CHECK_MEM (ips); - - bzero (&hint, sizeof (hint)); - hint.ai_family = AF_INET; - hint.ai_socktype = SOCK_STREAM; - - if ((ret = getaddrinfo (hostname, NULL, &hint, &answer)) != 0) { - fprintf (stderr, "getaddrinfo: %s\n",gai_strerror (ret)); - exit (EXIT_FAILURE); - } - - for (curr = answer; curr != NULL; curr = curr->ai_next) { - - inet_ntop (AF_INET, - &(((struct sockaddr_in *)(curr->ai_addr))->sin_addr), - ipstr, sizeof (ipstr)); - add2list (ips, ipstr); - } - - freeaddrinfo (answer); - return ips; - -error: - return NULL; -} - -extern void free_ip_list (struct ip_list *ips) -{ - struct ip_list *temp = NULL; - struct ip_list *delete_temp = NULL; - delete_temp = ips; - - while (1) - { - temp = delete_temp->next; - free (delete_temp); - delete_temp = NULL; - delete_temp = temp; - if (delete_temp == NULL) break; - } - ips = NULL; -} - -static void add2list (struct ip_list * const ips,char const *ipstr) -{ - struct ip_list *ip = NULL; - struct ip_list *temp = NULL; - - CHECK_MEM(ips); - - if (ips->next == NULL && (strlen(ips->ipstr) == 0)) - { - strncpy (ips->ipstr, ipstr, 16); - return; - } - - ip = (struct ip_list *) calloc (1, sizeof (struct ip_list)); - CHECK_MEM (ip); - - temp = ips; - while (temp->next) - { - temp = temp->next; - } - temp->next = ip; - strncpy (ip->ipstr, ipstr, 16); - -error: - return; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.h deleted file mode 100644 index 112beca..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - "parse.h" - Copyright (C) <2012> <"Mark Deng" 2010.tpk@gmail.com> - - This program 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 3 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - - -#ifndef __PARSE_H -#define __PARSE_H - -struct ip_list { - char ipstr[16]; - struct ip_list *next; -}; - -extern struct ip_list *parse_addr (char const *hostname); -extern void free_ip_list (struct ip_list *ips); - -#endif /* __PARSE_H */ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.o deleted file mode 100644 index 9ce1a09..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_1.c_http_download_prototype/downloader/src/parse.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/.README.swp b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/.README.swp deleted file mode 100644 index cefbb1c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/.README.swp and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/Makefile deleted file mode 100644 index 8de0441..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -PROJ_DIR = . -INCLUDE_DIR = $(PROJ_DIR)/include -SRC_DIR = $(PROJ_DIR)/src -OBJ_DIR = $(PROJ_DIR)/obj - -LIBFLAGS = -pthread - -INCLUDE = -I $(INCLUDE_DIR) -CFLAGS = -fno-builtin -ggdb -c -Wall $(LIBFLAGS) $(INCLUDE) -CC = /usr/bin/gcc -BIN = http_cache - - -SRC = $(SRC_DIR)/http_cache.c \ - $(SRC_DIR)/listener.c \ - $(SRC_DIR)/tokenize.c \ - $(SRC_DIR)/file_parser.c \ - $(SRC_DIR)/http_config.c \ - $(SRC_DIR)/wcache.c - -#OBJ = ${SRC:%.c=%.o} -OBJ = $(OBJ_DIR)/http_cache.o \ - $(OBJ_DIR)/listener.o \ - $(OBJ_DIR)/tokenize.o \ - $(OBJ_DIR)/file_parser.o \ - $(OBJ_DIR)/http_config.o \ - $(OBJ_DIR)/wcache.o -#---make targets -all: $(BIN) -#%.o: %.c -# $(CC) $(CFLAGS) -c $< -o $(OBJ_DIR)/$@ - -$(OBJ_DIR)/http_cache.o: $(SRC_DIR)/http_cache.c - $(CC) -c $(CFLAGS) $< -o $@ - -$(OBJ_DIR)/http_config.o: $(SRC_DIR)/http_config.c - $(CC) -c $(CFLAGS) $< -o $@ -$(OBJ_DIR)/listener.o: $(SRC_DIR)/listener.c - $(CC) -c $(CFLAGS) $< -o $@ -$(OBJ_DIR)/tokenize.o: $(SRC_DIR)/tokenize.c - $(CC) -c $(CFLAGS) $< -o $@ -$(OBJ_DIR)/file_parser.o: $(SRC_DIR)/file_parser.c - $(CC) -c $(CFLAGS) $< -o $@ -$(OBJ_DIR)/wcache.o: $(SRC_DIR)/wcache.c - $(CC) -c $(CFLAGS) $< -o $@ - -http_cache: $(OBJ) - $(CC) $(LIBFLAGS) -o $(OBJ_DIR)/$(BIN) $(OBJ) - -.PHONY : clean -clean: - rm -f $(OBJ_DIR)/*.o - rm -f $(OBJ_DIR)/http_cache diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/README b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/README deleted file mode 100644 index 8140d95..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/README +++ /dev/null @@ -1,69 +0,0 @@ -*****Simple HTTP Web Proxy cache***** -************************************* -Author: Gaurav Tungatkar - -Description: -A HTTP proxy. Point your browser to the proxy. It fetches the pages from the -actual server and caches them. It follows the HTTP RFC regarding keeping the -cache updated. -If the http response contains if-modified-since field, a conditional get is sent -to determine the liveness of the cached object. If it does not contain -if-modified-since, simple fiexd timeout strategy is used. - -Handy doubly linked list utility created, reusable in other projects. - -Code organization and directory structure: - -Project3 - |__ src - All .c source files in this directory - |__ include - All header files in this directory - |_Makefile, config.txt - These files at the same level - -tokenize.c -utility function to separate a line into tokens -fileparser.c -utility function to parse a file line by line -http_config.c -Handles reading of config file, error checking and populating - in-memory config object. -http_cache.c -Main http web cache engine, acts as client as well as server -listener.c -Connection handler routine - -Instructions to compile: -1. Go to base project folder Project3. -2. make - -Instructions to run: -1. From Project3 folder -./obj/http_server [config_file] - -Config file path is optional. It may be specified at the command line. -If not provided, following assumptions hold:- - a. config.txt located in Project1 directory is the default config file - b. The config.txt file must be located in the cwd(current working - directory from which server is run) - -Cache Replacement: -Modified FIFO - The cache follows a modified First-In-first-out policy. Lets say -cache is full. New entry has size s. The first entry in FIFO order which is of -size greater than s, is removed. Hence, now the cache will have sufficent space -to add new entry. - -Cache Design - -Cache - A doubly linked list which stores all cache entries. - -Hashtable - An array of list pointers, indexed by the hash index, pointing to -all elements hashing to that value. So any element can be looked up directly -based on its hash value of its http header. - -Cache entry - Each entry stores a list of fragments - data buffers linked -together which form part of the object. - -Cache stale entries - Cache objects are updated lazily. No timer is used. Only when a -particular entry is accessed, it is checked for staleness. If stale, a request -to original server is sent and new data is cached. - -Limitations: -Client may send requests in HTTP/1.0 or HTTP/1.1 version. However, server response is always HTTP/1.0 -This folows the Robustness principle given in rfc 2145 http://www.ietf.org/rfc/rfc2145.txt - -Logging: -Logs can be turned off by defining TRACE to be 0 in log.h at compile time. -All logs are currently directed to stdout. diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/config.txt b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/config.txt deleted file mode 100644 index f1bb351..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/config.txt +++ /dev/null @@ -1,6 +0,0 @@ -LISTEN 8080 -#comment -#DocumentRoot /home/gaurav/Dropbox/Code -CACHESIZE 20000000 -CACHETIME 60 -IPADDR 10.2.69.8 diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/fileparser.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/fileparser.h deleted file mode 100644 index c013739..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/fileparser.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef __FILE_PARSER_HDR__ -#define __FILE_PARSER_HDR__ -int file_parser(char *filename, int (*reader)(void *, char *line), void *c); -#define MAX_LINE 1024 -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/httpconf.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/httpconf.h deleted file mode 100644 index a4a6fb8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/httpconf.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __HTTPCONF__ -#define __HTTPCONF__ - -#define MAX_BUF 1024 -#define PENDING_CONN 64 - -#include "log.h" - -/* various config element types parsed from config file*/ -enum cfg_elements_t { - CACHE_SIZE, - CACHE_TIME, - IPADDR, - LISTEN_PORT, - DEFAULT -}; -struct http_server_config { - int listen_port; /*server listens on this port*/ - char ipaddr[16]; - int cachesize; - int cachetime; -}; - -/*Not used currently. Convenience data structure in case threads need to be used*/ -struct http_server_data { - struct http_server_config *cfg; - int sockfd; -}; - -/*Function declarations */ - -int cfg_reader(void *c, char *line); -void http_server(void * sockfd); - -int valid_method_string(char **request, char *request_method); -int valid_version(char **request, struct http_server_config *cfg, - char *version); - -int valid_uri(char **request, struct http_server_config *cfg, - char *uri); -int connection_handler(struct http_server_config *cfg); -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/log.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/log.h deleted file mode 100644 index 074d9be..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/log.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __LOGGER__ -#define __LOGGER__ -#ifndef TRACE -#define TRACE 0 -#endif -#include -#define LOG(_hdl, _msg) \ -{ \ - if(TRACE > 0) \ - fprintf(_hdl,"Pid=%d:%s %s",getpid(),__FUNCTION__, _msg); \ -} -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/tokenize.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/tokenize.h deleted file mode 100644 index 9e3fa8a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/tokenize.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __TOKENIZE_HDR__ -#define __TOKENIZE_HDR__ -#define MAX_TOKEN_SIZE 2048 - -int tokenize(char **str, char *dest); - -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/wcache.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/wcache.h deleted file mode 100644 index 1bb1a54..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/include/wcache.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef __WCACHE_HDR__ -#define __WCACHE_HDR__ -#include -#include -#define WCACHE_HASHTABLE_SIZE 1024 -#define HTTP_SIGNATURE_SIZE 512 -#define HTTP_SIGNATURE_HASH_SIZE 32 -#define CACHETIME 6 -#define FRAGMENT_SIZE 4096 -#define TIMESTAMP_SIZE 50 -#define OK 1 -#define ERROR 0 - -struct wcache_list_element { - struct wcache_list_element *next; - struct wcache_list_element *prev; -}; - - -/* New linked list*/ -struct wcache_list { - struct wcache_list_element head; -}; - -/*A cache storing a list of cache objects*/ -struct wcache { - int curr_size; - int max_size; - struct wcache_list l; -}; - -/*A single entry in cache*/ -struct wcache_entry { - char http_signature[HTTP_SIGNATURE_SIZE]; - unsigned int signature_hash; - time_t ts; - char timestamp[TIMESTAMP_SIZE]; - int last_modified; /*did this entry have a Last-modified parameter*/ - int valid; /*Is this entry valid*/ - int size; /*size of the entry*/ - struct wcache_list fragments; /*list storing fragment buffers*/ - struct wcache_list_element cache_elem; /*part of single global cache - list*/ - struct wcache_list_element hash_elem; /*part of hash table*/ - pthread_mutex_t entry_lock; -}; -struct fragment_buffer { - char buffer[FRAGMENT_SIZE]; - int size; - struct wcache_list_element elem; -}; - - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - - -#define list_for_each(pos, list) \ - for (pos = ((list)->head.next); pos != &((list)->head)&&(pos!= NULL); pos = pos->next) - -int wcache_list_add(struct wcache_list *l, struct wcache_list_element *e); -struct wcache_entry * wcache_entry_alloc(); -void wcache_list_init(struct wcache_list *l); -int wcache_list_del(struct wcache_list_element *e); - -int wcache_fragment_add(struct wcache_entry *entry, char *buffer, int size); -int wcache_entry_replace(struct wcache *w, struct wcache_entry *entry); - -int wcache_add(struct wcache *w, struct wcache_entry *entry); -struct wcache_entry * wcache_find(char http_signature[HTTP_SIGNATURE_SIZE], - time_t ts); - -void wcache_table_init(); -int wcache_remove_entry(struct wcache_entry *w); -struct wcache_entry * wcache_find(char http_signature[HTTP_SIGNATURE_SIZE], - time_t ts); -int wcache_remove_fragments(struct wcache_entry *w); -unsigned int hash(char * buf); -int lock_entry(struct wcache_entry *w); -int unlock_entry(struct wcache_entry *w); -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/index.htm b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/index.htm deleted file mode 100644 index 2a4375c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/index.htm +++ /dev/null @@ -1,14 +0,0 @@ - - - - Gaurav Tungatkar - -

Under construction!

-Photo - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/index.html deleted file mode 100644 index 9271cb6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -.: Game Land :. © Graformix - - - - JUST A TEST FILE! - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/file_parser.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/file_parser.o deleted file mode 100644 index 6682887..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/file_parser.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_cache b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_cache deleted file mode 100755 index 19841cf..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_cache and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_cache.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_cache.o deleted file mode 100644 index 883ff95..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_cache.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_config.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_config.o deleted file mode 100644 index ab928af..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/http_config.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/listener.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/listener.o deleted file mode 100644 index 4480d4d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/listener.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/tokenize.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/tokenize.o deleted file mode 100644 index 8ec0676..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/tokenize.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/wcache.o b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/wcache.o deleted file mode 100644 index 5ce2de6..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/obj/wcache.o and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/.dump.c.swp b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/.dump.c.swp deleted file mode 100644 index 790a250..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/.dump.c.swp and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/file_parser.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/file_parser.c deleted file mode 100644 index b9d7c47..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/file_parser.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * File Name : file_parser.c - * Author : Gaurav Tungatkar - * Creation Date : 16-01-2011 - * Description : - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "fileparser.h" - -/* file_parser() - Parse a file line by line - * Parameters: - * filename - name of file to parse - * reader - user defined routine to handle the parsed line. It is fed the - * current parsed line - * c - void* user defined data that will be passed to reader() - */ -int file_parser(char *filename, int (*reader)(void *, char *line), void *c) -{ - - FILE *fp; - char line[MAX_LINE]; - assert(filename != NULL); - assert(c != NULL); - if((fp = fopen(filename, "r")) == NULL) - { - LOG(stdout, "Failed to open config file\n"); - return -1; - } - while((fgets(line, MAX_LINE, fp) != NULL)) - { - if(reader(c, line) == -1) - { - LOG(stdout, "file parser: reader() failed\n"); - return -1; - } - } - fclose(fp); - return 0; - -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/http_cache.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/http_cache.c deleted file mode 100644 index 9298c5d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/http_cache.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * File Name : http_server.c - * Author : Gaurav Tungatkar - * Creation Date : 17-01-2011 - * Description : - * - */ -//needed for strptime -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "httpconf.h" -#include "wcache.h" -#include "tokenize.h" -#include "fileparser.h" - - -#define BUFFSIZE (4*1024) -#define MAX_FILENAME 512 -#define HTTP_HDR_SIZE 512 -#define HTTP_URI_SIZE 2048 -#define HTTP_STATUS_SIZE 1024 -#define HTTP_GET 11 -#define HTTP_PORT 80 -#define SP 0x20 -#define CRLF "\r\n" - -struct http_server_config cfg ; -struct wcache cache; -pthread_mutex_t list_mutex; - -/*Check if the request contains the Last-modified field. - *return time in seconds since epoch if yes. - *return 0 if it doesnt exist*/ -time_t get_last_modified(char * request, char *timestamp) -{ - char *str; - char dummy[20]; - struct tm t; - time_t tsec = 0; - int i = 0; - assert(request); - - timestamp[0] = '\0'; - str = strstr(request, "Last-Modified:"); - if(str == NULL) goto NOTIME; - if(tokenize(&str, dummy) <= 0) - goto NOTIME; - while(*str == ' ') - str++; - //if(tokenize(&str, timestr) <= 0) - // goto NOTIME; - while(str[i] != '\n') - { - timestamp[i] = str[i]; - i++; - } - timestamp[i] = '\n'; - timestamp[i+1] = '\0'; - if (strptime(timestamp, "%a,%n%e%n%b%n%Y%n%H:%M:%S", &t) != 0 ) - tsec = mktime(&t); - else - goto NOTIME; - return tsec; - -NOTIME: - return 0; -} - -int valid_method_string(char **request, char *request_method) -{ - /*only GET method supported for caching */ - if((tokenize(request, request_method) != 3) - ||(strcmp(request_method, "GET") != 0)) - { - // LOG(stdout, "Invalid method\n"); - // return -1; - return 0; - } - else - { - return HTTP_GET; - } - -} -int valid_version(char **request, struct http_server_config *cfg, - char *version) -{ - /* HTTP versions 1.0 and 1.1 messages are accepted - */ - if((tokenize(request, version) <= 0) - ||((strcmp(version, "HTTP/1.1") != 0) && (strcmp(version, - "HTTP/1.0") != 0))) - { - LOG(stdout, "Version not supported\n"); - return -1; - } - else - { - return 0; - } - - -} -int valid_uri(char **request, struct http_server_config *cfg, - char *uri) -{ - /*if it sees 2 or more leading spaces(SP) - thats invalid URI*/ - if(*(*(request)+1) == SP) - { - LOG(stdout, "Invalid URI\n"); - return -1; - } - - if((tokenize(request, uri) <= 0)) - { - LOG(stdout, "Invalid URI\n"); - return -1; - } - else - { - //cannot refer to the parent directory - if(uri[0] == '.' && uri[1] == '.') - { - LOG(stdout, "Invalid URI\n"); - return -1; - } - } - return 0; - -} - -/*Given a host name and a port, open a socket to that host. - *Returns that socket*/ -int connect_server(char *host, int port) -{ - /* refer to getaddrinfo() man page */ - - struct addrinfo hints; - struct addrinfo *res, *rp; - int fd, s; - int flag = 0; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = 0; - hints.ai_protocol = 0; - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - s = getaddrinfo(host, NULL, &hints, &res); - if (s != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); - return ERROR; - } - for (rp = res; rp != NULL; rp = rp->ai_next) { - if(rp->ai_socktype != SOCK_STREAM) - continue; - fd = socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (fd == -1) - continue; - if(port >= 0) - ((struct sockaddr_in *)(rp->ai_addr))->sin_port = - htons(port); - else - ((struct sockaddr_in *)(rp->ai_addr))->sin_port = - htons(HTTP_PORT); - if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0) - { - flag = 1; - break; /* Success */ - } - close(fd); - } - freeaddrinfo(res); - - if (!flag) { /* No address succeeded */ - fprintf(stderr, "Could not bind\n"); - return ERROR; - } - return fd; - -} - -/*Get the host name from the HTTP request buffer*/ -int get_host(char *request, char *host) -{ - char token[HTTP_URI_SIZE]; - while(tokenize(&request, token) > 0) - { - if(!strcasecmp(token, "Host:")) - break; - } - if(tokenize(&request, host) <= 0) - return ERROR; - return OK; - -} - -int get_port(char *request) -{ - int r; - while((*request)!= '\n' && - (*request)!='\0' && - (*request != ':')) - request++; - if(*request == ':') - request++; - r = strtol(request, NULL, 10); - if(r > 0 && r < 65535) - return r; - return -1; -} -/* Connect to the original server and get the response. - * Cache the object.*/ -int get_fresh_response_and_cache(char *request, char *uri, int cfd) -{ - struct wcache_entry *entry = wcache_entry_alloc(); - char host[1024]; //original server - char buff[FRAGMENT_SIZE]; - char timestamp[100]; - int fd; - time_t m; - int rlen = 0, sent = 0; - int nbytes; - struct timeval t; - gettimeofday(&t, NULL); - - //TODO dynamically allocate the signature buffer - memcpy(entry->http_signature, uri, sizeof(entry->http_signature)); - - - //strcpy(entry->http_request, request); - - entry->valid = 1; - entry->signature_hash = hash(uri); - entry->size = sizeof(struct wcache_entry); - entry->ts = t.tv_sec; - wcache_list_init(&entry->fragments); - LOG(stdout,"\nNew cache entry created for uri :"); - LOG(stdout, uri); - - get_host(request, host); //TODO - fd = connect_server(host, HTTP_PORT); - // FIXME - rlen = strlen(request); - while(sent < rlen) - { - nbytes = write(fd, request+sent, rlen - sent); - if(nbytes == -1){ - perror("Socket write failed"); - exit(1); - } - sent += nbytes; - } - - /*sent the request to the actual server. - *Now receive the response, fill up the cache entry - */ - int f = 0; - while((rlen = read(fd, buff, FRAGMENT_SIZE)) > 0) - { - if(f == 0) - { - f = 1; - m = get_last_modified(buff, timestamp); - if(m != 0) - { - memcpy(entry->timestamp, timestamp, sizeof(entry->timestamp)); - entry->last_modified = 1; - entry->ts = m ; - } - else - entry->last_modified = 0; - } - wcache_fragment_add(entry, buff, rlen); - write(cfd, buff, rlen); - } - wcache_add(&cache, entry); - return OK; - -} -/* Check response. If it contains 304: Not modified, return 1; else return 0*/ -int not_modified(char *buffer) -{ - if(strstr(buffer, "304") != NULL) - return 1; - return 0; -} - -/*Ignore SIGPIPE */ -void sigpipe_ign() - -{ - struct sigaction act; - act.sa_handler = SIG_IGN; - sigemptyset (&act.sa_mask); - act.sa_flags = 0; - sigaction (SIGPIPE, &act, NULL); - - -} -void http_server(void * data) -{ - - char request[BUFFSIZE+1]; - int numbytes; - int errflag = 0; - char request_method[5]; - char version[10]; - int method; - int sockfd; - char uri[HTTP_URI_SIZE]; - char status[HTTP_STATUS_SIZE]; - sockfd = *(int *)data; - // free(data); - - if((numbytes = read(sockfd, (void *)request, BUFFSIZE)) <= 0) - { - LOG(stdout, "read from socket failed"); - close(sockfd); - return; - } - char *requestptr = request; - if((method = valid_method_string(&requestptr, request_method)) == -1) - { - //ERROR in Request - snprintf(status, - HTTP_STATUS_SIZE, - "HTTP/1.0 400 Bad Request: Invalid Method: %s\r\n", - request_method); - LOG(stdout, status); - errflag = 1; - } - if(method != HTTP_GET) - { - int sfd, rlen, n; - char host[1024]; //original server - char *r = request; - LOG(stdout, "Acting as relay. Caching only for GET\n"); - get_host(r, host); //TODO - //port = get_port(r); - sfd = connect_server(host, HTTP_PORT); - n = write(sfd, request, BUFFSIZE); - while((rlen = read(sfd, request, BUFFSIZE)) > 0) - { - write(sockfd, request, rlen); - } - return; - - } - - if(!errflag && (method == HTTP_GET)) - { - //tokenize URI - //check that the method name and URI are separated by exactly 1 - //SP character - //requestptr should now be pointing at a SP character. If the - //next character is SP as well, invalid request - if(valid_uri(&requestptr, &cfg, uri) == -1) - { - snprintf(status, - HTTP_STATUS_SIZE, - "HTTP/1.0 400 Bad Request: Invalid URI: %s\r\n", - uri); - LOG(stdout, status); - //ERROR in request - errflag = 1; - - } - - - } - if(!errflag) - { - if(valid_version(&requestptr, &cfg, version) == -1) - { - //ERROR - //HTTP/1.0 400 Bad Request: Invalid HTTP-Version: - // - snprintf(status, - HTTP_STATUS_SIZE, - "HTTP/1.0 400 Bad Request: Invalid HTTP-Version: %s\r\n", - version); - LOG(stdout, status); - errflag = 1; - } - - } - //seems like request came up fine! Now lets see if we can read the file - if(!errflag) - { - struct wcache_entry *entry; - struct timeval tv; - struct wcache_list_element *e; - struct fragment_buffer *fb; - time_t ctim; - char cond_get[BUFFSIZE] = {0}; - int rlen; - char host[1024]; //original server - // get if-modified-since ts here TODO - gettimeofday(&tv, NULL); - entry = wcache_find(uri, tv.tv_sec); - if(entry) - { - lock_entry(entry); - if(entry->last_modified) - { - //construct conditional GET request, send it to - //server. If response says not modified, return - //the cache value. - //Else discard the old fragments and add the - //newly returned ones. - //conditional GET - int srvfd; - snprintf(cond_get,BUFFSIZE, - "GET %s HTTP/1.0\r\nIf-modified-since: %s\n", - uri, entry->timestamp); - char *rr = request; - get_host(rr, host); //TODO - srvfd = connect_server(host, HTTP_PORT); - if(write(srvfd, cond_get, BUFFSIZE) <= 0) - { - LOG(stdout, "socket write error\n"); - } - cond_get[0] = '\0'; - LOG(stdout, "Sending conditional GET:"); - LOG(stdout, host); - //now just get the initial part of the request - //check if it is 304 Not-Modified - rlen = read(srvfd, cond_get, FRAGMENT_SIZE); - if(not_modified(cond_get)) - { - LOG(stdout, "Not modified. Return cached result\n"); - list_for_each(e, &(entry->fragments)) - { - fb = container_of(e, struct fragment_buffer, elem); - write(sockfd, fb->buffer, fb->size); - } - close(sockfd); - unlock_entry(entry); - return; - } - else - { - //remove the old fragments and cache new - //ones - - wcache_remove_fragments(entry); - ctim = get_last_modified(cond_get, - entry->timestamp); - if(ctim != 0) - { - entry->last_modified = 1; - entry->ts = ctim ; - } - else - { - entry->last_modified = 0; - entry->ts = tv.tv_sec; - } - wcache_fragment_add(entry, cond_get, rlen); - write(sockfd, cond_get, rlen); - while((rlen = read(srvfd, cond_get, FRAGMENT_SIZE)) > 0) - { - wcache_fragment_add(entry, - cond_get, rlen); - write(sockfd, cond_get, rlen); - } - } - - - } - else - { - //FOUND IN CACHE! - if((tv.tv_sec - entry->ts) <= cfg.cachetime) - { - list_for_each(e, &(entry->fragments)) - { - fb = container_of(e, struct fragment_buffer, elem); - write(sockfd, fb->buffer, fb->size); - } - } - else - { - //cache entry has expired. This is lazy - //checking of expired entries. - entry->valid = 0; - unlock_entry(entry); - wcache_remove_entry(entry); - get_fresh_response_and_cache(request, uri, sockfd); - goto NOUNLOCK; - } - } - - } - else - { - //NOT IN CACHE TODO - get_fresh_response_and_cache(request, uri, sockfd); - - } - if(entry != NULL) - unlock_entry(entry); - } - - - - -NOUNLOCK: - close(sockfd); - return; -} -int main(int argc, char *argv[]) -{ - memset(&cfg, 0, sizeof(cfg)); - char filename[MAX_FILENAME]; - sigpipe_ign(); - if(argc == 2) - { - if(strlen(argv[1]) < MAX_FILENAME) - strcpy(filename, argv[1]); - } - else - strcpy(filename, "config.txt"); - pthread_mutex_init(&list_mutex, NULL); - wcache_list_init(&(cache.l)); - if(file_parser(filename, cfg_reader, &cfg)== -1) - { - LOG(stdout, "Configuration Error.Exiting...\n"); - exit(1); - - } - cache.max_size = (cfg.cachesize)*(1024); - LOG(stdout, - "Starting primitive HTTP web server implemented for CSC573\n"); - wcache_table_init(); - if(connection_handler(&cfg) == -1) - { - LOG(stdout, "Error!Exiting..\n"); - exit(1); - } - pthread_mutex_destroy(&list_mutex); - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/http_config.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/http_config.c deleted file mode 100644 index 2e9acb7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/http_config.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * File Name : http_config.c - * Author : Gaurav Tungatkar - * Creation Date : 14-01-2011 - * Description : - * - */ -/*Read http server configuration from the config file and store it in memory - */ -#include -#include -#include -#include -#include -#include -#include -#include "log.h" -#include "tokenize.h" -#include "httpconf.h" -#include "fileparser.h" - -int cfg_reader(void *c, char *line) -{ - assert(c); - assert(line); - char token[MAX_TOKEN_SIZE]; - int next_token = DEFAULT; - struct http_server_config *cfg = (struct http_server_config *)c; - int config_cnt = 0; - /* From the given config file format, we assume we have 4 distinct - * config objects - port, DocumentRoot, DirectoryIndex, supported files - * and all are mandatory. If one of them is missing, we should give an - * error and return. - * This function gets one line of the config file at a time, which is - * further parses. - */ - - while(tokenize(&line, token) > 0) - { - if(token[0] == '#') - { - //This line must be a Comment. Ignore and return - return 0; - } - if(strcmp(token, "IPADDR") == 0) - { - next_token = IPADDR; - config_cnt++; - - - } - else if(strcmp(token, "LISTEN") == 0) - { - next_token = LISTEN_PORT; - config_cnt++; - - } - else if(strcmp(token, "CACHESIZE") == 0) - { - next_token = CACHE_SIZE; - config_cnt++; - } - else if(strcmp(token, "CACHETIME") == 0) - { - next_token = CACHE_TIME; - config_cnt++; - } - else - { - int len; - char *p; - len = strlen(token); - /* next_token was set previously based on the type of - * config object. Based on that type, we now store its - * value - */ - switch(next_token) - { - case CACHE_SIZE: - if(len > 10) - { - LOG(stdout, - "config: cache size exceeded\n"); - return -1; - - } - cfg->cachesize = strtol(token, &p, 10); - config_cnt++; - next_token = DEFAULT; - break; - case LISTEN_PORT: - cfg->listen_port = strtol(token, &p, 10); - if(cfg->listen_port > 65535) - { - LOG(stdout, - "Port value invalid\n"); - return -1; - } - config_cnt++; - next_token = DEFAULT; - break; - case CACHE_TIME: - cfg->cachetime = strtol(token, &p, 10); - if(cfg->cachetime > 65535) - { - LOG(stdout, - "time value invalid\n"); - return -1; - } - config_cnt++; - next_token = DEFAULT; - break; - case IPADDR: - if(len > - sizeof(cfg->ipaddr)) - { - - LOG(stdout, - "config:IP addr size exceeded\n"); - return -1; - - } - strcpy(cfg->ipaddr,token); - config_cnt++; - next_token = DEFAULT; - break; - default: - LOG(stdout, - "Error in config file.Exiting...\n"); - return -1; - - } - - } - - } - /* config_cnt counts how many config types or values we have seen. - * if it is 1, it means we just got the type and not the value.*/ - if(config_cnt == 1) - { - LOG(stdout, "Error in config file\n"); - return -1; - - } - return 0; - -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/index.html deleted file mode 100644 index 2c3fecd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ -Google



 

Advanced searchLanguage tools

© 2011 - Privacy

\ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/listener.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/listener.c deleted file mode 100644 index f170ba7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/listener.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * File Name : listener.c - * Author : Gaurav Tungatkar - * Creation Date : 16-01-2011 - * Description : - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "httpconf.h" - - -int connection_handler(struct http_server_config *cfg) -{ - int listen_fd, new_fd, set = 1, rc; - struct sockaddr_in listener_addr, client_addr; - socklen_t addr_len = 0; - pthread_t thr; - char p[50]; - int *tdata = NULL; - assert(cfg != NULL); - /* Standard server side socket sequence*/ - - if((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) - { - LOG(stdout, "socket() failure\n"); - return -1; - } - if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &set, - sizeof(int)) == -1) { - LOG(stdout, "setsockopt() failed"); - return -1; - } - bzero(&listener_addr, sizeof(listener_addr)); - listener_addr.sin_family = AF_INET; - listener_addr.sin_port = htons(cfg->listen_port); - inet_aton(cfg->ipaddr, &(listener_addr.sin_addr)); - memset(listener_addr.sin_zero, '\0', sizeof(listener_addr.sin_zero)); - - if(bind(listen_fd, (struct sockaddr*)&listener_addr, sizeof - listener_addr) == -1) - { - LOG(stdout, "bind() failed\n"); - return -1; - - } - - if(listen(listen_fd, PENDING_CONN) == -1) - { - LOG(stdout, "listen() failed\n"); - return -1; - } - sprintf(p, "HTTP server listening on port:%d\n", cfg->listen_port); - LOG(stdout, p); - while(1) - { - - new_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &addr_len); - if(new_fd == -1) - { - //log - LOG(stdout, "accept() failed\n"); - return -1; - - } - LOG(stdout, "new connection accepted\n"); - tdata = (int *)malloc(sizeof(int)); - *tdata = new_fd; - rc = pthread_create(&thr, NULL, (void *)http_server, - (void *)tdata); - if (rc){ - printf("ERROR; return code from pthread_create() is %d\n", rc); - exit(-1); - } - //fork a new process to handle this request -#if 0 - if((pid = fork()) == -1) - { - //LOG Error - LOG(stdout, "Error in fork\n"); - - } - else if(pid == 0) - { - /*This is the child process. This will service the - *request while parent goes back to listening.*/ - LOG(stdout, "Servicing request\n"); - http_server(cfg, new_fd); - return 0; - } - else - { - close(new_fd); - } -#endif - - } - - return 0; - -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/tokenize.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/tokenize.c deleted file mode 100644 index f4978ec..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/tokenize.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * File Name : tokenize.c - * Author : Gaurav Tungatkar - * Creation Date : 14-01-2011 - * Description : - * - */ -#include -#include -#include "tokenize.h" -/* - * tokenize() - * str = pointer to string that has to be tokenized - * dest = destination where separate token will be stored - * - * This function separates tokens from the given string. Tokens can be of - * maximum MAX_TOKEN_SIZE . After a call to tokenize, str points to the first - * character after the current token; the string is consumed by the tokenize - * routine. - * RETURNS: length of current token - * -1 if error - */ -int tokenize(char **str, char *dest) -{ - int count = 0; - while(isspace(**str)) - (*str)++; - while(!isspace(**str) && (**str != '\0')) - { - *dest++ = *(*str)++; - count++; - if(count >= MAX_TOKEN_SIZE) - { - count = -1; - break; - } - } - *dest = '\0'; - return count; -} -#define main nomain -int main() -{ - char *str = " Do I get all \n \n ninechars ninetyninechars "; - char dest[MAX_TOKEN_SIZE]; - int ret; - while((ret = tokenize(&str, dest))> 0) - { - printf("token = %s\n", dest); - } - if(ret == -1) - printf("Tokenization failed to complete\n"); - return 0; - -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/wcache.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/wcache.c deleted file mode 100644 index 5b20a84..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTP-Proxy-cache/src/wcache.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * File Name : wcache.c - * Author : Gaurav Tungatkar - * Creation Date : 07-03-2011 - * Description : - * Web cache - * This includes generic linked list implementation as well as wrapper function - * for managing cache. - * Cache design : - * Each cache object is linked in a global double linked list "cache" - * It is also part of the list pointed to by a HashTable entry. - * Each cache object contains multiple "fragments" - nothing but data buffers, - * linked together. - * Hash table stores pointers to cache based on hash value of http GET reqest - * line. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "wcache.h" -#include "httpconf.h" -struct wcache_list * wcache_hashtable[WCACHE_HASHTABLE_SIZE]; -struct wcache_list cache_list; -extern struct http_server_config cfg; -extern pthread_mutex_t list_mutex; - /* very rudimentary hash function */ -unsigned int hash(char * buf) -{ - unsigned int hashv = 1298; //seed - const char *s = buf; - while (*s) - { - hashv = hashv * 101 + *s++; - } - return hashv; -} - -struct wcache_entry * wcache_entry_alloc() -{ - struct wcache_entry *e = (struct wcache_entry *)malloc(sizeof(struct wcache_entry)); - memset(e, 0, sizeof(struct wcache_entry)); - pthread_mutex_init(&(e->entry_lock), NULL); - return e; -} -int lock_entry(struct wcache_entry *w) -{ - return pthread_mutex_lock(&(w->entry_lock)); - -} -int unlock_entry(struct wcache_entry *w) -{ - return pthread_mutex_unlock(&(w->entry_lock)); - -} -void wcache_table_init() -{ - int i; - for(i = 0; i < WCACHE_HASHTABLE_SIZE; i++) - { - wcache_hashtable[i] = NULL; - } -} -struct wcache_list * wcache_list_alloc() -{ - struct wcache_list * l = (struct wcache_list*)malloc(sizeof(struct wcache_list)); - memset(l, 0, sizeof(struct wcache_list)); - return l; -} -void wcache_list_init(struct wcache_list *l) -{ - assert(l != NULL); - l->head.next = l->head.prev = &(l->head); -} - - -/*add element to a list*/ -int wcache_list_add(struct wcache_list *l, struct wcache_list_element *e) -{ - if(e == NULL) goto ERR; - if(l == NULL) goto ERR; - struct wcache_list_element * last; - if(l->head.prev == NULL) - { - l->head.prev = l->head.next = e; - e->prev = &(l->head); - e->next = &(l->head); - return OK; - } - last = l->head.prev; - last->next = e; - e->prev = last; - e->next = &(l->head); - l->head.prev = e; - return OK; -ERR: - //LOG - return ERROR; - -} - -int wcache_list_del(struct wcache_list_element *e) -{ - if(e == NULL) goto ERR; - e->prev->next = e->next; - e->next->prev = e->prev; - e->prev = NULL; - e->next = NULL; - return OK; -ERR: - return ERROR; - -} -/*add a fragment to this entry*/ -int wcache_fragment_add(struct wcache_entry *entry, char *buffer, int size) -{ - struct fragment_buffer *fb = - (struct fragment_buffer *)malloc(sizeof(struct fragment_buffer)); - int ret; - assert(fb); - // memset(fb, 0, sizeof(struct fragment_buffer)); - memcpy(fb->buffer, buffer, FRAGMENT_SIZE); - fb->size = size; - entry->size += size + sizeof(struct fragment_buffer); - pthread_mutex_lock(&list_mutex); - ret = wcache_list_add(&(entry->fragments), &(fb->elem)); - pthread_mutex_unlock(&list_mutex); - return ret; -} - - -int wcache_entry_replace(struct wcache *w, struct wcache_entry *entry) -{ - //cache entry replacement - //for now, modified FIFO policy followed- replace the oldest entry - //whose deletion leaves __enough space__ in the cache for the current entry. - //This means, that the "oldest" entry may not be the one that is always - //replaced. - struct wcache_list_element *e = &(w->l.head); - - struct wcache_entry * we; - if(e == NULL) - return OK; - - for(; e->next != &(w->l.head); e = e->next) - { - we = container_of(e->next, struct wcache_entry, cache_elem); - if((w->curr_size + entry->size - we->size) <= w->max_size) - { - w->curr_size =- we->size; - printf("Removing %s\n", we->http_signature); - wcache_remove_entry(we); - return OK; - } - - } - return ERROR; - -} -/*add an entry to cache. Handle cache full and replacement*/ -int wcache_add(struct wcache *w, struct wcache_entry *entry) -{ - struct wcache_list * l = &(w->l); - struct wcache_list *hte; - if(pthread_mutex_lock(&list_mutex) != 0) - return ERROR; - if(w->curr_size + entry->size >= w->max_size) - { - //cache full. remove one entry and make space. - wcache_entry_replace(w, entry); - - } - if(w->curr_size + entry->size >= w->max_size) - { - //LOG - goto ERR; - - } - - if(wcache_list_add(l, &(entry->cache_elem)) == ERROR) - goto ERR; - - w->curr_size += entry->size; - hte = wcache_hashtable[entry->signature_hash % WCACHE_HASHTABLE_SIZE]; - if(hte == NULL) - { - hte = wcache_hashtable[entry->signature_hash % WCACHE_HASHTABLE_SIZE] = - wcache_list_alloc(); - - } - if(wcache_list_add(hte, &(entry->hash_elem)) == ERROR) - goto ERR; - - pthread_mutex_unlock(&list_mutex); - return OK; -ERR: - pthread_mutex_unlock(&list_mutex); - //LOG - return ERROR; -} - -/*find the cache entry corresponding to this http signature*/ -struct wcache_entry * wcache_find(char http_signature[HTTP_SIGNATURE_SIZE], - time_t ts) -{ - /* - * ts - either the if modified since time or the current time - * */ - /* TODO */ - unsigned int hashv = hash(http_signature); - struct wcache_list *l = NULL; - struct wcache_list_element *e; - struct wcache_entry * we; - - if(pthread_mutex_lock(&list_mutex) != 0) - return NULL; - l = wcache_hashtable[hashv % WCACHE_HASHTABLE_SIZE]; - if(l) - e = &(l->head); - else - goto RET; - for(;e->next != &(l->head); e = e->next) - { - //w = l; - we = container_of((e->next), struct wcache_entry, hash_elem); - if(!we->valid) - goto RET; - if(strcmp(http_signature, we->http_signature) == 0) - { - goto RETWE; - } - - } -RET: - pthread_mutex_unlock(&list_mutex); - return NULL; -RETWE: - pthread_mutex_unlock(&list_mutex); - return we; - -} - -/*free all fragments of this entry*/ -int wcache_remove_fragments(struct wcache_entry *w) -{ - struct fragment_buffer *b; - if(w->fragments.head.next) - { - while(w->fragments.head.next != w->fragments.head.prev) - { - b = container_of(w->fragments.head.next, - struct fragment_buffer, elem); - wcache_list_del(w->fragments.head.next); - w->size -= b->size; - if(b) free(b); - } - } - return OK; - -} -int wcache_remove_entry(struct wcache_entry *w) -{ - - if(wcache_list_del(&(w->cache_elem)) == ERROR) - { - printf(":2 check\n"); - return ERROR; - } - if(wcache_list_del(&(w->hash_elem)) == ERROR) - { - printf(":3 check\n"); - return ERROR; - } - printf(":4 check\n"); - //free every fragment - wcache_remove_fragments(w); - pthread_mutex_destroy(&(w->entry_lock)); - free(w); - w = NULL; - - return OK; -} -#if 0 -//void * alloc_wcache_hashtable(); -int main11() -{ - struct wcache_entry *entry = - (struct wcache_entry *)malloc(sizeof(struct wcache_entry)); -// cache_list.head = (struct wcache_list_element*)malloc( - // sizeof (struct wcache_list_element)); - /* wcache_list_add(&cache_list, &(entry->cache_elem)); - entry = (struct wcache_entry *)malloc(sizeof(struct wcache_entry)); - entry->signature_hash = 30; - wcache_list_add(&cache_list, &(entry->cache_elem)); - entry = NULL; - entry = get_struct(cache_list.head.next, struct wcache_entry, - cache_elem); - printf("TC1: %d\n", entry->signature_hash); - entry = get_struct(cache_list.head.next->next, struct wcache_entry, - cache_elem); - printf("TC1: %d\n", entry->signature_hash); - */ - cache.curr_size= 0; - cache.max_size = 5; - // cache.l.head.next = cache.l.head.prev = &(cache.l.head); - wcache_list_init(&(cache.l)); - entry->size = 15; - strcpy(entry->http_signature, "HTTP/1.10"); - entry->signature_hash = hash(entry->http_signature); - entry->valid = 1; - entry->ts = 10; - wcache_add(&cache, entry); - entry = (struct wcache_entry *)malloc(sizeof(struct wcache_entry)); - entry->size = 10; - strcpy(entry->http_signature, "HTTP/2.22"); - entry->signature_hash = hash(entry->http_signature); - entry->valid = 1; - entry->ts = 10; - wcache_add(&cache, entry); - entry = NULL; - entry = wcache_find("HTTP/1.10", 12); - if(entry != NULL) - printf("TC1: %s\n", entry->http_signature); - - return 0; -} -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/Makefile deleted file mode 100644 index d65b2ca..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -SOURCES := $(shell find . -iname '*.c' -depth 1 ) -OBJECTS := $(SOURCES:.c=.o) - -all: http_proxy tests - -http_proxy: $(OBJECTS) - gcc $(OBJECTS) $(LFLAGS) -o http_proxy - -.PHONY: tests - -tests: - gcc -I.. tests/http_message_test.c http_message.c -o http_message_test - -.PHONY: clean -clean: - rm $(OBJECTS) http_proxy diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/README b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/README deleted file mode 100644 index 674718b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/README +++ /dev/null @@ -1,6 +0,0 @@ -HTTPProxy - -Description: -HTTPProxy is a basic proxy server for http. - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/README.md b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/README.md deleted file mode 100644 index 80e3d91..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/README.md +++ /dev/null @@ -1,33 +0,0 @@ -User Manual - NetNinny -====================== - -### Building - -To build the software, simply unpack the archive and issue “make†in the HTTPProxy directory. This will produce a NetNinny binary in the same catalogue. - -### Configuration - -It is possible to configure yourself what port the proxy server should use. This can be done by giving the port number as a argument to the executable. For example: - - ./NetNinny 8081 - -### Features - -NetNinny has the following features: - -* Support for both HTTP version 1.0 and 1.1 -* Can handle any size of data received from the web server -* Blocks URLs containing forbidden words -* Blocks content containing forbidden words -* Compatible with all major browsers, i.e follows the specification - -### Lacks - -We have not implemented any other request than GET currently. It also lacks complete error checking, so currently it is not hard, probably, to get the server to crash with a bad request. - -### Proof - -We have tested the proxy server with sites like Aftonbladet, Expressen, Wikipedia, Facebook and YouTube and it seems to work fine. - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/client b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/client deleted file mode 100755 index b076025..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/client and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http deleted file mode 100755 index 1ec8087..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http_message.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http_message.c deleted file mode 100644 index 383443c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http_message.c +++ /dev/null @@ -1,227 +0,0 @@ -#include -#include -#include -#include -#include "proxy.h" - - -int http_methods_len = 9; -const char *http_methods[] = -{ - "OPTIONS", - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "TRACE", - "CONNECT", - "INVALID" -}; - -void http_request_init(http_request **req) -{ - *req = (http_request*)malloc(sizeof(http_request)); - - http_request *request = *req; - request->method = 0; - request->search_path = NULL; - - TAILQ_INIT(&request->metadata_head); -} - -void http_request_destroy(http_request *req) -{ - free((char*)req->search_path); - - struct http_metadata_item *item; - TAILQ_FOREACH(item, &req->metadata_head, entries) { - free((char*)item->key); - free((char*)item->value); - free(item); - } -} - -void http_request_print(http_request *req) -{ - printf("[HTTP_REQUEST] \n"); - - switch (req->version) { - case HTTP_VERSION_1_0: - printf("version:\tHTTP/1.0\n"); - break; - case HTTP_VERSION_1_1: - printf("version:\tHTTP/1.1\n"); - break; - case HTTP_VERSION_INVALID: - printf("version:\tInvalid\n"); - break; - } - - printf("method:\t\t%s\n", - http_methods[req->method]); - printf("path:\t\t%s\n", - req->search_path); - - printf("[Metadata] \n"); - struct http_metadata_item *item; - TAILQ_FOREACH(item, &req->metadata_head, entries) { - printf("%s: %s\n", item->key, item->value); - } - - printf("\n"); -} - -void http_parse_method(http_request* result, const char* line) -{ - enum parser_states { - METHOD, - URL, - VERSION, - DONE - }; - - char* copy; - char* p; - copy = p = strdup(line); - char* token = NULL; - int s = METHOD; - - while ((token = strsep(&p, " \r\n")) != NULL) { - switch (s) { - case METHOD: { - int found = 0; - int i; - for (i = 0; i < http_methods_len; i++) { - if (strcmp(token, http_methods[i]) == 0) { - found = 1; - result->method = i; - break; - } - } - if (found == 0) { - result->method = http_methods_len - 1; - free(copy); - return; - } - s++; - break; - } - case URL: - result->search_path = strdup(token); - s++; - break; - case VERSION: - { - if(strcmp(token, "HTTP/1.0") == 0) { - result->version = HTTP_VERSION_1_0; - } else if(strcmp(token, "HTTP/1.1") == 0) { - result->version = HTTP_VERSION_1_1; - } else { - result->version = HTTP_VERSION_INVALID; - } - s++; - break; - } - case DONE: - break; - } - } - free(copy); - return; -} - -// Content-Byte: 101 -void http_parse_metadata(http_request *result, char *line) -{ - char *line_copy = strdup(line); - char *key = strdup(strtok(line_copy, ":")); - - char *value = strtok(NULL, "\r"); - - // remove whitespaces :) - char *p = value; - while(*p == ' ') p++; - value = strdup(p); - - free(line_copy); - - // create the http_metadata_item object and - // put the data in it - http_metadata_item *item = malloc(sizeof(*item)); - item->key = key; - item->value = value; - - // add the new item to the list of metadatas - TAILQ_INSERT_TAIL(&result->metadata_head, item, entries); -} - - - -char *http_build_request(http_request *req) -{ - const char *search_path = req->search_path; - - // construct the http request - int size = strlen("GET ") + 1; - //char *request_buffer = calloc(sizeof(char)*size); - char *request_buffer = calloc(size, sizeof(char)); - strncat(request_buffer, "GET ", 4); - - size += strlen(search_path) + 1; - request_buffer = realloc(request_buffer, size); - strncat(request_buffer, search_path, strlen(search_path)); - - // TODO: Check the actual HTTP version that is used, and if - // 1.1 is used we should append: - // Connection: close - // to the header. - switch(req->version) - { - case HTTP_VERSION_1_0: - size += strlen(" HTTP/1.0\r\n\r\n"); - request_buffer = realloc(request_buffer, size); - strncat(request_buffer, " HTTP/1.0\r\n", strlen(" HTTP/1.0\r\n")); - break; - case HTTP_VERSION_1_1: - size += strlen(" HTTP/1.1\r\n\r\n"); - request_buffer = realloc(request_buffer, size); - strncat(request_buffer, " HTTP/1.1\r\n", strlen(" HTTP/1.1\r\n")); - break; - default: - LOG(LOG_ERROR, "Failed to retrieve the http version\n"); - return NULL; - } - - http_metadata_item *item; - TAILQ_FOREACH(item, &req->metadata_head, entries) { - // Remove Connection properties in header in case - // there are any - if(strcmp(item->key, "Connection") == 0 || - strcmp(item->key, "Proxy-Connection") == 0) - { - continue; - } - - size += strlen(item->key) + strlen(": ") + strlen(item->value) + strlen("\r\n"); - request_buffer = realloc(request_buffer, size); - strncat(request_buffer, item->key, strlen(item->key)); - strncat(request_buffer, ": ", 2); - strncat(request_buffer, item->value, strlen(item->value)); - strncat(request_buffer, "\r\n", 2); - } - - if(req->version == HTTP_VERSION_1_1) - { - size += strlen("Connection: close\r\n"); - request_buffer = realloc(request_buffer, size); - strncat(request_buffer, "Connection: close\r\n", strlen("Connection: close\r\n")); - } - - - size += strlen("\r\n"); - request_buffer = realloc(request_buffer, size); - strncat(request_buffer, "\r\n", 2); - - return request_buffer; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http_message.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http_message.h deleted file mode 100644 index 614483e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/http_message.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef HTTP_MESSAGE_HH -#define HTTP_MESSAGE_HH -#include "proxy.h" - -void http_request_init(http_request**); -void http_request_destroy(http_request*); -void http_request_print(http_request*); -void http_parse_method(http_request*, char*); -void http_parse_metadata(http_request*, char*); -char *http_build_request(http_request*); - -extern int http_methods_len; -extern const char* http_methods[]; - -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/list.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/list.c deleted file mode 100644 index 70c519d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/list.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include -#include -#include "list.h" -#include "proxy.h" - -const char *list_get_key(struct METADATA_HEAD *list, const char *key) -{ - http_metadata_item *item; - TAILQ_FOREACH(item, list, entries) { - if(strcmp(item->key, key) == 0) - { - return item->value; - } - } - - return NULL; -} - -void list_add_key(struct METADATA_HEAD *list, const char *key, const char *value) -{ - http_metadata_item *item = (http_metadata_item*)malloc(sizeof(http_metadata_item)); - item->key = key; - item->value = value; - - TAILQ_INSERT_TAIL(list, item, entries); -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/list.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/list.h deleted file mode 100644 index 5ceb267..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/list.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LIST_HH -#define LIST_HH - -#include "proxy.h" - -const char *list_get_key(struct METADATA_HEAD *list, const char *key); - -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/main.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/main.c deleted file mode 100644 index a6d8d0c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/main.c +++ /dev/null @@ -1,313 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "proxy.h" -#include "net.h" -#include "list.h" -#include "http_message.h" - -char *read_line(int sockfd) -{ - int buffer_size = 2; - char *line = (char*)malloc(sizeof(char)*buffer_size+1); - char c; - int length = 0; - int counter = 0; - - while(1) - { - length = recv(sockfd, &c, 1, 0); - line[counter++] = c; - - if(c == '\n') - { - line[counter] = '\0'; - return line; - } - - // reallocate the buffer - if(counter == buffer_size) - { - buffer_size *= 2; - - // TODO: should probably allocate +1 for the null terminator, - // but not sure. - line = (char*)realloc(line, sizeof(char)*buffer_size); - } - - } - - return NULL; -} - -int containing_forbidden_words(char str[]){ - - // Forbidden words - char *words[] = {"SpongeBob", "Britney Spears", "Paris Hilton", "NorrkÓ§ping", "Norrköping", "Norrk%C3%B6ping"}; - int hits[] = {0, 0, 0, 0, 0, 0}; // Every forbidden word need to have a zero in this array to be able to count number of char hits. - int numb_words = 6; // Number of forbidden words - - int str_length = strlen(str); - int c, w; // Index for char in str, and index for word in words - - // Search for forbidden words - for (c = 0; c < str_length; c++) - { - for (w = 0; w < numb_words; w++) - { - if (tolower(words[w][ hits[w] ]) == tolower(str[c])){ - if(++hits[w] == strlen(words[w])) - return 1; - } - else if (hits[w] != 0) - hits[w--] = 0; - } - } - - return 0; -} - -int send_to_client(int client_sockfd, char data[], int packages_size, ssize_t length) -{ - // if packages_size is set to 0, then the function will try to send all data as one package. - if(packages_size < 1) - { - if(send(client_sockfd, data, length, 0) == -1) - { - perror("Couldn't send data to the client."); - return -1; - } - } - else - { - int p; - for(p = 0; p*packages_size + packages_size < length; p++){ - if(send(client_sockfd, (data + p*packages_size), packages_size, 0) == -1) - { - perror("Couldn't send any or just some data to the client. (loop)\n"); - return -1; - } - } - - if (p*packages_size < length) - { - if(send(client_sockfd, (data + p*packages_size), length - p*packages_size, 0) == -1) - { - perror("Couldn't send any or just some data to the client.\n"); - return -1; - } - } - } - - return 0; -} - -int http_request_send(int sockfd, http_request *req) -{ - LOG(LOG_TRACE, "Requesting: %s\n", req->search_path); - - char *request_buffer = http_build_request(req); - - // send the http request to the web server - if(send(sockfd, request_buffer, strlen(request_buffer), 0) == -1) - { - free(request_buffer); - perror("send"); - return 1; - } - free(request_buffer); - - LOG(LOG_TRACE, "Sent HTTP header to web server\n"); - - return 0; -} - -void handle_client(int client_sockfd) -{ - char *line; - int server_sockfd; - http_request *req; - - req = http_read_header(client_sockfd); - if(req == NULL) - { - LOG(LOG_ERROR, "Failed to parse the header\n"); - return; - } - - if (containing_forbidden_words((char*)req->search_path) || containing_forbidden_words((char*)list_get_key(&req->metadata_head, "Host"))){ - char *error1 = "HTTP/1.1 200 OK\r\nServer: Net Ninny\r\nContent-Type: text/html\r\n\r\n\n\n\nNet Ninny Error Page 1 for CPSC 441 Assignment 1\n\n\n\n

\nSorry, but the Web page that you were trying to access\nis inappropriate for you, based on the URL.\nThe page has been blocked to avoid insulting your intelligence.\n

\n\n

\nNet Ninny\n

\n\n\n\n\n"; - http_request_destroy(req); - send_to_client(client_sockfd, error1, 0, strlen(error1)); - return; - } - - server_sockfd = http_connect(req); - if(server_sockfd == -1) - { - LOG(LOG_ERROR, "Failed to connect to host\n"); - http_request_destroy(req); - return; - } - - LOG(LOG_TRACE, "Connected to host\n"); - - http_request_send(server_sockfd, req); - http_request_destroy(req); - - LOG(LOG_TRACE, "Beginning to retrieve the response header\n"); - int is_bad_encoding = 0; - int is_text_content = 0; - int line_length; - while(1) - { - line = read_line(server_sockfd); - line_length = strlen(line); - send_to_client(client_sockfd, line, 0, line_length); - - if(line[0] == '\r' && line[1] == '\n') - { - // We received the end of the HTTP header - LOG(LOG_TRACE, "Received the end of the HTTP response header\n"); - free(line); - break; - } - else if(18 <= line_length) - { - line[18] = '\0'; // Destroys the data in the line, but is needed to check if in coming data will be text format. - if (strcmp(line, "Content-Type: text") == 0) - is_text_content = 1; - else if (strcmp(line, "Content-Encoding: ") == 0) - is_bad_encoding = 1; - } - - free(line); - } - - LOG(LOG_TRACE, "Beginning to retrieve content\n"); - ssize_t chunk_length; - char *temp = http_read_chunk(server_sockfd, &chunk_length); - LOG(LOG_TRACE, "Received the content, %d bytes\n", (int)chunk_length); - - if (is_text_content && !is_bad_encoding && containing_forbidden_words(temp)) - { - LOG(LOG_TRACE, "Received data contains forbidden words!\n"); - char *error2 = "\n\nNet Ninny Error Page 3 for CPSC 441 Assignment 1\n\n\n\n

\nSorry, but the Web page that you were trying to access\nis inappropriate for you, based on some of the words it contains.\nThe page has been blocked to avoid insulting your intelligence.\n

\n\n

\nNet Ninny\n

\n\n\n\n\n"; - - send_to_client(client_sockfd, error2, 0, strlen(error2)); - } - else - send_to_client(client_sockfd, temp, 0, chunk_length); - free(temp); - close(server_sockfd); -} - -void start_server(char *port) -{ - printf("Starting server\n"); - - int sockfd, new_fd; - struct addrinfo hints, *servinfo, *p; - struct sockaddr_storage their_addr; - socklen_t sin_size; - int rv; - int yes = 1; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) - { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); - return; - } - - for(p = servinfo; p != NULL; p = p->ai_next) - { - if((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) - { - perror("server: socket"); - continue; - } - - if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, - sizeof(int)) == -1) - { - perror("setsockopt"); - exit(1); - } - - if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) - { - close(sockfd); - perror("server: bind"); - continue; - } - - break; - } - - if(p == NULL) - { - fprintf(stderr, "server: failed to bind\n"); - return; - } - - freeaddrinfo(servinfo); - - if(listen(sockfd, 10) == -1) - { - perror("listen"); - exit(1); - } - - printf("server: waiting for connections..\n"); - while(1) - { - sin_size = sizeof(their_addr); - new_fd = accept(sockfd, (struct sockaddr*)&their_addr, &sin_size); - if(new_fd == -1) - { - perror("accept"); - continue; - } - - printf("Receieved connection\n"); - - signal(SIGCHLD, SIG_IGN); - pid_t child_pid = fork(); - if(!child_pid) - { - handle_client(new_fd); - - close(new_fd); - exit(0); - } - close(new_fd); - } -} - -int main(int argc, char *argv[]) -{ - char *port = "8080"; - if (argc > 1) - port = argv[1]; - start_server(port); - return 0; -} - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/net.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/net.c deleted file mode 100644 index 9001036..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/net.c +++ /dev/null @@ -1,194 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "proxy.h" -#include "list.h" -#include "http_message.h" - -/* -Creates a TCP connection to the given host -and returns the socket. Returns -1 if something -fails. -*/ -int http_connect(http_request *req) -{ - char *host = (char*)list_get_key(&req->metadata_head, "Host"); - char *port = strstr(host, ":"); - - if(port == NULL) - { - // set port to default - port = calloc(3, sizeof(char)); - strncat(port, "80", 2); - - LOG(LOG_TRACE, "Using default port\n"); - } - else - { - // remove the port number from the host - host = strtok(host, ":"); - - // jump over the ':' char - port++; - - LOG(LOG_TRACE, "Using port: %s\n", port); - } - - - LOG(LOG_TRACE, "Connecting to HTTP server: %s\n", host); - - if(host == NULL) - { - LOG(LOG_ERROR, "Could not find the Host property in the metadata\n"); - return -1; - } - - struct addrinfo hints, *servinfo, *p; - int sockfd, rv; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - if((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) - { - LOG(LOG_ERROR, "Failed to lookup hostname\n"); - return -1; - } - - // loop through all the results and connect to the first we can - for(p = servinfo; p != NULL; p = p->ai_next) { - if ((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { - perror("client: socket"); - continue; - } - - if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { - close(sockfd); - perror("client: connect"); - continue; - } - - break; - } - - if (p == NULL) { - LOG(LOG_ERROR, "Failed to connect to HTTP server\n"); - return -1; - } - - return sockfd; -} - -/* -Read a HTTP header from the given socket and -returns a http_request*. -*/ -http_request *http_read_header(int sockfd) -{ - LOG(LOG_TRACE, "Reading header\n"); - http_request *req; - http_request_init(&req); - - char *line; - line = read_line(sockfd); - http_parse_method(req, line); - - while(1) - { - line = read_line(sockfd); - if(line[0] == '\r' && line[1] == '\n') - { - // We received the end of the HTTP header - LOG(LOG_TRACE, "Received header\n"); - - break; - - } - - http_parse_metadata(req, line); - - free(line); - } - - return req; -} - -/* -Read as much data as possible from the given socket -and returns it as a null terminated char pointer. Data -returned from this function must be freed somewhere else. -*/ -char *http_read_chunk(int sockfd, ssize_t *length) -{ - if(length == NULL) - { - LOG(LOG_ERROR, "The length pointer supplied to http_read_chunk is NULL\n"); - return NULL; - } - - if(sockfd == -1) - { - LOG(LOG_ERROR, "The socket given to http_read_chunk is invalid\n"); - return NULL; - } - - char *buf = malloc(sizeof(char)); - memset(buf, '\0', sizeof(char)); - char c; - int current_size = 1; - - time_t timeout = 5; - time_t start = time(NULL); - - ssize_t total_bytes = 0; - ssize_t num_bytes = 0; - - while(1) - { - // check if we should timeout - if(time(NULL) - start > timeout) - { - LOG(LOG_WARNING, "Request timed out\n"); - break; - } - - num_bytes = recv(sockfd, &c, 1, 0); - - if(num_bytes <= -1) - { - break; - } - else if(num_bytes == 0) - { - break; - } - - // reallocate the buffer so the new data will fit - buf = realloc(buf, sizeof(char)*++current_size); - buf[total_bytes] = c; - - total_bytes += num_bytes; - } - - LOG(LOG_TRACE, "Received: %d\n", (int)total_bytes); - - *length = total_bytes; - - return buf; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/net.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/net.h deleted file mode 100644 index a87a9dc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/net.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef NET_HH -#define NET_HH - -int http_connect(http_request *req); -http_request *http_read_header(int sockfd); -char *http_read_chunk(int sockfd, ssize_t *length); - -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/proxy.h b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/proxy.h deleted file mode 100644 index e73dc50..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/proxy.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef PROXY_HH -#define PROXY_HH - -#include - -#define LOG_ERROR 0 -#define LOG_WARNING 1 -#define LOG_NOTICE 2 -#define LOG_TRACE 3 - -#define ACTIVE_LEVEL 3 -#define LOG(LEVEL, MSG, ...) \ - if(LEVEL <= ACTIVE_LEVEL) { \ - printf("LOG(%d): ", LEVEL); \ - printf(MSG, ##__VA_ARGS__); \ - } \ - -extern int http_methods_len; -extern const char *http_methods[]; - -char *read_line(int sockfd); - -enum http_methods_enum { - OPTIONS, - GET, - HEAD, - POST, - PUT, - DELETE, - TRACE, - CONNECT, - UNKNOWN -}; - -enum http_versions_enum { - HTTP_VERSION_1_0, - HTTP_VERSION_1_1, - HTTP_VERSION_INVALID -}; - -typedef struct http_request -{ - enum http_methods_enum method; - enum http_versions_enum version; - const char *search_path; - - TAILQ_HEAD(METADATA_HEAD, http_metadata_item) metadata_head; -} http_request; - -typedef struct http_metadata_item -{ - const char *key; - const char *value; - - TAILQ_ENTRY(http_metadata_item) entries; -} http_metadata_item; - - -#endif diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/tests/http_message_test.c b/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/tests/http_message_test.c deleted file mode 100644 index a84057e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/1_7_2.http_proxy_prototype/HTTPProxy/tests/http_message_test.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include "../http_message.h" - -int test_parse_valid_method() -{ - printf("test_parse_valid_method - running\n"); - http_request* req; - http_request_init(&req); - char* data = "GET http://www.redd.it/hej/ HTTP/1.1\r\n"; - http_parse_method(req, data); - assert(strcmp(http_methods[req->method], "GET") == 0); - assert(req->version == HTTP_VERSION_1_1); - assert(strcmp(req->search_path, "http://www.redd.it/hej/") == 0); - http_request_destroy(req); - printf("test_parse_valid_method - ok\n"); - return 0; -} - -int test_parse_invalid_method() -{ - printf("test_parse_invalid_method - running\n"); - http_request* req; - http_request_init(&req); - char* data = "FAKE http://www.redd.it/hej/ HTTP/1.1\r\n"; - http_parse_method(req, data); - assert(strcmp(http_methods[req->method], "INVALID") == 0); - printf("test_parse_invalid_method - ok\n"); - return 0; -} - -int test_parse_invalid_http_version() -{ - printf("test_parse_invalid_http_version - running\n"); - http_request* req; - http_request_init(&req); - char* data = "GET http://www.redd.it/hej/ HTTP/2.0\r\n"; - http_parse_method(req, data); - assert(req->version == HTTP_VERSION_INVALID); - printf("test_parse_invalid_http_version - ok\n"); - return 0; -} - -int main() -{ - test_parse_valid_method(); - test_parse_invalid_method(); - test_parse_invalid_http_version(); -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/DownloadTask.h b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/DownloadTask.h deleted file mode 100644 index 915dc8d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/DownloadTask.h +++ /dev/null @@ -1,249 +0,0 @@ -/************************************************ - * - * file : DownloadTask.h - * author: bobding - * date : 2014-09-25 - * detail: - * -************************************************/ - -#ifndef _DOWNLOADTASK_H_ -#define _DOWNLOADTASK_H_ - -#include "TcpSocket.h" -#include "HttpUtils.h" - -#define MAXBUFFERSIZE 2048 - -//TcpSocket* socket; -/* -void initDownloadTask() -{ - //socket = 0; - initTcpSocket(); - //socket = new TcpSocket(); -} - -void destroyDownloadTask() -{ - if (0 != socket) - { - free(socket); - } - - socket = 0; -} -*/ - -int taskStart(const char* url, char** buffer, unsigned int* length) -{ - /*if (0 == socket) - { - LogError("[DownloadTask::Start] invalid socket, url: %s.\n", url); - return -1; - }*/ - - int ret = socketOpen(); - if (ret < 0) - { - return -1; - } - - struct HttpUrl httpUrl = ParseUrl(url); - - ret = socketConnect(httpUrl.host, httpUrl.port); - if (ret < 0) - { - return -1; - } - - ret = socketSend(httpUrl.request, strlen(httpUrl.request)); - if (ret < 0) - { - return -1; - } - - char dummy[MAXBUFFERSIZE]; - ret = socketRecv(dummy, MAXBUFFERSIZE); // receive 1st package. - if (ret <= 0) - { - LogError("[DownloadTask::Start] recv head 0 bytes, url: %s.\n", url); - return -1; - } - - dummy[ret] = '\0'; - - struct HttpHead httpHead = ParseHead(dummy, strlen(dummy)); - if (HS_FAIL == httpHead.httpState) - { - LogError("[DownloadTask::Start] recv failed, url: %s.\n", url); - return -1; - } - else if (HS_RETRY == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] retry, url: %s.\n", url); - return taskStart(url, buffer, length); - } - else if (HS_REDIR == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] redir, url: %s, location: %s.\n", url, httpHead.location); - return taskStart(httpHead.location, buffer, length); - } - - *length = httpHead.contentLength; - *buffer = (char *)malloc(*length * sizeof(char*)); - //*buffer = new char[*length]; - memset(*buffer, 0, *length); - unsigned int offset = 0; - - if (ret > httpHead.headLength) - { - memcpy((*buffer) + offset, dummy + httpHead.headLength, ret - httpHead.headLength); - offset += ret - httpHead.headLength; - } - - while ((ret = socketRecv(dummy, MAXBUFFERSIZE)) >= 0) - { - LogPrompt("[DownloadTask::Start] received: %d, %d / %d bytes.\n", ret, offset, *length); - - if (offset >= *length) - { - break; - } - - if (0 == ret) - { - continue; - } - - if (offset + ret > *length) - { - ret = *length - offset; - } - - memcpy((*buffer) + offset, dummy, ret); - - offset += ret; - } - return 0; -} - - -/* -class DownloadTask -{ -public: - DownloadTask() - { - socket = 0; - socket = new TcpSocket(); - } - - ~DownloadTask() - { - if (0 != socket) - { - delete socket; - } - - socket = 0; - } - - int Start(const char* url, char** buffer, unsigned int* length) - { - if (0 == socket) - { - LogError("[DownloadTask::Start] invalid socket, url: %s.\n", url); - return -1; - } - - int ret = socket->Open(); - if (ret < 0) - { - return -1; - } - - HttpUrl httpUrl = HttpUtils::ParseUrl(url); - - ret = socket->Connect(httpUrl.host, httpUrl.port); - if (ret < 0) - { - return -1; - } - - ret = socket->Send(httpUrl.request, strlen(httpUrl.request)); - if (ret < 0) - { - return -1; - } - - char dummy[MAXBUFFERSIZE]; - ret = socket->Recv(dummy, MAXBUFFERSIZE); // receive 1st package. - if (ret <= 0) - { - LogError("[DownloadTask::Start] recv head 0 bytes, url: %s.\n", url); - return -1; - } - - dummy[ret] = '\0'; - - HttpHead httpHead = HttpUtils::ParseHead(dummy, strlen(dummy)); - if (HS_FAIL == httpHead.httpState) - { - LogError("[DownloadTask::Start] recv failed, url: %s.\n", url); - return -1; - } - else if (HS_RETRY == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] retry, url: %s.\n", url); - return Start(url, buffer, length); - } - else if (HS_REDIR == httpHead.httpState) - { - LogWarn("[DownloadTask::Start] redir, url: %s, location: %s.\n", url, httpHead.location); - return Start(httpHead.location, buffer, length); - } - - *length = httpHead.contentLength; - *buffer = new char[*length]; - memset(*buffer, 0, *length); - unsigned int offset = 0; - - if (ret > httpHead.headLength) - { - memcpy((*buffer) + offset, dummy + httpHead.headLength, ret - httpHead.headLength); - offset += ret - httpHead.headLength; - } - - while ((ret = socket->Recv(dummy, MAXBUFFERSIZE)) >= 0) - { - LogPrompt("[DownloadTask::Start] received: %d, %d / %d bytes.\n", ret, offset, *length); - - if (offset >= *length) - { - break; - } - - if (0 == ret) - { - continue; - } - - if (offset + ret > *length) - { - ret = *length - offset; - } - - memcpy((*buffer) + offset, dummy, ret); - - offset += ret; - } - - return 0; - } - -private: - TcpSocket* socket; -}; -*/ -#endif // _DOWNLOADTASK_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/HttpUtils.h b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/HttpUtils.h deleted file mode 100644 index b65d435..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/HttpUtils.h +++ /dev/null @@ -1,249 +0,0 @@ -/************************************************ - * - * file : HttpUtils.h - * author: bobding - * date : 2014-09-25 - * detail: - * -************************************************/ - -#ifndef _HTTPUTILS_H_ -#define _HTTPUTILS_H_ - -#define MAXURLLENGTH 1024 - -struct HttpUrl -{ - char host[MAXURLLENGTH]; // host - char file[MAXURLLENGTH]; // file - unsigned short port; // port - char request[MAXURLLENGTH]; // request -}; - -enum HttpState -{ - HS_FAIL, - HS_SUCC, - HS_RETRY, - HS_REDIR, -}; - -struct HttpHead -{ - unsigned int httpCode; // http code - enum HttpState httpState; // state - unsigned int contentLength; // content length - unsigned int headLength; // head length - char location[MAXURLLENGTH];// redirection -}; - -static struct HttpUrl ParseUrl(const char* url) -{ - struct HttpUrl httpUrl; - memset(&httpUrl, 0, sizeof(struct HttpUrl)); - - unsigned int length = strlen(url); - if (length > MAXURLLENGTH) - { - LogError("[HttpUtils::ParseUrl] url is too long, url: %s.\n", url); - return httpUrl; - } - - memcpy(httpUrl.host, url, strlen(url)); - - const char* s = strchr(httpUrl.host, '/'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - memcpy(httpUrl.file, s, strlen(s)); - } - - s = strchr(httpUrl.host, ':'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - httpUrl.port = (unsigned short)atoi(s); - } - else - { - httpUrl.port = 80; - } - - snprintf(httpUrl.request, MAXURLLENGTH - 1, - "GET /%s HTTP/1.1\r\n" - "Host: %s\r\n\r\n", - httpUrl.file, httpUrl.host); - - LogPrompt("[HttpUtils::ParseUrl] host: %s, file: %s, port: %d.\n", httpUrl.host, httpUrl.file, httpUrl.port); - return httpUrl; -} - -static struct HttpHead ParseHead(const char* buffer, unsigned int length) -{ - struct HttpHead httpHead; - memset(&httpHead, 0, sizeof(struct HttpHead)); - - const char* s = strstr(buffer, "HTTP/1.1 "); - if (0 != s) - { - httpHead.httpCode = (unsigned int)atoi(s + strlen("HTTP/1.1 ")); - } - - if (200 == httpHead.httpCode || 206 == httpHead.httpCode) - { - httpHead.httpState = HS_SUCC; - } - else if (201 == httpHead.httpCode) - { - httpHead.httpState = HS_REDIR; - } - else if (202 == httpHead.httpCode) - { - httpHead.httpState = HS_RETRY; - } - else if (httpHead.httpCode >= 300 && httpHead.httpCode < 400) - { - httpHead.httpState = HS_REDIR; - } - else - { - httpHead.httpState = HS_FAIL; - } - - if (HS_REDIR == httpHead.httpState && 0 != (s = strstr(buffer, "Location: "))) - { - const char* e = strstr(s, "\r\n"); - s += strlen("Location: "); - memcpy(httpHead.location, s, (0 == e) ? strlen(s) : (e - s)); - } - - s = strstr(buffer, "Content-Length: "); - if (0 != s) - { - httpHead.contentLength = (unsigned int)atoi(s + strlen("Content-Length: ")); - } - - s = strstr(buffer, "\r\n\r\n"); - if (0 != s) - { - httpHead.headLength = s + strlen("\r\n\r\n") - buffer; - } - - LogPrompt("[HttpUtils::ParseHead] httpCode: %d, contentLength: %d, headLength: %d.\n", - httpHead.httpCode, httpHead.contentLength, httpHead.headLength); - - return httpHead; -} - - - -/* -class HttpUtils -{ -public: - static HttpUrl ParseUrl(const char* url) - { - HttpUrl httpUrl; - memset(&httpUrl, 0, sizeof(HttpUrl)); - - unsigned int length = strlen(url); - if (length > MAXURLLENGTH) - { - LogError("[HttpUtils::ParseUrl] url is too long, url: %s.\n", url); - return httpUrl; - } - - memcpy(httpUrl.host, url, strlen(url)); - - const char* s = strchr(httpUrl.host, '/'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - memcpy(httpUrl.file, s, strlen(s)); - } - - s = strchr(httpUrl.host, ':'); - if (0 != s) - { - httpUrl.host[s - httpUrl.host] = '\0'; - s++; - httpUrl.port = (unsigned short)atoi(s); - } - else - { - httpUrl.port = 80; - } - - snprintf(httpUrl.request, MAXURLLENGTH - 1, - "GET /%s HTTP/1.1\r\n" - "Host: %s\r\n\r\n", - httpUrl.file, httpUrl.host); - - LogPrompt("[HttpUtils::ParseUrl] host: %s, file: %s, port: %d.\n", httpUrl.host, httpUrl.file, httpUrl.port); - - return httpUrl; - } - - static HttpHead ParseHead(const char* buffer, unsigned int length) - { - HttpHead httpHead; - memset(&httpHead, 0, sizeof(HttpHead)); - - const char* s = strstr(buffer, "HTTP/1.1 "); - if (0 != s) - { - httpHead.httpCode = (unsigned int)atoi(s + strlen("HTTP/1.1 ")); - } - - if (200 == httpHead.httpCode || 206 == httpHead.httpCode) - { - httpHead.httpState = HS_SUCC; - } - else if (201 == httpHead.httpCode) - { - httpHead.httpState = HS_REDIR; - } - else if (202 == httpHead.httpCode) - { - httpHead.httpState = HS_RETRY; - } - else if (httpHead.httpCode >= 300 && httpHead.httpCode < 400) - { - httpHead.httpState = HS_REDIR; - } - else - { - httpHead.httpState = HS_FAIL; - } - - if (HS_REDIR == httpHead.httpState && 0 != (s = strstr(buffer, "Location: "))) - { - const char* e = strstr(s, "\r\n"); - s += strlen("Location: "); - memcpy(httpHead.location, s, (0 == e) ? strlen(s) : (e - s)); - } - - s = strstr(buffer, "Content-Length: "); - if (0 != s) - { - httpHead.contentLength = (unsigned int)atoi(s + strlen("Content-Length: ")); - } - - s = strstr(buffer, "\r\n\r\n"); - if (0 != s) - { - httpHead.headLength = s + strlen("\r\n\r\n") - buffer; - } - - LogPrompt("[HttpUtils::ParseHead] httpCode: %d, contentLength: %d, headLength: %d.\n", - httpHead.httpCode, httpHead.contentLength, httpHead.headLength); - - return httpHead; - } -}; -*/ - -#endif // _HTTPUTILS_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/LICENSE b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/LICENSE deleted file mode 100644 index feb3592..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ -Copyright (c) 2004-2013 Sergey Lyubka -Copyright (c) 2013-2015 Cesanta Software Limited -All rights reserved - -This code is dual-licensed: you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 as -published by the Free Software Foundation. For the terms of this -license, see . - -You are free to use this code under the terms of the GNU General -Public License, 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. - -Alternatively, you can license this code under a commercial -license, as set out in . diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/Log.h b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/Log.h deleted file mode 100644 index 28be3f8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/Log.h +++ /dev/null @@ -1,322 +0,0 @@ -/************************************************ - * - * file : Log.h - * author: bobding - * date : 2014-09-24 - * detail: - * -************************************************/ - -#ifndef _LOG_H_ -#define _LOG_H_ - -#include -#include -#include -#include -#include -#include - -#define LogCritical Critical -#define LogError Error -#define LogWarn Warn -#define LogPrompt Prompt - -#define LOGPATH "./1.log" - -FILE* handle; -/* -static Log* Instance() -{ - static Log instance; - return &instance; -} -*/ - -const char* FormatedTime() -{ - static char strDate[128]; - memset(strDate, 0, sizeof(strDate)); - - struct timeval tv; - int ret = gettimeofday(&tv, 0); - if (ret < 0) - { - return strDate; - } - - struct tm* pt = localtime(&tv.tv_sec); - snprintf(strDate, 127, "%d-%02d-%02d %02d:%02d:%02d.%03d", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec, (int)(tv.tv_usec / 1000)); - - return strDate; -} - -void initLog() -{ - handle = 0; - if (-1 != access(LOGPATH, F_OK)) - { - remove(LOGPATH); - } - handle = fopen(LOGPATH, "w"); -} - -void destroyLog() -{ - if (0 != handle) - { - fclose(handle); - } - - handle = 0; -} - -// flush every item -int Critical(const char* fmt, ...) -{ - initLog(); - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Critical"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - destroyLog(); - return length; -} - -// flush every item -int Error(const char* fmt, ...) -{ - initLog(); - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Error"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - destroyLog(); - return length; -} - -// flush every 100 items, careless lost -int Warn(const char* fmt, ...) -{ - initLog(); - static unsigned int maxCnt = 100; - static unsigned int curCnt = 0; - - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Warn"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - - if (++curCnt >= maxCnt) - { - fflush(handle); - curCnt = 0; - } - - printf("%s", buffer); - destroyLog(); - return length; -} - -// stdout -int Prompt(const char* fmt, ...) -{ - initLog(); - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Prompt"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - printf("%s", buffer); - destroyLog(); - return length; -} - -/* -class Log -{ -private: - FILE* handle; - -public: - static Log* Instance() - { - static Log instance; - return &instance; - } - -public: - Log() : handle(0) - { - if (-1 != access(LOGPATH, F_OK)) - { - remove(LOGPATH); - } - - handle = fopen(LOGPATH, "w"); - } - - ~Log() - { - if (0 != handle) - { - fclose(handle); - } - - handle = 0; - } - - // flush every item - int Critical(const char* fmt, ...) - { - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Critical"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - - return length; - } - - // flush every item - int Error(const char* fmt, ...) - { - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Error"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - fflush(handle); - - printf("%s", buffer); - - return length; - } - - // flush every 100 items, careless lost - int Warn(const char* fmt, ...) - { - static unsigned int maxCnt = 100; - static unsigned int curCnt = 0; - - if (0 == handle) - { - return -1; - } - - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Warn"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - fwrite(buffer, strlen(buffer), 1, handle); - - if (++curCnt >= maxCnt) - { - fflush(handle); - curCnt = 0; - } - - printf("%s", buffer); - - return length; - } - - // stdout - int Prompt(const char* fmt, ...) - { - static char buffer[128 + 1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 128, "%s [%-8s] ", FormatedTime(), "Prompt"); - - va_list ap; - va_start(ap, fmt); - int length = vsnprintf((char*)(buffer+strlen(buffer)), 1023, fmt, ap); - va_end(ap); - - printf("%s", buffer); - - return length; - } - -protected: - const char* FormatedTime() - { - static char strDate[128]; - memset(strDate, 0, sizeof(strDate)); - - struct timeval tv; - int ret = gettimeofday(&tv, 0); - if (ret < 0) - { - return strDate; - } - - struct tm* pt = localtime(&tv.tv_sec); - snprintf(strDate, 127, "%d-%02d-%02d %02d:%02d:%02d.%03d", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec, (int)(tv.tv_usec / 1000)); - - return strDate; - } -}; -*/ -#endif // _LOG_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/README.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/README.md deleted file mode 100644 index 4b4fc32..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# Mongoose Web Server - -[![Join the chat at https://gitter.im/cesanta/mongoose](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cesanta/mongoose?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -Mongoose is the most easy to use web server on the planet. A web server of choice for Web developers (PHP, Ruby, Python, etc) and Web designers. - -Mongoose is built on top of Libmongoose embedded library, which can turn -anything into a web server in 5 minutes worth of effort and few lines of code. -Libmongoose is used to serve Web GUI on embedded devices, implement RESTful -services, RPC frameworks (e.g. JSON-RPC), handle telemetry data exchange, and -perform many other tasks in various different industries including aerospace, -manufacturing, finance, research, automotive, gaming, IT. - - - * [Mailing list](http://groups.google.com/group/mongoose-users) - * [Downloads](http://cesanta.com/products.shtml) - * [Documentation](http://cesanta.com/docs.shtml) - -Check out Fossa - our [embedded multi-protocol library](https://github.com/cesanta/fossa) with TCP,UDP,HTTP,Websocket,MQTT,DNS support, designed for Internet Of Things! - -# Features - -- Works on Windows, Mac, UNIX/Linux, iPhone, Android eCos, QNX -and many other platforms -- CGI, SSI, SSL, Digest auth, Websocket, WEbDAV, Resumed download, - URL rewrite, file blacklist -- Custom error pages, Virtual hosts, IP-based ACL, Windows service, - HTTP/HTTPS client -- Simple and clean - [embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h). - The source is in single - [mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file - to make embedding easy -- Extremely lightweight, has a core of under 40kB and tiny runtime footprint -- Asynchronous, non-blocking core supporting single- or multi-threaded usage -- On the market since 2004 with over 1 million cumulative downloads -- Stable, mature and tested, has several man-years invested - in continuous improvement and refinement - -# Screenshots - -Download, double-click to start, run browser -- that's all! - -![shot1](http://cesanta.com/images/tut_sharing/tut1.png) -![shot2](http://cesanta.com/images/tut_sharing/tut2.png) - -![shot3](http://cesanta.com/images/tut_sharing/tut3.png) -![shot4](http://cesanta.com/images/tut_sharing/tut4.png) - -# Contributions - -People who have agreed to the -[Cesanta CLA](http://cesanta.com/contributors_la.html) -can make contributions. Note that the CLA isn't a copyright -_assigment_ but rather a copyright _license_. -You retain the copyright on your contributions. - -# Licensing - -Mongoose is released under commercial and -[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open -source licenses. The GPLv2 open source License does not generally permit -incorporating this software into non-open source programs. -For those customers who do not wish to comply with the GPLv2 open -source license requirements, -[Cesanta](http://cesanta.com) offers a full, -royalty-free commercial license and professional support -without any of the GPL restrictions. - -# Other products by Cesanta - -- [Fossa](http://github.com/cesanta/fossa) - Multi-protocol networking library -- [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to - secure network communications -- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator -- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression - library -- [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/TcpSocket.h b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/TcpSocket.h deleted file mode 100644 index fc20b00..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/TcpSocket.h +++ /dev/null @@ -1,246 +0,0 @@ -/************************************************ - * - * file : TcpSocket.h - * author: bobding - * date : 2014-09-25 - * detail: - * -************************************************/ - -#ifndef _TCPSOCKET_H_ -#define _TCPSOCKET_H_ - -#include -#include -#include -#include -#include -#include "Log.h" - -int sockfd; - -void initTcpSocket(){ - sockfd = -1; -} - -// return >=0 means success, otherwise failed. -int socketOpen(){ - sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sockfd < 0) - { - LogError("[Socket::Open] create socket failed: %s.\n", strerror(errno)); - } - return sockfd; -} - -// host: 127.0.0.1 or www.qq.com -// return 0 means success, otherwise failed. -int socketConnect(const char* host, unsigned short port) -{ - if (sockfd < 0) - { - LogError("[Socket::Connect] invalid sockfd.\n"); - return -1; - } - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - struct hostent* h = gethostbyname(host); - if (0 == h) - { - LogError("[Socket::Connect] gethostbyname failed: %s.\n", strerror(errno)); - return -1; - } - - addr.sin_addr = *(struct in_addr*)h->h_addr_list[0]; - - int ret = connect(sockfd, (const struct sockaddr*)&addr, sizeof(addr)); - if (ret < 0) - { - LogError("[Socket::Connect] connect failed: %s.\n", strerror(errno)); - return -1; - } - - return 0; -} - -// return send bytes, -1 means failed. -int socketSend(const char* buffer, unsigned int length) -{ - if (sockfd < 0) - { - LogError("[Socket::Send] invalid sockfd.\n"); - return -1; - } - - int ret = send(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Send] send failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; -} - -// return recv bytes, -1 means failed. -int socketRecv(char* buffer, unsigned int length) -{ - if (sockfd < 0) - { - LogError("[Socket::Recv] invalid sockfd.\n"); - return -1; - } - - int ret = recv(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Recv] recv failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; -} - -// return 0 success, otherwise failed. -int Close() -{ - int ret = close(sockfd); - if (ret < 0) - { - LogError("[Socket::Close] close socket failed: %s.\n", strerror(errno)); - } - - sockfd = -1; - - return ret; -} - -int GetSocket() -{ - return sockfd; -} - -/* -class TcpSocket -{ -public: - TcpSocket() - { - sockfd = -1; - } - - // return >=0 means success, otherwise failed. - int Open() - { - sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sockfd < 0) - { - LogError("[Socket::Open] create socket failed: %s.\n", strerror(errno)); - } - - return sockfd; - } - - // host: 127.0.0.1 or www.qq.com - // return 0 means success, otherwise failed. - int Connect(const char* host, unsigned short port) - { - if (sockfd < 0) - { - LogError("[Socket::Connect] invalid sockfd.\n"); - return -1; - } - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - struct hostent* h = gethostbyname(host); - if (0 == h) - { - LogError("[Socket::Connect] gethostbyname failed: %s.\n", strerror(errno)); - return -1; - } - - addr.sin_addr = *(struct in_addr*)h->h_addr_list[0]; - - int ret = connect(sockfd, (const struct sockaddr*)&addr, sizeof(addr)); - if (ret < 0) - { - LogError("[Socket::Connect] connect failed: %s.\n", strerror(errno)); - return -1; - } - - return 0; - } - - // return send bytes, -1 means failed. - int Send(const char* buffer, unsigned int length) - { - if (sockfd < 0) - { - LogError("[Socket::Send] invalid sockfd.\n"); - return -1; - } - - int ret = send(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Send] send failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; - } - - // return recv bytes, -1 means failed. - int Recv(char* buffer, unsigned int length) - { - if (sockfd < 0) - { - LogError("[Socket::Recv] invalid sockfd.\n"); - return -1; - } - - int ret = recv(sockfd, buffer, length, 0); - if (ret < 0) - { - LogError("[Socket::Recv] recv failed: %s.\n", strerror(errno)); - return -1; - } - - return ret; - } - - // return 0 success, otherwise failed. - int Close() - { - int ret = close(sockfd); - if (ret < 0) - { - LogError("[Socket::Close] close socket failed: %s.\n", strerror(errno)); - } - - sockfd = -1; - - return ret; - } - - int GetSocket() - { - return sockfd; - } - -private: - int sockfd; -}; -*/ - -#endif // _TCPSOCKET_H_ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/API.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/API.md deleted file mode 100644 index faf93da..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/API.md +++ /dev/null @@ -1,249 +0,0 @@ -# Mongoose API Reference - - struct mg_server *mg_create_server(void *server_param, mg_handler_t handler); - -Creates web server instance. Returns opaque instance pointer, or NULL if -there is not enough memory. `server_param`: Could be any pointer, or NULL. -This pointer will be passed -to the callback functions as `struct mg_connection::server_param` field. -A common use case is to pass `this` pointer of the C++ wrapper class -as `user_param`, to let the callback get the pointer to the C++ object. - -Note that this function doesn't make the -server instance to serve. Serving is done by `mg_poll_server()` function. -Mongoose has single-threaded, event-driven, asynchronous, non-blocking core. -When server instance is created, it contains an information about -the configuration and the state of each connection. -Server instance is capable on listening on only one port. After creation, -`struct mg_server` has a list -of active connections and configuration parameters. - -Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom -processing is required SIGPIPE, signal handler must be set up after -calling `mg_create_server()`. - -Important: Mongoose does not install `SIGCHLD` handler. If CGI is used, -`SIGCHLD` handler must be set up to reap CGI zombie processes. - - - void mg_destroy_server(struct mg_server **server); - -Deallocates web server instance, closes all pending connections, and makes -server pointer a NULL pointer. - - const char mg_set_option(struct mg_server *server, const char *name, - const char *value); - -Sets a particular server option. Note that at least one option, -`listening_port`, must be specified. To serve static files, `document_root` -must be specified too. If `document_root` option is left unset, Mongoose -will not access filesystem at all. `mg_set_option()` returns NULL if option was -set successfully, otherwise it returns human-readable error string. It is -allowed to call `mg_set_option()` by the same thread that does -`mg_poll_server()` (Mongoose thread) and change server configuration while it -is serving, in between `mg_poll_server()` calls. - - int mg_poll_server(struct mg_server *server, int milliseconds); - -Performs one iteration of IO loop by iterating over all -active connections, performing `select()` syscall on all sockets with a timeout -of `milliseconds`. When `select()` returns, Mongoose -does an IO for each socket that has data to be sent or received. Application -code must call `mg_poll_server()` in a loop. It is an error to have more then -one thread calling `mg_poll_server()`, `mg_set_option()` or any other function -that take `struct mg_server *` parameter. Mongoose does not -mutex-protect `struct mg_server *`, therefore only single thread -(Mongoose thread) should make Mongoose calls. - -`mg_poll_server()` calls user-specified event handler when certain events -occur. Sequence of events for the accepted connection is this: - - * `MG_AUTH` - Mongoose asks whether this connection is authorized. If event - handler returns `MG_FALSE`, then Mongoose does not serve the request but - sends authorization request to the client. If `MG_TRUE` is returned, - then Mongoose continues on with the request. - * `MG_REQUEST` - Mongoose asks event handler to serve the request. If - event handler serves the request by sending a reply, - it should return `MG_TRUE`. Otherwise, - it should return `MG_FALSE` which tells Mongoose that request is not - served and Mongoose should serve it. For example, event handler might - choose to serve only RESTful API requests with URIs that start with - certain prefix, and let Mongoose serve all static files. - If event handler decides to serve the request, but doesn't have - all the data at the moment, it should return `MG_MORE`. That tells - Mongoose to keep the connection open after callback returns. - - `mg_connection::connection_param` pointer is a placeholder to keep - user-specific data. For example, handler could decide to open a DB - connection and store DB connection handle in `connection_param`. - * `MG_POLL` is sent to every connection on every iteration of - `mg_poll_server()`. Event handler should return `MG_FALSE` to ignore - this event. If event handler returns `MG_TRUE`, then Mongoose assumes - that event handler has finished sending data, and Mongoose will - close the connection. - * `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back - to the client. Event handler can choose to send a reply itself, in which - case event handler must return `MG_TRUE`. Otherwise, event handler must - return `MG_FALSE`. - * `MG_CLOSE` is sent when the connection is closed. This event is used - to cleanup per-connection state stored in `connection_param` - if it was allocated. Event handler return value is ignored. - -Sequence of events for the client connection is this: - - * `MG_CONNECT` sent when Mongoose has connected to the remote host. - This event is sent to the connection initiated by `mg_connect()` call. - Connection status is held in `mg_connection::status_code`: if zero, - then connection was successful, otherwise connection was not established. - User should send a request upon successful connection. - Event handler should return `MG_TRUE` if connection was successful and - HTTP request has been sent. Otherwise, it should send `MG_FALSE`. - * `MG_REPLY` is sent when response has been received from the remote host. - If event handler sends another request, then it should return `MG_TRUE`. - Otherwise it should return `MG_FALSE` and Mongoose will close the connection. - * `MG_CLOSE` same as for the accepted connection. - - -When mongoose buffers in HTTP request and successfully parses it, it sends -`MG_REQUEST` event for GET requests immediately. For POST requests, -Mongoose delays the call until the whole POST request is buffered in memory. -POST data is available to the callback as `struct mg_connection::content`, -and POST data length is in `struct mg_connection::content_len`. - -Note that websocket connections are treated the same way. Mongoose buffers -websocket frame in memory, and calls event handler when frame is fully -buffered. Frame data is available `struct mg_connection::content`, and -data length is in `struct mg_connection::content_len`, i.e. very similar to -the POST request. `struct mg_connection::is_websocket` flag indicates -whether the request is websocket or not. Also, for websocket requests, -there is `struct mg_connection::wsbits` field which contains first byte -of the websocket frame which URI handler can examine. Note that to -reply to the websocket client, `mg_websocket_write()` should be used. -To reply to the plain HTTP client, `mg_write_data()` should be used. - -Return value: number of active connections. - - - const char **mg_get_valid_option_names(void); - -Returns a NULL-terminated array of option names and their default values. -There are two entries per option in an array: an option name followed by a -default value. A default value could be NULL. A NULL name indicates an end -of the array. - - const char *mg_get_option(const struct mg_server *server, const char *name); - -Returns the value of particular configuration parameter. If -given parameter name is not valid, NULL is returned. For valid names, return -value is guaranteed to be non-NULL. If parameter is not set, zero-length string -is returned. - - void mg_wakeup_server_ex(struct mg_server *, mg_handler_t func, - const char *fmt, ...); - -Sends string message to a server. Function `func` is called for every active -connection. String message is passed in `struct mg_connection::callback_param`. -This function is designed to push data to the connected clients, and -can be called from any thread. There is a limitation on the length of -the message, currently at 8 kilobytes. - - void mg_send_status(struct mg_connection *, int status_code); - void mg_send_header(struct mg_connection *, const char *name, - const char *value); - void mg_send_data(struct mg_connection *, const void *data, int data_len); - void mg_printf_data(struct mg_connection *, const char *format, ...); - -These functions are used to construct a response to the client. HTTP response -consists of three parts: a status line, zero or more HTTP headers, -a response body. Mongoose provides functions for all three parts: - * `mg_send_status()` is used to create status line. This function can be - called zero or once. If `mg_send_status()` is not called, then Mongoose - will send status 200 (success) implicitly. - * `mg_send_header()` adds HTTP header to the response. This function could - be called zero or more times. - * `mg_send_data()` and `mg_printf_data()` are used to send data to the - client. Note that Mongoose adds `Transfer-Encoding: chunked` header - implicitly, and sends data in chunks. Therefore, it is not necessary to - set `Content-Length` header. Note that `mg_send_data()` and - `mg_printf_data()` do not send data immediately. Instead, they spool - data in memory, and Mongoose sends that data later after URI handler - returns. If data to be sent is huge, an URI handler might - send data in pieces by saving state in - `struct mg_connection::connection_param` variable and returning `0`. Then - Mongoose will call a handler repeatedly after each socket write. - - - - void mg_send_file(struct mg_connection *, const char *path); - -Tells Mongoose to serve given file. Mongoose handles file according to -it's extensions, i.e. Mongoose will invoke CGI script if `path` has CGI -extension, it'll render SSI file if `path` has SSI extension, etc. If `path` -points to a directory, Mongoose will show directory listing. If this function -is used, no calls to `mg_send*` or `mg_printf*` functions must be made, and -event handler must return `MG_MORE`. - - size_t mg_websocket_write(struct mg_connection* conn, int opcode, - const char *data, size_t data_len); - size_t mg_websocket_printf(struct mg_connection* conn, int opcode, - const char *fmt, ...); - - -Similar to `mg_write()` and `mg_printf()`, but wraps the data into a -websocket frame with a given websocket `opcode`. - - const char *mg_get_header(const struct mg_connection *, const char *name); - -Get the value of particular HTTP header. This is a helper function. -It traverses http_headers array, and if the header is present in the array, -returns its value. If it is not present, NULL is returned. - - - int mg_get_var(const struct mg_connection *conn, const char *var_name, - char *buf, size_t buf_len); - -Gets HTTP form variable. Both POST buffer and query string are inspected. -Form variable is url-decoded and written to the buffer. On success, this -function returns the length of decoded variable. On error, -1 is returned if -variable not found, and -2 is returned if destination buffer is too small -to hold the variable. Destination buffer is guaranteed to be -'\0' - terminated if it is not NULL or zero length. - - int mg_parse_header(const char *hdr, const char *var_name, char *buf, - size_t buf_size); - -This function parses HTTP header and fetches given variable's value in a buffer. -A header should be like `x=123, y=345, z="other value"`. This function is -designed to parse Cookie headers, Authorization headers, and similar. Returns -the length of the fetched value, or 0 if variable not found. - - int mg_modify_passwords_file(const char *passwords_file_name, - const char *domain, - const char *user, - const char *password); - -Add, edit or delete the entry in the passwords file. -This function allows an application to manipulate .htpasswd files on the -fly by adding, deleting and changing user records. This is one of the -several ways of implementing authentication on the server side. -If password is not NULL, entry is added (or modified if already exists). -If password is NULL, entry is deleted. -Return: 1 on success, 0 on error. - - - int mg_parse_multipart(const char *buf, int buf_len, - char *var_name, int var_name_len, - char *file_name, int file_name_len, - const char **data, int *data_len); - -Parses a buffer that contains multipart form data. Stores chunk name -in a `var_name` buffer. If chunk is an uploaded file, then `file_name` -will have a file name. `data` and `data_len` will point to the chunk data. -Returns number of bytes to skip to the next chunk. - - struct mg_connection *mg_connect(struct mg_server *server, - const char *host, int port, int use_ssl); - -Create connection to the remote host. Returns `NULL` on error, non-null -if the connection has been scheduled for connection. Upon a connection, -Mongoose will send `MG_CONNECT` event to the event handler. diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/AndroidBuild.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/AndroidBuild.md deleted file mode 100644 index afd2152..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/AndroidBuild.md +++ /dev/null @@ -1,27 +0,0 @@ -# Mongoose Build on Android - -This is a small guide to help you run mongoose on Android. Currently it is -tested on the HTC Wildfire. If you have managed to run it on other devices -as well, please comment or drop an email in the mailing list. -Note : You dont need root access to run mongoose on Android. - -- Clone Mongoose Git repo -- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html) -- Run `/path-to-ndk/ndk-build -C /path/to/mongoose` - That should generate mongoose/lib/armeabi/mongoose -- Using the adb tool (you need to have Android SDK installed for that), - push the generated mongoose binary to `/data/local` folder on device. -- From adb shell, navigate to `/data/local` and execute `./mongoose`. -- To test if the server is running fine, visit your web-browser and - navigate to `http://127.0.0.1:8080` You should see the `Index of /` page. - -![screenshot](http://cesanta.com/images/android_build.png) - - -Notes: - -- `jni` stands for Java Native Interface. Read up on Android NDK if you want - to know how to interact with the native C functions of mongoose in Android - Java applications. -- TODO: A Java application that interacts with the native binary or a - shared library. diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/BasicWebsite.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/BasicWebsite.md deleted file mode 100644 index c5c93c7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/BasicWebsite.md +++ /dev/null @@ -1,34 +0,0 @@ -How To Create Basic Website With Mongoose -=========================================== - -## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`: - -![screenshot](http://cesanta.com/images/tut_basic/tut1.png) - -## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited. - -![screenshot](http://cesanta.com/images/tut_basic/tut2.png) - -## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML code: - -![screenshot](http://cesanta.com/images/tut_basic/tut3.png) - -## 4. Save this file as `index.html`: - -![screenshot](http://cesanta.com/images/tut_basic/tut4.png) - - -## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory: - -![screenshot](http://cesanta.com/images/tut_basic/tut5.png) - -## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop: - -![screenshot](http://cesanta.com/images/tut_basic/tut6.png) - -## 7. Click on the mongoose icon and choose "Go to my address" menu: -![screenshot](http://cesanta.com/images/tut_basic/tut7.png) - -## 8. A browser will popup displaying `index.html` file. Now, you can expand your website by adding more content. - -![screenshot](http://cesanta.com/images/tut_basic/tut8.png) diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Embed.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Embed.md deleted file mode 100644 index 8e6dfbf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Embed.md +++ /dev/null @@ -1,173 +0,0 @@ -# Mongoose Embedding Guide - -Embedding Mongoose is done in two steps: - - 1. Copy - [mongoose.c](https://raw.github.com/cesanta/mongoose/master/mongoose.c) and - [mongoose.h](https://raw.github.com/cesanta/mongoose/master/mongoose.h) - to your application's source tree and include them in the build. - 2. Somewhere in the application code, call `mg_create_server()` to create - a server, configure it with `mg_set_option()` and loop with - `mg_poll_server()` until done. Call `mg_destroy_server()` to cleanup. - -Here's a minimal application `app.c` that embeds mongoose: - - #include "mongoose.h" - - int main(void) { - struct mg_server *server = mg_create_server(NULL, NULL); - mg_set_option(server, "document_root", "."); // Serve current directory - mg_set_option(server, "listening_port", "8080"); // Open port 8080 - - for (;;) { - mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop - } - mg_destroy_server(&server); - - return 0; - } - -To compile it, put `mongoose.c`, `mongoose.h` and `app.c` into one -folder, start terminal on UNIX or Visual Studio command line prompt on Windows, -and run the following command: - - cc app.c mongoose.c -pthread -o app # on Unix - cl.exe app.c mongoose.c /TC /MD # on Windows - -When run, this simple application opens port 8080 and serves static files, -CGI files and lists directory content in the current working directory. - -It is possible to generate HTML page content. Mongoose can call user-defined -function when certain events occur. -That function is called _an event handler_, and it is the second parameter -to `mg_create_server()` function. Here is the example event handler function: - - int event_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return MG_TRUE; - default: return MG_FALSE; - } - } - -Event handler is called by Mongoose with `struct mg_connection *` -pointer and an event number. `struct mg_connection *conn` -has all information about the request: HTTP headers, POST or websocket -data buffer, etcetera. `enum mg_event ev` tells which exactly event is sent. -For each event, an event handler returns a value which tells Mongoose how -to behave. - -The sequence of events for every connection is this: - - * `MG_AUTH` - Mongoose asks whether this connection is authorized. If event - handler returns `MG_FALSE`, then Mongoose does not serve the request but - sends authorization request to the client. If `MG_TRUE` is returned, - then Mongoose continues on with the request. - * `MG_REQUEST` - Mongoose asks event handler to serve the request. If - event handler serves the request by sending a reply, - it should return `MG_TRUE`. Otherwise, - it should return `MG_FALSE` which tells Mongoose that request is not - served and Mongoose should serve it. For example, event handler might - choose to serve only RESTful API requests with URIs that start with - certain prefix, and let Mongoose serve all static files. - If event handler decides to serve the request, but doesn't have - all the data at the moment, it should return `MG_MORE`. That tells - Mongoose to keep the connection open after callback returns. - - `mg_connection::connection_param` pointer is a placeholder to keep - user-specific data. For example, handler could decide to open a DB - connection and store DB connection handle in `connection_param`. - * `MG_POLL` is sent to every connection on every iteration of - `mg_poll_server()`. Event handler should return `MG_FALSE` to ignore - this event. If event handler returns `MG_TRUE`, then Mongoose assumes - that event handler has finished sending data, and Mongoose will - close the connection. - * `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back - to the client. Event handler can choose to send a reply itself, in which - case event handler must return `MG_TRUE`. Otherwise, event handler must - return `MG_FALSE` - * `MG_CLOSE` is sent when the connection is closed. This event is used - to cleanup per-connection state stored in `connection_param` - if it was allocated. - -Let's extend our minimal application example and -create an URI that will be served by user's C code. The app will handle -`/hello` URI by showing a hello message. So, when app is run, -http://127.0.0.1:8080/hello will say hello, and here's the code: - - #include - #include "mongoose.h" - - static int event_handler(struct mg_connection *conn, enum mg_event ev) { - if (ev == MG_AUTH) { - return MG_TRUE; // Authorize all requests - } else if (ev == MG_REQUEST && !strcmp(conn->uri, "/hello")) { - mg_printf_data(conn, "%s", "Hello world"); - return MG_TRUE; // Mark as processed - } else { - return MG_FALSE; // Rest of the events are not processed - } - } - - int main(void) { - struct mg_server *server = mg_create_server(NULL, event_handler); - mg_set_option(server, "document_root", "."); - mg_set_option(server, "listening_port", "8080"); - - for (;;) { - mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop - } - mg_destroy_server(&server); - - return 0; - } - -## Example code - -Mongoose source code contains number of examples, located in the -[examples](https://github.com/cesanta/mongoose/blob/master/examples/) directory. -To build any example, go to the respective directory and run `make`. - -## Compilation flags - -Below is the list of compilation flags that enable or disable certain -features. By default, some features are enabled, and could be disabled -by setting appropriate `NO_*` flag. Features that are disabled by default -could be enabled by setting appropriate `USE_*` flag. Bare bones Mongoose -is quite small, about 30 kilobytes of compiled x86 code. Each feature adds -a couple of kilobytes to the executable size, and also has some runtime penalty. - -Note that some flags start with `NS_` prefix. This is because Mongoose uses -[Net Skeleton](http://github.com/cesanta/net_skeleton) as a low-level -networking engine. If user code has `#include `, then -all Net Skeleton functions will be available too. - - - -DMONGOOSE_NO_AUTH Disable MD5 authorization support - -DMONGOOSE_NO_CGI Disable CGI support - -DMONGOOSE_NO_DAV Disable WebDAV support - (PUT, DELETE, MKCOL, PROPFIND methods) - -DMONGOOSE_NO_DIRECTORY_LISTING Disable directory listing - -DMONGOOSE_NO_FILESYSTEM Disables all file IO, serving from memory only - -DMONGOOSE_NO_LOGGING Disable access/error logging - -DMONGOOSE_ENABLE_THREADS Enable mg_start_thread() function - -DMONGOOSE_NO_WEBSOCKET Disable WebSocket support - -DMONGOOSE_NO_USER No concept of a user on used platform. - (Platform does not provide getpwnam, setgid or setuid) - - -DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30 - -DMONGOOSE_USE_LUA Enable Lua scripting - -DMONGOOSE_USE_LUA_SQLITE3 Enable sqlite3 binding for Lua - -DMONGOOSE_USE_POST_SIZE_LIMIT=X POST requests larger than X will be - rejected, not set by default - -DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers - for static files, empty by default - - -DNS_ENABLE_DEBUG Enables debug messages on stdout, very noisy - -DNS_ENABLE_SSL Enable SSL - -DNS_ENABLE_IPV6 Enable IPv6 support - -DNS_ENABLE_HEXDUMP Enables hexdump of sent and received traffic - -DNS_STACK_SIZE=X Sets stack size to X for ns_start_thread() - -DNS_DISABLE_THREADS Disable threads support - -DNS_DISABLE_SOCKETPAIR For systems without loopback interface - -DMONGOOSE_SEND_NS_EVENTS Send Net Skeleton events to the event handler - in addition to the Mongoose events diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/FAQ.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/FAQ.md deleted file mode 100644 index 5648f5a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/FAQ.md +++ /dev/null @@ -1,45 +0,0 @@ -# Mongoose FAQ - -## My Antivirus Software reports Mongoose as a security threat - -Mongoose doesn't contain any malicious logic. Antivirus reports a -[false positive](http://en.wikipedia.org/wiki/Type_I_and_type_II_errors#False_positive_error). -This is when certain byte sequence in Mongoose accidentally matches -virus signature in the Antivirus database. - -## Download page doesn't work - -Please make sure Javascript is enabled in your browser, and that the -antivirus software is not blocking the download. - - -## MacOS message: "Mongoose.app is damaged and can’t be opened. You should move it to the Trash" - -This happens on newer MacOS systems. The reason for the message -is the fact Mongoose.app is not digitally signed. -Mongoose download procedure changes the app on the fly by injecting -user information in the binary, making any prior digital signature void. -Open "System Preferences" -> "Security" and set "Allow apps downloaded from" -to "Anywhere". Revert the settings once Mongoose is installed. - -## PHP doesn't work: getting empty page, or 'File not found' error - -The reason for that is wrong paths to the interpreter. Remember that with PHP, -correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify -full path to the PHP interpreter, e.g.: - - mongoose -cgi_interpreter /full/path/to/php-cgi - -## Mongoose fails to start - -If Mongoose exits immediately when run, this -usually indicates a syntax error in the configuration file -(named `mongoose.conf` by default) or the command-line arguments. -Syntax checking is omitted from Mongoose to keep its size low. However, -the Manual should be of help. Note: the syntax changes from time to time, -so updating the config file might be necessary after executable update. - -### Embedding with OpenSSL on Windows might fail because of calling convention - -To force Mongoose to use `__stdcall` convention, add `/Gz` compilation -flag to the Visual Studio project settings. diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/FileSharing.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/FileSharing.md deleted file mode 100644 index e21750a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/FileSharing.md +++ /dev/null @@ -1,18 +0,0 @@ -How To Share Files With Mongoose -=========================================== - -## 1. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside the directory you want to share: - -![screenshot](http://cesanta.com/images/tut_sharing/tut1.png) - -## 2. Double-click mongoose executable. A browser will start automatically, an icon will appear on a system tray in the bottom right corner of the desktop: - -![screenshot](http://cesanta.com/images/tut_sharing/tut2.png) - -## 3. Click on the mongoose icon -![screenshot](http://cesanta.com/images/tut_sharing/tut3.png) - - -## 4. Click on "Go to my address" to launch a browser locally. Or, to access a folder from another machine, launch a browser and type in the URL: - -![screenshot](http://cesanta.com/images/tut_sharing/tut4.png) diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Internals.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Internals.md deleted file mode 100644 index 2ecde5c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Internals.md +++ /dev/null @@ -1,44 +0,0 @@ -# Mongoose Internals - -Mongoose has single-threaded, event-driven, asynchronous, non-blocking core. -`mg_create_server()` creates a web server instance. An instance is a container -for the config options and list of active connections. To do the actual -serving, user must call `mg_poll_server()`, which iterates over all -active connections, performing `select()` syscall on all sockets with a -timeout of specified number of milliseconds. When `select()` returns, Mongoose -does an IO for each socket that has data to be sent or received. Application -code must call `mg_poll_server()` in a loop. - -Mongoose server instance is designed to be used by a single thread. -It is an error to have more then -one thread calling `mg_poll_server()`, `mg_set_option()` or any other function -that take `struct mg_server *` parameter. Mongoose does not -mutex-protect `struct mg_server *`, therefore the best practice is -to call server management functions from the same thread (an IO thread). -On a multi-core systems, many server instances can be created, sharing the -same listening socket and managed by separate threads (see [multi_threaded.c](https://github.com/cesanta/mongoose/blob/master/examples/multi_threaded.c)) -example. - -It is an error to pass and store `struct mg_connection *` pointers for -later use to send data. The reason is that they can be invalidated by the -next `mg_poll_server()` call. For such a task, -there is `mg_iterate_over_connections()` API -exists, which sends a callback function to the IO thread, then IO thread -calls specified function for all active connection. - -When mongoose buffers in HTTP request and successfully parses it, it calls -appropriate URI handler immediately for GET requests. For POST requests, -Mongoose delays the call until the whole POST request is buffered in memory. -POST data is available to the callback as `struct mg_connection::content`, -and POST data length is in `struct mg_connection::content_len`. - -Note that websocket connections are treated the same way. Mongoose buffers -websocket frame in memory, and calls URI handler when frame is fully -buffered. Frame data is available `struct mg_connection::content`, and -data length is in `struct mg_connection::content_len`, i.e. very similar to -the POST request. `struct mg_connection::is_websocket` flag indicates -whether the request is websocket or not. Also, for websocket requests, -there is `struct mg_connection::wsbits` field which contains first byte -of the websocket frame which URI handler can examine. Note that to -reply to the websocket client, `mg_websocket_write()` should be used. -To reply to the plain HTTP client, `mg_write()` should be used. diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Options.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Options.md deleted file mode 100644 index 116c61f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Options.md +++ /dev/null @@ -1,154 +0,0 @@ -# Mongoose Configuration Options - -### access\_control\_list -An Access Control List (ACL) allows restrictions to be put on the list of IP -addresses which have access to the web server. In the case of the Mongoose -web server, the ACL is a comma separated list of IP subnets, where each -subnet is prepended by either a `-` or a `+` sign. A plus sign means allow, -where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`, -this means to deny only that single IP address. - -Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow -all accesses. On each request the full list is traversed, and -the last match wins. Example: `$ mongoose -access_control_list -0.0.0.0/0,+192.168/16` to deny all acccesses except those from `192.168/16` subnet. Note that if the option is set, then all accesses are forbidden -by default. Thus in a previous example, `-0.0.0.0` part is not necessary. -For example, `$mongoose access_control_list +10.0.0.0/8` -means disallow all, allow subnet 10/8 only. - -To learn more about subnet masks, see the -[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork) - -Default: not set, all accesses are allowed. - -### access\_log\_file -Path to a file for access logs. Either full path, or relative to the -mongoose executable. Default: not set, no query logging is done. - -### auth_domain -Authorization realm used in `.htpasswd` authorization. Default: `mydomain.com` - -### cgi_interpreter -Path to an executable to be used use as an interpreter for __all__ CGI scripts -regardless script extension. Default: not set, Mongoose looks at -[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\). - -For example, if both PHP and perl CGIs are used, then -`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the -respective CGI scripts. Note that paths should be either full file paths, -or file paths relative to the directory where mongoose executable is located. - -If all CGIs use the same interpreter, for example they are all PHP, then -`cgi_interpreter` option can be set to the path to `php-cgi.exe` executable and -shebang line in the CGI scripts can be omitted. -**Note**: PHP scripts must use `php-cgi.exe`, not `php.exe`. - -### cgi_pattern -All files that match `cgi_pattern` are treated as CGI files. Default pattern -allows CGI files be anywhere. To restrict CGIs to a certain directory, -use `/path/to/cgi-bin/**.cgi` as a pattern. Note that **full file path** is -matched against the pattern, not the URI. - -When Mongoose starts CGI program, it creates new environment for it (in -contrast, usually child program inherits the environment from parent). Several -environment variables however are inherited from Mongoose's environment, -they are: `PATH`, `TMP`, `TEMP`, `TMPDIR`, `PERLLIB`, `MONGOOSE_CGI`. On UNIX -it is also `LD_LIBRARY_PATH`. On Windows it is also `COMSPEC`, `SYSTEMROOT`, -`SystemDrive`, `ProgramFiles`, `ProgramFiles(x86)`, `CommonProgramFiles(x86)`. - -Default: `**.cgi$|**.pl$|**.php$` - -### dav\_auth\_file -Authentication file for WebDAV mutation requests: `PUT`, `DELETE`, `MKCOL`. -The format of that file is the same as for the `.htpasswd` file -used for digest authentication. It can be created and managed by -`mongoose -A` command. Default: not set, WebDAV mutations are disallowed. - -### document_root -A directory to serve. Default: current working directory. - -### enable\_directory\_listing -Enable directory listing, either `yes` or `no`. Default: `yes`. - -### enable\_proxy -Enable proxy functionality, either `yes` or `no`. If set to `yes`, then -browsers can be configured to use Mongoose as a proxy. Default: `no`. - - -### extra\_mime\_types -Extra mime types to recognize, in form `extension1=type1,extension2=type2,...`. -Extension must include dot. Example: -`mongoose -extra_mime_types .cpp=plain/text,.java=plain/text`. Default: not set. - - -### global\_auth\_file -Path to a global passwords file, either full path or relative to the mongoose -executable. If set, per-directory `.htpasswd` files are ignored, -and all requests are authorised against that file. Use `mongoose -A` to -manage passwords, or third party utilities like -[htpasswd-generator](http://www.askapache.com/online-tools/htpasswd-generator). -Default: not set, per-directory `.htpasswd` files are respected. - -### hide\_files\_patterns -A pattern for the files to hide. Files that match the pattern will not -show up in directory listing and return `404 Not Found` if requested. Pattern -must be for a file name only, not including directory name, e.g. -`mongoose -hide_files_patterns secret.txt|even_more_secret.txt`. Default: -not set. - -### index_files -Comma-separated list of files to be treated as directory index -files. Default: `index.html,index.htm,index.cgi,index.shtml,index.php` - -### listening_port -Port to listen on. Port could be prepended by the specific IP address to bind -to, e.g. `mongoose -listening_port 127.0.0.1:8080`. Otherwise Mongoose -will bind to all addresses. To enable SSL, build Mongoose with -`-DNS_ENABLE_SSL` compilation option, and specify `listening_port` as -`ssl://PORT:SSL_CERTIFICATE.PEM`. Example SSL listener: -`mongoose -listening_port ssl://8043:ssl_cert.pem`. Note that PEM file should -be in PEM format, and must have both certificate and private key in it, -concatenated together. More than one listening port can be specified, -separated by comma, -for example `mongoose -listening_port 8080,8000`. Default: 8080. - -### run\_as\_user -Switch to given user credentials after startup. UNIX-only. This option is -required when mongoose needs to bind on privileged port on UNIX, e.g. - - $ sudo mongoose -listening_port 80 -run_as_user nobody - -Default: not set. - -### url\_rewrites -Comma-separated list of URL rewrites in the form of -`uri_pattern=file_or_directory_path`. When Mongoose receives the request, -it constructs the file name to show by combining `document_root` and the URI. -However, if the rewrite option is used and `uri_pattern` matches the -requested URI, then `document_root` is ignored. Instead, -`file_or_directory_path` is used, which should be a full path name or -a path relative to the web server's current working directory. Note that -`uri_pattern`, as all mongoose patterns, is a prefix pattern. If `uri_pattern` -is a number, then it is treated as HTTP error code, and `file_or_directory_path` -should be an URI to redirect to. Mongoose will issue `302` temporary redirect -to the specified URI with following parameters: -`?code=HTTP_ERROR_CODE&orig_uri=ORIGINAL_URI&query_string=QUERY_STRING`. - -If `uri_pattern` starts with `@` symbol, then Mongoose compares -it with the `HOST` header of the request. If they are equal, Mongoose sets -document root to `file_or_directory_path`, implementing virtual hosts support. - -Examples: - - # Redirect all accesses to `.doc` files to a special script - mongoose -url_rewrites **.doc$=/path/to/cgi-bin/handle_doc.cgi - - # Implement user home directories support - mongoose -url_rewrites /~joe/=/home/joe/,/~bill=/home/bill/ - - # Redirect 404 errors to a specific error page - mongoose -url_rewrites 404=/cgi-bin/error.cgi - - # Virtual hosts example: serve foo.com domain from different directory - mongoose -url_rewrites @foo.com=/var/www/foo.com - -Default: not set. diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/PhpWebsite.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/PhpWebsite.md deleted file mode 100644 index 3b503c6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/PhpWebsite.md +++ /dev/null @@ -1,49 +0,0 @@ -How To Create A PHP Website With Mongoose -=========================================== - -## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`: - -![screenshot](http://cesanta.com/images/tut_php/tut1.png) - -## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited. - -![screenshot](http://cesanta.com/images/tut_php/tut2.png) - -## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML / PHP code: - -![screenshot](http://cesanta.com/images/tut_php/tut3.png) - -## 4. Save this file as `index.php`: - -![screenshot](http://cesanta.com/images/tut_php/tut4.png) - - -## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory: - -![screenshot](http://cesanta.com/images/tut_php/tut5.png) - -## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop: - -![screenshot](http://cesanta.com/images/tut_php/tut6.png) - -## 7. Download PHP 5.3 zip (do NOT download PHP 5.5 cause you might have missing DLLs problem) from http://windows.php.net/download and extract it to `C:\php5` directory: -![screenshot](http://cesanta.com/images/tut_php/tut7.png) - -## 8. Click on the mongoose icon and choose "Edit Settings" menu.: -![screenshot](http://cesanta.com/images/tut_php/tut8.png) - -## 9. A settings dialog will appear. Click on `cgi_interpreter` button: - -![screenshot](http://cesanta.com/images/tut_php/tut9.png) - -## 10. Choose `C:\php5\php-cgi.exe` and click "Save Settings": - -![screenshot](http://cesanta.com/images/tut_php/tut10.png) - -## 11. Click on the mongoose icon and choose "Go to my address" menu: -![screenshot](http://cesanta.com/images/tut_php/tut11.png) - - -## 12. A browser will popup displaying `index.php`. - -![screenshot](http://cesanta.com/images/tut_php/tut12.png) diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/ReleaseNotes.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/ReleaseNotes.md deleted file mode 100644 index 10fd459..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/ReleaseNotes.md +++ /dev/null @@ -1,218 +0,0 @@ -# Mongoose Release Notes - -## Release 5.6, 2015-03-17 - -Changes in Libmongoose library: - -- Added `-dav_root` configuration option that gives an ability to mount - a different root directory (not document_root) -- Fixes for build under Win23 and MinGW -- Bugfix: Double dots removal -- Bugfix: final chunked response double-send -- Fixed compilation in 64-bit environments -- Added OS/2 compatibility -- Added `getaddrinfo()` call and `NS_ENABLE_GETADDRINFO` -- Various SSL-related fixes -- Added integer overflow protection in `iobuf_append()` and `deliver_websocket_frame()` -- Fixed NetBSD build -- Enabled `NS_ENABLE_IPV6` build for Visual Studio 2008+ -- Enhanced comma detection in `parse_header()` -- Fixed unchanged memory accesses on ARM -- Added ability to use custom memory allocator through NS_MALLOC, NS_FREE, NS_REALLOC - -Changes in Mongoose binary: - -- Added `-start_browser` option to disable automatic browser launch -- Added experimental SSL support. To listen on HTTPS port, use `ssl://PORT:SSL_CERT` format. For example, to listen on HTTP port 8080 and HTTPS port 8043, use `-listening_port 8080,ssl://8043:ssl_cert.pem` - -## Release 5.5, October 28 2014 - -Changes in Libmongoose library: - -- Added new API function: `mg_forward()` for proxying functionality -- Added new API function: `mg_send_file_data()` for sending file data -- Added new utility API functions: `mg_mmap() and mg_munmap()` -- Changed the way SSL settings are handled: removed `ssl_certificate` and - `ssl_ca_certificate` options, and instead made `listening_port` accept - `ssl://PORT:SSL_CERT:CA_CERT` notation -- Added ability to listen on multiple ports, see `listening_port` documentation -- Added `enable_proxy` option -- Added [cookie_authentication](https://github.com/cesanta/mongoose/tree/master/examples/cookie_authentication) example -- Added [websocket\_ssl\_proxy](https://github.com/cesanta/mongoose/tree/master/examples/websocket_ssl_proxy) example -- Added [http_client](https://github.com/cesanta/mongoose/tree/master/examples/http_client) example -- Increased default 'idle connection' timeout from 30 to 300 seconds -- Fixed MinGW build -- Refactored all examples, put each in it's own directory with dedicated build -- Many smaller bugfixed, including SSL, CGI, API, proxy, etc - -Changes in pre-compiled binaries: - -- Support for multiple listening ports -- Fixed CGI handling for scripts that specify interpreter in the hashbang line - -## Release 5.4, July 28 2014 - -Changes in Libmongoose library: - -- Added `hexdump_file` option for low-level request/reply debugging -- Added `mg_template()` API function for generating HTML pages from - templates with expansions -- Fixed `struct mg_connection::local_ip` handling, `mg_set_option()` - behavior with NULL values -- Added `mg_send_file()` call to send arbitrary file to the client -- Added `mg_terminate_ssl()` for SSL termination functionality -- Added HTTP proxy support, `enable_proxy` config option -- Added `mg_next()` for iterating over existing active connections -- Added client-side SSL auth, `ssl_ca_certificate` option -- Added `mg_wakeup_server_ex()` for pushing messages to existing connections -- Added `MG_WS_HANDSHAKE` and `MG_WS_CONNECT` events that are sent on - Websocket handshake is connection establishment, respectively -- Removed server-side Lua support -- Filesystem access, reading from socket/SSL performance improvements -- DAV PROPFIND memory leak fixed -- Added `big_upload.c` and enhanced `upload.c` example -- Added `proxy.c` example that demonstrates proxy functionality and SSE pushes -- Added `websocket2.c` example that shows simple web chat implementation - over websockets -- Various minor fixes - - -Changes in pre-compiled binaries: - -- Created HTML administration console -- When server is started, browser is started automatically -- Fixed directory listing bug when directory contains `#` character -- Removed built-in Lua Server Pages in the binary, and instead - added Mongoose + Lua developer bundle which has Lua Server Pages support. - That also solves external Lua modules loading problem. - - -## Release 5.3, March 10 2014 - -Changes in Libmongoose library: - - * Moved to the evented API. Updated API documentation is at - http://cesanta.com/docs/Embed.shtml - http://cesanta.com/docs/API.shtml - * Added `MG_LUA` event for exporting custom variables to the Lua environment - * Added virtual hosts capability, see `url_rewrites` option description at - http://cesanta.com/docs/Options.shtml - * Added mjpg serving example - * Cleaned up and documented HTTP client API, with unit tests - * Added `mg_wakeup_server()` to awaken `mg_poll_server()` - from another thread - * Moved Mongoose IO core to [https://github.com/cesanta/net_skeleton](Net Skeleton) - * Added connection hexdump functionality for developers - * Bug fixes - -Changes in pre-compiled binaries: - - * New awesome Mongoose logos by our designer Katrin - thanks Katrin! - Check them out at http://cesanta.com/products.shtml - * Added Lua Server Pages support to the free version, quick intro is at - http://cesanta.com/docs/Lua.shtml - * Added quick "Set shared directory" menu item to set `document_root` - * Added SSI support to the Pro version - * Removed SSL support from the Pro version - -## Release 5.2, Feb 1 2014 - - * Windows binary made fully UNICODE aware. In previous versions, - the presence of non-ASCII chars in document root, CGI script name, - or directory name might have broken Mongoose as stand-alone - or as Windows service. Now Mongoose works with non-ASCII paths properly. - Internally, Mongoose uses UTF8 encoding. When making WinAPI calls, - mongoose converts UTF8 strings to wide chars and calls UNICODE API. - * Enhanced authorization API by providing `mg_set_auth_handler()` and - `mg_authorize_digest()` - * Removed `mg_add_uri_handler()`, added `mg_set_request_handler()`. - There is only oneURI handler that handles all requests, just like in 4.x. - The reason for this change is to provide an ability to catch all URIs, - and at the same time signal Mongoose to continue handling specific URIs. - * Added `mg_parse_multipart()` API for file uploads. - Note that the restriction on uploading huge files still exists, - and will be eliminated in the next release. - * Allowing mongoose to bind to port 0, in which case it'll bind to any - random unused port. - * Moved `idle_timeout_ms` run-time option to compile-time flag - * Added asynchronous HTTP client, not documented yet. Documentation and - examples are coming in the next couple of weeks. Async Websocket client - is scheduled for the next release. See usage examples at `unit_test.c` - * Windows and MacOS pre-built binaries are now split to free and paid ones, - paid binaries include CGI, SSL, Lua, Sqlite, support and updates. - Linux pre-built binary includes all functionality and is free, and will - continue to be free. Source code for Windows and MacOS GUI is closed. - Disclaimer: source code for the command line stand-alone server, - as well as Mongoose library itself, will never be closed. - * Multiple bug fixes and minor enhancements - -## Release 5.1, Jan 10 2014 - - * CGI-related bugs where fixed, primarily for Windows platform - * Bugs on Windows related to UNICODE support were fixed - * Added a feature to support "error pages" through redirect. - Done using `-url_redirects` option, details are on - http://cesanta.com/docs/Options.shtml - -## Release 5.0, Jan 6 2014 - - * Internal core has been changed from blocking, thread-per-connection to - non-blocking, asynchronous, one thread for all. - * API modification for server creation and response creation. That allowed - keep-alive support for dynamic requests, boosting the embedded performance - to 100+ thousands requests per second on a single core - (as measured on my development MacBook laptop) - * Unified handling of POST requests and Websocket requests by putting a - payload into `conn->content`, `conn->content_len` attributes. - That simplified user code and eliminated the need of `mg_read()`, - since mongoose buffers all data prior to calling the callback - * keep-alive support is the default - * Dropped SSI support and throttling support - * Several configuration parameters are gone: - * `cgi_environment` (replaced with MONGOOSE_CGI), - * `protect_uri` (not useful) - * `ssi_pattern` (SSI support is gone) - * `throttle` (throttling support is gone) - * `error_log_file` (not used) - * `enable_keep_alive` (enabled by default) - * `listening_ports` (renamed to listening_port) - * `num_threads` (core has changed to single thread) - * `put_delete_auth_file` (renamed to dav_auth_file) - * `authentication_domain` (renamed to auth_domain) - * Due to the async, non-blocking nature of the core, few restrictions - are now in place: - * user callbacks must not block - * POST and Websocket data are now buffered, and cannot be huge - * mongoose is now capable on listening on only one port - -## Release 4.1, Oct 2013 -## Release 4.0, Oct 2013 -## Release 3.8, Sep 2013 - -## Release 3.7, Feb 2 2013 - - * Added "redirect to SSL port" functionality, e.g. if you specify - `-listening_ports 8080r,8043s` - then all requests to HTTP port 8080 will be redirected to HTTPS port 8043 - * Added `mg_download()` API, an HTTP client interface! - * Lua server pages now must output HTTP headers -- full control for Lua - * Added pre-built binary for MacOS, with initial GUI support - * API change: got rid of events, moved to struct `mg_callbacks` - * Bugfixes, thanks to contributors - - -## Release 3.7, Jan 18 2013 - * Fixed source code archive (main.c was missing) - * Extended Windows GUI functionality: - * Added "Start browser" systray popup menu item - * Enhanced configuration editor - * Renamed config options: - * `put_delete_passwords_file` -> `put_delete_auth_file` - * `global_passwords_file` -> `global_auth_file` - * `select()` changed to `poll()`, to avoid big file descriptor - `FD_SET` problem on UNIX - * Couple of bugfixes, thanks to contributors - - -Earlier release notes could be found by searching -[Mongoose mailing list](https://groups.google.com/forum/#!forum/mongoose-users) diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/SSL.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/SSL.md deleted file mode 100644 index 09f16e9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/SSL.md +++ /dev/null @@ -1,70 +0,0 @@ -# Mongoose SSL guide - -SSL is a protocol that makes web communication secure. To enable SSL -in mongoose, 2 steps are required: - - 1. Create valid SSL certificate file - 2. Append SSL certificate file path to the `listening_ports` option - -Below is the `mongoose.conf` file snippet for typical SSL setup: - - document_root www_root # Serve files in www_root directory - listening_ports 80,443:cert.pem # Listen on ports 80 and 443 - -## How to create SSL certificate file - -SSL certificate file is a text file that must contain at least two -sections: - - 1. A private key - 2. A certificate - -Both sections should be chunks of text in PEM format. When PEM file is -opened in a text editor, it looks like this: - - -----BEGIN RSA PRIVATE KEY----- - MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH - hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg= - -----END RSA PRIVATE KEY----- - -----BEGIN CERTIFICATE----- - MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB - SEGI4JSxV56lYg== - -----END CERTIFICATE----- - -Two aforementioned sections are clearly seen. Typically, those section -are bigger then in the example shown. The text between the `BEGIN` and -`END` is the text representation of binary data, a private key and a -certificate. Therefore, in order to create a certificate file, - - * private key must be converted to PEM format - * certificate must be converted to PEM format - * those two should be concatenated into a single file - -If the certificate chain in used, a chain file also needs to be -converted into PEM format and appended to the certificate file. - -## How SSL works - -SSL is a protocol that can encrypt communication between two parties. If third -party observes all messages passed by, it would be very -hard for the third party (though not impossible) to decrypt the communication. - -The idea is based on so-called public key encryption. Communicating parties -have two keys: a public key and a private key. A public key is advertised -to everybody, and it is contained in a certificate. A private key is kept -secret. Security algorithm works in a way that anybody can encrypt -a message using public key, and only private key can decrypt it. - -This is why web server needs both private key and certificate: private key -is used to decrypt incoming messages, and certificate is used to tell the -public key to the other party. When communication starts, parties exchange -their public keys, and keep private keys to themselves. Man-in-the-middle -who observes the communication is unable to decrypt the messages cause -private keys are required for decryption. - -Encryption algorithms are built on top of hard mathematical problem, which -makes it very expensive for man-in-the-middle to compute private keys. -For example, RSA algorithm is based on a mathematical problem of factorization. -It is easy to generate two very large prime numbers `P` and `Q` and make -a product `P * Q`. But given a product, it is very hard to recover these -two prime numbers - this is called factorization. diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Usage.md b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Usage.md deleted file mode 100644 index b9f7052..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/docs/Usage.md +++ /dev/null @@ -1,86 +0,0 @@ -# Mongoose User Guide - -Mongoose is small and easy to use web server built on top of -mongoose library. It is designed with maximum simplicity in mind. For example, -to share any directory, just drop mongoose executable in that directory, -double-click it (on UNIX, run it from shell) and launch a browser at -[http://localhost:8080](http://localhost:8080) Note that 'localhost' should -be changed to a machine's name if a folder is accessed from other computer. - -On Windows and Mac, Mongoose iconifies itself to the system tray when started. -Right-click on the icon to pop up a menu, where it is possible to stop -mongoose, or configure it. - -On UNIX, `mongoose` is a command line utility. Running `mongoose` in -terminal, optionally followed by configuration parameters -(`mongoose [OPTIONS]`) or configuration file name -(`mongoose [config_file_name]`) starts the -web server: - - $ mongoose -document_root /var/www # Running mongoose with cmdline options - $ mongoose /etc/my_config.txt # Running mongoose with config file - $ mongoose # Running with no parameters. This will - # serve current directory on port 8080 - -Mongoose does not detach from terminal. Pressing `Ctrl-C` keys -stops the server. - -When started, mongoose first searches for the configuration file. -If configuration file is specified explicitly in the command line, then -specified configuration file is used. -Otherwise, mongoose would search for file `mongoose.conf` in the same directory -where binary is located, and use it. Configuration file can be absent. - -Configuration file is a sequence of lines, each line containing -command line argument name and it's value. Empty lines and lines beginning -with `#` are ignored. Here is the example of `mongoose.conf` file: - - # This is a comment - document_root C:\www - listening_port 80 - ssl_certificate C:\mongoose\ssl_cert.pem - -Command line arguments are highest priority and can override -configuration file settings. For example, if `mongoose.conf` has line -`document_root /var/www`, and mongoose has been started as -`mongoose -document_root /etc`, then `/etc` directory will be used as -document root. - -Note that configuration options on the command line must start with `-`, -and their names are the same as in the config file. Exampli gratia, -the following two setups are equivalent: - - $ mongoose -listening_port 1234 -document_root /var/www - - $ cat > mongoose.conf - listening_ports 1234 - document_root /var/www - ^D - $ mongoose - -Mongoose can also be used to modify `.htpasswd` passwords file: - - $ mongoose -A .htpasswd mydomain.com user_name user_password - -Unlike other web servers, mongoose does not require CGI scripts be located in -a special directory. CGI scripts can be anywhere. CGI (and SSI) files are -recognized by the file name pattern. Mongoose uses shell-like glob -patterns. Pattern match starts at the beginning of the string, so essentially -patterns are prefix patterns. Syntax is as follows: - - ** Matches everything - * Matches everything but slash character, '/' - ? Matches any character - $ Matches the end of the string - | Matches if pattern on the left side or the right side matches. - -All other characters in the pattern match themselves. Examples: - - # Pattern Meaning - **.cgi$ Any string that ends with .cgi - /foo Any string that begins with /foo - **a$|**b$ Any string that ends with a or b - -To restrict CGI files only to `/cgi-bin/` directory, use this setting: - - $ mongoose -cgi_pattern /cgi-bin/*.cgi # Emulate /cgi-bin/ restriction diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/.gitignore b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/.gitignore deleted file mode 100644 index b883f1f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.exe diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/Makefile deleted file mode 100644 index 43483c3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -SUBDIRS = $(sort $(filter-out csharp/, $(dir $(wildcard */)))) -X = $(SUBDIRS) -ifdef WINDIR - # appending the Winsock2 library at the end of the compiler - # invocation - CFLAGS_EXTRA += -lws2_32 -endif - -.PHONY: $(SUBDIRS) - -all: $(SUBDIRS) - -$(SUBDIRS): - @$(MAKE) CFLAGS_EXTRA="$(CFLAGS_EXTRA)" -C $@ - -clean: - for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/array_vars/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/array_vars/Makefile deleted file mode 100644 index 5ce2d1d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/array_vars/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = array_vars -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -all: $(PROG) - -run: $(PROG) - ./$(PROG) - -$(PROG): $(SOURCES) Makefile - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -win: - wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe - wine $(PROG).exe - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc* diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/array_vars/array_vars.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/array_vars/array_vars.c deleted file mode 100644 index d631a7b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/array_vars/array_vars.c +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2014 Cesanta Software -// All rights reserved -// -// This example demostrates how to use array get variables using mg_get_n_var -// $Date: 2014-09-09 22:20:23 UTC $ - -#include -#include -#include "mongoose.h" - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return MG_TRUE; - case MG_REQUEST: - { - mg_printf_data(conn, "Hello! Requested URI is [%s] ", conn->uri); - char buffer[1024]; - int i, ret; - for(i=0; (ret = mg_get_var_n(conn, "foo[]", buffer, 1024, i)) > 0; i++) - mg_printf_data(conn, "\nfoo[%d] = %s", i, buffer); - - return MG_TRUE; - } - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server; - - // Create and configure the server - server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8080"); - - // Serve request. Hit Ctrl-C to terminate the program - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - - // Cleanup, and free server instance - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/big_upload/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/big_upload/Makefile deleted file mode 100644 index a47d188..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/big_upload/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = big_upload -CFLAGS = -W -Wall -pthread -I../.. -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/big_upload/big_upload.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/big_upload/big_upload.c deleted file mode 100644 index a756ddd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/big_upload/big_upload.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include "mongoose.h" - -static int handle_request(struct mg_connection *conn) { - if (strcmp(conn->uri, "/upload") == 0) { - FILE *fp = (FILE *) conn->connection_param; - if (fp != NULL) { - fwrite(conn->content, 1, conn->content_len, fp); // Write last bits - mg_printf(conn, "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "Connection: close\r\n\r\n" - "Written %ld of POST data to a temp file:\n\n", - (long) ftell(fp)); - - // Temp file will be destroyed after fclose(), do something with the - // data here -- for example, parse it and extract uploaded files. - // As an example, we just echo the whole POST buffer back to the client. - rewind(fp); - mg_send_file_data(conn, fileno(fp)); - return MG_MORE; // Tell Mongoose reply is not completed yet - } else { - mg_printf_data(conn, "%s", "Had no data to write..."); - return MG_TRUE; // Tell Mongoose we're done with this request - } - } else { - mg_printf_data(conn, "%s", - "Upload example." - "
" - "
" - "" - "
"); - return MG_TRUE; // Tell mongoose to close this connection - } -} - -// Mongoose sends MG_RECV for every received POST chunk. -// When last POST chunk is received, Mongoose sends MG_REQUEST, then MG_CLOSE. -static int handle_recv(struct mg_connection *conn) { - FILE *fp = (FILE *) conn->connection_param; - - // Open temporary file where we going to write data - if (fp == NULL && ((conn->connection_param = fp = tmpfile())) == NULL) { - return -1; // Close connection on error - } - - // Return number of bytes written to a temporary file: that is how many - // bytes we want to discard from the receive buffer - return fwrite(conn->content, 1, conn->content_len, fp); -} - -// Make sure we free all allocated resources -static int handle_close(struct mg_connection *conn) { - if (conn->connection_param != NULL) { - fclose((FILE *) conn->connection_param); - conn->connection_param = NULL; - } - return MG_TRUE; -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return MG_TRUE; - case MG_REQUEST: return handle_request(conn); - case MG_RECV: return handle_recv(conn); - case MG_CLOSE: return handle_close(conn); - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8080"); - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - - for (;;) { - mg_poll_server(server, 1000); - } - - mg_destroy_server(&server); - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/Makefile deleted file mode 100644 index 1eb0652..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = cookie_auth -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/cookie_auth.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/cookie_auth.c deleted file mode 100644 index c35e044..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/cookie_auth.c +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2014 Cesanta Software -// All rights reserved - -#include -#include -#include -#include "mongoose.h" - -static const char *s_login_uri = "/login.html"; -static const char *s_secret = ":-)"; // Must be known only to server - -static void generate_ssid(const char *user_name, const char *expiration_date, - char *ssid, size_t ssid_size) { - char hash[33]; - mg_md5(hash, user_name, ":", expiration_date, ":", s_secret, NULL); - snprintf(ssid, ssid_size, "%s|%s|%s", user_name, expiration_date, hash); -} - -static int check_auth(struct mg_connection *conn) { - char ssid[100], calculated_ssid[100], name[100], expire[100]; - - // Always authenticate requests to login page - if (strcmp(conn->uri, s_login_uri) == 0) { - return MG_TRUE; - } - - // Look for session ID in the Cookie. - // That session ID can be validated against the database that stores - // current active sessions. - mg_parse_header(mg_get_header(conn, "Cookie"), "ssid", ssid, sizeof(ssid)); - if (sscanf(ssid, "%[^|]|%[^|]|", name, expire) == 2) { - generate_ssid(name, expire, calculated_ssid, sizeof(calculated_ssid)); - if (strcmp(ssid, calculated_ssid) == 0) { - return MG_TRUE; // Authenticate - } - } - - // Auth failed, do NOT authenticate, redirect to login page - mg_printf(conn, "HTTP/1.1 302 Moved\r\nLocation: %s\r\n\r\n", s_login_uri); - return MG_FALSE; -} - -static int check_login_form_submission(struct mg_connection *conn) { - char name[100], password[100], ssid[100], expire[100], expire_epoch[100]; - - mg_get_var(conn, "name", name, sizeof(name)); - mg_get_var(conn, "password", password, sizeof(password)); - - // A real authentication mechanism should be employed here. - // Also, the whole site should be served through HTTPS. - if (strcmp(name, "Joe") == 0 && strcmp(password, "Doe") == 0) { - // Generate expiry date - time_t t = time(NULL) + 3600; // Valid for 1 hour - snprintf(expire_epoch, sizeof(expire_epoch), "%lu", (unsigned long) t); - strftime(expire, sizeof(expire), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); - generate_ssid(name, expire_epoch, ssid, sizeof(ssid)); - // Set "session id" cookie, there could be some data encoded in it. - mg_printf(conn, - "HTTP/1.1 302 Moved\r\n" - "Set-Cookie: ssid=%s; expire=\"%s\"; http-only; HttpOnly;\r\n" - "Content-Length: 0\r\n" - "Location: /\r\n\r\n", - ssid, expire); - return MG_TRUE; - } - return MG_FALSE; -} - -static int serve_request(struct mg_connection *conn) { - if (strcmp(conn->uri, s_login_uri) == 0 && - strcmp(conn->request_method, "POST") == 0) { - return check_login_form_submission(conn); - } - return MG_FALSE; // Serve files in the document_root -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return check_auth(conn); - case MG_REQUEST: return serve_request(conn); - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8080"); - mg_set_option(server, "document_root", "."); - - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/index.html deleted file mode 100644 index fc992fd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/index.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - WebSocket Test - - - - -
-

Mongoose Cookie Base Authentication

-

This is an index page. Authentication succeeded.

- - \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/login.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/login.html deleted file mode 100644 index d3ff705..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/cookie_authentication/login.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - WebSocket Test - - - - -
-

Mongoose Cookie Based Authentication

-

Use name "Joe", password "Doe" to login.

-
-
- - -
- - -
- -
-
- - \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/csharp/example.cs b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/csharp/example.cs deleted file mode 100644 index 3b0ced6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/csharp/example.cs +++ /dev/null @@ -1,43 +0,0 @@ -// This file is part of mongoose web server project, -// https://github.com/cesanta/mongoose - -using System; - -public class Program { - static private int EventHandler(IntPtr conn_ptr, int ev) { - MongooseConnection conn = (MongooseConnection) - System.Runtime.InteropServices.Marshal.PtrToStructure( - conn_ptr , typeof(MongooseConnection)); - - if (ev == 102) { - // MG_AUTH - return 1; - } else if (ev == 103) { - // MG_REQUEST - Mongoose.send_data(conn_ptr, "Hello from C#!\n"); - Mongoose.send_data(conn_ptr, "URI: " + conn.uri + "\n"); - Mongoose.send_data(conn_ptr, "HTTP Headers:\n"); - - for (int i = 0; i < conn.num_headers; i++) { - IntPtr name = conn.http_headers[i].name; - IntPtr val = conn.http_headers[i].value; - System.Runtime.InteropServices.Marshal.PtrToStringAnsi(name); - Mongoose.send_data(conn_ptr, " " + - System.Runtime.InteropServices.Marshal.PtrToStringAnsi(name) + ": " + - System.Runtime.InteropServices.Marshal.PtrToStringAnsi(val) + "\n"); - } - return 1; - } - return 0; - } - - static void Main() { - Mongoose web_server = new Mongoose(".", "9001", - new MongooseEventHandler(EventHandler)); - - Console.WriteLine("Mongoose started, press Ctrl-C to exit."); - for (;;) { - web_server.poll(1000); - } - } -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/csharp/mongoose.cs b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/csharp/mongoose.cs deleted file mode 100644 index efd2658..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/csharp/mongoose.cs +++ /dev/null @@ -1,68 +0,0 @@ -// This file is part of mongoose web server project, -// https://github.com/cesanta/mongoose - -using System; -using System.Runtime.InteropServices; - -[StructLayout(LayoutKind.Sequential)] public struct MongooseHeader { - [MarshalAs(UnmanagedType.LPTStr)] public IntPtr name; - [MarshalAs(UnmanagedType.LPTStr)] public IntPtr value; -}; - -// mongoose.h :: struct mg_connection -[StructLayout(LayoutKind.Sequential)] public struct MongooseConnection { - [MarshalAs(UnmanagedType.LPTStr)] public string request_method; - [MarshalAs(UnmanagedType.LPTStr)] public string uri; - [MarshalAs(UnmanagedType.LPTStr)] public string http_version; - [MarshalAs(UnmanagedType.LPTStr)] public string query_string; - - [MarshalAs(UnmanagedType.ByValArray,SizeConst=48)] public char[] remote_ip; - [MarshalAs(UnmanagedType.LPTStr)] public string local_ip; - [MarshalAs(UnmanagedType.U2)] public short remote_port; - [MarshalAs(UnmanagedType.U2)] public short local_port; - - [MarshalAs(UnmanagedType.SysInt)] public int num_headers; - [MarshalAs(UnmanagedType.ByValArray,SizeConst=30)] - public MongooseHeader[] http_headers; - - [MarshalAs(UnmanagedType.LPTStr)] public IntPtr content; - [MarshalAs(UnmanagedType.SysInt)] public int content_len; - - [MarshalAs(UnmanagedType.SysInt)] public int is_websocket; - [MarshalAs(UnmanagedType.SysInt)] public int status_code; - [MarshalAs(UnmanagedType.SysInt)] public int wsbits; -}; - -public delegate int MongooseEventHandler(IntPtr c, int ev); - -public class Mongoose { - public const string dll_ = "mongoose"; - private IntPtr server_; - - [DllImport(dll_)] private static extern IntPtr - mg_create_server(IntPtr user_data, MongooseEventHandler eh); - [DllImport(dll_)] private static extern int - mg_poll_server(IntPtr server, int milli); - [DllImport(dll_)] private static extern IntPtr - mg_set_option(IntPtr server, string name, string value); - [DllImport(dll_)] public static extern int - mg_send_data(IntPtr conn, string data, int length); - - public Mongoose(string document_root, - string listening_port, - MongooseEventHandler event_handler) { - server_ = mg_create_server(IntPtr.Zero, event_handler); - mg_set_option(server_, "document_root", document_root); - mg_set_option(server_, "listening_port", listening_port); - } - - public static int send_data(IntPtr conn, string data) { - return mg_send_data(conn, data, data.Length); - } - - public void poll(int milli) { - mg_poll_server(server_, milli); - } - - // TODO: add destructor and call mg_destroy_server() -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/digest_authentication/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/digest_authentication/Makefile deleted file mode 100644 index 86cd30d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/digest_authentication/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = digest_auth -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/digest_authentication/digest_auth.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/digest_authentication/digest_auth.c deleted file mode 100644 index 18835c7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/digest_authentication/digest_auth.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include "mongoose.h" - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - - if (ev == MG_AUTH) { - int result = MG_FALSE; // Not authorized - FILE *fp; - - // To populate passwords file, do - // mongoose -A my_passwords.txt mydomain.com admin admin - if ((fp = fopen("my_passwords.txt", "r")) != NULL) { - result = mg_authorize_digest(conn, fp); - fclose(fp); - } - - return result; - } - - return MG_FALSE; -} - -int main(void) { - struct mg_server *server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8080"); - mg_set_option(server, "document_root", "."); - - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/file_upload/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/file_upload/Makefile deleted file mode 100644 index bf1e51d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/file_upload/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = file_upload -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -all: $(PROG) - -run: $(PROG) - ./$(PROG) - -$(PROG): $(SOURCES) Makefile - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -win: - wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc* diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/file_upload/file_upload.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/file_upload/file_upload.c deleted file mode 100644 index 1302d0e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/file_upload/file_upload.c +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2004-2012 Sergey Lyubka -// This file is a part of mongoose project, http://github.com/valenok/mongoose - -#include -#include -#include "mongoose.h" - -static int send_index_page(struct mg_connection *conn) { - const char *data; - int data_len, ofs = 0; - char var_name[100], file_name[100]; - - mg_printf_data(conn, "%s", - "Upload example." - "
" - "
" - "
" - "" - "
"); - - while ((ofs = mg_parse_multipart(conn->content + ofs, conn->content_len - ofs, - var_name, sizeof(var_name), - file_name, sizeof(file_name), - &data, &data_len)) > 0) { - mg_printf_data(conn, "var: %s, file_name: %s, size: %d bytes
", - var_name, file_name, data_len); - } - - mg_printf_data(conn, "%s", ""); - - return MG_TRUE; -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return MG_TRUE; - case MG_REQUEST: return send_index_page(conn); - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server; - - // Create and configure the server - server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8080"); - - // Serve request. Hit Ctrl-C to terminate the program - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - - // Cleanup, and free server instance - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/form_submit/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/form_submit/Makefile deleted file mode 100644 index b233f28..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/form_submit/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = form_submit -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/form_submit/form_submit.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/form_submit/form_submit.c deleted file mode 100644 index f689311..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/form_submit/form_submit.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include "mongoose.h" - -static const char *html_form = - "POST example." - "
" - "Input 1:
" - "Input 2:
" - "" - "
"; - -static void send_reply(struct mg_connection *conn) { - char var1[500], var2[500]; - - if (strcmp(conn->uri, "/handle_post_request") == 0) { - // User has submitted a form, show submitted data and a variable value - // Parse form data. var1 and var2 are guaranteed to be NUL-terminated - mg_get_var(conn, "input_1", var1, sizeof(var1)); - mg_get_var(conn, "input_2", var2, sizeof(var2)); - - // Send reply to the client, showing submitted form values. - // POST data is in conn->content, data length is in conn->content_len - mg_send_header(conn, "Content-Type", "text/plain"); - mg_printf_data(conn, - "Submitted data: [%.*s]\n" - "Submitted data length: %d bytes\n" - "input_1: [%s]\n" - "input_2: [%s]\n", - conn->content_len, conn->content, - conn->content_len, var1, var2); - } else { - // Show HTML form. - mg_send_data(conn, html_form, strlen(html_form)); - } -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - if (ev == MG_REQUEST) { - send_reply(conn); - return MG_TRUE; - } else if (ev == MG_AUTH) { - return MG_TRUE; - } else { - return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server = mg_create_server(NULL, ev_handler); - - mg_set_option(server, "listening_port", "8080"); - - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/hello_world/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/hello_world/Makefile deleted file mode 100644 index d1384e0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/hello_world/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = hello_world -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -all: $(PROG) - -run: $(PROG) - ./$(PROG) - -$(PROG): $(SOURCES) Makefile - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -win: - wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe - wine $(PROG).exe - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc* diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/hello_world/hello_world.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/hello_world/hello_world.c deleted file mode 100644 index 9505689..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/hello_world/hello_world.c +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2014 Cesanta Software -// All rights reserved -// -// This example demostrates basic use of Mongoose embedded web server. -// $Date: 2014-09-09 22:20:23 UTC $ - -#include -#include -#include "mongoose.h" - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return MG_TRUE; - case MG_REQUEST: - mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri); - return MG_TRUE; - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server; - - // Create and configure the server - server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8080"); - - // Serve request. Hit Ctrl-C to terminate the program - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - - // Cleanup, and free server instance - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/Makefile deleted file mode 100644 index 5769bab..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = http_client -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -unix: $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp *.o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/http_client b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/http_client deleted file mode 100755 index 7d8178a..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/http_client and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/http_client.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/http_client.c deleted file mode 100644 index 41eac58..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/http_client/http_client.c +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2014 Cesanta Software -// All rights reserved -// -// This example demostrates how to connect to the remote Web server, -// download data, process it and send back a reply. - -#include -#include - -#include "mongoose.h" - -static int s_received_signal = 0; -static struct mg_server *s_server = NULL; -static const char *s_remote_addr = "glosbe.com:80"; - -static void signal_handler(int sig_num) { - signal(sig_num, signal_handler); - s_received_signal = sig_num; -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - struct mg_connection *client, *orig; - - switch (ev) { - case MG_AUTH: - return MG_TRUE; - - case MG_CONNECT: - // Send request to the remote host. - // TODO(lsm): handle connect error here. - mg_printf(conn, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", - "/gapi/translate?from=eng&dest=fra&format=json&phrase=cat", - s_remote_addr); - return MG_TRUE; - - case MG_REPLY: - // Send reply to the original connection - orig = (struct mg_connection *) conn->connection_param; - mg_send_status(orig, conn->status_code); - mg_send_header(orig, "Content-Type", "text/plain"); - mg_send_data(orig, conn->content, conn->content_len); - mg_send_data(orig, "", 0); // Last chunk: mark the end of reply - - // Disconnect connections - orig->connection_param = NULL; - conn->connection_param = NULL; - return MG_TRUE; - - case MG_REQUEST: - if ((client = mg_connect(s_server, s_remote_addr)) != NULL) { - // Interconnect requests - client->connection_param = conn; - conn->connection_param = client; - return MG_MORE; - } else { - mg_printf_data(conn, "%s", "cannot send API request"); - return MG_TRUE; - } - - default: - return MG_FALSE; - } -} - -int main(void) { - s_server = mg_create_server(NULL, ev_handler); - - mg_set_option(s_server, "listening_port", "8080"); - - // Setup signal handlers - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); - - printf("Listening on port %s\n", mg_get_option(s_server, "listening_port")); - while (s_received_signal == 0) { - mg_poll_server(s_server, 1000); - } - mg_destroy_server(&s_server); - printf("Existing on signal %d\n", s_received_signal); - - return EXIT_SUCCESS; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/mjpg_streamer/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/mjpg_streamer/Makefile deleted file mode 100644 index 35946c0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/mjpg_streamer/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = mjpg_streamer -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/mjpg_streamer/mjpg_streamer.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/mjpg_streamer/mjpg_streamer.c deleted file mode 100644 index 4bac6c1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/mjpg_streamer/mjpg_streamer.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include -#include -#include "mongoose.h" - -static void send_file(struct mg_connection *conn, const char *path) { - char buf[1024]; - struct stat st; - int n; - FILE *fp; - - if (stat(path, &st) == 0 && (fp = fopen(path, "rb")) != NULL) { - mg_printf(conn, "--w00t\r\nContent-Type: image/jpeg\r\n" - "Content-Length: %lu\r\n\r\n", (unsigned long) st.st_size); - while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { - mg_write(conn, buf, n); - } - fclose(fp); - mg_write(conn, "\r\n", 2); - } -} - -struct conn_state { - int file_index; - time_t last_poll; -}; - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - const char **file_names = (const char **) conn->server_param; - struct conn_state *state; - time_t now = time(NULL); - - switch (ev) { - - case MG_AUTH: - return MG_TRUE; - - case MG_REQUEST: - if (strcmp(conn->uri, "/stream") != 0) { - mg_send_header(conn, "Content-Type", "text/html"); - mg_printf_data(conn, "%s", - "Go to /stream for MJPG stream"); - return MG_TRUE; - } - - mg_printf(conn, "%s", - "HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n" - "Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n" - "Connection: close\r\nContent-Type: multipart/x-mixed-replace; " - "boundary=--w00t\r\n\r\n"); - - send_file(conn, file_names[0]); - - state = (struct conn_state *) malloc(sizeof(*state)); - conn->connection_param = state; - state->file_index = 1; // First file is already sent - state->last_poll = time(NULL); - return MG_MORE; - - case MG_POLL: - state = (struct conn_state *) conn->connection_param; - - if (state != NULL && now > state->last_poll) { - if (file_names[state->file_index] != NULL) { - send_file(conn, file_names[state->file_index]); - state->file_index++; - if (file_names[state->file_index] == NULL) { - return MG_TRUE; // No more images, close connection - } - } - state->last_poll = now; - } - return MG_FALSE; - - case MG_CLOSE: - free(conn->connection_param); - conn->connection_param = NULL; - return MG_FALSE; - - default: - return MG_FALSE; - } -} - -int main(int argc, char *argv[]) { - struct mg_server *server; - - if (argc < 3) { - printf("Usage: %s image1.jpg image2.jpg ...\n", argv[0]); - return 1; - } - - server = mg_create_server(&argv[1], ev_handler); - mg_set_option(server, "listening_port", "8080"); - - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/multi_threaded_server/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/multi_threaded_server/Makefile deleted file mode 100644 index 2b08db1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/multi_threaded_server/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = multi_threaded_server -CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/multi_threaded_server/multi_threaded_server.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/multi_threaded_server/multi_threaded_server.c deleted file mode 100644 index 30af3f1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/multi_threaded_server/multi_threaded_server.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "mongoose.h" - -// Start a browser and hit refresh couple of times. The replies will -// come from both server instances. -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - if (ev == MG_REQUEST) { - mg_send_header(conn, "Content-Type", "text/plain"); - mg_printf_data(conn, "This is a reply from server instance # %s", - (char *) conn->server_param); - return MG_TRUE; - } else if (ev == MG_AUTH) { - return MG_TRUE; - } else { - return MG_FALSE; - } -} - -static void *serve(void *server) { - for (;;) mg_poll_server((struct mg_server *) server, 1000); - return NULL; -} - -int main(void) { - struct mg_server *server1, *server2; - - server1 = mg_create_server((void *) "1", ev_handler); - server2 = mg_create_server((void *) "2", ev_handler); - - // Make both server1 and server2 listen on the same sockets - mg_set_option(server1, "listening_port", "8080"); - mg_copy_listeners(server1, server2); - - // server1 goes to separate thread, server 2 runs in main thread. - // IMPORTANT: NEVER LET DIFFERENT THREADS HANDLE THE SAME SERVER. - mg_start_thread(serve, server1); - mg_start_thread(serve, server2); - getchar(); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/002564bb43f116e36f8c4c.jpg b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/002564bb43f116e36f8c4c.jpg deleted file mode 100644 index 5fe56b1..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/002564bb43f116e36f8c4c.jpg and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/1.log b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/1.log deleted file mode 100644 index e69de29..0000000 diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/Makefile deleted file mode 100644 index 7a5d2f7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = proxy_server -FLAGS = -I../.. -DNS_ENABLE_SSL -CFLAGS = -W -Wall -g -O0 -pthread -lssl -DMONGOOSE_ENABLE_THREADS $(FLAGS) $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -unix: $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_server b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_server deleted file mode 100755 index e74e6c1..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_server and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_server.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_server.c deleted file mode 100644 index e2cad4a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_server.c +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2014 Cesanta Software Limited -// All rights reserved -// -// To build and run this example: -// git clone https://github.com/cesanta/net_skeleton.git -// git clone https://github.com/cesanta/mongoose.git -// cd mongoose/examples -// make proxy -// ./proxy -// -// Configure your browser to use localhost:2014 as a proxy for all protocols -// Then, navigate to https://cesanta.com - -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#define sleep(x) Sleep((x) * 1000) -#else -#include -#endif - -#include "mongoose.h" -#include "TcpSocket.h" -#include "DownloadTask.h" - -static int s_received_signal = 0; -static struct mg_server *s_server = NULL; - -#define SSE_CONNECTION ((void *) 1) - -static void elog(int do_exit, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputc('\n', stderr); - if (do_exit) exit(EXIT_FAILURE); -} - -static void signal_handler(int sig_num) { - signal(sig_num, signal_handler); - s_received_signal = sig_num; -} - -static int sse_push(struct mg_connection *conn, enum mg_event ev) { - if (ev == MG_POLL && conn->connection_param == SSE_CONNECTION) { - mg_printf(conn, "data: %s\r\n\r\n", (const char *) conn->callback_param); - } - return MG_TRUE; -} - -static void *sse_pusher_thread_func(void *param) { - while (s_received_signal == 0) { - mg_wakeup_server_ex(s_server, sse_push, "%lu %s", - (unsigned long) time(NULL), (const char *) param); - sleep(1); - } - return NULL; -} - -// Return: 1 if regular file, 2 if directory, 0 if not found -static int exists(const char *path) { - struct stat st; - return stat(path, &st) != 0 ? 0 : S_ISDIR(st.st_mode) == 0 ? 1 : 2; -} - -// Return: 1 if regular file, 2 if directory, 0 if not found -static int is_local_file(const char *uri, char *path, size_t path_len) { - snprintf(path, path_len, "%s/%s", - mg_get_option(s_server, "document_root"), uri); - return exists(path); -} - -static int try_to_serve_locally(struct mg_connection *conn) { - char path[500], buf[2000]; - int n, res; - FILE *fp = NULL; - - if ((res = is_local_file(conn->uri, path, sizeof(path))) == 2) { - strncat(path, "/index.html", sizeof(path) - strlen(path) - 1); - res = exists(path); - printf("PATH: [%s]\n", path); - } - if (res == 0) return MG_FALSE; - - if ((fp = fopen(path, "rb")) != NULL) { - printf("Serving [%s] locally \n", path); - mg_send_header(conn, "Connection", "close"); - mg_send_header(conn, "Content-Type", mg_get_mime_type(path, "text/plain")); - while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { - mg_send_data(conn, buf, n); - } - mg_send_data(conn, "", 0); - fclose(fp); - } - return fp == NULL ? MG_FALSE : MG_TRUE; -} - -static int is_resource_present_locally(const char *uri) { - char path[500]; - return is_local_file(uri, path, sizeof(path)) || strcmp(uri, "/api/sse") == 0; -} - -static int proxy_event_handler(struct mg_connection *conn, enum mg_event ev) { - static const char target_url[] = "http://cesanta.com"; - static int target_url_size = sizeof(target_url) - 1; - const char *host; - - switch (ev) { - case MG_REQUEST: - host = mg_get_header(conn, "Host"); - printf("[%s] [%s] [%s]\n", conn->request_method, conn->uri, - host == NULL ? "" : host); - if (strstr(conn->uri, "/qqq") != NULL) { - s_received_signal = SIGTERM; - } - - if(strstr(conn->uri, "/images.china.cn") != NULL) { - char* buffer = 0; - unsigned int length = 0; - - //DownloadTask task; - //int ret = task.Start("image.modoomarble.qq.com/modoomarble/data610_spr_1.zip", &buffer, &length); - int ret = taskStart("images.china.cn/attachement/jpg/site1000/20150611/002564bb43f116e36f8c4c.jpg", &buffer, &length); - - if (ret >= 0) - { - FILE* fp = fopen("002564bb43f116e36f8c4c.jpg", "w"); - fwrite(buffer, length, 1, fp); - fclose(fp); - } - - free(buffer); - } - - // Proxied HTTPS requests use "CONNECT foo.com:443" - // Proxied HTTP requests use "GET http://..... " - // Serve requests for target_url from the local FS. - if (memcmp(conn->uri, target_url, target_url_size) == 0 && - is_resource_present_locally(conn->uri + target_url_size)) { - conn->uri += target_url_size; // Leave only path in the URI - } - - if (strcmp(conn->uri, "/api/sse") == 0) { - conn->connection_param = SSE_CONNECTION; - mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n" - "Content-Type: text/event-stream\r\n" - "Cache-Control: no-cache\r\n\r\n"); - return MG_MORE; - } - - if (host != NULL && strstr(host, "cesanta") != NULL) { - return try_to_serve_locally(conn); - } - - // Enable man-in-the-middle SSL mode for oracle.com - if (!strcmp(conn->request_method, "CONNECT") && - !strcmp(host, "oracle.com")) { - mg_terminate_ssl(conn, "ssl_cert.pem"); // MUST return MG_MORE after - return MG_MORE; - } - - return MG_FALSE; - case MG_AUTH: - return MG_TRUE; - default: - return MG_FALSE; - } -} - -static void setopt(struct mg_server *s, const char *opt, const char *val) { - const char *err_msg = mg_set_option(s, opt, val); - if (err_msg != NULL) { - elog(1, "Error setting [%s]: [%s]", opt, err_msg); - } -} - -int main(int argc, char *argv[]) { - const char *port = "2014", *dump = NULL, *root = "proxy_web_root"; - int i; - - // Parse command line options - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-port") == 0 && i + 1 < argc) { - port = argv[++i]; - } else if (strcmp(argv[i], "-root") == 0 && i + 1 < argc) { - root = argv[++i]; - } else if (strcmp(argv[i], "-dump") == 0 && i + 1 < argc) { - dump = argv[++i]; - } else { - elog(1, "Usage: %s [-cert FILE] [-ca_cert FILE] [-port PORT]", argv[0]); - } - } - - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); - - // Create and configure proxy server - s_server = mg_create_server(NULL, &proxy_event_handler); - setopt(s_server, "enable_proxy", "yes"); - setopt(s_server, "document_root", root); - setopt(s_server, "listening_port", port); - setopt(s_server, "hexdump_file", dump); - - // Start two SSE pushing threads - mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_1"); - mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_2"); - - // Start serving in the main thread - printf("Starting on port %s\n", mg_get_option(s_server, "listening_port")); - while (s_received_signal == 0) { - mg_poll_server(s_server, 1000); - } - printf("Existing on signal %d\n", s_received_signal); - mg_destroy_server(&s_server); - - return EXIT_SUCCESS; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/app1/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/app1/index.html deleted file mode 100644 index 5b5c816..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/app1/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - App1 Index - - - - -

App1 index page. Served locally from the the proxy server filesystem

- -

image that references non-existent local resource. Forwarded to - the 'real' proxy target:

- - -

Google logo via HTTPS (external resource, served by remote host):

- - -

Same image via HTTP:

- - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/app2/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/app2/index.html deleted file mode 100644 index 28d4bea..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/app2/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - App2 Index - - - - -

App2 index page. Served locally from the - the proxy's filesystem.

-

- Following div shows proxy forwarding of websocket connection, served by - ws://echo.websocket.org: -

- -
- - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/index.html deleted file mode 100644 index d8343bf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/proxy_web_root/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - proxy index - - - -

proxy index page.

-
    -
  • App1 - App1 root
  • -
  • App2 - App2 root
  • -
- -

SSE pushes, done by separate threads at random times:

-
- - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/ssl_cert.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/ssl_cert.pem deleted file mode 100644 index f7e15a0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/proxy_server/ssl_cert.pem +++ /dev/null @@ -1,50 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH -hMSGCcSV6y32hzhqR5lvTViaQez+xhc58NZRu+OUgEhodRBW/vAOjpz/xdMz5HaC -EhP3E9W1pkitVseS8B5rrgJo1BfCGai1fPav1nutPq2Kj7vMy24+g460Lonf6ln1 -di4aTIRtAqXtUU6RFpPJP35PkCXbTK65O8HJSxxt/XtfoezHCU5+UIwmZGYx46UB -Wzg3IfK6bGPSiHU3pdiTol0uMPt/GUK+x4NyZJ4/ImsNAicRwMBdja4ywHKXJehH -gXBthsVIHbL21x+4ibsg9eVM/XioTV6tW3IrdwIDAQABAoIBACFfdLutmkQFBcRN -HAJNNHmmsyr0vcUOVnXTFyYeDXV67qxrYHQlOHe6LqIpKq1Mon7O2kYMnWvooFAP -trOnsS6L+qaTYJdYg2TKjgo4ubw1hZXytyB/mdExuaMSkgMgtpia+tB5lD+V+LxN -x1DesZ+veFMO3Zluyckswt4qM5yVa04YFrt31H0E1rJfIen61lidXIKYmHHWuRxK -SadjFfbcqJ6P9ZF22BOkleg5Fm5NaxJmyQynOWaAkSZa5w1XySFfRjRfsbDr64G6 -+LSG8YtRuvfxnvUNhynVPHcpE40eiPo6v8Ho6yZKXpV5klCKciodXAORsswSoGJa -N3nnu/ECgYEA6Yb2rM3QUEPIALdL8f/OzZ1GBSdiQB2WSAxzl9pR/dLF2H+0pitS -to0830mk92ppVmRVD3JGxYDRZQ56tlFXyGaCzJBMRIcsotAhBoNbjV0i9n5bLJYf -BmjU9yvWcgsTt0tr3B0FrtYyp2tCvwHqlxvFpFdUCj2oRw2uGpkhmNkCgYEA03M6 -WxFhsix3y6eVCVvShfbLBSOqp8l0qiTEty+dgVQcWN4CO/5eyaZXKxlCG9KMmKxy -Yx+YgxZrDhfaZ0cxhHGPRKEAxM3IKwT2C8/wCaSiLWXZZpTifnSD99vtOt4wEfrG -+AghNd5kamFiM9tU0AyvhJc2vdJFuXrfeC7ntM8CgYBGDA+t4cZcbRhu7ow/OKYF -kulP3nJgHP/Y+LMrl3cEldZ2jEfZmCElVNQvfd2XwTl7injhOzvzPiKRF3jDez7D -g8w0JAxceddvttJRK9GoY4l7OoeKpjUELSnEQkf+yUfOsTbXPXVY7jMfeNL6jE6b -qN7t3qv8rmXtejMBE3G6cQKBgGR5W2BMiRSlxqKx1cKlrApV87BUe1HRCyuR3xuA -d6Item7Lx1oEi7vb242yKdSYnpApWQ06xTh83Y/Ly87JaIEbiM0+h+P8OEIg0F1a -iB+86AcUX1I8KseVy+Np0HbpfwP8GrFfA5DaRPK7pXMopEtby8cAJ1XZZaI1/ZvZ -BebHAoGAcQU9WvCkT+nIp9FpXfBybYUsvgkaizMIqp66/l3GYgYAq8p1VLGvN4v5 -ec0dW58SJrCpqsM3NP78DtEzQf9OOsk+FsjBFzDU2RkeUreyt2/nQBj/2mN/+hEy -hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTA4MTIwNzEwMjUyMloXDTE4MTIwNTEwMjUyMlowRTELMAkG -A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AMDjWizj+xHXoKo0bkCkg187x5hTGXwbn44RC4TY6OSrC+Inh4TEhgnElest9oc4 -akeZb01YmkHs/sYXOfDWUbvjlIBIaHUQVv7wDo6c/8XTM+R2ghIT9xPVtaZIrVbH -kvAea64CaNQXwhmotXz2r9Z7rT6tio+7zMtuPoOOtC6J3+pZ9XYuGkyEbQKl7VFO -kRaTyT9+T5Al20yuuTvByUscbf17X6HsxwlOflCMJmRmMeOlAVs4NyHyumxj0oh1 -N6XYk6JdLjD7fxlCvseDcmSePyJrDQInEcDAXY2uMsBylyXoR4FwbYbFSB2y9tcf -uIm7IPXlTP14qE1erVtyK3cCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAW4yZdqpB -oIdiuXRosr86Sg9FiMg/cn+2OwQ0QIaA8ZBwKsc+wIIHEgXCS8J6316BGQeUvMD+ -plNe0r4GWzzmlDMdobeQ5arPRB89qd9skE6pAMdLg3FyyfEjz3A0VpskolW5VBMr -P5R7uJ1FLgH12RyAjZCWYcCRqEMOffqvyMCH6oAjyDmQOA5IssRKX/HsHntSH/HW -W7slTcP45ty1b44Nq22/ubYk0CJRQgqKOIQ3cLgPomN1jNFQbAbfVTaK1DpEysrQ -5V8a8gNW+3sVZmV6d1Mj3pN2Le62wUKuV2g6BNU7iiwcoY8HI68aRxz2hVMS+t5f -SEGI4JSxV56lYg== ------END CERTIFICATE----- ------BEGIN DH PARAMETERS----- -MEYCQQD+ef8hZ4XbdoyIpJyCTF2UrUEfX6mYDvxuS5O1UNYcslUqlj6JkA11e/yS -6DK8Z86W6mSj5CEk4IjbyEOECXH7AgEC ------END DH PARAMETERS----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/Makefile deleted file mode 100644 index 97fcf3f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = restful_api -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/index.html deleted file mode 100644 index 9051ff0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - RESTful API demo - - - - - - - -
-

RESTful API demo.

- -

- This page demonstrates how Mongoose web server could be used to implement - RESTful APIs. Enter numbers below, and press Submit. Browser will send - two numbers to /api/sum URI, Mongoose calclulates the sum of - two and returns the result. -

- -
- -
- -
-   -
- -
- - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/restful_api.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/restful_api.c deleted file mode 100644 index ff0ac83..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/restful_api/restful_api.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include "mongoose.h" - -static const char *s_no_cache_header = - "Cache-Control: max-age=0, post-check=0, " - "pre-check=0, no-store, no-cache, must-revalidate\r\n"; - -static void handle_restful_call(struct mg_connection *conn) { - char n1[100], n2[100]; - - // Get form variables - mg_get_var(conn, "n1", n1, sizeof(n1)); - mg_get_var(conn, "n2", n2, sizeof(n2)); - - mg_printf_data(conn, "{ \"result\": %lf }", strtod(n1, NULL) + strtod(n2, NULL)); -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return MG_TRUE; - case MG_REQUEST: - if (!strcmp(conn->uri, "/api/sum")) { - handle_restful_call(conn); - return MG_TRUE; - } - mg_send_file(conn, "index.html", s_no_cache_header); - return MG_MORE; - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server; - - // Create and configure the server - server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8000"); - - // Serve request. Hit Ctrl-C to terminate the program - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 1000); - } - - // Cleanup, and free server instance - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/send_file/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/send_file/Makefile deleted file mode 100644 index 4c20d6a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/send_file/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = send_file -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -all: $(PROG) - -run: $(PROG) - ./$(PROG) - -$(PROG): $(SOURCES) Makefile - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -win: - wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe - wine $(PROG).exe - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc* diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/send_file/send_file.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/send_file/send_file.c deleted file mode 100644 index 345c3af..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/send_file/send_file.c +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2014 Cesanta Software -// All rights reserved -// -// This example demostrates how to send arbitrary files to the client. - -#include "mongoose.h" - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_REQUEST: - mg_send_file(conn, "send_file.c", NULL); // Also could be a dir, or CGI - return MG_MORE; // It is important to return MG_MORE after mg_send_file! - case MG_AUTH: return MG_TRUE; - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server = mg_create_server(NULL, ev_handler); - mg_set_option(server, "listening_port", "8080"); - - printf("Starting on port %s\n", mg_get_option(server, "listening_port")); - for (;;) mg_poll_server(server, 1000); - mg_destroy_server(&server); - - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/Makefile deleted file mode 100644 index 4f9eacb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = web_server -CFLAGS = -W -Wall -I../.. -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c -OPENSSL_FLAGS = -DNS_ENABLE_SSL -lssl - -# PolarSSL paths and flags -POLARSSL_PATH = /usr/local -POLARSSLCOMPAT_PATH = ./../../../polar -SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c -INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include -LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls -CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR) -DNS_ENABLE_SSL - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -$(PROG).exe: $(SOURCES) - cl -Fo $(PROG) $(SOURCES) -nologo -MD -I../.. - -openssl: - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(OPENSSL_FLAGS) - -polarssl: - $(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/certs/cert.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/certs/cert.pem deleted file mode 100644 index f191e3c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/certs/cert.pem +++ /dev/null @@ -1,46 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC+zCCAeOgAwIBAgIJAPhB8jbL+G82MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV -BAMMCTEyNy4wLjAuMTAeFw0xNTAzMDYxMjQzMzNaFw0yNTAzMDMxMjQzMzNaMBQx -EjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALi3b3daMgzUEROKob1Caf68i+//cTRkPdBJv2cOBak21CdQzY0Nvx73GLzf -5TKB347BCHNbYRKGJXDbYdmFp20/WeBHkY7RS3Ad2Q5lzyx66u9PxNx7hJIiqBgF -58VU+E3o/I+o8QNIoOT+wtCiq3Nwkp+zGBJmS32rzMEV9bcKxSzMrkfRhF+XAREd -DwM9vfPg6WRb/b+vv06uvVwcw390RprLautGfBdaRddVYkIAKJGRRTqZAvTRFW1J -FcIVOxlN+iA7qP7xjr3tUP78qMmlu0MXsHrUR2cgfveZK2sdUW5G804yHsU5sC8l -FbtLKMEOyLsk2bEIScOXgum7g2sCAwEAAaNQME4wHQYDVR0OBBYEFHtLzUqAsXkH -Il8S5sMhJuVhRJLdMB8GA1UdIwQYMBaAFHtLzUqAsXkHIl8S5sMhJuVhRJLdMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEzHc0AOr+qs0OFvWMfcSMi7 -O/aYlLS6f7Sos+lli69+61EcmCTJVarVeAVUsAoqmzBKDbeOpAK1hGX6/GGcXjR2 -BmuU0hUKyX9l1lwdMKU45BayH/riElwnvAyj2GxKoPpdIjlHns4SAITOCUx9NfpM -agd7kjolton0ZQ5DI/2a43PkqHv1lY4Dp60wJlxit9U68bsGOycCJ/BsAyrPROb2 -D1MkpMBIdfHc8uxRywM3/l9buFX8yrrMUGOYKgfjDwdzbj0iwIixoGpHL7IfeBtu -dvGO/g2rEhbtAP+xIgOR3GvzqjZh30er3no7zjDMn65tTME18Aq3tBQY7vPDKms= ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4t293WjIM1BET -iqG9Qmn+vIvv/3E0ZD3QSb9nDgWpNtQnUM2NDb8e9xi83+Uygd+OwQhzW2EShiVw -22HZhadtP1ngR5GO0UtwHdkOZc8seurvT8Tce4SSIqgYBefFVPhN6PyPqPEDSKDk -/sLQoqtzcJKfsxgSZkt9q8zBFfW3CsUszK5H0YRflwERHQ8DPb3z4OlkW/2/r79O -rr1cHMN/dEaay2rrRnwXWkXXVWJCACiRkUU6mQL00RVtSRXCFTsZTfogO6j+8Y69 -7VD+/KjJpbtDF7B61EdnIH73mStrHVFuRvNOMh7FObAvJRW7SyjBDsi7JNmxCEnD -l4Lpu4NrAgMBAAECggEAaFuqbAHXOQwuwZ2XFzgIblTTsrncmT7w9VZU/sIbTKif -X771AnX7vmDX5w2PjeN2DE7emV3NEAwd5w7qz1wFZWFfQ6jrgYaZWjRixxGZ5IVl -aeLlU7OtCGrwEPJ1KTWCO3IgDoHh+Hr1+6o7Imhk+QlmrTcfqHWGvO9s9MGVWt2S -RLAnSTFiOe5brdJnmlqq1sKZmnLmpydBaPUOYpZGAgRasrjdMZB+lZOazd1x23/5 -GAcm0rDREMnO9b2Jt+TNEZHT6d5KpVoExztZEZj8QCLXoic/SpFIqHGtpNlQXa+d -BVqgQbIYjO8ldldxZ8YIyJDVF+9e/uBBwu6jBIIsEQKBgQDspEHCyyuh4LG+7BbZ -eXlsfCxPTM6K9w31ZwHAwRtAuGqrOrE+pFJG9CEsFZbAI1aOGmZZdjexuSMcOlXl -TIVJTQHoFtoGEsanYEXO4O1t02Ab/DCYSpXusXUraRBRPpsTC77Sh5mxLUNd23d9 -NhnDBuwChAmC+IYexjkXeqPYFwKBgQDH08PEd+2PVo4MD8UVKUlEcgoyCr6ESiyp -HfYyhhfd5x3DbZLoKCkunDfBs/hakQk8DA2nn4tl4ZjfmzXmX0EBx+E5YTdYshW7 -ZcjN5x64B5PEOAR/NZA6agNlp3XGXXXgX+gnN6pgE49eVU22nZ4G+QBKD6NcCviB -LBPUxMbvzQKBgHgZYRqonGtaqzsXfP1AjmSFnMNeWtDiU95BOf2Gw/sT3WcrsXr2 -UJ+cFR3XkxvOk4YpVdp/igKT0ILqBGAMdvTdtWMB/gLpEpMt5B/7veRoS7XIRy1z -ZSawP6QZfWOOX4vKAT29/j2SmEcRNFKC245EfBFGy8EBuqfxuFX3MyJfAoGBAJ0y -tjsErVmpma1baosvI3g4zlR3p1CimWehLmCopHXorr1iocMIdP0535L+ZU258y3N -vaA0HpFTW9PsYgaMwLMJ7uAY3lVkIzx84e849i2HqHMgLkl0dbW+WFXL2xblxylv -yU2wuNNED/EB4lTawcpycAvTKYvrBXt4lVE4S9exAoGAGl6vZV3zyw4jpIw4uDfk -LTPYUrghFDDGKExyeOnC/W9pqR2veqzfBz02C3jqwhewoqgAcnNc2sg0rJmM+6Oz -Z2mmGZTHO9xR++7+W7e8AkQBbS6TB8a+7yNcM4USLP+b9sX5N+8gFhFs9tG7j/no -G44qLsJ/yve7/QsOA37uEMs= ------END PRIVATE KEY----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/index.html deleted file mode 100644 index 3eca91b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/index.html +++ /dev/null @@ -1,5 +0,0 @@ - - -

helloworld

- - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/web_server b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/web_server deleted file mode 100755 index 94f5500..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/web_server and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/web_server.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/web_server.c deleted file mode 100644 index 4d256a8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/web_server/web_server.c +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright (c) 2004-2013 Sergey Lyubka -// Copyright (c) 2013-2014 Cesanta Software Limited - -#undef UNICODE // Use ANSI WinAPI functions -#undef _UNICODE // Use multibyte encoding on Windows -#define _MBCS // Use multibyte encoding on Windows -#define _WIN32_WINNT 0x500 // Enable MIIM_BITMAP -#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 -#define _XOPEN_SOURCE 600 // For PATH_MAX on linux -#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mongoose.h" - -#ifdef _WIN32 -#include -#include // For chdir() -#include -#include - -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif - -#ifndef S_ISDIR -#define S_ISDIR(x) ((x) & _S_IFDIR) -#endif - -#define DIRSEP '\\' -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#ifndef sleep -#define sleep(x) Sleep((x) * 1000) -#endif -#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size)) -#define SIGCHLD 0 -typedef struct _stat file_stat_t; -#define stat(x, y) _stat((x), (y)) -#else -typedef struct stat file_stat_t; -#include -#include - -#ifdef IOS -#include -#endif - -#define DIRSEP '/' -#define __cdecl -#define abs_path(rel, abs, abs_size) realpath((rel), (abs)) -#endif // _WIN32 - -#define MAX_OPTIONS 100 -#define MAX_CONF_FILE_LINE_SIZE (8 * 1024) - -#ifndef MVER -#define MVER MONGOOSE_VERSION -#endif - -static int exit_flag; -static char server_name[50]; // Set by init_server_name() -static char s_config_file[PATH_MAX]; // Set by process_command_line_arguments -static struct mg_server *server; // Set by start_mongoose() -static const char *s_default_document_root = "."; -static const char *s_default_listening_port = "8080"; -static char **s_argv = { NULL }; - -static void set_options(char *argv[]); - -#if !defined(CONFIG_FILE) -#define CONFIG_FILE "mongoose.conf" -#endif /* !CONFIG_FILE */ - -static void __cdecl signal_handler(int sig_num) { - // Reinstantiate signal handler - signal(sig_num, signal_handler); - -#ifndef _WIN32 - // Do not do the trick with ignoring SIGCHLD, cause not all OSes (e.g. QNX) - // reap zombies if SIGCHLD is ignored. On QNX, for example, waitpid() - // fails if SIGCHLD is ignored, making system() non-functional. - if (sig_num == SIGCHLD) { - do {} while (waitpid(-1, &sig_num, WNOHANG) > 0); - } else -#endif - { exit_flag = sig_num; } -} - -static void vnotify(const char *fmt, va_list ap, int must_exit) { - vfprintf(stderr, fmt, ap); - fputc('\n', stderr); - if (must_exit) { - exit(EXIT_FAILURE); - } -} - -static void notify(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vnotify(fmt, ap, 0); - va_end(ap); -} - -static void die(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vnotify(fmt, ap, 1); - va_end(ap); -} - -static void show_usage_and_exit(void) { - const char **names; - int i; - - fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built on %s\n", - MVER, __DATE__); - fprintf(stderr, "Usage:\n"); -#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM) - fprintf(stderr, " mongoose -A \n"); -#endif - fprintf(stderr, " mongoose [config_file]\n"); - fprintf(stderr, " mongoose [-option value ...]\n"); - fprintf(stderr, "\nOPTIONS:\n"); - - names = mg_get_valid_option_names(); - for (i = 0; names[i] != NULL; i += 2) { - fprintf(stderr, " -%s %s\n", - names[i], names[i + 1] == NULL ? "" : names[i + 1]); - } - exit(EXIT_FAILURE); -} - -#define EV_HANDLER NULL - -static char *sdup(const char *str) { - char *p; - if ((p = (char *) malloc(strlen(str) + 1)) != NULL) { - strcpy(p, str); - } - return p; -} - -static void set_option(char **options, const char *name, const char *value) { - int i; - - for (i = 0; i < MAX_OPTIONS - 3; i++) { - if (options[i] == NULL) { - options[i] = sdup(name); - options[i + 1] = sdup(value); - options[i + 2] = NULL; - break; - } else if (!strcmp(options[i], name)) { - free(options[i + 1]); - options[i + 1] = sdup(value); - break; - } - } - - if (i == MAX_OPTIONS - 3) { - die("%s", "Too many options specified"); - } -} - -static void process_command_line_arguments(char *argv[], char **options) { - char line[MAX_CONF_FILE_LINE_SIZE], opt[sizeof(line)], val[sizeof(line)], - *p, cpath[PATH_MAX]; - FILE *fp = NULL; - size_t i, cmd_line_opts_start = 1, line_no = 0; - - // Should we use a config file ? - if (argv[1] != NULL && argv[1][0] != '-') { - snprintf(cpath, sizeof(cpath), "%s", argv[1]); - cmd_line_opts_start = 2; - } else if ((p = strrchr(argv[0], DIRSEP)) == NULL) { - // No command line flags specified. Look where binary lives - snprintf(cpath, sizeof(cpath), "%s", CONFIG_FILE); - } else { - snprintf(cpath, sizeof(cpath), "%.*s%c%s", - (int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE); - } - abs_path(cpath, s_config_file, sizeof(s_config_file)); - - fp = fopen(s_config_file, "r"); - - // If config file was set in command line and open failed, die - if (cmd_line_opts_start == 2 && fp == NULL) { - die("Cannot open config file %s: %s", s_config_file, strerror(errno)); - } - - // Load config file settings first - if (fp != NULL) { - fprintf(stderr, "Loading config file %s\n", s_config_file); - - // Loop over the lines in config file - while (fgets(line, sizeof(line), fp) != NULL) { - line_no++; - - // Ignore empty lines and comments - for (i = 0; isspace(* (unsigned char *) &line[i]); ) i++; - if (line[i] == '#' || line[i] == '\0') { - continue; - } - - if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) { - printf("%s: line %d is invalid, ignoring it:\n %s", - s_config_file, (int) line_no, line); - } else { - set_option(options, opt, val); - } - } - - fclose(fp); - } - - // If we're under MacOS and started by launchd, then the second - // argument is process serial number, -psn_..... - // In this case, don't process arguments at all. - if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) { - // Handle command line flags. - // They override config file and default settings. - for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) { - if (argv[i][0] != '-' || argv[i + 1] == NULL) { - show_usage_and_exit(); - } - set_option(options, &argv[i][1], argv[i + 1]); - } - } -} - -static void init_server_name(void) { - const char *descr = ""; - snprintf(server_name, sizeof(server_name), "Mongoose web server v.%s%s", - MVER, descr); -} - -static int is_path_absolute(const char *path) { -#ifdef _WIN32 - return path != NULL && - ((path[0] == '\\' && path[1] == '\\') || // UNC path, e.g. \\server\dir - (isalpha(path[0]) && path[1] == ':' && path[2] == '\\')); // E.g. X:\dir -#else - return path != NULL && path[0] == '/'; -#endif -} - -static char *get_option(char **options, const char *option_name) { - int i; - - for (i = 0; options[i] != NULL; i++) - if (!strcmp(options[i], option_name)) - return options[i + 1]; - - return NULL; -} - -static void *serving_thread_func(void *param) { - struct mg_server *srv = (struct mg_server *) param; - while (exit_flag == 0) { - mg_poll_server(srv, 1000); - } - return NULL; -} - -static int path_exists(const char *path, int is_dir) { - file_stat_t st; - return path == NULL || (stat(path, &st) == 0 && - ((S_ISDIR(st.st_mode) ? 1 : 0) == is_dir)); -} - -static void verify_existence(char **options, const char *name, int is_dir) { - const char *path = get_option(options, name); - if (!path_exists(path, is_dir)) { - notify("Invalid path for %s: [%s]: (%s). Make sure that path is either " - "absolute, or it is relative to mongoose executable.", - name, path, strerror(errno)); - } -} - -static void set_absolute_path(char *options[], const char *option_name) { - char path[PATH_MAX], abs[PATH_MAX], *option_value; - const char *p; - - // Check whether option is already set - option_value = get_option(options, option_name); - - // If option is already set and it is an absolute path, - // leave it as it is -- it's already absolute. - if (option_value != NULL && !is_path_absolute(option_value)) { - // Not absolute. Use the directory where mongoose executable lives - // be the relative directory for everything. - // Extract mongoose executable directory into path. - if ((p = strrchr(s_config_file, DIRSEP)) == NULL) { - getcwd(path, sizeof(path)); - } else { - snprintf(path, sizeof(path), "%.*s", (int) (p - s_config_file), - s_config_file); - } - - strncat(path, "/", sizeof(path) - 1); - strncat(path, option_value, sizeof(path) - 1); - - // Absolutize the path, and set the option - abs_path(path, abs, sizeof(abs)); - set_option(options, option_name, abs); - } -} - -#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM) -int modify_passwords_file(const char *fname, const char *domain, - const char *user, const char *pass) { - int found; - char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX]; - FILE *fp, *fp2; - - found = 0; - fp = fp2 = NULL; - - // Regard empty password as no password - remove user record. - if (pass != NULL && pass[0] == '\0') { - pass = NULL; - } - - (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname); - - // Create the file if does not exist - if ((fp = fopen(fname, "a+")) != NULL) { - fclose(fp); - } - - // Open the given file and temporary file - if ((fp = fopen(fname, "r")) == NULL) { - return 0; - } else if ((fp2 = fopen(tmp, "w+")) == NULL) { - fclose(fp); - return 0; - } - - // Copy the stuff to temporary file - while (fgets(line, sizeof(line), fp) != NULL) { - if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) { - continue; - } - - if (!strcmp(u, user) && !strcmp(d, domain)) { - found++; - if (pass != NULL) { - mg_md5(ha1, user, ":", domain, ":", pass, NULL); - fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); - } - } else { - fprintf(fp2, "%s", line); - } - } - - // If new user, just add it - if (!found && pass != NULL) { - mg_md5(ha1, user, ":", domain, ":", pass, NULL); - fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); - } - - // Close files - fclose(fp); - fclose(fp2); - - // Put the temp file in place of real file - remove(fname); - rename(tmp, fname); - - return 1; -} -#endif - -static void start_mongoose(int argc, char *argv[]) { - s_argv = argv; - if ((server = mg_create_server(NULL, EV_HANDLER)) == NULL) { - die("%s", "Failed to start Mongoose."); - } - -#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM) - // Edit passwords file if -A option is specified - if (argc > 1 && !strcmp(argv[1], "-A")) { - if (argc != 6) { - show_usage_and_exit(); - } - exit(modify_passwords_file(argv[2], argv[3], argv[4], argv[5]) ? - EXIT_SUCCESS : EXIT_FAILURE); - } -#endif - - // Show usage if -h or --help options are specified - if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { - show_usage_and_exit(); - } - set_options(argv); -} - -static void set_options(char *argv[]) { - char *options[MAX_OPTIONS]; - int i; - - options[0] = NULL; - set_option(options, "document_root", s_default_document_root); - set_option(options, "listening_port", s_default_listening_port); - - // Update config based on command line arguments - process_command_line_arguments(argv, options); - - // Make sure we have absolute paths for files and directories - // https://github.com/valenok/mongoose/issues/181 - set_absolute_path(options, "document_root"); - set_absolute_path(options, "dav_auth_file"); - set_absolute_path(options, "cgi_interpreter"); - set_absolute_path(options, "access_log_file"); - set_absolute_path(options, "global_auth_file"); - set_absolute_path(options, "ssl_certificate"); - - if (!path_exists(get_option(options, "document_root"), 1)) { - set_option(options, "document_root", s_default_document_root); - set_absolute_path(options, "document_root"); - notify("Setting document_root to [%s]", - mg_get_option(server, "document_root")); - } - - // Make extra verification for certain options - verify_existence(options, "document_root", 1); - verify_existence(options, "cgi_interpreter", 0); - verify_existence(options, "ssl_certificate", 0); - - for (i = 0; options[i] != NULL; i += 2) { - const char *msg = mg_set_option(server, options[i], options[i + 1]); - if (msg != NULL) { - notify("Failed to set option [%s] to [%s]: %s", - options[i], options[i + 1], msg); - if (!strcmp(options[i], "listening_port")) { - mg_set_option(server, "listening_port", s_default_listening_port); - notify("Setting %s to [%s]", options[i], s_default_listening_port); - } - } - free(options[i]); - free(options[i + 1]); - } - - // Change current working directory to document root. This way, - // scripts can use relative paths. - chdir(mg_get_option(server, "document_root")); - -#if 0 - // Add an ability to pass listening socket to mongoose - { - const char *env = getenv("MONGOOSE_LISTENING_SOCKET"); - if (env != NULL && atoi(env) > 0 ) { - mg_set_listening_socket(server, atoi(env)); - } - } -#endif - - // Setup signal handler: quit on Ctrl-C - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); -#ifndef _WIN32 - signal(SIGCHLD, signal_handler); -#endif -} - -int main(int argc, char *argv[]) { - init_server_name(); - start_mongoose(argc, argv); - printf("%s serving [%s] on port %s\n", - server_name, mg_get_option(server, "document_root"), - mg_get_option(server, "listening_port")); - fflush(stdout); // Needed, Windows terminals might not be line-buffered - serving_thread_func(server); - printf("Exiting on signal %d ...", exit_flag); - fflush(stdout); - mg_destroy_server(&server); - printf("%s\n", " done."); - - return EXIT_SUCCESS; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/Makefile deleted file mode 100644 index 780276e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = websocket_chat -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/index.html deleted file mode 100644 index 5da84d3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - WebSocket Test - - - - - - -
-

Websocket PubSub Demonstration

- -

- This page demonstrates how Mongoose web server could be used to implement - - publish–subscribe pattern. Open this page in several browser - windows. Each window initiates persistent - WebSocket - connection with Mongoose, making each browser window a websocket client. - Join a room, send messages, and see messages sent by other clients. -

- -

- My ID: -

-

- Join room: -

- -
-
- -

- - -

-
- - diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/websocket_chat.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/websocket_chat.c deleted file mode 100644 index 5ba5380..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_chat/websocket_chat.c +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2013-2014 Cesanta Software Limited -// $Date: 2014-09-09 17:07:55 UTC $ - -#include -#include -#include -#include -#include "mongoose.h" - -static int s_signal_received = 0; -static struct mg_server *s_server = NULL; - -// Data associated with each websocket connection -struct conn_data { - int room; -}; - -static void signal_handler(int sig_num) { - signal(sig_num, signal_handler); // Reinstantiate signal handler - s_signal_received = sig_num; -} - -static void handle_websocket_message(struct mg_connection *conn) { - struct conn_data *d = (struct conn_data *) conn->connection_param; - struct mg_connection *c; - - printf("[%.*s]\n", (int) conn->content_len, conn->content); - if (conn->content_len > 5 && !memcmp(conn->content, "join ", 5)) { - // Client joined new room - d->room = conn->content[5]; - } else if (conn->content_len > 4 && !memcmp(conn->content, "msg ", 4) && - d->room != 0 && d->room != '?') { - // Client has sent a message. Push this message to all clients - // that are subscribed to the same room as client - for (c = mg_next(s_server, NULL); c != NULL; c = mg_next(s_server, c)) { - struct conn_data *d2 = (struct conn_data *) c->connection_param; - if (!c->is_websocket || d2->room != d->room) continue; - mg_websocket_printf(c, WEBSOCKET_OPCODE_TEXT, "msg %c %p %.*s", - (char) d->room, conn, - conn->content_len - 4, conn->content + 4); - } - } -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_REQUEST: - if (conn->is_websocket) { - handle_websocket_message(conn); - return MG_TRUE; - } else { - mg_send_file(conn, "index.html", NULL); // Return MG_MORE after! - return MG_MORE; - } - case MG_WS_CONNECT: - // New websocket connection. Send connection ID back to the client. - conn->connection_param = calloc(1, sizeof(struct conn_data)); - mg_websocket_printf(conn, WEBSOCKET_OPCODE_TEXT, "id %p", conn); - return MG_FALSE; - case MG_CLOSE: - free(conn->connection_param); - return MG_TRUE; - case MG_AUTH: - return MG_TRUE; - default: - return MG_FALSE; - } -} - -int main(void) { - s_server = mg_create_server(NULL, ev_handler); - mg_set_option(s_server, "listening_port", "8080"); - - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); - - printf("Started on port %s\n", mg_get_option(s_server, "listening_port")); - while (s_signal_received == 0) { - mg_poll_server(s_server, 100); - } - mg_destroy_server(&s_server); - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/Makefile deleted file mode 100644 index f6b132d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = websocket_echo_server -CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) -SOURCES = $(PROG).c ../../mongoose.c - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/index.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/index.html deleted file mode 100644 index 84e7078..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/index.html +++ /dev/null @@ -1,46 +0,0 @@ - - -WebSocket Test - - -

Mongoose WebSocket Test

- -
- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/websocket_echo_server.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/websocket_echo_server.c deleted file mode 100644 index 9001a8a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_echo_server/websocket_echo_server.c +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2013-2014 Cesanta Software Limited -// $Date: 2014-09-09 17:07:55 UTC $ - -#include -#include -#include "mongoose.h" - -static void push_message(struct mg_server *server, time_t current_time) { - struct mg_connection *c; - char buf[20]; - int len = sprintf(buf, "%lu", (unsigned long) current_time); - - // Iterate over all connections, and push current time message to websocket ones. - for (c = mg_next(server, NULL); c != NULL; c = mg_next(server, c)) { - if (c->is_websocket) { - mg_websocket_write(c, 1, buf, len); - } - } -} - -static int send_reply(struct mg_connection *conn) { - if (conn->is_websocket) { - // This handler is called for each incoming websocket frame, one or more - // times for connection lifetime. - // Echo websocket data back to the client. - mg_websocket_write(conn, 1, conn->content, conn->content_len); - return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ? - MG_FALSE : MG_TRUE; - } else { - mg_send_file(conn, "index.html", NULL); - return MG_MORE; - } -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: return MG_TRUE; - case MG_REQUEST: return send_reply(conn); - default: return MG_FALSE; - } -} - -int main(void) { - struct mg_server *server = mg_create_server(NULL, ev_handler); - time_t current_timer = 0, last_timer = time(NULL); - - mg_set_option(server, "listening_port", "8080"); - - printf("Started on port %s\n", mg_get_option(server, "listening_port")); - for (;;) { - mg_poll_server(server, 100); - current_timer = time(NULL); - if (current_timer - last_timer > 0) { - last_timer = current_timer; - push_message(server, current_timer); - } - } - - mg_destroy_server(&server); - return 0; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/Makefile b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/Makefile deleted file mode 100644 index 968f1ac..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2014 Cesanta Software -# All rights reserved - -PROG = ws_ssl -CFLAGS = -W -Wall -I../.. -I. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS -DNS_ENABLE_SSL -DSSL_WRAPPER_USE_AS_LIBRARY $(CFLAGS_EXTRA) -LDFLAGS = -lssl -SOURCES = ws_ssl.c ../../mongoose.c ssl_wrapper.c - -# PolarSSL paths and flags -POLARSSL_PATH = /usr/local -POLARSSLCOMPAT_PATH = ./../../../polar -SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c -INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include -LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls -CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR) -# - -all: $(PROG) - -$(PROG): $(SOURCES) - $(CC) -o $(PROG) $(SOURCES) $(LDFLAGS) $(CFLAGS) - -polarssl: $(SOURCES_POLAR) - $(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR) - -clean: - rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_ca.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_ca.pem deleted file mode 100644 index ebc7d8f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_ca.pem +++ /dev/null @@ -1,49 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAwizPnrCx+/kPSdEeSJFLDXrBH+cSQsSLrCm99G1hCjzqSlIk -1BhkZMEHxBaiVLky4+M/nwhjwwRHI10h6U2Or3tbPLv7z94cPf+uCx1aF7TE3Fm3 -6YnDk+CjrYVFN5GRPGOPPdFxGoc+vFvQJyAAimvchnS1ZoEQFvermwzOnKspA6gc -Px+7wnOeju9TyJuDr5ngtDXFnkcpkBNPxz3En4MJY4xJiaueafh9pIES2vSl7uP0 -J/qot9v2rdiL7nt1H1vwseeEkZhQ+NLB5e2z4psyktJcwDX7wQ6j7JnKfHeP+ixO -TUORgV4foBMVOqo//Guo92Q5HoLNK77V0y4+ZQIDAQABAoIBAGEsx+LlDs3JQQty -KjOq8uKWElyC6bKcZkIMydGvg6b6AU6ceW3jnyqFJ/vMUAUSghNmQQq3yiVo2Kks -DLKTa9sKYwisE0NeJsgoUtOhJttCTlrwU4f+t/AjtgY68f7zTLnqIV+Ql4ftM0pU -sIFEFMExZbWsZrQb1w+Hd0wrRqNEbSOfSjHeigvuw1T3GH2tSBUTGTpcoewCzy7U -PKS5pkYyiKySQQNqZTac3NHPjxdK6xxzwURZp1irKdiPdt04KHLVLX8KXelt/J0k -AeYkVbpFIeQ9rNBerMEp6uRBt+nE5mvP+xx1XPqKRxuxbMyTnBXeOM2zS/a/dBiz -fwokwcECgYEA9RSsv9AQ/AR8tt+aPEQvjhJ5pn/YbCb1DA9IDXpaq3tzacGd8JHj -3kUtb79nosu85LvSkAYmtzgfJs6xZyUkscra6q+xlsJ12QRxLzqfxcp9Y0wsdqM4 -AcOwuiPKrjkWxOQpyWPWRwbmAefLfRMekHt4Y/QY0CwhslpnsOsj3O0CgYEAytOE -8I4GBfSQfSjXwfrso++Oi75VSsl5ZeiMGihfEhYFTE8/3rEZf7nf9iFSkN3TT+7f -pFqQzddzPBZXlpVM6k1jcEjdpJizbeR8DmICpABFrZvKz1o8pQ2Yw+FYI86ih0x4 -806snMNgg/RgcVijXKFrC5joJOI+DVgwWoQyMFkCgYBxt4MkiV2oIkjf7ca6GgVa -zbXGjOGV5Umkq96J6nDxyplVw/IN8xOhScX4aP6kahaep4vfKguCzjaeIh/stS5e -lLqZVKZ5Roe6B7ag7HnAI+GkVm73KWrOXse8xui/iFvJRfkhqgJ9+HR3A9/GjD2N -Ws0Uy+lLhn6oLAya6bA9TQKBgAVfZP4aRP6TY+Bs3Io+41XUWqpI+GlqvNR+PHfU -6e/ItYs37jEv78T6X3xdlZpQxfAwG6x22a8aLetBjEBo5Aiw1Bl9VKGvidE3ZDHd -VsSRXUckAVNMyJ52pb1KktMf/h4nYGzRgLEGW+Ai8QsPlgQ2ImfEPSH8/DfORjmf -ltTBAoGBAMxIZ52DrJvuxogSOfA1MoCD6a90trkXCquvi+A/fXojZ8BHmMQshvhK -rAO7SDIV1i1Nh3jQ/oFWE8KOprqrOLO6jNTyF65vh+zk7ztGsEME9FkDhHasUiXf -t5PE9KeTChHRvIa4FGCl9We9GftE5Ii77LWMOIq22pyxYbvHQFEf ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIJAIOoO+AapJ5WMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNV -BAMTA3dzMTEMMAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVi -bGluMB4XDTE0MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMD -d3MxMQwwCgYDVQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZEdWJsaW4w -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCLM+esLH7+Q9J0R5IkUsN -esEf5xJCxIusKb30bWEKPOpKUiTUGGRkwQfEFqJUuTLj4z+fCGPDBEcjXSHpTY6v -e1s8u/vP3hw9/64LHVoXtMTcWbfpicOT4KOthUU3kZE8Y4890XEahz68W9AnIACK -a9yGdLVmgRAW96ubDM6cqykDqBw/H7vCc56O71PIm4OvmeC0NcWeRymQE0/HPcSf -gwljjEmJq55p+H2kgRLa9KXu4/Qn+qi32/at2Ivue3UfW/Cx54SRmFD40sHl7bPi -mzKS0lzANfvBDqPsmcp8d4/6LE5NQ5GBXh+gExU6qj/8a6j3ZDkegs0rvtXTLj5l -AgMBAAGjgZwwgZkwHQYDVR0OBBYEFL54xAgtJTW6US4Mbr4QG0yKzvaxMGoGA1Ud -IwRjMGGAFL54xAgtJTW6US4Mbr4QG0yKzvaxoT6kPDA6MQwwCgYDVQQDEwN3czEx -DDAKBgNVBAoTA3dzMTELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpboIJAIOo -O+AapJ5WMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAJz/RzMa9Wa2 -eEXed7ijH1gcWtgVsVT1xZo0ksFl+QJ5Be1AJpOIe8nKdzYjxPWUkofIoaGHdMLL -Uc/udRzsXncup+0mD+Yos6Cqyo9yHq7L1HbXfKYZtBXIjWHdF2+RP8j9tHfITXYI -Pb2zsQ+A6PYpp5OLGZTDAnI2qffqsmwXFNhPfFhOANrGlOjsvy1P7JDzvymj/90m -NomlO3vjxLHOf6MvedTgCB0dRcAoUWPgbxPWifjBmGBjQjA4ukMQ58wbBQgvIoCW -obrXmLCNZIkpWTw4gMRYquY880IYK/OuFNJH/dawxx/WzuVr7IdLmbFY15zf5TUb -ZpIpwqRCysg= ------END CERTIFICATE----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_client.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_client.pem deleted file mode 100644 index 82e9950..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_client.pem +++ /dev/null @@ -1,45 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEAwOp1RS9RnE8L5TszDPIOmpf/1pqb+ki99l/sGhqB/KZBKCuq -uoCc2VPK3PCByBE15/xJ7t691FnJfForI9DO5p2R0FPD6o357hqRsh0dJNBm0VgG -iNtLQ8lyYoE72HJbkgCAUZW4N0OBibOmvp/s3Fmr7rEjW5LmZxOtX+iULKIUZ0w6 -gJlM8G5QA1SuqndN0PbPx+RZKSXZCoJj+Nboqw03nyJUexzs+lynR9ITMziUaaVM -4rzG+P6joQAnUkDNydxo/d4tj4xaioZdKxWLYEbj2BUtOlJJydotWo2wcG85ONrT -Gw0ltR1vku1hidMm2QL30uGIL5SeqyE8TqWk4QIDAQABAoIBAQCxHtKauc45MA4g -4hCGAzvLTmETnRI2YlEfAoTYlpvf5pkOE8GFyI25r4gjACJ4GO0gWG9dBF7Pt7wZ -EwRmttEvxV3aIv5OvRnKNdSs7rQSV9D+xc4CGy1oSG1f6X2TxbMzQoiN32OqQa2O -S0Z94IFs8lu8JCDtc9tcqiFVXEmnC3RvJZOShWpsCsbmh5ue1Xed0MQQ47vt7Zt7 -I0cutvwSFJMsZkZUJp5+KjVNYo9TEJxVD3m2NJNJxBfBoRVHXNii3hUEHcTIdIAz -omtRwBU8AKgJirGIRo1h2ZFyubI8ScGOJWIiWMQvQqTHKiOaz3yUar1NSG+kFn0U -cj7s3FhdAoGBAOQbx8Jwhtp4iOkP6aW1nVTgiaTj4LMlyJZioFwgPFRIcA3oRHt9 -5SRetmgFZNvcuNw1udfeaObKmlzxwUruprwOpihgAQWJFTtOjQNrt2gsYuX4l3W6 -T46dO2W1pV+mW4A5gt0aqhLv7pCS4lpreNAqyHSPqcQWcCeiTzmp/LfDAoGBANiB -FQOTyMElR9OzKwmcGfIvnhUfJQwi5qNE3R+xXiP5x36a9HQBey5ri2lnBle0Ksr/ -G+RKoflmk1eFXVHN0w35yw0dVco//WE4vOknldNEnIT85k02ld8lDTa2Q/EJZtPH -un6zeU0Q2/4SZ/GXPssEZPlpPM7WtQzztlH3+sqLAoGBAKnhppvAgi4ippQsLa4j -29BiiSAsNiQ1d3XIbfUubL+4UvuIh7gQwp6biu1dVwgHEgWuXYHPOgDn0p51zaao -pbRYlJZtKVWeChnpHkv15NnIdL8grGwZHTbxElNlPIxHsM2GB1fzi8YeumUhf0In -2AnwUum8NIq8yzo5PxeK6ZNRAoGBAIEA2Q6ankJH/nZsCbbeJq+iI+Wd+ysyGI8s -Vz2tJ9Tz3iTYG9SLlWRhfF4/nw3fMqhmPa5Xsg+zSRQbSTGXHKz1LEISOq4aVtX5 -QscCaUnLVh//uRJE9iRSJX92NyGGYpjKJ5ubQSnkY9EOEpVnc2jwo2HhjPQKBzNC -fF53Dh5lAoGALwTN5uxrBZLPu4DtZkOosKkv4l+kzFoOjLJR4vA7ONBx2CSe9G7F -tSsH7lZS3b0mxBWjO90WhaSvtMWWrfqq8vrqmoTE795fYxNoLfCLK13W31aTDUsI -pQRJIL30MPvASbcFHN2MD2dXz2nQzY8C9lvtvap/krYiDKDU2L7+iP8= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIC7DCCAdQCBRQHBXNHMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMTEM -MAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0 -MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMDd3MxMQwwCgYD -VQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA6nVFL1GcTwvlOzMM8g6al//Wmpv6SL32 -X+waGoH8pkEoK6q6gJzZU8rc8IHIETXn/Enu3r3UWcl8Wisj0M7mnZHQU8Pqjfnu -GpGyHR0k0GbRWAaI20tDyXJigTvYcluSAIBRlbg3Q4GJs6a+n+zcWavusSNbkuZn -E61f6JQsohRnTDqAmUzwblADVK6qd03Q9s/H5FkpJdkKgmP41uirDTefIlR7HOz6 -XKdH0hMzOJRppUzivMb4/qOhACdSQM3J3Gj93i2PjFqKhl0rFYtgRuPYFS06UknJ -2i1ajbBwbzk42tMbDSW1HW+S7WGJ0ybZAvfS4YgvlJ6rITxOpaThAgMBAAEwDQYJ -KoZIhvcNAQEFBQADggEBABPLmq6zKOMY0WRjtBoSymq6f+vXeEwtWCfVejdG6RlG -/PTdCKNvp3OL7FDnmQQ+r5rMs4+Os4fX/g315QFKXu01rqxmFb2XVNhhaECdUWtK -QP6ZoVZviUiDjhK6a+05aerPCJpkGy/lz0W6gmj4qhuAQbobxb6UbzqTRYY+ZwGk -+SI3TAVCdmXFlxN/M9b0DbmkseRG8GGFmyRYyRb84vbV6zemFI++5ROUT9zXT7ey -nYfFJvAAk5jJhY5UP2aMlVWYYa4jUZrrPLoiBLUuRrp67EKGebCH9mgCIf8ztNJF -fpuvcz++LUeRyTlAGDefe+FyHGIwFzIfZn39D7CaRvM= ------END CERTIFICATE----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_server.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_server.pem deleted file mode 100644 index 93ef657..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws1_server.pem +++ /dev/null @@ -1,45 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAyal0BZKRYd+Wpxv4MB8LjjgXv/MxSN5oSAKThlCZ/AWG0FEP -d4nrBACT2xUxwo+xbYl3joiwL/eCPAp6QNKRGhvXVOnSIFVSjKZWbdX+toqK9pDS -QMDTL4ZJvK6pLZXknyHjEr0PxZh22F7iS1+C8HxBPj0Xgg/u5/+jPhFPPZ1d5elv -4cm/z+xy6RjFlA80aIeK7dcWssOsOIPjUNFfmoYgR63ScZIlUZj6j8VX9oX7fJID -jumGajDxgD2nBWFbHcGKin6bz/wZ+OIhXOCDdY7oKuMW4JiBwbfBtedkQuQYS11s -PRFFYDLoZH59Ivcu0c4F2tomE86qM8THsI910wIDAQABAoIBAG55FAQRfO8/C0rU -eavy9eOdOvV+hltC66G3N5X3BcQYSvhHz89OkJ6KqnT0MWRCT5KQIhzFKK++SWwW -2U41jCPfaKEtzlzEIQrH/MUC3Byn3OSiBWxPteFtEWv5ytgcKzg52iljxQYcNc7m -e9WKpzKS/zLXSM+JZvlVA9p2pRA88kUZ/EE5H+FW3kHj5eGNqX+cxUVpL0VKTiLv -aXWjYotpmDJW/Rn9wRQethm6Gdx3bvo+LEVlJRELNq8NM5H/tZIVRzudJOgzsw5v -3OQGhfKB6Eg/vqSFoZxX6ApXDxmtaSO83B0kK550bDVv4sBnOExGjKCzybt04tet -KtLPPoECgYEA5WUD+mFL99sCX6pzIyUVlxp9eUhVy5nvhoF6u3mvhay2XsZUY0wy -+/qVqYSZTvuvJ6JSXc4iVIX8u/gj7914805AwujepIF/8E0AaXLBMndzDE4ze5S5 -2RHI7Cy4/3AWOcQ9wFFmUdSs7/6oAkcQtvzP40hGg3J2jAEhIdCqmbMCgYEA4Q0G -BYP9XeTdh0C+BcP9B5VUEC0jerYS8VqVqriB+9JfT3InI7K08sOG2DiQQBhAHuzL -RhCECU2a9j0+u5F5JNeY5m3IhU73Lw+lOlUkMaAO6x7JJEzhXhonE7Kv8fWygr/0 -OB7yzqz+YsWdQ2VOPZ88ntlAYE65vzcaVswZY2ECgYEAr7Gt2VA6Ei0A5Wq0Yr+d -iKz2WzUG2TkelqOG8B4kTDrbNz2qFp+fERV9GWgAz9i+75lIgqZF7vzsdL96LtYv -NBLEUURwegjhh5hCb4E/7bpFOLCQh9+CdHpFrHYYfzRHIZlnPmxZ9OTyS6J85bmu -WKjLRKXvs++wUkzvJmoesDcCgYEAkTOB6xUZ5/a+J4HSGI43NylVr4owFgBbgHVd -k2SwGPXGoM+aCSJINUmKOv9jsrbyyAEntfD5/7aegLlLPGHDs82WzTWP5tLoEOkb -ReOhEpOejHy0ckNYNQrSo5bqhkZsAogu3fa52jcrejbeHJnEPWX8CtFJA9pHZeP7 -jnzo9IECgYBefHg0dymSj2xxN0XmC+S5cvQu2K/NYUpatoWvHnPiQ87wIM0AWz0O -D0ghEI+Ze57NbtSrrcTE7hY/LHrAqXGAB9XNIM5g9Pp/lM+XjzKVr1FMf4xpuHf1 -VJJRHrOU14CvMvKbgbPrL6B0d5yrYmeex7GxNw0ZVvtjCa502Eck+w== ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIC7DCCAdQCBRQHBXNGMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMTEM -MAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0 -MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMDd3MxMQwwCgYD -VQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJqXQFkpFh35anG/gwHwuOOBe/8zFI3mhI -ApOGUJn8BYbQUQ93iesEAJPbFTHCj7FtiXeOiLAv94I8CnpA0pEaG9dU6dIgVVKM -plZt1f62ior2kNJAwNMvhkm8rqktleSfIeMSvQ/FmHbYXuJLX4LwfEE+PReCD+7n -/6M+EU89nV3l6W/hyb/P7HLpGMWUDzRoh4rt1xayw6w4g+NQ0V+ahiBHrdJxkiVR -mPqPxVf2hft8kgOO6YZqMPGAPacFYVsdwYqKfpvP/Bn44iFc4IN1jugq4xbgmIHB -t8G152RC5BhLXWw9EUVgMuhkfn0i9y7RzgXa2iYTzqozxMewj3XTAgMBAAEwDQYJ -KoZIhvcNAQEFBQADggEBAE20gAykuuaCoP49GnZ/Z6ZItFry4Fl6iCWBDdEsWI9R -wRNYumeaeejdFPXfSJdTT7UlrVK1WWGLQLq+ixHRDX+V9T67ou85F92H/OxbUoPr -iz/TZAEBTC1GvTJl49lsfPl1dTWH8T4Ej2hxCUvIJrkCkI2Ov4Wwef6A26USrwBt -S/CPInjCe6qkE5E8xfTDl8k5IIgMadTPhi5sbV2piBJoN4floJPqR0hdDKbgUymn -5WNSiRkuI6UIDZwQEp+A8TmFBHbSwfTGt2Sz5iI27P8J6pFvR5eRA1k57dRUWNXC -WAU1nqteP3QAjj9L3o8IO0T62scaiJX8x01gTmVVe2I= ------END CERTIFICATE----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_ca.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_ca.pem deleted file mode 100644 index 9345a94..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_ca.pem +++ /dev/null @@ -1,49 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAwXIMpHuTNsro2pxe6y1mu27md2Olhvfx26rO3maO0/stIC2z -G/xQatFDLIWzfKFYOT0iSEj252ENFDCw6aDRKpiaUFtXcMAWkNkkKntEyoEgE45k -rTrvpay0v0B+ojwjA1Jz/9v35cgvDwTs3vNFno5HhI0m2YF4ocTmeHJ6u0xRL/qy -atfKsfuVq5s5CXOYCXp3Ux6kJ1c22J0EdZMvS75SVjAZgRkqQpqt9L3e2ZBCEgUr -w0KwlERvpeJF+sJJOshXjfrDzvwL8IpPnGZLJNINFbSJMk5MFGcMyq/28pSZLB9E -Dh8vk5D5gUnxM60ONUy2nYPcYr5p1PLDiC8hfQIDAQABAoIBAB0Twpi6xn8W8vdh -R9c75NRJsDTD8q6d+GnXe+7sJY3xlG/gzqpnO8NCn0FC+57BNdystsl8xjgzW17s -jrsfZDFt7MwlXrhg90NgkFIeY1G5JRQrdDChykHx+t1AmYhTV8P5EdykuNd+RqyQ -RfahRJa3tkJTYUKSdoqCaU4zjwU2CSxltuJx24V+WoZE12EwewJ8HPg2XTnbsGE7 -Fnx5s29O4ItM70CC0536AY/OgfuPix5z573VQiilqqfOQkVkKa1fHd6tGpWU+3kH -X9FnhEBf9cN9tVgmaB0sCSVVrfgqSXg1EwKHqe/+FCumuesA68Q35+/K3b+QrNiR -ka2yliECgYEA+V/4pbgG/lPYvTwWhKxGXXdJmrSPgZC0mwE+fRuYkeptbIkS0pwt -/UDTXk9nttj1f1ZJ3NgQbT/1w8jpXfsCJ8VeGzL9+ADhRKWVFRlu/nyFCMXawLEV -rot7SEr8BW/m8moHgY5lYipM3dXJPk0F+KLrN60U/aNmFUtPGW802BkCgYEAxpWy -FGL2sEQ0QaRDTcqqF5faVqw+5rVGvN+EX5o26E0QWWnoo3L2c2/5X93iBl+Fqtnm -9jSIQUC3rYOawKnZ/HcIE2ergFit/p6JaV9NiLDRtDUmSzlffEGVCj0neYFsnWp5 -zcmkUyZ6fr19EmKQWfdteNBlXue32TjVlFbfUQUCgYAfMbgi0sBdNBPaqBeRBRPQ -QUm9xnRlGrrc4Oz2LWuKZS7G8uad3deK5H8MPxaUMtOS2DJpI8X6RJPzp8A5d1qv -quq4sEpAqauEMMpTV1khEGZ70HQqwnwZ12zWgDrCW1siW80QkcVw4CW5YjLITk4+ -6fJOhqInkDcG1uLQJa8QkQKBgQCfs8l4DbJ4RRGFbLXXvNGXkb68j18yqLxPrq3F -OL9JiJhKYBsAP7clVPrG9ykLmQxlP0I35D1jxMkymLD+mlo9Z/itqmTJHggnyZWW -kVdIQ3MSKuA2BNjek9tpVY8Gb2hLHFMChVRKrpo6jOclvvB5+bsnOukbLtyyq7tP -xaFohQKBgByCmlltjOBWZLFLeA1x8j3inm9zM/FAJuANbHUOZ1RwrRcNFbDv/FXm -rLPnPCaH5AwAWhVRJcNHo37Ee0s/xqe+Q4dG4xL943k+6KlopAw1SXhuXF6PnBfF -y+ArVlh9d2oWN5cBEzRddnWnKJuMi70kMzYf6dIW9s/dHbq/gFDy ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIJAJDtcXU2wiJIMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNV -BAMTA3dzMjEMMAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVi -bGluMB4XDTE0MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMD -d3MyMQwwCgYDVQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZEdWJsaW4w -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBcgyke5M2yujanF7rLWa7 -buZ3Y6WG9/Hbqs7eZo7T+y0gLbMb/FBq0UMshbN8oVg5PSJISPbnYQ0UMLDpoNEq -mJpQW1dwwBaQ2SQqe0TKgSATjmStOu+lrLS/QH6iPCMDUnP/2/flyC8PBOze80We -jkeEjSbZgXihxOZ4cnq7TFEv+rJq18qx+5WrmzkJc5gJendTHqQnVzbYnQR1ky9L -vlJWMBmBGSpCmq30vd7ZkEISBSvDQrCURG+l4kX6wkk6yFeN+sPO/Avwik+cZksk -0g0VtIkyTkwUZwzKr/bylJksH0QOHy+TkPmBSfEzrQ41TLadg9xivmnU8sOILyF9 -AgMBAAGjgZwwgZkwHQYDVR0OBBYEFLK4flD5QD/mRufsPx63xlEKM8pwMGoGA1Ud -IwRjMGGAFLK4flD5QD/mRufsPx63xlEKM8pwoT6kPDA6MQwwCgYDVQQDEwN3czIx -DDAKBgNVBAoTA3dzMjELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpboIJAJDt -cXU2wiJIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEYD+CReikYr -Rzvk+/Vdi/7IcaH9CFknIdtineSIw1y98nxnbnNJqxwfNaRblbYvg6OFdUI3POuI -+rdYLCFl8z3tWqRHLkGqHSJA9xcng3jLJxz0+ctiVcekJvXaB3O6eSZjhGbmmI/s -CQhdy2zpEIVOeUq50DrSJp9CknyGu/IkaGx5GOZtkiHMrpig50CRjX1lS6qrMNYp -vB8gfuqpjsL4Ar3vg+lgMSwNWXBNHrIRPHB5VEzBEdmLFZlvueR0ooEMCklpwX/a -lFImVc6JcY1pBEkHTiTLGMpGAHG3I1aVUaWb3L+V+2ym/KNRNL5C2+1eiqql5u8m -HUaOcNC90ew= ------END CERTIFICATE----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_client.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_client.pem deleted file mode 100644 index 8021de3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_client.pem +++ /dev/null @@ -1,45 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA0ucemqFwBFziVOgTgx4mZII4WnGDpA/rWAGHvUZOqy2dQ3Pz -woGKxBaVPAl5kxEosROVGa7dTuq5yFZ4XIGvwCKxF30vCmdGCytqq6MMp904jG32 -KikkmjCApIMGxMO4eoBHZZxiyVvKTbg9M2CRXErwnYWhFH/qGdPnuo0CEaHJA4VK -A9incT9dpeEhU30R6ajAe/je9rCj2OMLMFSMfd51L/VYfO60zDwUNY7YVIghQZgJ -e44EVGsp1pXaqaD6o3PvGY3ohw2aZjJzlJ7MJHbKV9lft98R3pklbpBzMH849cEy -Q/51L/rlfTUgCpTy7wEZpWHQNtHfu/1rhJjpNQIDAQABAoIBAQCUNIHXG/dBuZv7 -GpMLotZL7w520Co30lAJqhmfMpb5x7YpvoPffXTsUwpQBECAzqAPv7kZMT6nxF8F -n245Y5EDrd1QqlGyN9yK4Nm2/39XPygL1wITopHsIIVmFgVdpEQxIZAKoZjx8yT4 -9K1dO1Eq0CbCKzOE2lbCC51eBNUdWZIMxwC6O/j/KoIkZ/HwlG2hpUuXg8x/XawA -ZJDCoTcWHCjYP10FxKVN3vAyWM2IM44o9IbsAGEOswR4gUwRsgq6Ehc1U59XUHi+ -x30oda55I1/8xD+SfP/zk2dDPHkv/hq5+258GU/THsw2+AAexocvSIS/g9EppTEg -biFaDKzJAoGBAPqey10JeyiOlHbBjoSSa7lJYUjocQANFQ4ayOAgfNX72iyabrKF -p9sVAeO/nM00+DPrm2wWws03ScsPeh+9BDJMPRBUHfSNp7+F+oyj7PWHBEFHbyO9 -5HnYZP+1vhdG2dYPIY2gRSFXpiGn3j0M1D0w9c7Ilm8ee3krdR4E/mw3AoGBANdu -EfS1dK3+m7sEgc2+3U32z83GpuCHeUIKGPYMLI0fIb1CPpboHU9YjOFJZH9iIIdl -00JC963O3+pqLe0XbMOmBVt9QjZfhfB+AY+JHtbPgoQVLtq9X/WvW7h3xn6S971r -Crkhqay3Cs4BzsgYDYraQCTw3oq4twR9Nuy4etfzAoGAXOsG5wWe3diO/sCggFJx -Eg88vHVBgA1ZoxMXKtGgtw1bRHI1XIblRvqw6qmeDw72fvl5dEe0DbXT7C9ezemc -ZrGRaj5lpMfoS7/2trIIJrfaQgGkGRJMZUhvmcbeJW8lUJHnlMS5HLWMaKn+YZAi -GFXQrMv9ylD44mHUWD7tvV0CgYBNctPfvvCQsQ05ofgsiKa1Jbs1hmpuJCYy2MB6 -jIvjvEJ78PnhdNc8tGAJikIoDZYWN0RI+RxkDxCvDLcwGpDOkbwxVQnd1F+pwxM6 -kBhXL8kDRT5QA28hO4bk/aKN1LZeEcKMJg8C+ddXkozNoOAVgDs5TKMlCh057u41 -EmmPgwKBgQDOlYi7fPYOCy0yjHMxSrp2SZOS06AMWGbbCoGkjRtvuP+FmKSNB+LZ -pOSEPJgzjsRutKjneww4LpV6dViAyTcP5JoeQpokHf7UVo7yq2QH/iwF3zJwsC/S -OuVLkqpZzWuye/QCH5NOTfw27ye8jG8VcQW2QPbcbkLXLM7zg2yX7g== ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIC7DCCAdQCBRQHBXNJMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMjEM -MAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0 -MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMDd3MyMQwwCgYD -VQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS5x6aoXAEXOJU6BODHiZkgjhacYOkD+tY -AYe9Rk6rLZ1Dc/PCgYrEFpU8CXmTESixE5UZrt1O6rnIVnhcga/AIrEXfS8KZ0YL -K2qrowyn3TiMbfYqKSSaMICkgwbEw7h6gEdlnGLJW8pNuD0zYJFcSvCdhaEUf+oZ -0+e6jQIRockDhUoD2KdxP12l4SFTfRHpqMB7+N72sKPY4wswVIx93nUv9Vh87rTM -PBQ1jthUiCFBmAl7jgRUaynWldqpoPqjc+8ZjeiHDZpmMnOUnswkdspX2V+33xHe -mSVukHMwfzj1wTJD/nUv+uV9NSAKlPLvARmlYdA20d+7/WuEmOk1AgMBAAEwDQYJ -KoZIhvcNAQEFBQADggEBACCCAJypO9DFU6GeOH+FwE0JCLTypHoIwERWxNL7xfjg -rwVqIxwAEo+fJjL+QY7JbAb/eqKaXIBYkAF2lFc4iEmecXX/A3Aqw95AYi78o7HD -MwRPqJha9mxLcCWwjX8XK8pT152BvYFPNhi+6jd++rDRxKDfmNvgdUQ2/YW6a5Wv -zEmLDPUWRIuMQIEmOa2/JhlllDviMExTw51nbqYgCghycRvDACyQAuu8re7P6gcg -bXObNlfxcU/8Ph6MFI+2S9ODtQ4BHyuKd4kRNsYn8vV42a0h3bCYSGPk3kSIgxd7 -XijwHT/o8E9ddH2BvDv+6Nhno9C6/MbezEOIs4nlhRk= ------END CERTIFICATE----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_server.pem b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_server.pem deleted file mode 100644 index b6b48ef..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/certs/ws2_server.pem +++ /dev/null @@ -1,45 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEA29iFnMf4pjty6knOt4wT0joPUlU2dGCFWxQ5Eg77Yx3Lou2a -FOzNGp7zLYH8gauOK+mgY+B9cBv8PvVtUQQKB0SKTTV8ZNKVyP3O5F2gRSJ+tHtT -FqaPfG0WPOn/f02YbOpAe6Rk+NnlJoeuBxG4uapUSq7r0mTGJQe+52y1LcMs23ID -ENBfDoUMVt5vCnF+cYK5ndeFVLyPO3JjohDH1zv3a9ECG28rtjKHLpNYFDsPJaD7 -UPuyyk3hIvfPCZoJOUlEVfpLT/lM+9oCPnq9PwIp5NqYofkuc3eKooCo7N4r4IlP -Ajktaao6b0ScNwNQB3leOIdEUFSIYy8N1JszVwIDAQABAoIBAFlIvjrGG/2m9yyf -fQyeHw6p9b8CTHNHH+G1fNgQrZe7ahBpXsJQyZueIjTBLcOb4MmEwFbPvSHiu7b2 -Bcd5VHlPJLvmlPZ9b8eJDJVCUOzC7aJu03fHfU6THwzuG42f/d9942JTiY5nL+FO -CSdl0xfUTRdnou53buFrG+TxCUPj13HP1HY6DAVzEIq1H4TZwIZo7KRRTIYpTB3P -6yvr9xsISLlnmfQ4tp2pApl5o+bHJEhr1VO6SAT/pSyShi79KmMMqYtyTmOMz7w6 -VJkre5ybnXBDN6tfMHWqdobJ4gRWK9rqf+LIZig5XQnyzkue8k+I7aPgO4xNFh56 -dkejQcECgYEA9MDCWViqpfvof+epiKzccqnIRnz1EfHdRQjiKsKGRe39+K+pyaqJ -FOOPFy3aOw6M4cFWwcdMYzKTItvzyLVhDqMzT5eup/NVqo5tPoy93XPf2qRYiTl4 -2j5wvm0RVkYEONd3pk2lbfbUmn7XQXj0+AG60SvsqErF/UhIBGec/xsCgYEA5fLC -EdiiC98kr4sVaE8G854WI+aAkStqO5YXyrnsMzRsqk8KVVYE1yCC9rYyymDBYmlx -uEW+vbWqLc8PO3v4ty3o5ff303lPMWIrvKiUldjqMjS6ncWxsQjU0bygGVgOgHO7 -c8rjiDH5M0JgWSREYUVFT5mW/5+Y1LVT8mYNlHUCgYEAhMSX6N23XGkFW3Twu2qB -/1Vohgw86OoaDNvfzDBPpFmQ3rlz0ijHSeSTd5BxBH5FICXACUgygNErjcphOSxj -JQyUxgVTQlo2y1mNm1O/nwS/lxx1xqK9ky4x/Kqvr+w1WBxSFI2kQr2V4OUTobma -sXpGvDcmnrhJJLd0EaefO6cCgYEA3Xw/S9tC8nZjqqYn34nHI16Q6tF54tpTf8Np -dT4x8Xw8cqqhRGMPVHsfSi1irKYXfwgbnienuqlBmtAHVv9pKF+TJfb7gXkmO2XY -xOYIAHGn2uYJHjCun9vmyYKLHv4/MaDH3Jd/I88mviXgEdyp9Js5UJua4utB1Rg3 -HJMJ34UCgYEAr0PpHEBMbZXZBybNU96+jRTgkrNeJpzlnMy7et2IsRAtLjZ0mpbn -NaX8i8eO+ubweqFdhOvbh7Hd0zr7BzrYcUG1e3njhtxJE1MgWL5plnLVUbIyDAm3 -iBpIHIBASNCN3sqeq+VqXvavRmeZh5O0vyLP46/kxZx0rzR/NCi9xxU= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIC7DCCAdQCBRQHBXNIMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMjEM -MAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0 -MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMDd3MyMQwwCgYD -VQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb2IWcx/imO3LqSc63jBPSOg9SVTZ0YIVb -FDkSDvtjHcui7ZoU7M0anvMtgfyBq44r6aBj4H1wG/w+9W1RBAoHRIpNNXxk0pXI -/c7kXaBFIn60e1MWpo98bRY86f9/TZhs6kB7pGT42eUmh64HEbi5qlRKruvSZMYl -B77nbLUtwyzbcgMQ0F8OhQxW3m8KcX5xgrmd14VUvI87cmOiEMfXO/dr0QIbbyu2 -Mocuk1gUOw8loPtQ+7LKTeEi988Jmgk5SURV+ktP+Uz72gI+er0/Aink2pih+S5z -d4qigKjs3ivgiU8COS1pqjpvRJw3A1AHeV44h0RQVIhjLw3UmzNXAgMBAAEwDQYJ -KoZIhvcNAQEFBQADggEBALi/RmqeXGazT/WRj9+ZqdcnbcHwK5wwr2/YkpFPJ0Hf -ZDm+2vgjDdTT6cJS6fau0M5nliYdz89aQQo1j9RSRZnzlc/2YCFXyRLCOJYaINbj -1MEUAvNDGL7xTpepK9hVkXASRkbyNXERXRKFI1N+vpKu6UorT6/osEV/qM+MFJ3s -24xE8/J3J4MirVQVt6eY6Jb+tkliOPMIugr6YQlLsqJygEWATP8Qsr81XSfcZhVq -rXzVt7QV8dO0nStMjKK5omrtEAhVnASk7w1tFHkpBF1rqXGoo9ML40RnFZ+E5zqi -iZtzp+NzzLnEnWMNs+fJpPJ96P0kbq2bQzuSBcUynq0= ------END CERTIFICATE----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/net_skeleton.h b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/net_skeleton.h deleted file mode 100644 index 4d1c33f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/net_skeleton.h +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) 2014 Cesanta Software Limited -// All rights reserved -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. For the terms of this -// license, see . -// -// You are free to use this software under the terms of the GNU General -// Public License, 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. -// -// Alternatively, you can license this software under a commercial -// license, as set out in . -// -// $Date: 2014-09-28 05:04:41 UTC $ - -#ifndef NS_SKELETON_HEADER_INCLUDED -#define NS_SKELETON_HEADER_INCLUDED - -#define NS_SKELETON_VERSION "2.1.0" - -#undef UNICODE // Use ANSI WinAPI functions -#undef _UNICODE // Use multibyte encoding on Windows -#define _MBCS // Use multibyte encoding on Windows -#define _INTEGRAL_MAX_BITS 64 // Enable _stati64() on Windows -#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+ -#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h -#define _XOPEN_SOURCE 600 // For flockfile() on Linux -#define __STDC_FORMAT_MACROS // wants this for C++ -#define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE // Enable fseeko() and ftello() functions -#endif -#define _FILE_OFFSET_BITS 64 // Enable 64-bit file offsets - -#ifdef _MSC_VER -#pragma warning (disable : 4127) // FD_SET() emits warning, disable it -#pragma warning (disable : 4204) // missing c99 support -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#ifdef _MSC_VER -#pragma comment(lib, "ws2_32.lib") // Linking with winsock library -#endif -#include -#include -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef __func__ -#define STRX(x) #x -#define STR(x) STRX(x) -#define __func__ __FILE__ ":" STR(__LINE__) -#endif -#ifndef va_copy -#define va_copy(x,y) x = y -#endif // MINGW #defines va_copy -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define sleep(x) Sleep((x) * 1000) -#define to64(x) _atoi64(x) -typedef int socklen_t; -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef unsigned short uint16_t; -typedef unsigned __int64 uint64_t; -typedef __int64 int64_t; -typedef SOCKET sock_t; -typedef struct _stati64 ns_stat_t; -#ifndef S_ISDIR -#define S_ISDIR(x) ((x) & _S_IFDIR) -#endif -#else -#include -#include -#include -#include -#include -#include -#include // For inet_pton() when NS_ENABLE_IPV6 is defined -#include -#include -#include -#define closesocket(x) close(x) -#define __cdecl -#define INVALID_SOCKET (-1) -#define to64(x) strtoll(x, NULL, 10) -typedef int sock_t; -typedef struct stat ns_stat_t; -#endif - -#ifdef NS_ENABLE_DEBUG -#define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \ - fflush(stdout); } while(0) -#else -#define DBG(x) -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) -#endif - -#ifdef NS_ENABLE_SSL -#ifdef __APPLE__ -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif -#include -#else -typedef void *SSL; -typedef void *SSL_CTX; -#endif - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -union socket_address { - struct sockaddr sa; - struct sockaddr_in sin; -#ifdef NS_ENABLE_IPV6 - struct sockaddr_in6 sin6; -#else - struct sockaddr sin6; -#endif -}; - -// Describes chunk of memory -struct ns_str { - const char *p; - size_t len; -}; - -// IO buffers interface -struct iobuf { - char *buf; - size_t len; - size_t size; -}; - -void iobuf_init(struct iobuf *, size_t initial_size); -void iobuf_free(struct iobuf *); -size_t iobuf_append(struct iobuf *, const void *data, size_t data_size); -void iobuf_remove(struct iobuf *, size_t data_size); -void iobuf_resize(struct iobuf *, size_t new_size); - -// Callback function (event handler) prototype, must be defined by user. -// Net skeleton will call event handler, passing events defined above. -struct ns_connection; -typedef void (*ns_callback_t)(struct ns_connection *, int event_num, void *evp); - -// Events. Meaning of event parameter (evp) is given in the comment. -#define NS_POLL 0 // Sent to each connection on each call to ns_mgr_poll() -#define NS_ACCEPT 1 // New connection accept()-ed. union socket_address *addr -#define NS_CONNECT 2 // connect() succeeded or failed. int *success_status -#define NS_RECV 3 // Data has benn received. int *num_bytes -#define NS_SEND 4 // Data has been written to a socket. int *num_bytes -#define NS_CLOSE 5 // Connection is closed. NULL - - -struct ns_mgr { - struct ns_connection *active_connections; - const char *hexdump_file; // Debug hexdump file path - sock_t ctl[2]; // Socketpair for mg_wakeup() - void *user_data; // User data -}; - - -struct ns_connection { - struct ns_connection *next, *prev; // ns_mgr::active_connections linkage - struct ns_connection *listener; // Set only for accept()-ed connections - struct ns_mgr *mgr; - - sock_t sock; // Socket - union socket_address sa; // Peer address - struct iobuf recv_iobuf; // Received data - struct iobuf send_iobuf; // Data scheduled for sending - SSL *ssl; - SSL_CTX *ssl_ctx; - void *user_data; // User-specific data - void *proto_data; // Application protocol-specific data - time_t last_io_time; // Timestamp of the last socket IO - ns_callback_t callback; // Event handler function - - unsigned int flags; -#define NSF_FINISHED_SENDING_DATA (1 << 0) -#define NSF_BUFFER_BUT_DONT_SEND (1 << 1) -#define NSF_SSL_HANDSHAKE_DONE (1 << 2) -#define NSF_CONNECTING (1 << 3) -#define NSF_CLOSE_IMMEDIATELY (1 << 4) -#define NSF_WANT_READ (1 << 5) -#define NSF_WANT_WRITE (1 << 6) -#define NSF_LISTENING (1 << 7) -#define NSF_UDP (1 << 8) - -#define NSF_USER_1 (1 << 20) -#define NSF_USER_2 (1 << 21) -#define NSF_USER_3 (1 << 22) -#define NSF_USER_4 (1 << 23) -#define NSF_USER_5 (1 << 24) -#define NSF_USER_6 (1 << 25) -}; - -void ns_mgr_init(struct ns_mgr *, void *user_data); -void ns_mgr_free(struct ns_mgr *); -time_t ns_mgr_poll(struct ns_mgr *, int milli); -void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t); - -struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *); -struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t, - ns_callback_t, void *); -struct ns_connection *ns_bind(struct ns_mgr *, const char *, - ns_callback_t, void *); -struct ns_connection *ns_connect(struct ns_mgr *, const char *, - ns_callback_t, void *); - -int ns_send(struct ns_connection *, const void *buf, int len); -int ns_printf(struct ns_connection *, const char *fmt, ...); -int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap); - -// Utility functions -void *ns_start_thread(void *(*f)(void *), void *p); -int ns_socketpair(sock_t [2]); -int ns_socketpair2(sock_t [2], int sock_type); // SOCK_STREAM or SOCK_DGRAM -void ns_set_close_on_exec(sock_t); -void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags); -int ns_hexdump(const void *buf, int len, char *dst, int dst_len); -int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap); -int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // NS_SKELETON_HEADER_INCLUDED diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.c deleted file mode 100644 index 969aa97..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.c +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2014 Cesanta Software Limited -// All rights reserved -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. For the terms of this -// license, see . -// -// You are free to use this software under the terms of the GNU General -// Public License, 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. -// -// Alternatively, you can license this software under a commercial -// license, as set out in . -// -// $Date$ - -#include "net_skeleton.h" -#include "ssl_wrapper.h" - -static void ev_handler(struct ns_connection *nc, int ev, void *p) { - const char *target_addr = (const char *) nc->mgr->user_data; - struct ns_connection *pc = (struct ns_connection *) nc->user_data; - struct iobuf *io = &nc->recv_iobuf; - - (void) p; - switch (ev) { - case NS_ACCEPT: - // Create a connection to the target, and interlink both connections - nc->user_data = ns_connect(nc->mgr, target_addr, ev_handler, nc); - if (nc->user_data == NULL) { - nc->flags |= NSF_CLOSE_IMMEDIATELY; - } - break; - - case NS_CLOSE: - // If either connection closes, unlink them and shedule closing - if (pc != NULL) { - pc->flags |= NSF_FINISHED_SENDING_DATA; - pc->user_data = NULL; - } - nc->user_data = NULL; - break; - - case NS_RECV: - // Forward arrived data to the other connection, and discard from buffer - if (pc != NULL) { - ns_send(pc, io->buf, io->len); - iobuf_remove(io, io->len); - } - break; - - default: - break; - } -} - -void *ssl_wrapper_init(const char *local_addr, const char *target_addr, - const char **err_msg) { - struct ns_mgr *mgr = (struct ns_mgr *) calloc(1, sizeof(mgr[0])); - *err_msg = NULL; - - if (mgr == NULL) { - *err_msg = "malloc failed"; - } else { - ns_mgr_init(mgr, (void *) target_addr); - if (ns_bind(mgr, local_addr, ev_handler, NULL) == NULL) { - *err_msg = "ns_bind() failed: bad listening_port"; - ns_mgr_free(mgr); - free(mgr); - mgr = NULL; - } - } - - return mgr; -} - -void ssl_wrapper_serve(void *param, volatile int *quit) { - struct ns_mgr *mgr = (struct ns_mgr *) param; - - while (*quit == 0) { - ns_mgr_poll(mgr, 1000); - } - ns_mgr_free(mgr); - free(mgr); -} - -#ifndef SSL_WRAPPER_USE_AS_LIBRARY -static int s_received_signal = 0; - -static void signal_handler(int sig_num) { - signal(sig_num, signal_handler); - s_received_signal = sig_num; -} - -static void show_usage_and_exit(const char *prog) { - fprintf(stderr, "Usage: %s \n", prog); - exit(EXIT_FAILURE); -} - -int main(int argc, char *argv[]) { - void *wrapper; - const char *err_msg; - - if (argc != 3) { - show_usage_and_exit(argv[0]); - } - - // Setup signal handlers - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGPIPE, SIG_IGN); - - if ((wrapper = ssl_wrapper_init(argv[1], argv[2], &err_msg)) == NULL) { - fprintf(stderr, "Error: %s\n", err_msg); - exit(EXIT_FAILURE); - } - ssl_wrapper_serve(wrapper, &s_received_signal); - - return EXIT_SUCCESS; -} -#endif // SSL_WRAPPER_USE_AS_LIBRARY diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.h b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.h deleted file mode 100644 index ccdf780..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ssl_wrapper.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2014 Cesanta Software Limited -// All rights reserved -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. For the terms of this -// license, see . -// -// You are free to use this software under the terms of the GNU General -// Public License, 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. -// -// Alternatively, you can license this software under a commercial -// license, as set out in . -// -// $Date$ - -#ifndef SSL_WRAPPER_HEADER_INCLUDED -#define SSL_WRAPPER_HEADER_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -void *ssl_wrapper_init(const char *listen_addr, const char *target_addr, - const char **err_msg); -void ssl_wrapper_serve(void *, volatile int *stop_marker); - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // SSL_WRAPPER_HEADER_INCLUDED diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ws_ssl.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ws_ssl.c deleted file mode 100644 index d2fceee..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ws_ssl.c +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2014 Cesanta Software -// All rights reserved -// -// This example demostrates proxying of WebSocket traffic, regardless of the -// protocol (ws:// or wss://). -// To use this example: -// 1. configure your browser to use a proxy on port 2014 -// 2. import certs/ws1_ca.pem and certs/ws2_ca.pem into the trusted -// certificates list on your browser -// 3. make && ./ws_ssl -// 4. Point your browser to http://ws_ssl.com -// A page with 4 sections should appear, showing websocket echoes - -#include "net_skeleton.h" -#include "mongoose.h" -#include "ssl_wrapper.h" - -#define S1_PEM "certs/ws1_server.pem" -#define C1_PEM "certs/ws1_client.pem" -#define CA1_PEM "certs/ws1_ca.pem" -#define S2_PEM "certs/ws2_server.pem" -#define C2_PEM "certs/ws2_client.pem" -#define CA2_PEM "certs/ws2_ca.pem" - -struct config { - const char *uri; - const char *wrapper_server_addr; - const char *wrapper_client_addr; - const char *target_addr; -}; - -static struct config s_wrappers[] = { - { - "ws1:80", - "tcp://127.0.0.1:7001", - "tcp://127.0.0.1:7001", - "tcp://127.0.0.1:9001" - }, - { - "ws1:443", - "ssl://127.0.0.1:7002:" S1_PEM, - "tcp://127.0.0.1:7002", - "tcp://127.0.0.1:9001" - }, - { - "ws2:80", - "tcp://127.0.0.1:7003", - "tcp://127.0.0.1:7003", - "ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM - }, - { - "ws2:443", - "ssl://127.0.0.1:7004:" S2_PEM, - "tcp://127.0.0.1:7004", - "ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM - }, -}; - -static int s_received_signal = 0; - -static void signal_handler(int sig_num) { - signal(sig_num, signal_handler); - s_received_signal = sig_num; -} - -static int ev_handler(struct mg_connection *conn, enum mg_event ev) { - int i; - - switch (ev) { - case MG_AUTH: - return MG_TRUE; - - case MG_REQUEST: - printf("==> [%s] [%s]\n", conn->request_method, conn->uri); - - if (strcmp(conn->request_method, "CONNECT") == 0) { - // Iterate over configured wrappers, see if we can use one of them - for (i = 0; i < (int) ARRAY_SIZE(s_wrappers); i++) { - if (strcmp(conn->uri, s_wrappers[i].uri) == 0) { - mg_forward(conn, s_wrappers[i].wrapper_client_addr); - return MG_MORE; - } - } - - // No suitable wrappers found. Disallow that CONNECT request. - mg_send_status(conn, 405); - return MG_TRUE; - } - - // Not a CONNECT request, serve HTML file. - mg_send_file(conn, "ws_ssl.html", NULL); - return MG_MORE; - - default: - return MG_FALSE; - } -} - -static int ws_handler(struct mg_connection *conn, enum mg_event ev) { - switch (ev) { - case MG_AUTH: - return MG_TRUE; - case MG_REQUEST: - if (conn->is_websocket) { - // Simple websocket echo server - mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, - conn->content, conn->content_len); - } else { - mg_printf_data(conn, "%s", "websocket connection expected"); - } - return MG_TRUE; - default: - return MG_FALSE; - } -} - -static void *serve_thread_func(void *param) { - struct mg_server *server = (struct mg_server *) param; - printf("Listening on port %s\n", mg_get_option(server, "listening_port")); - while (s_received_signal == 0) { - mg_poll_server(server, 1000); - } - mg_destroy_server(&server); - return NULL; -} - -static void *wrapper_thread_func(void *param) { - struct config *c = (struct config *) param; - const char *err_msg; - void *wrapper; - - wrapper = ssl_wrapper_init(c->wrapper_server_addr, c->target_addr, &err_msg); - if (wrapper == NULL) { - fprintf(stderr, "Error: %s\n", err_msg); - exit(EXIT_FAILURE); - } - //((struct ns_mgr *) wrapper)->hexdump_file = "/dev/stderr"; - ssl_wrapper_serve(wrapper, &s_received_signal); - - return NULL; -} - -int main(void) { - struct mg_server *proxy_server = mg_create_server(NULL, ev_handler); - struct mg_server *ws1_server = mg_create_server(NULL, ws_handler); - struct mg_server *ws2_server = mg_create_server(NULL, ws_handler); - size_t i; - - ((struct ns_mgr *) proxy_server)->hexdump_file = "/dev/stderr"; - - // Configure proxy server to listen on port 2014 - mg_set_option(proxy_server, "listening_port", "2014"); - //mg_set_option(proxy_server, "enable_proxy", "yes"); - - // Configure two websocket echo servers: - // ws1 is WS, listening on 9001 - // ws2 is WSS, listening on 9002 - // Note that HTML page thinks that ws1 is WSS, and ws2 is WS, - // where in reality it is vice versa and proxy server makes the decision. - mg_set_option(ws1_server, "listening_port", "tcp://127.0.0.1:9001"); - mg_set_option(ws2_server, "listening_port", - "ssl://127.0.0.1:9002:" S2_PEM ":" CA2_PEM); - - // Setup signal handlers - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); - - // Start SSL wrappers, each in it's own thread - for (i = 0; i < ARRAY_SIZE(s_wrappers); i++) { - ns_start_thread(wrapper_thread_func, &s_wrappers[i]); - } - - // Start websocket servers in separate threads - mg_start_thread(serve_thread_func, ws1_server); - mg_start_thread(serve_thread_func, ws2_server); - - // Finally, start proxy server in this thread: this call blocks - serve_thread_func(proxy_server); - - printf("Existing on signal %d\n", s_received_signal); - return EXIT_SUCCESS; -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ws_ssl.html b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ws_ssl.html deleted file mode 100644 index 23ab250..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/examples/websocket_ssl_proxy/ws_ssl.html +++ /dev/null @@ -1,50 +0,0 @@ - - - Websocket Proxy SSL Test - - - - - - - \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/jni/Android.mk b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/jni/Android.mk deleted file mode 100644 index 3a7daa0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/jni/Android.mk +++ /dev/null @@ -1,8 +0,0 @@ -LOCAL_PATH := $(call my-dir)/.. -include $(CLEAR_VARS) - -LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(COPT) -LOCAL_MODULE := mongoose -LOCAL_SRC_FILES := examples/web_server/web_server.c mongoose.c - -include $(BUILD_EXECUTABLE) diff --git a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/mongoose.c b/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/mongoose.c deleted file mode 100644 index 4b8726e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/c/mongoose/mongoose.c +++ /dev/null @@ -1,5487 +0,0 @@ -// Copyright (c) 2004-2013 Sergey Lyubka -// Copyright (c) 2013-2014 Cesanta Software Limited -// All rights reserved -// -// This library is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. For the terms of this -// license, see . -// -// You are free to use this library under the terms of the GNU General -// Public License, 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. -// -// Alternatively, you can license this library under a commercial -// license, as set out in . - -#ifdef NOEMBED_NET_SKELETON -#include "net_skeleton.h" -#else -// net_skeleton start -// Copyright (c) 2014 Cesanta Software Limited -// All rights reserved -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. For the terms of this -// license, see . -// -// You are free to use this software under the terms of the GNU General -// Public License, 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. -// -// Alternatively, you can license this software under a commercial -// license, as set out in . - -#ifndef NS_SKELETON_HEADER_INCLUDED -#define NS_SKELETON_HEADER_INCLUDED - -#define NS_SKELETON_VERSION "2.1.0" - -#undef UNICODE // Use ANSI WinAPI functions -#undef _UNICODE // Use multibyte encoding on Windows -#define _MBCS // Use multibyte encoding on Windows -#define _INTEGRAL_MAX_BITS 64 // Enable _stati64() on Windows -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+ -#endif -#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h -#ifdef __Linux__ -#define _XOPEN_SOURCE 600 // For flockfile() on Linux -#endif -#define __STDC_FORMAT_MACROS // wants this for C++ -#define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE // Enable fseeko() and ftello() functions -#endif -#define _FILE_OFFSET_BITS 64 // Enable 64-bit file offsets - -#ifdef _MSC_VER -#pragma warning (disable : 4127) // FD_SET() emits warning, disable it -#pragma warning (disable : 4204) // missing c99 support -#endif - -#if defined(_WIN32) && !defined(MONGOOSE_NO_CGI) -#define MONGOOSE_ENABLE_THREADS /* Windows uses stdio threads for CGI */ -#endif - -#ifndef MONGOOSE_ENABLE_THREADS -#define NS_DISABLE_THREADS -#endif - -#ifdef __OS2__ -#define _MMAP_DECLARED // Prevent dummy mmap() declaration in stdio.h -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#ifdef _MSC_VER -#pragma comment(lib, "ws2_32.lib") // Linking with winsock library -#include -typedef SSIZE_T ssize_t; -#endif -#ifndef FD_SETSIZE -#define FD_SETSIZE 1024 -#endif -#include -#include -#include -#include -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef __func__ -#define STRX(x) #x -#define STR(x) STRX(x) -#define __func__ __FILE__ ":" STR(__LINE__) -#endif -#ifndef va_copy -#define va_copy(x,y) x = y -#endif // MINGW #defines va_copy -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define sleep(x) Sleep((x) * 1000) -#define to64(x) _atoi64(x) -typedef int socklen_t; -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef unsigned short uint16_t; -typedef unsigned __int64 uint64_t; -typedef __int64 int64_t; -typedef SOCKET sock_t; -typedef struct _stati64 ns_stat_t; -#ifndef S_ISDIR -#define S_ISDIR(x) ((x) & _S_IFDIR) -#endif -#else -#include -#include -#include -#include -#include -#include -#include // For inet_pton() when NS_ENABLE_IPV6 is defined -#include -#include -#include -#define closesocket(x) close(x) -#ifndef __OS2__ -#define __cdecl -#else -#include -typedef int socklen_t; -#endif -#define INVALID_SOCKET (-1) -#define to64(x) strtoll(x, NULL, 10) -typedef int sock_t; -typedef struct stat ns_stat_t; -#endif - -#ifdef NS_ENABLE_DEBUG -#define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \ - fflush(stdout); } while(0) -#else -#define DBG(x) -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) -#endif - -#ifdef NS_ENABLE_SSL -#ifdef __APPLE__ -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif -#include -#else -typedef void *SSL; -typedef void *SSL_CTX; -#endif - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -union socket_address { - struct sockaddr sa; - struct sockaddr_in sin; -#ifdef NS_ENABLE_IPV6 - struct sockaddr_in6 sin6; -#else - struct sockaddr sin6; -#endif -}; - -// Describes chunk of memory -struct ns_str { - const char *p; - size_t len; -}; - -// IO buffers interface -struct iobuf { - char *buf; - size_t len; - size_t size; -}; - -void iobuf_init(struct iobuf *, size_t initial_size); -void iobuf_free(struct iobuf *); -size_t iobuf_append(struct iobuf *, const void *data, size_t data_size); -void iobuf_remove(struct iobuf *, size_t data_size); -void iobuf_resize(struct iobuf *, size_t new_size); - -// Callback function (event handler) prototype, must be defined by user. -// Net skeleton will call event handler, passing events defined above. -struct ns_connection; -typedef void (*ns_callback_t)(struct ns_connection *, int event_num, void *evp); - -// Events. Meaning of event parameter (evp) is given in the comment. -#define NS_POLL 0 // Sent to each connection on each call to ns_mgr_poll() -#define NS_ACCEPT 1 // New connection accept()-ed. union socket_address *addr -#define NS_CONNECT 2 // connect() succeeded or failed. int *success_status -#define NS_RECV 3 // Data has benn received. int *num_bytes -#define NS_SEND 4 // Data has been written to a socket. int *num_bytes -#define NS_CLOSE 5 // Connection is closed. NULL - - -struct ns_mgr { - struct ns_connection *active_connections; - const char *hexdump_file; // Debug hexdump file path - sock_t ctl[2]; // Socketpair for mg_wakeup() - void *user_data; // User data -}; - - -struct ns_connection { - struct ns_connection *next, *prev; // ns_mgr::active_connections linkage - struct ns_connection *listener; // Set only for accept()-ed connections - struct ns_mgr *mgr; - - sock_t sock; // Socket - union socket_address sa; // Peer address - size_t recv_iobuf_limit; /* Max size of recv buffer */ - struct iobuf recv_iobuf; // Received data - struct iobuf send_iobuf; // Data scheduled for sending - SSL *ssl; - SSL_CTX *ssl_ctx; - void *user_data; // User-specific data - void *proto_data; // Application protocol-specific data - time_t last_io_time; // Timestamp of the last socket IO - ns_callback_t callback; // Event handler function - - unsigned int flags; -#define NSF_FINISHED_SENDING_DATA (1 << 0) -#define NSF_BUFFER_BUT_DONT_SEND (1 << 1) -#define NSF_SSL_HANDSHAKE_DONE (1 << 2) -#define NSF_CONNECTING (1 << 3) -#define NSF_CLOSE_IMMEDIATELY (1 << 4) -#define NSF_WANT_READ (1 << 5) -#define NSF_WANT_WRITE (1 << 6) -#define NSF_LISTENING (1 << 7) -#define NSF_UDP (1 << 8) - -#define NSF_USER_1 (1 << 20) -#define NSF_USER_2 (1 << 21) -#define NSF_USER_3 (1 << 22) -#define NSF_USER_4 (1 << 23) -#define NSF_USER_5 (1 << 24) -#define NSF_USER_6 (1 << 25) -}; - -void ns_mgr_init(struct ns_mgr *, void *user_data); -void ns_mgr_free(struct ns_mgr *); -time_t ns_mgr_poll(struct ns_mgr *, int milli); -void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t); - -struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *); -struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t, - ns_callback_t, void *); -struct ns_connection *ns_bind(struct ns_mgr *, const char *, - ns_callback_t, void *); -struct ns_connection *ns_connect(struct ns_mgr *, const char *, - ns_callback_t, void *); - -int ns_send(struct ns_connection *, const void *buf, size_t len); -int ns_printf(struct ns_connection *, const char *fmt, ...); -int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap); - -// Utility functions -void *ns_start_thread(void *(*f)(void *), void *p); -int ns_socketpair(sock_t [2]); -int ns_socketpair2(sock_t [2], int sock_type); // SOCK_STREAM or SOCK_DGRAM -void ns_set_close_on_exec(sock_t); -void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags); -int ns_hexdump(const void *buf, int len, char *dst, int dst_len); -int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap); -int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // NS_SKELETON_HEADER_INCLUDED -// Copyright (c) 2014 Cesanta Software Limited -// All rights reserved -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. For the terms of this -// license, see . -// -// You are free to use this software under the terms of the GNU General -// Public License, 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. -// -// Alternatively, you can license this software under a commercial -// license, as set out in . -// -// $Date: 2014-09-28 05:04:41 UTC $ - - -#ifndef NS_MALLOC -#define NS_MALLOC malloc -#endif - -#ifndef NS_REALLOC -#define NS_REALLOC realloc -#endif - -#ifndef NS_FREE -#define NS_FREE free -#endif - -#ifndef NS_CALLOC -#define NS_CALLOC calloc -#endif - -#define NS_MAX_SOCKETPAIR_ATTEMPTS 10 -#define NS_CTL_MSG_MESSAGE_SIZE (8 * 1024) -#define NS_READ_BUFFER_SIZE 2048 -#define NS_UDP_RECEIVE_BUFFER_SIZE 2000 -#define NS_VPRINTF_BUFFER_SIZE 500 - -struct ctl_msg { - ns_callback_t callback; - char message[NS_CTL_MSG_MESSAGE_SIZE]; -}; - -void iobuf_resize(struct iobuf *io, size_t new_size) { - char *p; - if ((new_size > io->size || (new_size < io->size && new_size >= io->len)) && - (p = (char *) NS_REALLOC(io->buf, new_size)) != NULL) { - io->size = new_size; - io->buf = p; - } -} - -void iobuf_init(struct iobuf *iobuf, size_t initial_size) { - iobuf->len = iobuf->size = 0; - iobuf->buf = NULL; - iobuf_resize(iobuf, initial_size); -} - -void iobuf_free(struct iobuf *iobuf) { - if (iobuf != NULL) { - if (iobuf->buf != NULL) NS_FREE(iobuf->buf); - iobuf_init(iobuf, 0); - } -} - -size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) { - char *p = NULL; - - assert(io != NULL); - assert(io->len <= io->size); - - /* check overflow */ - if (len > ~(size_t)0 - (size_t)(io->buf + io->len)) { - return 0; - } - - if (len <= 0) { - } else if (io->len + len <= io->size) { - memcpy(io->buf + io->len, buf, len); - io->len += len; - } else if ((p = (char *) NS_REALLOC(io->buf, io->len + len)) != NULL) { - io->buf = p; - memcpy(io->buf + io->len, buf, len); - io->len += len; - io->size = io->len; - } else { - len = 0; - } - - return len; -} - -void iobuf_remove(struct iobuf *io, size_t n) { - if (n > 0 && n <= io->len) { - memmove(io->buf, io->buf + n, io->len - n); - io->len -= n; - } -} - -static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) { - if (nc->flags & NSF_UDP) { - long n = sendto(nc->sock, (const char *) buf, len, 0, &nc->sa.sa, - sizeof(nc->sa.sin)); - DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno))); - return n < 0 ? 0 : n; - } else { - return iobuf_append(&nc->send_iobuf, buf, len); - } -} - -#ifndef NS_DISABLE_THREADS -void *ns_start_thread(void *(*f)(void *), void *p) { -#ifdef _WIN32 - return (void *) _beginthread((void (__cdecl *)(void *)) f, 0, p); -#else - pthread_t thread_id = (pthread_t) 0; - pthread_attr_t attr; - - (void) pthread_attr_init(&attr); - (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - -#if defined(NS_STACK_SIZE) && NS_STACK_SIZE > 1 - (void) pthread_attr_setstacksize(&attr, NS_STACK_SIZE); -#endif - - pthread_create(&thread_id, &attr, f, p); - pthread_attr_destroy(&attr); - - return (void *) thread_id; -#endif -} -#endif // NS_DISABLE_THREADS - -static void ns_add_conn(struct ns_mgr *mgr, struct ns_connection *c) { - c->next = mgr->active_connections; - mgr->active_connections = c; - c->prev = NULL; - if (c->next != NULL) c->next->prev = c; -} - -static void ns_remove_conn(struct ns_connection *conn) { - if (conn->prev == NULL) conn->mgr->active_connections = conn->next; - if (conn->prev) conn->prev->next = conn->next; - if (conn->next) conn->next->prev = conn->prev; -} - -// Print message to buffer. If buffer is large enough to hold the message, -// return buffer. If buffer is to small, allocate large enough buffer on heap, -// and return allocated buffer. -int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { - va_list ap_copy; - int len; - - va_copy(ap_copy, ap); - len = vsnprintf(*buf, size, fmt, ap_copy); - va_end(ap_copy); - - if (len < 0) { - // eCos and Windows are not standard-compliant and return -1 when - // the buffer is too small. Keep allocating larger buffers until we - // succeed or out of memory. - *buf = NULL; - while (len < 0) { - if (*buf) NS_FREE(*buf); - size *= 2; - if ((*buf = (char *) NS_MALLOC(size)) == NULL) break; - va_copy(ap_copy, ap); - len = vsnprintf(*buf, size, fmt, ap_copy); - va_end(ap_copy); - } - } else if (len > (int) size) { - // Standard-compliant code path. Allocate a buffer that is large enough. - if ((*buf = (char *) NS_MALLOC(len + 1)) == NULL) { - len = -1; - } else { - va_copy(ap_copy, ap); - len = vsnprintf(*buf, len + 1, fmt, ap_copy); - va_end(ap_copy); - } - } - - return len; -} - -int ns_vprintf(struct ns_connection *nc, const char *fmt, va_list ap) { - char mem[NS_VPRINTF_BUFFER_SIZE], *buf = mem; - int len; - - if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) { - ns_out(nc, buf, len); - } - if (buf != mem && buf != NULL) { - NS_FREE(buf); - } - - return len; -} - -int ns_printf(struct ns_connection *conn, const char *fmt, ...) { - int len; - va_list ap; - va_start(ap, fmt); - len = ns_vprintf(conn, fmt, ap); - va_end(ap); - return len; -} - -static void hexdump(struct ns_connection *nc, const char *path, - int num_bytes, int ev) { - const struct iobuf *io = ev == NS_SEND ? &nc->send_iobuf : &nc->recv_iobuf; - FILE *fp; - char *buf, src[60], dst[60]; - int buf_size = num_bytes * 5 + 100; - - if ((fp = fopen(path, "a")) != NULL) { - ns_sock_to_str(nc->sock, src, sizeof(src), 3); - ns_sock_to_str(nc->sock, dst, sizeof(dst), 7); - //printf("%p") - fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) time(NULL), - nc->user_data, src, - ev == NS_RECV ? "<-" : ev == NS_SEND ? "->" : - ev == NS_ACCEPT ? "" : "XX", - dst, num_bytes); - if (num_bytes > 0 && (buf = (char *) NS_MALLOC(buf_size)) != NULL) { - ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) - - (ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size); - fprintf(fp, "%s", buf); - NS_FREE(buf); - } - fclose(fp); - } -} - -static void ns_call(struct ns_connection *nc, int ev, void *p) { - if (nc->mgr->hexdump_file != NULL && ev != NS_POLL) { - int len = (ev == NS_RECV || ev == NS_SEND) ? * (int *) p : 0; - hexdump(nc, nc->mgr->hexdump_file, len, ev); - } - - nc->callback(nc, ev, p); -} - -static void ns_destroy_conn(struct ns_connection *conn) { - closesocket(conn->sock); - iobuf_free(&conn->recv_iobuf); - iobuf_free(&conn->send_iobuf); -#ifdef NS_ENABLE_SSL - if (conn->ssl != NULL) { - SSL_free(conn->ssl); - } - if (conn->ssl_ctx != NULL) { - SSL_CTX_free(conn->ssl_ctx); - } -#endif - NS_FREE(conn); -} - -static void ns_close_conn(struct ns_connection *conn) { - DBG(("%p %d", conn, conn->flags)); - ns_call(conn, NS_CLOSE, NULL); - ns_remove_conn(conn); - ns_destroy_conn(conn); -} - -void ns_set_close_on_exec(sock_t sock) { -#ifdef _WIN32 - (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); -#else - fcntl(sock, F_SETFD, FD_CLOEXEC); -#endif -} - -static void ns_set_non_blocking_mode(sock_t sock) { -#ifdef _WIN32 - unsigned long on = 1; - ioctlsocket(sock, FIONBIO, &on); -#else - int flags = fcntl(sock, F_GETFL, 0); - fcntl(sock, F_SETFL, flags | O_NONBLOCK); -#endif -} - -#ifndef NS_DISABLE_SOCKETPAIR -int ns_socketpair2(sock_t sp[2], int sock_type) { - union socket_address sa; - sock_t sock; - socklen_t len = sizeof(sa.sin); - int ret = 0; - - sp[0] = sp[1] = INVALID_SOCKET; - - (void) memset(&sa, 0, sizeof(sa)); - sa.sin.sin_family = AF_INET; - sa.sin.sin_port = htons(0); - sa.sin.sin_addr.s_addr = htonl(0x7f000001); - - if ((sock = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET && - !bind(sock, &sa.sa, len) && - (sock_type == SOCK_DGRAM || !listen(sock, 1)) && - !getsockname(sock, &sa.sa, &len) && - (sp[0] = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET && - !connect(sp[0], &sa.sa, len) && - (sock_type == SOCK_STREAM || - (!getsockname(sp[0], &sa.sa, &len) && !connect(sock, &sa.sa, len))) && - (sp[1] = (sock_type == SOCK_DGRAM ? sock : - accept(sock, &sa.sa, &len))) != INVALID_SOCKET) { - ns_set_close_on_exec(sp[0]); - ns_set_close_on_exec(sp[1]); - ret = 1; - } else { - if (sp[0] != INVALID_SOCKET) closesocket(sp[0]); - if (sp[1] != INVALID_SOCKET) closesocket(sp[1]); - sp[0] = sp[1] = INVALID_SOCKET; - } - if (sock_type != SOCK_DGRAM) closesocket(sock); - - return ret; -} - -int ns_socketpair(sock_t sp[2]) { - return ns_socketpair2(sp, SOCK_STREAM); -} -#endif // NS_DISABLE_SOCKETPAIR - -// TODO(lsm): use non-blocking resolver -static int ns_resolve2(const char *host, struct in_addr *ina) { -#ifdef NS_ENABLE_GETADDRINFO - int rv = 0; - struct addrinfo hints, *servinfo, *p; - struct sockaddr_in *h = NULL; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - if((rv = getaddrinfo(host, NULL , NULL, &servinfo)) != 0) { - DBG(("getaddrinfo(%s) failed: %s", host, strerror(errno))); - return 0; - } - - for(p = servinfo; p != NULL; p = p->ai_next) { - memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *)); - memcpy(ina, &h->sin_addr, sizeof(ina)); - } - - freeaddrinfo(servinfo); - return 1; -#else - struct hostent *he; - if ((he = gethostbyname(host)) == NULL) { - DBG(("gethostbyname(%s) failed: %s", host, strerror(errno))); - } else { - memcpy(ina, he->h_addr_list[0], sizeof(*ina)); - return 1; - } - return 0; -#endif -} - -// Resolve FDQN "host", store IP address in the "ip". -// Return > 0 (IP address length) on success. -int ns_resolve(const char *host, char *buf, size_t n) { - struct in_addr ad; - return ns_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0; -} - -// Address format: [PROTO://][IP_ADDRESS:]PORT[:CERT][:CA_CERT] -static int ns_parse_address(const char *str, union socket_address *sa, - int *proto, int *use_ssl, char *cert, char *ca) { - unsigned int a, b, c, d, port; - int n = 0, len = 0; - char host[200]; -#ifdef NS_ENABLE_IPV6 - char buf[100]; -#endif - - // MacOS needs that. If we do not zero it, subsequent bind() will fail. - // Also, all-zeroes in the socket address means binding to all addresses - // for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). - memset(sa, 0, sizeof(*sa)); - sa->sin.sin_family = AF_INET; - - *proto = SOCK_STREAM; - *use_ssl = 0; - cert[0] = ca[0] = '\0'; - - if (memcmp(str, "ssl://", 6) == 0) { - str += 6; - *use_ssl = 1; - } else if (memcmp(str, "udp://", 6) == 0) { - str += 6; - *proto = SOCK_DGRAM; - } else if (memcmp(str, "tcp://", 6) == 0) { - str += 6; - } - - if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) { - // Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 - sa->sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d); - sa->sin.sin_port = htons((uint16_t) port); -#ifdef NS_ENABLE_IPV6 - } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 && - inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) { - // IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 - sa->sin6.sin6_family = AF_INET6; - sa->sin6.sin6_port = htons((uint16_t) port); -#endif - } else if (sscanf(str, "%199[^ :]:%u%n", host, &port, &len) == 2) { - sa->sin.sin_port = htons((uint16_t) port); - ns_resolve2(host, &sa->sin.sin_addr); - } else if (sscanf(str, "%u%n", &port, &len) == 1) { - // If only port is specified, bind to IPv4, INADDR_ANY - sa->sin.sin_port = htons((uint16_t) port); - } - - if (*use_ssl && (sscanf(str + len, ":%99[^:,]:%99[^:,]%n", cert, ca, &n) == 2 || - sscanf(str + len, ":%99[^:,]%n", cert, &n) == 1)) { - len += n; - } - - return port < 0xffff && str[len] == '\0' ? len : 0; -} - -// 'sa' must be an initialized address to bind to -static sock_t ns_open_listening_socket(union socket_address *sa, int proto) { - socklen_t sa_len = (sa->sa.sa_family == AF_INET) ? - sizeof(sa->sin) : sizeof(sa->sin6); - sock_t sock = INVALID_SOCKET; -#ifndef _WIN32 - int on = 1; -#endif - - if ((sock = socket(sa->sa.sa_family, proto, 0)) != INVALID_SOCKET && -#ifndef _WIN32 - // SO_RESUSEADDR is not enabled on Windows because the semantics of - // SO_REUSEADDR on UNIX and Windows is different. On Windows, - // SO_REUSEADDR allows to bind a socket to a port without error even if - // the port is already open by another program. This is not the behavior - // SO_REUSEADDR was designed for, and leads to hard-to-track failure - // scenarios. Therefore, SO_REUSEADDR was disabled on Windows. - !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) && -#endif - !bind(sock, &sa->sa, sa_len) && - (proto == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) { - ns_set_non_blocking_mode(sock); - // In case port was set to 0, get the real port number - (void) getsockname(sock, &sa->sa, &sa_len); - } else if (sock != INVALID_SOCKET) { - closesocket(sock); - sock = INVALID_SOCKET; - } - - return sock; -} - -#ifdef NS_ENABLE_SSL -// Certificate generation script is at -// https://github.com/cesanta/net_skeleton/blob/master/scripts/gen_certs.sh - -static int ns_use_ca_cert(SSL_CTX *ctx, const char *cert) { - if (ctx == NULL) { - return -1; - } else if (cert == NULL || cert[0] == '\0') { - return 0; - } - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); - return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2; -} - -static int ns_use_cert(SSL_CTX *ctx, const char *pem_file) { - if (ctx == NULL) { - return -1; - } else if (pem_file == NULL || pem_file[0] == '\0') { - return 0; - } else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 || - SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) { - return -2; - } else { - SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_use_certificate_chain_file(ctx, pem_file); - return 0; - } -} -#endif // NS_ENABLE_SSL - -struct ns_connection *ns_bind(struct ns_mgr *srv, const char *str, - ns_callback_t callback, void *user_data) { - union socket_address sa; - struct ns_connection *nc = NULL; - int use_ssl, proto; - char cert[100], ca_cert[100]; - sock_t sock; - - ns_parse_address(str, &sa, &proto, &use_ssl, cert, ca_cert); - if (use_ssl && cert[0] == '\0') return NULL; - - if ((sock = ns_open_listening_socket(&sa, proto)) == INVALID_SOCKET) { - } else if ((nc = ns_add_sock(srv, sock, callback, NULL)) == NULL) { - closesocket(sock); - } else { - nc->sa = sa; - nc->flags |= NSF_LISTENING; - nc->user_data = user_data; - nc->callback = callback; - - if (proto == SOCK_DGRAM) { - nc->flags |= NSF_UDP; - } - -#ifdef NS_ENABLE_SSL - if (use_ssl) { - nc->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - if (ns_use_cert(nc->ssl_ctx, cert) != 0 || - ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0) { - ns_close_conn(nc); - nc = NULL; - } - } -#endif - - DBG(("%p sock %d/%d ssl %p %p", nc, sock, proto, nc->ssl_ctx, nc->ssl)); - } - - return nc; -} - -static struct ns_connection *accept_conn(struct ns_connection *ls) { - struct ns_connection *c = NULL; - union socket_address sa; - socklen_t len = sizeof(sa); - sock_t sock = INVALID_SOCKET; - - // NOTE(lsm): on Windows, sock is always > FD_SETSIZE - if ((sock = accept(ls->sock, &sa.sa, &len)) == INVALID_SOCKET) { - } else if ((c = ns_add_sock(ls->mgr, sock, ls->callback, - ls->user_data)) == NULL) { - closesocket(sock); -#ifdef NS_ENABLE_SSL - } else if (ls->ssl_ctx != NULL && - ((c->ssl = SSL_new(ls->ssl_ctx)) == NULL || - SSL_set_fd(c->ssl, sock) != 1)) { - DBG(("SSL error")); - ns_close_conn(c); - c = NULL; -#endif - } else { - c->listener = ls; - c->proto_data = ls->proto_data; - ns_call(c, NS_ACCEPT, &sa); - DBG(("%p %d %p %p", c, c->sock, c->ssl_ctx, c->ssl)); - } - - return c; -} - -static int ns_is_error(int n) { - return n == 0 || - (n < 0 && errno != EINTR && errno != EINPROGRESS && - errno != EAGAIN && errno != EWOULDBLOCK -#ifdef _WIN32 - && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK -#endif - ); -} - -void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) { - union socket_address sa; - socklen_t slen = sizeof(sa); - - if (buf != NULL && len > 0) { - buf[0] = '\0'; - memset(&sa, 0, sizeof(sa)); - if (flags & 4) { - getpeername(sock, &sa.sa, &slen); - } else { - getsockname(sock, &sa.sa, &slen); - } - if (flags & 1) { -#if defined(NS_ENABLE_IPV6) - inet_ntop(sa.sa.sa_family, sa.sa.sa_family == AF_INET ? - (void *) &sa.sin.sin_addr : - (void *) &sa.sin6.sin6_addr, buf, len); -#elif defined(_WIN32) - // Only Windoze Vista (and newer) have inet_ntop() - strncpy(buf, inet_ntoa(sa.sin.sin_addr), len); -#else - inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf,(socklen_t)len); -#endif - } - if (flags & 2) { - snprintf(buf + strlen(buf), len - (strlen(buf) + 1), "%s%d", - flags & 1 ? ":" : "", (int) ntohs(sa.sin.sin_port)); - } - } -} - -int ns_hexdump(const void *buf, int len, char *dst, int dst_len) { - const unsigned char *p = (const unsigned char *) buf; - char ascii[17] = ""; - int i, idx, n = 0; - - for (i = 0; i < len; i++) { - idx = i % 16; - if (idx == 0) { - if (i > 0) n += snprintf(dst + n, dst_len - n, " %s\n", ascii); - n += snprintf(dst + n, dst_len - n, "%04x ", i); - } - n += snprintf(dst + n, dst_len - n, " %02x", p[i]); - ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i]; - ascii[idx + 1] = '\0'; - } - - while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", " "); - n += snprintf(dst + n, dst_len - n, " %s\n\n", ascii); - - return n; -} - -#ifdef NS_ENABLE_SSL -static int ns_ssl_err(struct ns_connection *conn, int res) { - int ssl_err = SSL_get_error(conn->ssl, res); - if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ; - if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE; - return ssl_err; -} -#endif - -static void ns_read_from_socket(struct ns_connection *conn) { - char buf[NS_READ_BUFFER_SIZE]; - int n = 0; - - if (conn->flags & NSF_CONNECTING) { - int ok = 1, ret; - socklen_t len = sizeof(ok); - - ret = getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &ok, &len); - (void) ret; -#ifdef NS_ENABLE_SSL - if (ret == 0 && ok == 0 && conn->ssl != NULL) { - int res = SSL_connect(conn->ssl); - int ssl_err = ns_ssl_err(conn, res); - if (res == 1) { - conn->flags |= NSF_SSL_HANDSHAKE_DONE; - } else if (ssl_err == SSL_ERROR_WANT_READ || - ssl_err == SSL_ERROR_WANT_WRITE) { - return; // Call us again - } else { - ok = 1; - } - conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE); - } -#endif - conn->flags &= ~NSF_CONNECTING; - DBG(("%p ok=%d", conn, ok)); - if (ok != 0) { - conn->flags |= NSF_CLOSE_IMMEDIATELY; - } - ns_call(conn, NS_CONNECT, &ok); - return; - } - -#ifdef NS_ENABLE_SSL - if (conn->ssl != NULL) { - if (conn->flags & NSF_SSL_HANDSHAKE_DONE) { - // SSL library may have more bytes ready to read then we ask to read. - // Therefore, read in a loop until we read everything. Without the loop, - // we skip to the next select() cycle which can just timeout. - while ((n = SSL_read(conn->ssl, buf, sizeof(buf))) > 0) { - DBG(("%p %d <- %d bytes (SSL)", conn, conn->flags, n)); - iobuf_append(&conn->recv_iobuf, buf, n); - ns_call(conn, NS_RECV, &n); - } - ns_ssl_err(conn, n); - } else { - int res = SSL_accept(conn->ssl); - int ssl_err = ns_ssl_err(conn, res); - if (res == 1) { - conn->flags |= NSF_SSL_HANDSHAKE_DONE; - conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE); - } else if (ssl_err == SSL_ERROR_WANT_READ || - ssl_err == SSL_ERROR_WANT_WRITE) { - return; // Call us again - } else { - conn->flags |= NSF_CLOSE_IMMEDIATELY; - } - return; - } - } else -#endif - { - while ((n = (int) recv(conn->sock, buf, sizeof(buf), 0)) > 0) { - DBG(("%p %d <- %d bytes (PLAIN)", conn, conn->flags, n)); - iobuf_append(&conn->recv_iobuf, buf, n); - ns_call(conn, NS_RECV, &n); - } - } - - if (ns_is_error(n)) { - conn->flags |= NSF_CLOSE_IMMEDIATELY; - } -} - -static void ns_write_to_socket(struct ns_connection *conn) { - struct iobuf *io = &conn->send_iobuf; - int n = 0; - -#ifdef NS_ENABLE_SSL - if (conn->ssl != NULL) { - n = SSL_write(conn->ssl, io->buf, io->len); - if (n <= 0) { - int ssl_err = ns_ssl_err(conn, n); - if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { - return; // Call us again - } else { - conn->flags |= NSF_CLOSE_IMMEDIATELY; - } - } else { - conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE); - } - } else -#endif - { n = (int) send(conn->sock, io->buf, io->len, 0); } - - DBG(("%p %d -> %d bytes", conn, conn->flags, n)); - - ns_call(conn, NS_SEND, &n); - if (ns_is_error(n)) { - conn->flags |= NSF_CLOSE_IMMEDIATELY; - } else if (n > 0) { - iobuf_remove(io, n); - } -} - -int ns_send(struct ns_connection *conn, const void *buf, size_t len) { - return (int) ns_out(conn, buf, len); -} - -static void ns_handle_udp(struct ns_connection *ls) { - struct ns_connection nc; - char buf[NS_UDP_RECEIVE_BUFFER_SIZE]; - ssize_t n; - socklen_t s_len = sizeof(nc.sa); - - memset(&nc, 0, sizeof(nc)); - n = recvfrom(ls->sock, buf, sizeof(buf), 0, &nc.sa.sa, &s_len); - if (n <= 0) { - DBG(("%p recvfrom: %s", ls, strerror(errno))); - } else { - nc.mgr = ls->mgr; - nc.recv_iobuf.buf = buf; - nc.recv_iobuf.len = nc.recv_iobuf.size = n; - nc.sock = ls->sock; - nc.callback = ls->callback; - nc.user_data = ls->user_data; - nc.proto_data = ls->proto_data; - nc.mgr = ls->mgr; - nc.listener = ls; - nc.flags = NSF_UDP; - DBG(("%p %d bytes received", ls, n)); - ns_call(&nc, NS_RECV, &n); - } -} - -static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) { - if ( (sock != INVALID_SOCKET) && (sock < FD_SETSIZE) ) { - FD_SET(sock, set); - if (*max_fd == INVALID_SOCKET || sock > *max_fd) { - *max_fd = sock; - } - } -} - -time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) { - struct ns_connection *conn, *tmp_conn; - struct timeval tv; - fd_set read_set, write_set; - sock_t max_fd = INVALID_SOCKET; - time_t current_time = time(NULL); - - FD_ZERO(&read_set); - FD_ZERO(&write_set); - ns_add_to_set(mgr->ctl[1], &read_set, &max_fd); - for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) { - tmp_conn = conn->next; - if (!(conn->flags & (NSF_LISTENING | NSF_CONNECTING))) { - - printf("ns_mgr_poll test,ns_call\n"); - ns_call(conn, NS_POLL, ¤t_time); - } - if (conn->flags & NSF_CLOSE_IMMEDIATELY) { - ns_close_conn(conn); - } else { - if (!(conn->flags & NSF_WANT_WRITE)) { - //DBG(("%p read_set", conn)); - ns_add_to_set(conn->sock, &read_set, &max_fd); - } - if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) || - (conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) && - !(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) { - //DBG(("%p write_set", conn)); - ns_add_to_set(conn->sock, &write_set, &max_fd); - } - } - } - - tv.tv_sec = milli / 1000; - tv.tv_usec = (milli % 1000) * 1000; - - if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) < 0) { - return 0; - } else { - // select() might have been waiting for a long time, reset current_time - // now to prevent last_io_time being set to the past. - current_time = time(NULL); - - // Read wakeup messages - if (mgr->ctl[1] != INVALID_SOCKET && - FD_ISSET(mgr->ctl[1], &read_set)) { - struct ctl_msg ctl_msg; - int len = (int) recv(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0); - send(mgr->ctl[1], ctl_msg.message, 1, 0); - if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) { - struct ns_connection *c; - for (c = ns_next(mgr, NULL); c != NULL; c = ns_next(mgr, c)) { - ctl_msg.callback(c, NS_POLL, ctl_msg.message); - } - } - } - - for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) { - tmp_conn = conn->next; - if (FD_ISSET(conn->sock, &read_set)) { - if (conn->flags & NSF_LISTENING) { - if (conn->flags & NSF_UDP) { - ns_handle_udp(conn); - } else { - // We're not looping here, and accepting just one connection at - // a time. The reason is that eCos does not respect non-blocking - // flag on a listening socket and hangs in a loop. - accept_conn(conn); - } - } else { - conn->last_io_time = current_time; - ns_read_from_socket(conn); - } - } - - if (FD_ISSET(conn->sock, &write_set)) { - if (conn->flags & NSF_CONNECTING) { - ns_read_from_socket(conn); - } else if (!(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) { - conn->last_io_time = current_time; - ns_write_to_socket(conn); - } - } - } - } - - for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) { - tmp_conn = conn->next; - if ((conn->flags & NSF_CLOSE_IMMEDIATELY) || - (conn->send_iobuf.len == 0 && - (conn->flags & NSF_FINISHED_SENDING_DATA))) { - ns_close_conn(conn); - } - } - - return current_time; -} - -struct ns_connection *ns_connect(struct ns_mgr *mgr, const char *address, - ns_callback_t callback, void *user_data) { - sock_t sock = INVALID_SOCKET; - struct ns_connection *nc = NULL; - union socket_address sa; - char cert[100], ca_cert[100]; - int rc, use_ssl, proto; - - ns_parse_address(address, &sa, &proto, &use_ssl, cert, ca_cert); - if ((sock = socket(AF_INET, proto, 0)) == INVALID_SOCKET) { - return NULL; - } - ns_set_non_blocking_mode(sock); - rc = (proto == SOCK_DGRAM) ? 0 : connect(sock, &sa.sa, sizeof(sa.sin)); - - if (rc != 0 && ns_is_error(rc)) { - closesocket(sock); - return NULL; - } else if ((nc = ns_add_sock(mgr, sock, callback, user_data)) == NULL) { - closesocket(sock); - return NULL; - } - - nc->sa = sa; // Important, cause UDP conns will use sendto() - nc->flags = (proto == SOCK_DGRAM) ? NSF_UDP : NSF_CONNECTING; - -#ifdef NS_ENABLE_SSL - if (use_ssl) { - if ((nc->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL || - ns_use_cert(nc->ssl_ctx, cert) != 0 || - ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0 || - (nc->ssl = SSL_new(nc->ssl_ctx)) == NULL) { - ns_close_conn(nc); - return NULL; - } else { - SSL_set_fd(nc->ssl, sock); - } - } -#endif - - return nc; -} - -struct ns_connection *ns_add_sock(struct ns_mgr *s, sock_t sock, - ns_callback_t callback, void *user_data) { - struct ns_connection *conn; - if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) { - memset(conn, 0, sizeof(*conn)); - ns_set_non_blocking_mode(sock); - ns_set_close_on_exec(sock); - conn->sock = sock; - conn->user_data = user_data; - conn->callback = callback; - conn->mgr = s; - conn->last_io_time = time(NULL); - ns_add_conn(s, conn); - DBG(("%p %d", conn, sock)); - } - return conn; -} - -struct ns_connection *ns_next(struct ns_mgr *s, struct ns_connection *conn) { - return conn == NULL ? s->active_connections : conn->next; -} - -void ns_broadcast(struct ns_mgr *mgr, ns_callback_t cb,void *data, size_t len) { - struct ctl_msg ctl_msg; - if (mgr->ctl[0] != INVALID_SOCKET && data != NULL && - len < sizeof(ctl_msg.message)) { - ctl_msg.callback = cb; - memcpy(ctl_msg.message, data, len); - send(mgr->ctl[0], (char *) &ctl_msg, - offsetof(struct ctl_msg, message) + len, 0); - recv(mgr->ctl[0], (char *) &len, 1, 0); - } -} - -void ns_mgr_init(struct ns_mgr *s, void *user_data) { - memset(s, 0, sizeof(*s)); - s->ctl[0] = s->ctl[1] = INVALID_SOCKET; - s->user_data = user_data; - -#ifdef _WIN32 - { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); } -#else - // Ignore SIGPIPE signal, so if client cancels the request, it - // won't kill the whole process. - signal(SIGPIPE, SIG_IGN); -#endif - -#ifndef NS_DISABLE_SOCKETPAIR - { - int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS; - do { - ns_socketpair2(s->ctl, SOCK_DGRAM); - } while (s->ctl[0] == INVALID_SOCKET && ++attempts < max_attempts); - } -#endif - -#ifdef NS_ENABLE_SSL - {static int init_done; if (!init_done) { SSL_library_init(); init_done++; }} -#endif -} - -void ns_mgr_free(struct ns_mgr *s) { - struct ns_connection *conn, *tmp_conn; - - DBG(("%p", s)); - if (s == NULL) return; - // Do one last poll, see https://github.com/cesanta/mongoose/issues/286 - ns_mgr_poll(s, 0); - - if (s->ctl[0] != INVALID_SOCKET) closesocket(s->ctl[0]); - if (s->ctl[1] != INVALID_SOCKET) closesocket(s->ctl[1]); - s->ctl[0] = s->ctl[1] = INVALID_SOCKET; - - for (conn = s->active_connections; conn != NULL; conn = tmp_conn) { - tmp_conn = conn->next; - ns_close_conn(conn); - } -} -// net_skeleton end -#endif // NOEMBED_NET_SKELETON - -#include - -#ifdef _WIN32 //////////////// Windows specific defines and includes -#include // For _lseeki64 -#include // For _mkdir -#ifndef S_ISDIR -#define S_ISDIR(x) ((x) & _S_IFDIR) -#endif -#ifdef stat -#undef stat -#endif -#ifdef lseek -#undef lseek -#endif -#ifdef popen -#undef popen -#endif -#ifdef pclose -#undef pclose -#endif -#define stat(x, y) mg_stat((x), (y)) -#define fopen(x, y) mg_fopen((x), (y)) -#define open(x, y, z) mg_open((x), (y), (z)) -#define close(x) _close(x) -#define fileno(x) _fileno(x) -#define lseek(x, y, z) _lseeki64((x), (y), (z)) -#define read(x, y, z) _read((x), (y), (z)) -#define write(x, y, z) _write((x), (y), (z)) -#define popen(x, y) _popen((x), (y)) -#define pclose(x) _pclose(x) -#define mkdir(x, y) _mkdir(x) -#define rmdir(x) _rmdir(x) -#define strdup(x) _strdup(x) -#ifndef __func__ -#define STRX(x) #x -#define STR(x) STRX(x) -#define __func__ __FILE__ ":" STR(__LINE__) -#endif -#define INT64_FMT "I64d" -#define flockfile(x) ((void) (x)) -#define funlockfile(x) ((void) (x)) -typedef struct _stati64 file_stat_t; -typedef HANDLE process_id_t; - -#else ////////////// UNIX specific defines and includes - -#if !defined(MONGOOSE_NO_FILESYSTEM) &&\ - (!defined(MONGOOSE_NO_DAV) || !defined(MONGOOSE_NO_DIRECTORY_LISTING)) -#include -#endif -#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_DL) -#include -#endif -#include -#include -#if !defined(O_BINARY) -#define O_BINARY 0 -#endif -#define INT64_FMT PRId64 -typedef struct stat file_stat_t; -typedef pid_t process_id_t; -#endif //////// End of platform-specific defines and includes - -#include "mongoose.h" - -#define MAX_REQUEST_SIZE 16384 -#define IOBUF_SIZE 8192 -#define MAX_PATH_SIZE 8192 -#define DEFAULT_CGI_PATTERN "**.cgi$|**.pl$|**.php$" -#define CGI_ENVIRONMENT_SIZE 8192 -#define MAX_CGI_ENVIR_VARS 64 -#define ENV_EXPORT_TO_CGI "MONGOOSE_CGI" -#define PASSWORDS_FILE_NAME ".htpasswd" - -#ifndef MONGOOSE_USE_WEBSOCKET_PING_INTERVAL -#define MONGOOSE_USE_WEBSOCKET_PING_INTERVAL 5 -#endif - -// Extra HTTP headers to send in every static file reply -#if !defined(MONGOOSE_USE_EXTRA_HTTP_HEADERS) -#define MONGOOSE_USE_EXTRA_HTTP_HEADERS "" -#endif - -#ifndef MONGOOSE_POST_SIZE_LIMIT -#define MONGOOSE_POST_SIZE_LIMIT 0 -#endif - -#ifndef MONGOOSE_IDLE_TIMEOUT_SECONDS -#define MONGOOSE_IDLE_TIMEOUT_SECONDS 300 -#endif - -#if defined(NS_DISABLE_SOCKETPAIR) && !defined(MONGOOSE_NO_CGI) -#define MONGOOSE_NO_CGI -#endif - -#ifdef MONGOOSE_NO_FILESYSTEM -#define MONGOOSE_NO_AUTH -#if !defined(MONGOOSE_NO_CGI) -#define MONGOOSE_NO_CGI -#endif -#define MONGOOSE_NO_DAV -#define MONGOOSE_NO_DIRECTORY_LISTING -#define MONGOOSE_NO_LOGGING -#define MONGOOSE_NO_SSI -#define MONGOOSE_NO_DL -#endif - -struct vec { - const char *ptr; - size_t len; -}; - -// For directory listing and WevDAV support -struct dir_entry { - struct connection *conn; - char *file_name; - file_stat_t st; -}; - -// NOTE(lsm): this enum should be in sync with the config_options. -enum { - ACCESS_CONTROL_LIST, -#ifndef MONGOOSE_NO_FILESYSTEM - ACCESS_LOG_FILE, -#ifndef MONGOOSE_NO_AUTH - AUTH_DOMAIN, -#endif -#ifndef MONGOOSE_NO_CGI - CGI_INTERPRETER, - CGI_PATTERN, -#endif - DAV_AUTH_FILE, - DAV_ROOT, - DOCUMENT_ROOT, -#ifndef MONGOOSE_NO_DIRECTORY_LISTING - ENABLE_DIRECTORY_LISTING, -#endif -#endif - ENABLE_PROXY, - EXTRA_MIME_TYPES, -#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH) - GLOBAL_AUTH_FILE, -#endif -#ifndef MONGOOSE_NO_FILESYSTEM - HIDE_FILES_PATTERN, - HEXDUMP_FILE, - INDEX_FILES, -#endif - LISTENING_PORT, -#ifndef _WIN32 - RUN_AS_USER, -#endif -#ifndef MONGOOSE_NO_SSI - SSI_PATTERN, -#endif - URL_REWRITES, - NUM_OPTIONS -}; - -static const char *static_config_options[] = { - "access_control_list", NULL, -#ifndef MONGOOSE_NO_FILESYSTEM - "access_log_file", NULL, -#ifndef MONGOOSE_NO_AUTH - "auth_domain", "mydomain.com", -#endif -#ifndef MONGOOSE_NO_CGI - "cgi_interpreter", NULL, - "cgi_pattern", DEFAULT_CGI_PATTERN, -#endif - "dav_auth_file", NULL, - "dav_root", NULL, - "document_root", NULL, -#ifndef MONGOOSE_NO_DIRECTORY_LISTING - "enable_directory_listing", "yes", -#endif -#endif - "enable_proxy", NULL, - "extra_mime_types", NULL, -#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH) - "global_auth_file", NULL, -#endif -#ifndef MONGOOSE_NO_FILESYSTEM - "hide_files_patterns", NULL, - "hexdump_file", NULL, - "index_files","index.html,index.htm,index.shtml,index.cgi,index.php", -#endif - "listening_port", NULL, -#ifndef _WIN32 - "run_as_user", NULL, -#endif -#ifndef MONGOOSE_NO_SSI - "ssi_pattern", "**.shtml$|**.shtm$", -#endif - "url_rewrites", NULL, - NULL -}; - -struct mg_server { - struct ns_mgr ns_mgr; - union socket_address lsa; // Listening socket address - mg_handler_t event_handler; - char *config_options[NUM_OPTIONS]; -}; - -// Local endpoint representation -union endpoint { - int fd; // Opened regular local file - struct ns_connection *nc; // CGI or proxy->target connection -}; - -enum endpoint_type { - EP_NONE, EP_FILE, EP_CGI, EP_USER, EP_PUT, EP_CLIENT, EP_PROXY -}; - -#define MG_HEADERS_SENT NSF_USER_1 -#define MG_USING_CHUNKED_API NSF_USER_2 -#define MG_CGI_CONN NSF_USER_3 -#define MG_PROXY_CONN NSF_USER_4 -#define MG_PROXY_DONT_PARSE NSF_USER_5 - -struct connection { - struct ns_connection *ns_conn; // NOTE(lsm): main.c depends on this order - struct mg_connection mg_conn; - struct mg_server *server; - union endpoint endpoint; - enum endpoint_type endpoint_type; - char *path_info; - char *request; - int64_t num_bytes_recv; // Total number of bytes received - int64_t cl; // Reply content length, for Range support - ssize_t request_len; // Request length, including last \r\n after last header -}; - -#define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \ - offsetof(struct connection, mg_conn))) - -static void open_local_endpoint(struct connection *conn, int skip_user); -static void close_local_endpoint(struct connection *conn); -static void mg_ev_handler(struct ns_connection *nc, int ev, void *p); - -static const struct { - const char *extension; - size_t ext_len; - const char *mime_type; -} static_builtin_mime_types[] = { - {".html", 5, "text/html"}, - {".htm", 4, "text/html"}, - {".shtm", 5, "text/html"}, - {".shtml", 6, "text/html"}, - {".css", 4, "text/css"}, - {".js", 3, "application/javascript"}, - {".ico", 4, "image/x-icon"}, - {".gif", 4, "image/gif"}, - {".jpg", 4, "image/jpeg"}, - {".jpeg", 5, "image/jpeg"}, - {".png", 4, "image/png"}, - {".svg", 4, "image/svg+xml"}, - {".txt", 4, "text/plain"}, - {".torrent", 8, "application/x-bittorrent"}, - {".wav", 4, "audio/x-wav"}, - {".mp3", 4, "audio/x-mp3"}, - {".mid", 4, "audio/mid"}, - {".m3u", 4, "audio/x-mpegurl"}, - {".ogg", 4, "application/ogg"}, - {".ram", 4, "audio/x-pn-realaudio"}, - {".xml", 4, "text/xml"}, - {".json", 5, "application/json"}, - {".xslt", 5, "application/xml"}, - {".xsl", 4, "application/xml"}, - {".ra", 3, "audio/x-pn-realaudio"}, - {".doc", 4, "application/msword"}, - {".exe", 4, "application/octet-stream"}, - {".zip", 4, "application/x-zip-compressed"}, - {".xls", 4, "application/excel"}, - {".tgz", 4, "application/x-tar-gz"}, - {".tar", 4, "application/x-tar"}, - {".gz", 3, "application/x-gunzip"}, - {".arj", 4, "application/x-arj-compressed"}, - {".rar", 4, "application/x-rar-compressed"}, - {".rtf", 4, "application/rtf"}, - {".pdf", 4, "application/pdf"}, - {".swf", 4, "application/x-shockwave-flash"}, - {".mpg", 4, "video/mpeg"}, - {".webm", 5, "video/webm"}, - {".mpeg", 5, "video/mpeg"}, - {".mov", 4, "video/quicktime"}, - {".mp4", 4, "video/mp4"}, - {".m4v", 4, "video/x-m4v"}, - {".asf", 4, "video/x-ms-asf"}, - {".avi", 4, "video/x-msvideo"}, - {".bmp", 4, "image/bmp"}, - {".ttf", 4, "application/x-font-ttf"}, - {NULL, 0, NULL} -}; - -#ifdef MONGOOSE_ENABLE_THREADS -void *mg_start_thread(void *(*f)(void *), void *p) { - return ns_start_thread(f, p); -} -#endif // MONGOOSE_ENABLE_THREADS - -#ifndef MONGOOSE_NO_MMAP -#ifdef _WIN32 -static void *mmap(void *addr, int64_t len, int prot, int flags, int fd, - int offset) { - HANDLE fh = (HANDLE) _get_osfhandle(fd); - HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0); - void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len); - CloseHandle(mh); - return p; -} -#define munmap(x, y) UnmapViewOfFile(x) -#define MAP_FAILED NULL -#define MAP_PRIVATE 0 -#define PROT_READ 0 -#elif defined(__OS2__) -static void *mmap(void *addr, int64_t len, int prot, int flags, int fd, - int offset) { - void *p; - - int pos = lseek( fd, 0, SEEK_CUR ); /* Get a current position */ - - if (pos == -1) - return NULL; - - /* Seek to offset offset */ - if (lseek( fd, offset, SEEK_SET) == -1) - return NULL; - - p = malloc(len); - - /* Read in a file */ - if (!p || read(fd, p, len) == -1) { - free(p); - p = NULL; - } - - /* Restore the position */ - lseek(fd, pos, SEEK_SET); - - return p; -} -#define munmap(x, y) free(x) -#define MAP_FAILED NULL -#define MAP_PRIVATE 0 -#define PROT_READ 0 -#else -#include -#endif - -void *mg_mmap(FILE *fp, size_t size) { - void *p = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fileno(fp), 0); - return p == MAP_FAILED ? NULL : p; -} - -void mg_munmap(void *p, size_t size) { - munmap(p, size); -} -#endif // MONGOOSE_NO_MMAP - -#if defined(_WIN32) && !defined(MONGOOSE_NO_FILESYSTEM) -// Encode 'path' which is assumed UTF-8 string, into UNICODE string. -// wbuf and wbuf_len is a target buffer and its length. -static void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) { - char buf[MAX_PATH_SIZE * 2], buf2[MAX_PATH_SIZE * 2], *p; - - strncpy(buf, path, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; - - // Trim trailing slashes. Leave backslash for paths like "X:\" - p = buf + strlen(buf) - 1; - while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0'; - - // Convert to Unicode and back. If doubly-converted string does not - // match the original, something is fishy, reject. - memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); - WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), - NULL, NULL); - if (strcmp(buf, buf2) != 0) { - wbuf[0] = L'\0'; - } -} - -static int mg_stat(const char *path, file_stat_t *st) { - wchar_t wpath[MAX_PATH_SIZE]; - to_wchar(path, wpath, ARRAY_SIZE(wpath)); - DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st))); - return _wstati64(wpath, st); -} - -static FILE *mg_fopen(const char *path, const char *mode) { - wchar_t wpath[MAX_PATH_SIZE], wmode[10]; - to_wchar(path, wpath, ARRAY_SIZE(wpath)); - to_wchar(mode, wmode, ARRAY_SIZE(wmode)); - return _wfopen(wpath, wmode); -} - -static int mg_open(const char *path, int flag, int mode) { - wchar_t wpath[MAX_PATH_SIZE]; - to_wchar(path, wpath, ARRAY_SIZE(wpath)); - return _wopen(wpath, flag, mode); -} -#endif // _WIN32 && !MONGOOSE_NO_FILESYSTEM - -// A helper function for traversing a comma separated list of values. -// It returns a list pointer shifted to the next value, or NULL if the end -// of the list found. -// Value is stored in val vector. If value has form "x=y", then eq_val -// vector is initialized to point to the "y" part, and val vector length -// is adjusted to point only to "x". -static const char *next_option(const char *list, struct vec *val, - struct vec *eq_val) { - if (list == NULL || *list == '\0') { - // End of the list - list = NULL; - } else { - val->ptr = list; - if ((list = strchr(val->ptr, ',')) != NULL) { - // Comma found. Store length and shift the list ptr - val->len = list - val->ptr; - list++; - } else { - // This value is the last one - list = val->ptr + strlen(val->ptr); - val->len = list - val->ptr; - } - - if (eq_val != NULL) { - // Value has form "x=y", adjust pointers and lengths - // so that val points to "x", and eq_val points to "y". - eq_val->len = 0; - eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len); - if (eq_val->ptr != NULL) { - eq_val->ptr++; // Skip over '=' character - eq_val->len = val->ptr + val->len - eq_val->ptr; - val->len = (eq_val->ptr - val->ptr) - 1; - } - } - } - - return list; -} - -// Like snprintf(), but never returns negative value, or a value -// that is larger than a supplied buffer. -static int mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) { - int n; - if (buflen < 1) return 0; - n = vsnprintf(buf, buflen, fmt, ap); - if (n < 0) { - n = 0; - } else if (n >= (int) buflen) { - n = (int) buflen - 1; - } - buf[n] = '\0'; - return n; -} - -static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) { - va_list ap; - int n; - va_start(ap, fmt); - n = mg_vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - return n; -} - -// Check whether full request is buffered. Return: -// -1 if request is malformed -// 0 if request is not yet fully buffered -// >0 actual request length, including last \r\n\r\n -static int get_request_len(const char *s, size_t buf_len) { - const unsigned char *buf = (unsigned char *) s; - size_t i; - - for (i = 0; i < buf_len; i++) { - // Control characters are not allowed but >=128 are. - // Abort scan as soon as one malformed character is found. - if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) { - return -1; - } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') { - return i + 2; - } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' && - buf[i + 2] == '\n') { - return i + 3; - } - } - - return 0; -} - -// Skip the characters until one of the delimiters characters found. -// 0-terminate resulting word. Skip the rest of the delimiters if any. -// Advance pointer to buffer to the next word. Return found 0-terminated word. -static char *skip(char **buf, const char *delimiters) { - char *p, *begin_word, *end_word, *end_delimiters; - - begin_word = *buf; - end_word = begin_word + strcspn(begin_word, delimiters); - end_delimiters = end_word + strspn(end_word, delimiters); - - for (p = end_word; p < end_delimiters; p++) { - *p = '\0'; - } - - *buf = end_delimiters; - - return begin_word; -} - -// Parse HTTP headers from the given buffer, advance buffer to the point -// where parsing stopped. -static void parse_http_headers(char **buf, struct mg_connection *ri) { - size_t i; - - for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) { - ri->http_headers[i].name = skip(buf, ": "); - ri->http_headers[i].value = skip(buf, "\r\n"); - if (ri->http_headers[i].name[0] == '\0') - break; - ri->num_headers = i + 1; - } -} - -static const char *status_code_to_str(int status_code) { - switch (status_code) { - - case 100: return "Continue"; - case 101: return "Switching Protocols"; - case 102: return "Processing"; - - case 200: return "OK"; - case 201: return "Created"; - case 202: return "Accepted"; - case 203: return "Non-Authoritative Information"; - case 204: return "No Content"; - case 205: return "Reset Content"; - case 206: return "Partial Content"; - case 207: return "Multi-Status"; - case 208: return "Already Reported"; - case 226: return "IM Used"; - - case 300: return "Multiple Choices"; - case 301: return "Moved Permanently"; - case 302: return "Found"; - case 303: return "See Other"; - case 304: return "Not Modified"; - case 305: return "Use Proxy"; - case 306: return "Switch Proxy"; - case 307: return "Temporary Redirect"; - case 308: return "Permanent Redirect"; - - case 400: return "Bad Request"; - case 401: return "Unauthorized"; - case 402: return "Payment Required"; - case 403: return "Forbidden"; - case 404: return "Not Found"; - case 405: return "Method Not Allowed"; - case 406: return "Not Acceptable"; - case 407: return "Proxy Authentication Required"; - case 408: return "Request Timeout"; - case 409: return "Conflict"; - case 410: return "Gone"; - case 411: return "Length Required"; - case 412: return "Precondition Failed"; - case 413: return "Payload Too Large"; - case 414: return "URI Too Long"; - case 415: return "Unsupported Media Type"; - case 416: return "Requested Range Not Satisfiable"; - case 417: return "Expectation Failed"; - case 418: return "I\'m a teapot"; - case 422: return "Unprocessable Entity"; - case 423: return "Locked"; - case 424: return "Failed Dependency"; - case 426: return "Upgrade Required"; - case 428: return "Precondition Required"; - case 429: return "Too Many Requests"; - case 431: return "Request Header Fields Too Large"; - case 451: return "Unavailable For Legal Reasons"; - - case 500: return "Internal Server Error"; - case 501: return "Not Implemented"; - case 502: return "Bad Gateway"; - case 503: return "Service Unavailable"; - case 504: return "Gateway Timeout"; - case 505: return "HTTP Version Not Supported"; - case 506: return "Variant Also Negotiates"; - case 507: return "Insufficient Storage"; - case 508: return "Loop Detected"; - case 510: return "Not Extended"; - case 511: return "Network Authentication Required"; - - default: return "Server Error"; - } -} - -static int call_user(struct connection *conn, enum mg_event ev) { - return conn != NULL && conn->server != NULL && - conn->server->event_handler != NULL ? - conn->server->event_handler(&conn->mg_conn, ev) : MG_FALSE; -} - -static void send_http_error(struct connection *conn, int code, - const char *fmt, ...) { - const char *message = status_code_to_str(code); - const char *rewrites = conn->server->config_options[URL_REWRITES]; - char headers[200], body[200]; - struct vec a, b; - va_list ap; - int body_len, headers_len, match_code; - - conn->mg_conn.status_code = code; - - // Invoke error handler if it is set - if (call_user(conn, MG_HTTP_ERROR) == MG_TRUE) { - close_local_endpoint(conn); - return; - } - - // Handle error code rewrites - while ((rewrites = next_option(rewrites, &a, &b)) != NULL) { - if ((match_code = atoi(a.ptr)) > 0 && match_code == code) { - struct mg_connection *c = &conn->mg_conn; - c->status_code = 302; - mg_printf(c, "HTTP/1.1 %d Moved\r\n" - "Location: %.*s?code=%d&orig_uri=%s&query_string=%s\r\n\r\n", - c->status_code, b.len, b.ptr, code, c->uri, - c->query_string == NULL ? "" : c->query_string); - close_local_endpoint(conn); - return; - } - } - - body_len = mg_snprintf(body, sizeof(body), "%d %s\n", code, message); - if (fmt != NULL) { - va_start(ap, fmt); - body_len += mg_vsnprintf(body + body_len, sizeof(body) - body_len, fmt, ap); - va_end(ap); - } - if ((code >= 300 && code <= 399) || code == 204) { - // 3xx errors do not have body - body_len = 0; - } - headers_len = mg_snprintf(headers, sizeof(headers), - "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n" - "Content-Type: text/plain\r\n\r\n", - code, message, body_len); - ns_send(conn->ns_conn, headers, headers_len); - ns_send(conn->ns_conn, body, body_len); - close_local_endpoint(conn); // This will write to the log file -} - -static void write_chunk(struct connection *conn, const char *buf, int len) { - char chunk_size[50]; - int n = mg_snprintf(chunk_size, sizeof(chunk_size), "%X\r\n", len); - ns_send(conn->ns_conn, chunk_size, n); - ns_send(conn->ns_conn, buf, len); - ns_send(conn->ns_conn, "\r\n", 2); -} - -size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) { - va_list ap; - int ret; - - va_start(ap, fmt); - ret = mg_vprintf(conn, fmt, ap); - va_end(ap); - - return ret; -} - -size_t mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) { - struct connection *c = MG_CONN_2_CONN(conn); - - ns_vprintf(c->ns_conn, fmt, ap); - - return c->ns_conn->send_iobuf.len; -} - -static void ns_forward(struct ns_connection *from, struct ns_connection *to) { - DBG(("%p -> %p %lu bytes", from, to, (unsigned long)from->recv_iobuf.len)); - ns_send(to, from->recv_iobuf.buf, from->recv_iobuf.len); - iobuf_remove(&from->recv_iobuf, from->recv_iobuf.len); -} - -#ifndef MONGOOSE_NO_CGI -#ifdef _WIN32 -struct threadparam { - sock_t s; - HANDLE hPipe; -}; - -static int wait_until_ready(sock_t sock, int for_read) { - fd_set set; - if ( (sock == INVALID_SOCKET) || (sock >= FD_SETSIZE) ) - return 0; - FD_ZERO(&set); - FD_SET(sock, &set); - select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0); - return 1; -} - -static void *push_to_stdin(void *arg) { - struct threadparam *tp = (struct threadparam *)arg; - int n, sent, stop = 0; - DWORD k; - char buf[IOBUF_SIZE]; - - while (!stop && wait_until_ready(tp->s, 1) && - (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) { - if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue; - for (sent = 0; !stop && sent < n; sent += k) { - if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1; - } - } - DBG(("%s", "FORWARDED EVERYTHING TO CGI")); - CloseHandle(tp->hPipe); - NS_FREE(tp); - _endthread(); - return NULL; -} - -static void *pull_from_stdout(void *arg) { - struct threadparam *tp = (struct threadparam *)arg; - int k = 0, stop = 0; - DWORD n, sent; - char buf[IOBUF_SIZE]; - - while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) { - for (sent = 0; !stop && sent < n; sent += k) { - if (wait_until_ready(tp->s, 0) && - (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) stop = 1; - } - } - DBG(("%s", "EOF FROM CGI")); - CloseHandle(tp->hPipe); - shutdown(tp->s, 2); // Without this, IO thread may get truncated data - closesocket(tp->s); - NS_FREE(tp); - _endthread(); - return NULL; -} - -static void spawn_stdio_thread(sock_t sock, HANDLE hPipe, - void *(*func)(void *)) { - struct threadparam *tp = (struct threadparam *)NS_MALLOC(sizeof(*tp)); - if (tp != NULL) { - tp->s = sock; - tp->hPipe = hPipe; - mg_start_thread(func, tp); - } -} - -static void abs_path(const char *utf8_path, char *abs_path, size_t len) { - wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE]; - to_wchar(utf8_path, buf, ARRAY_SIZE(buf)); - GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL); - WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0); -} - -static process_id_t start_process(char *interp, const char *cmd, - const char *env, const char *envp[], - const char *dir, sock_t sock) { - STARTUPINFOW si; - PROCESS_INFORMATION pi; - HANDLE a[2], b[2], me = GetCurrentProcess(); - wchar_t wcmd[MAX_PATH_SIZE], full_dir[MAX_PATH_SIZE]; - char buf[MAX_PATH_SIZE], buf4[MAX_PATH_SIZE], buf5[MAX_PATH_SIZE], - cmdline[MAX_PATH_SIZE], *p; - DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS; - FILE *fp; - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - - CreatePipe(&a[0], &a[1], NULL, 0); - CreatePipe(&b[0], &b[1], NULL, 0); - DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags); - DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags); - - if (interp == NULL && (fp = fopen(cmd, "r")) != NULL) { - buf[0] = buf[1] = '\0'; - fgets(buf, sizeof(buf), fp); - buf[sizeof(buf) - 1] = '\0'; - if (buf[0] == '#' && buf[1] == '!') { - interp = buf + 2; - for (p = interp + strlen(interp) - 1; - isspace(* (uint8_t *) p) && p > interp; p--) *p = '\0'; - } - fclose(fp); - } - - if (interp != NULL) { - abs_path(interp, buf4, ARRAY_SIZE(buf4)); - interp = buf4; - } - abs_path(dir, buf5, ARRAY_SIZE(buf5)); - to_wchar(dir, full_dir, ARRAY_SIZE(full_dir)); - mg_snprintf(cmdline, sizeof(cmdline), "%s%s\"%s\"", - interp ? interp : "", interp ? " " : "", cmd); - to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd)); - - if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, - (void *) env, full_dir, &si, &pi) != 0) { - spawn_stdio_thread(sock, a[1], push_to_stdin); - spawn_stdio_thread(sock, b[0], pull_from_stdout); - } else { - CloseHandle(a[1]); - CloseHandle(b[0]); - closesocket(sock); - } - DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess)); - - // Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdInput); - //CloseHandle(pi.hThread); - //CloseHandle(pi.hProcess); - - return pi.hProcess; -} -#else -static process_id_t start_process(const char *interp, const char *cmd, - const char *env, const char *envp[], - const char *dir, sock_t sock) { - char buf[500]; - process_id_t pid = fork(); - (void) env; - - if (pid == 0) { - (void) chdir(dir); - (void) dup2(sock, 0); - (void) dup2(sock, 1); - closesocket(sock); - - // After exec, all signal handlers are restored to their default values, - // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's - // implementation, SIGCHLD's handler will leave unchanged after exec - // if it was set to be ignored. Restore it to default action. - signal(SIGCHLD, SIG_DFL); - - if (interp == NULL) { - execle(cmd, cmd, (char *) 0, envp); // Using (char *) 0 to avoid warning - } else { - execle(interp, interp, cmd, (char *) 0, envp); - } - snprintf(buf, sizeof(buf), "Status: 500\r\n\r\n" - "500 Server Error: %s%s%s: %s", interp == NULL ? "" : interp, - interp == NULL ? "" : " ", cmd, strerror(errno)); - send(1, buf, strlen(buf), 0); - exit(EXIT_FAILURE); // exec call failed - } - - return pid; -} -#endif // _WIN32 - -// This structure helps to create an environment for the spawned CGI program. -// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings, -// last element must be NULL. -// However, on Windows there is a requirement that all these VARIABLE=VALUE\0 -// strings must reside in a contiguous buffer. The end of the buffer is -// marked by two '\0' characters. -// We satisfy both worlds: we create an envp array (which is vars), all -// entries are actually pointers inside buf. -struct cgi_env_block { - struct mg_connection *conn; - char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer - const char *vars[MAX_CGI_ENVIR_VARS]; // char *envp[] - int len; // Space taken - int nvars; // Number of variables in envp[] -}; - -// Append VARIABLE=VALUE\0 string to the buffer, and add a respective -// pointer into the vars array. -static char *addenv(struct cgi_env_block *block, const char *fmt, ...) { - int n, space; - char *added; - va_list ap; - - // Calculate how much space is left in the buffer - space = sizeof(block->buf) - block->len - 2; - assert(space >= 0); - - // Make a pointer to the free space int the buffer - added = block->buf + block->len; - - // Copy VARIABLE=VALUE\0 string into the free space - va_start(ap, fmt); - n = mg_vsnprintf(added, (size_t) space, fmt, ap); - va_end(ap); - - // Make sure we do not overflow buffer and the envp array - if (n > 0 && n + 1 < space && - block->nvars < (int) ARRAY_SIZE(block->vars) - 2) { - // Append a pointer to the added string into the envp array - block->vars[block->nvars++] = added; - // Bump up used length counter. Include \0 terminator - block->len += n + 1; - } - - return added; -} - -static void addenv2(struct cgi_env_block *blk, const char *name) { - const char *s; - if ((s = getenv(name)) != NULL) addenv(blk, "%s=%s", name, s); -} - -static void prepare_cgi_environment(struct connection *conn, - const char *prog, - struct cgi_env_block *blk) { - struct mg_connection *ri = &conn->mg_conn; - const char *s, *slash; - char *p, **opts = conn->server->config_options; - int i; - - blk->len = blk->nvars = 0; - blk->conn = ri; - - if ((s = getenv("SERVER_NAME")) != NULL) { - addenv(blk, "SERVER_NAME=%s", s); - } else { - addenv(blk, "SERVER_NAME=%s", ri->local_ip); - } - addenv(blk, "SERVER_ROOT=%s", opts[DOCUMENT_ROOT]); - addenv(blk, "DOCUMENT_ROOT=%s", opts[DOCUMENT_ROOT]); - addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MONGOOSE_VERSION); - - // Prepare the environment block - addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1"); - addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1"); - addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP - - // TODO(lsm): fix this for IPv6 case - //addenv(blk, "SERVER_PORT=%d", ri->remote_port); - - addenv(blk, "REQUEST_METHOD=%s", ri->request_method); - addenv(blk, "REMOTE_ADDR=%s", ri->remote_ip); - addenv(blk, "REMOTE_PORT=%d", ri->remote_port); - addenv(blk, "REQUEST_URI=%s%s%s", ri->uri, - ri->query_string == NULL ? "" : "?", - ri->query_string == NULL ? "" : ri->query_string); - - // SCRIPT_NAME - if (conn->path_info != NULL) { - addenv(blk, "SCRIPT_NAME=%.*s", - (int) (strlen(ri->uri) - strlen(conn->path_info)), ri->uri); - addenv(blk, "PATH_INFO=%s", conn->path_info); - } else { - s = strrchr(prog, '/'); - slash = strrchr(ri->uri, '/'); - addenv(blk, "SCRIPT_NAME=%.*s%s", - slash == NULL ? 0 : (int) (slash - ri->uri), ri->uri, - s == NULL ? prog : s); - } - - addenv(blk, "SCRIPT_FILENAME=%s", prog); - addenv(blk, "PATH_TRANSLATED=%s", prog); - addenv(blk, "HTTPS=%s", conn->ns_conn->ssl != NULL ? "on" : "off"); - - if ((s = mg_get_header(ri, "Content-Type")) != NULL) - addenv(blk, "CONTENT_TYPE=%s", s); - - if (ri->query_string != NULL) - addenv(blk, "QUERY_STRING=%s", ri->query_string); - - if ((s = mg_get_header(ri, "Content-Length")) != NULL) - addenv(blk, "CONTENT_LENGTH=%s", s); - - addenv2(blk, "PATH"); - addenv2(blk, "TMP"); - addenv2(blk, "TEMP"); - addenv2(blk, "TMPDIR"); - addenv2(blk, "PERLLIB"); - addenv2(blk, ENV_EXPORT_TO_CGI); - -#if defined(_WIN32) - addenv2(blk, "COMSPEC"); - addenv2(blk, "SYSTEMROOT"); - addenv2(blk, "SystemDrive"); - addenv2(blk, "ProgramFiles"); - addenv2(blk, "ProgramFiles(x86)"); - addenv2(blk, "CommonProgramFiles(x86)"); -#else - addenv2(blk, "LD_LIBRARY_PATH"); -#endif // _WIN32 - - // Add all headers as HTTP_* variables - for (i = 0; i < ri->num_headers; i++) { - p = addenv(blk, "HTTP_%s=%s", - ri->http_headers[i].name, ri->http_headers[i].value); - - // Convert variable name into uppercase, and change - to _ - for (; *p != '=' && *p != '\0'; p++) { - if (*p == '-') - *p = '_'; - *p = (char) toupper(* (unsigned char *) p); - } - } - - blk->vars[blk->nvars++] = NULL; - blk->buf[blk->len++] = '\0'; - - assert(blk->nvars < (int) ARRAY_SIZE(blk->vars)); - assert(blk->len > 0); - assert(blk->len < (int) sizeof(blk->buf)); -} - -static const char cgi_status[] = "HTTP/1.1 200 OK\r\n"; - -static void open_cgi_endpoint(struct connection *conn, const char *prog) { - struct cgi_env_block blk; - char dir[MAX_PATH_SIZE]; - const char *p; - sock_t fds[2]; - - prepare_cgi_environment(conn, prog, &blk); - // CGI must be executed in its own directory. 'dir' must point to the - // directory containing executable program, 'p' must point to the - // executable program name relative to 'dir'. - if ((p = strrchr(prog, '/')) == NULL) { - mg_snprintf(dir, sizeof(dir), "%s", "."); - } else { - mg_snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog); - } - - // Try to create socketpair in a loop until success. ns_socketpair() - // can be interrupted by a signal and fail. - // TODO(lsm): use sigaction to restart interrupted syscall - { - int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS; - do { - ns_socketpair(fds); - } while (fds[0] == INVALID_SOCKET && ++attempts < max_attempts); - - if (fds[0] == INVALID_SOCKET) { - closesocket(fds[0]); - send_http_error(conn, 500, "ns_socketpair() failed"); - } - } - - if (start_process(conn->server->config_options[CGI_INTERPRETER], - prog, blk.buf, blk.vars, dir, fds[1]) != 0) { - conn->endpoint_type = EP_CGI; - conn->endpoint.nc = ns_add_sock(&conn->server->ns_mgr, fds[0], - mg_ev_handler, conn); - conn->endpoint.nc->flags |= MG_CGI_CONN; - ns_send(conn->ns_conn, cgi_status, sizeof(cgi_status) - 1); - conn->mg_conn.status_code = 200; - conn->ns_conn->flags |= NSF_BUFFER_BUT_DONT_SEND; - // Pass POST data to the CGI process - conn->endpoint.nc->send_iobuf = conn->ns_conn->recv_iobuf; - iobuf_init(&conn->ns_conn->recv_iobuf, 0); - } else { - closesocket(fds[0]); - send_http_error(conn, 500, "start_process(%s) failed", prog); - } - -#ifndef _WIN32 - closesocket(fds[1]); // On Windows, CGI stdio thread closes that socket -#endif -} - -static void on_cgi_data(struct ns_connection *nc) { - struct connection *conn = (struct connection *) nc->user_data; - const char *status = "500"; - struct mg_connection c; - - if (!conn) return; - - // Copy CGI data from CGI socket to the client send buffer - ns_forward(nc, conn->ns_conn); - - // If reply has not been parsed yet, parse it - if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) { - struct iobuf *io = &conn->ns_conn->send_iobuf; - size_t s_len = sizeof(cgi_status) - 1; - int len = get_request_len(io->buf + s_len, io->len - s_len); - char buf[MAX_REQUEST_SIZE], *s = buf; - - if (len == 0) return; - - if (len < 0 || len > (int) sizeof(buf)) { - len = io->len; - iobuf_remove(io, io->len); - send_http_error(conn, 500, "CGI program sent malformed headers: [%.*s]", - len, io->buf); - } else { - memset(&c, 0, sizeof(c)); - memcpy(buf, io->buf + s_len, len); - buf[len - 1] = '\0'; - parse_http_headers(&s, &c); - if (mg_get_header(&c, "Location") != NULL) { - status = "302"; - } else if ((status = (char *) mg_get_header(&c, "Status")) == NULL) { - status = "200"; - } - memcpy(io->buf + 9, status, 3); - conn->mg_conn.status_code = atoi(status); - } - conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND; - } -} -#endif // !MONGOOSE_NO_CGI - -static char *mg_strdup(const char *str) { - char *copy = (char *) NS_MALLOC(strlen(str) + 1); - if (copy != NULL) { - strcpy(copy, str); - } - return copy; -} - -static int isbyte(int n) { - return n >= 0 && n <= 255; -} - -static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) { - int n, a, b, c, d, slash = 32, len = 0; - - if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 || - sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) && - isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && - slash >= 0 && slash < 33) { - len = n; - *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d; - *mask = slash ? 0xffffffffU << (32 - slash) : 0; - } - - return len; -} - -// Verify given socket address against the ACL. -// Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed. -static int check_acl(const char *acl, uint32_t remote_ip) { - int allowed, flag; - uint32_t net, mask; - struct vec vec; - - // If any ACL is set, deny by default - allowed = acl == NULL ? '+' : '-'; - - while ((acl = next_option(acl, &vec, NULL)) != NULL) { - flag = vec.ptr[0]; - if ((flag != '+' && flag != '-') || - parse_net(&vec.ptr[1], &net, &mask) == 0) { - return -1; - } - - if (net == (remote_ip & mask)) { - allowed = flag; - } - } - - return allowed == '+'; -} - -// Protect against directory disclosure attack by removing '..', -// excessive '/' and '\' characters -static void remove_double_dots_and_double_slashes(char *s) { - char *p = s; - - while (*s != '\0') { - *p++ = *s++; - if (s[-1] == '/' || s[-1] == '\\') { - // Skip all following slashes, backslashes and double-dots - while (s[0] != '\0') { - if (s[0] == '/' || s[0] == '\\') { s++; } - else if (s[0] == '.' && (s[1] == '/' || s[1] == '\\')) { s += 2; } - else if (s[0] == '.' && s[1] == '.' && s[2] == '\0') { s += 2; } - else if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\\')) { s += 3; } - else { break; } - } - } - } - *p = '\0'; -} - -int mg_url_decode(const char *src, size_t src_len, char *dst, - size_t dst_len, int is_form_url_encoded) { - size_t i, j = 0; - int a, b; -#define HEXTOI(x) (isdigit(x) ? (x) - '0' : (x) - 'W') - - for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { - if (src[i] == '%' && i + 2 < src_len && - isxdigit(* (const unsigned char *) (src + i + 1)) && - isxdigit(* (const unsigned char *) (src + i + 2))) { - a = tolower(* (const unsigned char *) (src + i + 1)); - b = tolower(* (const unsigned char *) (src + i + 2)); - dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); - i += 2; - } else if (is_form_url_encoded && src[i] == '+') { - dst[j] = ' '; - } else { - dst[j] = src[i]; - } - } - - dst[j] = '\0'; // Null-terminate the destination - - return i >= src_len ? j : -1; -} - -static int is_valid_http_method(const char *s) { - return !strcmp(s, "GET") || !strcmp(s, "POST") || !strcmp(s, "HEAD") || - !strcmp(s, "CONNECT") || !strcmp(s, "PUT") || !strcmp(s, "DELETE") || - !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL") || - !strcmp(s, "PATCH"); -} - -// Parse HTTP request, fill in mg_request structure. -// This function modifies the buffer by NUL-terminating -// HTTP request components, header names and header values. -// Note that len must point to the last \n of HTTP headers. -static size_t parse_http_message(char *buf, size_t len, - struct mg_connection *ri) { - int is_request, n; - - // Reset the connection. Make sure that we don't touch fields that are - // set elsewhere: remote_ip, remote_port, server_param - ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL; - ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0; - - if (len < 1) return ~0; - - buf[len - 1] = '\0'; - - // RFC says that all initial whitespaces should be ignored - while (*buf != '\0' && isspace(* (unsigned char *) buf)) { - buf++; - } - ri->request_method = skip(&buf, " "); - ri->uri = skip(&buf, " "); - ri->http_version = skip(&buf, "\r\n"); - - // HTTP message could be either HTTP request or HTTP response, e.g. - // "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." - is_request = is_valid_http_method(ri->request_method); - if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) || - (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { - len = ~0; - } else { - if (is_request) { - ri->http_version += 5; - } else { - ri->status_code = atoi(ri->uri); - } - parse_http_headers(&buf, ri); - - if ((ri->query_string = strchr(ri->uri, '?')) != NULL) { - *(char *) ri->query_string++ = '\0'; - } - n = (int) strlen(ri->uri); - mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0); - if (*ri->uri == '/' || *ri->uri == '.') { - remove_double_dots_and_double_slashes((char *) ri->uri); - } - } - - return len; -} - -static int lowercase(const char *s) { - return tolower(* (const unsigned char *) s); -} - -static int mg_strcasecmp(const char *s1, const char *s2) { - int diff; - - do { - diff = lowercase(s1++) - lowercase(s2++); - } while (diff == 0 && s1[-1] != '\0'); - - return diff; -} - -static int mg_strncasecmp(const char *s1, const char *s2, size_t len) { - int diff = 0; - - if (len > 0) - do { - diff = lowercase(s1++) - lowercase(s2++); - } while (diff == 0 && s1[-1] != '\0' && --len > 0); - - return diff; -} - -// Return HTTP header value, or NULL if not found. -const char *mg_get_header(const struct mg_connection *ri, const char *s) { - int i; - - for (i = 0; i < ri->num_headers; i++) - if (!mg_strcasecmp(s, ri->http_headers[i].name)) - return ri->http_headers[i].value; - - return NULL; -} - -// Perform case-insensitive match of string against pattern -int mg_match_prefix(const char *pattern, ssize_t pattern_len, const char *str) { - const char *or_str; - int len, res, i = 0, j = 0; - - if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) { - res = mg_match_prefix(pattern, or_str - pattern, str); - return res > 0 ? res : mg_match_prefix(or_str + 1, - (pattern + pattern_len) - (or_str + 1), str); - } - - for (; i < pattern_len; i++, j++) { - if (pattern[i] == '?' && str[j] != '\0') { - continue; - } else if (pattern[i] == '$') { - return str[j] == '\0' ? j : -1; - } else if (pattern[i] == '*') { - i++; - if (pattern[i] == '*') { - i++; - len = (int) strlen(str + j); - } else { - len = (int) strcspn(str + j, "/"); - } - if (i == pattern_len) { - return j + len; - } - do { - res = mg_match_prefix(pattern + i, pattern_len - i, str + j + len); - } while (res == -1 && len-- > 0); - return res == -1 ? -1 : j + res + len; - } else if (lowercase(&pattern[i]) != lowercase(&str[j])) { - return -1; - } - } - return j; -} - -// This function prints HTML pages, and expands "{{something}}" blocks -// inside HTML by calling appropriate callback functions. -// Note that {{@path/to/file}} construct outputs embedded file's contents, -// which provides SSI-like functionality. -void mg_template(struct mg_connection *conn, const char *s, - struct mg_expansion *expansions) { - int i, j, pos = 0, inside_marker = 0; - - for (i = 0; s[i] != '\0'; i++) { - if (inside_marker == 0 && !memcmp(&s[i], "{{", 2)) { - if (i > pos) { - mg_send_data(conn, &s[pos], i - pos); - } - pos = i; - inside_marker = 1; - } - if (inside_marker == 1 && !memcmp(&s[i], "}}", 2)) { - for (j = 0; expansions[j].keyword != NULL; j++) { - const char *kw = expansions[j].keyword; - if ((int) strlen(kw) == i - (pos + 2) && - memcmp(kw, &s[pos + 2], i - (pos + 2)) == 0) { - expansions[j].handler(conn); - pos = i + 2; - break; - } - } - inside_marker = 0; - } - } - if (i > pos) { - mg_send_data(conn, &s[pos], i - pos); - } -} - -#ifndef MONGOOSE_NO_FILESYSTEM -static int is_dav_request(const struct connection *conn) { - const char *s = conn->mg_conn.request_method; - return !strcmp(s, "PUT") || !strcmp(s, "DELETE") || - !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND"); -} - -static int must_hide_file(struct connection *conn, const char *path) { - const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$"; - const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN]; - return mg_match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 || - (pattern != NULL && mg_match_prefix(pattern, strlen(pattern), path) > 0); -} - -// Return 1 if real file has been found, 0 otherwise -static int convert_uri_to_file_name(struct connection *conn, char *buf, - size_t buf_len, file_stat_t *st) { - struct vec a, b; - const char *rewrites = conn->server->config_options[URL_REWRITES]; - const char *root = -#ifndef MONGOOSE_NO_DAV - is_dav_request(conn) && conn->server->config_options[DAV_ROOT] != NULL ? - conn->server->config_options[DAV_ROOT] : -#endif - conn->server->config_options[DOCUMENT_ROOT]; -#ifndef MONGOOSE_NO_CGI - const char *cgi_pat = conn->server->config_options[CGI_PATTERN]; - char *p; -#endif - const char *uri = conn->mg_conn.uri; - const char *domain = mg_get_header(&conn->mg_conn, "Host"); - // Important: match_len has to be declared as int, unless rewrites break. - int match_len, root_len = root == NULL ? 0 : strlen(root); - - // Perform virtual hosting rewrites - if (rewrites != NULL && domain != NULL) { - const char *colon = strchr(domain, ':'); - size_t domain_len = colon == NULL ? strlen(domain) : colon - domain; - - while ((rewrites = next_option(rewrites, &a, &b)) != NULL) { - if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 && - mg_strncasecmp(a.ptr + 1, domain, domain_len) == 0) { - root = b.ptr; - root_len = b.len; - break; - } - } - } - - // No filesystem access - if (root == NULL || root_len == 0) return 0; - - // Handle URL rewrites - mg_snprintf(buf, buf_len, "%.*s%s", root_len, root, uri); - rewrites = conn->server->config_options[URL_REWRITES]; // Re-initialize! - while ((rewrites = next_option(rewrites, &a, &b)) != NULL) { - if ((match_len = mg_match_prefix(a.ptr, a.len, uri)) > 0) { - mg_snprintf(buf, buf_len, "%.*s%s", (int) b.len, b.ptr, uri + match_len); - break; - } - } - - if (stat(buf, st) == 0) return 1; - -#ifndef MONGOOSE_NO_CGI - // Support PATH_INFO for CGI scripts. - for (p = buf + strlen(root) + 2; *p != '\0'; p++) { - if (*p == '/') { - *p = '\0'; - if (mg_match_prefix(cgi_pat, strlen(cgi_pat), buf) > 0 && - !stat(buf, st)) { - DBG(("!!!! [%s]", buf)); - *p = '/'; - conn->path_info = mg_strdup(p); - *p = '\0'; - return 1; - } - *p = '/'; - } - } -#endif - - return 0; -} -#endif // MONGOOSE_NO_FILESYSTEM - -static int should_keep_alive(const struct mg_connection *conn) { - struct connection *c = MG_CONN_2_CONN(conn); - const char *method = conn->request_method; - const char *http_version = conn->http_version; - const char *header = mg_get_header(conn, "Connection"); - return method != NULL && - (!strcmp(method, "GET") || c->endpoint_type == EP_USER) && - ((header != NULL && !mg_strcasecmp(header, "keep-alive")) || - (header == NULL && http_version && !strcmp(http_version, "1.1"))); -} - -size_t mg_write(struct mg_connection *c, const void *buf, size_t len) { - struct connection *conn = MG_CONN_2_CONN(c); - ns_send(conn->ns_conn, buf, len); - return conn->ns_conn->send_iobuf.len; -} - -void mg_send_status(struct mg_connection *c, int status) { - struct connection *conn = MG_CONN_2_CONN(c); - if (c->status_code == 0) { - c->status_code = status; - mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status)); - } - conn->ns_conn->flags |= MG_USING_CHUNKED_API; -} - -void mg_send_header(struct mg_connection *c, const char *name, const char *v) { - struct connection *conn = MG_CONN_2_CONN(c); - if (c->status_code == 0) { - c->status_code = 200; - mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200)); - } - mg_printf(c, "%s: %s\r\n", name, v); - conn->ns_conn->flags |= MG_USING_CHUNKED_API; -} - -static void terminate_headers(struct mg_connection *c) { - struct connection *conn = MG_CONN_2_CONN(c); - if (!(conn->ns_conn->flags & MG_HEADERS_SENT)) { - mg_send_header(c, "Transfer-Encoding", "chunked"); - mg_write(c, "\r\n", 2); - conn->ns_conn->flags |= MG_HEADERS_SENT; - } -} - -size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) { - struct connection *conn = MG_CONN_2_CONN(c); - terminate_headers(c); - write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len); - return conn->ns_conn->send_iobuf.len; -} - -size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) { - va_list ap; - int ret; - - va_start(ap, fmt); - ret = mg_vprintf_data(c, fmt, ap); - va_end(ap); - - return ret; -} - -size_t mg_vprintf_data(struct mg_connection *c, const char *fmt, va_list ap) { - struct connection *conn = MG_CONN_2_CONN(c); - int len; - char mem[IOBUF_SIZE], *buf = mem; - - terminate_headers(c); - - len = ns_avprintf(&buf, sizeof(mem), fmt, ap); - - if (len >= 0) { - write_chunk((struct connection *) conn, buf, len); - } - if (buf != mem && buf != NULL) { - NS_FREE(buf); - } - return conn->ns_conn->send_iobuf.len; -} - -#if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH) -static int is_big_endian(void) { - static const int n = 1; - return ((char *) &n)[0] == 0; -} -#endif - -#ifndef MONGOOSE_NO_WEBSOCKET -// START OF SHA-1 code -// Copyright(c) By Steve Reid -#define SHA1HANDSOFF -#if defined(__sun) -#include "solarisfixes.h" -#endif - -union char64long16 { unsigned char c[64]; uint32_t l[16]; }; - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -static uint32_t blk0(union char64long16 *block, int i) { - // Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN - if (!is_big_endian()) { - block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | - (rol(block->l[i], 8) & 0x00FF00FF); - } - return block->l[i]; -} - -/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */ -#undef blk -#undef R0 -#undef R1 -#undef R2 -#undef R3 -#undef R4 - -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) { - uint32_t a, b, c, d, e; - union char64long16 block[1]; - - memcpy(block, buffer, 64); - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - // Erase working structures. The order of operations is important, - // used to ensure that compiler doesn't optimize those out. - memset(block, 0, sizeof(block)); - a = b = c = d = e = 0; - (void) a; (void) b; (void) c; (void) d; (void) e; -} - -static void SHA1Init(SHA1_CTX *context) { - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - -static void SHA1Update(SHA1_CTX *context, const unsigned char *data, - size_t len) { - size_t i, j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1]++; - context->count[1] += (len>>29); - j = (j >> 3) & 63; - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - -static void SHA1Final(unsigned char digest[20], SHA1_CTX *context) { - unsigned i; - unsigned char finalcount[8], c; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); - } - c = 0200; - SHA1Update(context, &c, 1); - while ((context->count[0] & 504) != 448) { - c = 0000; - SHA1Update(context, &c, 1); - } - SHA1Update(context, finalcount, 8); - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} -// END OF SHA1 CODE - -static void base64_encode(const unsigned char *src, int src_len, char *dst) { - static const char *b64 = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - int i, j, a, b, c; - - for (i = j = 0; i < src_len; i += 3) { - a = src[i]; - b = i + 1 >= src_len ? 0 : src[i + 1]; - c = i + 2 >= src_len ? 0 : src[i + 2]; - - dst[j++] = b64[a >> 2]; - dst[j++] = b64[((a & 3) << 4) | (b >> 4)]; - if (i + 1 < src_len) { - dst[j++] = b64[(b & 15) << 2 | (c >> 6)]; - } - if (i + 2 < src_len) { - dst[j++] = b64[c & 63]; - } - } - while (j % 4 != 0) { - dst[j++] = '='; - } - dst[j++] = '\0'; -} - -static void send_websocket_handshake(struct mg_connection *conn, - const char *key) { - static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - char buf[500], sha[20], b64_sha[sizeof(sha) * 2]; - SHA1_CTX sha_ctx; - - mg_snprintf(buf, sizeof(buf), "%s%s", key, magic); - SHA1Init(&sha_ctx); - SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf)); - SHA1Final((unsigned char *) sha, &sha_ctx); - base64_encode((unsigned char *) sha, sizeof(sha), b64_sha); - mg_snprintf(buf, sizeof(buf), "%s%s%s", - "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n"); - - mg_write(conn, buf, strlen(buf)); -} - -static size_t deliver_websocket_frame(struct connection *conn) { - // Having buf unsigned char * is important, as it is used below in arithmetic - unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf; - size_t i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0, - mask_len = 0, header_len = 0, data_len = 0, buffered = 0; - - if (buf_len >= 2) { - len = buf[1] & 127; - mask_len = buf[1] & 128 ? 4 : 0; - if (len < 126 && buf_len >= mask_len) { - data_len = len; - header_len = 2 + mask_len; - } else if (len == 126 && buf_len >= 4 + mask_len) { - header_len = 4 + mask_len; - data_len = ((((size_t) buf[2]) << 8) + buf[3]); - } else if (buf_len >= 10 + mask_len) { - header_len = 10 + mask_len; - data_len = (size_t) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) + - htonl(* (uint32_t *) &buf[6]); - } - } - - frame_len = header_len + data_len; - buffered = frame_len > 0 && frame_len <= buf_len; - - if (buffered) { - conn->mg_conn.content_len = data_len; - conn->mg_conn.content = (char *) buf + header_len; - conn->mg_conn.wsbits = buf[0]; - - // Apply mask if necessary - if (mask_len > 0) { - for (i = 0; i < data_len; i++) { - buf[i + header_len] ^= (buf + header_len - mask_len)[i % 4]; - } - } - - // Call the handler and remove frame from the iobuf - if (call_user(conn, MG_REQUEST) == MG_FALSE || - (buf[0] & 0x0f) == WEBSOCKET_OPCODE_CONNECTION_CLOSE) { - conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA; - } - iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len); - } - - return buffered; -} - -size_t mg_websocket_write(struct mg_connection *conn, int opcode, - const char *data, size_t data_len) { - unsigned char mem[4192], *copy = mem; - size_t copy_len = 0; - - /* Check overflow */ - if (data_len > ~(size_t)0 - (size_t)10) { - return 0; - } - - if (data_len + 10 > sizeof(mem) && - (copy = (unsigned char *) NS_MALLOC(data_len + 10)) == NULL) { - return 0; - } - - copy[0] = 0x80 + (opcode & 0x0f); - - // Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 - if (data_len < 126) { - // Inline 7-bit length field - copy[1] = data_len; - memcpy(copy + 2, data, data_len); - copy_len = 2 + data_len; - } else if (data_len <= 0xFFFF) { - // 16-bit length field - copy[1] = 126; - * (uint16_t *) (copy + 2) = (uint16_t) htons((uint16_t) data_len); - memcpy(copy + 4, data, data_len); - copy_len = 4 + data_len; - } else { - // 64-bit length field - const uint32_t hi = htonl((uint32_t) ((uint64_t) data_len >> 32)); - const uint32_t lo = htonl(data_len & 0xffffffff); - copy[1] = 127; - memcpy(copy+2,&hi,sizeof(hi)); - memcpy(copy+6,&lo,sizeof(lo)); - memcpy(copy + 10, data, data_len); - copy_len = 10 + data_len; - } - - if (copy_len > 0) { - mg_write(conn, copy, copy_len); - } - if (copy != mem) { - NS_FREE(copy); - } - - // If we send closing frame, schedule a connection to be closed after - // data is drained to the client. - if (opcode == WEBSOCKET_OPCODE_CONNECTION_CLOSE) { - MG_CONN_2_CONN(conn)->ns_conn->flags |= NSF_FINISHED_SENDING_DATA; - } - - return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len; -} - -size_t mg_websocket_printf(struct mg_connection *conn, int opcode, - const char *fmt, ...) { - char mem[4192], *buf = mem; - va_list ap; - int len; - - va_start(ap, fmt); - if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) { - mg_websocket_write(conn, opcode, buf, len); - } - va_end(ap); - - if (buf != mem && buf != NULL) { - NS_FREE(buf); - } - - return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len; -} - -static void send_websocket_handshake_if_requested(struct mg_connection *conn) { - const char *ver = mg_get_header(conn, "Sec-WebSocket-Version"), - *key = mg_get_header(conn, "Sec-WebSocket-Key"); - if (ver != NULL && key != NULL) { - conn->is_websocket = 1; - if (call_user(MG_CONN_2_CONN(conn), MG_WS_HANDSHAKE) == MG_FALSE) { - send_websocket_handshake(conn, key); - } - call_user(MG_CONN_2_CONN(conn), MG_WS_CONNECT); - } -} - -static void ping_idle_websocket_connection(struct connection *conn, time_t t) { - if (t - conn->ns_conn->last_io_time > MONGOOSE_USE_WEBSOCKET_PING_INTERVAL) { - mg_websocket_write(&conn->mg_conn, WEBSOCKET_OPCODE_PING, "", 0); - } -} -#else -#define ping_idle_websocket_connection(conn, t) -#endif // !MONGOOSE_NO_WEBSOCKET - -static void write_terminating_chunk(struct connection *conn) { - mg_write(&conn->mg_conn, "0\r\n\r\n", 5); -} - -static int call_request_handler(struct connection *conn) { - int result; - conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf; - if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) { - if (conn->ns_conn->flags & MG_USING_CHUNKED_API) { - terminate_headers(&conn->mg_conn); - write_terminating_chunk(conn); - } - close_local_endpoint(conn); - } - return result; -} - -const char *mg_get_mime_type(const char *path, const char *default_mime_type) { - const char *ext; - size_t i, path_len; - - path_len = strlen(path); - - for (i = 0; static_builtin_mime_types[i].extension != NULL; i++) { - ext = path + (path_len - static_builtin_mime_types[i].ext_len); - if (path_len > static_builtin_mime_types[i].ext_len && - mg_strcasecmp(ext, static_builtin_mime_types[i].extension) == 0) { - return static_builtin_mime_types[i].mime_type; - } - } - - return default_mime_type; -} - -#ifndef MONGOOSE_NO_FILESYSTEM -// Convert month to the month number. Return -1 on error, or month number -static int get_month_index(const char *s) { - static const char *month_names[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - int i; - - for (i = 0; i < (int) ARRAY_SIZE(month_names); i++) - if (!strcmp(s, month_names[i])) - return i; - - return -1; -} - -static int num_leap_years(int year) { - return year / 4 - year / 100 + year / 400; -} - -// Parse UTC date-time string, and return the corresponding time_t value. -static time_t parse_date_string(const char *datetime) { - static const unsigned short days_before_month[] = { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 - }; - char month_str[32]; - int second, minute, hour, day, month, year, leap_days, days; - time_t result = (time_t) 0; - - if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6) || - (sscanf(datetime, "%d %3s %d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6) || - (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6) || - (sscanf(datetime, "%d-%3s-%d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6)) && - year > 1970 && - (month = get_month_index(month_str)) != -1) { - leap_days = num_leap_years(year) - num_leap_years(1970); - year -= 1970; - days = year * 365 + days_before_month[month] + (day - 1) + leap_days; - result = days * 24 * 3600 + hour * 3600 + minute * 60 + second; - } - - return result; -} - -// Look at the "path" extension and figure what mime type it has. -// Store mime type in the vector. -static void get_mime_type(const struct mg_server *server, const char *path, - struct vec *vec) { - struct vec ext_vec, mime_vec; - const char *list, *ext; - size_t path_len; - - path_len = strlen(path); - - // Scan user-defined mime types first, in case user wants to - // override default mime types. - list = server->config_options[EXTRA_MIME_TYPES]; - while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) { - // ext now points to the path suffix - ext = path + path_len - ext_vec.len; - if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) { - *vec = mime_vec; - return; - } - } - - vec->ptr = mg_get_mime_type(path, "text/plain"); - vec->len = strlen(vec->ptr); -} - -static const char *suggest_connection_header(const struct mg_connection *conn) { - return should_keep_alive(conn) ? "keep-alive" : "close"; -} - -static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) { - mg_snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", - (unsigned long) st->st_mtime, (int64_t) st->st_size); -} - -// Return True if we should reply 304 Not Modified. -static int is_not_modified(const struct connection *conn, - const file_stat_t *stp) { - char etag[64]; - const char *ims = mg_get_header(&conn->mg_conn, "If-Modified-Since"); - const char *inm = mg_get_header(&conn->mg_conn, "If-None-Match"); - construct_etag(etag, sizeof(etag), stp); - return (inm != NULL && !mg_strcasecmp(etag, inm)) || - (ims != NULL && stp->st_mtime <= parse_date_string(ims)); -} - -// For given directory path, substitute it to valid index file. -// Return 0 if index file has been found, -1 if not found. -// If the file is found, it's stats is returned in stp. -static int find_index_file(struct connection *conn, char *path, - size_t path_len, file_stat_t *stp) { - const char *list = conn->server->config_options[INDEX_FILES]; - file_stat_t st; - struct vec filename_vec; - size_t n = strlen(path); - int found = 0; - - // The 'path' given to us points to the directory. Remove all trailing - // directory separator characters from the end of the path, and - // then append single directory separator character. - while (n > 0 && path[n - 1] == '/') { - n--; - } - path[n] = '/'; - - // Traverse index files list. For each entry, append it to the given - // path and see if the file exists. If it exists, break the loop - while ((list = next_option(list, &filename_vec, NULL)) != NULL) { - - if (path_len <= n + 2) { - continue; - } - - // Ignore too long entries that may overflow path buffer - if (filename_vec.len > (path_len - (n + 2))) - continue; - - // Prepare full path to the index file - strncpy(path + n + 1, filename_vec.ptr, filename_vec.len); - path[n + 1 + filename_vec.len] = '\0'; - - //DBG(("[%s]", path)); - - // Does it exist? - if (!stat(path, &st)) { - // Yes it does, break the loop - *stp = st; - found = 1; - break; - } - } - - // If no index file exists, restore directory path - if (!found) { - path[n] = '/'; - path[n + 1] = '\0'; - } - - return found; -} - -static int parse_range_header(const char *header, int64_t *a, int64_t *b) { - return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b); -} - -static void gmt_time_string(char *buf, size_t buf_len, time_t *t) { - strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t)); -} - -static void open_file_endpoint(struct connection *conn, const char *path, - file_stat_t *st, const char *extra_headers) { - char date[64], lm[64], etag[64], range[64], headers[1000]; - const char *msg = "OK", *hdr; - time_t t, curtime = time(NULL); - int64_t r1, r2; - struct vec mime_vec; - int n; - - conn->endpoint_type = EP_FILE; - ns_set_close_on_exec(conn->endpoint.fd); - conn->mg_conn.status_code = 200; - - get_mime_type(conn->server, path, &mime_vec); - conn->cl = st->st_size; - range[0] = '\0'; - - // If Range: header specified, act accordingly - r1 = r2 = 0; - hdr = mg_get_header(&conn->mg_conn, "Range"); - if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && - r1 >= 0 && r2 >= 0) { - conn->mg_conn.status_code = 206; - conn->cl = n == 2 ? (r2 > conn->cl ? conn->cl : r2) - r1 + 1: conn->cl - r1; - mg_snprintf(range, sizeof(range), "Content-Range: bytes " - "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n", - r1, r1 + conn->cl - 1, (int64_t) st->st_size); - msg = "Partial Content"; - lseek(conn->endpoint.fd, r1, SEEK_SET); - } - - // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 - gmt_time_string(date, sizeof(date), &curtime); - t = st->st_mtime; // store in local variable for NDK compile - gmt_time_string(lm, sizeof(lm), &t); - construct_etag(etag, sizeof(etag), st); - - n = mg_snprintf(headers, sizeof(headers), - "HTTP/1.1 %d %s\r\n" - "Date: %s\r\n" - "Last-Modified: %s\r\n" - "Etag: %s\r\n" - "Content-Type: %.*s\r\n" - "Content-Length: %" INT64_FMT "\r\n" - "Connection: %s\r\n" - "Accept-Ranges: bytes\r\n" - "%s%s%s\r\n", - conn->mg_conn.status_code, msg, date, lm, etag, - (int) mime_vec.len, mime_vec.ptr, conn->cl, - suggest_connection_header(&conn->mg_conn), - range, extra_headers == NULL ? "" : extra_headers, - MONGOOSE_USE_EXTRA_HTTP_HEADERS); - ns_send(conn->ns_conn, headers, n); - - if (!strcmp(conn->mg_conn.request_method, "HEAD")) { - conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA; - close(conn->endpoint.fd); - conn->endpoint_type = EP_NONE; - } -} - -void mg_send_file_data(struct mg_connection *c, int fd) { - struct connection *conn = MG_CONN_2_CONN(c); - conn->endpoint_type = EP_FILE; - conn->endpoint.fd = fd; - ns_set_close_on_exec(conn->endpoint.fd); -} -#endif // MONGOOSE_NO_FILESYSTEM - -static void call_request_handler_if_data_is_buffered(struct connection *conn) { -#ifndef MONGOOSE_NO_WEBSOCKET - if (conn->mg_conn.is_websocket) { - do { } while (deliver_websocket_frame(conn)); - } else -#endif - if (conn->num_bytes_recv >= (conn->cl + conn->request_len) && - call_request_handler(conn) == MG_FALSE) { - open_local_endpoint(conn, 1); - } -} - -#if !defined(MONGOOSE_NO_DIRECTORY_LISTING) || !defined(MONGOOSE_NO_DAV) - -#ifdef _WIN32 -struct dirent { - char d_name[MAX_PATH_SIZE]; -}; - -typedef struct DIR { - HANDLE handle; - WIN32_FIND_DATAW info; - struct dirent result; -} DIR; - -// Implementation of POSIX opendir/closedir/readdir for Windows. -static DIR *opendir(const char *name) { - DIR *dir = NULL; - wchar_t wpath[MAX_PATH_SIZE]; - DWORD attrs; - - if (name == NULL) { - SetLastError(ERROR_BAD_ARGUMENTS); - } else if ((dir = (DIR *) NS_MALLOC(sizeof(*dir))) == NULL) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - } else { - to_wchar(name, wpath, ARRAY_SIZE(wpath)); - attrs = GetFileAttributesW(wpath); - if (attrs != 0xFFFFFFFF && - ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) { - (void) wcscat(wpath, L"\\*"); - dir->handle = FindFirstFileW(wpath, &dir->info); - dir->result.d_name[0] = '\0'; - } else { - NS_FREE(dir); - dir = NULL; - } - } - - return dir; -} - -static int closedir(DIR *dir) { - int result = 0; - - if (dir != NULL) { - if (dir->handle != INVALID_HANDLE_VALUE) - result = FindClose(dir->handle) ? 0 : -1; - - NS_FREE(dir); - } else { - result = -1; - SetLastError(ERROR_BAD_ARGUMENTS); - } - - return result; -} - -static struct dirent *readdir(DIR *dir) { - struct dirent *result = 0; - - if (dir) { - if (dir->handle != INVALID_HANDLE_VALUE) { - result = &dir->result; - (void) WideCharToMultiByte(CP_UTF8, 0, - dir->info.cFileName, -1, result->d_name, - sizeof(result->d_name), NULL, NULL); - - if (!FindNextFileW(dir->handle, &dir->info)) { - (void) FindClose(dir->handle); - dir->handle = INVALID_HANDLE_VALUE; - } - - } else { - SetLastError(ERROR_FILE_NOT_FOUND); - } - } else { - SetLastError(ERROR_BAD_ARGUMENTS); - } - - return result; -} -#endif // _WIN32 POSIX opendir/closedir/readdir implementation - -static int scan_directory(struct connection *conn, const char *dir, - struct dir_entry **arr) { - char path[MAX_PATH_SIZE]; - struct dir_entry *p; - struct dirent *dp; - int arr_size = 0, arr_ind = 0, inc = 100; - DIR *dirp; - - *arr = NULL; - if ((dirp = (opendir(dir))) == NULL) return 0; - - while ((dp = readdir(dirp)) != NULL) { - // Do not show current dir and hidden files - if (!strcmp(dp->d_name, ".") || - !strcmp(dp->d_name, "..") || - must_hide_file(conn, dp->d_name)) { - continue; - } - mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name); - - // Resize the array if necessary - if (arr_ind >= arr_size) { - if ((p = (struct dir_entry *) - NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) { - // Memset new chunk to zero, otherwise st_mtime will have garbage which - // can make strftime() segfault, see - // http://code.google.com/p/mongoose/issues/detail?id=79 - memset(p + arr_size, 0, sizeof(**arr) * inc); - - *arr = p; - arr_size += inc; - } - } - - if (arr_ind < arr_size) { - (*arr)[arr_ind].conn = conn; - (*arr)[arr_ind].file_name = strdup(dp->d_name); - stat(path, &(*arr)[arr_ind].st); - arr_ind++; - } - } - closedir(dirp); - - return arr_ind; -} - -size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) { - static const char *dont_escape = "._-$,;~()"; - static const char *hex = "0123456789abcdef"; - size_t i = 0, j = 0; - - for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) { - if (isalnum(* (const unsigned char *) (src + i)) || - strchr(dont_escape, * (const unsigned char *) (src + i)) != NULL) { - dst[j] = src[i]; - } else if (j + 3 < dst_len) { - dst[j] = '%'; - dst[j + 1] = hex[(* (const unsigned char *) (src + i)) >> 4]; - dst[j + 2] = hex[(* (const unsigned char *) (src + i)) & 0xf]; - j += 2; - } - } - - dst[j] = '\0'; - return j; -} -#endif // !NO_DIRECTORY_LISTING || !MONGOOSE_NO_DAV - -#ifndef MONGOOSE_NO_DIRECTORY_LISTING - -static void print_dir_entry(const struct dir_entry *de) { - char size[64], mod[64], href[MAX_PATH_SIZE * 3]; - int64_t fsize = de->st.st_size; - int is_dir = S_ISDIR(de->st.st_mode); - const char *slash = is_dir ? "/" : ""; - time_t t; - - if (is_dir) { - mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]"); - } else { - // We use (signed) cast below because MSVC 6 compiler cannot - // convert unsigned __int64 to double. - if (fsize < 1024) { - mg_snprintf(size, sizeof(size), "%d", (int) fsize); - } else if (fsize < 0x100000) { - mg_snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0); - } else if (fsize < 0x40000000) { - mg_snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576); - } else { - mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824); - } - } - t = de->st.st_mtime; // store in local variable for NDK compile - strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&t)); - mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href)); - mg_printf_data(&de->conn->mg_conn, - "%s%s" - " %s  %s\n", - href, slash, de->file_name, slash, mod, size); -} - -// Sort directory entries by size, or name, or modification time. -// On windows, __cdecl specification is needed in case if project is built -// with __stdcall convention. qsort always requires __cdels callback. -static int __cdecl compare_dir_entries(const void *p1, const void *p2) { - const struct dir_entry *a = (const struct dir_entry *) p1, - *b = (const struct dir_entry *) p2; - const char *qs = a->conn->mg_conn.query_string ? - a->conn->mg_conn.query_string : "na"; - int cmp_result = 0; - - if (S_ISDIR(a->st.st_mode) && !S_ISDIR(b->st.st_mode)) { - return -1; // Always put directories on top - } else if (!S_ISDIR(a->st.st_mode) && S_ISDIR(b->st.st_mode)) { - return 1; // Always put directories on top - } else if (*qs == 'n') { - cmp_result = strcmp(a->file_name, b->file_name); - } else if (*qs == 's') { - cmp_result = a->st.st_size == b->st.st_size ? 0 : - a->st.st_size > b->st.st_size ? 1 : -1; - } else if (*qs == 'd') { - cmp_result = a->st.st_mtime == b->st.st_mtime ? 0 : - a->st.st_mtime > b->st.st_mtime ? 1 : -1; - } - - return qs[1] == 'd' ? -cmp_result : cmp_result; -} - -static void send_directory_listing(struct connection *conn, const char *dir) { - struct dir_entry *arr = NULL; - int i, num_entries, sort_direction = conn->mg_conn.query_string != NULL && - conn->mg_conn.query_string[1] == 'd' ? 'a' : 'd'; - - mg_send_header(&conn->mg_conn, "Transfer-Encoding", "chunked"); - mg_send_header(&conn->mg_conn, "Content-Type", "text/html; charset=utf-8"); - - mg_printf_data(&conn->mg_conn, - "Index of %s" - "" - "

Index of %s

"
-              ""
-              ""
-              ""
-              "",
-              conn->mg_conn.uri, conn->mg_conn.uri,
-              sort_direction, sort_direction, sort_direction);
-
-  num_entries = scan_directory(conn, dir, &arr);
-  if (arr) {
-      qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
-      for (i = 0; i < num_entries; i++) {
-        print_dir_entry(&arr[i]);
-        NS_FREE(arr[i].file_name);
-      }
-      NS_FREE(arr);
-  }
-
-  write_terminating_chunk(conn);
-  close_local_endpoint(conn);
-}
-#endif  // MONGOOSE_NO_DIRECTORY_LISTING
-
-#ifndef MONGOOSE_NO_DAV
-static void print_props(struct connection *conn, const char *uri,
-                        file_stat_t *stp) {
-  char mtime[64];
-  time_t t = stp->st_mtime;  // store in local variable for NDK compile
-  gmt_time_string(mtime, sizeof(mtime), &t);
-  mg_printf(&conn->mg_conn,
-      ""
-       "%s"
-       ""
-        ""
-         "%s"
-         "%" INT64_FMT ""
-         "%s"
-        ""
-        "HTTP/1.1 200 OK"
-       ""
-      "\n",
-      uri, S_ISDIR(stp->st_mode) ? "" : "",
-      (int64_t) stp->st_size, mtime);
-}
-
-static void handle_propfind(struct connection *conn, const char *path,
-                            file_stat_t *stp, int exists) {
-  static const char header[] = "HTTP/1.1 207 Multi-Status\r\n"
-    "Connection: close\r\n"
-    "Content-Type: text/xml; charset=utf-8\r\n\r\n"
-    ""
-    "\n";
-  static const char footer[] = "";
-  const char *depth = mg_get_header(&conn->mg_conn, "Depth");
-#ifdef MONGOOSE_NO_DIRECTORY_LISTING
-  const char *list_dir = "no";
-#else
-  const char *list_dir = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
-#endif
-
-  conn->mg_conn.status_code = 207;
-
-  // Print properties for the requested resource itself
-  if (!exists) {
-    conn->mg_conn.status_code = 404;
-    mg_printf(&conn->mg_conn, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
-  } else if (S_ISDIR(stp->st_mode) && mg_strcasecmp(list_dir, "yes") != 0) {
-    conn->mg_conn.status_code = 403;
-    mg_printf(&conn->mg_conn, "%s",
-              "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
-  } else {
-    ns_send(conn->ns_conn, header, sizeof(header) - 1);
-    print_props(conn, conn->mg_conn.uri, stp);
-
-    if (S_ISDIR(stp->st_mode) &&
-             (depth == NULL || strcmp(depth, "0") != 0)) {
-      struct dir_entry *arr = NULL;
-      int i, num_entries = scan_directory(conn, path, &arr);
-
-      for (i = 0; i < num_entries; i++) {
-        char buf[MAX_PATH_SIZE * 3];
-        struct dir_entry *de = &arr[i];
-        mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
-        print_props(conn, buf, &de->st);
-        NS_FREE(de->file_name);
-      }
-      NS_FREE(arr);
-    }
-    ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
-  }
-
-  close_local_endpoint(conn);
-}
-
-static void handle_mkcol(struct connection *conn, const char *path) {
-  int status_code = 500;
-
-  if (conn->mg_conn.content_len > 0) {
-    status_code = 415;
-  } else if (!mkdir(path, 0755)) {
-    status_code = 201;
-  } else if (errno == EEXIST) {
-    status_code = 405;
-  } else if (errno == EACCES) {
-    status_code = 403;
-  } else if (errno == ENOENT) {
-    status_code = 409;
-  }
-  send_http_error(conn, status_code, NULL);
-}
-
-static int remove_directory(const char *dir) {
-  char path[MAX_PATH_SIZE];
-  struct dirent *dp;
-  file_stat_t st;
-  DIR *dirp;
-
-  if ((dirp = opendir(dir)) == NULL) return 0;
-
-  while ((dp = readdir(dirp)) != NULL) {
-    if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
-    mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
-    stat(path, &st);
-    if (S_ISDIR(st.st_mode)) {
-      remove_directory(path);
-    } else {
-      remove(path);
-    }
-  }
-  closedir(dirp);
-  rmdir(dir);
-
-  return 1;
-}
-
-static void handle_delete(struct connection *conn, const char *path) {
-  file_stat_t st;
-
-  if (stat(path, &st) != 0) {
-    send_http_error(conn, 404, NULL);
-  } else if (S_ISDIR(st.st_mode)) {
-    remove_directory(path);
-    send_http_error(conn, 204, NULL);
-  } else if (remove(path) == 0) {
-    send_http_error(conn, 204, NULL);
-  } else {
-    send_http_error(conn, 423, NULL);
-  }
-}
-
-// For a given PUT path, create all intermediate subdirectories
-// for given path. Return 0 if the path itself is a directory,
-// or -1 on error, 1 if OK.
-static int put_dir(const char *path) {
-  char buf[MAX_PATH_SIZE];
-  const char *s, *p;
-  file_stat_t st;
-
-  // Create intermediate directories if they do not exist
-  for (s = p = path + 1; (p = strchr(s, '/')) != NULL; s = ++p) {
-    if (p - path >= (int) sizeof(buf)) return -1; // Buffer overflow
-    memcpy(buf, path, p - path);
-    buf[p - path] = '\0';
-    if (stat(buf, &st) != 0 && mkdir(buf, 0755) != 0) return -1;
-    if (p[1] == '\0') return 0;  // Path is a directory itself
-  }
-
-  return 1;
-}
-
-static void handle_put(struct connection *conn, const char *path) {
-  file_stat_t st;
-  const char *range, *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
-  int64_t r1, r2;
-  int rc;
-
-  conn->mg_conn.status_code = !stat(path, &st) ? 200 : 201;
-  if ((rc = put_dir(path)) == 0) {
-    mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\n\r\n",
-              conn->mg_conn.status_code);
-    close_local_endpoint(conn);
-  } else if (rc == -1) {
-    send_http_error(conn, 500, "put_dir: %s", strerror(errno));
-  } else if (cl_hdr == NULL) {
-    send_http_error(conn, 411, NULL);
-  } else if ((conn->endpoint.fd =
-              open(path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644)) < 0) {
-    send_http_error(conn, 500, "open(%s): %s", path, strerror(errno));
-  } else {
-    DBG(("PUT [%s] %lu", path, (unsigned long) conn->ns_conn->recv_iobuf.len));
-    conn->endpoint_type = EP_PUT;
-    ns_set_close_on_exec(conn->endpoint.fd);
-    range = mg_get_header(&conn->mg_conn, "Content-Range");
-    conn->cl = to64(cl_hdr);
-    r1 = r2 = 0;
-    if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
-      conn->mg_conn.status_code = 206;
-      lseek(conn->endpoint.fd, r1, SEEK_SET);
-      conn->cl = r2 > r1 ? r2 - r1 + 1: conn->cl - r1;
-    }
-    mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
-              conn->mg_conn.status_code);
-  }
-}
-
-static void forward_put_data(struct connection *conn) {
-  struct iobuf *io = &conn->ns_conn->recv_iobuf;
-  size_t k = conn->cl < (int64_t) io->len ? conn->cl : (int64_t) io->len;   // To write
-  size_t n = write(conn->endpoint.fd, io->buf, k);   // Write them!
-  if (n > 0) {
-    iobuf_remove(io, n);
-    conn->cl -= n;
-  }
-  if (conn->cl <= 0) {
-    close_local_endpoint(conn);
-  }
-}
-#endif //  MONGOOSE_NO_DAV
-
-static void send_options(struct connection *conn) {
-  conn->mg_conn.status_code = 200;
-  mg_printf(&conn->mg_conn, "%s",
-            "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, PUT, "
-            "DELETE, OPTIONS, PROPFIND, MKCOL\r\nDAV: 1\r\n\r\n");
-  close_local_endpoint(conn);
-}
-
-#ifndef MONGOOSE_NO_AUTH
-void mg_send_digest_auth_request(struct mg_connection *c) {
-  struct connection *conn = MG_CONN_2_CONN(c);
-  c->status_code = 401;
-  mg_printf(c,
-            "HTTP/1.1 401 Unauthorized\r\n"
-            "Content-Length: 0\r\n"
-            "WWW-Authenticate: Digest qop=\"auth\", "
-            "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
-            conn->server->config_options[AUTH_DOMAIN],
-            (unsigned long) time(NULL));
-  close_local_endpoint(conn);
-}
-
-// Use the global passwords file, if specified by auth_gpass option,
-// or search for .htpasswd in the requested directory.
-static FILE *open_auth_file(struct connection *conn, const char *path,
-                            int is_directory) {
-  char name[MAX_PATH_SIZE];
-  const char *p, *gpass = conn->server->config_options[GLOBAL_AUTH_FILE];
-  FILE *fp = NULL;
-
-  if (gpass != NULL) {
-    // Use global passwords file
-    fp = fopen(gpass, "r");
-  } else if (is_directory) {
-    mg_snprintf(name, sizeof(name), "%s%c%s", path, '/', PASSWORDS_FILE_NAME);
-    fp = fopen(name, "r");
-  } else {
-    // Try to find .htpasswd in requested directory.
-    if ((p = strrchr(path, '/')) == NULL) p = path;
-    mg_snprintf(name, sizeof(name), "%.*s%c%s",
-                (int) (p - path), path, '/', PASSWORDS_FILE_NAME);
-    fp = fopen(name, "r");
-  }
-
-  return fp;
-}
-
-#if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH)
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest.	This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-typedef struct MD5Context {
-  uint32_t buf[4];
-  uint32_t bits[2];
-  unsigned char in[64];
-} MD5_CTX;
-
-static void byteReverse(unsigned char *buf, unsigned longs) {
-  uint32_t t;
-
-  // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
-  if (is_big_endian()) {
-    do {
-      t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-        ((unsigned) buf[1] << 8 | buf[0]);
-      * (uint32_t *) buf = t;
-      buf += 4;
-    } while (--longs);
-  }
-}
-
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-#define MD5STEP(f, w, x, y, z, data, s) \
-  ( w += f(x, y, z) + data,  w = w<>(32-s),  w += x )
-
-// Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
-// initialization constants.
-static void MD5Init(MD5_CTX *ctx) {
-  ctx->buf[0] = 0x67452301;
-  ctx->buf[1] = 0xefcdab89;
-  ctx->buf[2] = 0x98badcfe;
-  ctx->buf[3] = 0x10325476;
-
-  ctx->bits[0] = 0;
-  ctx->bits[1] = 0;
-}
-
-static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
-  register uint32_t a, b, c, d;
-
-  a = buf[0];
-  b = buf[1];
-  c = buf[2];
-  d = buf[3];
-
-  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
-  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-  buf[0] += a;
-  buf[1] += b;
-  buf[2] += c;
-  buf[3] += d;
-}
-
-static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
-  uint32_t t;
-
-  t = ctx->bits[0];
-  if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
-    ctx->bits[1]++;
-  ctx->bits[1] += len >> 29;
-
-  t = (t >> 3) & 0x3f;
-
-  if (t) {
-    unsigned char *p = (unsigned char *) ctx->in + t;
-
-    t = 64 - t;
-    if (len < t) {
-      memcpy(p, buf, len);
-      return;
-    }
-    memcpy(p, buf, t);
-    byteReverse(ctx->in, 16);
-    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-    buf += t;
-    len -= t;
-  }
-
-  while (len >= 64) {
-    memcpy(ctx->in, buf, 64);
-    byteReverse(ctx->in, 16);
-    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-    buf += 64;
-    len -= 64;
-  }
-
-  memcpy(ctx->in, buf, len);
-}
-
-static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
-  unsigned count;
-  unsigned char *p;
-  uint32_t *a;
-
-  count = (ctx->bits[0] >> 3) & 0x3F;
-
-  p = ctx->in + count;
-  *p++ = 0x80;
-  count = 64 - 1 - count;
-  if (count < 8) {
-    memset(p, 0, count);
-    byteReverse(ctx->in, 16);
-    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-    memset(ctx->in, 0, 56);
-  } else {
-    memset(p, 0, count - 8);
-  }
-  byteReverse(ctx->in, 14);
-
-  a = (uint32_t *)ctx->in;
-  a[14] = ctx->bits[0];
-  a[15] = ctx->bits[1];
-
-  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-  byteReverse((unsigned char *) ctx->buf, 4);
-  memcpy(digest, ctx->buf, 16);
-  memset((char *) ctx, 0, sizeof(*ctx));
-}
-#endif // !HAVE_MD5
-
-
-
-// Stringify binary data. Output buffer must be twice as big as input,
-// because each byte takes 2 bytes in string representation
-static void bin2str(char *to, const unsigned char *p, size_t len) {
-  static const char *hex = "0123456789abcdef";
-
-  for (; len--; p++) {
-    *to++ = hex[p[0] >> 4];
-    *to++ = hex[p[0] & 0x0f];
-  }
-  *to = '\0';
-}
-
-// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
-char *mg_md5(char buf[33], ...) {
-  unsigned char hash[16];
-  const char *p;
-  va_list ap;
-  MD5_CTX ctx;
-
-  MD5Init(&ctx);
-
-  va_start(ap, buf);
-  while ((p = va_arg(ap, const char *)) != NULL) {
-    MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
-  }
-  va_end(ap);
-
-  MD5Final(hash, &ctx);
-  bin2str(buf, hash, sizeof(hash));
-  return buf;
-}
-
-// Check the user's password, return 1 if OK
-static int check_password(const char *method, const char *ha1, const char *uri,
-                          const char *nonce, const char *nc, const char *cnonce,
-                          const char *qop, const char *response) {
-  char ha2[32 + 1], expected_response[32 + 1];
-
-#if 0
-  // Check for authentication timeout
-  if ((unsigned long) time(NULL) - (unsigned long) to64(nonce) > 3600 * 2) {
-    return 0;
-  }
-#endif
-
-  mg_md5(ha2, method, ":", uri, NULL);
-  mg_md5(expected_response, ha1, ":", nonce, ":", nc,
-      ":", cnonce, ":", qop, ":", ha2, NULL);
-
-  return mg_strcasecmp(response, expected_response) == 0 ? MG_TRUE : MG_FALSE;
-}
-
-
-// Authorize against the opened passwords file. Return 1 if authorized.
-int mg_authorize_digest(struct mg_connection *c, FILE *fp) {
-  struct connection *conn = MG_CONN_2_CONN(c);
-  const char *hdr;
-  char line[256], f_user[256], ha1[256], f_domain[256], user[100], nonce[100],
-       uri[MAX_REQUEST_SIZE], cnonce[100], resp[100], qop[100], nc[100];
-
-  if (c == NULL || fp == NULL) return 0;
-  if ((hdr = mg_get_header(c, "Authorization")) == NULL ||
-      mg_strncasecmp(hdr, "Digest ", 7) != 0) return 0;
-  if (!mg_parse_header(hdr, "username", user, sizeof(user))) return 0;
-  if (!mg_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce))) return 0;
-  if (!mg_parse_header(hdr, "response", resp, sizeof(resp))) return 0;
-  if (!mg_parse_header(hdr, "uri", uri, sizeof(uri))) return 0;
-  if (!mg_parse_header(hdr, "qop", qop, sizeof(qop))) return 0;
-  if (!mg_parse_header(hdr, "nc", nc, sizeof(nc))) return 0;
-  if (!mg_parse_header(hdr, "nonce", nonce, sizeof(nonce))) return 0;
-
-  while (fgets(line, sizeof(line), fp) != NULL) {
-    if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) == 3 &&
-        !strcmp(user, f_user) &&
-        // NOTE(lsm): due to a bug in MSIE, we do not compare URIs
-        !strcmp(conn->server->config_options[AUTH_DOMAIN], f_domain))
-      return check_password(c->request_method, ha1, uri,
-                            nonce, nc, cnonce, qop, resp);
-  }
-  return MG_FALSE;
-}
-
-
-// Return 1 if request is authorised, 0 otherwise.
-static int is_authorized(struct connection *conn, const char *path,
-                         int is_directory) {
-  FILE *fp;
-  int authorized = MG_TRUE;
-
-  if ((fp = open_auth_file(conn, path, is_directory)) != NULL) {
-    authorized = mg_authorize_digest(&conn->mg_conn, fp);
-    fclose(fp);
-  }
-
-  return authorized;
-}
-
-static int is_authorized_for_dav(struct connection *conn) {
-  const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
-  const char *method = conn->mg_conn.request_method;
-  FILE *fp;
-  int authorized = MG_FALSE;
-
-  // If dav_auth_file is not set, allow non-authorized PROPFIND
-  if (method != NULL && !strcmp(method, "PROPFIND") && auth_file == NULL) {
-    authorized = MG_TRUE;
-  } else if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
-    authorized = mg_authorize_digest(&conn->mg_conn, fp);
-    fclose(fp);
-  }
-
-  return authorized;
-}
-#endif // MONGOOSE_NO_AUTH
-
-static int parse_header(const char *str, size_t str_len, const char *var_name,
-                        char *buf, size_t buf_size) {
-  int ch = ' ', ch1 = ',', len = 0;
-  size_t n = strlen(var_name);
-  const char *p, *end = str + str_len, *s = NULL;
-
-  if (buf != NULL && buf_size > 0) buf[0] = '\0';
-
-  // Find where variable starts
-  for (s = str; s != NULL && s + n < end; s++) {
-    if ((s == str || s[-1] == ch || s[-1] == ch1) && s[n] == '=' &&
-        !memcmp(s, var_name, n)) break;
-  }
-
-  if (s != NULL && &s[n + 1] < end) {
-    s += n + 1;
-    if (*s == '"' || *s == '\'') ch = ch1 = *s++;
-    p = s;
-    while (p < end && p[0] != ch && p[0] != ch1 && len < (int) buf_size) {
-      if (ch == ch1 && p[0] == '\\' && p[1] == ch) p++;
-      buf[len++] = *p++;
-    }
-    if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
-      len = 0;
-    } else {
-      if (len > 0 && s[len - 1] == ',') len--;
-      if (len > 0 && s[len - 1] == ';') len--;
-      buf[len] = '\0';
-    }
-  }
-
-  return len;
-}
-
-int mg_parse_header(const char *s, const char *var_name, char *buf,
-                    size_t buf_size) {
-  return parse_header(s, s == NULL ? 0 : strlen(s), var_name, buf, buf_size);
-}
-
-#ifndef MONGOOSE_NO_SSI
-static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
-
-static void send_file_data(struct mg_connection *conn, FILE *fp) {
-  char buf[IOBUF_SIZE];
-  size_t n;
-  while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
-    mg_write(conn, buf, n);
-  }
-}
-
-static void do_ssi_include(struct mg_connection *conn, const char *ssi,
-                           char *tag, int include_level) {
-  char file_name[IOBUF_SIZE], path[MAX_PATH_SIZE], *p;
-  char **opts = (MG_CONN_2_CONN(conn))->server->config_options;
-  FILE *fp;
-
-  // sscanf() is safe here, since send_ssi_file() also uses buffer
-  // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
-  if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
-    // File name is relative to the webserver root
-    mg_snprintf(path, sizeof(path), "%s%c%s",
-                opts[DOCUMENT_ROOT], '/', file_name);
-  } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
-    // File name is relative to the webserver working directory
-    // or it is absolute system path
-    mg_snprintf(path, sizeof(path), "%s", file_name);
-  } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
-             sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
-    // File name is relative to the current document
-    mg_snprintf(path, sizeof(path), "%s", ssi);
-    if ((p = strrchr(path, '/')) != NULL) {
-      p[1] = '\0';
-    }
-    mg_snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s",
-                file_name);
-  } else {
-    mg_printf(conn, "Bad SSI #include: [%s]", tag);
-    return;
-  }
-
-  if ((fp = fopen(path, "rb")) == NULL) {
-    mg_printf(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
-              tag, path, strerror(errno));
-  } else {
-    ns_set_close_on_exec(fileno(fp));
-    if (mg_match_prefix(opts[SSI_PATTERN], strlen(opts[SSI_PATTERN]),
-        path) > 0) {
-      send_ssi_file(conn, path, fp, include_level + 1);
-    } else {
-      send_file_data(conn, fp);
-    }
-    fclose(fp);
-  }
-}
-
-#ifndef MONGOOSE_NO_POPEN
-static void do_ssi_exec(struct mg_connection *conn, char *tag) {
-  char cmd[IOBUF_SIZE];
-  FILE *fp;
-
-  if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
-    mg_printf(conn, "Bad SSI #exec: [%s]", tag);
-  } else if ((fp = popen(cmd, "r")) == NULL) {
-    mg_printf(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
-  } else {
-    send_file_data(conn, fp);
-    pclose(fp);
-  }
-}
-#endif // !MONGOOSE_NO_POPEN
-
-static void send_ssi_file(struct mg_connection *conn, const char *path,
-                          FILE *fp, int include_level) {
-  char buf[IOBUF_SIZE];
-  int ch, offset, len, in_ssi_tag;
-
-  if (include_level > 10) {
-    mg_printf(conn, "SSI #include level is too deep (%s)", path);
-    return;
-  }
-
-  in_ssi_tag = len = offset = 0;
-  while ((ch = fgetc(fp)) != EOF) {
-    if (in_ssi_tag && ch == '>') {
-      in_ssi_tag = 0;
-      buf[len++] = (char) ch;
-      buf[len] = '\0';
-      assert(len <= (int) sizeof(buf));
-      if (len < 6 || memcmp(buf, "'
-            '')
-        document = minidom.parseString(documentSource)
-        filename = self.mktemp()
-        checker = getDefaultChecker()
-
-        output = StringIO()
-        patch = self.patch(sys, 'stdout', output)
-        checker.check(document, filename)
-        patch.restore()
-
-        self.assertEqual(output.getvalue(), "")
-
-
-    def test_aNode(self):
-        """
-        If there is an  tag in the document, the checker returned by
-        L{getDefaultChecker} does not report an error.
-        """
-        documentSource = (
-            ''
-            'foo'
-            '

foo

A link.' - '') - - self.assertEqual(self._lintCheck(True, documentSource), "") - - - def test_textMatchesRef(self): - """ - If an I{a} node has a link with a scheme as its contained text, a - warning is emitted if that link does not match the value of the - I{href} attribute. - """ - documentSource = ( - '' - 'foo' - '

foo

' - '%s' - '' - '') - self.assertEqual( - self._lintCheck(True, documentSource % ("http://bar/baz",)), "") - self.assertIn( - "link text does not match href", - self._lintCheck(False, documentSource % ("http://bar/quux",))) - - - def _lintCheck(self, expectSuccess, source): - """ - Lint the given document source and return the output. - - @param expectSuccess: A flag indicating whether linting is expected - to succeed or not. - - @param source: The document source to lint. - - @return: A C{str} of the output of linting. - """ - document = minidom.parseString(source) - filename = self.mktemp() - checker = getDefaultChecker() - - output = StringIO() - patch = self.patch(sys, 'stdout', output) - try: - try: - checker.check(document, filename) - finally: - patch.restore() - except ProcessingFailure: - if expectSuccess: - raise - else: - if not expectSuccess: - self.fail( - "Expected checker to fail, but it did not. " - "Output was: %r" % (output.getvalue(),)) - - return output.getvalue() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_lmath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_lmath.py deleted file mode 100644 index a1e4c09..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_lmath.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.lore.lmath}. -""" - -from xml.dom.minidom import Element, Text - -from twisted.trial.unittest import TestCase -from twisted.python.filepath import FilePath -from twisted.lore.scripts.lore import IProcessor - -from twisted.plugin import getPlugins - -from twisted.lore.lmath import formulaeToImages - - -class PluginTests(TestCase): - """ - Tests for the plugin which lets L{twisted.lore.lmath} be used from the lore - command line tool. - """ - def test_discoverable(self): - """ - The plugin for L{twisted.lore.lmath} can be discovered by querying for - L{IProcessor} plugins. - """ - plugins = getPlugins(IProcessor) - lmath = [p for p in plugins if p.name == "mlore"] - self.assertEqual(len(lmath), 1, "Did not find math lore plugin: %r" % (lmath,)) - - - -class FormulaeTests(TestCase): - """ - Tests for L{formulaeToImages}. - """ - def test_insertImages(self): - """ - L{formulaeToImages} replaces any elements with the I{latexformula} - class with I{img} elements which refer to external images generated - based on the latex in the original elements. - """ - parent = Element('div') - base = FilePath(self.mktemp()) - base.makedirs() - - macros = Element('span') - macros.setAttribute('class', 'latexmacros') - text = Text() - text.data = 'foo' - macros.appendChild(text) - parent.appendChild(macros) - - formula = Element('span') - formula.setAttribute('class', 'latexformula') - text = Text() - text.data = 'bar' - formula.appendChild(text) - parent.appendChild(formula) - - # Avoid actually executing the commands to generate images from the - # latex. It might be nice to have some assertions about what commands - # are executed, or perhaps even execute them and make sure an image - # file is created, but that is a task for another day. - commands = [] - formulaeToImages(parent, base.path, _system=commands.append) - - self.assertEqual( - parent.toxml(), - '


') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_lore.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_lore.py deleted file mode 100644 index f9675b0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_lore.py +++ /dev/null @@ -1,1218 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# ++ single anchor added to individual output file -# ++ two anchors added to individual output file -# ++ anchors added to individual output files -# ++ entry added to index -# ++ index entry pointing to correct file and anchor -# ++ multiple entries added to index -# ++ multiple index entries pointing to correct files and anchors -# __ all of above for files in deep directory structure -# -# ++ group index entries by indexed term -# ++ sort index entries by indexed term -# __ hierarchical index entries (e.g. language!programming) -# -# ++ add parameter for what the index filename should be -# ++ add (default) ability to NOT index (if index not specified) -# -# ++ put actual index filename into INDEX link (if any) in the template -# __ make index links RELATIVE! -# __ make index pay attention to the outputdir! -# -# __ make index look nice -# -# ++ add section numbers to headers in lore output -# ++ make text of index entry links be chapter numbers -# ++ make text of index entry links be section numbers -# -# __ put all of our test files someplace neat and tidy -# - -import os, shutil, errno, time -from StringIO import StringIO -from xml.dom import minidom as dom - -from twisted.trial import unittest -from twisted.python.filepath import FilePath - -from twisted.lore import tree, process, indexer, numberer, htmlbook, default -from twisted.lore.default import factory -from twisted.lore.latex import LatexSpitter - -from twisted.python.util import sibpath - -from twisted.lore.scripts import lore - -from twisted.web import domhelpers -from twisted.test.testutils import XMLAssertionMixin - - -def sp(originalFileName): - return sibpath(__file__, originalFileName) - - - -options = {"template" : sp("template.tpl"), 'baseurl': '%s', 'ext': '.xhtml'} -d = options - - - -class RemoveBlanksTests(unittest.TestCase): - """ - Tests for L{tree._removeLeadingBlankLines} and - L{tree._removeLeadingTrailingBlankLines}. - """ - def setUp(self): - self.inputString = '\n\n\n\nfoo\nbar\n\n\n' - - - def test_removeLeadingBlankLines(self): - """ - L{tree._removeLeadingBlankLines} removes leading blank lines from a string and returns a list containing the remaining characters. - """ - result = tree._removeLeadingBlankLines(self.inputString) - self.assertEqual(result, - ['f', 'o', 'o', '\n', 'b', 'a', 'r', '\n', '\n', '\n']) - - - def test_removeLeadingTrailingBlankLines(self): - """ - L{tree._removeLeadingTrailingBlankLines} removes leading and trailing - blank lines from a string and returns a string with all lines joined. - """ - result = tree._removeLeadingTrailingBlankLines(self.inputString) - self.assertEqual(result, 'foo\nbar\n') - - - -class TestFactory(unittest.TestCase, XMLAssertionMixin): - - file = sp('simple.html') - linkrel = "" - - def assertEqualFiles1(self, exp, act): - if (exp == act): return True - fact = open(act) - self.assertEqualsFile(exp, fact.read()) - - def assertEqualFiles(self, exp, act): - if (exp == act): return True - fact = open(sp(act)) - self.assertEqualsFile(exp, fact.read()) - - def assertEqualsFile(self, exp, act): - expected = open(sp(exp)).read() - self.assertEqual(expected, act) - - def makeTemp(self, *filenames): - tmp = self.mktemp() - os.mkdir(tmp) - for filename in filenames: - tmpFile = os.path.join(tmp, filename) - shutil.copyfile(sp(filename), tmpFile) - return tmp - -######################################## - - def setUp(self): - indexer.reset() - numberer.reset() - - def testProcessingFunctionFactory(self): - base = FilePath(self.mktemp()) - base.makedirs() - - simple = base.child('simple.html') - FilePath(__file__).sibling('simple.html').copyTo(simple) - - htmlGenerator = factory.generate_html(options) - htmlGenerator(simple.path, self.linkrel) - - self.assertXMLEqual( - """\ - - Twisted Documentation: My Test Lore Input - -

My Test Lore Input

-
- -

A Body.

-
- Index - -""", - simple.sibling('simple.xhtml').getContent()) - - - def testProcessingFunctionFactoryWithFilenameGenerator(self): - base = FilePath(self.mktemp()) - base.makedirs() - - def filenameGenerator(originalFileName, outputExtension): - name = os.path.splitext(FilePath(originalFileName).basename())[0] - return base.child(name + outputExtension).path - - htmlGenerator = factory.generate_html(options, filenameGenerator) - htmlGenerator(self.file, self.linkrel) - self.assertXMLEqual( - """\ - - Twisted Documentation: My Test Lore Input - -

My Test Lore Input

-
- -

A Body.

-
- Index - -""", - base.child("simple.xhtml").getContent()) - - - def test_doFile(self): - base = FilePath(self.mktemp()) - base.makedirs() - - simple = base.child('simple.html') - FilePath(__file__).sibling('simple.html').copyTo(simple) - - templ = dom.parse(open(d['template'])) - - tree.doFile(simple.path, self.linkrel, d['ext'], d['baseurl'], templ, d) - self.assertXMLEqual( - """\ - - Twisted Documentation: My Test Lore Input - -

My Test Lore Input

-
- -

A Body.

-
- Index - -""", - base.child("simple.xhtml").getContent()) - - - def test_doFile_withFilenameGenerator(self): - base = FilePath(self.mktemp()) - base.makedirs() - - def filenameGenerator(originalFileName, outputExtension): - name = os.path.splitext(FilePath(originalFileName).basename())[0] - return base.child(name + outputExtension).path - - templ = dom.parse(open(d['template'])) - tree.doFile(self.file, self.linkrel, d['ext'], d['baseurl'], templ, d, filenameGenerator) - - self.assertXMLEqual( - """\ - - Twisted Documentation: My Test Lore Input - -

My Test Lore Input

-
- -

A Body.

-
- Index - -""", - base.child("simple.xhtml").getContent()) - - - def test_munge(self): - indexer.setIndexFilename("lore_index_file.html") - doc = dom.parse(open(self.file)) - node = dom.parse(open(d['template'])) - tree.munge(doc, node, self.linkrel, - os.path.dirname(self.file), - self.file, - d['ext'], d['baseurl'], d) - - self.assertXMLEqual( - """\ - - Twisted Documentation: My Test Lore Input - -

My Test Lore Input

-
- -

A Body.

-
- Index - -""", - node.toxml()) - - - def test_mungeAuthors(self): - """ - If there is a node with a I{class} attribute set to C{"authors"}, - L{tree.munge} adds anchors as children to it, taking the necessary - information from any I{link} nodes in the I{head} with their I{rel} - attribute set to C{"author"}. - """ - document = dom.parseString( - """\ - - - munge authors - - - - - -

munge authors

- -""") - template = dom.parseString( - """\ - - - - </head> - - <body> - <div class="body" /> - <div class="authors" /> - </body> -</html> -""") - tree.munge( - document, template, self.linkrel, os.path.dirname(self.file), - self.file, d['ext'], d['baseurl'], d) - - self.assertXMLEqual( - template.toxml(), - """\ -<?xml version="1.0" ?><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> - <head> - <title>munge authors - - - -
- -
-
foo, baz, and foobar
- -""") - - - def test_getProcessor(self): - - base = FilePath(self.mktemp()) - base.makedirs() - input = base.child("simple3.html") - FilePath(__file__).sibling("simple3.html").copyTo(input) - - options = { 'template': sp('template.tpl'), 'ext': '.xhtml', 'baseurl': 'burl', - 'filenameMapping': None } - p = process.getProcessor(default, "html", options) - p(input.path, self.linkrel) - self.assertXMLEqual( - """\ - - Twisted Documentation: My Test Lore Input - -

My Test Lore Input

-
- -

A Body.

-
- Index - -""", - base.child("simple3.xhtml").getContent()) - - def test_outputdirGenerator(self): - normp = os.path.normpath; join = os.path.join - inputdir = normp(join("/", 'home', 'joe')) - outputdir = normp(join("/", 'away', 'joseph')) - actual = process.outputdirGenerator(join("/", 'home', 'joe', "myfile.html"), - '.xhtml', inputdir, outputdir) - expected = normp(join("/", 'away', 'joseph', 'myfile.xhtml')) - self.assertEqual(expected, actual) - - def test_outputdirGeneratorBadInput(self): - options = {'outputdir': '/away/joseph/', 'inputdir': '/home/joe/' } - self.assertRaises(ValueError, process.outputdirGenerator, '.html', '.xhtml', **options) - - def test_makeSureDirectoryExists(self): - dirname = os.path.join("tmp", 'nonexistentdir') - if os.path.exists(dirname): - os.rmdir(dirname) - self.failIf(os.path.exists(dirname), "Hey: someone already created the dir") - filename = os.path.join(dirname, 'newfile') - tree.makeSureDirectoryExists(filename) - self.failUnless(os.path.exists(dirname), 'should have created dir') - os.rmdir(dirname) - - - def test_indexAnchorsAdded(self): - indexer.setIndexFilename('theIndexFile.html') - # generate the output file - templ = dom.parse(open(d['template'])) - tmp = self.makeTemp('lore_index_test.xhtml') - - tree.doFile(os.path.join(tmp, 'lore_index_test.xhtml'), - self.linkrel, '.html', d['baseurl'], templ, d) - - self.assertXMLEqual( - """\ - - Twisted Documentation: The way of the program - -

The way of the program

-
- - - -

The first paragraph.

- - -

The Python programming language

- - - -

The second paragraph.

- - -
- Index - -""", - FilePath(tmp).child("lore_index_test.html").getContent()) - - - def test_indexEntriesAdded(self): - indexer.addEntry('lore_index_test.html', 'index02', 'language of programming', '1.3') - indexer.addEntry('lore_index_test.html', 'index01', 'programming language', '1.2') - indexer.setIndexFilename("lore_index_file.html") - indexer.generateIndex() - self.assertEqualFiles1("lore_index_file_out.html", "lore_index_file.html") - - def test_book(self): - tmp = self.makeTemp() - inputFilename = sp('lore_index_test.xhtml') - - bookFilename = os.path.join(tmp, 'lore_test_book.book') - bf = open(bookFilename, 'w') - bf.write('Chapter(r"%s", None)\r\n' % inputFilename) - bf.close() - - book = htmlbook.Book(bookFilename) - expected = {'indexFilename': None, - 'chapters': [(inputFilename, None)], - } - dct = book.__dict__ - for k in dct: - self.assertEqual(dct[k], expected[k]) - - def test_runningLore(self): - options = lore.Options() - tmp = self.makeTemp('lore_index_test.xhtml') - - templateFilename = sp('template.tpl') - inputFilename = os.path.join(tmp, 'lore_index_test.xhtml') - indexFilename = 'theIndexFile' - - bookFilename = os.path.join(tmp, 'lore_test_book.book') - bf = open(bookFilename, 'w') - bf.write('Chapter(r"%s", None)\n' % inputFilename) - bf.close() - - options.parseOptions(['--null', '--book=%s' % bookFilename, - '--config', 'template=%s' % templateFilename, - '--index=%s' % indexFilename - ]) - result = lore.runGivenOptions(options) - self.assertEqual(None, result) - self.assertEqualFiles1("lore_index_file_unnumbered_out.html", indexFilename + ".html") - - - def test_runningLoreMultipleFiles(self): - tmp = self.makeTemp('lore_index_test.xhtml', 'lore_index_test2.xhtml') - templateFilename = sp('template.tpl') - inputFilename = os.path.join(tmp, 'lore_index_test.xhtml') - inputFilename2 = os.path.join(tmp, 'lore_index_test2.xhtml') - indexFilename = 'theIndexFile' - - bookFilename = os.path.join(tmp, 'lore_test_book.book') - bf = open(bookFilename, 'w') - bf.write('Chapter(r"%s", None)\n' % inputFilename) - bf.write('Chapter(r"%s", None)\n' % inputFilename2) - bf.close() - - options = lore.Options() - options.parseOptions(['--null', '--book=%s' % bookFilename, - '--config', 'template=%s' % templateFilename, - '--index=%s' % indexFilename - ]) - result = lore.runGivenOptions(options) - self.assertEqual(None, result) - - self.assertEqual( - # XXX This doesn't seem like a very good index file. - """\ -aahz: link
-aahz2: link
-language of programming: link, link
-programming language: link
-""", - file(FilePath(indexFilename + ".html").path).read()) - - self.assertXMLEqual( - """\ - - Twisted Documentation: The way of the program - -

The way of the program

-
- - - -

The first paragraph.

- - -

The Python programming language

- - - -

The second paragraph.

- - -
- Index - -""", - FilePath(tmp).child("lore_index_test.html").getContent()) - - self.assertXMLEqual( - """\ - - Twisted Documentation: The second page to index - -

The second page to index

-
- - - -

The first paragraph of the second page.

- - -

The Jython programming language

- - - - -

The second paragraph of the second page.

- - -
- Index - -""", - FilePath(tmp).child("lore_index_test2.html").getContent()) - - - - def XXXtest_NumberedSections(self): - # run two files through lore, with numbering turned on - # every h2 should be numbered: - # first file's h2s should be 1.1, 1.2 - # second file's h2s should be 2.1, 2.2 - templateFilename = sp('template.tpl') - inputFilename = sp('lore_numbering_test.xhtml') - inputFilename2 = sp('lore_numbering_test2.xhtml') - indexFilename = 'theIndexFile' - - # you can number without a book: - options = lore.Options() - options.parseOptions(['--null', - '--index=%s' % indexFilename, - '--config', 'template=%s' % templateFilename, - '--config', 'ext=%s' % ".tns", - '--number', - inputFilename, inputFilename2]) - result = lore.runGivenOptions(options) - - self.assertEqual(None, result) - #self.assertEqualFiles1("lore_index_file_out_multiple.html", indexFilename + ".tns") - # VVV change to new, numbered files - self.assertEqualFiles("lore_numbering_test_out.html", "lore_numbering_test.tns") - self.assertEqualFiles("lore_numbering_test_out2.html", "lore_numbering_test2.tns") - - - def test_setTitle(self): - """ - L{tree.setTitle} inserts the given title into the first I{title} - element and the first element with the I{title} class in the given - template. - """ - parent = dom.Element('div') - firstTitle = dom.Element('title') - parent.appendChild(firstTitle) - secondTitle = dom.Element('span') - secondTitle.setAttribute('class', 'title') - parent.appendChild(secondTitle) - - titleNodes = [dom.Text()] - # minidom has issues with cloning documentless-nodes. See Python issue - # 4851. - titleNodes[0].ownerDocument = dom.Document() - titleNodes[0].data = 'foo bar' - - tree.setTitle(parent, titleNodes, None) - self.assertEqual(firstTitle.toxml(), 'foo bar') - self.assertEqual( - secondTitle.toxml(), 'foo bar') - - - def test_setTitleWithChapter(self): - """ - L{tree.setTitle} includes a chapter number if it is passed one. - """ - document = dom.Document() - - parent = dom.Element('div') - parent.ownerDocument = document - - title = dom.Element('title') - parent.appendChild(title) - - titleNodes = [dom.Text()] - titleNodes[0].ownerDocument = document - titleNodes[0].data = 'foo bar' - - # Oh yea. The numberer has to agree to put the chapter number in, too. - numberer.setNumberSections(True) - - tree.setTitle(parent, titleNodes, '13') - self.assertEqual(title.toxml(), '13. foo bar') - - - def test_setIndexLink(self): - """ - Tests to make sure that index links are processed when an index page - exists and removed when there is not. - """ - templ = dom.parse(open(d['template'])) - indexFilename = 'theIndexFile' - numLinks = len(domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - # if our testing template has no index-link nodes, complain about it - self.assertNotEquals( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - tree.setIndexLink(templ, indexFilename) - - self.assertEqual( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - indexLinks = domhelpers.findElementsWithAttribute(templ, - "href", - indexFilename) - self.assertTrue(len(indexLinks) >= numLinks) - - templ = dom.parse(open(d['template'])) - self.assertNotEquals( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - indexFilename = None - - tree.setIndexLink(templ, indexFilename) - - self.assertEqual( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - - def test_addMtime(self): - """ - L{tree.addMtime} inserts a text node giving the last modification time - of the specified file wherever it encounters an element with the - I{mtime} class. - """ - path = FilePath(self.mktemp()) - path.setContent('') - when = time.ctime(path.getModificationTime()) - - parent = dom.Element('div') - mtime = dom.Element('span') - mtime.setAttribute('class', 'mtime') - parent.appendChild(mtime) - - tree.addMtime(parent, path.path) - self.assertEqual( - mtime.toxml(), '' + when + '') - - - def test_makeLineNumbers(self): - """ - L{tree._makeLineNumbers} takes an integer and returns a I{p} tag with - that number of line numbers in it. - """ - numbers = tree._makeLineNumbers(1) - self.assertEqual(numbers.tagName, 'p') - self.assertEqual(numbers.getAttribute('class'), 'py-linenumber') - self.assertIsInstance(numbers.firstChild, dom.Text) - self.assertEqual(numbers.firstChild.nodeValue, '1\n') - - numbers = tree._makeLineNumbers(10) - self.assertEqual(numbers.tagName, 'p') - self.assertEqual(numbers.getAttribute('class'), 'py-linenumber') - self.assertIsInstance(numbers.firstChild, dom.Text) - self.assertEqual( - numbers.firstChild.nodeValue, - ' 1\n 2\n 3\n 4\n 5\n' - ' 6\n 7\n 8\n 9\n10\n') - - - def test_fontifyPythonNode(self): - """ - L{tree.fontifyPythonNode} accepts a text node and replaces it in its - parent with a syntax colored and line numbered version of the Python - source it contains. - """ - parent = dom.Element('div') - source = dom.Text() - source.data = 'def foo():\n pass\n' - parent.appendChild(source) - - tree.fontifyPythonNode(source) - - expected = """\ -

1 -2 -

def foo(): - pass -
""" - - self.assertEqual(parent.toxml(), expected) - - - def test_addPyListings(self): - """ - L{tree.addPyListings} accepts a document with nodes with their I{class} - attribute set to I{py-listing} and replaces those nodes with Python - source listings from the file given by the node's I{href} attribute. - """ - listingPath = FilePath(self.mktemp()) - listingPath.setContent('def foo():\n pass\n') - - parent = dom.Element('div') - listing = dom.Element('a') - listing.setAttribute('href', listingPath.basename()) - listing.setAttribute('class', 'py-listing') - parent.appendChild(listing) - - tree.addPyListings(parent, listingPath.dirname()) - - expected = """\ -

1 -2 -

def foo(): - pass -
- temp
""" - - self.assertEqual(parent.toxml(), expected) - - - def test_addPyListingsSkipLines(self): - """ - If a node with the I{py-listing} class also has a I{skipLines} - attribute, that number of lines from the beginning of the source - listing are omitted. - """ - listingPath = FilePath(self.mktemp()) - listingPath.setContent('def foo():\n pass\n') - - parent = dom.Element('div') - listing = dom.Element('a') - listing.setAttribute('href', listingPath.basename()) - listing.setAttribute('class', 'py-listing') - listing.setAttribute('skipLines', 1) - parent.appendChild(listing) - - tree.addPyListings(parent, listingPath.dirname()) - - expected = """\ -

1 -

pass -
- temp
""" - - self.assertEqual(parent.toxml(), expected) - - - def test_fixAPI(self): - """ - The element passed to L{tree.fixAPI} has all of its children with the - I{API} class rewritten to contain links to the API which is referred to - by the text they contain. - """ - parent = dom.Element('div') - link = dom.Element('span') - link.setAttribute('class', 'API') - text = dom.Text() - text.data = 'foo' - link.appendChild(text) - parent.appendChild(link) - - tree.fixAPI(parent, 'http://example.com/%s') - self.assertEqual( - parent.toxml(), - '
' - 'foo' - '
') - - - def test_fixAPIBase(self): - """ - If a node with the I{API} class and a value for the I{base} attribute - is included in the DOM passed to L{tree.fixAPI}, the link added to that - node refers to the API formed by joining the value of the I{base} - attribute to the text contents of the node. - """ - parent = dom.Element('div') - link = dom.Element('span') - link.setAttribute('class', 'API') - link.setAttribute('base', 'bar') - text = dom.Text() - text.data = 'baz' - link.appendChild(text) - parent.appendChild(link) - - tree.fixAPI(parent, 'http://example.com/%s') - - self.assertEqual( - parent.toxml(), - '
' - 'baz' - '
') - - - def test_fixLinks(self): - """ - Links in the nodes of the DOM passed to L{tree.fixLinks} have their - extensions rewritten to the given extension. - """ - parent = dom.Element('div') - link = dom.Element('a') - link.setAttribute('href', 'foo.html') - parent.appendChild(link) - - tree.fixLinks(parent, '.xhtml') - - self.assertEqual(parent.toxml(), '
') - - - def test_setVersion(self): - """ - Nodes of the DOM passed to L{tree.setVersion} which have the I{version} - class have the given version added to them a child. - """ - parent = dom.Element('div') - version = dom.Element('span') - version.setAttribute('class', 'version') - parent.appendChild(version) - - tree.setVersion(parent, '1.2.3') - - self.assertEqual( - parent.toxml(), '
1.2.3
') - - - def test_footnotes(self): - """ - L{tree.footnotes} finds all of the nodes with the I{footnote} class in - the DOM passed to it and adds a footnotes section to the end of the - I{body} element which includes them. It also inserts links to those - footnotes from the original definition location. - """ - parent = dom.Element('div') - body = dom.Element('body') - footnote = dom.Element('span') - footnote.setAttribute('class', 'footnote') - text = dom.Text() - text.data = 'this is the footnote' - footnote.appendChild(text) - body.appendChild(footnote) - body.appendChild(dom.Element('p')) - parent.appendChild(body) - - tree.footnotes(parent) - - self.assertEqual( - parent.toxml(), - '
') - - - def test_generateTableOfContents(self): - """ - L{tree.generateToC} returns an element which contains a table of - contents generated from the headers in the document passed to it. - """ - parent = dom.Element('body') - header = dom.Element('h2') - text = dom.Text() - text.data = u'header & special character' - header.appendChild(text) - parent.appendChild(header) - subheader = dom.Element('h3') - text = dom.Text() - text.data = 'subheader' - subheader.appendChild(text) - parent.appendChild(subheader) - - tableOfContents = tree.generateToC(parent) - self.assertEqual( - tableOfContents.toxml(), - '
  1. header & special character
') - - self.assertEqual( - header.toxml(), - '

header & special character

') - - self.assertEqual( - subheader.toxml(), - '

subheader

') - - - def test_putInToC(self): - """ - L{tree.putInToC} replaces all of the children of the first node with - the I{toc} class with the given node representing a table of contents. - """ - parent = dom.Element('div') - toc = dom.Element('span') - toc.setAttribute('class', 'toc') - toc.appendChild(dom.Element('foo')) - parent.appendChild(toc) - - tree.putInToC(parent, dom.Element('toc')) - - self.assertEqual(toc.toxml(), '') - - - def test_invalidTableOfContents(self): - """ - If passed a document with I{h3} elements before any I{h2} element, - L{tree.generateToC} raises L{ValueError} explaining that this is not a - valid document. - """ - parent = dom.Element('body') - parent.appendChild(dom.Element('h3')) - err = self.assertRaises(ValueError, tree.generateToC, parent) - self.assertEqual( - str(err), "No H3 element is allowed until after an H2 element") - - - def test_notes(self): - """ - L{tree.notes} inserts some additional markup before the first child of - any node with the I{note} class. - """ - parent = dom.Element('div') - noteworthy = dom.Element('span') - noteworthy.setAttribute('class', 'note') - noteworthy.appendChild(dom.Element('foo')) - parent.appendChild(noteworthy) - - tree.notes(parent) - - self.assertEqual( - noteworthy.toxml(), - 'Note: ') - - - def test_findNodeJustBefore(self): - """ - L{tree.findNodeJustBefore} returns the previous sibling of the node it - is passed. The list of nodes passed in is ignored. - """ - parent = dom.Element('div') - result = dom.Element('foo') - target = dom.Element('bar') - parent.appendChild(result) - parent.appendChild(target) - - self.assertIdentical( - tree.findNodeJustBefore(target, [parent, result]), - result) - - # Also, support other configurations. This is a really not nice API. - newTarget = dom.Element('baz') - target.appendChild(newTarget) - self.assertIdentical( - tree.findNodeJustBefore(newTarget, [parent, result]), - result) - - - def test_getSectionNumber(self): - """ - L{tree.getSectionNumber} accepts an I{H2} element and returns its text - content. - """ - header = dom.Element('foo') - text = dom.Text() - text.data = 'foobar' - header.appendChild(text) - self.assertEqual(tree.getSectionNumber(header), 'foobar') - - - def test_numberDocument(self): - """ - L{tree.numberDocument} inserts section numbers into the text of each - header. - """ - parent = dom.Element('foo') - section = dom.Element('h2') - text = dom.Text() - text.data = 'foo' - section.appendChild(text) - parent.appendChild(section) - - tree.numberDocument(parent, '7') - - self.assertEqual(section.toxml(), '

7.1 foo

') - - - def test_parseFileAndReport(self): - """ - L{tree.parseFileAndReport} parses the contents of the filename passed - to it and returns the corresponding DOM. - """ - path = FilePath(self.mktemp()) - path.setContent('hello\n') - - document = tree.parseFileAndReport(path.path) - self.assertXMLEqual( - document.toxml(), - 'hello') - - - def test_parseFileAndReportMismatchedTags(self): - """ - If the contents of the file passed to L{tree.parseFileAndReport} - contain a mismatched tag, L{process.ProcessingFailure} is raised - indicating the location of the open and close tags which were - mismatched. - """ - path = FilePath(self.mktemp()) - path.setContent(' \n\n ') - - err = self.assertRaises( - process.ProcessingFailure, tree.parseFileAndReport, path.path) - self.assertEqual( - str(err), - "mismatched close tag at line 3, column 4; expected " - "(from line 1, column 2)") - - # Test a case which requires involves proper close tag handling. - path.setContent('\n ') - - err = self.assertRaises( - process.ProcessingFailure, tree.parseFileAndReport, path.path) - self.assertEqual( - str(err), - "mismatched close tag at line 2, column 4; expected " - "(from line 1, column 0)") - - - def test_parseFileAndReportParseError(self): - """ - If the contents of the file passed to L{tree.parseFileAndReport} cannot - be parsed for a reason other than mismatched tags, - L{process.ProcessingFailure} is raised with a string describing the - parse error. - """ - path = FilePath(self.mktemp()) - path.setContent('\n foo') - - err = self.assertRaises( - process.ProcessingFailure, tree.parseFileAndReport, path.path) - self.assertEqual(str(err), 'syntax error at line 2, column 3') - - - def test_parseFileAndReportIOError(self): - """ - If an L{IOError} is raised while reading from the file specified to - L{tree.parseFileAndReport}, a L{process.ProcessingFailure} is raised - indicating what the error was. The file should be closed by the - time the exception is raised to the caller. - """ - class FakeFile: - _open = True - def read(self, bytes=None): - raise IOError(errno.ENOTCONN, 'socket not connected') - - def close(self): - self._open = False - - theFile = FakeFile() - def fakeOpen(filename): - return theFile - - err = self.assertRaises( - process.ProcessingFailure, tree.parseFileAndReport, "foo", fakeOpen) - self.assertEqual(str(err), "socket not connected, filename was 'foo'") - self.assertFalse(theFile._open) - - - -class XMLParsingTests(unittest.TestCase): - """ - Tests for various aspects of parsing a Lore XML input document using - L{tree.parseFileAndReport}. - """ - def _parseTest(self, xml): - path = FilePath(self.mktemp()) - path.setContent(xml) - return tree.parseFileAndReport(path.path) - - - def test_withoutDocType(self): - """ - A Lore XML input document may omit a I{DOCTYPE} declaration. If it - does so, the XHTML1 Strict DTD is used. - """ - # Parsing should succeed. - document = self._parseTest("uses an xhtml entity: ©") - # But even more than that, the © entity should be turned into the - # appropriate unicode codepoint. - self.assertEqual( - domhelpers.gatherTextNodes(document.documentElement), - u"uses an xhtml entity: \N{COPYRIGHT SIGN}") - - - def test_withTransitionalDocType(self): - """ - A Lore XML input document may include a I{DOCTYPE} declaration - referring to the XHTML1 Transitional DTD. - """ - # Parsing should succeed. - document = self._parseTest("""\ - -uses an xhtml entity: © -""") - # But even more than that, the © entity should be turned into the - # appropriate unicode codepoint. - self.assertEqual( - domhelpers.gatherTextNodes(document.documentElement), - u"uses an xhtml entity: \N{COPYRIGHT SIGN}") - - - def test_withStrictDocType(self): - """ - A Lore XML input document may include a I{DOCTYPE} declaration - referring to the XHTML1 Strict DTD. - """ - # Parsing should succeed. - document = self._parseTest("""\ - -uses an xhtml entity: © -""") - # But even more than that, the © entity should be turned into the - # appropriate unicode codepoint. - self.assertEqual( - domhelpers.gatherTextNodes(document.documentElement), - u"uses an xhtml entity: \N{COPYRIGHT SIGN}") - - - def test_withDisallowedDocType(self): - """ - A Lore XML input document may not include a I{DOCTYPE} declaration - referring to any DTD other than XHTML1 Transitional or XHTML1 Strict. - """ - self.assertRaises( - process.ProcessingFailure, - self._parseTest, - """\ - -uses an xhtml entity: © -""") - - - -class XMLSerializationTests(unittest.TestCase, XMLAssertionMixin): - """ - Tests for L{tree._writeDocument}. - """ - def test_nonASCIIData(self): - """ - A document which contains non-ascii characters is serialized to a - file using UTF-8. - """ - document = dom.Document() - parent = dom.Element('foo') - text = dom.Text() - text.data = u'\N{SNOWMAN}' - parent.appendChild(text) - document.appendChild(parent) - outFile = self.mktemp() - tree._writeDocument(outFile, document) - self.assertXMLEqual( - FilePath(outFile).getContent(), - u'\N{SNOWMAN}'.encode('utf-8')) - - - -class LatexSpitterTestCase(unittest.TestCase): - """ - Tests for the Latex output plugin. - """ - def test_indexedSpan(self): - """ - Test processing of a span tag with an index class results in a latex - \\index directive the correct value. - """ - doc = dom.parseString('').documentElement - out = StringIO() - spitter = LatexSpitter(out.write) - spitter.visitNode(doc) - self.assertEqual(out.getvalue(), u'\\index{name}\n') - - - -class ScriptTests(unittest.TestCase): - """ - Tests for L{twisted.lore.scripts.lore}, the I{lore} command's - implementation, - """ - def test_getProcessor(self): - """ - L{lore.getProcessor} loads the specified output plugin from the - specified input plugin. - """ - processor = lore.getProcessor("lore", "html", options) - self.assertNotIdentical(processor, None) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_man2lore.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_man2lore.py deleted file mode 100644 index 06ada30..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_man2lore.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Tests for L{twisted.lore.man2lore}. -""" - -from StringIO import StringIO - -from twisted.trial.unittest import TestCase - -from twisted.lore.man2lore import ManConverter - - -_TRANSITIONAL_XHTML_DTD = ("""\ - - -""") - - -class ManConverterTestCase(TestCase): - """ - Tests for L{ManConverter}. - """ - - def setUp(self): - """ - Build instance variables useful for tests. - - @ivar converter: a L{ManConverter} to be used during tests. - """ - self.converter = ManConverter() - - - def assertConvert(self, inputLines, expectedOutput): - """ - Helper method to check conversion from a man page to a Lore output. - - @param inputLines: lines of the manpages. - @type inputLines: C{list} - - @param expectedOutput: expected Lore content. - @type expectedOutput: C{str} - """ - inputFile = StringIO() - for line in inputLines: - inputFile.write(line + '\n') - inputFile.seek(0) - outputFile = StringIO() - self.converter.convert(inputFile, outputFile) - self.assertEqual( - outputFile.getvalue(), _TRANSITIONAL_XHTML_DTD + expectedOutput) - - - def test_convert(self): - """ - Test convert on a minimal example. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', "Foo\n"] - output = ("\nBAR.1\n\n\n" - "

BAR.1

\n\n

Foo\n\n

\n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_TP(self): - """ - Test C{TP} parsing. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".TP", - "\\fB-o\\fR, \\fB--option\\fR", - "An option"] - output = ("\nBAR.1\n\n\n" - "

BAR.1

\n\n

HEADER

\n\n
" - "-o, --option\n
" - "
An option\n
\n\n
\n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_TPMultipleOptions(self): - """ - Try to parse multiple C{TP} fields. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".TP", - "\\fB-o\\fR, \\fB--option\\fR", - "An option", - ".TP", - "\\fB-n\\fR, \\fB--another\\fR", - "Another option", - ] - output = ("\nBAR.1\n\n\n" - "

BAR.1

\n\n

HEADER

\n\n
" - "-o, --option\n
" - "
An option\n
\n\n
" - "-n, --another\n
" - "
Another option\n
\n\n
\n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_TPMultiLineOptions(self): - """ - Try to parse multiple C{TP} fields, with options text on several lines. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".TP", - "\\fB-o\\fR, \\fB--option\\fR", - "An option", - "on two lines", - ".TP", - "\\fB-n\\fR, \\fB--another\\fR", - "Another option", - "on two lines", - ] - output = ("\nBAR.1\n\n\n" - "

BAR.1

\n\n

HEADER

\n\n
" - "-o, --option\n
" - "
An option\non two lines\n
\n\n" - "
-n, --another\n
" - "
Another option\non two lines\n
\n\n
\n\n" - "\n\n") - self.assertConvert(inputLines, output) - - - def test_ITLegacyManagement(self): - """ - Test management of BL/IT/EL used in some man pages. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".BL", - ".IT An option", - "on two lines", - ".IT", - "Another option", - "on two lines", - ".EL" - ] - output = ("\nBAR.1\n\n\n" - "

BAR.1

\n\n

HEADER

\n\n
" - "
on two lines\n
Another option\non two lines\n" - "
\n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_interactiveCommand(self): - """ - Test management of interactive command tag. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".BL", - ".IT IC foo AR bar", - "option 1", - ".IT IC egg AR spam OP AR stuff", - "option 2", - ".EL" - ] - output = ("\nBAR.1\n\n\n" - "

BAR.1

\n\n

HEADER

\n\n
" - "
foo bar
option 1\n
egg " - "spam [stuff]
option 2\n
" - "\n\n\n\n") - self.assertConvert(inputLines, output) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_scripts.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_scripts.py deleted file mode 100644 index 0a8328b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_scripts.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for the command-line interface to lore. -""" - -from twisted.trial.unittest import TestCase -from twisted.scripts.test.test_scripts import ScriptTestsMixin -from twisted.python.test.test_shellcomp import ZshScriptTestMixin - - - -class ScriptTests(TestCase, ScriptTestsMixin): - """ - Tests for all one of lore's scripts. - """ - def test_lore(self): - self.scriptTest("lore/lore") - - - -class ZshIntegrationTestCase(TestCase, ZshScriptTestMixin): - """ - Test that zsh completion functions are generated without error - """ - generateFor = [('lore', 'twisted.lore.scripts.lore.Options')] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_slides.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_slides.py deleted file mode 100644 index ccb9271..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_slides.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.lore.slides}. -""" - -from xml.dom.minidom import Element, Text - -from twisted.trial.unittest import TestCase -from twisted.lore.slides import ( - HTMLSlide, splitIntoSlides, insertPrevNextLinks, MagicpointOutput) - - -class SlidesTests(TestCase): - """ - Tests for functions in L{twisted.lore.slides}. - """ - def test_splitIntoSlides(self): - """ - L{splitIntoSlides} accepts a document and returns a list of two-tuples, - each element of which contains the title of a slide taken from an I{h2} - element and the body of that slide. - """ - parent = Element('html') - body = Element('body') - parent.appendChild(body) - - first = Element('h2') - text = Text() - text.data = 'first slide' - first.appendChild(text) - body.appendChild(first) - body.appendChild(Element('div')) - body.appendChild(Element('span')) - - second = Element('h2') - text = Text() - text.data = 'second slide' - second.appendChild(text) - body.appendChild(second) - body.appendChild(Element('p')) - body.appendChild(Element('br')) - - slides = splitIntoSlides(parent) - - self.assertEqual(slides[0][0], 'first slide') - firstContent = slides[0][1] - self.assertEqual(firstContent[0].tagName, 'div') - self.assertEqual(firstContent[1].tagName, 'span') - self.assertEqual(len(firstContent), 2) - - self.assertEqual(slides[1][0], 'second slide') - secondContent = slides[1][1] - self.assertEqual(secondContent[0].tagName, 'p') - self.assertEqual(secondContent[1].tagName, 'br') - self.assertEqual(len(secondContent), 2) - - self.assertEqual(len(slides), 2) - - - def test_insertPrevNextText(self): - """ - L{insertPrevNextLinks} appends a text node with the title of the - previous slide to each node with a I{previous} class and the title of - the next slide to each node with a I{next} class. - """ - next = Element('span') - next.setAttribute('class', 'next') - container = Element('div') - container.appendChild(next) - slideWithNext = HTMLSlide(container, 'first', 0) - - previous = Element('span') - previous.setAttribute('class', 'previous') - container = Element('div') - container.appendChild(previous) - slideWithPrevious = HTMLSlide(container, 'second', 1) - - insertPrevNextLinks( - [slideWithNext, slideWithPrevious], None, None) - - self.assertEqual( - next.toxml(), 'second') - self.assertEqual( - previous.toxml(), 'first') - - - -class MagicpointOutputTests(TestCase): - """ - Tests for L{lore.slides.MagicpointOutput}. - """ - def setUp(self): - self.filename = self.mktemp() - self.output = [] - self.spitter = MagicpointOutput(self.output.append, - filename=self.filename) - - self.parent = Element('html') - title = Element('title') - text = Text() - text.data = "My Title" - title.appendChild(text) - self.body = Element('body') - self.parent.appendChild(title) - self.parent.appendChild(self.body) - - - def test_body(self): - """ - L{MagicpointOutput.visitNode} emits a verbatim block when it encounters - a I{body} element. - """ - link = Element('link') - link.setAttribute('class', 'author') - text = Text() - text.data = u"John Doe" - link.appendChild(text) - self.body.appendChild(link) - - head = Element('h2') - first = Text() - first.data = u'My Header' - head.appendChild(first) - self.body.appendChild(head) - - self.spitter.visitNode(self.parent) - self.assertEqual( - ''.join(self.output), - '%page\n\nMy Title\n\n\n%center\n\n\n\n\nJohn Doe\n%page\n\n' - 'My Title\n\n\n\tMy Header\nJohn Doe%page\n\nMy Header\n\n\n') - - - def test_pre(self): - """ - L{MagicpointOutput.visitNode} emits the 'typewriter' font when it - encounters a I{pre} element. - """ - pre = Element('pre') - text = Text() - text.data = u"\nfirst line\nsecond line\n\n" - pre.appendChild(text) - self.body.appendChild(pre) - - self.spitter.visitNode(self.parent) - self.assertEqual( - ''.join(self.output), - '%page\n\nMy Title\n\n\n%center\n\n\n\n\n%page\n\nMy Title\n\n\n' - '%font "typewriter", size 4\n first line\n second line\n \n' - '%font "standard"\n') - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_texi.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_texi.py deleted file mode 100644 index ac805da..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/test/test_texi.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.lore.texi}. -""" - -from xml.dom.minidom import Element, Text - -from twisted.trial.unittest import TestCase -from twisted.lore.texi import TexiSpitter - - -class TexiSpitterTests(TestCase): - """ - Tests for L{TexiSpitter}. - """ - def setUp(self): - self.filename = self.mktemp() - self.output = [] - self.spitter = TexiSpitter(self.output.append, filename=self.filename) - - - def test_title(self): - """ - L{TexiSpitter.visitNode} emits I{@node} and I{@section} blocks when it - encounters a I{title} element. - """ - titleElement = Element('title') - text = Text() - text.data = u'bar' - titleElement.appendChild(text) - - self.spitter.visitNode(titleElement) - self.assertEqual(''.join(self.output), '@node bar\n@section bar\n') - - - def test_titleWithHeader(self): - """ - L{TexiSpitter.visitNode} emits I{@subsection} and I{@menu} blocks when - it encounters a header (h2 or h3) in a I{title} element. - """ - titleElement = Element('title') - text = Text() - text.data = u'bar' - titleElement.appendChild(text) - - head = Element('h2') - first = Text() - first.data = u'header1' - head.appendChild(first) - titleElement.appendChild(head) - - self.spitter.visitNode(titleElement) - self.assertEqual(''.join(self.output), - '@node bar\n\n@node header1\n\n\n@subsection header1\n\n' - '@section bar\n\n@node header1\n\n\n@subsection header1\n\n' - '@menu\n* header1::\n@end menu\n') - - - def test_pre(self): - """ - L{TexiSpitter.visitNode} emits a verbatim block when it encounters a - I{pre} element. - """ - preElement = Element('pre') - text = Text() - text.data = u'foo' - preElement.appendChild(text) - - self.spitter.visitNode(preElement) - self.assertEqual(''.join(self.output), - '@verbatim\nfoo\n@end verbatim\n') - - - def test_code(self): - """ - L{TexiSpitter.visitNode} emits a C{@code} block when it encounters a - I{code} element. - """ - codeElement = Element('code') - text = Text() - text.data = u'print' - codeElement.appendChild(text) - - self.spitter.visitNode(codeElement) - self.assertEqual(''.join(self.output), "@code{print}") - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/texi.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/texi.py deleted file mode 100644 index 991b3f3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/texi.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- test-case-name: twisted.lore.test.test_texi -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from cStringIO import StringIO -import os, re - -from twisted.web import domhelpers -import latex, tree - -spaceRe = re.compile('\s+') - -def texiEscape(text): - return spaceRe.sub(text, ' ') - -entities = latex.entities.copy() -entities['copy'] = '@copyright{}' - -class TexiSpitter(latex.BaseLatexSpitter): - - baseLevel = 1 - - def writeNodeData(self, node): - latex.getLatexText(node, self.writer, texiEscape, entities) - - def visitNode_title(self, node): - self.writer('@node ') - self.visitNodeDefault(node) - self.writer('\n') - self.writer('@section ') - self.visitNodeDefault(node) - self.writer('\n') - headers = tree.getHeaders(domhelpers.getParents(node)[-1]) - if not headers: - return - self.writer('@menu\n') - for header in headers: - self.writer('* %s::\n' % domhelpers.getNodeText(header)) - self.writer('@end menu\n') - - - def visitNode_pre(self, node): - """ - Writes a I{verbatim} block when it encounters a I{pre} element. - - @param node: The element to process. - @type node: L{xml.dom.minidom.Element} - """ - self.writer('@verbatim\n') - buf = StringIO() - latex.getLatexText(node, buf.write, entities=entities) - self.writer(tree._removeLeadingTrailingBlankLines(buf.getvalue())) - self.writer('@end verbatim\n') - - - def visitNode_code(self, node): - fout = StringIO() - latex.getLatexText(node, fout.write, texiEscape, entities) - self.writer('@code{'+fout.getvalue()+'}') - - def visitNodeHeader(self, node): - self.writer('\n\n@node ') - self.visitNodeDefault(node) - self.writer('\n') - level = (int(node.tagName[1])-2)+self.baseLevel - self.writer('\n\n@'+level*'sub'+'section ') - self.visitNodeDefault(node) - self.writer('\n') - - def visitNode_a_listing(self, node): - fileName = os.path.join(self.currDir, node.getAttribute('href')) - self.writer('@verbatim\n') - self.writer(open(fileName).read()) - self.writer('@end verbatim') - # Write a caption for this source listing - - def visitNode_a_href(self, node): - self.visitNodeDefault(node) - - def visitNode_a_name(self, node): - self.visitNodeDefault(node) - - visitNode_h2 = visitNode_h3 = visitNode_h4 = visitNodeHeader - - start_dl = '@itemize\n' - end_dl = '@end itemize\n' - start_ul = '@itemize\n' - end_ul = '@end itemize\n' - - start_ol = '@enumerate\n' - end_ol = '@end enumerate\n' - - start_li = '@item\n' - end_li = '\n' - - start_dt = '@item\n' - end_dt = ': ' - end_dd = '\n' - - start_p = '\n\n' - - start_strong = start_em = '@emph{' - end_strong = end_em = '}' - - start_q = "``" - end_q = "''" - - start_span_footnote = '@footnote{' - end_span_footnote = '}' - - start_div_note = '@quotation\n@strong{Note:}' - end_div_note = '@end quotation\n' - - start_th = '@strong{' - end_th = '}' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/NEWS deleted file mode 100644 index 74f6213..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/NEWS +++ /dev/null @@ -1,239 +0,0 @@ -Ticket numbers in this file can be looked up by visiting -http://twistedmatrix.com/trac/ticket/ - -Twisted Lore 15.2.1 (2015-05-23) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 15.2.0 (2015-05-18) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 15.1.0 (2015-04-02) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 15.0.0 (2015-01-24) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 14.0.2 (2014-09-18) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 14.0.1 (2014-09-17) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 14.0.0 (2014-05-08) -================================ - -Deprecations and Removals -------------------------- - - twisted.lore is now deprecated in favor of Sphinx. (#6907) - -Other ------ - - #6998 - - -Twisted Lore 13.2.0 (2013-10-29) -================================ - -No significant changes have been made for this release. - -Other ------ - - #6546 - - -Twisted Lore 13.1.0 (2013-06-23) -================================ - -Deprecations and Removals -------------------------- - - twisted.lore.lint.parserErrors is deprecated now. (#5386) - - -Twisted Lore 13.0.0 (2013-03-19) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 12.3.0 (2012-12-20) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 12.2.0 (2012-08-26) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 12.1.0 (2012-06-02) -================================ - -Bugfixes --------- - - twisted.plugins.twisted_lore's MathProcessor plugin is now - associated with the correct implementation module. (#5326) - - -Twisted Lore 12.0.0 (2012-02-10) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 11.1.0 (2011-11-15) -================================ - -Bugfixes --------- - - When run from an unpacked source tarball or a VCS checkout, - bin/lore/lore will now use the version of Twisted it is part of. - (#3526) - -Deprecations and Removals -------------------------- - - Removed compareMarkPos and comparePosition from lore.tree, - deprecated in Twisted 9.0. (#5127) - - -Twisted Lore 11.0.0 (2011-04-01) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 10.2.0 (2010-11-29) -================================ - -No significant changes have been made for this release. - -Other ------ - - #4571 - - -Twisted Lore 10.1.0 (2010-06-27) -================================ - -No significant changes have been made for this release. - - -Twisted Lore 10.0.0 (2010-03-01) -================================ - -Other ------ - - #4241 - - -Twisted Lore 9.0.0 (2009-11-24) -=============================== - -Features --------- - - Python source listings now include line numbers (#3486) - -Fixes ------ - - Lore now uses minidom instead of Twisted's microdom, which incidentally - fixes some Lore bugs such as throwing away certain whitespace - (#3560, #414, #3619) - - Lore's "lint" command should no longer break on documents with links in them - (#4051, #4115) - -Deprecations and Removals -------------------------- - - Lore no longer uses the ancient "tml" Twisted plugin system (#1911) - -Other ------ - - #3565, #3246, #3540, #3750, #4050 - - -Lore 8.2.0 (2008-12-16) -======================= - -Other ------ - - #2207, #2514 - - -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Fixes ------ - - Change twisted.lore.tree.setIndexLin so that it removes node with index-link - class when the specified index filename is None. (#812) - - Fix the conversion of the list of options in man pages to Lore format. - (#3017) - - Fix conch man pages generation. (#3075) - - Fix management of the interactive command tag in man2lore. (#3076) - -Misc ----- - - #2847 - - -0.3.0 (2007-01-06) -================== - -Features --------- - - Many docstrings were added to twisted.lore.tree (#2301) - -Fixes ------ - - Emitting a span with an index class to latex now works (#2134) - - -0.2.0 (2006-05-24) -================== - -Features --------- - - Docstring improvements. - -Fixes ------ - - Embedded Dia support for Latex no longer requires the 'which' - command line tool. - - Misc: #1142. - -Deprecations ------------- - - The unused, undocumented, untested and severely crashy 'bookify' - functionality was removed. - - -0.1.0 -===== - - Use htmlizer mode that doesn't insert extra span tags, thus making - it not mess up in Safari. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/README deleted file mode 100644 index 6ad4afa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/README +++ /dev/null @@ -1,3 +0,0 @@ -Twisted Lore 15.2.1 - -Twisted Lore depends on Twisted and Twisted Web. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/setup.py deleted file mode 100644 index b9c29ca..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/topfiles/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="lore", - scripts=dist.getScripts("lore"), - # metadata - name="Twisted Lore", - description="Twisted documentation system", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Andrew Bennetts", - url="http://twistedmatrix.com/trac/wiki/TwistedLore", - license="MIT", - long_description="""\ -Twisted Lore is a documentation generator with HTML and LaTeX support, -used in the Twisted project. -""", - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/tree.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/tree.py deleted file mode 100755 index 1435b34..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/tree.py +++ /dev/null @@ -1,1161 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from itertools import count -import re, os, cStringIO, time, cgi, urlparse -from xml.dom import minidom as dom -from xml.sax.handler import ErrorHandler, feature_validation -from xml.dom.pulldom import SAX2DOM -from xml.sax import make_parser -from xml.sax.xmlreader import InputSource - -from twisted.python import htmlizer -from twisted.python.filepath import FilePath -from twisted.web import domhelpers -import process, latex, indexer, numberer, htmlbook - - - -# relative links to html files -def fixLinks(document, ext): - """ - Rewrite links to XHTML lore input documents so they point to lore XHTML - output documents. - - Any node with an C{href} attribute which does not contain a value starting - with C{http}, C{https}, C{ftp}, or C{mailto} and which does not have a - C{class} attribute of C{absolute} or which contains C{listing} and which - does point to an URL ending with C{html} will have that attribute value - rewritten so that the filename extension is C{ext} instead of C{html}. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type ext: C{str} - @param ext: The extension to use when selecting an output file name. This - replaces the extension of the input file name. - - @return: C{None} - """ - supported_schemes=['http', 'https', 'ftp', 'mailto'] - for node in domhelpers.findElementsWithAttribute(document, 'href'): - href = node.getAttribute("href") - if urlparse.urlparse(href)[0] in supported_schemes: - continue - if node.getAttribute("class") == "absolute": - continue - if node.getAttribute("class").find('listing') != -1: - continue - - # This is a relative link, so it should be munged. - if href.endswith('html') or href[:href.rfind('#')].endswith('html'): - fname, fext = os.path.splitext(href) - if '#' in fext: - fext = ext+'#'+fext.split('#', 1)[1] - else: - fext = ext - node.setAttribute("href", fname + fext) - - - -def addMtime(document, fullpath): - """ - Set the last modified time of the given document. - - @type document: A DOM Node or Document - @param document: The output template which defines the presentation of the - last modified time. - - @type fullpath: C{str} - @param fullpath: The file name from which to take the last modified time. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class","mtime"): - txt = dom.Text() - txt.data = time.ctime(os.path.getmtime(fullpath)) - node.appendChild(txt) - - - -def _getAPI(node): - """ - Retrieve the fully qualified Python name represented by the given node. - - The name is represented by one or two aspects of the node: the value of the - node's first child forms the end of the name. If the node has a C{base} - attribute, that attribute's value is prepended to the node's value, with - C{.} separating the two parts. - - @rtype: C{str} - @return: The fully qualified Python name. - """ - base = "" - if node.hasAttribute("base"): - base = node.getAttribute("base") + "." - return base+node.childNodes[0].nodeValue - - - -def fixAPI(document, url): - """ - Replace API references with links to API documentation. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type url: C{str} - @param url: A string which will be interpolated with the fully qualified - Python name of any API reference encountered in the input document, the - result of which will be used as a link to API documentation for that name - in the output document. - - @return: C{None} - """ - # API references - for node in domhelpers.findElementsWithAttribute(document, "class", "API"): - fullname = _getAPI(node) - anchor = dom.Element('a') - anchor.setAttribute('href', url % (fullname,)) - anchor.setAttribute('title', fullname) - while node.childNodes: - child = node.childNodes[0] - node.removeChild(child) - anchor.appendChild(child) - node.appendChild(anchor) - if node.hasAttribute('base'): - node.removeAttribute('base') - - - -def fontifyPython(document): - """ - Syntax color any node in the given document which contains a Python source - listing. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - def matcher(node): - return (node.nodeName == 'pre' and node.hasAttribute('class') and - node.getAttribute('class') == 'python') - for node in domhelpers.findElements(document, matcher): - fontifyPythonNode(node) - - - -def fontifyPythonNode(node): - """ - Syntax color the given node containing Python source code. - - The node must have a parent. - - @return: C{None} - """ - oldio = cStringIO.StringIO() - latex.getLatexText(node, oldio.write, - entities={'lt': '<', 'gt': '>', 'amp': '&'}) - oldio = cStringIO.StringIO(oldio.getvalue().strip()+'\n') - howManyLines = len(oldio.getvalue().splitlines()) - newio = cStringIO.StringIO() - htmlizer.filter(oldio, newio, writer=htmlizer.SmallerHTMLWriter) - lineLabels = _makeLineNumbers(howManyLines) - newel = dom.parseString(newio.getvalue()).documentElement - newel.setAttribute("class", "python") - node.parentNode.replaceChild(newel, node) - newel.insertBefore(lineLabels, newel.firstChild) - - - -def addPyListings(document, dir): - """ - Insert Python source listings into the given document from files in the - given directory based on C{py-listing} nodes. - - Any node in C{document} with a C{class} attribute set to C{py-listing} will - have source lines taken from the file named in that node's C{href} - attribute (searched for in C{dir}) inserted in place of that node. - - If a node has a C{skipLines} attribute, its value will be parsed as an - integer and that many lines will be skipped at the beginning of the source - file. - - @type document: A DOM Node or Document - @param document: The document within which to make listing replacements. - - @type dir: C{str} - @param dir: The directory in which to find source files containing the - referenced Python listings. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class", - "py-listing"): - filename = node.getAttribute("href") - outfile = cStringIO.StringIO() - lines = map(str.rstrip, open(os.path.join(dir, filename)).readlines()) - - skip = node.getAttribute('skipLines') or 0 - lines = lines[int(skip):] - howManyLines = len(lines) - data = '\n'.join(lines) - - data = cStringIO.StringIO(_removeLeadingTrailingBlankLines(data)) - htmlizer.filter(data, outfile, writer=htmlizer.SmallerHTMLWriter) - sourceNode = dom.parseString(outfile.getvalue()).documentElement - sourceNode.insertBefore(_makeLineNumbers(howManyLines), sourceNode.firstChild) - _replaceWithListing(node, sourceNode.toxml(), filename, "py-listing") - - - -def _makeLineNumbers(howMany): - """ - Return an element which will render line numbers for a source listing. - - @param howMany: The number of lines in the source listing. - @type howMany: C{int} - - @return: An L{dom.Element} which can be added to the document before - the source listing to add line numbers to it. - """ - # Figure out how many digits wide the widest line number label will be. - width = len(str(howMany)) - - # Render all the line labels with appropriate padding - labels = ['%*d' % (width, i) for i in range(1, howMany + 1)] - - # Create a p element with the right style containing the labels - p = dom.Element('p') - p.setAttribute('class', 'py-linenumber') - t = dom.Text() - t.data = '\n'.join(labels) + '\n' - p.appendChild(t) - return p - - -def _replaceWithListing(node, val, filename, class_): - captionTitle = domhelpers.getNodeText(node) - if captionTitle == os.path.basename(filename): - captionTitle = 'Source listing' - text = ('
' % - (class_, val, captionTitle, filename, filename)) - newnode = dom.parseString(text).documentElement - node.parentNode.replaceChild(newnode, node) - - - -def _removeLeadingBlankLines(lines): - """ - Removes leading blank lines from C{lines} and returns a list containing the - remaining characters. - - @param lines: Input string. - @type lines: L{str} - @rtype: C{list} - @return: List of characters. - """ - ret = [] - for line in lines: - if ret or line.strip(): - ret.append(line) - return ret - - - -def _removeLeadingTrailingBlankLines(inputString): - """ - Splits input string C{inputString} into lines, strips leading and trailing - blank lines, and returns a string with all lines joined, each line - separated by a newline character. - - @param inputString: The input string. - @type inputString: L{str} - @rtype: L{str} - @return: String containing normalized lines. - """ - lines = _removeLeadingBlankLines(inputString.split('\n')) - lines.reverse() - lines = _removeLeadingBlankLines(lines) - lines.reverse() - return '\n'.join(lines) + '\n' - - - -def addHTMLListings(document, dir): - """ - Insert HTML source listings into the given document from files in the given - directory based on C{html-listing} nodes. - - Any node in C{document} with a C{class} attribute set to C{html-listing} - will have source lines taken from the file named in that node's C{href} - attribute (searched for in C{dir}) inserted in place of that node. - - @type document: A DOM Node or Document - @param document: The document within which to make listing replacements. - - @type dir: C{str} - @param dir: The directory in which to find source files containing the - referenced HTML listings. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class", - "html-listing"): - filename = node.getAttribute("href") - val = ('
\n%s
' % - cgi.escape(open(os.path.join(dir, filename)).read())) - _replaceWithListing(node, val, filename, "html-listing") - - - -def addPlainListings(document, dir): - """ - Insert text listings into the given document from files in the given - directory based on C{listing} nodes. - - Any node in C{document} with a C{class} attribute set to C{listing} will - have source lines taken from the file named in that node's C{href} - attribute (searched for in C{dir}) inserted in place of that node. - - @type document: A DOM Node or Document - @param document: The document within which to make listing replacements. - - @type dir: C{str} - @param dir: The directory in which to find source files containing the - referenced text listings. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class", - "listing"): - filename = node.getAttribute("href") - val = ('
\n%s
' % - cgi.escape(open(os.path.join(dir, filename)).read())) - _replaceWithListing(node, val, filename, "listing") - - - -def getHeaders(document): - """ - Return all H2 and H3 nodes in the given document. - - @type document: A DOM Node or Document - - @rtype: C{list} - """ - return domhelpers.findElements( - document, - lambda n, m=re.compile('h[23]$').match: m(n.nodeName)) - - - -def generateToC(document): - """ - Create a table of contents for the given document. - - @type document: A DOM Node or Document - - @rtype: A DOM Node - @return: a Node containing a table of contents based on the headers of the - given document. - """ - subHeaders = None - headers = [] - for element in getHeaders(document): - if element.tagName == 'h2': - subHeaders = [] - headers.append((element, subHeaders)) - elif subHeaders is None: - raise ValueError( - "No H3 element is allowed until after an H2 element") - else: - subHeaders.append(element) - - auto = count().next - - def addItem(headerElement, parent): - anchor = dom.Element('a') - name = 'auto%d' % (auto(),) - anchor.setAttribute('href', '#' + name) - text = dom.Text() - text.data = domhelpers.getNodeText(headerElement) - anchor.appendChild(text) - headerNameItem = dom.Element('li') - headerNameItem.appendChild(anchor) - parent.appendChild(headerNameItem) - anchor = dom.Element('a') - anchor.setAttribute('name', name) - headerElement.appendChild(anchor) - - toc = dom.Element('ol') - for headerElement, subHeaders in headers: - addItem(headerElement, toc) - if subHeaders: - subtoc = dom.Element('ul') - toc.appendChild(subtoc) - for subHeaderElement in subHeaders: - addItem(subHeaderElement, subtoc) - - return toc - - - -def putInToC(document, toc): - """ - Insert the given table of contents into the given document. - - The node with C{class} attribute set to C{toc} has its children replaced - with C{toc}. - - @type document: A DOM Node or Document - @type toc: A DOM Node - """ - tocOrig = domhelpers.findElementsWithAttribute(document, 'class', 'toc') - if tocOrig: - tocOrig= tocOrig[0] - tocOrig.childNodes = [toc] - - - -def removeH1(document): - """ - Replace all C{h1} nodes in the given document with empty C{span} nodes. - - C{h1} nodes mark up document sections and the output template is given an - opportunity to present this information in a different way. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - h1 = domhelpers.findNodesNamed(document, 'h1') - empty = dom.Element('span') - for node in h1: - node.parentNode.replaceChild(empty, node) - - - -def footnotes(document): - """ - Find footnotes in the given document, move them to the end of the body, and - generate links to them. - - A footnote is any node with a C{class} attribute set to C{footnote}. - Footnote links are generated as superscript. Footnotes are collected in a - C{ol} node at the end of the document. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - footnotes = domhelpers.findElementsWithAttribute(document, "class", - "footnote") - if not footnotes: - return - footnoteElement = dom.Element('ol') - id = 1 - for footnote in footnotes: - href = dom.parseString('' - '%(id)d' - % vars()).documentElement - text = ' '.join(domhelpers.getNodeText(footnote).split()) - href.setAttribute('title', text) - target = dom.Element('a') - target.setAttribute('name', 'footnote-%d' % (id,)) - target.childNodes = [footnote] - footnoteContent = dom.Element('li') - footnoteContent.childNodes = [target] - footnoteElement.childNodes.append(footnoteContent) - footnote.parentNode.replaceChild(href, footnote) - id += 1 - body = domhelpers.findNodesNamed(document, "body")[0] - header = dom.parseString('

Footnotes

').documentElement - body.childNodes.append(header) - body.childNodes.append(footnoteElement) - - - -def notes(document): - """ - Find notes in the given document and mark them up as such. - - A note is any node with a C{class} attribute set to C{note}. - - (I think this is a very stupid feature. When I found it I actually - exclaimed out loud. -exarkun) - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - notes = domhelpers.findElementsWithAttribute(document, "class", "note") - notePrefix = dom.parseString('Note: ').documentElement - for note in notes: - note.childNodes.insert(0, notePrefix) - - - -def findNodeJustBefore(target, nodes): - """ - Find the last Element which is a sibling of C{target} and is in C{nodes}. - - @param target: A node the previous sibling of which to return. - @param nodes: A list of nodes which might be the right node. - - @return: The previous sibling of C{target}. - """ - while target is not None: - node = target.previousSibling - while node is not None: - if node in nodes: - return node - node = node.previousSibling - target = target.parentNode - raise RuntimeError("Oops") - - - -def getFirstAncestorWithSectionHeader(entry): - """ - Visit the ancestors of C{entry} until one with at least one C{h2} child - node is found, then return all of that node's C{h2} child nodes. - - @type entry: A DOM Node - @param entry: The node from which to begin traversal. This node itself is - excluded from consideration. - - @rtype: C{list} of DOM Nodes - @return: All C{h2} nodes of the ultimately selected parent node. - """ - for a in domhelpers.getParents(entry)[1:]: - headers = domhelpers.findNodesNamed(a, "h2") - if len(headers) > 0: - return headers - return [] - - - -def getSectionNumber(header): - """ - Retrieve the section number of the given node. - - This is probably intended to interact in a rather specific way with - L{numberDocument}. - - @type header: A DOM Node or L{None} - @param header: The section from which to extract a number. The section - number is the value of this node's first child. - - @return: C{None} or a C{str} giving the section number. - """ - if not header: - return None - return domhelpers.gatherTextNodes(header.childNodes[0]) - - - -def getSectionReference(entry): - """ - Find the section number which contains the given node. - - This function looks at the given node's ancestry until it finds a node - which defines a section, then returns that section's number. - - @type entry: A DOM Node - @param entry: The node for which to determine the section. - - @rtype: C{str} - @return: The section number, as returned by C{getSectionNumber} of the - first ancestor of C{entry} which defines a section, as determined by - L{getFirstAncestorWithSectionHeader}. - """ - headers = getFirstAncestorWithSectionHeader(entry) - myHeader = findNodeJustBefore(entry, headers) - return getSectionNumber(myHeader) - - - -def index(document, filename, chapterReference): - """ - Extract index entries from the given document and store them for later use - and insert named anchors so that the index can link back to those entries. - - Any node with a C{class} attribute set to C{index} is considered an index - entry. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type filename: C{str} - @param filename: A link to the output for the given document which will be - included in the index to link to any index entry found here. - - @type chapterReference: ??? - @param chapterReference: ??? - - @return: C{None} - """ - entries = domhelpers.findElementsWithAttribute(document, "class", "index") - if not entries: - return - i = 0; - for entry in entries: - i += 1 - anchor = 'index%02d' % i - if chapterReference: - ref = getSectionReference(entry) or chapterReference - else: - ref = 'link' - indexer.addEntry(filename, anchor, entry.getAttribute('value'), ref) - # does nodeName even affect anything? - entry.nodeName = entry.tagName = entry.endTagName = 'a' - for attrName in entry.attributes.keys(): - entry.removeAttribute(attrName) - entry.setAttribute('name', anchor) - - - -def setIndexLink(template, indexFilename): - """ - Insert a link to an index document. - - Any node with a C{class} attribute set to C{index-link} will have its tag - name changed to C{a} and its C{href} attribute set to C{indexFilename}. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type indexFilename: C{str} - @param indexFilename: The address of the index document to which to link. - If any C{False} value, this function will remove all index-link nodes. - - @return: C{None} - """ - indexLinks = domhelpers.findElementsWithAttribute(template, - "class", - "index-link") - for link in indexLinks: - if indexFilename is None: - link.parentNode.removeChild(link) - else: - link.nodeName = link.tagName = link.endTagName = 'a' - for attrName in link.attributes.keys(): - link.removeAttribute(attrName) - link.setAttribute('href', indexFilename) - - - -def numberDocument(document, chapterNumber): - """ - Number the sections of the given document. - - A dot-separated chapter, section number is added to the beginning of each - section, as defined by C{h2} nodes. - - This is probably intended to interact in a rather specific way with - L{getSectionNumber}. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type chapterNumber: C{int} - @param chapterNumber: The chapter number of this content in an overall - document. - - @return: C{None} - """ - i = 1 - for node in domhelpers.findNodesNamed(document, "h2"): - label = dom.Text() - label.data = "%s.%d " % (chapterNumber, i) - node.insertBefore(label, node.firstChild) - i += 1 - - - -def fixRelativeLinks(document, linkrel): - """ - Replace relative links in C{str} and C{href} attributes with links relative - to C{linkrel}. - - @type document: A DOM Node or Document - @param document: The output template. - - @type linkrel: C{str} - @param linkrel: An prefix to apply to all relative links in C{src} or - C{href} attributes in the input document when generating the output - document. - """ - for attr in 'src', 'href': - for node in domhelpers.findElementsWithAttribute(document, attr): - href = node.getAttribute(attr) - if not href.startswith('http') and not href.startswith('/'): - node.setAttribute(attr, linkrel+node.getAttribute(attr)) - - - -def setTitle(template, title, chapterNumber): - """ - Add title and chapter number information to the template document. - - The title is added to the end of the first C{title} tag and the end of the - first tag with a C{class} attribute set to C{title}. If specified, the - chapter is inserted before the title. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type title: C{list} of DOM Nodes - @param title: Nodes from the input document defining its title. - - @type chapterNumber: C{int} - @param chapterNumber: The chapter number of this content in an overall - document. If not applicable, any C{False} value will result in this - information being omitted. - - @return: C{None} - """ - if numberer.getNumberSections() and chapterNumber: - titleNode = dom.Text() - # This is necessary in order for cloning below to work. See Python - # isuse 4851. - titleNode.ownerDocument = template.ownerDocument - titleNode.data = '%s. ' % (chapterNumber,) - title.insert(0, titleNode) - - for nodeList in (domhelpers.findNodesNamed(template, "title"), - domhelpers.findElementsWithAttribute(template, "class", - 'title')): - if nodeList: - for titleNode in title: - nodeList[0].appendChild(titleNode.cloneNode(True)) - - - -def setAuthors(template, authors): - """ - Add author information to the template document. - - Names and contact information for authors are added to each node with a - C{class} attribute set to C{authors} and to the template head as C{link} - nodes. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type authors: C{list} of two-tuples of C{str} - @param authors: List of names and contact information for the authors of - the input document. - - @return: C{None} - """ - - for node in domhelpers.findElementsWithAttribute(template, - "class", 'authors'): - - # First, similarly to setTitle, insert text into an
- container = dom.Element('span') - for name, href in authors: - anchor = dom.Element('a') - anchor.setAttribute('href', href) - anchorText = dom.Text() - anchorText.data = name - anchor.appendChild(anchorText) - if (name, href) == authors[-1]: - if len(authors) == 1: - container.appendChild(anchor) - else: - andText = dom.Text() - andText.data = 'and ' - container.appendChild(andText) - container.appendChild(anchor) - else: - container.appendChild(anchor) - commaText = dom.Text() - commaText.data = ', ' - container.appendChild(commaText) - - node.appendChild(container) - - # Second, add appropriate tags to the . - head = domhelpers.findNodesNamed(template, 'head')[0] - authors = [dom.parseString('' - % (href, name)).childNodes[0] - for name, href in authors] - head.childNodes.extend(authors) - - - -def setVersion(template, version): - """ - Add a version indicator to the given template. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type version: C{str} - @param version: The version string to add to the template. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(template, "class", - "version"): - text = dom.Text() - text.data = version - node.appendChild(text) - - - -def getOutputFileName(originalFileName, outputExtension, index=None): - """ - Return a filename which is the same as C{originalFileName} except for the - extension, which is replaced with C{outputExtension}. - - For example, if C{originalFileName} is C{'/foo/bar.baz'} and - C{outputExtension} is C{'quux'}, the return value will be - C{'/foo/bar.quux'}. - - @type originalFileName: C{str} - @type outputExtension: C{stR} - @param index: ignored, never passed. - @rtype: C{str} - """ - return os.path.splitext(originalFileName)[0]+outputExtension - - - -def munge(document, template, linkrel, dir, fullpath, ext, url, config, outfileGenerator=getOutputFileName): - """ - Mutate C{template} until it resembles C{document}. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type template: A DOM Node or Document - @param template: The template document which defines the desired - presentation format of the content. - - @type linkrel: C{str} - @param linkrel: An prefix to apply to all relative links in C{src} or - C{href} attributes in the input document when generating the output - document. - - @type dir: C{str} - @param dir: The directory in which to search for source listing files. - - @type fullpath: C{str} - @param fullpath: The file name which contained the input document. - - @type ext: C{str} - @param ext: The extension to use when selecting an output file name. This - replaces the extension of the input file name. - - @type url: C{str} - @param url: A string which will be interpolated with the fully qualified - Python name of any API reference encountered in the input document, the - result of which will be used as a link to API documentation for that name - in the output document. - - @type config: C{dict} - @param config: Further specification of the desired form of the output. - Valid keys in this dictionary:: - - noapi: If present and set to a True value, links to API documentation - will not be generated. - - version: A string which will be included in the output to indicate the - version of this documentation. - - @type outfileGenerator: Callable of C{str}, C{str} returning C{str} - @param outfileGenerator: Output filename factory. This is invoked with the - intput filename and C{ext} and the output document is serialized to the - file with the name returned. - - @return: C{None} - """ - fixRelativeLinks(template, linkrel) - addMtime(template, fullpath) - removeH1(document) - if not config.get('noapi', False): - fixAPI(document, url) - fontifyPython(document) - fixLinks(document, ext) - addPyListings(document, dir) - addHTMLListings(document, dir) - addPlainListings(document, dir) - putInToC(template, generateToC(document)) - footnotes(document) - notes(document) - - setIndexLink(template, indexer.getIndexFilename()) - setVersion(template, config.get('version', '')) - - # Insert the document into the template - chapterNumber = htmlbook.getNumber(fullpath) - title = domhelpers.findNodesNamed(document, 'title')[0].childNodes - setTitle(template, title, chapterNumber) - if numberer.getNumberSections() and chapterNumber: - numberDocument(document, chapterNumber) - index(document, outfileGenerator(os.path.split(fullpath)[1], ext), - htmlbook.getReference(fullpath)) - - authors = domhelpers.findNodesNamed(document, 'link') - authors = [(node.getAttribute('title') or '', - node.getAttribute('href') or '') - for node in authors - if node.getAttribute('rel') == 'author'] - setAuthors(template, authors) - - body = domhelpers.findNodesNamed(document, "body")[0] - tmplbody = domhelpers.findElementsWithAttribute(template, "class", - "body")[0] - tmplbody.childNodes = body.childNodes - tmplbody.setAttribute("class", "content") - - -class _LocationReportingErrorHandler(ErrorHandler): - """ - Define a SAX error handler which can report the location of fatal - errors. - - Unlike the errors reported during parsing by other APIs in the xml - package, this one tries to mismatched tag errors by including the - location of both the relevant opening and closing tags. - """ - def __init__(self, contentHandler): - self.contentHandler = contentHandler - - def fatalError(self, err): - # Unfortunately, the underlying expat error code is only exposed as - # a string. I surely do hope no one ever goes and localizes expat. - if err.getMessage() == 'mismatched tag': - expect, begLine, begCol = self.contentHandler._locationStack[-1] - endLine, endCol = err.getLineNumber(), err.getColumnNumber() - raise process.ProcessingFailure( - "mismatched close tag at line %d, column %d; expected " - "(from line %d, column %d)" % ( - endLine, endCol, expect, begLine, begCol)) - raise process.ProcessingFailure( - '%s at line %d, column %d' % (err.getMessage(), - err.getLineNumber(), - err.getColumnNumber())) - - -class _TagTrackingContentHandler(SAX2DOM): - """ - Define a SAX content handler which keeps track of the start location of - all open tags. This information is used by the above defined error - handler to report useful locations when a fatal error is encountered. - """ - def __init__(self): - SAX2DOM.__init__(self) - self._locationStack = [] - - def setDocumentLocator(self, locator): - self._docLocator = locator - SAX2DOM.setDocumentLocator(self, locator) - - def startElement(self, name, attrs): - self._locationStack.append((name, self._docLocator.getLineNumber(), self._docLocator.getColumnNumber())) - SAX2DOM.startElement(self, name, attrs) - - def endElement(self, name): - self._locationStack.pop() - SAX2DOM.endElement(self, name) - - -class _LocalEntityResolver(object): - """ - Implement DTD loading (from a local source) for the limited number of - DTDs which are allowed for Lore input documents. - - @ivar filename: The name of the file containing the lore input - document. - - @ivar knownDTDs: A mapping from DTD system identifiers to L{FilePath} - instances pointing to the corresponding DTD. - """ - s = FilePath(__file__).sibling - - knownDTDs = { - None: s("xhtml1-strict.dtd"), - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd": s("xhtml1-strict.dtd"), - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd": s("xhtml1-transitional.dtd"), - "xhtml-lat1.ent": s("xhtml-lat1.ent"), - "xhtml-symbol.ent": s("xhtml-symbol.ent"), - "xhtml-special.ent": s("xhtml-special.ent"), - } - del s - - def __init__(self, filename): - self.filename = filename - - - def resolveEntity(self, publicId, systemId): - source = InputSource() - source.setSystemId(systemId) - try: - dtdPath = self.knownDTDs[systemId] - except KeyError: - raise process.ProcessingFailure( - "Invalid DTD system identifier (%r) in %s. Only " - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd " - "is allowed." % (systemId, self.filename)) - source.setByteStream(dtdPath.open()) - return source - - - -def parseFileAndReport(filename, _open=file): - """ - Parse and return the contents of the given lore XHTML document. - - @type filename: C{str} - @param filename: The name of a file containing a lore XHTML document to - load. - - @raise process.ProcessingFailure: When the contents of the specified file - cannot be parsed. - - @rtype: A DOM Document - @return: The document contained in C{filename}. - """ - content = _TagTrackingContentHandler() - error = _LocationReportingErrorHandler(content) - parser = make_parser() - parser.setContentHandler(content) - parser.setErrorHandler(error) - - # In order to call a method on the expat parser which will be used by this - # parser, we need the expat parser to be created. This doesn't happen - # until reset is called, normally by the parser's parse method. That's too - # late for us, since it will then go on to parse the document without - # letting us do any extra set up. So, force the expat parser to be created - # here, and then disable reset so that the parser created is the one - # actually used to parse our document. Resetting is only needed if more - # than one document is going to be parsed, and that isn't the case here. - parser.reset() - parser.reset = lambda: None - - # This is necessary to make the xhtml1 transitional declaration optional. - # It causes LocalEntityResolver.resolveEntity(None, None) to be called. - # LocalEntityResolver handles that case by giving out the xhtml1 - # transitional dtd. Unfortunately, there is no public API for manipulating - # the expat parser when using xml.sax. Using the private _parser attribute - # may break. It's also possible that make_parser will return a parser - # which doesn't use expat, but uses some other parser. Oh well. :( - # -exarkun - parser._parser.UseForeignDTD(True) - parser.setEntityResolver(_LocalEntityResolver(filename)) - - # This is probably no-op because expat is not a validating parser. Who - # knows though, maybe you figured out a way to not use expat. - parser.setFeature(feature_validation, False) - - fObj = _open(filename) - try: - try: - parser.parse(fObj) - except IOError, e: - raise process.ProcessingFailure( - e.strerror + ", filename was '" + filename + "'") - finally: - fObj.close() - return content.document - - -def makeSureDirectoryExists(filename): - filename = os.path.abspath(filename) - dirname = os.path.dirname(filename) - if (not os.path.exists(dirname)): - os.makedirs(dirname) - -def doFile(filename, linkrel, ext, url, templ, options={}, outfileGenerator=getOutputFileName): - """ - Process the input document at C{filename} and write an output document. - - @type filename: C{str} - @param filename: The path to the input file which will be processed. - - @type linkrel: C{str} - @param linkrel: An prefix to apply to all relative links in C{src} or - C{href} attributes in the input document when generating the output - document. - - @type ext: C{str} - @param ext: The extension to use when selecting an output file name. This - replaces the extension of the input file name. - - @type url: C{str} - @param url: A string which will be interpolated with the fully qualified - Python name of any API reference encountered in the input document, the - result of which will be used as a link to API documentation for that name - in the output document. - - @type templ: A DOM Node or Document - @param templ: The template on which the output document will be based. - This is mutated and then serialized to the output file. - - @type options: C{dict} - @param options: Further specification of the desired form of the output. - Valid keys in this dictionary:: - - noapi: If present and set to a True value, links to API documentation - will not be generated. - - version: A string which will be included in the output to indicate the - version of this documentation. - - @type outfileGenerator: Callable of C{str}, C{str} returning C{str} - @param outfileGenerator: Output filename factory. This is invoked with the - intput filename and C{ext} and the output document is serialized to the - file with the name returned. - - @return: C{None} - """ - doc = parseFileAndReport(filename) - clonedNode = templ.cloneNode(1) - munge(doc, clonedNode, linkrel, os.path.dirname(filename), filename, ext, - url, options, outfileGenerator) - newFilename = outfileGenerator(filename, ext) - _writeDocument(newFilename, clonedNode) - - - -def _writeDocument(newFilename, clonedNode): - """ - Serialize the given node to XML into the named file. - - @param newFilename: The name of the file to which the XML will be - written. If this is in a directory which does not exist, the - directory will be created. - - @param clonedNode: The root DOM node which will be serialized. - - @return: C{None} - """ - makeSureDirectoryExists(newFilename) - f = open(newFilename, 'w') - f.write(clonedNode.toxml('utf-8')) - f.close() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-lat1.ent b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-lat1.ent deleted file mode 100644 index ffee223..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-lat1.ent +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-special.ent b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-special.ent deleted file mode 100644 index ca358b2f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-special.ent +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-symbol.ent b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-symbol.ent deleted file mode 100644 index 63c2abf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml-symbol.ent +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml1-strict.dtd b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml1-strict.dtd deleted file mode 100644 index 2927b9e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml1-strict.dtd +++ /dev/null @@ -1,978 +0,0 @@ - - - - - -%HTMLlat1; - - -%HTMLsymbol; - - -%HTMLspecial; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml1-transitional.dtd b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml1-transitional.dtd deleted file mode 100644 index 628f27a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/lore/xhtml1-transitional.dtd +++ /dev/null @@ -1,1201 +0,0 @@ - - - - - -%HTMLlat1; - - -%HTMLsymbol; - - -%HTMLspecial; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/__init__.py deleted file mode 100644 index ae82bdc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Mail: Servers and clients for POP3, ESMTP, and IMAP. -""" - -from twisted.mail._version import version -__version__ = version.short() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/_version.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/_version.py deleted file mode 100644 index f5a2e83..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/_version.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This is an auto-generated file. Do not edit it. - -""" -Provides Twisted version information. -""" - -from twisted.python import versions -version = versions.Version('twisted.mail', 15, 2, 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/alias.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/alias.py deleted file mode 100644 index 50ba499..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/alias.py +++ /dev/null @@ -1,813 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support for aliases(5) configuration files. - -@author: Jp Calderone -""" - -import os -import tempfile - -from twisted.mail import smtp -from twisted.internet import reactor -from twisted.internet import protocol -from twisted.internet import defer -from twisted.python import failure -from twisted.python import log -from zope.interface import implements, Interface - - -def handle(result, line, filename, lineNo): - """ - Parse a line from an aliases file. - - @type result: L{dict} mapping L{bytes} to L{list} of L{bytes} - @param result: A dictionary mapping username to aliases to which - the results of parsing the line are added. - - @type line: L{bytes} - @param line: A line from an aliases file. - - @type filename: L{bytes} - @param filename: The full or relative path to the aliases file. - - @type lineNo: L{int} - @param lineNo: The position of the line within the aliases file. - """ - parts = [p.strip() for p in line.split(':', 1)] - if len(parts) != 2: - fmt = "Invalid format on line %d of alias file %s." - arg = (lineNo, filename) - log.err(fmt % arg) - else: - user, alias = parts - result.setdefault(user.strip(), []).extend(map(str.strip, alias.split(','))) - - - -def loadAliasFile(domains, filename=None, fp=None): - """ - Load a file containing email aliases. - - Lines in the file should be formatted like so:: - - username: alias1, alias2, ..., aliasN - - Aliases beginning with a C{|} will be treated as programs, will be run, and - the message will be written to their stdin. - - Aliases beginning with a C{:} will be treated as a file containing - additional aliases for the username. - - Aliases beginning with a C{/} will be treated as the full pathname to a file - to which the message will be appended. - - Aliases without a host part will be assumed to be addresses on localhost. - - If a username is specified multiple times, the aliases for each are joined - together as if they had all been on one line. - - Lines beginning with a space or a tab are continuations of the previous - line. - - Lines beginning with a C{#} are comments. - - @type domains: L{dict} mapping L{bytes} to L{IDomain} provider - @param domains: A mapping of domain name to domain object. - - @type filename: L{bytes} or L{NoneType } - @param filename: The full or relative path to a file from which to load - aliases. If omitted, the C{fp} parameter must be specified. - - @type fp: file-like object or L{NoneType } - @param fp: The file from which to load aliases. If specified, - the C{filename} parameter is ignored. - - @rtype: L{dict} mapping L{bytes} to L{AliasGroup} - @return: A mapping from username to group of aliases. - """ - result = {} - if fp is None: - fp = file(filename) - else: - filename = getattr(fp, 'name', '') - i = 0 - prev = '' - for line in fp: - i += 1 - line = line.rstrip() - if line.lstrip().startswith('#'): - continue - elif line.startswith(' ') or line.startswith('\t'): - prev = prev + line - else: - if prev: - handle(result, prev, filename, i) - prev = line - if prev: - handle(result, prev, filename, i) - for (u, a) in result.items(): - result[u] = AliasGroup(a, domains, u) - return result - - - -class IAlias(Interface): - """ - An interface for aliases. - """ - def createMessageReceiver(): - """ - Create a message receiver. - - @rtype: L{IMessage } provider - @return: A message receiver. - """ - - - -class AliasBase: - """ - The default base class for aliases. - - @ivar domains: See L{__init__}. - - @type original: L{Address} - @ivar original: The original address being aliased. - """ - def __init__(self, domains, original): - """ - @type domains: L{dict} mapping L{bytes} to L{IDomain} provider - @param domains: A mapping of domain name to domain object. - - @type original: L{bytes} - @param original: The original address being aliased. - """ - self.domains = domains - self.original = smtp.Address(original) - - - def domain(self): - """ - Return the domain associated with original address. - - @rtype: L{IDomain} provider - @return: The domain for the original address. - """ - return self.domains[self.original.domain] - - - def resolve(self, aliasmap, memo=None): - """ - Map this alias to its ultimate destination. - - @type aliasmap: L{dict} mapping L{bytes} to L{AliasBase} - @param aliasmap: A mapping of username to alias or group of aliases. - - @type memo: L{NoneType } or L{dict} of L{AliasBase} - @param memo: A record of the aliases already considered in the - resolution process. If provided, C{memo} is modified to include - this alias. - - @rtype: L{IMessage } or L{NoneType } - @return: A message receiver for the ultimate destination or None for - an invalid destination. - """ - if memo is None: - memo = {} - if str(self) in memo: - return None - memo[str(self)] = None - return self.createMessageReceiver() - - - -class AddressAlias(AliasBase): - """ - An alias which translates one email address into another. - - @type alias : L{Address} - @ivar alias: The destination address. - """ - implements(IAlias) - - def __init__(self, alias, *args): - """ - @type alias: L{Address}, L{User}, L{bytes} or object which can be - converted into L{bytes} - @param alias: The destination address. - - @type args: 2-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain} - provider, (1) L{bytes} - @param args: Arguments for L{AliasBase.__init__}. - """ - AliasBase.__init__(self, *args) - self.alias = smtp.Address(alias) - - - def __str__(self): - """ - Build a string representation of this L{AddressAlias} instance. - - @rtype: L{bytes} - @return: A string containing the destination address. - """ - return '
' % (self.alias,) - - - def createMessageReceiver(self): - """ - Create a message receiver which delivers a message to - the destination address. - - @rtype: L{IMessage } provider - @return: A message receiver. - """ - return self.domain().exists(str(self.alias)) - - - def resolve(self, aliasmap, memo=None): - """ - Map this alias to its ultimate destination. - - @type aliasmap: L{dict} mapping L{bytes} to L{AliasBase} - @param aliasmap: A mapping of username to alias or group of aliases. - - @type memo: L{NoneType } or L{dict} of L{AliasBase} - @param memo: A record of the aliases already considered in the - resolution process. If provided, C{memo} is modified to include - this alias. - - @rtype: L{IMessage } or L{NoneType } - @return: A message receiver for the ultimate destination or None for - an invalid destination. - """ - if memo is None: - memo = {} - if str(self) in memo: - return None - memo[str(self)] = None - try: - return self.domain().exists(smtp.User(self.alias, None, None, None), memo)() - except smtp.SMTPBadRcpt: - pass - if self.alias.local in aliasmap: - return aliasmap[self.alias.local].resolve(aliasmap, memo) - return None - - - -class FileWrapper: - """ - A message receiver which delivers a message to a file. - - @type fp: file-like object - @ivar fp: A file used for temporary storage of the message. - - @type finalname: L{bytes} - @ivar finalname: The name of the file in which the message should be - stored. - """ - implements(smtp.IMessage) - - def __init__(self, filename): - """ - @type filename: L{bytes} - @param filename: The name of the file in which the message should be - stored. - """ - self.fp = tempfile.TemporaryFile() - self.finalname = filename - - - def lineReceived(self, line): - """ - Write a received line to the temporary file. - - @type line: L{bytes} - @param line: A received line of the message. - """ - self.fp.write(line + '\n') - - - def eomReceived(self): - """ - Handle end of message by writing the message to the file. - - @rtype: L{Deferred } which successfully results in - L{bytes} - @return: A deferred which succeeds with the name of the file to which - the message has been stored or fails if the message cannot be - saved to the file. - """ - self.fp.seek(0, 0) - try: - f = file(self.finalname, 'a') - except: - return defer.fail(failure.Failure()) - - f.write(self.fp.read()) - self.fp.close() - f.close() - - return defer.succeed(self.finalname) - - - def connectionLost(self): - """ - Close the temporary file when the connection is lost. - """ - self.fp.close() - self.fp = None - - - def __str__(self): - """ - Build a string representation of this L{FileWrapper} instance. - - @rtype: L{bytes} - @return: A string containing the file name of the message. - """ - return '' % (self.finalname,) - - - -class FileAlias(AliasBase): - """ - An alias which translates an address to a file. - - @ivar filename: See L{__init__}. - """ - implements(IAlias) - - def __init__(self, filename, *args): - """ - @type filename: L{bytes} - @param filename: The name of the file in which to store the message. - - @type args: 2-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain} - provider, (1) L{bytes} - @param args: Arguments for L{AliasBase.__init__}. - """ - AliasBase.__init__(self, *args) - self.filename = filename - - - def __str__(self): - """ - Build a string representation of this L{FileAlias} instance. - - @rtype: L{bytes} - @return: A string containing the name of the file. - """ - return '' % (self.filename,) - - - def createMessageReceiver(self): - """ - Create a message receiver which delivers a message to the file. - - @rtype: L{FileWrapper} - @return: A message receiver which writes a message to the file. - """ - return FileWrapper(self.filename) - - - -class ProcessAliasTimeout(Exception): - """ - An error indicating that a timeout occurred while waiting for a process - to complete. - """ - - - -class MessageWrapper: - """ - A message receiver which delivers a message to a child process. - - @type completionTimeout: L{int} or L{float} - @ivar completionTimeout: The number of seconds to wait for the child - process to exit before reporting the delivery as a failure. - - @type _timeoutCallID: L{NoneType } or - L{IDelayedCall } provider - @ivar _timeoutCallID: The call used to time out delivery, started when the - connection to the child process is closed. - - @type done: L{bool} - @ivar done: A flag indicating whether the child process has exited - (C{True}) or not (C{False}). - - @type reactor: L{IReactorTime } - provider - @ivar reactor: A reactor which will be used to schedule timeouts. - - @ivar protocol: See L{__init__}. - - @type processName: L{bytes} or L{NoneType } - @ivar processName: The process name. - - @type completion: L{Deferred } - @ivar completion: The deferred which will be triggered by the protocol - when the child process exits. - """ - implements(smtp.IMessage) - - done = False - - completionTimeout = 60 - _timeoutCallID = None - - reactor = reactor - - def __init__(self, protocol, process=None, reactor=None): - """ - @type protocol: L{ProcessAliasProtocol} - @param protocol: The protocol associated with the child process. - - @type process: L{bytes} or L{NoneType } - @param process: The process name. - - @type reactor: L{NoneType } or L{IReactorTime - } provider - @param reactor: A reactor which will be used to schedule timeouts. - """ - self.processName = process - self.protocol = protocol - self.completion = defer.Deferred() - self.protocol.onEnd = self.completion - self.completion.addBoth(self._processEnded) - - if reactor is not None: - self.reactor = reactor - - - def _processEnded(self, result): - """ - Record process termination and cancel the timeout call if it is active. - - @type result: L{Failure } - @param result: The reason the child process terminated. - - @rtype: L{NoneType } or - L{Failure } - @return: None, if the process end is expected, or the reason the child - process terminated, if the process end is unexpected. - """ - self.done = True - if self._timeoutCallID is not None: - # eomReceived was called, we're actually waiting for the process to - # exit. - self._timeoutCallID.cancel() - self._timeoutCallID = None - else: - # eomReceived was not called, this is unexpected, propagate the - # error. - return result - - - def lineReceived(self, line): - """ - Write a received line to the child process. - - @type line: L{bytes} - @param line: A received line of the message. - """ - if self.done: - return - self.protocol.transport.write(line + '\n') - - - def eomReceived(self): - """ - Disconnect from the child process and set up a timeout to wait for it - to exit. - - @rtype: L{Deferred } - @return: A deferred which will be called back when the child process - exits. - """ - if not self.done: - self.protocol.transport.loseConnection() - self._timeoutCallID = self.reactor.callLater( - self.completionTimeout, self._completionCancel) - return self.completion - - - def _completionCancel(self): - """ - Handle the expiration of the timeout for the child process to exit by - terminating the child process forcefully and issuing a failure to the - L{completion} deferred. - """ - self._timeoutCallID = None - self.protocol.transport.signalProcess('KILL') - exc = ProcessAliasTimeout( - "No answer after %s seconds" % (self.completionTimeout,)) - self.protocol.onEnd = None - self.completion.errback(failure.Failure(exc)) - - - def connectionLost(self): - """ - Ignore notification of lost connection. - """ - - - def __str__(self): - """ - Build a string representation of this L{MessageWrapper} instance. - - @rtype: L{bytes} - @return: A string containing the name of the process. - """ - return '' % (self.processName,) - - - -class ProcessAliasProtocol(protocol.ProcessProtocol): - """ - A process protocol which errbacks a deferred when the associated - process ends. - - @type onEnd: L{NoneType } or L{Deferred } - @ivar onEnd: If set, a deferred on which to errback when the process ends. - """ - onEnd = None - - def processEnded(self, reason): - """ - Call an errback. - - @type reason: L{Failure } - @param reason: The reason the child process terminated. - """ - if self.onEnd is not None: - self.onEnd.errback(reason) - - - -class ProcessAlias(AliasBase): - """ - An alias which is handled by the execution of a program. - - @type path: L{list} of L{bytes} - @ivar path: The arguments to pass to the process. The first string is - the executable's name. - - @type program: L{bytes} - @ivar program: The path of the program to be executed. - - @type reactor: L{IReactorTime } - and L{IReactorProcess } - provider - @ivar reactor: A reactor which will be used to create and timeout the - child process. - """ - implements(IAlias) - - reactor = reactor - - def __init__(self, path, *args): - """ - @type path: L{bytes} - @param path: The command to invoke the program consisting of the path - to the executable followed by any arguments. - - @type args: 2-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain} - provider, (1) L{bytes} - @param args: Arguments for L{AliasBase.__init__}. - """ - - AliasBase.__init__(self, *args) - self.path = path.split() - self.program = self.path[0] - - - def __str__(self): - """ - Build a string representation of this L{ProcessAlias} instance. - - @rtype: L{bytes} - @return: A string containing the command used to invoke the process. - """ - return '' % (self.path,) - - - def spawnProcess(self, proto, program, path): - """ - Spawn a process. - - This wraps the L{spawnProcess - } method on - L{reactor} so that it can be customized for test purposes. - - @type proto: L{IProcessProtocol - } provider - @param proto: An object which will be notified of all events related to - the created process. - - @type program: L{bytes} - @param program: The full path name of the file to execute. - - @type path: L{list} of L{bytes} - @param path: The arguments to pass to the process. The first string - should be the executable's name. - - @rtype: L{IProcessTransport - } provider - @return: A process transport. - """ - return self.reactor.spawnProcess(proto, program, path) - - - def createMessageReceiver(self): - """ - Launch a process and create a message receiver to pass a message - to the process. - - @rtype: L{MessageWrapper} - @return: A message receiver which delivers a message to the process. - """ - p = ProcessAliasProtocol() - m = MessageWrapper(p, self.program, self.reactor) - self.spawnProcess(p, self.program, self.path) - return m - - - -class MultiWrapper: - """ - A message receiver which delivers a single message to multiple other - message receivers. - - @ivar objs: See L{__init__}. - """ - implements(smtp.IMessage) - - def __init__(self, objs): - """ - @type objs: L{list} of L{IMessage } provider - @param objs: Message receivers to which the incoming message should be - directed. - """ - self.objs = objs - - - def lineReceived(self, line): - """ - Pass a received line to the message receivers. - - @type line: L{bytes} - @param line: A line of the message. - """ - for o in self.objs: - o.lineReceived(line) - - - def eomReceived(self): - """ - Pass the end of message along to the message receivers. - - @rtype: L{DeferredList } whose successful results - are L{bytes} or L{NoneType } - @return: A deferred list which triggers when all of the message - receivers have finished handling their end of message. - """ - return defer.DeferredList([ - o.eomReceived() for o in self.objs - ]) - - - def connectionLost(self): - """ - Inform the message receivers that the connection has been lost. - """ - for o in self.objs: - o.connectionLost() - - - def __str__(self): - """ - Build a string representation of this L{MultiWrapper} instance. - - @rtype: L{bytes} - @return: A string containing a list of the message receivers. - """ - return '' % (map(str, self.objs),) - - - -class AliasGroup(AliasBase): - """ - An alias which points to multiple destination aliases. - - @type processAliasFactory: no-argument callable which returns - L{ProcessAlias} - @ivar processAliasFactory: A factory for process aliases. - - @type aliases: L{list} of L{AliasBase} which implements L{IAlias} - @ivar aliases: The destination aliases. - """ - implements(IAlias) - - processAliasFactory = ProcessAlias - - def __init__(self, items, *args): - """ - Create a group of aliases. - - Parse a list of alias strings and, for each, create an appropriate - alias object. - - @type items: L{list} of L{bytes} - @param items: Aliases. - - @type args: n-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain} - provider, (1) L{bytes} - @param args: Arguments for L{AliasBase.__init__}. - """ - - AliasBase.__init__(self, *args) - self.aliases = [] - while items: - addr = items.pop().strip() - if addr.startswith(':'): - try: - f = file(addr[1:]) - except: - log.err("Invalid filename in alias file %r" % (addr[1:],)) - else: - addr = ' '.join([l.strip() for l in f]) - items.extend(addr.split(',')) - elif addr.startswith('|'): - self.aliases.append(self.processAliasFactory(addr[1:], *args)) - elif addr.startswith('/'): - if os.path.isdir(addr): - log.err("Directory delivery not supported") - else: - self.aliases.append(FileAlias(addr, *args)) - else: - self.aliases.append(AddressAlias(addr, *args)) - - - def __len__(self): - """ - Return the number of aliases in the group. - - @rtype: L{int} - @return: The number of aliases in the group. - """ - return len(self.aliases) - - - def __str__(self): - """ - Build a string representation of this L{AliasGroup} instance. - - @rtype: L{bytes} - @return: A string containing the aliases in the group. - """ - return '' % (', '.join(map(str, self.aliases))) - - - def createMessageReceiver(self): - """ - Create a message receiver for each alias and return a message receiver - which will pass on a message to each of those. - - @rtype: L{MultiWrapper} - @return: A message receiver which passes a message on to message - receivers for each alias in the group. - """ - return MultiWrapper([a.createMessageReceiver() for a in self.aliases]) - - - def resolve(self, aliasmap, memo=None): - """ - Map each of the aliases in the group to its ultimate destination. - - @type aliasmap: L{dict} mapping L{bytes} to L{AliasBase} - @param aliasmap: A mapping of username to alias or group of aliases. - - @type memo: L{NoneType } or L{dict} of L{AliasBase} - @param memo: A record of the aliases already considered in the - resolution process. If provided, C{memo} is modified to include - this alias. - - @rtype: L{MultiWrapper} - @return: A message receiver which passes the message on to message - receivers for the ultimate destination of each alias in the group. - """ - if memo is None: - memo = {} - r = [] - for a in self.aliases: - r.append(a.resolve(aliasmap, memo)) - return MultiWrapper(filter(None, r)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/bounce.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/bounce.py deleted file mode 100644 index a65c39b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/bounce.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_bounce -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support for bounce message generation. -""" - -import StringIO -import rfc822 -import time -import os - - -from twisted.mail import smtp - -BOUNCE_FORMAT = """\ -From: postmaster@%(failedDomain)s -To: %(failedFrom)s -Subject: Returned Mail: see transcript for details -Message-ID: %(messageID)s -Content-Type: multipart/report; report-type=delivery-status; - boundary="%(boundary)s" - ---%(boundary)s - -%(transcript)s - ---%(boundary)s -Content-Type: message/delivery-status -Arrival-Date: %(ctime)s -Final-Recipient: RFC822; %(failedTo)s -""" - - - -def generateBounce(message, failedFrom, failedTo, transcript=''): - """ - Generate a bounce message for an undeliverable email message. - - @type message: L{bytes} - @param message: The undeliverable message. - - @type failedFrom: L{bytes} - @param failedFrom: The originator of the undeliverable message. - - @type failedTo: L{bytes} - @param failedTo: The destination of the undeliverable message. - - @type transcript: L{bytes} - @param transcript: An error message to include in the bounce message. - - @rtype: 3-L{tuple} of (E{1}) L{bytes}, (E{2}) L{bytes}, (E{3}) L{bytes} - @return: The originator, the destination and the contents of the bounce - message. The destination of the bounce message is the originator of - the undeliverable message. - """ - if not transcript: - transcript = '''\ -I'm sorry, the following address has permanent errors: %(failedTo)s. -I've given up, and I will not retry the message again. -''' % {'failedTo': failedTo} - - failedAddress = rfc822.AddressList(failedTo)[0][1] - data = { - 'boundary': "%s_%s_%s" % (time.time(), os.getpid(), 'XXXXX'), - 'ctime': time.ctime(time.time()), - 'failedAddress': failedAddress, - 'failedDomain': failedAddress.split('@', 1)[1], - 'failedFrom': failedFrom, - 'failedTo': failedTo, - 'messageID': smtp.messageid(uniq='bounce'), - 'message': message, - 'transcript': transcript, - } - - fp = StringIO.StringIO() - fp.write(BOUNCE_FORMAT % data) - orig = message.tell() - message.seek(2, 0) - sz = message.tell() - message.seek(0, orig) - if sz > 10000: - while 1: - line = message.readline() - if len(line)<=1: - break - fp.write(line) - else: - fp.write(message.read()) - return '', failedFrom, fp.getvalue() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/imap4.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/imap4.py deleted file mode 100644 index 7fba48d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/imap4.py +++ /dev/null @@ -1,6253 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_imap -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An IMAP4 protocol implementation - -@author: Jp Calderone - -To do:: - Suspend idle timeout while server is processing - Use an async message parser instead of buffering in memory - Figure out a way to not queue multi-message client requests (Flow? A simple callback?) - Clarify some API docs (Query, etc) - Make APPEND recognize (again) non-existent mailboxes before accepting the literal -""" - -import rfc822 -import base64 -import binascii -import hmac -import re -import copy -import tempfile -import string -import time -import random -import types - -import email.Utils - -try: - import cStringIO as StringIO -except: - import StringIO - -from zope.interface import implements, Interface - -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import defer -from twisted.internet import error -from twisted.internet.defer import maybeDeferred -from twisted.python import log, text -from twisted.internet import interfaces - -from twisted.cred import credentials -from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials - -# locale-independent month names to use instead of strftime's -_MONTH_NAMES = dict(zip( - range(1, 13), - "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split())) - - -class MessageSet(object): - """ - Essentially an infinite bitfield, with some extra features. - - @type getnext: Function taking C{int} returning C{int} - @ivar getnext: A function that returns the next message number, - used when iterating through the MessageSet. By default, a function - returning the next integer is supplied, but as this can be rather - inefficient for sparse UID iterations, it is recommended to supply - one when messages are requested by UID. The argument is provided - as a hint to the implementation and may be ignored if it makes sense - to do so (eg, if an iterator is being used that maintains its own - state, it is guaranteed that it will not be called out-of-order). - """ - _empty = [] - - def __init__(self, start=_empty, end=_empty): - """ - Create a new MessageSet() - - @type start: Optional C{int} - @param start: Start of range, or only message number - - @type end: Optional C{int} - @param end: End of range. - """ - self._last = self._empty # Last message/UID in use - self.ranges = [] # List of ranges included - self.getnext = lambda x: x+1 # A function which will return the next - # message id. Handy for UID requests. - - if start is self._empty: - return - - if isinstance(start, types.ListType): - self.ranges = start[:] - self.clean() - else: - self.add(start,end) - - # Ooo. A property. - def last(): - def _setLast(self, value): - if self._last is not self._empty: - raise ValueError("last already set") - - self._last = value - for i, (l, h) in enumerate(self.ranges): - if l is not None: - break # There are no more Nones after this - l = value - if h is None: - h = value - if l > h: - l, h = h, l - self.ranges[i] = (l, h) - - self.clean() - - def _getLast(self): - return self._last - - doc = ''' - "Highest" message number, referred to by "*". - Must be set before attempting to use the MessageSet. - ''' - return _getLast, _setLast, None, doc - last = property(*last()) - - def add(self, start, end=_empty): - """ - Add another range - - @type start: C{int} - @param start: Start of range, or only message number - - @type end: Optional C{int} - @param end: End of range. - """ - if end is self._empty: - end = start - - if self._last is not self._empty: - if start is None: - start = self.last - if end is None: - end = self.last - - if start > end: - # Try to keep in low, high order if possible - # (But we don't know what None means, this will keep - # None at the start of the ranges list) - start, end = end, start - - self.ranges.append((start, end)) - self.clean() - - def __add__(self, other): - if isinstance(other, MessageSet): - ranges = self.ranges + other.ranges - return MessageSet(ranges) - else: - res = MessageSet(self.ranges) - try: - res.add(*other) - except TypeError: - res.add(other) - return res - - - def extend(self, other): - if isinstance(other, MessageSet): - self.ranges.extend(other.ranges) - self.clean() - else: - try: - self.add(*other) - except TypeError: - self.add(other) - - return self - - - def clean(self): - """ - Clean ranges list, combining adjacent ranges - """ - - self.ranges.sort() - - oldl, oldh = None, None - for i,(l, h) in enumerate(self.ranges): - if l is None: - continue - # l is >= oldl and h is >= oldh due to sort() - if oldl is not None and l <= oldh + 1: - l = oldl - h = max(oldh, h) - self.ranges[i - 1] = None - self.ranges[i] = (l, h) - - oldl, oldh = l, h - - self.ranges = filter(None, self.ranges) - - - def __contains__(self, value): - """ - May raise TypeError if we encounter an open-ended range - """ - for l, h in self.ranges: - if l is None: - raise TypeError( - "Can't determine membership; last value not set") - if l <= value <= h: - return True - - return False - - - def _iterator(self): - for l, h in self.ranges: - l = self.getnext(l-1) - while l <= h: - yield l - l = self.getnext(l) - if l is None: - break - - def __iter__(self): - if self.ranges and self.ranges[0][0] is None: - raise TypeError("Can't iterate; last value not set") - - return self._iterator() - - def __len__(self): - res = 0 - for l, h in self.ranges: - if l is None: - if h is None: - res += 1 - else: - raise TypeError("Can't size object; last value not set") - else: - res += (h - l) + 1 - - return res - - def __str__(self): - p = [] - for low, high in self.ranges: - if low == high: - if low is None: - p.append('*') - else: - p.append(str(low)) - elif low is None: - p.append('%d:*' % (high,)) - else: - p.append('%d:%d' % (low, high)) - return ','.join(p) - - def __repr__(self): - return '' % (str(self),) - - def __eq__(self, other): - if isinstance(other, MessageSet): - return self.ranges == other.ranges - return False - - -class LiteralString: - def __init__(self, size, defered): - self.size = size - self.data = [] - self.defer = defered - - def write(self, data): - self.size -= len(data) - passon = None - if self.size > 0: - self.data.append(data) - else: - if self.size: - data, passon = data[:self.size], data[self.size:] - else: - passon = '' - if data: - self.data.append(data) - return passon - - def callback(self, line): - """ - Call deferred with data and rest of line - """ - self.defer.callback((''.join(self.data), line)) - -class LiteralFile: - _memoryFileLimit = 1024 * 1024 * 10 - - def __init__(self, size, defered): - self.size = size - self.defer = defered - if size > self._memoryFileLimit: - self.data = tempfile.TemporaryFile() - else: - self.data = StringIO.StringIO() - - def write(self, data): - self.size -= len(data) - passon = None - if self.size > 0: - self.data.write(data) - else: - if self.size: - data, passon = data[:self.size], data[self.size:] - else: - passon = '' - if data: - self.data.write(data) - return passon - - def callback(self, line): - """ - Call deferred with data and rest of line - """ - self.data.seek(0,0) - self.defer.callback((self.data, line)) - - -class WriteBuffer: - """Buffer up a bunch of writes before sending them all to a transport at once. - """ - def __init__(self, transport, size=8192): - self.bufferSize = size - self.transport = transport - self._length = 0 - self._writes = [] - - def write(self, s): - self._length += len(s) - self._writes.append(s) - if self._length > self.bufferSize: - self.flush() - - def flush(self): - if self._writes: - self.transport.writeSequence(self._writes) - self._writes = [] - self._length = 0 - - -class Command: - _1_RESPONSES = ('CAPABILITY', 'FLAGS', 'LIST', 'LSUB', 'STATUS', 'SEARCH', 'NAMESPACE') - _2_RESPONSES = ('EXISTS', 'EXPUNGE', 'FETCH', 'RECENT') - _OK_RESPONSES = ('UIDVALIDITY', 'UNSEEN', 'READ-WRITE', 'READ-ONLY', 'UIDNEXT', 'PERMANENTFLAGS') - defer = None - - def __init__(self, command, args=None, wantResponse=(), - continuation=None, *contArgs, **contKw): - self.command = command - self.args = args - self.wantResponse = wantResponse - self.continuation = lambda x: continuation(x, *contArgs, **contKw) - self.lines = [] - - def format(self, tag): - if self.args is None: - return ' '.join((tag, self.command)) - return ' '.join((tag, self.command, self.args)) - - def finish(self, lastLine, unusedCallback): - send = [] - unuse = [] - for L in self.lines: - names = parseNestedParens(L) - N = len(names) - if (N >= 1 and names[0] in self._1_RESPONSES or - N >= 2 and names[1] in self._2_RESPONSES or - N >= 2 and names[0] == 'OK' and isinstance(names[1], types.ListType) and names[1][0] in self._OK_RESPONSES): - send.append(names) - else: - unuse.append(names) - d, self.defer = self.defer, None - d.callback((send, lastLine)) - if unuse: - unusedCallback(unuse) - -class LOGINCredentials(credentials.UsernamePassword): - def __init__(self): - self.challenges = ['Password\0', 'User Name\0'] - self.responses = ['password', 'username'] - credentials.UsernamePassword.__init__(self, None, None) - - def getChallenge(self): - return self.challenges.pop() - - def setResponse(self, response): - setattr(self, self.responses.pop(), response) - - def moreChallenges(self): - return bool(self.challenges) - -class PLAINCredentials(credentials.UsernamePassword): - def __init__(self): - credentials.UsernamePassword.__init__(self, None, None) - - def getChallenge(self): - return '' - - def setResponse(self, response): - parts = response.split('\0') - if len(parts) != 3: - raise IllegalClientResponse("Malformed Response - wrong number of parts") - useless, self.username, self.password = parts - - def moreChallenges(self): - return False - -class IMAP4Exception(Exception): - def __init__(self, *args): - Exception.__init__(self, *args) - -class IllegalClientResponse(IMAP4Exception): pass - -class IllegalOperation(IMAP4Exception): pass - -class IllegalMailboxEncoding(IMAP4Exception): pass - -class IMailboxListener(Interface): - """Interface for objects interested in mailbox events""" - - def modeChanged(writeable): - """Indicates that the write status of a mailbox has changed. - - @type writeable: C{bool} - @param writeable: A true value if write is now allowed, false - otherwise. - """ - - def flagsChanged(newFlags): - """Indicates that the flags of one or more messages have changed. - - @type newFlags: C{dict} - @param newFlags: A mapping of message identifiers to tuples of flags - now set on that message. - """ - - def newMessages(exists, recent): - """Indicates that the number of messages in a mailbox has changed. - - @type exists: C{int} or C{None} - @param exists: The total number of messages now in this mailbox. - If the total number of messages has not changed, this should be - C{None}. - - @type recent: C{int} - @param recent: The number of messages now flagged \\Recent. - If the number of recent messages has not changed, this should be - C{None}. - """ - -# Some constants to help define what an atom is and is not - see the grammar -# section of the IMAP4 RFC - . -# Some definitions (SP, CTL, DQUOTE) are also from the ABNF RFC - -# . -_SP = ' ' -_CTL = ''.join(chr(ch) for ch in range(0x21) + range(0x80, 0x100)) - -# It is easier to define ATOM-CHAR in terms of what it does not match than in -# terms of what it does match. -_nonAtomChars = r'(){%*"\]' + _SP + _CTL - -# This is all the bytes that match the ATOM-CHAR from the grammar in the RFC. -_atomChars = ''.join(chr(ch) for ch in range(0x100) if chr(ch) not in _nonAtomChars) - -class IMAP4Server(basic.LineReceiver, policies.TimeoutMixin): - """ - Protocol implementation for an IMAP4rev1 server. - - The server can be in any of four states: - - Non-authenticated - - Authenticated - - Selected - - Logout - """ - implements(IMailboxListener) - - # Identifier for this server software - IDENT = 'Twisted IMAP4rev1 Ready' - - # Number of seconds before idle timeout - # Initially 1 minute. Raised to 30 minutes after login. - timeOut = 60 - - POSTAUTH_TIMEOUT = 60 * 30 - - # Whether STARTTLS has been issued successfully yet or not. - startedTLS = False - - # Whether our transport supports TLS - canStartTLS = False - - # Mapping of tags to commands we have received - tags = None - - # The object which will handle logins for us - portal = None - - # The account object for this connection - account = None - - # Logout callback - _onLogout = None - - # The currently selected mailbox - mbox = None - - # Command data to be processed when literal data is received - _pendingLiteral = None - - # Maximum length to accept for a "short" string literal - _literalStringLimit = 4096 - - # IChallengeResponse factories for AUTHENTICATE command - challengers = None - - # Search terms the implementation of which needs to be passed both the last - # message identifier (UID) and the last sequence id. - _requiresLastMessageInfo = set(["OR", "NOT", "UID"]) - - state = 'unauth' - - parseState = 'command' - - def __init__(self, chal = None, contextFactory = None, scheduler = None): - if chal is None: - chal = {} - self.challengers = chal - self.ctx = contextFactory - if scheduler is None: - scheduler = iterateInReactor - self._scheduler = scheduler - self._queuedAsync = [] - - def capabilities(self): - cap = {'AUTH': self.challengers.keys()} - if self.ctx and self.canStartTLS: - if not self.startedTLS and interfaces.ISSLTransport(self.transport, None) is None: - cap['LOGINDISABLED'] = None - cap['STARTTLS'] = None - cap['NAMESPACE'] = None - cap['IDLE'] = None - return cap - - def connectionMade(self): - self.tags = {} - self.canStartTLS = interfaces.ITLSTransport(self.transport, None) is not None - self.setTimeout(self.timeOut) - self.sendServerGreeting() - - def connectionLost(self, reason): - self.setTimeout(None) - if self._onLogout: - self._onLogout() - self._onLogout = None - - def timeoutConnection(self): - self.sendLine('* BYE Autologout; connection idle too long') - self.transport.loseConnection() - if self.mbox: - self.mbox.removeListener(self) - cmbx = ICloseableMailbox(self.mbox, None) - if cmbx is not None: - maybeDeferred(cmbx.close).addErrback(log.err) - self.mbox = None - self.state = 'timeout' - - def rawDataReceived(self, data): - self.resetTimeout() - passon = self._pendingLiteral.write(data) - if passon is not None: - self.setLineMode(passon) - - # Avoid processing commands while buffers are being dumped to - # our transport - blocked = None - - def _unblock(self): - commands = self.blocked - self.blocked = None - while commands and self.blocked is None: - self.lineReceived(commands.pop(0)) - if self.blocked is not None: - self.blocked.extend(commands) - - def lineReceived(self, line): - if self.blocked is not None: - self.blocked.append(line) - return - - self.resetTimeout() - - f = getattr(self, 'parse_' + self.parseState) - try: - f(line) - except Exception, e: - self.sendUntaggedResponse('BAD Server error: ' + str(e)) - log.err() - - def parse_command(self, line): - args = line.split(None, 2) - rest = None - if len(args) == 3: - tag, cmd, rest = args - elif len(args) == 2: - tag, cmd = args - elif len(args) == 1: - tag = args[0] - self.sendBadResponse(tag, 'Missing command') - return None - else: - self.sendBadResponse(None, 'Null command') - return None - - cmd = cmd.upper() - try: - return self.dispatchCommand(tag, cmd, rest) - except IllegalClientResponse, e: - self.sendBadResponse(tag, 'Illegal syntax: ' + str(e)) - except IllegalOperation, e: - self.sendNegativeResponse(tag, 'Illegal operation: ' + str(e)) - except IllegalMailboxEncoding, e: - self.sendNegativeResponse(tag, 'Illegal mailbox name: ' + str(e)) - - def parse_pending(self, line): - d = self._pendingLiteral - self._pendingLiteral = None - self.parseState = 'command' - d.callback(line) - - def dispatchCommand(self, tag, cmd, rest, uid=None): - f = self.lookupCommand(cmd) - if f: - fn = f[0] - parseargs = f[1:] - self.__doCommand(tag, fn, [self, tag], parseargs, rest, uid) - else: - self.sendBadResponse(tag, 'Unsupported command') - - def lookupCommand(self, cmd): - return getattr(self, '_'.join((self.state, cmd.upper())), None) - - def __doCommand(self, tag, handler, args, parseargs, line, uid): - for (i, arg) in enumerate(parseargs): - if callable(arg): - parseargs = parseargs[i+1:] - maybeDeferred(arg, self, line).addCallback( - self.__cbDispatch, tag, handler, args, - parseargs, uid).addErrback(self.__ebDispatch, tag) - return - else: - args.append(arg) - - if line: - # Too many arguments - raise IllegalClientResponse("Too many arguments for command: " + repr(line)) - - if uid is not None: - handler(uid=uid, *args) - else: - handler(*args) - - def __cbDispatch(self, (arg, rest), tag, fn, args, parseargs, uid): - args.append(arg) - self.__doCommand(tag, fn, args, parseargs, rest, uid) - - def __ebDispatch(self, failure, tag): - if failure.check(IllegalClientResponse): - self.sendBadResponse(tag, 'Illegal syntax: ' + str(failure.value)) - elif failure.check(IllegalOperation): - self.sendNegativeResponse(tag, 'Illegal operation: ' + - str(failure.value)) - elif failure.check(IllegalMailboxEncoding): - self.sendNegativeResponse(tag, 'Illegal mailbox name: ' + - str(failure.value)) - else: - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - log.err(failure) - - def _stringLiteral(self, size): - if size > self._literalStringLimit: - raise IllegalClientResponse( - "Literal too long! I accept at most %d octets" % - (self._literalStringLimit,)) - d = defer.Deferred() - self.parseState = 'pending' - self._pendingLiteral = LiteralString(size, d) - self.sendContinuationRequest('Ready for %d octets of text' % size) - self.setRawMode() - return d - - def _fileLiteral(self, size): - d = defer.Deferred() - self.parseState = 'pending' - self._pendingLiteral = LiteralFile(size, d) - self.sendContinuationRequest('Ready for %d octets of data' % size) - self.setRawMode() - return d - - def arg_astring(self, line): - """ - Parse an astring from the line, return (arg, rest), possibly - via a deferred (to handle literals) - """ - line = line.strip() - if not line: - raise IllegalClientResponse("Missing argument") - d = None - arg, rest = None, None - if line[0] == '"': - try: - spam, arg, rest = line.split('"',2) - rest = rest[1:] # Strip space - except ValueError: - raise IllegalClientResponse("Unmatched quotes") - elif line[0] == '{': - # literal - if line[-1] != '}': - raise IllegalClientResponse("Malformed literal") - try: - size = int(line[1:-1]) - except ValueError: - raise IllegalClientResponse("Bad literal size: " + line[1:-1]) - d = self._stringLiteral(size) - else: - arg = line.split(' ',1) - if len(arg) == 1: - arg.append('') - arg, rest = arg - return d or (arg, rest) - - # ATOM: Any CHAR except ( ) { % * " \ ] CTL SP (CHAR is 7bit) - atomre = re.compile(r'(?P[%s]+)( (?P.*$)|$)' % (re.escape(_atomChars),)) - - def arg_atom(self, line): - """ - Parse an atom from the line - """ - if not line: - raise IllegalClientResponse("Missing argument") - m = self.atomre.match(line) - if m: - return m.group('atom'), m.group('rest') - else: - raise IllegalClientResponse("Malformed ATOM") - - def arg_plist(self, line): - """ - Parse a (non-nested) parenthesised list from the line - """ - if not line: - raise IllegalClientResponse("Missing argument") - - if line[0] != "(": - raise IllegalClientResponse("Missing parenthesis") - - i = line.find(")") - - if i == -1: - raise IllegalClientResponse("Mismatched parenthesis") - - return (parseNestedParens(line[1:i],0), line[i+2:]) - - def arg_literal(self, line): - """ - Parse a literal from the line - """ - if not line: - raise IllegalClientResponse("Missing argument") - - if line[0] != '{': - raise IllegalClientResponse("Missing literal") - - if line[-1] != '}': - raise IllegalClientResponse("Malformed literal") - - try: - size = int(line[1:-1]) - except ValueError: - raise IllegalClientResponse("Bad literal size: " + line[1:-1]) - - return self._fileLiteral(size) - - def arg_searchkeys(self, line): - """ - searchkeys - """ - query = parseNestedParens(line) - # XXX Should really use list of search terms and parse into - # a proper tree - - return (query, '') - - def arg_seqset(self, line): - """ - sequence-set - """ - rest = '' - arg = line.split(' ',1) - if len(arg) == 2: - rest = arg[1] - arg = arg[0] - - try: - return (parseIdList(arg), rest) - except IllegalIdentifierError, e: - raise IllegalClientResponse("Bad message number " + str(e)) - - def arg_fetchatt(self, line): - """ - fetch-att - """ - p = _FetchParser() - p.parseString(line) - return (p.result, '') - - def arg_flaglist(self, line): - """ - Flag part of store-att-flag - """ - flags = [] - if line[0] == '(': - if line[-1] != ')': - raise IllegalClientResponse("Mismatched parenthesis") - line = line[1:-1] - - while line: - m = self.atomre.search(line) - if not m: - raise IllegalClientResponse("Malformed flag") - if line[0] == '\\' and m.start() == 1: - flags.append('\\' + m.group('atom')) - elif m.start() == 0: - flags.append(m.group('atom')) - else: - raise IllegalClientResponse("Malformed flag") - line = m.group('rest') - - return (flags, '') - - def arg_line(self, line): - """ - Command line of UID command - """ - return (line, '') - - def opt_plist(self, line): - """ - Optional parenthesised list - """ - if line.startswith('('): - return self.arg_plist(line) - else: - return (None, line) - - def opt_datetime(self, line): - """ - Optional date-time string - """ - if line.startswith('"'): - try: - spam, date, rest = line.split('"',2) - except IndexError: - raise IllegalClientResponse("Malformed date-time") - return (date, rest[1:]) - else: - return (None, line) - - def opt_charset(self, line): - """ - Optional charset of SEARCH command - """ - if line[:7].upper() == 'CHARSET': - arg = line.split(' ',2) - if len(arg) == 1: - raise IllegalClientResponse("Missing charset identifier") - if len(arg) == 2: - arg.append('') - spam, arg, rest = arg - return (arg, rest) - else: - return (None, line) - - def sendServerGreeting(self): - msg = '[CAPABILITY %s] %s' % (' '.join(self.listCapabilities()), self.IDENT) - self.sendPositiveResponse(message=msg) - - def sendBadResponse(self, tag = None, message = ''): - self._respond('BAD', tag, message) - - def sendPositiveResponse(self, tag = None, message = ''): - self._respond('OK', tag, message) - - def sendNegativeResponse(self, tag = None, message = ''): - self._respond('NO', tag, message) - - def sendUntaggedResponse(self, message, async=False): - if not async or (self.blocked is None): - self._respond(message, None, None) - else: - self._queuedAsync.append(message) - - def sendContinuationRequest(self, msg = 'Ready for additional command text'): - if msg: - self.sendLine('+ ' + msg) - else: - self.sendLine('+') - - def _respond(self, state, tag, message): - if state in ('OK', 'NO', 'BAD') and self._queuedAsync: - lines = self._queuedAsync - self._queuedAsync = [] - for msg in lines: - self._respond(msg, None, None) - if not tag: - tag = '*' - if message: - self.sendLine(' '.join((tag, state, message))) - else: - self.sendLine(' '.join((tag, state))) - - def listCapabilities(self): - caps = ['IMAP4rev1'] - for c, v in self.capabilities().iteritems(): - if v is None: - caps.append(c) - elif len(v): - caps.extend([('%s=%s' % (c, cap)) for cap in v]) - return caps - - def do_CAPABILITY(self, tag): - self.sendUntaggedResponse('CAPABILITY ' + ' '.join(self.listCapabilities())) - self.sendPositiveResponse(tag, 'CAPABILITY completed') - - unauth_CAPABILITY = (do_CAPABILITY,) - auth_CAPABILITY = unauth_CAPABILITY - select_CAPABILITY = unauth_CAPABILITY - logout_CAPABILITY = unauth_CAPABILITY - - def do_LOGOUT(self, tag): - self.sendUntaggedResponse('BYE Nice talking to you') - self.sendPositiveResponse(tag, 'LOGOUT successful') - self.transport.loseConnection() - - unauth_LOGOUT = (do_LOGOUT,) - auth_LOGOUT = unauth_LOGOUT - select_LOGOUT = unauth_LOGOUT - logout_LOGOUT = unauth_LOGOUT - - def do_NOOP(self, tag): - self.sendPositiveResponse(tag, 'NOOP No operation performed') - - unauth_NOOP = (do_NOOP,) - auth_NOOP = unauth_NOOP - select_NOOP = unauth_NOOP - logout_NOOP = unauth_NOOP - - def do_AUTHENTICATE(self, tag, args): - args = args.upper().strip() - if args not in self.challengers: - self.sendNegativeResponse(tag, 'AUTHENTICATE method unsupported') - else: - self.authenticate(self.challengers[args](), tag) - - unauth_AUTHENTICATE = (do_AUTHENTICATE, arg_atom) - - def authenticate(self, chal, tag): - if self.portal is None: - self.sendNegativeResponse(tag, 'Temporary authentication failure') - return - - self._setupChallenge(chal, tag) - - def _setupChallenge(self, chal, tag): - try: - challenge = chal.getChallenge() - except Exception, e: - self.sendBadResponse(tag, 'Server error: ' + str(e)) - else: - coded = base64.encodestring(challenge)[:-1] - self.parseState = 'pending' - self._pendingLiteral = defer.Deferred() - self.sendContinuationRequest(coded) - self._pendingLiteral.addCallback(self.__cbAuthChunk, chal, tag) - self._pendingLiteral.addErrback(self.__ebAuthChunk, tag) - - def __cbAuthChunk(self, result, chal, tag): - try: - uncoded = base64.decodestring(result) - except binascii.Error: - raise IllegalClientResponse("Malformed Response - not base64") - - chal.setResponse(uncoded) - if chal.moreChallenges(): - self._setupChallenge(chal, tag) - else: - self.portal.login(chal, None, IAccount).addCallbacks( - self.__cbAuthResp, - self.__ebAuthResp, - (tag,), None, (tag,), None - ) - - def __cbAuthResp(self, (iface, avatar, logout), tag): - assert iface is IAccount, "IAccount is the only supported interface" - self.account = avatar - self.state = 'auth' - self._onLogout = logout - self.sendPositiveResponse(tag, 'Authentication successful') - self.setTimeout(self.POSTAUTH_TIMEOUT) - - def __ebAuthResp(self, failure, tag): - if failure.check(UnauthorizedLogin): - self.sendNegativeResponse(tag, 'Authentication failed: unauthorized') - elif failure.check(UnhandledCredentials): - self.sendNegativeResponse(tag, 'Authentication failed: server misconfigured') - else: - self.sendBadResponse(tag, 'Server error: login failed unexpectedly') - log.err(failure) - - def __ebAuthChunk(self, failure, tag): - self.sendNegativeResponse(tag, 'Authentication failed: ' + str(failure.value)) - - def do_STARTTLS(self, tag): - if self.startedTLS: - self.sendNegativeResponse(tag, 'TLS already negotiated') - elif self.ctx and self.canStartTLS: - self.sendPositiveResponse(tag, 'Begin TLS negotiation now') - self.transport.startTLS(self.ctx) - self.startedTLS = True - self.challengers = self.challengers.copy() - if 'LOGIN' not in self.challengers: - self.challengers['LOGIN'] = LOGINCredentials - if 'PLAIN' not in self.challengers: - self.challengers['PLAIN'] = PLAINCredentials - else: - self.sendNegativeResponse(tag, 'TLS not available') - - unauth_STARTTLS = (do_STARTTLS,) - - def do_LOGIN(self, tag, user, passwd): - if 'LOGINDISABLED' in self.capabilities(): - self.sendBadResponse(tag, 'LOGIN is disabled before STARTTLS') - return - - maybeDeferred(self.authenticateLogin, user, passwd - ).addCallback(self.__cbLogin, tag - ).addErrback(self.__ebLogin, tag - ) - - unauth_LOGIN = (do_LOGIN, arg_astring, arg_astring) - - def authenticateLogin(self, user, passwd): - """Lookup the account associated with the given parameters - - Override this method to define the desired authentication behavior. - - The default behavior is to defer authentication to C{self.portal} - if it is not None, or to deny the login otherwise. - - @type user: C{str} - @param user: The username to lookup - - @type passwd: C{str} - @param passwd: The password to login with - """ - if self.portal: - return self.portal.login( - credentials.UsernamePassword(user, passwd), - None, IAccount - ) - raise UnauthorizedLogin() - - def __cbLogin(self, (iface, avatar, logout), tag): - if iface is not IAccount: - self.sendBadResponse(tag, 'Server error: login returned unexpected value') - log.err("__cbLogin called with %r, IAccount expected" % (iface,)) - else: - self.account = avatar - self._onLogout = logout - self.sendPositiveResponse(tag, 'LOGIN succeeded') - self.state = 'auth' - self.setTimeout(self.POSTAUTH_TIMEOUT) - - def __ebLogin(self, failure, tag): - if failure.check(UnauthorizedLogin): - self.sendNegativeResponse(tag, 'LOGIN failed') - else: - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - log.err(failure) - - def do_NAMESPACE(self, tag): - personal = public = shared = None - np = INamespacePresenter(self.account, None) - if np is not None: - personal = np.getPersonalNamespaces() - public = np.getSharedNamespaces() - shared = np.getSharedNamespaces() - self.sendUntaggedResponse('NAMESPACE ' + collapseNestedLists([personal, public, shared])) - self.sendPositiveResponse(tag, "NAMESPACE command completed") - - auth_NAMESPACE = (do_NAMESPACE,) - select_NAMESPACE = auth_NAMESPACE - - def _parseMbox(self, name): - if isinstance(name, unicode): - return name - try: - return name.decode('imap4-utf-7') - except: - log.err() - raise IllegalMailboxEncoding(name) - - def _selectWork(self, tag, name, rw, cmdName): - if self.mbox: - self.mbox.removeListener(self) - cmbx = ICloseableMailbox(self.mbox, None) - if cmbx is not None: - maybeDeferred(cmbx.close).addErrback(log.err) - self.mbox = None - self.state = 'auth' - - name = self._parseMbox(name) - maybeDeferred(self.account.select, self._parseMbox(name), rw - ).addCallback(self._cbSelectWork, cmdName, tag - ).addErrback(self._ebSelectWork, cmdName, tag - ) - - def _ebSelectWork(self, failure, cmdName, tag): - self.sendBadResponse(tag, "%s failed: Server error" % (cmdName,)) - log.err(failure) - - def _cbSelectWork(self, mbox, cmdName, tag): - if mbox is None: - self.sendNegativeResponse(tag, 'No such mailbox') - return - if '\\noselect' in [s.lower() for s in mbox.getFlags()]: - self.sendNegativeResponse(tag, 'Mailbox cannot be selected') - return - - flags = mbox.getFlags() - self.sendUntaggedResponse(str(mbox.getMessageCount()) + ' EXISTS') - self.sendUntaggedResponse(str(mbox.getRecentCount()) + ' RECENT') - self.sendUntaggedResponse('FLAGS (%s)' % ' '.join(flags)) - self.sendPositiveResponse(None, '[UIDVALIDITY %d]' % mbox.getUIDValidity()) - - s = mbox.isWriteable() and 'READ-WRITE' or 'READ-ONLY' - mbox.addListener(self) - self.sendPositiveResponse(tag, '[%s] %s successful' % (s, cmdName)) - self.state = 'select' - self.mbox = mbox - - auth_SELECT = ( _selectWork, arg_astring, 1, 'SELECT' ) - select_SELECT = auth_SELECT - - auth_EXAMINE = ( _selectWork, arg_astring, 0, 'EXAMINE' ) - select_EXAMINE = auth_EXAMINE - - - def do_IDLE(self, tag): - self.sendContinuationRequest(None) - self.parseTag = tag - self.lastState = self.parseState - self.parseState = 'idle' - - def parse_idle(self, *args): - self.parseState = self.lastState - del self.lastState - self.sendPositiveResponse(self.parseTag, "IDLE terminated") - del self.parseTag - - select_IDLE = ( do_IDLE, ) - auth_IDLE = select_IDLE - - - def do_CREATE(self, tag, name): - name = self._parseMbox(name) - try: - result = self.account.create(name) - except MailboxException, c: - self.sendNegativeResponse(tag, str(c)) - except: - self.sendBadResponse(tag, "Server error encountered while creating mailbox") - log.err() - else: - if result: - self.sendPositiveResponse(tag, 'Mailbox created') - else: - self.sendNegativeResponse(tag, 'Mailbox not created') - - auth_CREATE = (do_CREATE, arg_astring) - select_CREATE = auth_CREATE - - def do_DELETE(self, tag, name): - name = self._parseMbox(name) - if name.lower() == 'inbox': - self.sendNegativeResponse(tag, 'You cannot delete the inbox') - return - try: - self.account.delete(name) - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while deleting mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Mailbox deleted') - - auth_DELETE = (do_DELETE, arg_astring) - select_DELETE = auth_DELETE - - def do_RENAME(self, tag, oldname, newname): - oldname, newname = [self._parseMbox(n) for n in oldname, newname] - if oldname.lower() == 'inbox' or newname.lower() == 'inbox': - self.sendNegativeResponse(tag, 'You cannot rename the inbox, or rename another mailbox to inbox.') - return - try: - self.account.rename(oldname, newname) - except TypeError: - self.sendBadResponse(tag, 'Invalid command syntax') - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while renaming mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Mailbox renamed') - - auth_RENAME = (do_RENAME, arg_astring, arg_astring) - select_RENAME = auth_RENAME - - def do_SUBSCRIBE(self, tag, name): - name = self._parseMbox(name) - try: - self.account.subscribe(name) - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while subscribing to mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Subscribed') - - auth_SUBSCRIBE = (do_SUBSCRIBE, arg_astring) - select_SUBSCRIBE = auth_SUBSCRIBE - - def do_UNSUBSCRIBE(self, tag, name): - name = self._parseMbox(name) - try: - self.account.unsubscribe(name) - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while unsubscribing from mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Unsubscribed') - - auth_UNSUBSCRIBE = (do_UNSUBSCRIBE, arg_astring) - select_UNSUBSCRIBE = auth_UNSUBSCRIBE - - def _listWork(self, tag, ref, mbox, sub, cmdName): - mbox = self._parseMbox(mbox) - maybeDeferred(self.account.listMailboxes, ref, mbox - ).addCallback(self._cbListWork, tag, sub, cmdName - ).addErrback(self._ebListWork, tag - ) - - def _cbListWork(self, mailboxes, tag, sub, cmdName): - for (name, box) in mailboxes: - if not sub or self.account.isSubscribed(name): - flags = box.getFlags() - delim = box.getHierarchicalDelimiter() - resp = (DontQuoteMe(cmdName), map(DontQuoteMe, flags), delim, name.encode('imap4-utf-7')) - self.sendUntaggedResponse(collapseNestedLists(resp)) - self.sendPositiveResponse(tag, '%s completed' % (cmdName,)) - - def _ebListWork(self, failure, tag): - self.sendBadResponse(tag, "Server error encountered while listing mailboxes.") - log.err(failure) - - auth_LIST = (_listWork, arg_astring, arg_astring, 0, 'LIST') - select_LIST = auth_LIST - - auth_LSUB = (_listWork, arg_astring, arg_astring, 1, 'LSUB') - select_LSUB = auth_LSUB - - def do_STATUS(self, tag, mailbox, names): - mailbox = self._parseMbox(mailbox) - maybeDeferred(self.account.select, mailbox, 0 - ).addCallback(self._cbStatusGotMailbox, tag, mailbox, names - ).addErrback(self._ebStatusGotMailbox, tag - ) - - def _cbStatusGotMailbox(self, mbox, tag, mailbox, names): - if mbox: - maybeDeferred(mbox.requestStatus, names).addCallbacks( - self.__cbStatus, self.__ebStatus, - (tag, mailbox), None, (tag, mailbox), None - ) - else: - self.sendNegativeResponse(tag, "Could not open mailbox") - - def _ebStatusGotMailbox(self, failure, tag): - self.sendBadResponse(tag, "Server error encountered while opening mailbox.") - log.err(failure) - - auth_STATUS = (do_STATUS, arg_astring, arg_plist) - select_STATUS = auth_STATUS - - def __cbStatus(self, status, tag, box): - line = ' '.join(['%s %s' % x for x in status.iteritems()]) - self.sendUntaggedResponse('STATUS %s (%s)' % (box, line)) - self.sendPositiveResponse(tag, 'STATUS complete') - - def __ebStatus(self, failure, tag, box): - self.sendBadResponse(tag, 'STATUS %s failed: %s' % (box, str(failure.value))) - - def do_APPEND(self, tag, mailbox, flags, date, message): - mailbox = self._parseMbox(mailbox) - maybeDeferred(self.account.select, mailbox - ).addCallback(self._cbAppendGotMailbox, tag, flags, date, message - ).addErrback(self._ebAppendGotMailbox, tag - ) - - def _cbAppendGotMailbox(self, mbox, tag, flags, date, message): - if not mbox: - self.sendNegativeResponse(tag, '[TRYCREATE] No such mailbox') - return - - d = mbox.addMessage(message, flags, date) - d.addCallback(self.__cbAppend, tag, mbox) - d.addErrback(self.__ebAppend, tag) - - def _ebAppendGotMailbox(self, failure, tag): - self.sendBadResponse(tag, "Server error encountered while opening mailbox.") - log.err(failure) - - auth_APPEND = (do_APPEND, arg_astring, opt_plist, opt_datetime, - arg_literal) - select_APPEND = auth_APPEND - - def __cbAppend(self, result, tag, mbox): - self.sendUntaggedResponse('%d EXISTS' % mbox.getMessageCount()) - self.sendPositiveResponse(tag, 'APPEND complete') - - def __ebAppend(self, failure, tag): - self.sendBadResponse(tag, 'APPEND failed: ' + str(failure.value)) - - def do_CHECK(self, tag): - d = self.checkpoint() - if d is None: - self.__cbCheck(None, tag) - else: - d.addCallbacks( - self.__cbCheck, - self.__ebCheck, - callbackArgs=(tag,), - errbackArgs=(tag,) - ) - select_CHECK = (do_CHECK,) - - def __cbCheck(self, result, tag): - self.sendPositiveResponse(tag, 'CHECK completed') - - def __ebCheck(self, failure, tag): - self.sendBadResponse(tag, 'CHECK failed: ' + str(failure.value)) - - def checkpoint(self): - """Called when the client issues a CHECK command. - - This should perform any checkpoint operations required by the server. - It may be a long running operation, but may not block. If it returns - a deferred, the client will only be informed of success (or failure) - when the deferred's callback (or errback) is invoked. - """ - return None - - def do_CLOSE(self, tag): - d = None - if self.mbox.isWriteable(): - d = maybeDeferred(self.mbox.expunge) - cmbx = ICloseableMailbox(self.mbox, None) - if cmbx is not None: - if d is not None: - d.addCallback(lambda result: cmbx.close()) - else: - d = maybeDeferred(cmbx.close) - if d is not None: - d.addCallbacks(self.__cbClose, self.__ebClose, (tag,), None, (tag,), None) - else: - self.__cbClose(None, tag) - - select_CLOSE = (do_CLOSE,) - - def __cbClose(self, result, tag): - self.sendPositiveResponse(tag, 'CLOSE completed') - self.mbox.removeListener(self) - self.mbox = None - self.state = 'auth' - - def __ebClose(self, failure, tag): - self.sendBadResponse(tag, 'CLOSE failed: ' + str(failure.value)) - - def do_EXPUNGE(self, tag): - if self.mbox.isWriteable(): - maybeDeferred(self.mbox.expunge).addCallbacks( - self.__cbExpunge, self.__ebExpunge, (tag,), None, (tag,), None - ) - else: - self.sendNegativeResponse(tag, 'EXPUNGE ignored on read-only mailbox') - - select_EXPUNGE = (do_EXPUNGE,) - - def __cbExpunge(self, result, tag): - for e in result: - self.sendUntaggedResponse('%d EXPUNGE' % e) - self.sendPositiveResponse(tag, 'EXPUNGE completed') - - def __ebExpunge(self, failure, tag): - self.sendBadResponse(tag, 'EXPUNGE failed: ' + str(failure.value)) - log.err(failure) - - def do_SEARCH(self, tag, charset, query, uid=0): - sm = ISearchableMailbox(self.mbox, None) - if sm is not None: - maybeDeferred(sm.search, query, uid=uid - ).addCallback(self.__cbSearch, tag, self.mbox, uid - ).addErrback(self.__ebSearch, tag) - else: - # that's not the ideal way to get all messages, there should be a - # method on mailboxes that gives you all of them - s = parseIdList('1:*') - maybeDeferred(self.mbox.fetch, s, uid=uid - ).addCallback(self.__cbManualSearch, - tag, self.mbox, query, uid - ).addErrback(self.__ebSearch, tag) - - - select_SEARCH = (do_SEARCH, opt_charset, arg_searchkeys) - - def __cbSearch(self, result, tag, mbox, uid): - if uid: - result = map(mbox.getUID, result) - ids = ' '.join([str(i) for i in result]) - self.sendUntaggedResponse('SEARCH ' + ids) - self.sendPositiveResponse(tag, 'SEARCH completed') - - - def __cbManualSearch(self, result, tag, mbox, query, uid, - searchResults=None): - """ - Apply the search filter to a set of messages. Send the response to the - client. - - @type result: C{list} of C{tuple} of (C{int}, provider of - L{imap4.IMessage}) - @param result: A list two tuples of messages with their sequence ids, - sorted by the ids in descending order. - - @type tag: C{str} - @param tag: A command tag. - - @type mbox: Provider of L{imap4.IMailbox} - @param mbox: The searched mailbox. - - @type query: C{list} - @param query: A list representing the parsed form of the search query. - - @param uid: A flag indicating whether the search is over message - sequence numbers or UIDs. - - @type searchResults: C{list} - @param searchResults: The search results so far or C{None} if no - results yet. - """ - if searchResults is None: - searchResults = [] - i = 0 - - # result is a list of tuples (sequenceId, Message) - lastSequenceId = result and result[-1][0] - lastMessageId = result and result[-1][1].getUID() - - for (i, (id, msg)) in zip(range(5), result): - # searchFilter and singleSearchStep will mutate the query. Dang. - # Copy it here or else things will go poorly for subsequent - # messages. - if self._searchFilter(copy.deepcopy(query), id, msg, - lastSequenceId, lastMessageId): - if uid: - searchResults.append(str(msg.getUID())) - else: - searchResults.append(str(id)) - if i == 4: - from twisted.internet import reactor - reactor.callLater( - 0, self.__cbManualSearch, result[5:], tag, mbox, query, uid, - searchResults) - else: - if searchResults: - self.sendUntaggedResponse('SEARCH ' + ' '.join(searchResults)) - self.sendPositiveResponse(tag, 'SEARCH completed') - - - def _searchFilter(self, query, id, msg, lastSequenceId, lastMessageId): - """ - Pop search terms from the beginning of C{query} until there are none - left and apply them to the given message. - - @param query: A list representing the parsed form of the search query. - - @param id: The sequence number of the message being checked. - - @param msg: The message being checked. - - @type lastSequenceId: C{int} - @param lastSequenceId: The highest sequence number of any message in - the mailbox being searched. - - @type lastMessageId: C{int} - @param lastMessageId: The highest UID of any message in the mailbox - being searched. - - @return: Boolean indicating whether all of the query terms match the - message. - """ - while query: - if not self._singleSearchStep(query, id, msg, - lastSequenceId, lastMessageId): - return False - return True - - - def _singleSearchStep(self, query, id, msg, lastSequenceId, lastMessageId): - """ - Pop one search term from the beginning of C{query} (possibly more than - one element) and return whether it matches the given message. - - @param query: A list representing the parsed form of the search query. - - @param id: The sequence number of the message being checked. - - @param msg: The message being checked. - - @param lastSequenceId: The highest sequence number of any message in - the mailbox being searched. - - @param lastMessageId: The highest UID of any message in the mailbox - being searched. - - @return: Boolean indicating whether the query term matched the message. - """ - - q = query.pop(0) - if isinstance(q, list): - if not self._searchFilter(q, id, msg, - lastSequenceId, lastMessageId): - return False - else: - c = q.upper() - if not c[:1].isalpha(): - # A search term may be a word like ALL, ANSWERED, BCC, etc (see - # below) or it may be a message sequence set. Here we - # recognize a message sequence set "N:M". - messageSet = parseIdList(c, lastSequenceId) - return id in messageSet - else: - f = getattr(self, 'search_' + c, None) - if f is None: - raise IllegalQueryError("Invalid search command %s" % c) - - if c in self._requiresLastMessageInfo: - result = f(query, id, msg, (lastSequenceId, - lastMessageId)) - else: - result = f(query, id, msg) - - if not result: - return False - return True - - def search_ALL(self, query, id, msg): - """ - Returns C{True} if the message matches the ALL search key (always). - - @type query: A C{list} of C{str} - @param query: A list representing the parsed query string. - - @type id: C{int} - @param id: The sequence number of the message being checked. - - @type msg: Provider of L{imap4.IMessage} - """ - return True - - def search_ANSWERED(self, query, id, msg): - """ - Returns C{True} if the message has been answered. - - @type query: A C{list} of C{str} - @param query: A list representing the parsed query string. - - @type id: C{int} - @param id: The sequence number of the message being checked. - - @type msg: Provider of L{imap4.IMessage} - """ - return '\\Answered' in msg.getFlags() - - def search_BCC(self, query, id, msg): - """ - Returns C{True} if the message has a BCC address matching the query. - - @type query: A C{list} of C{str} - @param query: A list whose first element is a BCC C{str} - - @type id: C{int} - @param id: The sequence number of the message being checked. - - @type msg: Provider of L{imap4.IMessage} - """ - bcc = msg.getHeaders(False, 'bcc').get('bcc', '') - return bcc.lower().find(query.pop(0).lower()) != -1 - - def search_BEFORE(self, query, id, msg): - date = parseTime(query.pop(0)) - return rfc822.parsedate(msg.getInternalDate()) < date - - def search_BODY(self, query, id, msg): - body = query.pop(0).lower() - return text.strFile(body, msg.getBodyFile(), False) - - def search_CC(self, query, id, msg): - cc = msg.getHeaders(False, 'cc').get('cc', '') - return cc.lower().find(query.pop(0).lower()) != -1 - - def search_DELETED(self, query, id, msg): - return '\\Deleted' in msg.getFlags() - - def search_DRAFT(self, query, id, msg): - return '\\Draft' in msg.getFlags() - - def search_FLAGGED(self, query, id, msg): - return '\\Flagged' in msg.getFlags() - - def search_FROM(self, query, id, msg): - fm = msg.getHeaders(False, 'from').get('from', '') - return fm.lower().find(query.pop(0).lower()) != -1 - - def search_HEADER(self, query, id, msg): - hdr = query.pop(0).lower() - hdr = msg.getHeaders(False, hdr).get(hdr, '') - return hdr.lower().find(query.pop(0).lower()) != -1 - - def search_KEYWORD(self, query, id, msg): - query.pop(0) - return False - - def search_LARGER(self, query, id, msg): - return int(query.pop(0)) < msg.getSize() - - def search_NEW(self, query, id, msg): - return '\\Recent' in msg.getFlags() and '\\Seen' not in msg.getFlags() - - def search_NOT(self, query, id, msg, (lastSequenceId, lastMessageId)): - """ - Returns C{True} if the message does not match the query. - - @type query: A C{list} of C{str} - @param query: A list representing the parsed form of the search query. - - @type id: C{int} - @param id: The sequence number of the message being checked. - - @type msg: Provider of L{imap4.IMessage} - @param msg: The message being checked. - - @type lastSequenceId: C{int} - @param lastSequenceId: The highest sequence number of a message in the - mailbox. - - @type lastMessageId: C{int} - @param lastMessageId: The highest UID of a message in the mailbox. - """ - return not self._singleSearchStep(query, id, msg, - lastSequenceId, lastMessageId) - - def search_OLD(self, query, id, msg): - return '\\Recent' not in msg.getFlags() - - def search_ON(self, query, id, msg): - date = parseTime(query.pop(0)) - return rfc822.parsedate(msg.getInternalDate()) == date - - def search_OR(self, query, id, msg, (lastSequenceId, lastMessageId)): - """ - Returns C{True} if the message matches any of the first two query - items. - - @type query: A C{list} of C{str} - @param query: A list representing the parsed form of the search query. - - @type id: C{int} - @param id: The sequence number of the message being checked. - - @type msg: Provider of L{imap4.IMessage} - @param msg: The message being checked. - - @type lastSequenceId: C{int} - @param lastSequenceId: The highest sequence number of a message in the - mailbox. - - @type lastMessageId: C{int} - @param lastMessageId: The highest UID of a message in the mailbox. - """ - a = self._singleSearchStep(query, id, msg, - lastSequenceId, lastMessageId) - b = self._singleSearchStep(query, id, msg, - lastSequenceId, lastMessageId) - return a or b - - def search_RECENT(self, query, id, msg): - return '\\Recent' in msg.getFlags() - - def search_SEEN(self, query, id, msg): - return '\\Seen' in msg.getFlags() - - def search_SENTBEFORE(self, query, id, msg): - """ - Returns C{True} if the message date is earlier than the query date. - - @type query: A C{list} of C{str} - @param query: A list whose first element starts with a stringified date - that is a fragment of an L{imap4.Query()}. The date must be in the - format 'DD-Mon-YYYY', for example '03-March-2003' or '03-Mar-2003'. - - @type id: C{int} - @param id: The sequence number of the message being checked. - - @type msg: Provider of L{imap4.IMessage} - """ - date = msg.getHeaders(False, 'date').get('date', '') - date = rfc822.parsedate(date) - return date < parseTime(query.pop(0)) - - def search_SENTON(self, query, id, msg): - """ - Returns C{True} if the message date is the same as the query date. - - @type query: A C{list} of C{str} - @param query: A list whose first element starts with a stringified date - that is a fragment of an L{imap4.Query()}. The date must be in the - format 'DD-Mon-YYYY', for example '03-March-2003' or '03-Mar-2003'. - - @type msg: Provider of L{imap4.IMessage} - """ - date = msg.getHeaders(False, 'date').get('date', '') - date = rfc822.parsedate(date) - return date[:3] == parseTime(query.pop(0))[:3] - - def search_SENTSINCE(self, query, id, msg): - """ - Returns C{True} if the message date is later than the query date. - - @type query: A C{list} of C{str} - @param query: A list whose first element starts with a stringified date - that is a fragment of an L{imap4.Query()}. The date must be in the - format 'DD-Mon-YYYY', for example '03-March-2003' or '03-Mar-2003'. - - @type msg: Provider of L{imap4.IMessage} - """ - date = msg.getHeaders(False, 'date').get('date', '') - date = rfc822.parsedate(date) - return date > parseTime(query.pop(0)) - - def search_SINCE(self, query, id, msg): - date = parseTime(query.pop(0)) - return rfc822.parsedate(msg.getInternalDate()) > date - - def search_SMALLER(self, query, id, msg): - return int(query.pop(0)) > msg.getSize() - - def search_SUBJECT(self, query, id, msg): - subj = msg.getHeaders(False, 'subject').get('subject', '') - return subj.lower().find(query.pop(0).lower()) != -1 - - def search_TEXT(self, query, id, msg): - # XXX - This must search headers too - body = query.pop(0).lower() - return text.strFile(body, msg.getBodyFile(), False) - - def search_TO(self, query, id, msg): - to = msg.getHeaders(False, 'to').get('to', '') - return to.lower().find(query.pop(0).lower()) != -1 - - def search_UID(self, query, id, msg, (lastSequenceId, lastMessageId)): - """ - Returns C{True} if the message UID is in the range defined by the - search query. - - @type query: A C{list} of C{str} - @param query: A list representing the parsed form of the search - query. Its first element should be a C{str} that can be interpreted - as a sequence range, for example '2:4,5:*'. - - @type id: C{int} - @param id: The sequence number of the message being checked. - - @type msg: Provider of L{imap4.IMessage} - @param msg: The message being checked. - - @type lastSequenceId: C{int} - @param lastSequenceId: The highest sequence number of a message in the - mailbox. - - @type lastMessageId: C{int} - @param lastMessageId: The highest UID of a message in the mailbox. - """ - c = query.pop(0) - m = parseIdList(c, lastMessageId) - return msg.getUID() in m - - def search_UNANSWERED(self, query, id, msg): - return '\\Answered' not in msg.getFlags() - - def search_UNDELETED(self, query, id, msg): - return '\\Deleted' not in msg.getFlags() - - def search_UNDRAFT(self, query, id, msg): - return '\\Draft' not in msg.getFlags() - - def search_UNFLAGGED(self, query, id, msg): - return '\\Flagged' not in msg.getFlags() - - def search_UNKEYWORD(self, query, id, msg): - query.pop(0) - return False - - def search_UNSEEN(self, query, id, msg): - return '\\Seen' not in msg.getFlags() - - def __ebSearch(self, failure, tag): - self.sendBadResponse(tag, 'SEARCH failed: ' + str(failure.value)) - log.err(failure) - - def do_FETCH(self, tag, messages, query, uid=0): - if query: - self._oldTimeout = self.setTimeout(None) - maybeDeferred(self.mbox.fetch, messages, uid=uid - ).addCallback(iter - ).addCallback(self.__cbFetch, tag, query, uid - ).addErrback(self.__ebFetch, tag - ) - else: - self.sendPositiveResponse(tag, 'FETCH complete') - - select_FETCH = (do_FETCH, arg_seqset, arg_fetchatt) - - def __cbFetch(self, results, tag, query, uid): - if self.blocked is None: - self.blocked = [] - try: - id, msg = results.next() - except StopIteration: - # The idle timeout was suspended while we delivered results, - # restore it now. - self.setTimeout(self._oldTimeout) - del self._oldTimeout - - # All results have been processed, deliver completion notification. - - # It's important to run this *after* resetting the timeout to "rig - # a race" in some test code. writing to the transport will - # synchronously call test code, which synchronously loses the - # connection, calling our connectionLost method, which cancels the - # timeout. We want to make sure that timeout is cancelled *after* - # we reset it above, so that the final state is no timed - # calls. This avoids reactor uncleanliness errors in the test - # suite. - # XXX: Perhaps loopback should be fixed to not call the user code - # synchronously in transport.write? - self.sendPositiveResponse(tag, 'FETCH completed') - - # Instance state is now consistent again (ie, it is as though - # the fetch command never ran), so allow any pending blocked - # commands to execute. - self._unblock() - else: - self.spewMessage(id, msg, query, uid - ).addCallback(lambda _: self.__cbFetch(results, tag, query, uid) - ).addErrback(self.__ebSpewMessage - ) - - def __ebSpewMessage(self, failure): - # This indicates a programming error. - # There's no reliable way to indicate anything to the client, since we - # may have already written an arbitrary amount of data in response to - # the command. - log.err(failure) - self.transport.loseConnection() - - def spew_envelope(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('ENVELOPE ' + collapseNestedLists([getEnvelope(msg)])) - - def spew_flags(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('FLAGS ' + '(%s)' % (' '.join(msg.getFlags()))) - - def spew_internaldate(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - idate = msg.getInternalDate() - ttup = rfc822.parsedate_tz(idate) - if ttup is None: - log.msg("%d:%r: unpareseable internaldate: %r" % (id, msg, idate)) - raise IMAP4Exception("Internal failure generating INTERNALDATE") - - # need to specify the month manually, as strftime depends on locale - strdate = time.strftime("%d-%%s-%Y %H:%M:%S ", ttup[:9]) - odate = strdate % (_MONTH_NAMES[ttup[1]],) - if ttup[9] is None: - odate = odate + "+0000" - else: - if ttup[9] >= 0: - sign = "+" - else: - sign = "-" - odate = odate + sign + str(((abs(ttup[9]) // 3600) * 100 + (abs(ttup[9]) % 3600) // 60)).zfill(4) - _w('INTERNALDATE ' + _quote(odate)) - - def spew_rfc822header(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - hdrs = _formatHeaders(msg.getHeaders(True)) - _w('RFC822.HEADER ' + _literal(hdrs)) - - def spew_rfc822text(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('RFC822.TEXT ') - _f() - return FileProducer(msg.getBodyFile() - ).beginProducing(self.transport - ) - - def spew_rfc822size(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('RFC822.SIZE ' + str(msg.getSize())) - - def spew_rfc822(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('RFC822 ') - _f() - mf = IMessageFile(msg, None) - if mf is not None: - return FileProducer(mf.open() - ).beginProducing(self.transport - ) - return MessageProducer(msg, None, self._scheduler - ).beginProducing(self.transport - ) - - def spew_uid(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('UID ' + str(msg.getUID())) - - def spew_bodystructure(self, id, msg, _w=None, _f=None): - _w('BODYSTRUCTURE ' + collapseNestedLists([getBodyStructure(msg, True)])) - - def spew_body(self, part, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - for p in part.part: - if msg.isMultipart(): - msg = msg.getSubPart(p) - elif p > 0: - # Non-multipart messages have an implicit first part but no - # other parts - reject any request for any other part. - raise TypeError("Requested subpart of non-multipart message") - - if part.header: - hdrs = msg.getHeaders(part.header.negate, *part.header.fields) - hdrs = _formatHeaders(hdrs) - _w(str(part) + ' ' + _literal(hdrs)) - elif part.text: - _w(str(part) + ' ') - _f() - return FileProducer(msg.getBodyFile() - ).beginProducing(self.transport - ) - elif part.mime: - hdrs = _formatHeaders(msg.getHeaders(True)) - _w(str(part) + ' ' + _literal(hdrs)) - elif part.empty: - _w(str(part) + ' ') - _f() - if part.part: - return FileProducer(msg.getBodyFile() - ).beginProducing(self.transport - ) - else: - mf = IMessageFile(msg, None) - if mf is not None: - return FileProducer(mf.open()).beginProducing(self.transport) - return MessageProducer(msg, None, self._scheduler).beginProducing(self.transport) - - else: - _w('BODY ' + collapseNestedLists([getBodyStructure(msg)])) - - def spewMessage(self, id, msg, query, uid): - wbuf = WriteBuffer(self.transport) - write = wbuf.write - flush = wbuf.flush - def start(): - write('* %d FETCH (' % (id,)) - def finish(): - write(')\r\n') - def space(): - write(' ') - - def spew(): - seenUID = False - start() - for part in query: - if part.type == 'uid': - seenUID = True - if part.type == 'body': - yield self.spew_body(part, id, msg, write, flush) - else: - f = getattr(self, 'spew_' + part.type) - yield f(id, msg, write, flush) - if part is not query[-1]: - space() - if uid and not seenUID: - space() - yield self.spew_uid(id, msg, write, flush) - finish() - flush() - return self._scheduler(spew()) - - def __ebFetch(self, failure, tag): - self.setTimeout(self._oldTimeout) - del self._oldTimeout - log.err(failure) - self.sendBadResponse(tag, 'FETCH failed: ' + str(failure.value)) - - def do_STORE(self, tag, messages, mode, flags, uid=0): - mode = mode.upper() - silent = mode.endswith('SILENT') - if mode.startswith('+'): - mode = 1 - elif mode.startswith('-'): - mode = -1 - else: - mode = 0 - - maybeDeferred(self.mbox.store, messages, flags, mode, uid=uid).addCallbacks( - self.__cbStore, self.__ebStore, (tag, self.mbox, uid, silent), None, (tag,), None - ) - - select_STORE = (do_STORE, arg_seqset, arg_atom, arg_flaglist) - - def __cbStore(self, result, tag, mbox, uid, silent): - if result and not silent: - for (k, v) in result.iteritems(): - if uid: - uidstr = ' UID %d' % mbox.getUID(k) - else: - uidstr = '' - self.sendUntaggedResponse('%d FETCH (FLAGS (%s)%s)' % - (k, ' '.join(v), uidstr)) - self.sendPositiveResponse(tag, 'STORE completed') - - def __ebStore(self, failure, tag): - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - - def do_COPY(self, tag, messages, mailbox, uid=0): - mailbox = self._parseMbox(mailbox) - maybeDeferred(self.account.select, mailbox - ).addCallback(self._cbCopySelectedMailbox, tag, messages, mailbox, uid - ).addErrback(self._ebCopySelectedMailbox, tag - ) - select_COPY = (do_COPY, arg_seqset, arg_astring) - - def _cbCopySelectedMailbox(self, mbox, tag, messages, mailbox, uid): - if not mbox: - self.sendNegativeResponse(tag, 'No such mailbox: ' + mailbox) - else: - maybeDeferred(self.mbox.fetch, messages, uid - ).addCallback(self.__cbCopy, tag, mbox - ).addCallback(self.__cbCopied, tag, mbox - ).addErrback(self.__ebCopy, tag - ) - - def _ebCopySelectedMailbox(self, failure, tag): - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - - def __cbCopy(self, messages, tag, mbox): - # XXX - This should handle failures with a rollback or something - addedDeferreds = [] - - fastCopyMbox = IMessageCopier(mbox, None) - for (id, msg) in messages: - if fastCopyMbox is not None: - d = maybeDeferred(fastCopyMbox.copy, msg) - addedDeferreds.append(d) - continue - - # XXX - The following should be an implementation of IMessageCopier.copy - # on an IMailbox->IMessageCopier adapter. - - flags = msg.getFlags() - date = msg.getInternalDate() - - body = IMessageFile(msg, None) - if body is not None: - bodyFile = body.open() - d = maybeDeferred(mbox.addMessage, bodyFile, flags, date) - else: - def rewind(f): - f.seek(0) - return f - buffer = tempfile.TemporaryFile() - d = MessageProducer(msg, buffer, self._scheduler - ).beginProducing(None - ).addCallback(lambda _, b=buffer, f=flags, d=date: mbox.addMessage(rewind(b), f, d) - ) - addedDeferreds.append(d) - return defer.DeferredList(addedDeferreds) - - def __cbCopied(self, deferredIds, tag, mbox): - ids = [] - failures = [] - for (status, result) in deferredIds: - if status: - ids.append(result) - else: - failures.append(result.value) - if failures: - self.sendNegativeResponse(tag, '[ALERT] Some messages were not copied') - else: - self.sendPositiveResponse(tag, 'COPY completed') - - def __ebCopy(self, failure, tag): - self.sendBadResponse(tag, 'COPY failed:' + str(failure.value)) - log.err(failure) - - def do_UID(self, tag, command, line): - command = command.upper() - - if command not in ('COPY', 'FETCH', 'STORE', 'SEARCH'): - raise IllegalClientResponse(command) - - self.dispatchCommand(tag, command, line, uid=1) - - select_UID = (do_UID, arg_atom, arg_line) - # - # IMailboxListener implementation - # - def modeChanged(self, writeable): - if writeable: - self.sendUntaggedResponse(message='[READ-WRITE]', async=True) - else: - self.sendUntaggedResponse(message='[READ-ONLY]', async=True) - - def flagsChanged(self, newFlags): - for (mId, flags) in newFlags.iteritems(): - msg = '%d FETCH (FLAGS (%s))' % (mId, ' '.join(flags)) - self.sendUntaggedResponse(msg, async=True) - - def newMessages(self, exists, recent): - if exists is not None: - self.sendUntaggedResponse('%d EXISTS' % exists, async=True) - if recent is not None: - self.sendUntaggedResponse('%d RECENT' % recent, async=True) - - -class UnhandledResponse(IMAP4Exception): pass - -class NegativeResponse(IMAP4Exception): pass - -class NoSupportedAuthentication(IMAP4Exception): - def __init__(self, serverSupports, clientSupports): - IMAP4Exception.__init__(self, 'No supported authentication schemes available') - self.serverSupports = serverSupports - self.clientSupports = clientSupports - - def __str__(self): - return (IMAP4Exception.__str__(self) - + ': Server supports %r, client supports %r' - % (self.serverSupports, self.clientSupports)) - -class IllegalServerResponse(IMAP4Exception): pass - -TIMEOUT_ERROR = error.TimeoutError() - -class IMAP4Client(basic.LineReceiver, policies.TimeoutMixin): - """IMAP4 client protocol implementation - - @ivar state: A string representing the state the connection is currently - in. - """ - implements(IMailboxListener) - - tags = None - waiting = None - queued = None - tagID = 1 - state = None - - startedTLS = False - - # Number of seconds to wait before timing out a connection. - # If the number is <= 0 no timeout checking will be performed. - timeout = 0 - - # Capabilities are not allowed to change during the session - # So cache the first response and use that for all later - # lookups - _capCache = None - - _memoryFileLimit = 1024 * 1024 * 10 - - # Authentication is pluggable. This maps names to IClientAuthentication - # objects. - authenticators = None - - STATUS_CODES = ('OK', 'NO', 'BAD', 'PREAUTH', 'BYE') - - STATUS_TRANSFORMATIONS = { - 'MESSAGES': int, 'RECENT': int, 'UNSEEN': int - } - - context = None - - def __init__(self, contextFactory = None): - self.tags = {} - self.queued = [] - self.authenticators = {} - self.context = contextFactory - - self._tag = None - self._parts = None - self._lastCmd = None - - def registerAuthenticator(self, auth): - """Register a new form of authentication - - When invoking the authenticate() method of IMAP4Client, the first - matching authentication scheme found will be used. The ordering is - that in which the server lists support authentication schemes. - - @type auth: Implementor of C{IClientAuthentication} - @param auth: The object to use to perform the client - side of this authentication scheme. - """ - self.authenticators[auth.getName().upper()] = auth - - def rawDataReceived(self, data): - if self.timeout > 0: - self.resetTimeout() - - self._pendingSize -= len(data) - if self._pendingSize > 0: - self._pendingBuffer.write(data) - else: - passon = '' - if self._pendingSize < 0: - data, passon = data[:self._pendingSize], data[self._pendingSize:] - self._pendingBuffer.write(data) - rest = self._pendingBuffer - self._pendingBuffer = None - self._pendingSize = None - rest.seek(0, 0) - self._parts.append(rest.read()) - self.setLineMode(passon.lstrip('\r\n')) - -# def sendLine(self, line): -# print 'S:', repr(line) -# return basic.LineReceiver.sendLine(self, line) - - def _setupForLiteral(self, rest, octets): - self._pendingBuffer = self.messageFile(octets) - self._pendingSize = octets - if self._parts is None: - self._parts = [rest, '\r\n'] - else: - self._parts.extend([rest, '\r\n']) - self.setRawMode() - - def connectionMade(self): - if self.timeout > 0: - self.setTimeout(self.timeout) - - def connectionLost(self, reason): - """We are no longer connected""" - if self.timeout > 0: - self.setTimeout(None) - if self.queued is not None: - queued = self.queued - self.queued = None - for cmd in queued: - cmd.defer.errback(reason) - if self.tags is not None: - tags = self.tags - self.tags = None - for cmd in tags.itervalues(): - if cmd is not None and cmd.defer is not None: - cmd.defer.errback(reason) - - - def lineReceived(self, line): - """ - Attempt to parse a single line from the server. - - @type line: C{str} - @param line: The line from the server, without the line delimiter. - - @raise IllegalServerResponse: If the line or some part of the line - does not represent an allowed message from the server at this time. - """ -# print 'C: ' + repr(line) - if self.timeout > 0: - self.resetTimeout() - - lastPart = line.rfind('{') - if lastPart != -1: - lastPart = line[lastPart + 1:] - if lastPart.endswith('}'): - # It's a literal a-comin' in - try: - octets = int(lastPart[:-1]) - except ValueError: - raise IllegalServerResponse(line) - if self._parts is None: - self._tag, parts = line.split(None, 1) - else: - parts = line - self._setupForLiteral(parts, octets) - return - - if self._parts is None: - # It isn't a literal at all - self._regularDispatch(line) - else: - # If an expression is in progress, no tag is required here - # Since we didn't find a literal indicator, this expression - # is done. - self._parts.append(line) - tag, rest = self._tag, ''.join(self._parts) - self._tag = self._parts = None - self.dispatchCommand(tag, rest) - - def timeoutConnection(self): - if self._lastCmd and self._lastCmd.defer is not None: - d, self._lastCmd.defer = self._lastCmd.defer, None - d.errback(TIMEOUT_ERROR) - - if self.queued: - for cmd in self.queued: - if cmd.defer is not None: - d, cmd.defer = cmd.defer, d - d.errback(TIMEOUT_ERROR) - - self.transport.loseConnection() - - def _regularDispatch(self, line): - parts = line.split(None, 1) - if len(parts) != 2: - parts.append('') - tag, rest = parts - self.dispatchCommand(tag, rest) - - def messageFile(self, octets): - """Create a file to which an incoming message may be written. - - @type octets: C{int} - @param octets: The number of octets which will be written to the file - - @rtype: Any object which implements C{write(string)} and - C{seek(int, int)} - @return: A file-like object - """ - if octets > self._memoryFileLimit: - return tempfile.TemporaryFile() - else: - return StringIO.StringIO() - - def makeTag(self): - tag = '%0.4X' % self.tagID - self.tagID += 1 - return tag - - def dispatchCommand(self, tag, rest): - if self.state is None: - f = self.response_UNAUTH - else: - f = getattr(self, 'response_' + self.state.upper(), None) - if f: - try: - f(tag, rest) - except: - log.err() - self.transport.loseConnection() - else: - log.err("Cannot dispatch: %s, %s, %s" % (self.state, tag, rest)) - self.transport.loseConnection() - - def response_UNAUTH(self, tag, rest): - if self.state is None: - # Server greeting, this is - status, rest = rest.split(None, 1) - if status.upper() == 'OK': - self.state = 'unauth' - elif status.upper() == 'PREAUTH': - self.state = 'auth' - else: - # XXX - This is rude. - self.transport.loseConnection() - raise IllegalServerResponse(tag + ' ' + rest) - - b, e = rest.find('['), rest.find(']') - if b != -1 and e != -1: - self.serverGreeting( - self.__cbCapabilities( - ([parseNestedParens(rest[b + 1:e])], None))) - else: - self.serverGreeting(None) - else: - self._defaultHandler(tag, rest) - - def response_AUTH(self, tag, rest): - self._defaultHandler(tag, rest) - - def _defaultHandler(self, tag, rest): - if tag == '*' or tag == '+': - if not self.waiting: - self._extraInfo([parseNestedParens(rest)]) - else: - cmd = self.tags[self.waiting] - if tag == '+': - cmd.continuation(rest) - else: - cmd.lines.append(rest) - else: - try: - cmd = self.tags[tag] - except KeyError: - # XXX - This is rude. - self.transport.loseConnection() - raise IllegalServerResponse(tag + ' ' + rest) - else: - status, line = rest.split(None, 1) - if status == 'OK': - # Give them this last line, too - cmd.finish(rest, self._extraInfo) - else: - cmd.defer.errback(IMAP4Exception(line)) - del self.tags[tag] - self.waiting = None - self._flushQueue() - - def _flushQueue(self): - if self.queued: - cmd = self.queued.pop(0) - t = self.makeTag() - self.tags[t] = cmd - self.sendLine(cmd.format(t)) - self.waiting = t - - def _extraInfo(self, lines): - # XXX - This is terrible. - # XXX - Also, this should collapse temporally proximate calls into single - # invocations of IMailboxListener methods, where possible. - flags = {} - recent = exists = None - for response in lines: - elements = len(response) - if elements == 1 and response[0] == ['READ-ONLY']: - self.modeChanged(False) - elif elements == 1 and response[0] == ['READ-WRITE']: - self.modeChanged(True) - elif elements == 2 and response[1] == 'EXISTS': - exists = int(response[0]) - elif elements == 2 and response[1] == 'RECENT': - recent = int(response[0]) - elif elements == 3 and response[1] == 'FETCH': - mId = int(response[0]) - values = self._parseFetchPairs(response[2]) - flags.setdefault(mId, []).extend(values.get('FLAGS', ())) - else: - log.msg('Unhandled unsolicited response: %s' % (response,)) - - if flags: - self.flagsChanged(flags) - if recent is not None or exists is not None: - self.newMessages(exists, recent) - - def sendCommand(self, cmd): - cmd.defer = defer.Deferred() - if self.waiting: - self.queued.append(cmd) - return cmd.defer - t = self.makeTag() - self.tags[t] = cmd - self.sendLine(cmd.format(t)) - self.waiting = t - self._lastCmd = cmd - return cmd.defer - - def getCapabilities(self, useCache=1): - """Request the capabilities available on this server. - - This command is allowed in any state of connection. - - @type useCache: C{bool} - @param useCache: Specify whether to use the capability-cache or to - re-retrieve the capabilities from the server. Server capabilities - should never change, so for normal use, this flag should never be - false. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with a - dictionary mapping capability types to lists of supported - mechanisms, or to None if a support list is not applicable. - """ - if useCache and self._capCache is not None: - return defer.succeed(self._capCache) - cmd = 'CAPABILITY' - resp = ('CAPABILITY',) - d = self.sendCommand(Command(cmd, wantResponse=resp)) - d.addCallback(self.__cbCapabilities) - return d - - def __cbCapabilities(self, (lines, tagline)): - caps = {} - for rest in lines: - for cap in rest[1:]: - parts = cap.split('=', 1) - if len(parts) == 1: - category, value = parts[0], None - else: - category, value = parts - caps.setdefault(category, []).append(value) - - # Preserve a non-ideal API for backwards compatibility. It would - # probably be entirely sensible to have an object with a wider API than - # dict here so this could be presented less insanely. - for category in caps: - if caps[category] == [None]: - caps[category] = None - self._capCache = caps - return caps - - def logout(self): - """Inform the server that we are done with the connection. - - This command is allowed in any state of connection. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with None - when the proper server acknowledgement has been received. - """ - d = self.sendCommand(Command('LOGOUT', wantResponse=('BYE',))) - d.addCallback(self.__cbLogout) - return d - - def __cbLogout(self, (lines, tagline)): - self.transport.loseConnection() - # We don't particularly care what the server said - return None - - - def noop(self): - """Perform no operation. - - This command is allowed in any state of connection. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with a list - of untagged status updates the server responds with. - """ - d = self.sendCommand(Command('NOOP')) - d.addCallback(self.__cbNoop) - return d - - def __cbNoop(self, (lines, tagline)): - # Conceivable, this is elidable. - # It is, afterall, a no-op. - return lines - - def startTLS(self, contextFactory=None): - """ - Initiates a 'STARTTLS' request and negotiates the TLS / SSL - Handshake. - - @param contextFactory: The TLS / SSL Context Factory to - leverage. If the contextFactory is None the IMAP4Client will - either use the current TLS / SSL Context Factory or attempt to - create a new one. - - @type contextFactory: C{ssl.ClientContextFactory} - - @return: A Deferred which fires when the transport has been - secured according to the given contextFactory, or which fails - if the transport cannot be secured. - """ - assert not self.startedTLS, "Client and Server are currently communicating via TLS" - - if contextFactory is None: - contextFactory = self._getContextFactory() - - if contextFactory is None: - return defer.fail(IMAP4Exception( - "IMAP4Client requires a TLS context to " - "initiate the STARTTLS handshake")) - - if 'STARTTLS' not in self._capCache: - return defer.fail(IMAP4Exception( - "Server does not support secure communication " - "via TLS / SSL")) - - tls = interfaces.ITLSTransport(self.transport, None) - if tls is None: - return defer.fail(IMAP4Exception( - "IMAP4Client transport does not implement " - "interfaces.ITLSTransport")) - - d = self.sendCommand(Command('STARTTLS')) - d.addCallback(self._startedTLS, contextFactory) - d.addCallback(lambda _: self.getCapabilities()) - return d - - - def authenticate(self, secret): - """Attempt to enter the authenticated state with the server - - This command is allowed in the Non-Authenticated state. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the authentication - succeeds and whose errback will be invoked otherwise. - """ - if self._capCache is None: - d = self.getCapabilities() - else: - d = defer.succeed(self._capCache) - d.addCallback(self.__cbAuthenticate, secret) - return d - - def __cbAuthenticate(self, caps, secret): - auths = caps.get('AUTH', ()) - for scheme in auths: - if scheme.upper() in self.authenticators: - cmd = Command('AUTHENTICATE', scheme, (), - self.__cbContinueAuth, scheme, - secret) - return self.sendCommand(cmd) - - if self.startedTLS: - return defer.fail(NoSupportedAuthentication( - auths, self.authenticators.keys())) - else: - def ebStartTLS(err): - err.trap(IMAP4Exception) - # We couldn't negotiate TLS for some reason - return defer.fail(NoSupportedAuthentication( - auths, self.authenticators.keys())) - - d = self.startTLS() - d.addErrback(ebStartTLS) - d.addCallback(lambda _: self.getCapabilities()) - d.addCallback(self.__cbAuthTLS, secret) - return d - - - def __cbContinueAuth(self, rest, scheme, secret): - try: - chal = base64.decodestring(rest + '\n') - except binascii.Error: - self.sendLine('*') - raise IllegalServerResponse(rest) - else: - auth = self.authenticators[scheme] - chal = auth.challengeResponse(secret, chal) - self.sendLine(base64.encodestring(chal).strip()) - - def __cbAuthTLS(self, caps, secret): - auths = caps.get('AUTH', ()) - for scheme in auths: - if scheme.upper() in self.authenticators: - cmd = Command('AUTHENTICATE', scheme, (), - self.__cbContinueAuth, scheme, - secret) - return self.sendCommand(cmd) - raise NoSupportedAuthentication(auths, self.authenticators.keys()) - - - def login(self, username, password): - """Authenticate with the server using a username and password - - This command is allowed in the Non-Authenticated state. If the - server supports the STARTTLS capability and our transport supports - TLS, TLS is negotiated before the login command is issued. - - A more secure way to log in is to use C{startTLS} or - C{authenticate} or both. - - @type username: C{str} - @param username: The username to log in with - - @type password: C{str} - @param password: The password to log in with - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if login is successful - and whose errback is invoked otherwise. - """ - d = maybeDeferred(self.getCapabilities) - d.addCallback(self.__cbLoginCaps, username, password) - return d - - def serverGreeting(self, caps): - """Called when the server has sent us a greeting. - - @type caps: C{dict} - @param caps: Capabilities the server advertised in its greeting. - """ - - def _getContextFactory(self): - if self.context is not None: - return self.context - try: - from twisted.internet import ssl - except ImportError: - return None - else: - context = ssl.ClientContextFactory() - context.method = ssl.SSL.TLSv1_METHOD - return context - - def __cbLoginCaps(self, capabilities, username, password): - # If the server advertises STARTTLS, we might want to try to switch to TLS - tryTLS = 'STARTTLS' in capabilities - - # If our transport supports switching to TLS, we might want to try to switch to TLS. - tlsableTransport = interfaces.ITLSTransport(self.transport, None) is not None - - # If our transport is not already using TLS, we might want to try to switch to TLS. - nontlsTransport = interfaces.ISSLTransport(self.transport, None) is None - - if not self.startedTLS and tryTLS and tlsableTransport and nontlsTransport: - d = self.startTLS() - - d.addCallbacks( - self.__cbLoginTLS, - self.__ebLoginTLS, - callbackArgs=(username, password), - ) - return d - else: - if nontlsTransport: - log.msg("Server has no TLS support. logging in over cleartext!") - args = ' '.join((_quote(username), _quote(password))) - return self.sendCommand(Command('LOGIN', args)) - - def _startedTLS(self, result, context): - self.transport.startTLS(context) - self._capCache = None - self.startedTLS = True - return result - - def __cbLoginTLS(self, result, username, password): - args = ' '.join((_quote(username), _quote(password))) - return self.sendCommand(Command('LOGIN', args)) - - def __ebLoginTLS(self, failure): - log.err(failure) - return failure - - def namespace(self): - """Retrieve information about the namespaces available to this account - - This command is allowed in the Authenticated and Selected states. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with namespace - information. An example of this information is:: - - [[['', '/']], [], []] - - which indicates a single personal namespace called '' with '/' - as its hierarchical delimiter, and no shared or user namespaces. - """ - cmd = 'NAMESPACE' - resp = ('NAMESPACE',) - d = self.sendCommand(Command(cmd, wantResponse=resp)) - d.addCallback(self.__cbNamespace) - return d - - def __cbNamespace(self, (lines, last)): - for parts in lines: - if len(parts) == 4 and parts[0] == 'NAMESPACE': - return [e or [] for e in parts[1:]] - log.err("No NAMESPACE response to NAMESPACE command") - return [[], [], []] - - - def select(self, mailbox): - """ - Select a mailbox - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The name of the mailbox to select - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with mailbox - information if the select is successful and whose errback is - invoked otherwise. Mailbox information consists of a dictionary - with the following keys and values:: - - FLAGS: A list of strings containing the flags settable on - messages in this mailbox. - - EXISTS: An integer indicating the number of messages in this - mailbox. - - RECENT: An integer indicating the number of "recent" - messages in this mailbox. - - UNSEEN: The message sequence number (an integer) of the - first unseen message in the mailbox. - - PERMANENTFLAGS: A list of strings containing the flags that - can be permanently set on messages in this mailbox. - - UIDVALIDITY: An integer uniquely identifying this mailbox. - """ - cmd = 'SELECT' - args = _prepareMailboxName(mailbox) - resp = ('FLAGS', 'EXISTS', 'RECENT', 'UNSEEN', 'PERMANENTFLAGS', 'UIDVALIDITY') - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbSelect, 1) - return d - - - def examine(self, mailbox): - """Select a mailbox in read-only mode - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The name of the mailbox to examine - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with mailbox - information if the examine is successful and whose errback - is invoked otherwise. Mailbox information consists of a dictionary - with the following keys and values:: - - 'FLAGS': A list of strings containing the flags settable on - messages in this mailbox. - - 'EXISTS': An integer indicating the number of messages in this - mailbox. - - 'RECENT': An integer indicating the number of \"recent\" - messages in this mailbox. - - 'UNSEEN': An integer indicating the number of messages not - flagged \\Seen in this mailbox. - - 'PERMANENTFLAGS': A list of strings containing the flags that - can be permanently set on messages in this mailbox. - - 'UIDVALIDITY': An integer uniquely identifying this mailbox. - """ - cmd = 'EXAMINE' - args = _prepareMailboxName(mailbox) - resp = ('FLAGS', 'EXISTS', 'RECENT', 'UNSEEN', 'PERMANENTFLAGS', 'UIDVALIDITY') - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbSelect, 0) - return d - - - def _intOrRaise(self, value, phrase): - """ - Parse C{value} as an integer and return the result or raise - L{IllegalServerResponse} with C{phrase} as an argument if C{value} - cannot be parsed as an integer. - """ - try: - return int(value) - except ValueError: - raise IllegalServerResponse(phrase) - - - def __cbSelect(self, (lines, tagline), rw): - """ - Handle lines received in response to a SELECT or EXAMINE command. - - See RFC 3501, section 6.3.1. - """ - # In the absence of specification, we are free to assume: - # READ-WRITE access - datum = {'READ-WRITE': rw} - lines.append(parseNestedParens(tagline)) - for split in lines: - if len(split) > 0 and split[0].upper() == 'OK': - # Handle all the kinds of OK response. - content = split[1] - key = content[0].upper() - if key == 'READ-ONLY': - datum['READ-WRITE'] = False - elif key == 'READ-WRITE': - datum['READ-WRITE'] = True - elif key == 'UIDVALIDITY': - datum['UIDVALIDITY'] = self._intOrRaise( - content[1], split) - elif key == 'UNSEEN': - datum['UNSEEN'] = self._intOrRaise(content[1], split) - elif key == 'UIDNEXT': - datum['UIDNEXT'] = self._intOrRaise(content[1], split) - elif key == 'PERMANENTFLAGS': - datum['PERMANENTFLAGS'] = tuple(content[1]) - else: - log.err('Unhandled SELECT response (2): %s' % (split,)) - elif len(split) == 2: - # Handle FLAGS, EXISTS, and RECENT - if split[0].upper() == 'FLAGS': - datum['FLAGS'] = tuple(split[1]) - elif isinstance(split[1], str): - # Must make sure things are strings before treating them as - # strings since some other forms of response have nesting in - # places which results in lists instead. - if split[1].upper() == 'EXISTS': - datum['EXISTS'] = self._intOrRaise(split[0], split) - elif split[1].upper() == 'RECENT': - datum['RECENT'] = self._intOrRaise(split[0], split) - else: - log.err('Unhandled SELECT response (0): %s' % (split,)) - else: - log.err('Unhandled SELECT response (1): %s' % (split,)) - else: - log.err('Unhandled SELECT response (4): %s' % (split,)) - return datum - - - def create(self, name): - """Create a new mailbox on the server - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The name of the mailbox to create. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the mailbox creation - is successful and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('CREATE', _prepareMailboxName(name))) - - def delete(self, name): - """Delete a mailbox - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The name of the mailbox to delete. - - @rtype: C{Deferred} - @return: A deferred whose calblack is invoked if the mailbox is - deleted successfully and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('DELETE', _prepareMailboxName(name))) - - def rename(self, oldname, newname): - """Rename a mailbox - - This command is allowed in the Authenticated and Selected states. - - @type oldname: C{str} - @param oldname: The current name of the mailbox to rename. - - @type newname: C{str} - @param newname: The new name to give the mailbox. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the rename is - successful and whose errback is invoked otherwise. - """ - oldname = _prepareMailboxName(oldname) - newname = _prepareMailboxName(newname) - return self.sendCommand(Command('RENAME', ' '.join((oldname, newname)))) - - def subscribe(self, name): - """Add a mailbox to the subscription list - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The mailbox to mark as 'active' or 'subscribed' - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the subscription - is successful and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('SUBSCRIBE', _prepareMailboxName(name))) - - def unsubscribe(self, name): - """Remove a mailbox from the subscription list - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The mailbox to unsubscribe - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the unsubscription - is successful and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('UNSUBSCRIBE', _prepareMailboxName(name))) - - def list(self, reference, wildcard): - """List a subset of the available mailboxes - - This command is allowed in the Authenticated and Selected states. - - @type reference: C{str} - @param reference: The context in which to interpret C{wildcard} - - @type wildcard: C{str} - @param wildcard: The pattern of mailbox names to match, optionally - including either or both of the '*' and '%' wildcards. '*' will - match zero or more characters and cross hierarchical boundaries. - '%' will also match zero or more characters, but is limited to a - single hierarchical level. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of C{tuple}s, - the first element of which is a C{tuple} of mailbox flags, the second - element of which is the hierarchy delimiter for this mailbox, and the - third of which is the mailbox name; if the command is unsuccessful, - the deferred's errback is invoked instead. - """ - cmd = 'LIST' - args = '"%s" "%s"' % (reference, wildcard.encode('imap4-utf-7')) - resp = ('LIST',) - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbList, 'LIST') - return d - - def lsub(self, reference, wildcard): - """List a subset of the subscribed available mailboxes - - This command is allowed in the Authenticated and Selected states. - - The parameters and returned object are the same as for the C{list} - method, with one slight difference: Only mailboxes which have been - subscribed can be included in the resulting list. - """ - cmd = 'LSUB' - args = '"%s" "%s"' % (reference, wildcard.encode('imap4-utf-7')) - resp = ('LSUB',) - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbList, 'LSUB') - return d - - def __cbList(self, (lines, last), command): - results = [] - for parts in lines: - if len(parts) == 4 and parts[0] == command: - parts[1] = tuple(parts[1]) - results.append(tuple(parts[1:])) - return results - - def status(self, mailbox, *names): - """ - Retrieve the status of the given mailbox - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The name of the mailbox to query - - @type *names: C{str} - @param *names: The status names to query. These may be any number of: - C{'MESSAGES'}, C{'RECENT'}, C{'UIDNEXT'}, C{'UIDVALIDITY'}, and - C{'UNSEEN'}. - - @rtype: C{Deferred} - @return: A deferred which fires with the status information if the - command is successful and whose errback is invoked otherwise. The - status information is in the form of a C{dict}. Each element of - C{names} is a key in the dictionary. The value for each key is the - corresponding response from the server. - """ - cmd = 'STATUS' - args = "%s (%s)" % (_prepareMailboxName(mailbox), ' '.join(names)) - resp = ('STATUS',) - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbStatus) - return d - - def __cbStatus(self, (lines, last)): - status = {} - for parts in lines: - if parts[0] == 'STATUS': - items = parts[2] - items = [items[i:i+2] for i in range(0, len(items), 2)] - status.update(dict(items)) - for k in status.keys(): - t = self.STATUS_TRANSFORMATIONS.get(k) - if t: - try: - status[k] = t(status[k]) - except Exception, e: - raise IllegalServerResponse('(%s %s): %s' % (k, status[k], str(e))) - return status - - def append(self, mailbox, message, flags = (), date = None): - """Add the given message to the given mailbox. - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The mailbox to which to add this message. - - @type message: Any file-like object - @param message: The message to add, in RFC822 format. Newlines - in this file should be \\r\\n-style. - - @type flags: Any iterable of C{str} - @param flags: The flags to associated with this message. - - @type date: C{str} - @param date: The date to associate with this message. This should - be of the format DD-MM-YYYY HH:MM:SS +/-HHMM. For example, in - Eastern Standard Time, on July 1st 2004 at half past 1 PM, - \"01-07-2004 13:30:00 -0500\". - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked when this command - succeeds or whose errback is invoked if it fails. - """ - message.seek(0, 2) - L = message.tell() - message.seek(0, 0) - fmt = '%s (%s)%s {%d}' - if date: - date = ' "%s"' % date - else: - date = '' - cmd = fmt % ( - _prepareMailboxName(mailbox), ' '.join(flags), - date, L - ) - d = self.sendCommand(Command('APPEND', cmd, (), self.__cbContinueAppend, message)) - return d - - def __cbContinueAppend(self, lines, message): - s = basic.FileSender() - return s.beginFileTransfer(message, self.transport, None - ).addCallback(self.__cbFinishAppend) - - def __cbFinishAppend(self, foo): - self.sendLine('') - - def check(self): - """Tell the server to perform a checkpoint - - This command is allowed in the Selected state. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked when this command - succeeds or whose errback is invoked if it fails. - """ - return self.sendCommand(Command('CHECK')) - - def close(self): - """Return the connection to the Authenticated state. - - This command is allowed in the Selected state. - - Issuing this command will also remove all messages flagged \\Deleted - from the selected mailbox if it is opened in read-write mode, - otherwise it indicates success by no messages are removed. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked when the command - completes successfully or whose errback is invoked if it fails. - """ - return self.sendCommand(Command('CLOSE')) - - - def expunge(self): - """Return the connection to the Authenticate state. - - This command is allowed in the Selected state. - - Issuing this command will perform the same actions as issuing the - close command, but will also generate an 'expunge' response for - every message deleted. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - 'expunge' responses when this command is successful or whose errback - is invoked otherwise. - """ - cmd = 'EXPUNGE' - resp = ('EXPUNGE',) - d = self.sendCommand(Command(cmd, wantResponse=resp)) - d.addCallback(self.__cbExpunge) - return d - - - def __cbExpunge(self, (lines, last)): - ids = [] - for parts in lines: - if len(parts) == 2 and parts[1] == 'EXPUNGE': - ids.append(self._intOrRaise(parts[0], parts)) - return ids - - - def search(self, *queries, **kwarg): - """Search messages in the currently selected mailbox - - This command is allowed in the Selected state. - - Any non-zero number of queries are accepted by this method, as - returned by the C{Query}, C{Or}, and C{Not} functions. - - One keyword argument is accepted: if uid is passed in with a non-zero - value, the server is asked to return message UIDs instead of message - sequence numbers. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with a list of all - the message sequence numbers return by the search, or whose errback - will be invoked if there is an error. - """ - if kwarg.get('uid'): - cmd = 'UID SEARCH' - else: - cmd = 'SEARCH' - args = ' '.join(queries) - d = self.sendCommand(Command(cmd, args, wantResponse=(cmd,))) - d.addCallback(self.__cbSearch) - return d - - - def __cbSearch(self, (lines, end)): - ids = [] - for parts in lines: - if len(parts) > 0 and parts[0] == 'SEARCH': - ids.extend([self._intOrRaise(p, parts) for p in parts[1:]]) - return ids - - - def fetchUID(self, messages, uid=0): - """Retrieve the unique identifier for one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message sequence numbers to unique message identifiers, or whose - errback is invoked if there is an error. - """ - return self._fetch(messages, useUID=uid, uid=1) - - - def fetchFlags(self, messages, uid=0): - """Retrieve the flags for one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve flags. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to lists of flags, or whose errback is invoked if - there is an error. - """ - return self._fetch(str(messages), useUID=uid, flags=1) - - - def fetchInternalDate(self, messages, uid=0): - """Retrieve the internal date associated with one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve the internal date. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to date strings, or whose errback is invoked - if there is an error. Date strings take the format of - \"day-month-year time timezone\". - """ - return self._fetch(str(messages), useUID=uid, internaldate=1) - - - def fetchEnvelope(self, messages, uid=0): - """Retrieve the envelope data for one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve envelope data. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to envelope data, or whose errback is invoked - if there is an error. Envelope data consists of a sequence of the - date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, - and message-id header fields. The date, subject, in-reply-to, and - message-id fields are strings, while the from, sender, reply-to, - to, cc, and bcc fields contain address data. Address data consists - of a sequence of name, source route, mailbox name, and hostname. - Fields which are not present for a particular address may be C{None}. - """ - return self._fetch(str(messages), useUID=uid, envelope=1) - - - def fetchBodyStructure(self, messages, uid=0): - """Retrieve the structure of the body of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve body structure - data. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to body structure data, or whose errback is invoked - if there is an error. Body structure data describes the MIME-IMB - format of a message and consists of a sequence of mime type, mime - subtype, parameters, content id, description, encoding, and size. - The fields following the size field are variable: if the mime - type/subtype is message/rfc822, the contained message's envelope - information, body structure data, and number of lines of text; if - the mime type is text, the number of lines of text. Extension fields - may also be included; if present, they are: the MD5 hash of the body, - body disposition, body language. - """ - return self._fetch(messages, useUID=uid, bodystructure=1) - - - def fetchSimplifiedBody(self, messages, uid=0): - """Retrieve the simplified body structure of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to body data, or whose errback is invoked - if there is an error. The simplified body structure is the same - as the body structure, except that extension fields will never be - present. - """ - return self._fetch(messages, useUID=uid, body=1) - - - def fetchMessage(self, messages, uid=0): - """Retrieve one or more entire messages - - This command is allowed in the Selected state. - - @type messages: L{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: L{Deferred} - - @return: A L{Deferred} which will fire with a C{dict} mapping message - sequence numbers to C{dict}s giving message data for the - corresponding message. If C{uid} is true, the inner dictionaries - have a C{'UID'} key mapped to a C{str} giving the UID for the - message. The text of the message is a C{str} associated with the - C{'RFC822'} key in each dictionary. - """ - return self._fetch(messages, useUID=uid, rfc822=1) - - - def fetchHeaders(self, messages, uid=0): - """Retrieve headers of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dicts of message headers, or whose errback is - invoked if there is an error. - """ - return self._fetch(messages, useUID=uid, rfc822header=1) - - - def fetchBody(self, messages, uid=0): - """Retrieve body text of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to file-like objects containing body text, or whose - errback is invoked if there is an error. - """ - return self._fetch(messages, useUID=uid, rfc822text=1) - - - def fetchSize(self, messages, uid=0): - """Retrieve the size, in octets, of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to sizes, or whose errback is invoked if there is - an error. - """ - return self._fetch(messages, useUID=uid, rfc822size=1) - - - def fetchFull(self, messages, uid=0): - """Retrieve several different fields of one or more messages - - This command is allowed in the Selected state. This is equivalent - to issuing all of the C{fetchFlags}, C{fetchInternalDate}, - C{fetchSize}, C{fetchEnvelope}, and C{fetchSimplifiedBody} - functions. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dict of the retrieved data values, or whose - errback is invoked if there is an error. They dictionary keys - are "flags", "date", "size", "envelope", and "body". - """ - return self._fetch( - messages, useUID=uid, flags=1, internaldate=1, - rfc822size=1, envelope=1, body=1) - - - def fetchAll(self, messages, uid=0): - """Retrieve several different fields of one or more messages - - This command is allowed in the Selected state. This is equivalent - to issuing all of the C{fetchFlags}, C{fetchInternalDate}, - C{fetchSize}, and C{fetchEnvelope} functions. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dict of the retrieved data values, or whose - errback is invoked if there is an error. They dictionary keys - are "flags", "date", "size", and "envelope". - """ - return self._fetch( - messages, useUID=uid, flags=1, internaldate=1, - rfc822size=1, envelope=1) - - - def fetchFast(self, messages, uid=0): - """Retrieve several different fields of one or more messages - - This command is allowed in the Selected state. This is equivalent - to issuing all of the C{fetchFlags}, C{fetchInternalDate}, and - C{fetchSize} functions. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dict of the retrieved data values, or whose - errback is invoked if there is an error. They dictionary keys are - "flags", "date", and "size". - """ - return self._fetch( - messages, useUID=uid, flags=1, internaldate=1, rfc822size=1) - - - def _parseFetchPairs(self, fetchResponseList): - """ - Given the result of parsing a single I{FETCH} response, construct a - C{dict} mapping response keys to response values. - - @param fetchResponseList: The result of parsing a I{FETCH} response - with L{parseNestedParens} and extracting just the response data - (that is, just the part that comes after C{"FETCH"}). The form - of this input (and therefore the output of this method) is very - disagreeable. A valuable improvement would be to enumerate the - possible keys (representing them as structured objects of some - sort) rather than using strings and tuples of tuples of strings - and so forth. This would allow the keys to be documented more - easily and would allow for a much simpler application-facing API - (one not based on looking up somewhat hard to predict keys in a - dict). Since C{fetchResponseList} notionally represents a - flattened sequence of pairs (identifying keys followed by their - associated values), collapsing such complex elements of this - list as C{["BODY", ["HEADER.FIELDS", ["SUBJECT"]]]} into a - single object would also greatly simplify the implementation of - this method. - - @return: A C{dict} of the response data represented by C{pairs}. Keys - in this dictionary are things like C{"RFC822.TEXT"}, C{"FLAGS"}, or - C{("BODY", ("HEADER.FIELDS", ("SUBJECT",)))}. Values are entirely - dependent on the key with which they are associated, but retain the - same structured as produced by L{parseNestedParens}. - """ - values = {} - responseParts = iter(fetchResponseList) - while True: - try: - key = responseParts.next() - except StopIteration: - break - - try: - value = responseParts.next() - except StopIteration: - raise IllegalServerResponse( - "Not enough arguments", fetchResponseList) - - # The parsed forms of responses like: - # - # BODY[] VALUE - # BODY[TEXT] VALUE - # BODY[HEADER.FIELDS (SUBJECT)] VALUE - # BODY[HEADER.FIELDS (SUBJECT)] VALUE - # - # are: - # - # ["BODY", [], VALUE] - # ["BODY", ["TEXT"], VALUE] - # ["BODY", ["HEADER.FIELDS", ["SUBJECT"]], VALUE] - # ["BODY", ["HEADER.FIELDS", ["SUBJECT"]], "", VALUE] - # - # Additionally, BODY responses for multipart messages are - # represented as: - # - # ["BODY", VALUE] - # - # with list as the type of VALUE and the type of VALUE[0]. - # - # See #6281 for ideas on how this might be improved. - - if key not in ("BODY", "BODY.PEEK"): - # Only BODY (and by extension, BODY.PEEK) responses can have - # body sections. - hasSection = False - elif not isinstance(value, list): - # A BODY section is always represented as a list. Any non-list - # is not a BODY section. - hasSection = False - elif len(value) > 2: - # The list representing a BODY section has at most two elements. - hasSection = False - elif value and isinstance(value[0], list): - # A list containing a list represents the body structure of a - # multipart message, instead. - hasSection = False - else: - # Otherwise it must have a BODY section to examine. - hasSection = True - - # If it has a BODY section, grab some extra elements and shuffle - # around the shape of the key a little bit. - if hasSection: - if len(value) < 2: - key = (key, tuple(value)) - else: - key = (key, (value[0], tuple(value[1]))) - try: - value = responseParts.next() - except StopIteration: - raise IllegalServerResponse( - "Not enough arguments", fetchResponseList) - - # Handle partial ranges - if value.startswith('<') and value.endswith('>'): - try: - int(value[1:-1]) - except ValueError: - # This isn't really a range, it's some content. - pass - else: - key = key + (value,) - try: - value = responseParts.next() - except StopIteration: - raise IllegalServerResponse( - "Not enough arguments", fetchResponseList) - - values[key] = value - return values - - - def _cbFetch(self, (lines, last), requestedParts, structured): - info = {} - for parts in lines: - if len(parts) == 3 and parts[1] == 'FETCH': - id = self._intOrRaise(parts[0], parts) - if id not in info: - info[id] = [parts[2]] - else: - info[id][0].extend(parts[2]) - - results = {} - for (messageId, values) in info.iteritems(): - mapping = self._parseFetchPairs(values[0]) - results.setdefault(messageId, {}).update(mapping) - - flagChanges = {} - for messageId in results.keys(): - values = results[messageId] - for part in values.keys(): - if part not in requestedParts and part == 'FLAGS': - flagChanges[messageId] = values['FLAGS'] - # Find flags in the result and get rid of them. - for i in range(len(info[messageId][0])): - if info[messageId][0][i] == 'FLAGS': - del info[messageId][0][i:i+2] - break - del values['FLAGS'] - if not values: - del results[messageId] - - if flagChanges: - self.flagsChanged(flagChanges) - - if structured: - return results - else: - return info - - - def fetchSpecific(self, messages, uid=0, headerType=None, - headerNumber=None, headerArgs=None, peek=None, - offset=None, length=None): - """Retrieve a specific section of one or more messages - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @type headerType: C{str} - @param headerType: If specified, must be one of HEADER, - HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, or TEXT, and will determine - which part of the message is retrieved. For HEADER.FIELDS and - HEADER.FIELDS.NOT, C{headerArgs} must be a sequence of header names. - For MIME, C{headerNumber} must be specified. - - @type headerNumber: C{int} or C{int} sequence - @param headerNumber: The nested rfc822 index specifying the - entity to retrieve. For example, C{1} retrieves the first - entity of the message, and C{(2, 1, 3}) retrieves the 3rd - entity inside the first entity inside the second entity of - the message. - - @type headerArgs: A sequence of C{str} - @param headerArgs: If C{headerType} is HEADER.FIELDS, these are the - headers to retrieve. If it is HEADER.FIELDS.NOT, these are the - headers to exclude from retrieval. - - @type peek: C{bool} - @param peek: If true, cause the server to not set the \\Seen - flag on this message as a result of this command. - - @type offset: C{int} - @param offset: The number of octets at the beginning of the result - to skip. - - @type length: C{int} - @param length: The number of octets to retrieve. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a mapping of - message numbers to retrieved data, or whose errback is invoked - if there is an error. - """ - fmt = '%s BODY%s[%s%s%s]%s' - if headerNumber is None: - number = '' - elif isinstance(headerNumber, int): - number = str(headerNumber) - else: - number = '.'.join(map(str, headerNumber)) - if headerType is None: - header = '' - elif number: - header = '.' + headerType - else: - header = headerType - if header and headerType not in ('TEXT', 'MIME'): - if headerArgs is not None: - payload = ' (%s)' % ' '.join(headerArgs) - else: - payload = ' ()' - else: - payload = '' - if offset is None: - extra = '' - else: - extra = '<%d.%d>' % (offset, length) - fetch = uid and 'UID FETCH' or 'FETCH' - cmd = fmt % (messages, peek and '.PEEK' or '', number, header, payload, extra) - d = self.sendCommand(Command(fetch, cmd, wantResponse=('FETCH',))) - d.addCallback(self._cbFetch, (), False) - return d - - - def _fetch(self, messages, useUID=0, **terms): - fetch = useUID and 'UID FETCH' or 'FETCH' - - if 'rfc822text' in terms: - del terms['rfc822text'] - terms['rfc822.text'] = True - if 'rfc822size' in terms: - del terms['rfc822size'] - terms['rfc822.size'] = True - if 'rfc822header' in terms: - del terms['rfc822header'] - terms['rfc822.header'] = True - - cmd = '%s (%s)' % (messages, ' '.join([s.upper() for s in terms.keys()])) - d = self.sendCommand(Command(fetch, cmd, wantResponse=('FETCH',))) - d.addCallback(self._cbFetch, map(str.upper, terms.keys()), True) - return d - - def setFlags(self, messages, flags, silent=1, uid=0): - """Set the flags for one or more messages. - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type flags: Any iterable of C{str} - @param flags: The flags to set - - @type silent: C{bool} - @param silent: If true, cause the server to supress its verbose - response. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - server's responses (C{[]} if C{silent} is true) or whose - errback is invoked if there is an error. - """ - return self._store(str(messages), 'FLAGS', silent, flags, uid) - - def addFlags(self, messages, flags, silent=1, uid=0): - """Add to the set flags for one or more messages. - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type flags: Any iterable of C{str} - @param flags: The flags to set - - @type silent: C{bool} - @param silent: If true, cause the server to supress its verbose - response. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - server's responses (C{[]} if C{silent} is true) or whose - errback is invoked if there is an error. - """ - return self._store(str(messages),'+FLAGS', silent, flags, uid) - - def removeFlags(self, messages, flags, silent=1, uid=0): - """Remove from the set flags for one or more messages. - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type flags: Any iterable of C{str} - @param flags: The flags to set - - @type silent: C{bool} - @param silent: If true, cause the server to supress its verbose - response. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - server's responses (C{[]} if C{silent} is true) or whose - errback is invoked if there is an error. - """ - return self._store(str(messages), '-FLAGS', silent, flags, uid) - - - def _store(self, messages, cmd, silent, flags, uid): - if silent: - cmd = cmd + '.SILENT' - store = uid and 'UID STORE' or 'STORE' - args = ' '.join((messages, cmd, '(%s)' % ' '.join(flags))) - d = self.sendCommand(Command(store, args, wantResponse=('FETCH',))) - expected = () - if not silent: - expected = ('FLAGS',) - d.addCallback(self._cbFetch, expected, True) - return d - - - def copy(self, messages, mailbox, uid): - """Copy the specified messages to the specified mailbox. - - This command is allowed in the Selected state. - - @type messages: C{str} - @param messages: A message sequence set - - @type mailbox: C{str} - @param mailbox: The mailbox to which to copy the messages - - @type uid: C{bool} - @param uid: If true, the C{messages} refers to message UIDs, rather - than message sequence numbers. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a true value - when the copy is successful, or whose errback is invoked if there - is an error. - """ - if uid: - cmd = 'UID COPY' - else: - cmd = 'COPY' - args = '%s %s' % (messages, _prepareMailboxName(mailbox)) - return self.sendCommand(Command(cmd, args)) - - # - # IMailboxListener methods - # - def modeChanged(self, writeable): - """Override me""" - - def flagsChanged(self, newFlags): - """Override me""" - - def newMessages(self, exists, recent): - """Override me""" - - -class IllegalIdentifierError(IMAP4Exception): pass - -def parseIdList(s, lastMessageId=None): - """ - Parse a message set search key into a C{MessageSet}. - - @type s: C{str} - @param s: A string description of a id list, for example "1:3, 4:*" - - @type lastMessageId: C{int} - @param lastMessageId: The last message sequence id or UID, depending on - whether we are parsing the list in UID or sequence id context. The - caller should pass in the correct value. - - @rtype: C{MessageSet} - @return: A C{MessageSet} that contains the ids defined in the list - """ - res = MessageSet() - parts = s.split(',') - for p in parts: - if ':' in p: - low, high = p.split(':', 1) - try: - if low == '*': - low = None - else: - low = long(low) - if high == '*': - high = None - else: - high = long(high) - if low is high is None: - # *:* does not make sense - raise IllegalIdentifierError(p) - # non-positive values are illegal according to RFC 3501 - if ((low is not None and low <= 0) or - (high is not None and high <= 0)): - raise IllegalIdentifierError(p) - # star means "highest value of an id in the mailbox" - high = high or lastMessageId - low = low or lastMessageId - - # RFC says that 2:4 and 4:2 are equivalent - if low > high: - low, high = high, low - res.extend((low, high)) - except ValueError: - raise IllegalIdentifierError(p) - else: - try: - if p == '*': - p = None - else: - p = long(p) - if p is not None and p <= 0: - raise IllegalIdentifierError(p) - except ValueError: - raise IllegalIdentifierError(p) - else: - res.extend(p or lastMessageId) - return res - -class IllegalQueryError(IMAP4Exception): pass - -_SIMPLE_BOOL = ( - 'ALL', 'ANSWERED', 'DELETED', 'DRAFT', 'FLAGGED', 'NEW', 'OLD', 'RECENT', - 'SEEN', 'UNANSWERED', 'UNDELETED', 'UNDRAFT', 'UNFLAGGED', 'UNSEEN' -) - -_NO_QUOTES = ( - 'LARGER', 'SMALLER', 'UID' -) - -def Query(sorted=0, **kwarg): - """Create a query string - - Among the accepted keywords are:: - - all : If set to a true value, search all messages in the - current mailbox - - answered : If set to a true value, search messages flagged with - \\Answered - - bcc : A substring to search the BCC header field for - - before : Search messages with an internal date before this - value. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - body : A substring to search the body of the messages for - - cc : A substring to search the CC header field for - - deleted : If set to a true value, search messages flagged with - \\Deleted - - draft : If set to a true value, search messages flagged with - \\Draft - - flagged : If set to a true value, search messages flagged with - \\Flagged - - from : A substring to search the From header field for - - header : A two-tuple of a header name and substring to search - for in that header - - keyword : Search for messages with the given keyword set - - larger : Search for messages larger than this number of octets - - messages : Search only the given message sequence set. - - new : If set to a true value, search messages flagged with - \\Recent but not \\Seen - - old : If set to a true value, search messages not flagged with - \\Recent - - on : Search messages with an internal date which is on this - date. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - recent : If set to a true value, search for messages flagged with - \\Recent - - seen : If set to a true value, search for messages flagged with - \\Seen - - sentbefore : Search for messages with an RFC822 'Date' header before - this date. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - senton : Search for messages with an RFC822 'Date' header which is - on this date The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - sentsince : Search for messages with an RFC822 'Date' header which is - after this date. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - since : Search for messages with an internal date that is after - this date.. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - smaller : Search for messages smaller than this number of octets - - subject : A substring to search the 'subject' header for - - text : A substring to search the entire message for - - to : A substring to search the 'to' header for - - uid : Search only the messages in the given message set - - unanswered : If set to a true value, search for messages not - flagged with \\Answered - - undeleted : If set to a true value, search for messages not - flagged with \\Deleted - - undraft : If set to a true value, search for messages not - flagged with \\Draft - - unflagged : If set to a true value, search for messages not - flagged with \\Flagged - - unkeyword : Search for messages without the given keyword set - - unseen : If set to a true value, search for messages not - flagged with \\Seen - - @type sorted: C{bool} - @param sorted: If true, the output will be sorted, alphabetically. - The standard does not require it, but it makes testing this function - easier. The default is zero, and this should be acceptable for any - application. - - @rtype: C{str} - @return: The formatted query string - """ - cmd = [] - keys = kwarg.keys() - if sorted: - keys.sort() - for k in keys: - v = kwarg[k] - k = k.upper() - if k in _SIMPLE_BOOL and v: - cmd.append(k) - elif k == 'HEADER': - cmd.extend([k, v[0], '"%s"' % (v[1],)]) - elif k == 'KEYWORD' or k == 'UNKEYWORD': - # Discard anything that does not fit into an "atom". Perhaps turn - # the case where this actually removes bytes from the value into a - # warning and then an error, eventually. See #6277. - v = string.translate(v, string.maketrans('', ''), _nonAtomChars) - cmd.extend([k, v]) - elif k not in _NO_QUOTES: - cmd.extend([k, '"%s"' % (v,)]) - else: - cmd.extend([k, '%s' % (v,)]) - if len(cmd) > 1: - return '(%s)' % ' '.join(cmd) - else: - return ' '.join(cmd) - -def Or(*args): - """The disjunction of two or more queries""" - if len(args) < 2: - raise IllegalQueryError, args - elif len(args) == 2: - return '(OR %s %s)' % args - else: - return '(OR %s %s)' % (args[0], Or(*args[1:])) - -def Not(query): - """The negation of a query""" - return '(NOT %s)' % (query,) - -class MismatchedNesting(IMAP4Exception): - pass - -class MismatchedQuoting(IMAP4Exception): - pass - -def wildcardToRegexp(wildcard, delim=None): - wildcard = wildcard.replace('*', '(?:.*?)') - if delim is None: - wildcard = wildcard.replace('%', '(?:.*?)') - else: - wildcard = wildcard.replace('%', '(?:(?:[^%s])*?)' % re.escape(delim)) - return re.compile(wildcard, re.I) - -def splitQuoted(s): - """Split a string into whitespace delimited tokens - - Tokens that would otherwise be separated but are surrounded by \" - remain as a single token. Any token that is not quoted and is - equal to \"NIL\" is tokenized as C{None}. - - @type s: C{str} - @param s: The string to be split - - @rtype: C{list} of C{str} - @return: A list of the resulting tokens - - @raise MismatchedQuoting: Raised if an odd number of quotes are present - """ - s = s.strip() - result = [] - word = [] - inQuote = inWord = False - for i, c in enumerate(s): - if c == '"': - if i and s[i-1] == '\\': - word.pop() - word.append('"') - elif not inQuote: - inQuote = True - else: - inQuote = False - result.append(''.join(word)) - word = [] - elif not inWord and not inQuote and c not in ('"' + string.whitespace): - inWord = True - word.append(c) - elif inWord and not inQuote and c in string.whitespace: - w = ''.join(word) - if w == 'NIL': - result.append(None) - else: - result.append(w) - word = [] - inWord = False - elif inWord or inQuote: - word.append(c) - - if inQuote: - raise MismatchedQuoting(s) - if inWord: - w = ''.join(word) - if w == 'NIL': - result.append(None) - else: - result.append(w) - - return result - - - -def splitOn(sequence, predicate, transformers): - result = [] - mode = predicate(sequence[0]) - tmp = [sequence[0]] - for e in sequence[1:]: - p = predicate(e) - if p != mode: - result.extend(transformers[mode](tmp)) - tmp = [e] - mode = p - else: - tmp.append(e) - result.extend(transformers[mode](tmp)) - return result - -def collapseStrings(results): - """ - Turns a list of length-one strings and lists into a list of longer - strings and lists. For example, - - ['a', 'b', ['c', 'd']] is returned as ['ab', ['cd']] - - @type results: C{list} of C{str} and C{list} - @param results: The list to be collapsed - - @rtype: C{list} of C{str} and C{list} - @return: A new list which is the collapsed form of C{results} - """ - copy = [] - begun = None - listsList = [isinstance(s, types.ListType) for s in results] - - pred = lambda e: isinstance(e, types.TupleType) - tran = { - 0: lambda e: splitQuoted(''.join(e)), - 1: lambda e: [''.join([i[0] for i in e])] - } - for (i, c, isList) in zip(range(len(results)), results, listsList): - if isList: - if begun is not None: - copy.extend(splitOn(results[begun:i], pred, tran)) - begun = None - copy.append(collapseStrings(c)) - elif begun is None: - begun = i - if begun is not None: - copy.extend(splitOn(results[begun:], pred, tran)) - return copy - - -def parseNestedParens(s, handleLiteral = 1): - """Parse an s-exp-like string into a more useful data structure. - - @type s: C{str} - @param s: The s-exp-like string to parse - - @rtype: C{list} of C{str} and C{list} - @return: A list containing the tokens present in the input. - - @raise MismatchedNesting: Raised if the number or placement - of opening or closing parenthesis is invalid. - """ - s = s.strip() - inQuote = 0 - contentStack = [[]] - try: - i = 0 - L = len(s) - while i < L: - c = s[i] - if inQuote: - if c == '\\': - contentStack[-1].append(s[i:i+2]) - i += 2 - continue - elif c == '"': - inQuote = not inQuote - contentStack[-1].append(c) - i += 1 - else: - if c == '"': - contentStack[-1].append(c) - inQuote = not inQuote - i += 1 - elif handleLiteral and c == '{': - end = s.find('}', i) - if end == -1: - raise ValueError, "Malformed literal" - literalSize = int(s[i+1:end]) - contentStack[-1].append((s[end+3:end+3+literalSize],)) - i = end + 3 + literalSize - elif c == '(' or c == '[': - contentStack.append([]) - i += 1 - elif c == ')' or c == ']': - contentStack[-2].append(contentStack.pop()) - i += 1 - else: - contentStack[-1].append(c) - i += 1 - except IndexError: - raise MismatchedNesting(s) - if len(contentStack) != 1: - raise MismatchedNesting(s) - return collapseStrings(contentStack[0]) - -def _quote(s): - return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\\"'),) - -def _literal(s): - return '{%d}\r\n%s' % (len(s), s) - -class DontQuoteMe: - def __init__(self, value): - self.value = value - - def __str__(self): - return str(self.value) - -_ATOM_SPECIALS = '(){ %*"' -def _needsQuote(s): - if s == '': - return 1 - for c in s: - if c < '\x20' or c > '\x7f': - return 1 - if c in _ATOM_SPECIALS: - return 1 - return 0 - -def _prepareMailboxName(name): - name = name.encode('imap4-utf-7') - if _needsQuote(name): - return _quote(name) - return name - -def _needsLiteral(s): - # Change this to "return 1" to wig out stupid clients - return '\n' in s or '\r' in s or len(s) > 1000 - -def collapseNestedLists(items): - """Turn a nested list structure into an s-exp-like string. - - Strings in C{items} will be sent as literals if they contain CR or LF, - otherwise they will be quoted. References to None in C{items} will be - translated to the atom NIL. Objects with a 'read' attribute will have - it called on them with no arguments and the returned string will be - inserted into the output as a literal. Integers will be converted to - strings and inserted into the output unquoted. Instances of - C{DontQuoteMe} will be converted to strings and inserted into the output - unquoted. - - This function used to be much nicer, and only quote things that really - needed to be quoted (and C{DontQuoteMe} did not exist), however, many - broken IMAP4 clients were unable to deal with this level of sophistication, - forcing the current behavior to be adopted for practical reasons. - - @type items: Any iterable - - @rtype: C{str} - """ - pieces = [] - for i in items: - if i is None: - pieces.extend([' ', 'NIL']) - elif isinstance(i, (DontQuoteMe, int, long)): - pieces.extend([' ', str(i)]) - elif isinstance(i, types.StringTypes): - if _needsLiteral(i): - pieces.extend([' ', '{', str(len(i)), '}', IMAP4Server.delimiter, i]) - else: - pieces.extend([' ', _quote(i)]) - elif hasattr(i, 'read'): - d = i.read() - pieces.extend([' ', '{', str(len(d)), '}', IMAP4Server.delimiter, d]) - else: - pieces.extend([' ', '(%s)' % (collapseNestedLists(i),)]) - return ''.join(pieces[1:]) - - -class IClientAuthentication(Interface): - def getName(): - """Return an identifier associated with this authentication scheme. - - @rtype: C{str} - """ - - def challengeResponse(secret, challenge): - """Generate a challenge response string""" - - - -class CramMD5ClientAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "CRAM-MD5" - - def challengeResponse(self, secret, chal): - response = hmac.HMAC(secret, chal).hexdigest() - return '%s %s' % (self.user, response) - - - -class LOGINAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - self.challengeResponse = self.challengeUsername - - def getName(self): - return "LOGIN" - - def challengeUsername(self, secret, chal): - # Respond to something like "Username:" - self.challengeResponse = self.challengeSecret - return self.user - - def challengeSecret(self, secret, chal): - # Respond to something like "Password:" - return secret - -class PLAINAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "PLAIN" - - def challengeResponse(self, secret, chal): - return '\0%s\0%s' % (self.user, secret) - - -class MailboxException(IMAP4Exception): pass - -class MailboxCollision(MailboxException): - def __str__(self): - return 'Mailbox named %s already exists' % self.args - -class NoSuchMailbox(MailboxException): - def __str__(self): - return 'No mailbox named %s exists' % self.args - -class ReadOnlyMailbox(MailboxException): - def __str__(self): - return 'Mailbox open in read-only state' - - -class IAccount(Interface): - """Interface for Account classes - - Implementors of this interface should consider implementing - C{INamespacePresenter}. - """ - - def addMailbox(name, mbox = None): - """Add a new mailbox to this account - - @type name: C{str} - @param name: The name associated with this mailbox. It may not - contain multiple hierarchical parts. - - @type mbox: An object implementing C{IMailbox} - @param mbox: The mailbox to associate with this name. If C{None}, - a suitable default is created and used. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the creation succeeds, or a deferred whose - callback will be invoked when the creation succeeds. - - @raise MailboxException: Raised if this mailbox cannot be added for - some reason. This may also be raised asynchronously, if a C{Deferred} - is returned. - """ - - def create(pathspec): - """Create a new mailbox from the given hierarchical name. - - @type pathspec: C{str} - @param pathspec: The full hierarchical name of a new mailbox to create. - If any of the inferior hierarchical names to this one do not exist, - they are created as well. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the creation succeeds, or a deferred whose - callback will be invoked when the creation succeeds. - - @raise MailboxException: Raised if this mailbox cannot be added. - This may also be raised asynchronously, if a C{Deferred} is - returned. - """ - - def select(name, rw=True): - """Acquire a mailbox, given its name. - - @type name: C{str} - @param name: The mailbox to acquire - - @type rw: C{bool} - @param rw: If a true value, request a read-write version of this - mailbox. If a false value, request a read-only version. - - @rtype: Any object implementing C{IMailbox} or C{Deferred} - @return: The mailbox object, or a C{Deferred} whose callback will - be invoked with the mailbox object. None may be returned if the - specified mailbox may not be selected for any reason. - """ - - def delete(name): - """Delete the mailbox with the specified name. - - @type name: C{str} - @param name: The mailbox to delete. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is successfully deleted, or a - C{Deferred} whose callback will be invoked when the deletion - completes. - - @raise MailboxException: Raised if this mailbox cannot be deleted. - This may also be raised asynchronously, if a C{Deferred} is returned. - """ - - def rename(oldname, newname): - """Rename a mailbox - - @type oldname: C{str} - @param oldname: The current name of the mailbox to rename. - - @type newname: C{str} - @param newname: The new name to associate with the mailbox. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is successfully renamed, or a - C{Deferred} whose callback will be invoked when the rename operation - is completed. - - @raise MailboxException: Raised if this mailbox cannot be - renamed. This may also be raised asynchronously, if a C{Deferred} - is returned. - """ - - def isSubscribed(name): - """Check the subscription status of a mailbox - - @type name: C{str} - @param name: The name of the mailbox to check - - @rtype: C{Deferred} or C{bool} - @return: A true value if the given mailbox is currently subscribed - to, a false value otherwise. A C{Deferred} may also be returned - whose callback will be invoked with one of these values. - """ - - def subscribe(name): - """Subscribe to a mailbox - - @type name: C{str} - @param name: The name of the mailbox to subscribe to - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is subscribed to successfully, - or a Deferred whose callback will be invoked with this value when - the subscription is successful. - - @raise MailboxException: Raised if this mailbox cannot be - subscribed to. This may also be raised asynchronously, if a - C{Deferred} is returned. - """ - - def unsubscribe(name): - """Unsubscribe from a mailbox - - @type name: C{str} - @param name: The name of the mailbox to unsubscribe from - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is unsubscribed from successfully, - or a Deferred whose callback will be invoked with this value when - the unsubscription is successful. - - @raise MailboxException: Raised if this mailbox cannot be - unsubscribed from. This may also be raised asynchronously, if a - C{Deferred} is returned. - """ - - def listMailboxes(ref, wildcard): - """List all the mailboxes that meet a certain criteria - - @type ref: C{str} - @param ref: The context in which to apply the wildcard - - @type wildcard: C{str} - @param wildcard: An expression against which to match mailbox names. - '*' matches any number of characters in a mailbox name, and '%' - matches similarly, but will not match across hierarchical boundaries. - - @rtype: C{list} of C{tuple} - @return: A list of C{(mailboxName, mailboxObject)} which meet the - given criteria. C{mailboxObject} should implement either - C{IMailboxInfo} or C{IMailbox}. A Deferred may also be returned. - """ - -class INamespacePresenter(Interface): - def getPersonalNamespaces(): - """Report the available personal namespaces. - - Typically there should be only one personal namespace. A common - name for it is \"\", and its hierarchical delimiter is usually - \"/\". - - @rtype: iterable of two-tuples of strings - @return: The personal namespaces and their hierarchical delimiters. - If no namespaces of this type exist, None should be returned. - """ - - def getSharedNamespaces(): - """Report the available shared namespaces. - - Shared namespaces do not belong to any individual user but are - usually to one or more of them. Examples of shared namespaces - might be \"#news\" for a usenet gateway. - - @rtype: iterable of two-tuples of strings - @return: The shared namespaces and their hierarchical delimiters. - If no namespaces of this type exist, None should be returned. - """ - - def getUserNamespaces(): - """Report the available user namespaces. - - These are namespaces that contain folders belonging to other users - access to which this account has been granted. - - @rtype: iterable of two-tuples of strings - @return: The user namespaces and their hierarchical delimiters. - If no namespaces of this type exist, None should be returned. - """ - - -class MemoryAccount(object): - implements(IAccount, INamespacePresenter) - - mailboxes = None - subscriptions = None - top_id = 0 - - def __init__(self, name): - self.name = name - self.mailboxes = {} - self.subscriptions = [] - - def allocateID(self): - id = self.top_id - self.top_id += 1 - return id - - ## - ## IAccount - ## - def addMailbox(self, name, mbox = None): - name = name.upper() - if name in self.mailboxes: - raise MailboxCollision, name - if mbox is None: - mbox = self._emptyMailbox(name, self.allocateID()) - self.mailboxes[name] = mbox - return 1 - - def create(self, pathspec): - paths = filter(None, pathspec.split('/')) - for accum in range(1, len(paths)): - try: - self.addMailbox('/'.join(paths[:accum])) - except MailboxCollision: - pass - try: - self.addMailbox('/'.join(paths)) - except MailboxCollision: - if not pathspec.endswith('/'): - return False - return True - - def _emptyMailbox(self, name, id): - raise NotImplementedError - - def select(self, name, readwrite=1): - return self.mailboxes.get(name.upper()) - - def delete(self, name): - name = name.upper() - # See if this mailbox exists at all - mbox = self.mailboxes.get(name) - if not mbox: - raise MailboxException("No such mailbox") - # See if this box is flagged \Noselect - if r'\Noselect' in mbox.getFlags(): - # Check for hierarchically inferior mailboxes with this one - # as part of their root. - for others in self.mailboxes.keys(): - if others != name and others.startswith(name): - raise MailboxException, "Hierarchically inferior mailboxes exist and \\Noselect is set" - mbox.destroy() - - # iff there are no hierarchically inferior names, we will - # delete it from our ken. - if self._inferiorNames(name) > 1: - del self.mailboxes[name] - - def rename(self, oldname, newname): - oldname = oldname.upper() - newname = newname.upper() - if oldname not in self.mailboxes: - raise NoSuchMailbox, oldname - - inferiors = self._inferiorNames(oldname) - inferiors = [(o, o.replace(oldname, newname, 1)) for o in inferiors] - - for (old, new) in inferiors: - if new in self.mailboxes: - raise MailboxCollision, new - - for (old, new) in inferiors: - self.mailboxes[new] = self.mailboxes[old] - del self.mailboxes[old] - - def _inferiorNames(self, name): - inferiors = [] - for infname in self.mailboxes.keys(): - if infname.startswith(name): - inferiors.append(infname) - return inferiors - - def isSubscribed(self, name): - return name.upper() in self.subscriptions - - def subscribe(self, name): - name = name.upper() - if name not in self.subscriptions: - self.subscriptions.append(name) - - def unsubscribe(self, name): - name = name.upper() - if name not in self.subscriptions: - raise MailboxException, "Not currently subscribed to " + name - self.subscriptions.remove(name) - - def listMailboxes(self, ref, wildcard): - ref = self._inferiorNames(ref.upper()) - wildcard = wildcardToRegexp(wildcard, '/') - return [(i, self.mailboxes[i]) for i in ref if wildcard.match(i)] - - ## - ## INamespacePresenter - ## - def getPersonalNamespaces(self): - return [["", "/"]] - - def getSharedNamespaces(self): - return None - - def getOtherNamespaces(self): - return None - - - -_statusRequestDict = { - 'MESSAGES': 'getMessageCount', - 'RECENT': 'getRecentCount', - 'UIDNEXT': 'getUIDNext', - 'UIDVALIDITY': 'getUIDValidity', - 'UNSEEN': 'getUnseenCount' -} -def statusRequestHelper(mbox, names): - r = {} - for n in names: - r[n] = getattr(mbox, _statusRequestDict[n.upper()])() - return r - -def parseAddr(addr): - if addr is None: - return [(None, None, None),] - addr = email.Utils.getaddresses([addr]) - return [[fn or None, None] + address.split('@') for fn, address in addr] - -def getEnvelope(msg): - headers = msg.getHeaders(True) - date = headers.get('date') - subject = headers.get('subject') - from_ = headers.get('from') - sender = headers.get('sender', from_) - reply_to = headers.get('reply-to', from_) - to = headers.get('to') - cc = headers.get('cc') - bcc = headers.get('bcc') - in_reply_to = headers.get('in-reply-to') - mid = headers.get('message-id') - return (date, subject, parseAddr(from_), parseAddr(sender), - reply_to and parseAddr(reply_to), to and parseAddr(to), - cc and parseAddr(cc), bcc and parseAddr(bcc), in_reply_to, mid) - -def getLineCount(msg): - # XXX - Super expensive, CACHE THIS VALUE FOR LATER RE-USE - # XXX - This must be the number of lines in the ENCODED version - lines = 0 - for _ in msg.getBodyFile(): - lines += 1 - return lines - -def unquote(s): - if s[0] == s[-1] == '"': - return s[1:-1] - return s - - -def _getContentType(msg): - """ - Return a two-tuple of the main and subtype of the given message. - """ - attrs = None - mm = msg.getHeaders(False, 'content-type').get('content-type', None) - if mm: - mm = ''.join(mm.splitlines()) - mimetype = mm.split(';') - if mimetype: - type = mimetype[0].split('/', 1) - if len(type) == 1: - major = type[0] - minor = None - elif len(type) == 2: - major, minor = type - else: - major = minor = None - attrs = dict(x.strip().lower().split('=', 1) for x in mimetype[1:]) - else: - major = minor = None - else: - major = minor = None - return major, minor, attrs - - - -def _getMessageStructure(message): - """ - Construct an appropriate type of message structure object for the given - message object. - - @param message: A L{IMessagePart} provider - - @return: A L{_MessageStructure} instance of the most specific type available - for the given message, determined by inspecting the MIME type of the - message. - """ - main, subtype, attrs = _getContentType(message) - if main is not None: - main = main.lower() - if subtype is not None: - subtype = subtype.lower() - if main == 'multipart': - return _MultipartMessageStructure(message, subtype, attrs) - elif (main, subtype) == ('message', 'rfc822'): - return _RFC822MessageStructure(message, main, subtype, attrs) - elif main == 'text': - return _TextMessageStructure(message, main, subtype, attrs) - else: - return _SinglepartMessageStructure(message, main, subtype, attrs) - - - -class _MessageStructure(object): - """ - L{_MessageStructure} is a helper base class for message structure classes - representing the structure of particular kinds of messages, as defined by - their MIME type. - """ - def __init__(self, message, attrs): - """ - @param message: An L{IMessagePart} provider which this structure object - reports on. - - @param attrs: A C{dict} giving the parameters of the I{Content-Type} - header of the message. - """ - self.message = message - self.attrs = attrs - - - def _disposition(self, disp): - """ - Parse a I{Content-Disposition} header into a two-sequence of the - disposition and a flattened list of its parameters. - - @return: C{None} if there is no disposition header value, a C{list} with - two elements otherwise. - """ - if disp: - disp = disp.split('; ') - if len(disp) == 1: - disp = (disp[0].lower(), None) - elif len(disp) > 1: - # XXX Poorly tested parser - params = [x for param in disp[1:] for x in param.split('=', 1)] - disp = [disp[0].lower(), params] - return disp - else: - return None - - - def _unquotedAttrs(self): - """ - @return: The I{Content-Type} parameters, unquoted, as a flat list with - each Nth element giving a parameter name and N+1th element giving - the corresponding parameter value. - """ - if self.attrs: - unquoted = [(k, unquote(v)) for (k, v) in self.attrs.iteritems()] - return [y for x in sorted(unquoted) for y in x] - return None - - - -class _SinglepartMessageStructure(_MessageStructure): - """ - L{_SinglepartMessageStructure} represents the message structure of a - non-I{multipart/*} message. - """ - _HEADERS = [ - 'content-id', 'content-description', - 'content-transfer-encoding'] - - def __init__(self, message, main, subtype, attrs): - """ - @param message: An L{IMessagePart} provider which this structure object - reports on. - - @param main: A C{str} giving the main MIME type of the message (for - example, C{"text"}). - - @param subtype: A C{str} giving the MIME subtype of the message (for - example, C{"plain"}). - - @param attrs: A C{dict} giving the parameters of the I{Content-Type} - header of the message. - """ - _MessageStructure.__init__(self, message, attrs) - self.main = main - self.subtype = subtype - self.attrs = attrs - - - def _basicFields(self): - """ - Return a list of the basic fields for a single-part message. - """ - headers = self.message.getHeaders(False, *self._HEADERS) - - # Number of octets total - size = self.message.getSize() - - major, minor = self.main, self.subtype - - # content-type parameter list - unquotedAttrs = self._unquotedAttrs() - - return [ - major, minor, unquotedAttrs, - headers.get('content-id'), - headers.get('content-description'), - headers.get('content-transfer-encoding'), - size, - ] - - - def encode(self, extended): - """ - Construct and return a list of the basic and extended fields for a - single-part message. The list suitable to be encoded into a BODY or - BODYSTRUCTURE response. - """ - result = self._basicFields() - if extended: - result.extend(self._extended()) - return result - - - def _extended(self): - """ - The extension data of a non-multipart body part are in the - following order: - - 1. body MD5 - - A string giving the body MD5 value as defined in [MD5]. - - 2. body disposition - - A parenthesized list with the same content and function as - the body disposition for a multipart body part. - - 3. body language - - A string or parenthesized list giving the body language - value as defined in [LANGUAGE-TAGS]. - - 4. body location - - A string list giving the body content URI as defined in - [LOCATION]. - - """ - result = [] - headers = self.message.getHeaders( - False, 'content-md5', 'content-disposition', - 'content-language', 'content-language') - - result.append(headers.get('content-md5')) - result.append(self._disposition(headers.get('content-disposition'))) - result.append(headers.get('content-language')) - result.append(headers.get('content-location')) - - return result - - - -class _TextMessageStructure(_SinglepartMessageStructure): - """ - L{_TextMessageStructure} represents the message structure of a I{text/*} - message. - """ - def encode(self, extended): - """ - A body type of type TEXT contains, immediately after the basic - fields, the size of the body in text lines. Note that this - size is the size in its content transfer encoding and not the - resulting size after any decoding. - """ - result = _SinglepartMessageStructure._basicFields(self) - result.append(getLineCount(self.message)) - if extended: - result.extend(self._extended()) - return result - - - -class _RFC822MessageStructure(_SinglepartMessageStructure): - """ - L{_RFC822MessageStructure} represents the message structure of a - I{message/rfc822} message. - """ - def encode(self, extended): - """ - A body type of type MESSAGE and subtype RFC822 contains, - immediately after the basic fields, the envelope structure, - body structure, and size in text lines of the encapsulated - message. - """ - result = _SinglepartMessageStructure.encode(self, extended) - contained = self.message.getSubPart(0) - result.append(getEnvelope(contained)) - result.append(getBodyStructure(contained, False)) - result.append(getLineCount(contained)) - return result - - - -class _MultipartMessageStructure(_MessageStructure): - """ - L{_MultipartMessageStructure} represents the message structure of a - I{multipart/*} message. - """ - def __init__(self, message, subtype, attrs): - """ - @param message: An L{IMessagePart} provider which this structure object - reports on. - - @param subtype: A C{str} giving the MIME subtype of the message (for - example, C{"plain"}). - - @param attrs: A C{dict} giving the parameters of the I{Content-Type} - header of the message. - """ - _MessageStructure.__init__(self, message, attrs) - self.subtype = subtype - - - def _getParts(self): - """ - Return an iterator over all of the sub-messages of this message. - """ - i = 0 - while True: - try: - part = self.message.getSubPart(i) - except IndexError: - break - else: - yield part - i += 1 - - - def encode(self, extended): - """ - Encode each sub-message and added the additional I{multipart} fields. - """ - result = [_getMessageStructure(p).encode(extended) for p in self._getParts()] - result.append(self.subtype) - if extended: - result.extend(self._extended()) - return result - - - def _extended(self): - """ - The extension data of a multipart body part are in the following order: - - 1. body parameter parenthesized list - A parenthesized list of attribute/value pairs [e.g., ("foo" - "bar" "baz" "rag") where "bar" is the value of "foo", and - "rag" is the value of "baz"] as defined in [MIME-IMB]. - - 2. body disposition - A parenthesized list, consisting of a disposition type - string, followed by a parenthesized list of disposition - attribute/value pairs as defined in [DISPOSITION]. - - 3. body language - A string or parenthesized list giving the body language - value as defined in [LANGUAGE-TAGS]. - - 4. body location - A string list giving the body content URI as defined in - [LOCATION]. - """ - result = [] - headers = self.message.getHeaders( - False, 'content-language', 'content-location', - 'content-disposition') - - result.append(self._unquotedAttrs()) - result.append(self._disposition(headers.get('content-disposition'))) - result.append(headers.get('content-language', None)) - result.append(headers.get('content-location', None)) - - return result - - - -def getBodyStructure(msg, extended=False): - """ - RFC 3501, 7.4.2, BODYSTRUCTURE:: - - A parenthesized list that describes the [MIME-IMB] body structure of a - message. This is computed by the server by parsing the [MIME-IMB] header - fields, defaulting various fields as necessary. - - For example, a simple text message of 48 lines and 2279 octets can have - a body structure of: ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL - "7BIT" 2279 48) - - This is represented as:: - - ["TEXT", "PLAIN", ["CHARSET", "US-ASCII"], None, None, "7BIT", 2279, 48] - - These basic fields are documented in the RFC as: - - 1. body type - - A string giving the content media type name as defined in - [MIME-IMB]. - - 2. body subtype - - A string giving the content subtype name as defined in - [MIME-IMB]. - - 3. body parameter parenthesized list - - A parenthesized list of attribute/value pairs [e.g., ("foo" - "bar" "baz" "rag") where "bar" is the value of "foo" and - "rag" is the value of "baz"] as defined in [MIME-IMB]. - - 4. body id - - A string giving the content id as defined in [MIME-IMB]. - - 5. body description - - A string giving the content description as defined in - [MIME-IMB]. - - 6. body encoding - - A string giving the content transfer encoding as defined in - [MIME-IMB]. - - 7. body size - - A number giving the size of the body in octets. Note that this size is - the size in its transfer encoding and not the resulting size after any - decoding. - - Put another way, the body structure is a list of seven elements. The - semantics of the elements of this list are: - - 1. Byte string giving the major MIME type - 2. Byte string giving the minor MIME type - 3. A list giving the Content-Type parameters of the message - 4. A byte string giving the content identifier for the message part, or - None if it has no content identifier. - 5. A byte string giving the content description for the message part, or - None if it has no content description. - 6. A byte string giving the Content-Encoding of the message body - 7. An integer giving the number of octets in the message body - - The RFC goes on:: - - Multiple parts are indicated by parenthesis nesting. Instead of a body - type as the first element of the parenthesized list, there is a sequence - of one or more nested body structures. The second element of the - parenthesized list is the multipart subtype (mixed, digest, parallel, - alternative, etc.). - - For example, a two part message consisting of a text and a - BASE64-encoded text attachment can have a body structure of: (("TEXT" - "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152 23)("TEXT" "PLAIN" - ("CHARSET" "US-ASCII" "NAME" "cc.diff") - "<960723163407.20117h@cac.washington.edu>" "Compiler diff" "BASE64" 4554 - 73) "MIXED") - - This is represented as:: - - [["TEXT", "PLAIN", ["CHARSET", "US-ASCII"], None, None, "7BIT", 1152, - 23], - ["TEXT", "PLAIN", ["CHARSET", "US-ASCII", "NAME", "cc.diff"], - "<960723163407.20117h@cac.washington.edu>", "Compiler diff", - "BASE64", 4554, 73], - "MIXED"] - - In other words, a list of N + 1 elements, where N is the number of parts in - the message. The first N elements are structures as defined by the previous - section. The last element is the minor MIME subtype of the multipart - message. - - Additionally, the RFC describes extension data:: - - Extension data follows the multipart subtype. Extension data is never - returned with the BODY fetch, but can be returned with a BODYSTRUCTURE - fetch. Extension data, if present, MUST be in the defined order. - - The C{extended} flag controls whether extension data might be returned with - the normal data. - """ - return _getMessageStructure(msg).encode(extended) - - - -class IMessagePart(Interface): - def getHeaders(negate, *names): - """Retrieve a group of message headers. - - @type names: C{tuple} of C{str} - @param names: The names of the headers to retrieve or omit. - - @type negate: C{bool} - @param negate: If True, indicates that the headers listed in C{names} - should be omitted from the return value, rather than included. - - @rtype: C{dict} - @return: A mapping of header field names to header field values - """ - - def getBodyFile(): - """Retrieve a file object containing only the body of this message. - """ - - def getSize(): - """Retrieve the total size, in octets, of this message. - - @rtype: C{int} - """ - - def isMultipart(): - """Indicate whether this message has subparts. - - @rtype: C{bool} - """ - - def getSubPart(part): - """Retrieve a MIME sub-message - - @type part: C{int} - @param part: The number of the part to retrieve, indexed from 0. - - @raise IndexError: Raised if the specified part does not exist. - @raise TypeError: Raised if this message is not multipart. - - @rtype: Any object implementing C{IMessagePart}. - @return: The specified sub-part. - """ - -class IMessage(IMessagePart): - def getUID(): - """Retrieve the unique identifier associated with this message. - """ - - def getFlags(): - """Retrieve the flags associated with this message. - - @rtype: C{iterable} - @return: The flags, represented as strings. - """ - - def getInternalDate(): - """Retrieve the date internally associated with this message. - - @rtype: C{str} - @return: An RFC822-formatted date string. - """ - -class IMessageFile(Interface): - """Optional message interface for representing messages as files. - - If provided by message objects, this interface will be used instead - the more complex MIME-based interface. - """ - def open(): - """Return an file-like object opened for reading. - - Reading from the returned file will return all the bytes - of which this message consists. - """ - -class ISearchableMailbox(Interface): - def search(query, uid): - """Search for messages that meet the given query criteria. - - If this interface is not implemented by the mailbox, L{IMailbox.fetch} - and various methods of L{IMessage} will be used instead. - - Implementations which wish to offer better performance than the - default implementation should implement this interface. - - @type query: C{list} - @param query: The search criteria - - @type uid: C{bool} - @param uid: If true, the IDs specified in the query are UIDs; - otherwise they are message sequence IDs. - - @rtype: C{list} or C{Deferred} - @return: A list of message sequence numbers or message UIDs which - match the search criteria or a C{Deferred} whose callback will be - invoked with such a list. - - @raise IllegalQueryError: Raised when query is not valid. - """ - -class IMessageCopier(Interface): - def copy(messageObject): - """Copy the given message object into this mailbox. - - The message object will be one which was previously returned by - L{IMailbox.fetch}. - - Implementations which wish to offer better performance than the - default implementation should implement this interface. - - If this interface is not implemented by the mailbox, IMailbox.addMessage - will be used instead. - - @rtype: C{Deferred} or C{int} - @return: Either the UID of the message or a Deferred which fires - with the UID when the copy finishes. - """ - -class IMailboxInfo(Interface): - """Interface specifying only the methods required for C{listMailboxes}. - - Implementations can return objects implementing only these methods for - return to C{listMailboxes} if it can allow them to operate more - efficiently. - """ - - def getFlags(): - """Return the flags defined in this mailbox - - Flags with the \\ prefix are reserved for use as system flags. - - @rtype: C{list} of C{str} - @return: A list of the flags that can be set on messages in this mailbox. - """ - - def getHierarchicalDelimiter(): - """Get the character which delimits namespaces for in this mailbox. - - @rtype: C{str} - """ - -class IMailbox(IMailboxInfo): - def getUIDValidity(): - """Return the unique validity identifier for this mailbox. - - @rtype: C{int} - """ - - def getUIDNext(): - """Return the likely UID for the next message added to this mailbox. - - @rtype: C{int} - """ - - def getUID(message): - """Return the UID of a message in the mailbox - - @type message: C{int} - @param message: The message sequence number - - @rtype: C{int} - @return: The UID of the message. - """ - - def getMessageCount(): - """Return the number of messages in this mailbox. - - @rtype: C{int} - """ - - def getRecentCount(): - """Return the number of messages with the 'Recent' flag. - - @rtype: C{int} - """ - - def getUnseenCount(): - """Return the number of messages with the 'Unseen' flag. - - @rtype: C{int} - """ - - def isWriteable(): - """Get the read/write status of the mailbox. - - @rtype: C{int} - @return: A true value if write permission is allowed, a false value otherwise. - """ - - def destroy(): - """Called before this mailbox is deleted, permanently. - - If necessary, all resources held by this mailbox should be cleaned - up here. This function _must_ set the \\Noselect flag on this - mailbox. - """ - - def requestStatus(names): - """Return status information about this mailbox. - - Mailboxes which do not intend to do any special processing to - generate the return value, C{statusRequestHelper} can be used - to build the dictionary by calling the other interface methods - which return the data for each name. - - @type names: Any iterable - @param names: The status names to return information regarding. - The possible values for each name are: MESSAGES, RECENT, UIDNEXT, - UIDVALIDITY, UNSEEN. - - @rtype: C{dict} or C{Deferred} - @return: A dictionary containing status information about the - requested names is returned. If the process of looking this - information up would be costly, a deferred whose callback will - eventually be passed this dictionary is returned instead. - """ - - def addListener(listener): - """Add a mailbox change listener - - @type listener: Any object which implements C{IMailboxListener} - @param listener: An object to add to the set of those which will - be notified when the contents of this mailbox change. - """ - - def removeListener(listener): - """Remove a mailbox change listener - - @type listener: Any object previously added to and not removed from - this mailbox as a listener. - @param listener: The object to remove from the set of listeners. - - @raise ValueError: Raised when the given object is not a listener for - this mailbox. - """ - - def addMessage(message, flags = (), date = None): - """Add the given message to this mailbox. - - @type message: A file-like object - @param message: The RFC822 formatted message - - @type flags: Any iterable of C{str} - @param flags: The flags to associate with this message - - @type date: C{str} - @param date: If specified, the date to associate with this - message. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with the message - id if the message is added successfully and whose errback is - invoked otherwise. - - @raise ReadOnlyMailbox: Raised if this Mailbox is not open for - read-write. - """ - - def expunge(): - """Remove all messages flagged \\Deleted. - - @rtype: C{list} or C{Deferred} - @return: The list of message sequence numbers which were deleted, - or a C{Deferred} whose callback will be invoked with such a list. - - @raise ReadOnlyMailbox: Raised if this Mailbox is not open for - read-write. - """ - - def fetch(messages, uid): - """Retrieve one or more messages. - - @type messages: C{MessageSet} - @param messages: The identifiers of messages to retrieve information - about - - @type uid: C{bool} - @param uid: If true, the IDs specified in the query are UIDs; - otherwise they are message sequence IDs. - - @rtype: Any iterable of two-tuples of message sequence numbers and - implementors of C{IMessage}. - """ - - def store(messages, flags, mode, uid): - """Set the flags of one or more messages. - - @type messages: A MessageSet object with the list of messages requested - @param messages: The identifiers of the messages to set the flags of. - - @type flags: sequence of C{str} - @param flags: The flags to set, unset, or add. - - @type mode: -1, 0, or 1 - @param mode: If mode is -1, these flags should be removed from the - specified messages. If mode is 1, these flags should be added to - the specified messages. If mode is 0, all existing flags should be - cleared and these flags should be added. - - @type uid: C{bool} - @param uid: If true, the IDs specified in the query are UIDs; - otherwise they are message sequence IDs. - - @rtype: C{dict} or C{Deferred} - @return: A C{dict} mapping message sequence numbers to sequences of C{str} - representing the flags set on the message after this operation has - been performed, or a C{Deferred} whose callback will be invoked with - such a C{dict}. - - @raise ReadOnlyMailbox: Raised if this mailbox is not open for - read-write. - """ - -class ICloseableMailbox(Interface): - """A supplementary interface for mailboxes which require cleanup on close. - - Implementing this interface is optional. If it is implemented, the protocol - code will call the close method defined whenever a mailbox is closed. - """ - def close(): - """Close this mailbox. - - @return: A C{Deferred} which fires when this mailbox - has been closed, or None if the mailbox can be closed - immediately. - """ - -def _formatHeaders(headers): - hdrs = [': '.join((k.title(), '\r\n'.join(v.splitlines()))) for (k, v) - in headers.iteritems()] - hdrs = '\r\n'.join(hdrs) + '\r\n' - return hdrs - -def subparts(m): - i = 0 - try: - while True: - yield m.getSubPart(i) - i += 1 - except IndexError: - pass - -def iterateInReactor(i): - """Consume an interator at most a single iteration per reactor iteration. - - If the iterator produces a Deferred, the next iteration will not occur - until the Deferred fires, otherwise the next iteration will be taken - in the next reactor iteration. - - @rtype: C{Deferred} - @return: A deferred which fires (with None) when the iterator is - exhausted or whose errback is called if there is an exception. - """ - from twisted.internet import reactor - d = defer.Deferred() - def go(last): - try: - r = i.next() - except StopIteration: - d.callback(last) - except: - d.errback() - else: - if isinstance(r, defer.Deferred): - r.addCallback(go) - else: - reactor.callLater(0, go, r) - go(None) - return d - -class MessageProducer: - CHUNK_SIZE = 2 ** 2 ** 2 ** 2 - - def __init__(self, msg, buffer = None, scheduler = None): - """Produce this message. - - @param msg: The message I am to produce. - @type msg: L{IMessage} - - @param buffer: A buffer to hold the message in. If None, I will - use a L{tempfile.TemporaryFile}. - @type buffer: file-like - """ - self.msg = msg - if buffer is None: - buffer = tempfile.TemporaryFile() - self.buffer = buffer - if scheduler is None: - scheduler = iterateInReactor - self.scheduler = scheduler - self.write = self.buffer.write - - def beginProducing(self, consumer): - self.consumer = consumer - return self.scheduler(self._produce()) - - def _produce(self): - headers = self.msg.getHeaders(True) - boundary = None - if self.msg.isMultipart(): - content = headers.get('content-type') - parts = [x.split('=', 1) for x in content.split(';')[1:]] - parts = dict([(k.lower().strip(), v) for (k, v) in parts]) - boundary = parts.get('boundary') - if boundary is None: - # Bastards - boundary = '----=_%f_boundary_%f' % (time.time(), random.random()) - headers['content-type'] += '; boundary="%s"' % (boundary,) - else: - if boundary.startswith('"') and boundary.endswith('"'): - boundary = boundary[1:-1] - - self.write(_formatHeaders(headers)) - self.write('\r\n') - if self.msg.isMultipart(): - for p in subparts(self.msg): - self.write('\r\n--%s\r\n' % (boundary,)) - yield MessageProducer(p, self.buffer, self.scheduler - ).beginProducing(None - ) - self.write('\r\n--%s--\r\n' % (boundary,)) - else: - f = self.msg.getBodyFile() - while True: - b = f.read(self.CHUNK_SIZE) - if b: - self.buffer.write(b) - yield None - else: - break - if self.consumer: - self.buffer.seek(0, 0) - yield FileProducer(self.buffer - ).beginProducing(self.consumer - ).addCallback(lambda _: self - ) - -class _FetchParser: - class Envelope: - # Response should be a list of fields from the message: - # date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, - # and message-id. - # - # from, sender, reply-to, to, cc, and bcc are themselves lists of - # address information: - # personal name, source route, mailbox name, host name - # - # reply-to and sender must not be None. If not present in a message - # they should be defaulted to the value of the from field. - type = 'envelope' - __str__ = lambda self: 'envelope' - - class Flags: - type = 'flags' - __str__ = lambda self: 'flags' - - class InternalDate: - type = 'internaldate' - __str__ = lambda self: 'internaldate' - - class RFC822Header: - type = 'rfc822header' - __str__ = lambda self: 'rfc822.header' - - class RFC822Text: - type = 'rfc822text' - __str__ = lambda self: 'rfc822.text' - - class RFC822Size: - type = 'rfc822size' - __str__ = lambda self: 'rfc822.size' - - class RFC822: - type = 'rfc822' - __str__ = lambda self: 'rfc822' - - class UID: - type = 'uid' - __str__ = lambda self: 'uid' - - class Body: - type = 'body' - peek = False - header = None - mime = None - text = None - part = () - empty = False - partialBegin = None - partialLength = None - def __str__(self): - base = 'BODY' - part = '' - separator = '' - if self.part: - part = '.'.join([str(x + 1) for x in self.part]) - separator = '.' -# if self.peek: -# base += '.PEEK' - if self.header: - base += '[%s%s%s]' % (part, separator, self.header,) - elif self.text: - base += '[%s%sTEXT]' % (part, separator) - elif self.mime: - base += '[%s%sMIME]' % (part, separator) - elif self.empty: - base += '[%s]' % (part,) - if self.partialBegin is not None: - base += '<%d.%d>' % (self.partialBegin, self.partialLength) - return base - - class BodyStructure: - type = 'bodystructure' - __str__ = lambda self: 'bodystructure' - - # These three aren't top-level, they don't need type indicators - class Header: - negate = False - fields = None - part = None - def __str__(self): - base = 'HEADER' - if self.fields: - base += '.FIELDS' - if self.negate: - base += '.NOT' - fields = [] - for f in self.fields: - f = f.title() - if _needsQuote(f): - f = _quote(f) - fields.append(f) - base += ' (%s)' % ' '.join(fields) - if self.part: - base = '.'.join([str(x + 1) for x in self.part]) + '.' + base - return base - - class Text: - pass - - class MIME: - pass - - parts = None - - _simple_fetch_att = [ - ('envelope', Envelope), - ('flags', Flags), - ('internaldate', InternalDate), - ('rfc822.header', RFC822Header), - ('rfc822.text', RFC822Text), - ('rfc822.size', RFC822Size), - ('rfc822', RFC822), - ('uid', UID), - ('bodystructure', BodyStructure), - ] - - def __init__(self): - self.state = ['initial'] - self.result = [] - self.remaining = '' - - def parseString(self, s): - s = self.remaining + s - try: - while s or self.state: - if not self.state: - raise IllegalClientResponse("Invalid Argument") - # print 'Entering state_' + self.state[-1] + ' with', repr(s) - state = self.state.pop() - try: - used = getattr(self, 'state_' + state)(s) - except: - self.state.append(state) - raise - else: - # print state, 'consumed', repr(s[:used]) - s = s[used:] - finally: - self.remaining = s - - def state_initial(self, s): - # In the initial state, the literals "ALL", "FULL", and "FAST" - # are accepted, as is a ( indicating the beginning of a fetch_att - # token, as is the beginning of a fetch_att token. - if s == '': - return 0 - - l = s.lower() - if l.startswith('all'): - self.result.extend(( - self.Flags(), self.InternalDate(), - self.RFC822Size(), self.Envelope() - )) - return 3 - if l.startswith('full'): - self.result.extend(( - self.Flags(), self.InternalDate(), - self.RFC822Size(), self.Envelope(), - self.Body() - )) - return 4 - if l.startswith('fast'): - self.result.extend(( - self.Flags(), self.InternalDate(), self.RFC822Size(), - )) - return 4 - - if l.startswith('('): - self.state.extend(('close_paren', 'maybe_fetch_att', 'fetch_att')) - return 1 - - self.state.append('fetch_att') - return 0 - - def state_close_paren(self, s): - if s.startswith(')'): - return 1 - raise Exception("Missing )") - - def state_whitespace(self, s): - # Eat up all the leading whitespace - if not s or not s[0].isspace(): - raise Exception("Whitespace expected, none found") - i = 0 - for i in range(len(s)): - if not s[i].isspace(): - break - return i - - def state_maybe_fetch_att(self, s): - if not s.startswith(')'): - self.state.extend(('maybe_fetch_att', 'fetch_att', 'whitespace')) - return 0 - - def state_fetch_att(self, s): - # Allowed fetch_att tokens are "ENVELOPE", "FLAGS", "INTERNALDATE", - # "RFC822", "RFC822.HEADER", "RFC822.SIZE", "RFC822.TEXT", "BODY", - # "BODYSTRUCTURE", "UID", - # "BODY [".PEEK"] [
] ["<" "." ">"] - - l = s.lower() - for (name, cls) in self._simple_fetch_att: - if l.startswith(name): - self.result.append(cls()) - return len(name) - - b = self.Body() - if l.startswith('body.peek'): - b.peek = True - used = 9 - elif l.startswith('body'): - used = 4 - else: - raise Exception("Nothing recognized in fetch_att: %s" % (l,)) - - self.pending_body = b - self.state.extend(('got_body', 'maybe_partial', 'maybe_section')) - return used - - def state_got_body(self, s): - self.result.append(self.pending_body) - del self.pending_body - return 0 - - def state_maybe_section(self, s): - if not s.startswith("["): - return 0 - - self.state.extend(('section', 'part_number')) - return 1 - - _partExpr = re.compile(r'(\d+(?:\.\d+)*)\.?') - def state_part_number(self, s): - m = self._partExpr.match(s) - if m is not None: - self.parts = [int(p) - 1 for p in m.groups()[0].split('.')] - return m.end() - else: - self.parts = [] - return 0 - - def state_section(self, s): - # Grab "HEADER]" or "HEADER.FIELDS (Header list)]" or - # "HEADER.FIELDS.NOT (Header list)]" or "TEXT]" or "MIME]" or - # just "]". - - l = s.lower() - used = 0 - if l.startswith(']'): - self.pending_body.empty = True - used += 1 - elif l.startswith('header]'): - h = self.pending_body.header = self.Header() - h.negate = True - h.fields = () - used += 7 - elif l.startswith('text]'): - self.pending_body.text = self.Text() - used += 5 - elif l.startswith('mime]'): - self.pending_body.mime = self.MIME() - used += 5 - else: - h = self.Header() - if l.startswith('header.fields.not'): - h.negate = True - used += 17 - elif l.startswith('header.fields'): - used += 13 - else: - raise Exception("Unhandled section contents: %r" % (l,)) - - self.pending_body.header = h - self.state.extend(('finish_section', 'header_list', 'whitespace')) - self.pending_body.part = tuple(self.parts) - self.parts = None - return used - - def state_finish_section(self, s): - if not s.startswith(']'): - raise Exception("section must end with ]") - return 1 - - def state_header_list(self, s): - if not s.startswith('('): - raise Exception("Header list must begin with (") - end = s.find(')') - if end == -1: - raise Exception("Header list must end with )") - - headers = s[1:end].split() - self.pending_body.header.fields = map(str.upper, headers) - return end + 1 - - def state_maybe_partial(self, s): - # Grab or nothing at all - if not s.startswith('<'): - return 0 - end = s.find('>') - if end == -1: - raise Exception("Found < but not >") - - partial = s[1:end] - parts = partial.split('.', 1) - if len(parts) != 2: - raise Exception("Partial specification did not include two .-delimited integers") - begin, length = map(int, parts) - self.pending_body.partialBegin = begin - self.pending_body.partialLength = length - - return end + 1 - -class FileProducer: - CHUNK_SIZE = 2 ** 2 ** 2 ** 2 - - firstWrite = True - - def __init__(self, f): - self.f = f - - def beginProducing(self, consumer): - self.consumer = consumer - self.produce = consumer.write - d = self._onDone = defer.Deferred() - self.consumer.registerProducer(self, False) - return d - - def resumeProducing(self): - b = '' - if self.firstWrite: - b = '{%d}\r\n' % self._size() - self.firstWrite = False - if not self.f: - return - b = b + self.f.read(self.CHUNK_SIZE) - if not b: - self.consumer.unregisterProducer() - self._onDone.callback(self) - self._onDone = self.f = self.consumer = None - else: - self.produce(b) - - def pauseProducing(self): - pass - - def stopProducing(self): - pass - - def _size(self): - b = self.f.tell() - self.f.seek(0, 2) - e = self.f.tell() - self.f.seek(b, 0) - return e - b - -def parseTime(s): - # XXX - This may require localization :( - months = [ - 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', - 'nov', 'dec', 'january', 'february', 'march', 'april', 'may', 'june', - 'july', 'august', 'september', 'october', 'november', 'december' - ] - expr = { - 'day': r"(?P3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", - 'mon': r"(?P\w+)", - 'year': r"(?P\d\d\d\d)" - } - m = re.match('%(day)s-%(mon)s-%(year)s' % expr, s) - if not m: - raise ValueError, "Cannot parse time string %r" % (s,) - d = m.groupdict() - try: - d['mon'] = 1 + (months.index(d['mon'].lower()) % 12) - d['year'] = int(d['year']) - d['day'] = int(d['day']) - except ValueError: - raise ValueError, "Cannot parse time string %r" % (s,) - else: - return time.struct_time( - (d['year'], d['mon'], d['day'], 0, 0, 0, -1, -1, -1) - ) - -import codecs -def modified_base64(s): - s_utf7 = s.encode('utf-7') - return s_utf7[1:-1].replace('/', ',') - -def modified_unbase64(s): - s_utf7 = '+' + s.replace(',', '/') + '-' - return s_utf7.decode('utf-7') - -def encoder(s, errors=None): - """ - Encode the given C{unicode} string using the IMAP4 specific variation of - UTF-7. - - @type s: C{unicode} - @param s: The text to encode. - - @param errors: Policy for handling encoding errors. Currently ignored. - - @return: C{tuple} of a C{str} giving the encoded bytes and an C{int} - giving the number of code units consumed from the input. - """ - r = [] - _in = [] - for c in s: - if ord(c) in (range(0x20, 0x26) + range(0x27, 0x7f)): - if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) - del _in[:] - r.append(str(c)) - elif c == '&': - if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) - del _in[:] - r.append('&-') - else: - _in.append(c) - if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) - return (''.join(r), len(s)) - -def decoder(s, errors=None): - """ - Decode the given C{str} using the IMAP4 specific variation of UTF-7. - - @type s: C{str} - @param s: The bytes to decode. - - @param errors: Policy for handling decoding errors. Currently ignored. - - @return: a C{tuple} of a C{unicode} string giving the text which was - decoded and an C{int} giving the number of bytes consumed from the - input. - """ - r = [] - decode = [] - for c in s: - if c == '&' and not decode: - decode.append('&') - elif c == '-' and decode: - if len(decode) == 1: - r.append('&') - else: - r.append(modified_unbase64(''.join(decode[1:]))) - decode = [] - elif decode: - decode.append(c) - else: - r.append(c) - if decode: - r.append(modified_unbase64(''.join(decode[1:]))) - return (''.join(r), len(s)) - -class StreamReader(codecs.StreamReader): - def decode(self, s, errors='strict'): - return decoder(s) - -class StreamWriter(codecs.StreamWriter): - def encode(self, s, errors='strict'): - return encoder(s) - -_codecInfo = (encoder, decoder, StreamReader, StreamWriter) -try: - _codecInfoClass = codecs.CodecInfo -except AttributeError: - pass -else: - _codecInfo = _codecInfoClass(*_codecInfo) - -def imap4_utf_7(name): - if name == 'imap4-utf-7': - return _codecInfo -codecs.register(imap4_utf_7) - -__all__ = [ - # Protocol classes - 'IMAP4Server', 'IMAP4Client', - - # Interfaces - 'IMailboxListener', 'IClientAuthentication', 'IAccount', 'IMailbox', - 'INamespacePresenter', 'ICloseableMailbox', 'IMailboxInfo', - 'IMessage', 'IMessageCopier', 'IMessageFile', 'ISearchableMailbox', - - # Exceptions - 'IMAP4Exception', 'IllegalClientResponse', 'IllegalOperation', - 'IllegalMailboxEncoding', 'UnhandledResponse', 'NegativeResponse', - 'NoSupportedAuthentication', 'IllegalServerResponse', - 'IllegalIdentifierError', 'IllegalQueryError', 'MismatchedNesting', - 'MismatchedQuoting', 'MailboxException', 'MailboxCollision', - 'NoSuchMailbox', 'ReadOnlyMailbox', - - # Auth objects - 'CramMD5ClientAuthenticator', 'PLAINAuthenticator', 'LOGINAuthenticator', - 'PLAINCredentials', 'LOGINCredentials', - - # Simple query interface - 'Query', 'Not', 'Or', - - # Miscellaneous - 'MemoryAccount', - 'statusRequestHelper', -] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/mail.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/mail.py deleted file mode 100644 index 8841a18..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/mail.py +++ /dev/null @@ -1,819 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Mail service support. -""" - -# Twisted imports -from twisted.internet import defer -from twisted.application import service, internet -from twisted.python import util -from twisted.python import log -from twisted.cred.portal import Portal - -# Sibling imports -from twisted.mail import protocols, smtp - -# System imports -import os -from zope.interface import implements, Interface - - -class DomainWithDefaultDict: - """ - A simulated dictionary for mapping domain names to domain objects with - a default value for non-existing keys. - - @ivar domains: See L{__init__} - @ivar default: See L{__init__} - """ - def __init__(self, domains, default): - """ - @type domains: L{dict} of L{bytes} -> L{IDomain} provider - @param domains: A mapping of domain name to domain object. - - @type default: L{IDomain} provider - @param default: The default domain. - """ - self.domains = domains - self.default = default - - - def setDefaultDomain(self, domain): - """ - Set the default domain. - - @type domain: L{IDomain} provider - @param domain: The default domain. - """ - self.default = domain - - - def has_key(self, name): - """ - Test for the presence of a domain name in this dictionary. - - This always returns C{True} because a default value will be returned - if the name doesn't exist in this dictionary. - - @type name: L{bytes} - @param name: A domain name. - - @rtype: L{bool} - @return: C{True} to indicate that the domain name is in this - dictionary. - """ - return 1 - - - def fromkeys(klass, keys, value=None): - """ - Create a new L{DomainWithDefaultDict} with the specified keys. - - @type keys: iterable of L{bytes} - @param keys: Domain names to serve as keys in the new dictionary. - - @type value: L{NoneType } or L{IDomain} provider - @param value: A domain object to serve as the value for all new keys - in the dictionary. - - @rtype: L{DomainWithDefaultDict} - @return: A new dictionary. - """ - d = klass() - for k in keys: - d[k] = value - return d - fromkeys = classmethod(fromkeys) - - - def __contains__(self, name): - """ - Test for the presence of a domain name in this dictionary. - - This always returns C{True} because a default value will be returned - if the name doesn't exist in this dictionary. - - @type name: L{bytes} - @param name: A domain name. - - @rtype: L{bool} - @return: C{True} to indicate that the domain name is in this - dictionary. - """ - return 1 - - - def __getitem__(self, name): - """ - Look up a domain name and, if it is present, return the domain object - associated with it. Otherwise return the default domain. - - @type name: L{bytes} - @param name: A domain name. - - @rtype: L{IDomain} provider or L{NoneType } - @return: A domain object. - """ - return self.domains.get(name, self.default) - - - def __setitem__(self, name, value): - """ - Associate a domain object with a domain name in this dictionary. - - @type name: L{bytes} - @param name: A domain name. - - @type value: L{IDomain} provider - @param value: A domain object. - """ - self.domains[name] = value - - - def __delitem__(self, name): - """ - Delete the entry for a domain name in this dictionary. - - @type name: L{bytes} - @param name: A domain name. - """ - del self.domains[name] - - - def __iter__(self): - """ - Return an iterator over the domain names in this dictionary. - - @rtype: iterator over L{bytes} - @return: An iterator over the domain names. - """ - return iter(self.domains) - - - def __len__(self): - """ - Return the number of domains in this dictionary. - - @rtype: L{int} - @return: The number of domains in this dictionary. - """ - return len(self.domains) - - - def __str__(self): - """ - Build an informal string representation of this dictionary. - - @rtype: L{bytes} - @return: A string containing the mapping of domain names to domain - objects. - """ - return '' % (self.domains,) - - - def __repr__(self): - """ - Build an "official" string representation of this dictionary. - - @rtype: L{bytes} - @return: A pseudo-executable string describing the underlying domain - mapping of this object. - """ - return 'DomainWithDefaultDict(%s)' % (self.domains,) - - - def get(self, key, default=None): - """ - Look up a domain name in this dictionary. - - @type key: L{bytes} - @param key: A domain name. - - @type default: L{IDomain} provider or L{NoneType } - @param default: A domain object to be returned if the domain name is - not in this dictionary. - - @rtype: L{IDomain} provider or L{NoneType } - @return: The domain object associated with the domain name if it is in - this dictionary. Otherwise, the default value. - """ - return self.domains.get(key, default) - - - def copy(self): - """ - Make a copy of this dictionary. - - @rtype: L{DomainWithDefaultDict} - @return: A copy of this dictionary. - """ - return DomainWithDefaultDict(self.domains.copy(), self.default) - - - def iteritems(self): - """ - Return an iterator over the domain name/domain object pairs in the - dictionary. - - Using the returned iterator while adding or deleting entries from the - dictionary may result in a L{RuntimeError } or - failing to iterate over all the domain name/domain object pairs. - - @rtype: iterator over 2-L{tuple} of (E{1}) L{bytes}, - (E{2}) L{IDomain} provider or L{NoneType } - @return: An iterator over the domain name/domain object pairs. - """ - return self.domains.iteritems() - - - def iterkeys(self): - """ - Return an iterator over the domain names in this dictionary. - - Using the returned iterator while adding or deleting entries from the - dictionary may result in a L{RuntimeError } or - failing to iterate over all the domain names. - - @rtype: iterator over L{bytes} - @return: An iterator over the domain names. - """ - return self.domains.iterkeys() - - - def itervalues(self): - """ - Return an iterator over the domain objects in this dictionary. - - Using the returned iterator while adding or deleting entries from the - dictionary may result in a L{RuntimeError } - or failing to iterate over all the domain objects. - - @rtype: iterator over L{IDomain} provider or - L{NoneType } - @return: An iterator over the domain objects. - """ - return self.domains.itervalues() - - - def keys(self): - """ - Return a list of all domain names in this dictionary. - - @rtype: L{list} of L{bytes} - @return: The domain names in this dictionary. - - """ - return self.domains.keys() - - - def values(self): - """ - Return a list of all domain objects in this dictionary. - - @rtype: L{list} of L{IDomain} provider or L{NoneType } - @return: The domain objects in this dictionary. - """ - return self.domains.values() - - - def items(self): - """ - Return a list of all domain name/domain object pairs in this - dictionary. - - @rtype: L{list} of 2-L{tuple} of (E{1}) L{bytes}, (E{2}) L{IDomain} - provider or L{NoneType } - @return: Domain name/domain object pairs in this dictionary. - """ - return self.domains.items() - - - def popitem(self): - """ - Remove a random domain name/domain object pair from this dictionary and - return it as a tuple. - - @rtype: 2-L{tuple} of (E{1}) L{bytes}, (E{2}) L{IDomain} provider or - L{NoneType } - @return: A domain name/domain object pair. - - @raise KeyError: When this dictionary is empty. - """ - return self.domains.popitem() - - - def update(self, other): - """ - Update this dictionary with domain name/domain object pairs from - another dictionary. - - When this dictionary contains a domain name which is in the other - dictionary, its value will be overwritten. - - @type other: L{dict} of L{bytes} -> L{IDomain} provider and/or - L{bytes} -> L{NoneType } - @param other: Another dictionary of domain name/domain object pairs. - - @rtype: L{NoneType } - @return: None. - """ - return self.domains.update(other) - - - def clear(self): - """ - Remove all items from this dictionary. - - @rtype: L{NoneType } - @return: None. - """ - return self.domains.clear() - - - def setdefault(self, key, default): - """ - Return the domain object associated with the domain name if it is - present in this dictionary. Otherwise, set the value for the - domain name to the default and return that value. - - @type key: L{bytes} - @param key: A domain name. - - @type default: L{IDomain} provider - @param default: A domain object. - - @rtype: L{IDomain} provider or L{NoneType } - @return: The domain object associated with the domain name. - """ - return self.domains.setdefault(key, default) - - - -class IDomain(Interface): - """ - An interface for email domains. - """ - def exists(user): - """ - Check whether a user exists in this domain. - - @type user: L{User} - @param user: A user. - - @rtype: no-argument callable which returns L{IMessage } - provider - @return: A function which takes no arguments and returns a message - receiver for the user. - - @raise SMTPBadRcpt: When the given user does not exist in this domain. - """ - - - def addUser(user, password): - """ - Add a user to this domain. - - @type user: L{bytes} - @param user: A username. - - @type password: L{bytes} - @param password: A password. - """ - - - def getCredentialsCheckers(): - """ - Return credentials checkers for this domain. - - @rtype: L{list} of L{ICredentialsChecker - } provider - @return: Credentials checkers for this domain. - """ - - - -class IAliasableDomain(IDomain): - """ - An interface for email domains which can be aliased to other domains. - """ - def setAliasGroup(aliases): - """ - Set the group of defined aliases for this domain. - - @type aliases: L{dict} of L{bytes} -> L{IAlias} provider - @param aliases: A mapping of domain name to alias. - """ - - - def exists(user, memo=None): - """ - Check whether a user exists in this domain or an alias of it. - - @type user: L{User} - @param user: A user. - - @type memo: L{NoneType } or L{dict} of L{AliasBase} - @param memo: A record of the addresses already considered while - resolving aliases. The default value should be used by all - external code. - - @rtype: no-argument callable which returns L{IMessage } - provider - @return: A function which takes no arguments and returns a message - receiver for the user. - - @raise SMTPBadRcpt: When the given user does not exist in this domain - or an alias of it. - """ - - - -class BounceDomain: - """ - A domain with no users. - - This can be used to block off a domain. - """ - implements(IDomain) - - def exists(self, user): - """ - Raise an exception to indicate that the user does not exist in this - domain. - - @type user: L{User} - @param user: A user. - - @raise SMTPBadRcpt: When the given user does not exist in this domain. - """ - raise smtp.SMTPBadRcpt(user) - - - def willRelay(self, user, protocol): - """ - Indicate that this domain will not relay. - - @type user: L{Address} - @param user: The destination address. - - @type protocol: L{Protocol } - @param protocol: The protocol over which the message to be relayed is - being received. - - @rtype: L{bool} - @return: C{False}. - """ - return False - - - def addUser(self, user, password): - """ - Ignore attempts to add a user to this domain. - - @type user: L{bytes} - @param user: A username. - - @type password: L{bytes} - @param password: A password. - """ - pass - - - def getCredentialsCheckers(self): - """ - Return no credentials checkers for this domain. - - @rtype: L{list} - @return: The empty list. - """ - return [] - - - -class FileMessage: - """ - A message receiver which delivers a message to a file. - - @ivar fp: See L{__init__}. - @ivar name: See L{__init__}. - @ivar finalName: See L{__init__}. - """ - implements(smtp.IMessage) - - def __init__(self, fp, name, finalName): - """ - @type fp: file-like object - @param fp: The file in which to store the message while it is being - received. - - @type name: L{bytes} - @param name: The full path name of the temporary file. - - @type finalName: L{bytes} - @param finalName: The full path name that should be given to the file - holding the message after it has been fully received. - """ - self.fp = fp - self.name = name - self.finalName = finalName - - - def lineReceived(self, line): - """ - Write a received line to the file. - - @type line: L{bytes} - @param line: A received line. - """ - self.fp.write(line+'\n') - - - def eomReceived(self): - """ - At the end of message, rename the file holding the message to its - final name. - - @rtype: L{Deferred} which successfully results in L{bytes} - @return: A deferred which returns the final name of the file. - """ - self.fp.close() - os.rename(self.name, self.finalName) - return defer.succeed(self.finalName) - - - def connectionLost(self): - """ - Delete the file holding the partially received message. - """ - self.fp.close() - os.remove(self.name) - - - -class MailService(service.MultiService): - """ - An email service. - - @type queue: L{Queue} or L{NoneType } - @ivar queue: A queue for outgoing messages. - - @type domains: L{dict} of L{bytes} -> L{IDomain} provider - @ivar domains: A mapping of supported domain name to domain object. - - @type portals: L{dict} of L{bytes} -> L{Portal} - @ivar portals: A mapping of domain name to authentication portal. - - @type aliases: L{NoneType } or L{dict} of - L{bytes} -> L{IAlias} provider - @ivar aliases: A mapping of domain name to alias. - - @type smtpPortal: L{Portal} - @ivar smtpPortal: A portal for authentication for the SMTP server. - - @type monitor: L{FileMonitoringService} - @ivar monitor: A service to monitor changes to files. - """ - queue = None - domains = None - portals = None - aliases = None - smtpPortal = None - - def __init__(self): - """ - Initialize the mail service. - """ - service.MultiService.__init__(self) - # Domains and portals for "client" protocols - POP3, IMAP4, etc - self.domains = DomainWithDefaultDict({}, BounceDomain()) - self.portals = {} - - self.monitor = FileMonitoringService() - self.monitor.setServiceParent(self) - self.smtpPortal = Portal(self) - - - def getPOP3Factory(self): - """ - Create a POP3 protocol factory. - - @rtype: L{POP3Factory} - @return: A POP3 protocol factory. - """ - return protocols.POP3Factory(self) - - - def getSMTPFactory(self): - """ - Create an SMTP protocol factory. - - @rtype: L{SMTPFactory } - @return: An SMTP protocol factory. - """ - return protocols.SMTPFactory(self, self.smtpPortal) - - - def getESMTPFactory(self): - """ - Create an ESMTP protocol factory. - - @rtype: L{ESMTPFactory } - @return: An ESMTP protocol factory. - """ - return protocols.ESMTPFactory(self, self.smtpPortal) - - - def addDomain(self, name, domain): - """ - Add a domain for which the service will accept email. - - @type name: L{bytes} - @param name: A domain name. - - @type domain: L{IDomain} provider - @param domain: A domain object. - """ - portal = Portal(domain) - map(portal.registerChecker, domain.getCredentialsCheckers()) - self.domains[name] = domain - self.portals[name] = portal - if self.aliases and IAliasableDomain.providedBy(domain): - domain.setAliasGroup(self.aliases) - - - def setQueue(self, queue): - """ - Set the queue for outgoing emails. - - @type queue: L{Queue} - @param queue: A queue for outgoing messages. - """ - self.queue = queue - - - def requestAvatar(self, avatarId, mind, *interfaces): - """ - Return a message delivery for an authenticated SMTP user. - - @type avatarId: L{bytes} - @param avatarId: A string which identifies an authenticated user. - - @type mind: L{NoneType } - @param mind: Unused. - - @type interfaces: n-L{tuple} of C{zope.interface.Interface} - @param interfaces: A group of interfaces one of which the avatar must - support. - - @rtype: 3-L{tuple} of (E{1}) L{IMessageDelivery}, - (E{2}) L{ESMTPDomainDelivery}, (E{3}) no-argument callable - @return: A tuple of the supported interface, a message delivery, and - a logout function. - - @raise NotImplementedError: When the given interfaces do not include - L{IMessageDelivery}. - """ - if smtp.IMessageDelivery in interfaces: - a = protocols.ESMTPDomainDelivery(self, avatarId) - return smtp.IMessageDelivery, a, lambda: None - raise NotImplementedError() - - - def lookupPortal(self, name): - """ - Find the portal for a domain. - - @type name: L{bytes} - @param name: A domain name. - - @rtype: L{Portal} - @return: A portal. - """ - return self.portals[name] - - - def defaultPortal(self): - """ - Return the portal for the default domain. - - The default domain is named ''. - - @rtype: L{Portal} - @return: The portal for the default domain. - """ - return self.portals[''] - - - -class FileMonitoringService(internet.TimerService): - """ - A service for monitoring changes to files. - - @type files: L{list} of L{list} of (E{1}) L{float}, (E{2}) L{bytes}, - (E{3}) callable which takes a L{bytes} argument, (E{4}) L{float} - @ivar files: Information about files to be monitored. Each list entry - provides the following information for a file: interval in seconds - between checks, filename, callback function, time of last modification - to the file. - - @type intervals: L{_IntervalDifferentialIterator - } - @ivar intervals: Intervals between successive file checks. - - @type _call: L{IDelayedCall } - provider - @ivar _call: The next scheduled call to check a file. - - @type index: L{int} - @ivar index: The index of the next file to be checked. - """ - def __init__(self): - """ - Initialize the file monitoring service. - """ - self.files = [] - self.intervals = iter(util.IntervalDifferential([], 60)) - - - def startService(self): - """ - Start the file monitoring service. - """ - service.Service.startService(self) - self._setupMonitor() - - - def _setupMonitor(self): - """ - Schedule the next monitoring call. - """ - from twisted.internet import reactor - t, self.index = self.intervals.next() - self._call = reactor.callLater(t, self._monitor) - - - def stopService(self): - """ - Stop the file monitoring service. - """ - service.Service.stopService(self) - if self._call: - self._call.cancel() - self._call = None - - - def monitorFile(self, name, callback, interval=10): - """ - Start monitoring a file for changes. - - @type name: L{bytes} - @param name: The name of a file to monitor. - - @type callback: callable which takes a L{bytes} argument - @param callback: The function to call when the file has changed. - - @type interval: L{float} - @param interval: The interval in seconds between checks. - """ - try: - mtime = os.path.getmtime(name) - except: - mtime = 0 - self.files.append([interval, name, callback, mtime]) - self.intervals.addInterval(interval) - - - def unmonitorFile(self, name): - """ - Stop monitoring a file. - - @type name: L{bytes} - @param name: A file name. - """ - for i in range(len(self.files)): - if name == self.files[i][1]: - self.intervals.removeInterval(self.files[i][0]) - del self.files[i] - break - - - def _monitor(self): - """ - Monitor a file and make a callback if it has changed. - """ - self._call = None - if self.index is not None: - name, callback, mtime = self.files[self.index][1:] - try: - now = os.path.getmtime(name) - except: - now = 0 - if now > mtime: - log.msg("%s changed, notifying listener" % (name,)) - self.files[self.index][3] = now - callback(name) - self._setupMonitor() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/maildir.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/maildir.py deleted file mode 100644 index b7ea648..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/maildir.py +++ /dev/null @@ -1,942 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Maildir-style mailbox support. -""" - -import os -import stat -import socket -from hashlib import md5 - -from zope.interface import implementer - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -from twisted.mail import pop3 -from twisted.mail import smtp -from twisted.protocols import basic -from twisted.persisted import dirdbm -from twisted.python import log, failure -from twisted.mail import mail -from twisted.internet import interfaces, defer, reactor -from twisted.cred import portal, credentials, checkers -from twisted.cred.error import UnauthorizedLogin - -INTERNAL_ERROR = '''\ -From: Twisted.mail Internals -Subject: An Error Occurred - - An internal server error has occurred. Please contact the - server administrator. -''' - - - -class _MaildirNameGenerator: - """ - A utility class to generate a unique maildir name. - - @type n: L{int} - @ivar n: A counter used to generate unique integers. - - @type p: L{int} - @ivar p: The ID of the current process. - - @type s: L{bytes} - @ivar s: A representation of the hostname. - - @ivar _clock: See C{clock} parameter of L{__init__}. - """ - n = 0 - p = os.getpid() - s = socket.gethostname().replace('/', r'\057').replace(':', r'\072') - - def __init__(self, clock): - """ - @type clock: L{IReactorTime } provider - @param clock: A reactor which will be used to learn the current time. - """ - self._clock = clock - - - def generate(self): - """ - Generate a string which is intended to be unique across all calls to - this function (across all processes, reboots, etc). - - Strings returned by earlier calls to this method will compare less - than strings returned by later calls as long as the clock provided - doesn't go backwards. - - @rtype: L{bytes} - @return: A unique string. - """ - self.n = self.n + 1 - t = self._clock.seconds() - seconds = str(int(t)) - microseconds = '%07d' % (int((t - int(t)) * 10e6),) - return '%s.M%sP%sQ%s.%s' % (seconds, microseconds, - self.p, self.n, self.s) - -_generateMaildirName = _MaildirNameGenerator(reactor).generate - - - -def initializeMaildir(dir): - """ - Create a maildir user directory if it doesn't already exist. - - @type dir: L{bytes} - @param dir: The path name for a user directory. - """ - if not os.path.isdir(dir): - os.mkdir(dir, 0700) - for subdir in ['new', 'cur', 'tmp', '.Trash']: - os.mkdir(os.path.join(dir, subdir), 0700) - for subdir in ['new', 'cur', 'tmp']: - os.mkdir(os.path.join(dir, '.Trash', subdir), 0700) - # touch - open(os.path.join(dir, '.Trash', 'maildirfolder'), 'w').close() - - - -class MaildirMessage(mail.FileMessage): - """ - A message receiver which adds a header and delivers a message to a file - whose name includes the size of the message. - - @type size: L{int} - @ivar size: The number of octets in the message. - """ - size = None - - def __init__(self, address, fp, *a, **kw): - """ - @type address: L{bytes} - @param address: The address of the message recipient. - - @type fp: file-like object - @param fp: The file in which to store the message while it is being - received. - - @type a: 2-L{tuple} of (0) L{bytes}, (1) L{bytes} - @param a: Positional arguments for L{FileMessage.__init__}. - - @type kw: L{dict} - @param kw: Keyword arguments for L{FileMessage.__init__}. - """ - header = "Delivered-To: %s\n" % address - fp.write(header) - self.size = len(header) - mail.FileMessage.__init__(self, fp, *a, **kw) - - - def lineReceived(self, line): - """ - Write a line to the file. - - @type line: L{bytes} - @param line: A received line. - """ - mail.FileMessage.lineReceived(self, line) - self.size += len(line)+1 - - - def eomReceived(self): - """ - At the end of message, rename the file holding the message to its final - name concatenated with the size of the file. - - @rtype: L{Deferred } which successfully results in - L{bytes} - @return: A deferred which returns the name of the file holding the - message. - """ - self.finalName = self.finalName+',S=%d' % self.size - return mail.FileMessage.eomReceived(self) - - - -@implementer(mail.IAliasableDomain) -class AbstractMaildirDomain: - """ - An abstract maildir-backed domain. - - @type alias: L{NoneType } or L{dict} mapping - L{bytes} to L{AliasBase} - @ivar alias: A mapping of username to alias. - - @ivar root: See L{__init__}. - """ - alias = None - root = None - - def __init__(self, service, root): - """ - @type service: L{MailService} - @param service: An email service. - - @type root: L{bytes} - @param root: The maildir root directory. - """ - self.root = root - - - def userDirectory(self, user): - """ - Return the maildir directory for a user. - - @type user: L{bytes} - @param user: A username. - - @rtype: L{bytes} or L{NoneType } - @return: The user's mail directory for a valid user. Otherwise, - C{None}. - """ - return None - - - def setAliasGroup(self, alias): - """ - Set the group of defined aliases for this domain. - - @type alias: L{dict} mapping L{bytes} to L{IAlias} provider. - @param alias: A mapping of domain name to alias. - """ - self.alias = alias - - - def exists(self, user, memo=None): - """ - Check whether a user exists in this domain or an alias of it. - - @type user: L{User} - @param user: A user. - - @type memo: L{NoneType } or L{dict} of L{AliasBase} - @param memo: A record of the addresses already considered while - resolving aliases. The default value should be used by all - external code. - - @rtype: no-argument callable which returns L{IMessage } - provider. - @return: A function which takes no arguments and returns a message - receiver for the user. - - @raises SMTPBadRcpt: When the given user does not exist in this domain - or an alias of it. - """ - if self.userDirectory(user.dest.local) is not None: - return lambda: self.startMessage(user) - try: - a = self.alias[user.dest.local] - except: - raise smtp.SMTPBadRcpt(user) - else: - aliases = a.resolve(self.alias, memo) - if aliases: - return lambda: aliases - log.err("Bad alias configuration: " + str(user)) - raise smtp.SMTPBadRcpt(user) - - - def startMessage(self, user): - """ - Create a maildir message for a user. - - @type user: L{bytes} - @param user: A username. - - @rtype: L{MaildirMessage} - @return: A message receiver for this user. - """ - if isinstance(user, str): - name, domain = user.split('@', 1) - else: - name, domain = user.dest.local, user.dest.domain - dir = self.userDirectory(name) - fname = _generateMaildirName() - filename = os.path.join(dir, 'tmp', fname) - fp = open(filename, 'w') - return MaildirMessage('%s@%s' % (name, domain), fp, filename, - os.path.join(dir, 'new', fname)) - - - def willRelay(self, user, protocol): - """ - Check whether this domain will relay. - - @type user: L{Address} - @param user: The destination address. - - @type protocol: L{SMTP} - @param protocol: The protocol over which the message to be relayed is - being received. - - @rtype: L{bool} - @return: An indication of whether this domain will relay the message to - the destination. - """ - return False - - - def addUser(self, user, password): - """ - Add a user to this domain. - - Subclasses should override this method. - - @type user: L{bytes} - @param user: A username. - - @type password: L{bytes} - @param password: A password. - """ - raise NotImplementedError - - - def getCredentialsCheckers(self): - """ - Return credentials checkers for this domain. - - Subclasses should override this method. - - @rtype: L{list} of L{ICredentialsChecker - } provider - @return: Credentials checkers for this domain. - """ - raise NotImplementedError - - - -@implementer(interfaces.IConsumer) -class _MaildirMailboxAppendMessageTask: - """ - A task which adds a message to a maildir mailbox. - - @ivar mbox: See L{__init__}. - - @type defer: L{Deferred } which successfully returns - L{NoneType } - @ivar defer: A deferred which fires when the task has completed. - - @type opencall: L{IDelayedCall } provider or - L{NoneType } - @ivar opencall: A scheduled call to L{prodProducer}. - - @type msg: file-like object - @ivar msg: The message to add. - - @type tmpname: L{bytes} - @ivar tmpname: The pathname of the temporary file holding the message while - it is being transferred. - - @type fh: file - @ivar fh: The new maildir file. - - @type filesender: L{FileSender } - @ivar filesender: A file sender which sends the message. - - @type myproducer: L{IProducer } - @ivar myproducer: The registered producer. - - @type streaming: L{bool} - @ivar streaming: Indicates whether the registered producer provides a - streaming interface. - """ - osopen = staticmethod(os.open) - oswrite = staticmethod(os.write) - osclose = staticmethod(os.close) - osrename = staticmethod(os.rename) - - def __init__(self, mbox, msg): - """ - @type mbox: L{MaildirMailbox} - @param mbox: A maildir mailbox. - - @type msg: L{bytes} or file-like object - @param msg: The message to add. - """ - self.mbox = mbox - self.defer = defer.Deferred() - self.openCall = None - if not hasattr(msg, "read"): - msg = StringIO.StringIO(msg) - self.msg = msg - - - def startUp(self): - """ - Start transferring the message to the mailbox. - """ - self.createTempFile() - if self.fh != -1: - self.filesender = basic.FileSender() - self.filesender.beginFileTransfer(self.msg, self) - - - def registerProducer(self, producer, streaming): - """ - Register a producer and start asking it for data if it is - non-streaming. - - @type producer: L{IProducer } - @param producer: A producer. - - @type streaming: L{bool} - @param streaming: A flag indicating whether the producer provides a - streaming interface. - """ - self.myproducer = producer - self.streaming = streaming - if not streaming: - self.prodProducer() - - - def prodProducer(self): - """ - Repeatedly prod a non-streaming producer to produce data. - """ - self.openCall = None - if self.myproducer is not None: - self.openCall = reactor.callLater(0, self.prodProducer) - self.myproducer.resumeProducing() - - - def unregisterProducer(self): - """ - Finish transferring the message to the mailbox. - """ - self.myproducer = None - self.streaming = None - self.osclose(self.fh) - self.moveFileToNew() - - - def write(self, data): - """ - Write data to the maildir file. - - @type data: L{bytes} - @param data: Data to be written to the file. - """ - try: - self.oswrite(self.fh, data) - except: - self.fail() - - - def fail(self, err=None): - """ - Fire the deferred to indicate the task completed with a failure. - - @type err: L{Failure } - @param err: The error that occurred. - """ - if err is None: - err = failure.Failure() - if self.openCall is not None: - self.openCall.cancel() - self.defer.errback(err) - self.defer = None - - - def moveFileToNew(self): - """ - Place the message in the I{new/} directory, add it to the mailbox and - fire the deferred to indicate that the task has completed - successfully. - """ - while True: - newname = os.path.join(self.mbox.path, "new", _generateMaildirName()) - try: - self.osrename(self.tmpname, newname) - break - except OSError, (err, estr): - import errno - # if the newname exists, retry with a new newname. - if err != errno.EEXIST: - self.fail() - newname = None - break - if newname is not None: - self.mbox.list.append(newname) - self.defer.callback(None) - self.defer = None - - - def createTempFile(self): - """ - Create a temporary file to hold the message as it is being transferred. - """ - attr = (os.O_RDWR | os.O_CREAT | os.O_EXCL - | getattr(os, "O_NOINHERIT", 0) - | getattr(os, "O_NOFOLLOW", 0)) - tries = 0 - self.fh = -1 - while True: - self.tmpname = os.path.join(self.mbox.path, "tmp", _generateMaildirName()) - try: - self.fh = self.osopen(self.tmpname, attr, 0600) - return None - except OSError: - tries += 1 - if tries > 500: - self.defer.errback(RuntimeError("Could not create tmp file for %s" % self.mbox.path)) - self.defer = None - return None - - - -class MaildirMailbox(pop3.Mailbox): - """ - A maildir-backed mailbox. - - @ivar path: See L{__init__}. - - @type list: L{list} of L{int} or 2-L{tuple} of (0) file-like object, - (1) L{bytes} - @ivar list: Information about the messages in the mailbox. For undeleted - messages, the file containing the message and the - full path name of the file are stored. Deleted messages are indicated - by 0. - - @type deleted: L{dict} mapping 2-L{tuple} of (0) file-like object, - (1) L{bytes} to L{bytes} - @type deleted: A mapping of the information about a file before it was - deleted to the full path name of the deleted file in the I{.Trash/} - subfolder. - """ - AppendFactory = _MaildirMailboxAppendMessageTask - - def __init__(self, path): - """ - @type path: L{bytes} - @param path: The directory name for a maildir mailbox. - """ - self.path = path - self.list = [] - self.deleted = {} - initializeMaildir(path) - for name in ('cur', 'new'): - for file in os.listdir(os.path.join(path, name)): - self.list.append((file, os.path.join(path, name, file))) - self.list.sort() - self.list = [e[1] for e in self.list] - - - def listMessages(self, i=None): - """ - Retrieve the size of a message, or, if none is specified, the size of - each message in the mailbox. - - @type i: L{int} or L{NoneType } - @param i: The 0-based index of a message. - - @rtype: L{int} or L{list} of L{int} - @return: The number of octets in the specified message, or, if an index - is not specified, a list of the number of octets for all messages - in the mailbox. Any value which corresponds to a deleted message - is set to 0. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - if i is None: - ret = [] - for mess in self.list: - if mess: - ret.append(os.stat(mess)[stat.ST_SIZE]) - else: - ret.append(0) - return ret - return self.list[i] and os.stat(self.list[i])[stat.ST_SIZE] or 0 - - - def getMessage(self, i): - """ - Retrieve a file-like object with the contents of a message. - - @type i: L{int} - @param i: The 0-based index of a message. - - @rtype: file-like object - @return: A file containing the message. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - return open(self.list[i]) - - - def getUidl(self, i): - """ - Get a unique identifier for a message. - - @type i: L{int} - @param i: The 0-based index of a message. - - @rtype: L{bytes} - @return: A string of printable characters uniquely identifying the - message for all time. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - # Returning the actual filename is a mistake. Hash it. - base = os.path.basename(self.list[i]) - return md5(base).hexdigest() - - - def deleteMessage(self, i): - """ - Mark a message for deletion. - - Move the message to the I{.Trash/} subfolder so it can be undeleted - by an administrator. - - @type i: L{int} - @param i: The 0-based index of a message. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - trashFile = os.path.join( - self.path, '.Trash', 'cur', os.path.basename(self.list[i]) - ) - os.rename(self.list[i], trashFile) - self.deleted[self.list[i]] = trashFile - self.list[i] = 0 - - - def undeleteMessages(self): - """ - Undelete all messages marked for deletion. - - Move each message marked for deletion from the I{.Trash/} subfolder back - to its original position. - """ - for (real, trash) in self.deleted.items(): - try: - os.rename(trash, real) - except OSError, (err, estr): - import errno - # If the file has been deleted from disk, oh well! - if err != errno.ENOENT: - raise - # This is a pass - else: - try: - self.list[self.list.index(0)] = real - except ValueError: - self.list.append(real) - self.deleted.clear() - - - def appendMessage(self, txt): - """ - Add a message to the mailbox. - - @type txt: L{bytes} or file-like object - @param txt: A message to add. - - @rtype: L{Deferred } - @return: A deferred which fires when the message has been added to - the mailbox. - """ - task = self.AppendFactory(self, txt) - result = task.defer - task.startUp() - return result - - - -@implementer(pop3.IMailbox) -class StringListMailbox: - """ - An in-memory mailbox. - - @ivar msgs: See L{__init__}. - - @type _delete: L{set} of L{int} - @ivar _delete: The indices of messages which have been marked for deletion. - """ - def __init__(self, msgs): - """ - @type msgs: L{list} of L{bytes} - @param msgs: The contents of each message in the mailbox. - """ - self.msgs = msgs - self._delete = set() - - - def listMessages(self, i=None): - """ - Retrieve the size of a message, or, if none is specified, the size of - each message in the mailbox. - - @type i: L{int} or L{NoneType } - @param i: The 0-based index of a message. - - @rtype: L{int} or L{list} of L{int} - @return: The number of octets in the specified message, or, if an index - is not specified, a list of the number of octets in each message in - the mailbox. Any value which corresponds to a deleted message is - set to 0. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - if i is None: - return [self.listMessages(msg) for msg in range(len(self.msgs))] - if i in self._delete: - return 0 - return len(self.msgs[i]) - - - def getMessage(self, i): - """ - Return an in-memory file-like object with the contents of a message. - - @type i: L{int} - @param i: The 0-based index of a message. - - @rtype: L{StringIO } - @return: An in-memory file-like object containing the message. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - return StringIO.StringIO(self.msgs[i]) - - - def getUidl(self, i): - """ - Get a unique identifier for a message. - - @type i: L{int} - @param i: The 0-based index of a message. - - @rtype: L{bytes} - @return: A hash of the contents of the message at the given index. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - return md5(self.msgs[i]).hexdigest() - - - def deleteMessage(self, i): - """ - Mark a message for deletion. - - @type i: L{int} - @param i: The 0-based index of a message to delete. - - @raise IndexError: When the index does not correspond to a message in - the mailbox. - """ - self._delete.add(i) - - - def undeleteMessages(self): - """ - Undelete any messages which have been marked for deletion. - """ - self._delete = set() - - - def sync(self): - """ - Discard the contents of any messages marked for deletion. - """ - for index in self._delete: - self.msgs[index] = "" - self._delete = set() - - - -@implementer(portal.IRealm) -class MaildirDirdbmDomain(AbstractMaildirDomain): - """ - A maildir-backed domain where membership is checked with a - L{DirDBM } database. - - The directory structure of a MaildirDirdbmDomain is: - - /passwd <-- a DirDBM directory - - /USER/{cur, new, del} <-- each user has these three directories - - @ivar postmaster: See L{__init__}. - - @type dbm: L{DirDBM } - @ivar dbm: The authentication database for the domain. - """ - portal = None - _credcheckers = None - - def __init__(self, service, root, postmaster=0): - """ - @type service: L{MailService} - @param service: An email service. - - @type root: L{bytes} - @param root: The maildir root directory. - - @type postmaster: L{bool} - @param postmaster: A flag indicating whether non-existent addresses - should be forwarded to the postmaster (C{True}) or - bounced (C{False}). - """ - AbstractMaildirDomain.__init__(self, service, root) - dbm = os.path.join(root, 'passwd') - if not os.path.exists(dbm): - os.makedirs(dbm) - self.dbm = dirdbm.open(dbm) - self.postmaster = postmaster - - - def userDirectory(self, name): - """ - Return the path to a user's mail directory. - - @type name: L{bytes} - @param name: A username. - - @rtype: L{bytes} or L{NoneType } - @return: The path to the user's mail directory for a valid user. For - an invalid user, the path to the postmaster's mailbox if bounces - are redirected there. Otherwise, C{None}. - """ - if name not in self.dbm: - if not self.postmaster: - return None - name = 'postmaster' - dir = os.path.join(self.root, name) - if not os.path.exists(dir): - initializeMaildir(dir) - return dir - - - def addUser(self, user, password): - """ - Add a user to this domain by adding an entry in the authentication - database and initializing the user's mail directory. - - @type user: L{bytes} - @param user: A username. - - @type password: L{bytes} - @param password: A password. - """ - self.dbm[user] = password - # Ensure it is initialized - self.userDirectory(user) - - - def getCredentialsCheckers(self): - """ - Return credentials checkers for this domain. - - @rtype: L{list} of L{ICredentialsChecker - } provider - @return: Credentials checkers for this domain. - """ - if self._credcheckers is None: - self._credcheckers = [DirdbmDatabase(self.dbm)] - return self._credcheckers - - - def requestAvatar(self, avatarId, mind, *interfaces): - """ - Get the mailbox for an authenticated user. - - The mailbox for the authenticated user will be returned only if the - given interfaces include L{IMailbox }. Requests for - anonymous access will be met with a mailbox containing a message - indicating that an internal error has occurred. - - @type avatarId: L{bytes} or C{twisted.cred.checkers.ANONYMOUS} - @param avatarId: A string which identifies a user or an object which - signals a request for anonymous access. - - @type mind: L{NoneType } - @param mind: Unused. - - @type interfaces: n-L{tuple} of C{zope.interface.Interface} - @param interfaces: A group of interfaces, one of which the avatar - must support. - - @rtype: 3-L{tuple} of (0) L{IMailbox }, - (1) L{IMailbox } provider, (2) no-argument - callable - @return: A tuple of the supported interface, a mailbox, and a - logout function. - - @raise NotImplementedError: When the given interfaces do not include - L{IMailbox }. - """ - if pop3.IMailbox not in interfaces: - raise NotImplementedError("No interface") - if avatarId == checkers.ANONYMOUS: - mbox = StringListMailbox([INTERNAL_ERROR]) - else: - mbox = MaildirMailbox(os.path.join(self.root, avatarId)) - - return ( - pop3.IMailbox, - mbox, - lambda: None - ) - - - -@implementer(checkers.ICredentialsChecker) -class DirdbmDatabase: - """ - A credentials checker which authenticates users out of a - L{DirDBM } database. - - @type dirdbm: L{DirDBM } - @ivar dirdbm: An authentication database. - """ - # credentialInterfaces is not used by the class - credentialInterfaces = ( - credentials.IUsernamePassword, - credentials.IUsernameHashedPassword - ) - - def __init__(self, dbm): - """ - @type dbm: L{DirDBM } - @param dbm: An authentication database. - """ - self.dirdbm = dbm - - - def requestAvatarId(self, c): - """ - Authenticate a user and, if successful, return their username. - - @type c: L{IUsernamePassword } or - L{IUsernameHashedPassword } - provider. - @param c: Credentials. - - @rtype: L{bytes} - @return: A string which identifies an user. - - @raise UnauthorizedLogin: When the credentials check fails. - """ - if c.username in self.dirdbm: - if c.checkPassword(self.dirdbm[c.username]): - return c.username - raise UnauthorizedLogin() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pb.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pb.py deleted file mode 100644 index 53eb44a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pb.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.spread import pb - -import os - - -class Maildir(pb.Referenceable): - - def __init__(self, directory, rootDirectory): - self.virtualDirectory = directory - self.rootDirectory = rootDirectory - self.directory = os.path.join(rootDirectory, directory) - - def getFolderMessage(self, folder, name): - if '/' in name: - raise IOError("can only open files in '%s' directory'" % folder) - fp = open(os.path.join(self.directory, 'new', name)) - try: - return fp.read() - finally: - fp.close() - - def deleteFolderMessage(self, folder, name): - if '/' in name: - raise IOError("can only delete files in '%s' directory'" % folder) - os.rename(os.path.join(self.directory, folder, name), - os.path.join(self.rootDirectory, '.Trash', folder, name)) - - def deleteNewMessage(self, name): - return self.deleteFolderMessage('new', name) - remote_deleteNewMessage = deleteNewMessage - - def deleteCurMessage(self, name): - return self.deleteFolderMessage('cur', name) - remote_deleteCurMessage = deleteCurMessage - - def getNewMessages(self): - return os.listdir(os.path.join(self.directory, 'new')) - remote_getNewMessages = getNewMessages - - def getCurMessages(self): - return os.listdir(os.path.join(self.directory, 'cur')) - remote_getCurMessages = getCurMessages - - def getNewMessage(self, name): - return self.getFolderMessage('new', name) - remote_getNewMessage = getNewMessage - - def getCurMessage(self, name): - return self.getFolderMessage('cur', name) - remote_getCurMessage = getCurMessage - - def getSubFolder(self, name): - if name[0] == '.': - raise IOError("subfolder name cannot begin with a '.'") - name = name.replace('/', ':') - if self.virtualDirectoy == '.': - name = '.'+name - else: - name = self.virtualDirectory+':'+name - if not self._isSubFolder(name): - raise IOError("not a subfolder") - return Maildir(name, self.rootDirectory) - remote_getSubFolder = getSubFolder - - def _isSubFolder(self, name): - return (not os.path.isdir(os.path.join(self.rootDirectory, name)) or - not os.path.isfile(os.path.join(self.rootDirectory, name, - 'maildirfolder'))) - - -class MaildirCollection(pb.Referenceable): - - def __init__(self, root): - self.root = root - - def getSubFolders(self): - return os.listdir(self.getRoot()) - remote_getSubFolders = getSubFolders - - def getSubFolder(self, name): - if '/' in name or name[0] == '.': - raise IOError("invalid name") - return Maildir('.', os.path.join(self.getRoot(), name)) - remote_getSubFolder = getSubFolder - - -class MaildirBroker(pb.Broker): - - def proto_getCollection(self, requestID, name, domain, password): - collection = self._getCollection() - if collection is None: - self.sendError(requestID, "permission denied") - else: - self.sendAnswer(requestID, collection) - - def getCollection(self, name, domain, password): - if not self.domains.has_key(domain): - return - domain = self.domains[domain] - if (domain.dbm.has_key(name) and - domain.dbm[name] == password): - return MaildirCollection(domain.userDirectory(name)) - - -class MaildirClient(pb.Broker): - - def getCollection(self, name, domain, password, callback, errback): - requestID = self.newRequestID() - self.waitingForAnswers[requestID] = callback, errback - self.sendCall("getCollection", requestID, name, domain, password) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pop3.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pop3.py deleted file mode 100644 index 933dd6c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pop3.py +++ /dev/null @@ -1,1880 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_pop3 -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Post-office Protocol version 3. - -@author: Glyph Lefkowitz -@author: Jp Calderone -""" - -import base64 -import binascii -import warnings -from hashlib import md5 - -from zope.interface import implements, Interface - -from twisted.mail import smtp -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import task -from twisted.internet import defer -from twisted.internet import interfaces -from twisted.python import log - -from twisted import cred - -## -## Authentication -## -class APOPCredentials: - """ - Credentials for use in APOP authentication. - - @ivar magic: See L{__init__} - @ivar username: See L{__init__} - @ivar digest: See L{__init__} - """ - implements(cred.credentials.IUsernamePassword) - - def __init__(self, magic, username, digest): - """ - @type magic: L{bytes} - @param magic: The challenge string used to encrypt the password. - - @type username: L{bytes} - @param username: The username associated with these credentials. - - @type digest: L{bytes} - @param digest: An encrypted version of the user's password. Should be - generated as an MD5 hash of the challenge string concatenated with - the plaintext password. - """ - self.magic = magic - self.username = username - self.digest = digest - - - def checkPassword(self, password): - """ - Validate a plaintext password against the credentials. - - @type password: L{bytes} - @param password: A plaintext password. - - @rtype: L{bool} - @return: C{True} if the credentials represented by this object match - the given password, C{False} if they do not. - """ - seed = self.magic + password - myDigest = md5(seed).hexdigest() - return myDigest == self.digest - - - -class _HeadersPlusNLines: - """ - A utility class to retrieve the header and some lines of the body of a mail - message. - - @ivar f: See L{__init__} - @ivar n: See L{__init__} - - @type linecount: L{int} - @ivar linecount: The number of full lines of the message body scanned. - - @type headers: L{bool} - @ivar headers: An indication of which part of the message is being scanned. - C{True} for the header and C{False} for the body. - - @type done: L{bool} - @ivar done: A flag indicating when the desired part of the message has been - scanned. - - @type buf: L{bytes} - @ivar buf: The portion of the message body that has been scanned, up to - C{n} lines. - """ - def __init__(self, f, n): - """ - @type f: file-like object - @param f: A file containing a mail message. - - @type n: L{int} - @param n: The number of lines of the message body to retrieve. - """ - self.f = f - self.n = n - self.linecount = 0 - self.headers = 1 - self.done = 0 - self.buf = '' - - - def read(self, bytes): - """ - Scan bytes from the file. - - @type bytes: L{int} - @param bytes: The number of bytes to read from the file. - - @rtype: L{bytes} - @return: Each portion of the header as it is scanned. Then, full lines - of the message body as they are scanned. When more than one line - of the header and/or body has been scanned, the result is the - concatenation of the lines. When the scan results in no full - lines, the empty string is returned. - """ - if self.done: - return '' - data = self.f.read(bytes) - if not data: - return data - if self.headers: - df, sz = data.find('\r\n\r\n'), 4 - if df == -1: - df, sz = data.find('\n\n'), 2 - if df != -1: - df += sz - val = data[:df] - data = data[df:] - self.linecount = 1 - self.headers = 0 - else: - val = '' - if self.linecount > 0: - dsplit = (self.buf+data).split('\n') - self.buf = dsplit[-1] - for ln in dsplit[:-1]: - if self.linecount > self.n: - self.done = 1 - return val - val += (ln + '\n') - self.linecount += 1 - return val - else: - return data - - - -class _POP3MessageDeleted(Exception): - """ - An internal control-flow error which indicates that a deleted message was - requested. - """ - - - -class POP3Error(Exception): - """ - The base class for POP3 errors. - """ - pass - - - -class _IteratorBuffer(object): - """ - An iterator which buffers the elements of a container and periodically - passes them as input to a writer. - - @ivar write: See L{__init__}. - @ivar memoryBufferSize: See L{__init__}. - - @type bufSize: L{int} - @ivar bufSize: The number of bytes currently in the buffer. - - @type lines: L{list} of L{bytes} - @ivar lines: The buffer, which is a list of strings. - - @type iterator: iterator which yields L{bytes} - @ivar iterator: An iterator over a container of strings. - """ - bufSize = 0 - - def __init__(self, write, iterable, memoryBufferSize=None): - """ - @type write: callable that takes L{list} of L{bytes} - @param write: A writer which is a callable that takes a list of - strings. - - @type iterable: iterable which yields L{bytes} - @param iterable: An iterable container of strings. - - @type memoryBufferSize: L{int} or L{NoneType } - @param memoryBufferSize: The number of bytes to buffer before flushing - the buffer to the writer. - """ - self.lines = [] - self.write = write - self.iterator = iter(iterable) - if memoryBufferSize is None: - memoryBufferSize = 2 ** 16 - self.memoryBufferSize = memoryBufferSize - - - def __iter__(self): - """ - Return an iterator. - - @rtype: iterator which yields L{bytes} - @return: An iterator over strings. - """ - return self - - - def next(self): - """ - Get the next string from the container, buffer it, and possibly send - the buffer to the writer. - - The contents of the buffer are written when it is full or when no - further values are available from the container. - - @raise StopIteration: When no further values are available from the - container. - """ - try: - v = self.iterator.next() - except StopIteration: - if self.lines: - self.write(self.lines) - # Drop some references, in case they're edges in a cycle. - del self.iterator, self.lines, self.write - raise - else: - if v is not None: - self.lines.append(v) - self.bufSize += len(v) - if self.bufSize > self.memoryBufferSize: - self.write(self.lines) - self.lines = [] - self.bufSize = 0 - - - -def iterateLineGenerator(proto, gen): - """ - Direct the output of an iterator to the transport of a protocol and arrange - for iteration to take place. - - @type proto: L{POP3} - @param proto: A POP3 server protocol. - - @type gen: iterator which yields L{bytes} - @param gen: An iterator over strings. - - @rtype: L{Deferred } - @return: A deferred which fires when the iterator finishes. - """ - coll = _IteratorBuffer(proto.transport.writeSequence, gen) - return proto.schedule(coll) - - - -def successResponse(response): - """ - Format an object as a positive response. - - @type response: stringifyable L{object} - @param response: An object with a string representation. - - @rtype: L{bytes} - @return: A positive POP3 response string. - """ - response = str(response) - return '+OK %s\r\n' % (response,) - - - -def formatStatResponse(msgs): - """ - Format a list of message sizes into a STAT response. - - This generator function is intended to be used with - L{Cooperator }. - - @type msgs: L{list} of L{int} - @param msgs: A list of message sizes. - - @rtype: L{NoneType } or L{bytes} - @return: Yields none until a result is available, then a string that is - suitable for use in a STAT response. The string consists of the number - of messages and the total size of the messages in octets. - """ - i = 0 - bytes = 0 - for size in msgs: - i += 1 - bytes += size - yield None - yield successResponse('%d %d' % (i, bytes)) - - - -def formatListLines(msgs): - """ - Format a list of message sizes for use in a LIST response. - - @type msgs: L{list} of L{int} - @param msgs: A list of message sizes. - - @rtype: L{bytes} - @return: Yields a series of strings that are suitable for use as scan - listings in a LIST response. Each string consists of a message number - and its size in octets. - """ - i = 0 - for size in msgs: - i += 1 - yield '%d %d\r\n' % (i, size) - - - -def formatListResponse(msgs): - """ - Format a list of message sizes into a complete LIST response. - - This generator function is intended to be used with - L{Cooperator }. - - @type msgs: L{list} of L{int} - @param msgs: A list of message sizes. - - @rtype: L{bytes} - @return: Yields a series of strings which make up a complete LIST response. - """ - yield successResponse(len(msgs)) - for ele in formatListLines(msgs): - yield ele - yield '.\r\n' - - - -def formatUIDListLines(msgs, getUidl): - """ - Format a list of message sizes for use in a UIDL response. - - @type msgs: L{list} of L{int} - @param msgs: A list of message sizes. - - @rtype: L{bytes} - @return: Yields a series of strings that are suitable for use as unique-id - listings in a UIDL response. Each string consists of a message number - and its unique id. - """ - for i, m in enumerate(msgs): - if m is not None: - uid = getUidl(i) - yield '%d %s\r\n' % (i + 1, uid) - - - -def formatUIDListResponse(msgs, getUidl): - """ - Format a list of message sizes into a complete UIDL response. - - This generator function is intended to be used with - L{Cooperator }. - - @type msgs: L{list} of L{int} - @param msgs: A list of message sizes. - - @rtype: L{bytes} - @return: Yields a series of strings which make up a complete UIDL response. - """ - yield successResponse('') - for ele in formatUIDListLines(msgs, getUidl): - yield ele - yield '.\r\n' - - - -class POP3(basic.LineOnlyReceiver, policies.TimeoutMixin): - """ - A POP3 server protocol. - - @type portal: L{Portal} - @ivar portal: A portal for authentication. - - @type factory: L{IServerFactory} provider - @ivar factory: A server factory which provides an interface for querying - capabilities of the server. - - @type timeOut: L{int} - @ivar timeOut: The number of seconds to wait for a command from the client - before disconnecting. - - @type schedule: callable that takes interator and returns - L{Deferred } - @ivar schedule: A callable that arranges for an iterator to be - cooperatively iterated over along with all other iterators which have - been passed to it such that runtime is divided between all of them. It - returns a deferred which fires when the iterator finishes. - - @type magic: L{bytes} or L{NoneType } - @ivar magic: An APOP challenge. If not set, an APOP challenge string - will be generated when a connection is made. - - @type _userIs: L{bytes} or L{NoneType } - @ivar _userIs: The username sent with the USER command. - - @type _onLogout: no-argument callable or L{NoneType } - @ivar _onLogout: The function to be executed when the connection is - lost. - - @type mbox: L{IMailbox} provider - @ivar mbox: The mailbox for the authenticated user. - - @type state: L{bytes} - @ivar state: The state which indicates what type of messages are expected - from the client. Valid states are 'COMMAND' and 'AUTH' - - @type blocked: L{NoneType } or L{list} of 2-L{tuple} of - (E{1}) L{bytes} (E{2}) L{tuple} of L{bytes} - @ivar blocked: A list of blocked commands. While a response to a command - is being generated by the server, other commands are blocked. When - no command is outstanding, C{blocked} is set to none. Otherwise, it - contains a list of information about blocked commands. Each list - entry consists of the command and the arguments to the command. - - @type _highest: L{int} - @ivar _highest: The 1-based index of the highest message retrieved. - - @type _auth: L{IUsernameHashedPassword - } provider - @ivar _auth: Authorization credentials. - """ - implements(interfaces.IProducer) - - magic = None - _userIs = None - _onLogout = None - - AUTH_CMDS = ['CAPA', 'USER', 'PASS', 'APOP', 'AUTH', 'RPOP', 'QUIT'] - - portal = None - factory = None - - # The mailbox we're serving - mbox = None - - # Set this pretty low -- POP3 clients are expected to log in, download - # everything, and log out. - timeOut = 300 - - state = "COMMAND" - - # PIPELINE - blocked = None - - # Cooperate and suchlike. - schedule = staticmethod(task.coiterate) - - _highest = 0 - - def connectionMade(self): - """ - Send a greeting to the client after the connection has been made. - """ - if self.magic is None: - self.magic = self.generateMagic() - self.successResponse(self.magic) - self.setTimeout(self.timeOut) - if getattr(self.factory, 'noisy', True): - log.msg("New connection from " + str(self.transport.getPeer())) - - - def connectionLost(self, reason): - """ - Clean up when the connection has been lost. - - @type reason: L{Failure} - @param reason: The reason the connection was terminated. - """ - if self._onLogout is not None: - self._onLogout() - self._onLogout = None - self.setTimeout(None) - - - def generateMagic(self): - """ - Generate an APOP challenge. - - @rtype: L{bytes} - @return: An RFC 822 message id format string. - """ - return smtp.messageid() - - - def successResponse(self, message=''): - """ - Send a response indicating success. - - @type message: stringifyable L{object} - @param message: An object whose string representation should be - included in the response. - """ - self.transport.write(successResponse(message)) - - - def failResponse(self, message=''): - """ - Send a response indicating failure. - - @type message: stringifyable L{object} - @param message: An object whose string representation should be - included in the response. - """ - self.sendLine('-ERR ' + str(message)) - - - def lineReceived(self, line): - """ - Pass a received line to a state machine function. - - @type line: L{bytes} - @param line: A received line. - """ - self.resetTimeout() - getattr(self, 'state_' + self.state)(line) - - - def _unblock(self, _): - """ - Process as many blocked commands as possible. - - If there are no more blocked commands, set up for the next command to - be sent immediately. - - @type _: L{object} - @param _: Ignored. - """ - commands = self.blocked - self.blocked = None - while commands and self.blocked is None: - cmd, args = commands.pop(0) - self.processCommand(cmd, *args) - if self.blocked is not None: - self.blocked.extend(commands) - - - def state_COMMAND(self, line): - """ - Handle received lines for the COMMAND state in which commands from the - client are expected. - - @type line: L{bytes} - @param line: A received command. - """ - try: - return self.processCommand(*line.split(' ')) - except (ValueError, AttributeError, POP3Error, TypeError), e: - log.err() - self.failResponse('bad protocol or server: %s: %s' % (e.__class__.__name__, e)) - - - def processCommand(self, command, *args): - """ - Dispatch a command from the client for handling. - - @type command: L{bytes} - @param command: A POP3 command. - - @type args: L{tuple} of L{bytes} - @param args: Arguments to the command. - - @raise POP3Error: When the command is invalid or the command requires - prior authentication which hasn't been performed. - """ - if self.blocked is not None: - self.blocked.append((command, args)) - return - - command = command.upper() - authCmd = command in self.AUTH_CMDS - if not self.mbox and not authCmd: - raise POP3Error("not authenticated yet: cannot do " + command) - f = getattr(self, 'do_' + command, None) - if f: - return f(*args) - raise POP3Error("Unknown protocol command: " + command) - - - def listCapabilities(self): - """ - Return a list of server capabilities suitable for use in a CAPA - response. - - @rtype: L{list} of L{bytes} - @return: A list of server capabilities. - """ - baseCaps = [ - "TOP", - "USER", - "UIDL", - "PIPELINE", - "CELERITY", - "AUSPEX", - "POTENCE", - ] - - if IServerFactory.providedBy(self.factory): - # Oh my god. We can't just loop over a list of these because - # each has spectacularly different return value semantics! - try: - v = self.factory.cap_IMPLEMENTATION() - except NotImplementedError: - pass - except: - log.err() - else: - baseCaps.append("IMPLEMENTATION " + str(v)) - - try: - v = self.factory.cap_EXPIRE() - except NotImplementedError: - pass - except: - log.err() - else: - if v is None: - v = "NEVER" - if self.factory.perUserExpiration(): - if self.mbox: - v = str(self.mbox.messageExpiration) - else: - v = str(v) + " USER" - v = str(v) - baseCaps.append("EXPIRE " + v) - - try: - v = self.factory.cap_LOGIN_DELAY() - except NotImplementedError: - pass - except: - log.err() - else: - if self.factory.perUserLoginDelay(): - if self.mbox: - v = str(self.mbox.loginDelay) - else: - v = str(v) + " USER" - v = str(v) - baseCaps.append("LOGIN-DELAY " + v) - - try: - v = self.factory.challengers - except AttributeError: - pass - except: - log.err() - else: - baseCaps.append("SASL " + ' '.join(v.keys())) - return baseCaps - - - def do_CAPA(self): - """ - Handle a CAPA command. - - Respond with the server capabilities. - """ - self.successResponse("I can do the following:") - for cap in self.listCapabilities(): - self.sendLine(cap) - self.sendLine(".") - - - def do_AUTH(self, args=None): - """ - Handle an AUTH command. - - If the AUTH extension is not supported, send an error response. If an - authentication mechanism was not specified in the command, send a list - of all supported authentication methods. Otherwise, send an - authentication challenge to the client and transition to the - AUTH state. - - @type args: L{bytes} or L{NoneType } - @param args: The name of an authentication mechanism. - """ - if not getattr(self.factory, 'challengers', None): - self.failResponse("AUTH extension unsupported") - return - - if args is None: - self.successResponse("Supported authentication methods:") - for a in self.factory.challengers: - self.sendLine(a.upper()) - self.sendLine(".") - return - - auth = self.factory.challengers.get(args.strip().upper()) - if not self.portal or not auth: - self.failResponse("Unsupported SASL selected") - return - - self._auth = auth() - chal = self._auth.getChallenge() - - self.sendLine('+ ' + base64.encodestring(chal).rstrip('\n')) - self.state = 'AUTH' - - - def state_AUTH(self, line): - """ - Handle received lines for the AUTH state in which an authentication - challenge response from the client is expected. - - Transition back to the COMMAND state. Check the credentials and - complete the authorization process with the L{_cbMailbox} - callback function on success or the L{_ebMailbox} and L{_ebUnexpected} - errback functions on failure. - - @type line: L{bytes} - @param line: The challenge response. - """ - self.state = "COMMAND" - try: - parts = base64.decodestring(line).split(None, 1) - except binascii.Error: - self.failResponse("Invalid BASE64 encoding") - else: - if len(parts) != 2: - self.failResponse("Invalid AUTH response") - return - self._auth.username = parts[0] - self._auth.response = parts[1] - d = self.portal.login(self._auth, None, IMailbox) - d.addCallback(self._cbMailbox, parts[0]) - d.addErrback(self._ebMailbox) - d.addErrback(self._ebUnexpected) - - - def do_APOP(self, user, digest): - """ - Handle an APOP command. - - Perform APOP authentication and complete the authorization process with - the L{_cbMailbox} callback function on success or the L{_ebMailbox} - and L{_ebUnexpected} errback functions on failure. - - @type user: L{bytes} - @param user: A username. - - @type digest: L{bytes} - @param digest: An MD5 digest string. - """ - d = defer.maybeDeferred(self.authenticateUserAPOP, user, digest) - d.addCallbacks(self._cbMailbox, self._ebMailbox, callbackArgs=(user,) - ).addErrback(self._ebUnexpected) - - - def _cbMailbox(self, (interface, avatar, logout), user): - """ - Complete successful authentication. - - Save the mailbox and logout function for the authenticated user and - send a successful response to the client. - - @type interface: C{zope.interface.Interface} - @param interface: The interface supported by the avatar. - - @type avatar: L{IMailbox} provider - @param avatar: The mailbox for the authenticated user. - - @type logout: no-argument callable - @param logout: The function to be invoked when the session is - terminated. - - @type user: L{bytes} - @param user: The user being authenticated. - """ - if interface is not IMailbox: - self.failResponse('Authentication failed') - log.err("_cbMailbox() called with an interface other than IMailbox") - return - - self.mbox = avatar - self._onLogout = logout - self.successResponse('Authentication succeeded') - if getattr(self.factory, 'noisy', True): - log.msg("Authenticated login for " + user) - - - def _ebMailbox(self, failure): - """ - Handle an expected authentication failure. - - Send an appropriate error response for a L{LoginDenied} or - L{LoginFailed} authentication failure. - - @type failure: L{Failure} - @param failure: The authentication error. - """ - failure = failure.trap(cred.error.LoginDenied, cred.error.LoginFailed) - if issubclass(failure, cred.error.LoginDenied): - self.failResponse("Access denied: " + str(failure)) - elif issubclass(failure, cred.error.LoginFailed): - self.failResponse('Authentication failed') - if getattr(self.factory, 'noisy', True): - log.msg("Denied login attempt from " + str(self.transport.getPeer())) - - - def _ebUnexpected(self, failure): - """ - Handle an unexpected authentication failure. - - Send an error response for an unexpected authentication failure. - - @type failure: L{Failure} - @param failure: The authentication error. - """ - self.failResponse('Server error: ' + failure.getErrorMessage()) - log.err(failure) - - - def do_USER(self, user): - """ - Handle a USER command. - - Save the username and send a successful response prompting the client - for the password. - - @type user: L{bytes} - @param user: A username. - """ - self._userIs = user - self.successResponse('USER accepted, send PASS') - - - def do_PASS(self, password): - """ - Handle a PASS command. - - If a USER command was previously received, authenticate the user and - complete the authorization process with the L{_cbMailbox} callback - function on success or the L{_ebMailbox} and L{_ebUnexpected} errback - functions on failure. If a USER command was not previously received, - send an error response. - - @type password: L{bytes} - @param password: A password. - """ - if self._userIs is None: - self.failResponse("USER required before PASS") - return - user = self._userIs - self._userIs = None - d = defer.maybeDeferred(self.authenticateUserPASS, user, password) - d.addCallbacks(self._cbMailbox, self._ebMailbox, callbackArgs=(user,) - ).addErrback(self._ebUnexpected) - - - def _longOperation(self, d): - """ - Stop timeouts and block further command processing while a long - operation completes. - - @type d: L{Deferred } - @param d: A deferred which triggers at the completion of a long - operation. - - @rtype: L{Deferred } - @return: A deferred which triggers after command processing resumes and - timeouts restart after the completion of a long operation. - """ - timeOut = self.timeOut - self.setTimeout(None) - self.blocked = [] - d.addCallback(self._unblock) - d.addCallback(lambda ign: self.setTimeout(timeOut)) - return d - - - def _coiterate(self, gen): - """ - Direct the output of an iterator to the transport and arrange for - iteration to take place. - - @type gen: iterable which yields L{bytes} - @param gen: An iterator over strings. - - @rtype: L{Deferred } - @return: A deferred which fires when the iterator finishes. - """ - return self.schedule(_IteratorBuffer(self.transport.writeSequence, gen)) - - - def do_STAT(self): - """ - Handle a STAT command. - - @rtype: L{Deferred } - @return: A deferred which triggers after the response to the STAT - command has been issued. - """ - d = defer.maybeDeferred(self.mbox.listMessages) - def cbMessages(msgs): - return self._coiterate(formatStatResponse(msgs)) - def ebMessages(err): - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_STAT failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessages, ebMessages)) - - - def do_LIST(self, i=None): - """ - Handle a LIST command. - - @type i: L{bytes} or L{NoneType } - @param i: A 1-based message index. - - @rtype: L{Deferred } - @return: A deferred which triggers after the response to the LIST - command has been issued. - """ - if i is None: - d = defer.maybeDeferred(self.mbox.listMessages) - def cbMessages(msgs): - return self._coiterate(formatListResponse(msgs)) - def ebMessages(err): - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_LIST failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessages, ebMessages)) - else: - try: - i = int(i) - if i < 1: - raise ValueError() - except ValueError: - self.failResponse("Invalid message-number: %r" % (i,)) - else: - d = defer.maybeDeferred(self.mbox.listMessages, i - 1) - def cbMessage(msg): - self.successResponse('%d %d' % (i, msg)) - def ebMessage(err): - errcls = err.check(ValueError, IndexError) - if errcls is not None: - if errcls is IndexError: - # IndexError was supported for a while, but really - # shouldn't be. One error condition, one exception - # type. See ticket #6669. - warnings.warn( - "twisted.mail.pop3.IMailbox.listMessages may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.", - PendingDeprecationWarning) - self.failResponse("Invalid message-number: %r" % (i,)) - else: - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_LIST failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessage, ebMessage)) - - - def do_UIDL(self, i=None): - """ - Handle a UIDL command. - - @type i: L{bytes} or L{NoneType } - @param i: A 1-based message index. - - @rtype: L{Deferred } - @return: A deferred which triggers after the response to the UIDL - command has been issued. - """ - if i is None: - d = defer.maybeDeferred(self.mbox.listMessages) - def cbMessages(msgs): - return self._coiterate(formatUIDListResponse(msgs, self.mbox.getUidl)) - def ebMessages(err): - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_UIDL failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessages, ebMessages)) - else: - try: - i = int(i) - if i < 1: - raise ValueError() - except ValueError: - self.failResponse("Bad message number argument") - else: - try: - msg = self.mbox.getUidl(i - 1) - except IndexError: - # XXX TODO See above comment regarding IndexError. - warnings.warn( - "twisted.mail.pop3.IMailbox.getUidl may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.", - PendingDeprecationWarning) - self.failResponse("Bad message number argument") - except ValueError: - self.failResponse("Bad message number argument") - else: - self.successResponse(str(msg)) - - - def _getMessageFile(self, i): - """ - Retrieve the size and contents of a message. - - @type i: L{bytes} - @param i: A 1-based message index. - - @rtype: L{Deferred } which successfully fires with - 2-L{tuple} of (E{1}) L{int}, (E{2}) file-like object - @return: A deferred which successfully fires with the size of the - message and a file containing the contents of the message. - """ - try: - msg = int(i) - 1 - if msg < 0: - raise ValueError() - except ValueError: - self.failResponse("Bad message number argument") - return defer.succeed(None) - - sizeDeferred = defer.maybeDeferred(self.mbox.listMessages, msg) - def cbMessageSize(size): - if not size: - return defer.fail(_POP3MessageDeleted()) - fileDeferred = defer.maybeDeferred(self.mbox.getMessage, msg) - fileDeferred.addCallback(lambda fObj: (size, fObj)) - return fileDeferred - - def ebMessageSomething(err): - errcls = err.check(_POP3MessageDeleted, ValueError, IndexError) - if errcls is _POP3MessageDeleted: - self.failResponse("message deleted") - elif errcls in (ValueError, IndexError): - if errcls is IndexError: - # XXX TODO See above comment regarding IndexError. - warnings.warn( - "twisted.mail.pop3.IMailbox.listMessages may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.", - PendingDeprecationWarning) - self.failResponse("Bad message number argument") - else: - log.msg("Unexpected _getMessageFile failure:") - log.err(err) - return None - - sizeDeferred.addCallback(cbMessageSize) - sizeDeferred.addErrback(ebMessageSomething) - return sizeDeferred - - - def _sendMessageContent(self, i, fpWrapper, successResponse): - """ - Send the contents of a message. - - @type i: L{bytes} - @param i: A 1-based message index. - - @type fpWrapper: callable that takes a file-like object and returns - a file-like object - @param fpWrapper: - - @type successResponse: callable that takes L{int} and returns - L{bytes} - @param successResponse: - - @rtype: L{Deferred} - @return: A deferred which triggers after the message has been sent. - """ - d = self._getMessageFile(i) - def cbMessageFile(info): - if info is None: - # Some error occurred - a failure response has been sent - # already, just give up. - return - - self._highest = max(self._highest, int(i)) - resp, fp = info - fp = fpWrapper(fp) - self.successResponse(successResponse(resp)) - s = basic.FileSender() - d = s.beginFileTransfer(fp, self.transport, self.transformChunk) - - def cbFileTransfer(lastsent): - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - - def ebFileTransfer(err): - self.transport.loseConnection() - log.msg("Unexpected error in _sendMessageContent:") - log.err(err) - - d.addCallback(cbFileTransfer) - d.addErrback(ebFileTransfer) - return d - return self._longOperation(d.addCallback(cbMessageFile)) - - - def do_TOP(self, i, size): - """ - Handle a TOP command. - - @type i: L{bytes} - @param i: A 1-based message index. - - @type size: L{bytes} - @param size: The number of lines of the message to retrieve. - - @rtype: L{Deferred} - @return: A deferred which triggers after the response to the TOP - command has been issued. - """ - try: - size = int(size) - if size < 0: - raise ValueError - except ValueError: - self.failResponse("Bad line count argument") - else: - return self._sendMessageContent( - i, - lambda fp: _HeadersPlusNLines(fp, size), - lambda size: "Top of message follows") - - - def do_RETR(self, i): - """ - Handle a RETR command. - - @type i: L{bytes} - @param i: A 1-based message index. - - @rtype: L{Deferred} - @return: A deferred which triggers after the response to the RETR - command has been issued. - """ - return self._sendMessageContent( - i, - lambda fp: fp, - lambda size: "%d" % (size,)) - - - def transformChunk(self, chunk): - """ - Transform a chunk of a message to POP3 message format. - - Make sure each line ends with C{'\\r\\n'} and byte-stuff the - termination character (C{'.'}) by adding an extra one when one appears - at the beginning of a line. - - @type chunk: L{bytes} - @param chunk: A string to transform. - - @rtype: L{bytes} - @return: The transformed string. - """ - return chunk.replace('\n', '\r\n').replace('\r\n.', '\r\n..') - - - def finishedFileTransfer(self, lastsent): - """ - Send the termination sequence. - - @type lastsent: L{bytes} - @param lastsent: The last character of the file. - """ - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - - - def do_DELE(self, i): - """ - Handle a DELE command. - - Mark a message for deletion and issue a successful response. - - @type i: L{int} - @param i: A 1-based message index. - """ - i = int(i)-1 - self.mbox.deleteMessage(i) - self.successResponse() - - - def do_NOOP(self): - """ - Handle a NOOP command. - - Do nothing but issue a successful response. - """ - self.successResponse() - - - def do_RSET(self): - """ - Handle a RSET command. - - Unmark any messages that have been flagged for deletion. - """ - try: - self.mbox.undeleteMessages() - except: - log.err() - self.failResponse() - else: - self._highest = 0 - self.successResponse() - - - def do_LAST(self): - """ - Handle a LAST command. - - Respond with the 1-based index of the highest retrieved message. - """ - self.successResponse(self._highest) - - - def do_RPOP(self, user): - """ - Handle an RPOP command. - - RPOP is not supported. Send an error response. - - @type user: L{bytes} - @param user: A username. - - """ - self.failResponse('permission denied, sucker') - - - def do_QUIT(self): - """ - Handle a QUIT command. - - Remove any messages marked for deletion, issue a successful response, - and drop the connection. - """ - if self.mbox: - self.mbox.sync() - self.successResponse() - self.transport.loseConnection() - - - def authenticateUserAPOP(self, user, digest): - """ - Perform APOP authentication. - - @type user: L{bytes} - @param user: The name of the user attempting to log in. - - @type digest: L{bytes} - @param digest: The challenge response. - - @rtype: L{Deferred } which successfully results in - 3-L{tuple} of (E{1}) L{IMailbox }, (E{2}) - L{IMailbox } provider, (E{3}) no-argument callable - @return: A deferred which fires when authentication is complete. If - successful, it returns an L{IMailbox } interface, a - mailbox, and a function to be invoked with the session is - terminated. If authentication fails, the deferred fails with an - L{UnathorizedLogin } error. - - @raise cred.error.UnauthorizedLogin: When authentication fails. - """ - if self.portal is not None: - return self.portal.login( - APOPCredentials(self.magic, user, digest), - None, - IMailbox - ) - raise cred.error.UnauthorizedLogin() - - - def authenticateUserPASS(self, user, password): - """ - Perform authentication for a username/password login. - - @type user: L{bytes} - @param user: The name of the user attempting to log in. - - @type password: L{bytes} - @param password: The password to authenticate with. - - @rtype: L{Deferred } which successfully results in - 3-L{tuple} of (E{1}) L{IMailbox }, (E{2}) L{IMailbox - } provider, (E{3}) no-argument callable - @return: A deferred which fires when authentication is complete. If - successful, it returns a L{pop3.IMailbox} interface, a mailbox, - and a function to be invoked with the session is terminated. - If authentication fails, the deferred fails with an - L{UnathorizedLogin } error. - - @raise cred.error.UnauthorizedLogin: When authentication fails. - """ - if self.portal is not None: - return self.portal.login( - cred.credentials.UsernamePassword(user, password), - None, - IMailbox - ) - raise cred.error.UnauthorizedLogin() - - - -class IServerFactory(Interface): - """ - An interface for querying capabilities of a POP3 server. - - Any cap_* method may raise L{NotImplementedError} if the particular - capability is not supported. If L{cap_EXPIRE()} does not raise - L{NotImplementedError}, L{perUserExpiration()} must be implemented, - otherwise they are optional. If L{cap_LOGIN_DELAY()} is implemented, - L{perUserLoginDelay()} must be implemented, otherwise they are optional. - - @type challengers: L{dict} of L{bytes} -> L{IUsernameHashedPassword - } - @ivar challengers: A mapping of challenger names to - L{IUsernameHashedPassword } - provider. - """ - def cap_IMPLEMENTATION(): - """ - Return a string describing the POP3 server implementation. - - @rtype: L{bytes} - @return: Server implementation information. - """ - - - def cap_EXPIRE(): - """ - Return the minimum number of days messages are retained. - - @rtype: L{int} or L{NoneType } - @return: The minimum number of days messages are retained or none, if - the server never deletes messages. - """ - - - def perUserExpiration(): - """ - Indicate whether the message expiration policy differs per user. - - @rtype: L{bool} - @return: C{True} when the message expiration policy differs per user, - C{False} otherwise. - """ - - - def cap_LOGIN_DELAY(): - """ - Return the minimum number of seconds between client logins. - - @rtype: L{int} - @return: The minimum number of seconds between client logins. - """ - - - def perUserLoginDelay(): - """ - Indicate whether the login delay period differs per user. - - @rtype: L{bool} - @return: C{True} when the login delay differs per user, C{False} - otherwise. - """ - - - -class IMailbox(Interface): - """ - An interface for mailbox access. - - Message indices are 0-based. - - @type loginDelay: L{int} - @ivar loginDelay: The number of seconds between allowed logins for the - user associated with this mailbox. - - @type messageExpiration: L{int} - @ivar messageExpiration: The number of days messages in this mailbox will - remain on the server before being deleted. - """ - def listMessages(index=None): - """ - Retrieve the size of a message, or, if none is specified, the size of - each message in the mailbox. - - @type index: L{int} or L{NoneType } - @param index: The 0-based index of the message. - - @rtype: L{int}, sequence of L{int}, or L{Deferred } - @return: The number of octets in the specified message, or, if an - index is not specified, a sequence of the number of octets for - all messages in the mailbox or a deferred which fires with - one of those. Any value which corresponds to a deleted message - is set to 0. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - - - def getMessage(index): - """ - Retrieve a file containing the contents of a message. - - @type index: L{int} - @param index: The 0-based index of a message. - - @rtype: file-like object - @return: A file containing the message. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - - - def getUidl(index): - """ - Get a unique identifier for a message. - - @type index: L{int} - @param index: The 0-based index of a message. - - @rtype: L{bytes} - @return: A string of printable characters uniquely identifying the - message for all time. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - - - def deleteMessage(index): - """ - Mark a message for deletion. - - This must not change the number of messages in this mailbox. Further - requests for the size of the deleted message should return 0. Further - requests for the message itself may raise an exception. - - @type index: L{int} - @param index: The 0-based index of a message. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - - - def undeleteMessages(): - """ - Undelete all messages marked for deletion. - - Any message which can be undeleted should be returned to its original - position in the message sequence and retain its original UID. - """ - - - def sync(): - """ - Discard the contents of any message marked for deletion. - """ - - - -class Mailbox: - """ - A base class for mailboxes. - """ - implements(IMailbox) - - def listMessages(self, i=None): - """ - Retrieve the size of a message, or, if none is specified, the size of - each message in the mailbox. - - @type i: L{int} or L{NoneType } - @param i: The 0-based index of the message. - - @rtype: L{int}, sequence of L{int}, or L{Deferred } - @return: The number of octets in the specified message, or, if an - index is not specified, a sequence of the number of octets for - all messages in the mailbox or a deferred which fires with - one of those. Any value which corresponds to a deleted message - is set to 0. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - return [] - - - def getMessage(self, i): - """ - Retrieve a file containing the contents of a message. - - @type i: L{int} - @param i: The 0-based index of a message. - - @rtype: file-like object - @return: A file containing the message. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - raise ValueError - - - def getUidl(self, i): - """ - Get a unique identifier for a message. - - @type i: L{int} - @param i: The 0-based index of a message. - - @rtype: L{bytes} - @return: A string of printable characters uniquely identifying the - message for all time. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - raise ValueError - - - def deleteMessage(self, i): - """ - Mark a message for deletion. - - This must not change the number of messages in this mailbox. Further - requests for the size of the deleted message should return 0. Further - requests for the message itself may raise an exception. - - @type i: L{int} - @param i: The 0-based index of a message. - - @raise ValueError or IndexError: When the index does not correspond to - a message in the mailbox. The use of ValueError is preferred. - """ - raise ValueError - - - def undeleteMessages(self): - """ - Undelete all messages marked for deletion. - - Any message which can be undeleted should be returned to its original - position in the message sequence and retain its original UID. - """ - pass - - - def sync(self): - """ - Discard the contents of any message marked for deletion. - """ - pass - - - -NONE, SHORT, FIRST_LONG, LONG = range(4) - -NEXT = {} -NEXT[NONE] = NONE -NEXT[SHORT] = NONE -NEXT[FIRST_LONG] = LONG -NEXT[LONG] = NONE - - - -class POP3Client(basic.LineOnlyReceiver): - """ - A POP3 client protocol. - - @type mode: L{int} - @ivar mode: The type of response expected from the server. Choices include - none (0), a one line response (1), the first line of a multi-line - response (2), and subsequent lines of a multi-line response (3). - - @type command: L{bytes} - @ivar command: The command most recently sent to the server. - - @type welcomeRe: L{RegexObject } - @ivar welcomeRe: A regular expression which matches the APOP challenge in - the server greeting. - - @type welcomeCode: L{bytes} - @ivar welcomeCode: The APOP challenge passed in the server greeting. - """ - mode = SHORT - command = 'WELCOME' - import re - welcomeRe = re.compile('<(.*)>') - - def __init__(self): - """ - Issue deprecation warning. - """ - import warnings - warnings.warn("twisted.mail.pop3.POP3Client is deprecated, " - "please use twisted.mail.pop3.AdvancedPOP3Client " - "instead.", DeprecationWarning, - stacklevel=3) - - - def sendShort(self, command, params=None): - """ - Send a POP3 command to which a short response is expected. - - @type command: L{bytes} - @param command: A POP3 command. - - @type params: stringifyable L{object} or L{NoneType } - @param params: Command arguments. - """ - if params is not None: - self.sendLine('%s %s' % (command, params)) - else: - self.sendLine(command) - self.command = command - self.mode = SHORT - - - def sendLong(self, command, params): - """ - Send a POP3 command to which a long response is expected. - - @type command: L{bytes} - @param command: A POP3 command. - - @type params: stringifyable L{object} - @param params: Command arguments. - """ - if params: - self.sendLine('%s %s' % (command, params)) - else: - self.sendLine(command) - self.command = command - self.mode = FIRST_LONG - - - def handle_default(self, line): - """ - Handle responses from the server for which no other handler exists. - - @type line: L{bytes} - @param line: A received line. - """ - if line[:-4] == '-ERR': - self.mode = NONE - - - def handle_WELCOME(self, line): - """ - Handle a server response which is expected to be a server greeting. - - @type line: L{bytes} - @param line: A received line. - """ - code, data = line.split(' ', 1) - if code != '+OK': - self.transport.loseConnection() - else: - m = self.welcomeRe.match(line) - if m: - self.welcomeCode = m.group(1) - - - def _dispatch(self, command, default, *args): - """ - Dispatch a response from the server for handling. - - Command X is dispatched to handle_X() if it exists. If not, it is - dispatched to the default handler. - - @type command: L{bytes} - @param command: The command. - - @type default: callable that takes L{bytes} or - L{NoneType } - @param default: The default handler. - - @type args: L{tuple} or L{NoneType } - @param args: Arguments to the handler function. - """ - try: - method = getattr(self, 'handle_'+command, default) - if method is not None: - method(*args) - except: - log.err() - - - def lineReceived(self, line): - """ - Dispatch a received line for processing. - - The choice of function to handle the received line is based on the - type of response expected to the command sent to the server and how - much of that response has been received. - - An expected one line response to command X is handled by handle_X(). - The first line of a multi-line response to command X is also handled by - handle_X(). Subsequent lines of the multi-line response are handled by - handle_X_continue() except for the last line which is handled by - handle_X_end(). - - @type line: L{bytes} - @param line: A received line. - """ - if self.mode == SHORT or self.mode == FIRST_LONG: - self.mode = NEXT[self.mode] - self._dispatch(self.command, self.handle_default, line) - elif self.mode == LONG: - if line == '.': - self.mode = NEXT[self.mode] - self._dispatch(self.command+'_end', None) - return - if line[:1] == '.': - line = line[1:] - self._dispatch(self.command+"_continue", None, line) - - - def apopAuthenticate(self, user, password, magic): - """ - Perform an authenticated login. - - @type user: L{bytes} - @param user: The username with which to log in. - - @type password: L{bytes} - @param password: The password with which to log in. - - @type magic: L{bytes} - @param magic: The challenge provided by the server. - """ - digest = md5(magic + password).hexdigest() - self.apop(user, digest) - - - def apop(self, user, digest): - """ - Send an APOP command to perform authenticated login. - - @type user: L{bytes} - @param user: The username with which to log in. - - @type digest: L{bytes} - @param digest: The challenge response with which to authenticate. - """ - self.sendLong('APOP', ' '.join((user, digest))) - - - def retr(self, i): - """ - Send a RETR command to retrieve a message from the server. - - @type i: L{int} or L{bytes} - @param i: A 0-based message index. - """ - self.sendLong('RETR', i) - - - def dele(self, i): - """ - Send a DELE command to delete a message from the server. - - @type i: L{int} or L{bytes} - @param i: A 0-based message index. - """ - self.sendShort('DELE', i) - - - def list(self, i=''): - """ - Send a LIST command to retrieve the size of a message or, if no message - is specified, the sizes of all messages. - - @type i: L{int} or L{bytes} - @param i: A 0-based message index or the empty string to specify all - messages. - """ - self.sendLong('LIST', i) - - - def uidl(self, i=''): - """ - Send a UIDL command to retrieve the unique identifier of a message or, - if no message is specified, the unique identifiers of all messages. - - @type i: L{int} or L{bytes} - @param i: A 0-based message index or the empty string to specify all - messages. - """ - self.sendLong('UIDL', i) - - - def user(self, name): - """ - Send a USER command to perform the first half of a plaintext login. - - @type name: L{bytes} - @param name: The username with which to log in. - """ - self.sendShort('USER', name) - - - def pass_(self, pass_): - """ - Perform the second half of a plaintext login. - - @type pass_: L{bytes} - @param pass_: The plaintext password with which to authenticate. - """ - self.sendShort('PASS', pass_) - - - def quit(self): - """ - Send a QUIT command to disconnect from the server. - """ - self.sendShort('QUIT') - - -from twisted.mail.pop3client import POP3Client as AdvancedPOP3Client -from twisted.mail.pop3client import POP3ClientError -from twisted.mail.pop3client import InsecureAuthenticationDisallowed -from twisted.mail.pop3client import ServerErrorResponse -from twisted.mail.pop3client import LineTooLong -from twisted.mail.pop3client import TLSError -from twisted.mail.pop3client import TLSNotSupportedError - -__all__ = [ - # Interfaces - 'IMailbox', 'IServerFactory', - - # Exceptions - 'POP3Error', 'POP3ClientError', 'InsecureAuthenticationDisallowed', - 'ServerErrorResponse', 'LineTooLong', 'TLSError', 'TLSNotSupportedError', - - # Protocol classes - 'POP3', 'POP3Client', 'AdvancedPOP3Client', - - # Misc - 'APOPCredentials', 'Mailbox'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pop3client.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pop3client.py deleted file mode 100644 index 02d581a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/pop3client.py +++ /dev/null @@ -1,1320 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_pop3client -*- -# Copyright (c) 2001-2004 Divmod Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A POP3 client protocol implementation. - -Don't use this module directly. Use twisted.mail.pop3 instead. - -@author: Jp Calderone -""" - -import re -from hashlib import md5 - -from twisted.python import log -from twisted.internet import defer -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import error -from twisted.internet import interfaces - -OK = '+OK' -ERR = '-ERR' - - - -class POP3ClientError(Exception): - """ - The base class for all exceptions raised by POP3Client. - """ - - - -class InsecureAuthenticationDisallowed(POP3ClientError): - """ - An error indicating secure authentication was required but no mechanism - could be found. - """ - - - -class TLSError(POP3ClientError): - """ - An error indicating secure authentication was required but either the - transport does not support TLS or no TLS context factory was supplied. - """ - - - -class TLSNotSupportedError(POP3ClientError): - """ - An error indicating secure authentication was required but the server does - not support TLS. - """ - - - -class ServerErrorResponse(POP3ClientError): - """ - An error indicating that the server returned an error response to a - request. - - @ivar consumer: See L{__init__} - """ - def __init__(self, reason, consumer=None): - """ - @type reason: L{bytes} - @param reason: The server response minus the status indicator. - - @type consumer: callable that takes L{object} - @param consumer: The function meant to handle the values for a - multi-line response. - """ - POP3ClientError.__init__(self, reason) - self.consumer = consumer - - - -class LineTooLong(POP3ClientError): - """ - An error indicating that the server sent a line which exceeded the - maximum line length (L{LineOnlyReceiver.MAX_LENGTH}). - """ - - - -class _ListSetter: - """ - A utility class to construct a list from a multi-line response accounting - for deleted messages. - - POP3 responses sometimes occur in the form of a list of lines containing - two pieces of data, a message index and a value of some sort. When a - message is deleted, it is omitted from these responses. The L{setitem} - method of this class is meant to be called with these two values. In the - cases where indices are skipped, it takes care of padding out the missing - values with C{None}. - - @ivar L: See L{__init__} - """ - def __init__(self, L): - """ - @type L: L{list} of L{object} - @param L: The list being constructed. An empty list should be - passed in. - """ - self.L = L - - - def setitem(self, (item, value)): - """ - Add the value at the specified position, padding out missing entries. - - @type item: L{int} - @param item: The 0-based index in the list at which the value should - be placed. - - @type value: L{object} - @param value: The value to put in the list. - """ - diff = item - len(self.L) + 1 - if diff > 0: - self.L.extend([None] * diff) - self.L[item] = value - - - -def _statXform(line): - """ - Parse the response to a STAT command. - - @type line: L{bytes} - @param line: The response from the server to a STAT command minus the - status indicator. - - @rtype: 2-L{tuple} of (0) L{int}, (1) L{int} - @return: The number of messages in the mailbox and the size of the mailbox. - """ - numMsgs, totalSize = line.split(None, 1) - return int(numMsgs), int(totalSize) - - - -def _listXform(line): - """ - Parse a line of the response to a LIST command. - - The line from the LIST response consists of a 1-based message number - followed by a size. - - @type line: L{bytes} - @param line: A non-initial line from the multi-line response to a LIST - command. - - @rtype: 2-L{tuple} of (0) L{int}, (1) L{int} - @return: The 0-based index of the message and the size of the message. - """ - index, size = line.split(None, 1) - return int(index) - 1, int(size) - - - -def _uidXform(line): - """ - Parse a line of the response to a UIDL command. - - The line from the UIDL response consists of a 1-based message number - followed by a unique id. - - @type line: L{bytes} - @param line: A non-initial line from the multi-line response to a UIDL - command. - - @rtype: 2-L{tuple} of (0) L{int}, (1) L{bytes} - @return: The 0-based index of the message and the unique identifier - for the message. - """ - index, uid = line.split(None, 1) - return int(index) - 1, uid - - - -def _codeStatusSplit(line): - """ - Parse the first line of a multi-line server response. - - @type line: L{bytes} - @param line: The first line of a multi-line server response. - - @rtype: 2-tuple of (0) L{bytes}, (1) L{bytes} - @return: The status indicator and the rest of the server response. - """ - parts = line.split(' ', 1) - if len(parts) == 1: - return parts[0], '' - return parts - - - -def _dotUnquoter(line): - """ - Remove a byte-stuffed termination character at the beginning of a line if - present. - - When the termination character (C{'.'}) appears at the beginning of a line, - the server byte-stuffs it by adding another termination character to - avoid confusion with the terminating sequence (C{'.\\r\\n'}). - - @type line: L{bytes} - @param line: A received line. - - @rtype: L{bytes} - @return: The line without the byte-stuffed termination character at the - beginning if it was present. Otherwise, the line unchanged. - """ - if line.startswith('..'): - return line[1:] - return line - - - -class POP3Client(basic.LineOnlyReceiver, policies.TimeoutMixin): - """ - A POP3 client protocol. - - Instances of this class provide a convenient, efficient API for - retrieving and deleting messages from a POP3 server. - - This API provides a pipelining interface but POP3 pipelining - on the network is not yet supported. - - @type startedTLS: L{bool} - @ivar startedTLS: An indication of whether TLS has been negotiated - successfully. - - @type allowInsecureLogin: L{bool} - @ivar allowInsecureLogin: An indication of whether plaintext login should - be allowed when the server offers no authentication challenge and the - transport does not offer any protection via encryption. - - @type serverChallenge: L{bytes} or L{NoneType } - @ivar serverChallenge: The challenge received in the server greeting. - - @type timeout: L{int} - @ivar timeout: The number of seconds to wait on a response from the server - before timing out a connection. If the number is <= 0, no timeout - checking will be performed. - - @type _capCache: L{NoneType } or L{dict} mapping L{bytes} - to L{list} of L{bytes} and/or L{bytes} to L{NoneType } - @ivar _capCache: The cached server capabilities. Capabilities are not - allowed to change during the session (except when TLS is negotiated), - so the first response to a capabilities command can be used for - later lookups. - - @type _challengeMagicRe: L{RegexObject } - @ivar _challengeMagicRe: A regular expression which matches the - challenge in the server greeting. - - @type _blockedQueue: L{NoneType } or L{list} of 3-L{tuple} - of (0) L{Deferred }, (1) callable which results - in a L{Deferred }, (2) L{tuple} - @ivar _blockedQueue: A list of blocked commands. While a command is - awaiting a response from the server, other commands are blocked. When - no command is outstanding, C{_blockedQueue} is set to C{None}. - Otherwise, it contains a list of information about blocked commands. - Each list entry provides the following information about a blocked - command: the deferred that should be called when the response to the - command is received, the function that sends the command, and the - arguments to the function. - - @type _waiting: L{Deferred } or - L{NoneType } - @ivar _waiting: A deferred which fires when the response to the - outstanding command is received from the server. - - @type _timedOut: L{bool} - @ivar _timedOut: An indication of whether the connection was dropped - because of a timeout. - - @type _greetingError: L{bytes} or L{NoneType } - @ivar _greetingError: The server greeting minus the status indicator, when - the connection was dropped because of an error in the server greeting. - Otherwise, C{None}. - - @type state: L{bytes} - @ivar state: The state which indicates what type of response is expected - from the server. Valid states are: 'WELCOME', 'WAITING', 'SHORT', - 'LONG_INITIAL', 'LONG'. - - @type _xform: L{NoneType} or callable that takes L{bytes} - and returns L{object} - @ivar _xform: The transform function which is used to convert each - line of a multi-line response into usable values for use by the - consumer function. If C{None}, each line of the multi-line response - is sent directly to the consumer function. - - @type _consumer: callable that takes L{object} - @ivar _consumer: The consumer function which is used to store the - values derived by the transform function from each line of a - multi-line response into a list. - """ - startedTLS = False - allowInsecureLogin = False - timeout = 0 - serverChallenge = None - - _capCache = None - _challengeMagicRe = re.compile('(<[^>]+>)') - _blockedQueue = None - _waiting = None - _timedOut = False - _greetingError = None - - def _blocked(self, f, *a): - """ - Block a command, if necessary. - - If commands are being blocked, append information about the function - which sends the command to a list and return a deferred that will be - chained with the return value of the function when it eventually runs. - Otherwise, set up for subsequent commands to be blocked and return - C{None}. - - @type f: callable - @param f: A function which sends a command. - - @type a: L{tuple} - @param a: Arguments to the function. - - @rtype: L{NoneType } or L{Deferred } - @return: C{None} if the command can run immediately. Otherwise, - a deferred that will eventually trigger with the return value of - the function. - """ - if self._blockedQueue is not None: - d = defer.Deferred() - self._blockedQueue.append((d, f, a)) - return d - self._blockedQueue = [] - return None - - - def _unblock(self): - """ - Send the next blocked command. - - If there are no more commands in the blocked queue, set up for the next - command to be sent immediately. - """ - if self._blockedQueue == []: - self._blockedQueue = None - elif self._blockedQueue is not None: - _blockedQueue = self._blockedQueue - self._blockedQueue = None - - d, f, a = _blockedQueue.pop(0) - d2 = f(*a) - d2.chainDeferred(d) - # f is a function which uses _blocked (otherwise it wouldn't - # have gotten into the blocked queue), which means it will have - # re-set _blockedQueue to an empty list, so we can put the rest - # of the blocked queue back into it now. - self._blockedQueue.extend(_blockedQueue) - - - def sendShort(self, cmd, args): - """ - Send a POP3 command to which a short response is expected. - - Block all further commands from being sent until the response is - received. Transition the state to SHORT. - - @type cmd: L{bytes} - @param cmd: A POP3 command. - - @type args: L{bytes} - @param args: The command arguments. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the entire response is received. - On an OK response, it returns the response from the server minus - the status indicator. On an ERR response, it issues a server - error response failure with the response from the server minus the - status indicator. - """ - d = self._blocked(self.sendShort, cmd, args) - if d is not None: - return d - - if args: - self.sendLine(cmd + ' ' + args) - else: - self.sendLine(cmd) - self.state = 'SHORT' - self._waiting = defer.Deferred() - return self._waiting - - - def sendLong(self, cmd, args, consumer, xform): - """ - Send a POP3 command to which a multi-line response is expected. - - Block all further commands from being sent until the entire response is - received. Transition the state to LONG_INITIAL. - - @type cmd: L{bytes} - @param cmd: A POP3 command. - - @type args: L{bytes} - @param args: The command arguments. - - @type consumer: callable that takes L{object} - @param consumer: A consumer function which should be used to put - the values derived by a transform function from each line of the - multi-line response into a list. - - @type xform: L{NoneType } or callable that takes - L{bytes} and returns L{object} - @param xform: A transform function which should be used to transform - each line of the multi-line response into usable values for use by - a consumer function. If C{None}, each line of the multi-line - response should be sent directly to the consumer function. - - @rtype: L{Deferred } which successfully fires with - callable that takes L{object} and fails with L{ServerErrorResponse} - @return: A deferred which fires when the entire response is received. - On an OK response, it returns the consumer function. On an ERR - response, it issues a server error response failure with the - response from the server minus the status indicator and the - consumer function. - """ - d = self._blocked(self.sendLong, cmd, args, consumer, xform) - if d is not None: - return d - - if args: - self.sendLine(cmd + ' ' + args) - else: - self.sendLine(cmd) - self.state = 'LONG_INITIAL' - self._xform = xform - self._consumer = consumer - self._waiting = defer.Deferred() - return self._waiting - - - # Twisted protocol callback - def connectionMade(self): - """ - Wait for a greeting from the server after the connection has been made. - - Start the connection in the WELCOME state. - """ - if self.timeout > 0: - self.setTimeout(self.timeout) - - self.state = 'WELCOME' - self._blockedQueue = [] - - - def timeoutConnection(self): - """ - Drop the connection when the server does not respond in time. - """ - self._timedOut = True - self.transport.loseConnection() - - - def connectionLost(self, reason): - """ - Clean up when the connection has been lost. - - When the loss of connection was initiated by the client due to a - timeout, the L{_timedOut} flag will be set. When it was initiated by - the client due to an error in the server greeting, L{_greetingError} - will be set to the server response minus the status indicator. - - @type reason: L{Failure } - @param reason: The reason the connection was terminated. - """ - if self.timeout > 0: - self.setTimeout(None) - - if self._timedOut: - reason = error.TimeoutError() - elif self._greetingError: - reason = ServerErrorResponse(self._greetingError) - - d = [] - if self._waiting is not None: - d.append(self._waiting) - self._waiting = None - if self._blockedQueue is not None: - d.extend([deferred for (deferred, f, a) in self._blockedQueue]) - self._blockedQueue = None - for w in d: - w.errback(reason) - - - def lineReceived(self, line): - """ - Pass a received line to a state machine function and - transition to the next state. - - @type line: L{bytes} - @param line: A received line. - """ - if self.timeout > 0: - self.resetTimeout() - - state = self.state - self.state = None - state = getattr(self, 'state_' + state)(line) or state - if self.state is None: - self.state = state - - - def lineLengthExceeded(self, buffer): - """ - Drop the connection when a server response exceeds the maximum line - length (L{LineOnlyReceiver.MAX_LENGTH}). - - @type buffer: L{bytes} - @param buffer: A received line which exceeds the maximum line length. - """ - # XXX - We need to be smarter about this - if self._waiting is not None: - waiting, self._waiting = self._waiting, None - waiting.errback(LineTooLong()) - self.transport.loseConnection() - - - # POP3 Client state logic - don't touch this. - def state_WELCOME(self, line): - """ - Handle server responses for the WELCOME state in which the server - greeting is expected. - - WELCOME is the first state. The server should send one line of text - with a greeting and possibly an APOP challenge. Transition the state - to WAITING. - - @type line: L{bytes} - @param line: A line received from the server. - - @rtype: L{bytes} - @return: The next state. - """ - code, status = _codeStatusSplit(line) - if code != OK: - self._greetingError = status - self.transport.loseConnection() - else: - m = self._challengeMagicRe.search(status) - - if m is not None: - self.serverChallenge = m.group(1) - - self.serverGreeting(status) - - self._unblock() - return 'WAITING' - - - def state_WAITING(self, line): - """ - Log an error for server responses received in the WAITING state during - which the server is not expected to send anything. - - @type line: L{bytes} - @param line: A line received from the server. - """ - log.msg("Illegal line from server: " + repr(line)) - - - def state_SHORT(self, line): - """ - Handle server responses for the SHORT state in which the server is - expected to send a single line response. - - Parse the response and fire the deferred which is waiting on receipt of - a complete response. Transition the state back to WAITING. - - @type line: L{bytes} - @param line: A line received from the server. - - @rtype: L{bytes} - @return: The next state. - """ - deferred, self._waiting = self._waiting, None - self._unblock() - code, status = _codeStatusSplit(line) - if code == OK: - deferred.callback(status) - else: - deferred.errback(ServerErrorResponse(status)) - return 'WAITING' - - - def state_LONG_INITIAL(self, line): - """ - Handle server responses for the LONG_INITIAL state in which the server - is expected to send the first line of a multi-line response. - - Parse the response. On an OK response, transition the state to - LONG. On an ERR response, cleanup and transition the state to - WAITING. - - @type line: L{bytes} - @param line: A line received from the server. - - @rtype: L{bytes} - @return: The next state. - """ - code, status = _codeStatusSplit(line) - if code == OK: - return 'LONG' - consumer = self._consumer - deferred = self._waiting - self._consumer = self._waiting = self._xform = None - self._unblock() - deferred.errback(ServerErrorResponse(status, consumer)) - return 'WAITING' - - - def state_LONG(self, line): - """ - Handle server responses for the LONG state in which the server is - expected to send a non-initial line of a multi-line response. - - On receipt of the last line of the response, clean up, fire the - deferred which is waiting on receipt of a complete response, and - transition the state to WAITING. Otherwise, pass the line to the - transform function, if provided, and then the consumer function. - - @type line: L{bytes} - @param line: A line received from the server. - - @rtype: L{bytes} - @return: The next state. - """ - # This is the state for each line of a long response. - if line == '.': - consumer = self._consumer - deferred = self._waiting - self._consumer = self._waiting = self._xform = None - self._unblock() - deferred.callback(consumer) - return 'WAITING' - else: - if self._xform is not None: - self._consumer(self._xform(line)) - else: - self._consumer(line) - return 'LONG' - - - # Callbacks - override these - def serverGreeting(self, greeting): - """ - Handle the server greeting. - - @type greeting: L{bytes} - @param greeting: The server greeting minus the status indicator. - For servers implementing APOP authentication, this will contain a - challenge string. - """ - - - # External API - call these (most of 'em anyway) - def startTLS(self, contextFactory=None): - """ - Switch to encrypted communication using TLS. - - The first step of switching to encrypted communication is obtaining - the server's capabilities. When that is complete, the L{_startTLS} - callback function continues the switching process. - - @type contextFactory: L{NoneType } or - L{ClientContextFactory } - @param contextFactory: The context factory with which to negotiate TLS. - If not provided, try to create a new one. - - @rtype: L{Deferred } which successfully results in - L{dict} mapping L{bytes} to L{list} of L{bytes} and/or L{bytes} to - L{NoneType } or fails with L{TLSError} - @return: A deferred which fires when the transport has been - secured according to the given context factory with the server - capabilities, or which fails with a TLS error if the transport - cannot be secured. - """ - tls = interfaces.ITLSTransport(self.transport, None) - if tls is None: - return defer.fail(TLSError( - "POP3Client transport does not implement " - "interfaces.ITLSTransport")) - - if contextFactory is None: - contextFactory = self._getContextFactory() - - if contextFactory is None: - return defer.fail(TLSError( - "POP3Client requires a TLS context to " - "initiate the STLS handshake")) - - d = self.capabilities() - d.addCallback(self._startTLS, contextFactory, tls) - return d - - - def _startTLS(self, caps, contextFactory, tls): - """ - Continue the process of switching to encrypted communication. - - This callback function runs after the server capabilities are received. - - The next step is sending the server an STLS command to request a - switch to encrypted communication. When an OK response is received, - the L{_startedTLS} callback function completes the switch to encrypted - communication. Then, the new server capabilities are requested. - - @type caps: L{dict} mapping L{bytes} to L{list} of L{bytes} and/or - L{bytes} to L{NoneType } - @param caps: The server capabilities. - - @type contextFactory: L{ClientContextFactory - } - @param contextFactory: A context factory with which to negotiate TLS. - - @type tls: L{ITLSTransport } - @param tls: A TCP transport that supports switching to TLS midstream. - - @rtype: L{Deferred } which successfully triggers with - L{dict} mapping L{bytes} to L{list} of L{bytes} and/or L{bytes} to - L{NoneType } or fails with L{TLSNotSupportedError} - @return: A deferred which successfully fires when the response from - the server to the request to start TLS has been received and the - new server capabilities have been received or fails when the server - does not support TLS. - """ - assert not self.startedTLS, "Client and Server are currently communicating via TLS" - - if 'STLS' not in caps: - return defer.fail(TLSNotSupportedError( - "Server does not support secure communication " - "via TLS / SSL")) - - d = self.sendShort('STLS', None) - d.addCallback(self._startedTLS, contextFactory, tls) - d.addCallback(lambda _: self.capabilities()) - return d - - - def _startedTLS(self, result, context, tls): - """ - Complete the process of switching to encrypted communication. - - This callback function runs after the response to the STLS command has - been received. - - The final steps are discarding the cached capabilities and initiating - TLS negotiation on the transport. - - @type result: L{dict} mapping L{bytes} to L{list} of L{bytes} and/or - L{bytes} to L{NoneType } - @param result: The server capabilities. - - @type context: L{ClientContextFactory - } - @param context: A context factory with which to negotiate TLS. - - @type tls: L{ITLSTransport } - @param tls: A TCP transport that supports switching to TLS midstream. - - @rtype: L{dict} mapping L{bytes} to L{list} of L{bytes} and/or L{bytes} - to L{NoneType } - @return: The server capabilities. - """ - self.transport = tls - self.transport.startTLS(context) - self._capCache = None - self.startedTLS = True - return result - - - def _getContextFactory(self): - """ - Get a context factory with which to negotiate TLS. - - @rtype: L{NoneType } or - L{ClientContextFactory } - @return: A context factory or C{None} if TLS is not supported on the - client. - """ - try: - from twisted.internet import ssl - except ImportError: - return None - else: - context = ssl.ClientContextFactory() - context.method = ssl.SSL.TLSv1_METHOD - return context - - - def login(self, username, password): - """ - Log in to the server. - - If APOP is available it will be used. Otherwise, if TLS is - available, an encrypted session will be started and plaintext - login will proceed. Otherwise, if L{allowInsecureLogin} is set, - insecure plaintext login will proceed. Otherwise, - L{InsecureAuthenticationDisallowed} will be raised. - - The first step of logging into the server is obtaining the server's - capabilities. When that is complete, the L{_login} callback function - continues the login process. - - @type username: L{bytes} - @param username: The username with which to log in. - - @type password: L{bytes} - @param password: The password with which to log in. - - @rtype: L{Deferred } which successfully fires with - L{bytes} - @return: A deferred which fires when the login process is complete. - On a successful login, it returns the server's response minus the - status indicator. - """ - d = self.capabilities() - d.addCallback(self._login, username, password) - return d - - - def _login(self, caps, username, password): - """ - Continue the process of logging in to the server. - - This callback function runs after the server capabilities are received. - - If the server provided a challenge in the greeting, proceed with an - APOP login. Otherwise, if the server and the transport support - encrypted communication, try to switch to TLS and then complete - the login process with the L{_loginTLS} callback function. Otherwise, - if insecure authentication is allowed, do a plaintext login. - Otherwise, fail with an L{InsecureAuthenticationDisallowed} error. - - @type caps: L{dict} mapping L{bytes} to L{list} of L{bytes} and/or - L{bytes} to L{NoneType } - @param caps: The server capabilities. - - @type username: L{bytes} - @param username: The username with which to log in. - - @type password: L{bytes} - @param password: The password with which to log in. - - @rtype: L{Deferred } which successfully fires with - L{bytes} - @return: A deferred which fires when the login process is complete. - On a successful login, it returns the server's response minus the - status indicator. - """ - if self.serverChallenge is not None: - return self._apop(username, password, self.serverChallenge) - - tryTLS = 'STLS' in caps - - # If our transport supports switching to TLS, we might want to - # try to switch to TLS. - tlsableTransport = interfaces.ITLSTransport(self.transport, None) is not None - - # If our transport is not already using TLS, we might want to - # try to switch to TLS. - nontlsTransport = interfaces.ISSLTransport(self.transport, None) is None - - if not self.startedTLS and tryTLS and tlsableTransport and nontlsTransport: - d = self.startTLS() - - d.addCallback(self._loginTLS, username, password) - return d - - elif self.startedTLS or not nontlsTransport or self.allowInsecureLogin: - return self._plaintext(username, password) - else: - return defer.fail(InsecureAuthenticationDisallowed()) - - - def _loginTLS(self, res, username, password): - """ - Do a plaintext login over an encrypted transport. - - This callback function runs after the transport switches to encrypted - communication. - - @type res: L{dict} mapping L{bytes} to L{list} of L{bytes} and/or - L{bytes} to L{NoneType } - @param res: The server capabilities. - - @type username: L{bytes} - @param username: The username with which to log in. - - @type password: L{bytes} - @param password: The password with which to log in. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server accepts the username - and password or fails when the server rejects either. On a - successful login, it returns the server's response minus the - status indicator. - """ - return self._plaintext(username, password) - - - def _plaintext(self, username, password): - """ - Perform a plaintext login. - - @type username: L{bytes} - @param username: The username with which to log in. - - @type password: L{bytes} - @param password: The password with which to log in. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server accepts the username - and password or fails when the server rejects either. On a - successful login, it returns the server's response minus the - status indicator. - """ - return self.user(username).addCallback(lambda r: self.password(password)) - - - def _apop(self, username, password, challenge): - """ - Perform an APOP login. - - @type username: L{bytes} - @param username: The username with which to log in. - - @type password: L{bytes} - @param password: The password with which to log in. - - @type challenge: L{bytes} - @param challenge: A challenge string. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On a successful login, it returns the server response minus - the status indicator. - """ - digest = md5(challenge + password).hexdigest() - return self.apop(username, digest) - - - def apop(self, username, digest): - """ - Send an APOP command to perform authenticated login. - - This should be used in special circumstances only, when it is - known that the server supports APOP authentication, and APOP - authentication is absolutely required. For the common case, - use L{login} instead. - - @type username: L{bytes} - @param username: The username with which to log in. - - @type digest: L{bytes} - @param digest: The challenge response to authenticate with. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the server - response minus the status indicator. On an ERR response, the - deferred fails with a server error response failure. - """ - return self.sendShort('APOP', username + ' ' + digest) - - - def user(self, username): - """ - Send a USER command to perform the first half of plaintext login. - - Unless this is absolutely required, use the L{login} method instead. - - @type username: L{bytes} - @param username: The username with which to log in. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the server - response minus the status indicator. On an ERR response, the - deferred fails with a server error response failure. - """ - return self.sendShort('USER', username) - - - def password(self, password): - """ - Send a PASS command to perform the second half of plaintext login. - - Unless this is absolutely required, use the L{login} method instead. - - @type password: L{bytes} - @param password: The plaintext password with which to authenticate. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the server - response minus the status indicator. On an ERR response, the - deferred fails with a server error response failure. - """ - return self.sendShort('PASS', password) - - - def delete(self, index): - """ - Send a DELE command to delete a message from the server. - - @type index: L{int} - @param index: The 0-based index of the message to delete. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the server - response minus the status indicator. On an ERR response, the - deferred fails with a server error response failure. - """ - return self.sendShort('DELE', str(index + 1)) - - - def _consumeOrSetItem(self, cmd, args, consumer, xform): - """ - Send a command to which a long response is expected and process the - multi-line response into a list accounting for deleted messages. - - @type cmd: L{bytes} - @param cmd: A POP3 command to which a long response is expected. - - @type args: L{bytes} - @param args: The command arguments. - - @type consumer: L{NoneType } or callable that takes - L{object} - @param consumer: C{None} or a function that consumes the output from - the transform function. - - @type xform: L{NoneType }, callable that takes - L{bytes} and returns 2-L{tuple} of (0) L{int}, (1) L{object}, - or callable that takes L{bytes} and returns L{object} - @param xform: A function that parses a line from a multi-line response - and transforms the values into usable form for input to the - consumer function. If no consumer function is specified, the - output must be a message index and corresponding value. If no - transform function is specified, the line is used as is. - - @rtype: L{Deferred } which fires with L{list} of - L{object} or callable that takes L{list} of L{object} - @return: A deferred which fires when the entire response has been - received. When a consumer is not provided, the return value is a - list of the value for each message or C{None} for deleted messages. - Otherwise, it returns the consumer itself. - """ - if consumer is None: - L = [] - consumer = _ListSetter(L).setitem - return self.sendLong(cmd, args, consumer, xform).addCallback(lambda r: L) - return self.sendLong(cmd, args, consumer, xform) - - - def _consumeOrAppend(self, cmd, args, consumer, xform): - """ - Send a command to which a long response is expected and process the - multi-line response into a list. - - @type cmd: L{bytes} - @param cmd: A POP3 command which expects a long response. - - @type args: L{bytes} - @param args: The command arguments. - - @type consumer: L{NoneType } or callable that takes - L{object} - @param consumer: C{None} or a function that consumes the output from the - transform function. - - @type xform: L{NoneType } or callable that takes - L{bytes} and returns L{object} - @param xform: A function that transforms a line from a multi-line - response into usable form for input to the consumer function. If - no transform function is specified, the line is used as is. - - @rtype: L{Deferred } which fires with L{list} of - 2-L{tuple} of (0) L{int}, (1) L{object} or callable that - takes 2-L{tuple} of (0) L{int}, (1) L{object} - @return: A deferred which fires when the entire response has been - received. When a consumer is not provided, the return value is a - list of the transformed lines. Otherwise, it returns the consumer - itself. - """ - if consumer is None: - L = [] - consumer = L.append - return self.sendLong(cmd, args, consumer, xform).addCallback(lambda r: L) - return self.sendLong(cmd, args, consumer, xform) - - - def capabilities(self, useCache=True): - """ - Send a CAPA command to retrieve the capabilities supported by - the server. - - Not all servers support this command. If the server does not - support this, it is treated as though it returned a successful - response listing no capabilities. At some future time, this may be - changed to instead seek out information about a server's - capabilities in some other fashion (only if it proves useful to do - so, and only if there are servers still in use which do not support - CAPA but which do support POP3 extensions that are useful). - - @type useCache: L{bool} - @param useCache: A flag that determines whether previously retrieved - results should be used if available. - - @rtype: L{Deferred } which successfully results in - L{dict} mapping L{bytes} to L{list} of L{bytes} and/or L{bytes} to - L{NoneType } - @return: A deferred which fires with a mapping of capability name to - parameters. For example:: - - C: CAPA - S: +OK Capability list follows - S: TOP - S: USER - S: SASL CRAM-MD5 KERBEROS_V4 - S: RESP-CODES - S: LOGIN-DELAY 900 - S: PIPELINING - S: EXPIRE 60 - S: UIDL - S: IMPLEMENTATION Shlemazle-Plotz-v302 - S: . - - will be lead to a result of:: - - | {'TOP': None, - | 'USER': None, - | 'SASL': ['CRAM-MD5', 'KERBEROS_V4'], - | 'RESP-CODES': None, - | 'LOGIN-DELAY': ['900'], - | 'PIPELINING': None, - | 'EXPIRE': ['60'], - | 'UIDL': None, - | 'IMPLEMENTATION': ['Shlemazle-Plotz-v302']} - """ - if useCache and self._capCache is not None: - return defer.succeed(self._capCache) - - cache = {} - def consume(line): - tmp = line.split() - if len(tmp) == 1: - cache[tmp[0]] = None - elif len(tmp) > 1: - cache[tmp[0]] = tmp[1:] - - def capaNotSupported(err): - err.trap(ServerErrorResponse) - return None - - def gotCapabilities(result): - self._capCache = cache - return cache - - d = self._consumeOrAppend('CAPA', None, consume, None) - d.addErrback(capaNotSupported).addCallback(gotCapabilities) - return d - - - def noop(self): - """ - Send a NOOP command asking the server to do nothing but respond. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the server - response minus the status indicator. On an ERR response, the - deferred fails with a server error response failure. - """ - return self.sendShort("NOOP", None) - - - def reset(self): - """ - Send a RSET command to unmark any messages that have been flagged - for deletion on the server. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the server - response minus the status indicator. On an ERR response, the - deferred fails with a server error response failure. - """ - return self.sendShort("RSET", None) - - - def retrieve(self, index, consumer=None, lines=None): - """ - Send a RETR or TOP command to retrieve all or part of a message from - the server. - - @type index: L{int} - @param index: A 0-based message index. - - @type consumer: L{NoneType } or callable that takes - L{bytes} - @param consumer: A function which consumes each transformed line from a - multi-line response as it is received. - - @type lines: L{NoneType } or L{int} - @param lines: If specified, the number of lines of the message to be - retrieved. Otherwise, the entire message is retrieved. - - @rtype: L{Deferred } which fires with L{list} of - L{bytes}, or callable that takes 2-L{tuple} of (0) L{int}, - (1) L{object} - @return: A deferred which fires when the entire response has been - received. When a consumer is not provided, the return value is a - list of the transformed lines. Otherwise, it returns the consumer - itself. - """ - idx = str(index + 1) - if lines is None: - return self._consumeOrAppend('RETR', idx, consumer, _dotUnquoter) - - return self._consumeOrAppend('TOP', '%s %d' % (idx, lines), consumer, _dotUnquoter) - - - def stat(self): - """ - Send a STAT command to get information about the size of the mailbox. - - @rtype: L{Deferred } which successfully fires with - a 2-tuple of (0) L{int}, (1) L{int} or fails with - L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the number of - messages in the mailbox and the size of the mailbox in octets. - On an ERR response, the deferred fails with a server error - response failure. - """ - return self.sendShort('STAT', None).addCallback(_statXform) - - - def listSize(self, consumer=None): - """ - Send a LIST command to retrieve the sizes of all messages on the - server. - - @type consumer: L{NoneType } or callable that takes - 2-L{tuple} of (0) L{int}, (1) L{int} - @param consumer: A function which consumes the 0-based message index - and message size derived from the server response. - - @rtype: L{Deferred } which fires L{list} of L{int} or - callable that takes 2-L{tuple} of (0) L{int}, (1) L{int} - @return: A deferred which fires when the entire response has been - received. When a consumer is not provided, the return value is a - list of message sizes. Otherwise, it returns the consumer itself. - """ - return self._consumeOrSetItem('LIST', None, consumer, _listXform) - - - def listUID(self, consumer=None): - """ - Send a UIDL command to retrieve the UIDs of all messages on the server. - - @type consumer: L{NoneType } or callable that takes - 2-L{tuple} of (0) L{int}, (1) L{bytes} - @param consumer: A function which consumes the 0-based message index - and UID derived from the server response. - - @rtype: L{Deferred } which fires with L{list} of - L{object} or callable that takes 2-L{tuple} of (0) L{int}, - (1) L{bytes} - @return: A deferred which fires when the entire response has been - received. When a consumer is not provided, the return value is a - list of message sizes. Otherwise, it returns the consumer itself. - """ - return self._consumeOrSetItem('UIDL', None, consumer, _uidXform) - - - def quit(self): - """ - Send a QUIT command to disconnect from the server. - - @rtype: L{Deferred } which successfully fires with - L{bytes} or fails with L{ServerErrorResponse} - @return: A deferred which fires when the server response is received. - On an OK response, the deferred succeeds with the server - response minus the status indicator. On an ERR response, the - deferred fails with a server error response failure. - """ - return self.sendShort('QUIT', None) - -__all__ = [] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/protocols.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/protocols.py deleted file mode 100644 index b4dbfad..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/protocols.py +++ /dev/null @@ -1,504 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Mail protocol support. -""" - -from twisted.mail import pop3 -from twisted.mail import smtp -from twisted.internet import protocol -from twisted.internet import defer -from twisted.copyright import longversion -from twisted.python import log -from twisted.python.deprecate import deprecatedModuleAttribute -from twisted.python.versions import Version - -from twisted.cred.credentials import CramMD5Credentials, UsernamePassword -from twisted.cred.error import UnauthorizedLogin - -from twisted.mail import relay - -from zope.interface import implements - - - -class DomainDeliveryBase: - """ - A base class for message delivery using the domains of a mail service. - - @ivar service: See L{__init__} - @ivar user: See L{__init__} - @ivar host: See L{__init__} - - @type protocolName: L{bytes} - @ivar protocolName: The protocol being used to deliver the mail. - Sub-classes should set this appropriately. - """ - implements(smtp.IMessageDelivery) - - service = None - protocolName = None - - def __init__(self, service, user, host=smtp.DNSNAME): - """ - @type service: L{MailService} - @param service: A mail service. - - @type user: L{bytes} or L{NoneType } - @param user: The authenticated SMTP user. - - @type host: L{bytes} - @param host: The hostname. - """ - self.service = service - self.user = user - self.host = host - - - def receivedHeader(self, helo, origin, recipients): - """ - Generate a received header string for a message. - - @type helo: 2-L{tuple} of (L{bytes}, L{bytes}) - @param helo: The client's identity as sent in the HELO command and its - IP address. - - @type origin: L{Address} - @param origin: The origination address of the message. - - @type recipients: L{list} of L{User} - @param recipients: The destination addresses for the message. - - @rtype: L{bytes} - @return: A received header string. - """ - authStr = heloStr = "" - if self.user: - authStr = " auth=%s" % (self.user.encode('xtext'),) - if helo[0]: - heloStr = " helo=%s" % (helo[0],) - from_ = "from %s ([%s]%s%s)" % (helo[0], helo[1], heloStr, authStr) - by = "by %s with %s (%s)" % ( - self.host, self.protocolName, longversion - ) - for_ = "for <%s>; %s" % (' '.join(map(str, recipients)), smtp.rfc822date()) - return "Received: %s\n\t%s\n\t%s" % (from_, by, for_) - - - def validateTo(self, user): - """ - Validate the address for which a message is destined. - - @type user: L{User} - @param user: The destination address. - - @rtype: L{Deferred } which successfully fires with - no-argument callable which returns L{IMessage } - provider. - @return: A deferred which successfully fires with a no-argument - callable which returns a message receiver for the destination. - - @raise SMTPBadRcpt: When messages cannot be accepted for the - destination address. - """ - # XXX - Yick. This needs cleaning up. - if self.user and self.service.queue: - d = self.service.domains.get(user.dest.domain, None) - if d is None: - d = relay.DomainQueuer(self.service, True) - else: - d = self.service.domains[user.dest.domain] - return defer.maybeDeferred(d.exists, user) - - - def validateFrom(self, helo, origin): - """ - Validate the address from which a message originates. - - @type helo: 2-L{tuple} of (L{bytes}, L{bytes}) - @param helo: The client's identity as sent in the HELO command and its - IP address. - - @type origin: L{Address} - @param origin: The origination address of the message. - - @rtype: L{Address} - @return: The origination address. - - @raise SMTPBadSender: When messages cannot be accepted from the - origination address. - """ - if not helo: - raise smtp.SMTPBadSender(origin, 503, "Who are you? Say HELO first.") - if origin.local != '' and origin.domain == '': - raise smtp.SMTPBadSender(origin, 501, "Sender address must contain domain.") - return origin - - - -class SMTPDomainDelivery(DomainDeliveryBase): - """ - A domain delivery base class for use in an SMTP server. - """ - protocolName = 'smtp' - - - -class ESMTPDomainDelivery(DomainDeliveryBase): - """ - A domain delivery base class for use in an ESMTP server. - """ - protocolName = 'esmtp' - - - -class DomainSMTP(SMTPDomainDelivery, smtp.SMTP): - """ - An SMTP server which uses the domains of a mail service. - """ - service = user = None - - def __init__(self, *args, **kw): - """ - Initialize the SMTP server. - - @type args: 2-L{tuple} of (L{IMessageDelivery} provider or - L{NoneType }, L{IMessageDeliveryFactory} - provider or L{NoneType }) - @param args: Positional arguments for L{SMTP.__init__} - - @type kw: L{dict} - @param kw: Keyword arguments for L{SMTP.__init__}. - """ - import warnings - warnings.warn( - "DomainSMTP is deprecated. Use IMessageDelivery objects instead.", - DeprecationWarning, stacklevel=2, - ) - smtp.SMTP.__init__(self, *args, **kw) - if self.delivery is None: - self.delivery = self - - - -class DomainESMTP(ESMTPDomainDelivery, smtp.ESMTP): - """ - An ESMTP server which uses the domains of a mail service. - """ - service = user = None - - def __init__(self, *args, **kw): - """ - Initialize the ESMTP server. - - @type args: 2-L{tuple} of (L{IMessageDelivery} provider or - L{NoneType }, L{IMessageDeliveryFactory} - provider or L{NoneType }) - @param args: Positional arguments for L{ESMTP.__init__} - - @type kw: L{dict} - @param kw: Keyword arguments for L{ESMTP.__init__}. - """ - import warnings - warnings.warn( - "DomainESMTP is deprecated. Use IMessageDelivery objects instead.", - DeprecationWarning, stacklevel=2, - ) - smtp.ESMTP.__init__(self, *args, **kw) - if self.delivery is None: - self.delivery = self - - - -class SMTPFactory(smtp.SMTPFactory): - """ - An SMTP server protocol factory. - - @ivar service: See L{__init__} - @ivar portal: See L{__init__} - - @type protocol: no-argument callable which returns a L{Protocol - } subclass - @ivar protocol: A callable which creates a protocol. The default value is - L{SMTP}. - """ - protocol = smtp.SMTP - portal = None - - def __init__(self, service, portal = None): - """ - @type service: L{MailService} - @param service: An email service. - - @type portal: L{Portal } or - L{NoneType } - @param portal: A portal to use for authentication. - """ - smtp.SMTPFactory.__init__(self) - self.service = service - self.portal = portal - - - def buildProtocol(self, addr): - """ - Create an instance of an SMTP server protocol. - - @type addr: L{IAddress } provider - @param addr: The address of the SMTP client. - - @rtype: L{SMTP} - @return: An SMTP protocol. - """ - log.msg('Connection from %s' % (addr,)) - p = smtp.SMTPFactory.buildProtocol(self, addr) - p.service = self.service - p.portal = self.portal - return p - - - -class ESMTPFactory(SMTPFactory): - """ - An ESMTP server protocol factory. - - @type protocol: no-argument callable which returns a L{Protocol - } subclass - @ivar protocol: A callable which creates a protocol. The default value is - L{ESMTP}. - - @type context: L{ContextFactory } or - L{NoneType } - @ivar context: A factory to generate contexts to be used in negotiating - encrypted communication. - - @type challengers: L{dict} mapping L{bytes} to no-argument callable which - returns L{ICredentials } - subclass provider. - @ivar challengers: A mapping of acceptable authorization mechanism to - callable which creates credentials to use for authentication. - """ - protocol = smtp.ESMTP - context = None - - def __init__(self, *args): - """ - @param args: Arguments for L{SMTPFactory.__init__} - - @see: L{SMTPFactory.__init__} - """ - SMTPFactory.__init__(self, *args) - self.challengers = { - 'CRAM-MD5': CramMD5Credentials - } - - - def buildProtocol(self, addr): - """ - Create an instance of an ESMTP server protocol. - - @type addr: L{IAddress } provider - @param addr: The address of the ESMTP client. - - @rtype: L{ESMTP} - @return: An ESMTP protocol. - """ - p = SMTPFactory.buildProtocol(self, addr) - p.challengers = self.challengers - p.ctx = self.context - return p - - - -class VirtualPOP3(pop3.POP3): - """ - A virtual hosting POP3 server. - - @type service: L{MailService} - @ivar service: The email service that created this server. This must be - set by the service. - - @type domainSpecifier: L{bytes} - @ivar domainSpecifier: The character to use to split an email address into - local-part and domain. The default is '@'. - """ - service = None - - domainSpecifier = '@' # Gaagh! I hate POP3. No standardized way - # to indicate user@host. '@' doesn't work - # with NS, e.g. - - def authenticateUserAPOP(self, user, digest): - """ - Perform APOP authentication. - - Override the default lookup scheme to allow virtual domains. - - @type user: L{bytes} - @param user: The name of the user attempting to log in. - - @type digest: L{bytes} - @param digest: The challenge response. - - @rtype: L{Deferred} which successfully results in 3-L{tuple} of - (L{IMailbox }, L{IMailbox } - provider, no-argument callable) - @return: A deferred which fires when authentication is complete. - If successful, it returns an L{IMailbox } interface, - a mailbox and a logout function. If authentication fails, the - deferred fails with an L{UnauthorizedLogin - } error. - """ - user, domain = self.lookupDomain(user) - try: - portal = self.service.lookupPortal(domain) - except KeyError: - return defer.fail(UnauthorizedLogin()) - else: - return portal.login( - pop3.APOPCredentials(self.magic, user, digest), - None, - pop3.IMailbox - ) - - - def authenticateUserPASS(self, user, password): - """ - Perform authentication for a username/password login. - - Override the default lookup scheme to allow virtual domains. - - @type user: L{bytes} - @param user: The name of the user attempting to log in. - - @type password: L{bytes} - @param password: The password to authenticate with. - - @rtype: L{Deferred} which successfully results in 3-L{tuple} of - (L{IMailbox }, L{IMailbox } - provider, no-argument callable) - @return: A deferred which fires when authentication is complete. - If successful, it returns an L{IMailbox } interface, - a mailbox and a logout function. If authentication fails, the - deferred fails with an L{UnauthorizedLogin - } error. - """ - user, domain = self.lookupDomain(user) - try: - portal = self.service.lookupPortal(domain) - except KeyError: - return defer.fail(UnauthorizedLogin()) - else: - return portal.login( - UsernamePassword(user, password), - None, - pop3.IMailbox - ) - - - def lookupDomain(self, user): - """ - Check whether a domain is among the virtual domains supported by the - mail service. - - @type user: L{bytes} - @param user: An email address. - - @rtype: 2-L{tuple} of (L{bytes}, L{bytes}) - @return: The local part and the domain part of the email address if the - domain is supported. - - @raise POP3Error: When the domain is not supported by the mail service. - """ - try: - user, domain = user.split(self.domainSpecifier, 1) - except ValueError: - domain = '' - if domain not in self.service.domains: - raise pop3.POP3Error("no such domain %s" % domain) - return user, domain - - - -class POP3Factory(protocol.ServerFactory): - """ - A POP3 server protocol factory. - - @ivar service: See L{__init__} - - @type protocol: no-argument callable which returns a L{Protocol - } subclass - @ivar protocol: A callable which creates a protocol. The default value is - L{VirtualPOP3}. - """ - protocol = VirtualPOP3 - service = None - - def __init__(self, service): - """ - @type service: L{MailService} - @param service: An email service. - """ - self.service = service - - - def buildProtocol(self, addr): - """ - Create an instance of a POP3 server protocol. - - @type addr: L{IAddress } provider - @param addr: The address of the POP3 client. - - @rtype: L{POP3} - @return: A POP3 protocol. - """ - p = protocol.ServerFactory.buildProtocol(self, addr) - p.service = self.service - return p - - - -# It is useful to know, perhaps, that the required file for this to work can -# be created thusly: -# -# openssl req -x509 -newkey rsa:2048 -keyout file.key -out file.crt \ -# -days 365 -nodes -# -# And then cat file.key and file.crt together. The number of days and bits -# can be changed, of course. -# -class SSLContextFactory: - """ - An SSL context factory. - - @ivar filename: See L{__init__} - """ - deprecatedModuleAttribute( - Version("Twisted", 12, 2, 0), - "Use twisted.internet.ssl.DefaultOpenSSLContextFactory instead.", - "twisted.mail.protocols", "SSLContextFactory") - - def __init__(self, filename): - """ - @type filename: L{bytes} - @param filename: The name of a file containing a certificate and - private key. - """ - self.filename = filename - - - def getContext(self): - """ - Create an SSL context. - - @rtype: C{OpenSSL.SSL.Context} - @return: An SSL context configured with the certificate and private key - from the file. - """ - from OpenSSL import SSL - ctx = SSL.Context(SSL.SSLv23_METHOD) - ctx.use_certificate_file(self.filename) - ctx.use_privatekey_file(self.filename) - return ctx diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/relay.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/relay.py deleted file mode 100644 index 17626cf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/relay.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for relaying mail. -""" - -from twisted.mail import smtp -from twisted.python import log -from twisted.internet.address import UNIXAddress - -import os - -try: - import cPickle as pickle -except ImportError: - import pickle - - - -class DomainQueuer: - """ - An SMTP domain which add messages to a queue intended for relaying. - """ - - def __init__(self, service, authenticated=False): - self.service = service - self.authed = authenticated - - - def exists(self, user): - """ - Check whether mail can be relayed to a user. - - @type user: L{User} - @param user: A user. - - @rtype: no-argument callable which returns L{IMessage } - provider - @return: A function which takes no arguments and returns a message - receiver for the user. - - @raise SMTPBadRcpt: When mail cannot be relayed to the user. - """ - if self.willRelay(user.dest, user.protocol): - # The most cursor form of verification of the addresses - orig = filter(None, str(user.orig).split('@', 1)) - dest = filter(None, str(user.dest).split('@', 1)) - if len(orig) == 2 and len(dest) == 2: - return lambda: self.startMessage(user) - raise smtp.SMTPBadRcpt(user) - - - def willRelay(self, address, protocol): - """ - Check whether we agree to relay. - - The default is to relay for all connections over UNIX - sockets and all connections from localhost. - """ - peer = protocol.transport.getPeer() - return (self.authed or isinstance(peer, UNIXAddress) or - peer.host == '127.0.0.1') - - - def startMessage(self, user): - """ - Create an envelope and a message receiver for the relay queue. - - @type user: L{User} - @param user: A user. - - @rtype: L{IMessage } - @return: A message receiver. - """ - queue = self.service.queue - envelopeFile, smtpMessage = queue.createNewMessage() - try: - log.msg('Queueing mail %r -> %r' % (str(user.orig), - str(user.dest))) - pickle.dump([str(user.orig), str(user.dest)], envelopeFile) - finally: - envelopeFile.close() - return smtpMessage - - - -class RelayerMixin: - - # XXX - This is -totally- bogus - # It opens about a -hundred- -billion- files - # and -leaves- them open! - - def loadMessages(self, messagePaths): - self.messages = [] - self.names = [] - for message in messagePaths: - fp = open(message + '-H') - try: - messageContents = pickle.load(fp) - finally: - fp.close() - fp = open(message + '-D') - messageContents.append(fp) - self.messages.append(messageContents) - self.names.append(message) - - - def getMailFrom(self): - if not self.messages: - return None - return self.messages[0][0] - - - def getMailTo(self): - if not self.messages: - return None - return [self.messages[0][1]] - - - def getMailData(self): - if not self.messages: - return None - return self.messages[0][2] - - - def sentMail(self, code, resp, numOk, addresses, log): - """Since we only use one recipient per envelope, this - will be called with 0 or 1 addresses. We probably want - to do something with the error message if we failed. - """ - if code in smtp.SUCCESS: - # At least one, i.e. all, recipients successfully delivered - os.remove(self.names[0] + '-D') - os.remove(self.names[0] + '-H') - del self.messages[0] - del self.names[0] - - - -class SMTPRelayer(RelayerMixin, smtp.SMTPClient): - """ - A base class for SMTP relayers. - """ - def __init__(self, messagePaths, *args, **kw): - """ - @type messagePaths: L{list} of L{bytes} - @param messagePaths: The base filename for each message to be relayed. - - @type args: 1-L{tuple} of (0) L{bytes} or 2-L{tuple} of - (0) L{bytes}, (1) L{int} - @param args: Positional arguments for L{SMTPClient.__init__} - - @type kw: L{dict} - @param kw: Keyword arguments for L{SMTPClient.__init__} - """ - smtp.SMTPClient.__init__(self, *args, **kw) - self.loadMessages(messagePaths) - - - -class ESMTPRelayer(RelayerMixin, smtp.ESMTPClient): - """ - A base class for ESMTP relayers. - """ - def __init__(self, messagePaths, *args, **kw): - """ - @type messagePaths: L{list} of L{bytes} - @param messagePaths: The base filename for each message to be relayed. - - @type args: 3-L{tuple} of (0) L{bytes}, (1) L{NoneType - } or L{ClientContextFactory - }, (2) L{bytes} or - 4-L{tuple} of (0) L{bytes}, (1) L{NoneType } - or L{ClientContextFactory - }, (2) L{bytes}, - (3) L{int} - @param args: Positional arguments for L{ESMTPClient.__init__} - - @type kw: L{dict} - @param kw: Keyword arguments for L{ESMTPClient.__init__} - """ - smtp.ESMTPClient.__init__(self, *args, **kw) - self.loadMessages(messagePaths) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/relaymanager.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/relaymanager.py deleted file mode 100644 index 3fcf2e8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/relaymanager.py +++ /dev/null @@ -1,1158 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Infrastructure for relaying mail through a smart host. - -Traditional peer-to-peer email has been increasingly replaced by smart host -configurations. Instead of sending mail directly to the recipient, a sender -sends mail to a smart host. The smart host finds the mail exchange server for -the recipient and sends on the message. -""" - -import rfc822 -import os -import time - -try: - import cPickle as pickle -except ImportError: - import pickle - -from twisted.python import log -from twisted.python.failure import Failure -from twisted.mail import relay -from twisted.mail import bounce -from twisted.internet import protocol -from twisted.internet.defer import Deferred, DeferredList -from twisted.internet.error import DNSLookupError -from twisted.mail import smtp -from twisted.application import internet - - - -class ManagedRelayerMixin: - """SMTP Relayer which notifies a manager - - Notify the manager about successful mail, failed mail - and broken connections - """ - def __init__(self, manager): - self.manager = manager - - - def sentMail(self, code, resp, numOk, addresses, log): - """called when e-mail has been sent - - we will always get 0 or 1 addresses. - """ - message = self.names[0] - if code in smtp.SUCCESS: - self.manager.notifySuccess(self.factory, message) - else: - self.manager.notifyFailure(self.factory, message) - del self.messages[0] - del self.names[0] - - - def connectionLost(self, reason): - """called when connection is broken - - notify manager we will try to send no more e-mail - """ - self.manager.notifyDone(self.factory) - - - -class SMTPManagedRelayer(ManagedRelayerMixin, relay.SMTPRelayer): - """ - An SMTP managed relayer. - - This managed relayer is an SMTP client which is responsible for sending a - set of messages and keeping an attempt manager informed about its progress. - - @type factory: L{SMTPManagedRelayerFactory} - @ivar factory: The factory that created this relayer. This must be set by - the factory. - """ - def __init__(self, messages, manager, *args, **kw): - """ - @type messages: L{list} of L{bytes} - @param messages: The base filenames of messages to be relayed. - - @type manager: L{_AttemptManager} - @param manager: An attempt manager. - - @type args: 1-L{tuple} of (0) L{bytes} or 2-L{tuple} of - (0) L{bytes}, (1) L{int} - @param args: Positional arguments for L{SMTPClient.__init__} - - @type kw: L{dict} - @param kw: Keyword arguments for L{SMTPClient.__init__} - """ - ManagedRelayerMixin.__init__(self, manager) - relay.SMTPRelayer.__init__(self, messages, *args, **kw) - - - -class ESMTPManagedRelayer(ManagedRelayerMixin, relay.ESMTPRelayer): - """ - An ESMTP managed relayer. - - This managed relayer is an ESMTP client which is responsible for sending a - set of messages and keeping an attempt manager informed about its progress. - """ - def __init__(self, messages, manager, *args, **kw): - """ - @type messages: L{list} of L{bytes} - @param messages: The base filenames of messages to be relayed. - - @type manager: L{_AttemptManager} - @param manager: An attempt manager. - - @type args: 3-L{tuple} of (0) L{bytes}, (1) L{NoneType - } or L{ClientContextFactory - }, (2) L{bytes} or - 4-L{tuple} of (0) L{bytes}, (1) L{NoneType } - or L{ClientContextFactory - }, (2) L{bytes}, - (3) L{int} - @param args: Positional arguments for L{ESMTPClient.__init__} - - @type kw: L{dict} - @param kw: Keyword arguments for L{ESMTPClient.__init__} - """ - ManagedRelayerMixin.__init__(self, manager) - relay.ESMTPRelayer.__init__(self, messages, *args, **kw) - - - -class SMTPManagedRelayerFactory(protocol.ClientFactory): - """ - A factory to create an L{SMTPManagedRelayer}. - - This factory creates a managed relayer which relays a set of messages over - SMTP and informs an attempt manager of its progress. - - @ivar messages: See L{__init__} - @ivar manager: See L{__init__} - - @type protocol: callable which returns L{SMTPManagedRelayer} - @ivar protocol: A callable which returns a managed relayer for SMTP. See - L{SMTPManagedRelayer.__init__} for parameters to the callable. - - @type pArgs: 1-L{tuple} of (0) L{bytes} or 2-L{tuple} of - (0) L{bytes}, (1), L{int} - @ivar pArgs: Positional arguments for L{SMTPClient.__init__} - - @type pKwArgs: L{dict} - @ivar pKwArgs: Keyword arguments for L{SMTPClient.__init__} - """ - protocol = SMTPManagedRelayer - - def __init__(self, messages, manager, *args, **kw): - """ - @type messages: L{list} of L{bytes} - @param messages: The base filenames of messages to be relayed. - - @type manager: L{_AttemptManager} - @param manager: An attempt manager. - - @type args: 1-L{tuple} of (0) L{bytes} or 2-L{tuple} of - (0) L{bytes}, (1), L{int} - @param args: Positional arguments for L{SMTPClient.__init__} - - @type kw: L{dict} - @param kw: Keyword arguments for L{SMTPClient.__init__} - """ - self.messages = messages - self.manager = manager - self.pArgs = args - self.pKwArgs = kw - - - def buildProtocol(self, addr): - """ - Create an L{SMTPManagedRelayer}. - - @type addr: L{IAddress } provider - @param addr: The address of the SMTP server. - - @rtype: L{SMTPManagedRelayer} - @return: A managed relayer for SMTP. - """ - protocol = self.protocol(self.messages, self.manager, *self.pArgs, - **self.pKwArgs) - protocol.factory = self - return protocol - - - def clientConnectionFailed(self, connector, reason): - """ - Notify the attempt manager that a connection could not be established. - - @type connector: L{IConnector } - provider - @param connector: A connector. - - @type reason: L{Failure} - @param reason: The reason the connection attempt failed. - """ - self.manager.notifyNoConnection(self) - self.manager.notifyDone(self) - - - -class ESMTPManagedRelayerFactory(SMTPManagedRelayerFactory): - """ - A factory to create an L{ESMTPManagedRelayer}. - - This factory creates a managed relayer which relays a set of messages over - ESMTP and informs an attempt manager of its progress. - - @type protocol: callable which returns L{ESMTPManagedRelayer} - @ivar protocol: A callable which returns a managed relayer for ESMTP. See - L{ESMTPManagedRelayer.__init__} for parameters to the callable. - - @ivar secret: See L{__init__} - @ivar contextFactory: See L{__init__} - """ - protocol = ESMTPManagedRelayer - - def __init__(self, messages, manager, secret, contextFactory, *args, **kw): - """ - @type messages: L{list} of L{bytes} - @param messages: The base filenames of messages to be relayed. - - @type manager: L{_AttemptManager} - @param manager: An attempt manager. - - @type secret: L{bytes} - @param secret: A string for the authentication challenge response. - - @type contextFactory: L{NoneType } or - L{ClientContextFactory } - @param contextFactory: An SSL context factory. - - @type args: 1-L{tuple} of (0) L{bytes} or 2-L{tuple} of - (0) L{bytes}, (1), L{int} - @param args: Positional arguments for L{SMTPClient.__init__} - - @type pKwArgs: L{dict} - @param pKwArgs: Keyword arguments for L{SMTPClient.__init__} - """ - self.secret = secret - self.contextFactory = contextFactory - SMTPManagedRelayerFactory.__init__(self, messages, manager, *args, - **kw) - - - def buildProtocol(self, addr): - """ - Create an L{ESMTPManagedRelayer}. - - @type addr: L{IAddress } provider - @param addr: The address of the ESMTP server. - - @rtype: L{ESMTPManagedRelayer} - @return: A managed relayer for ESMTP. - """ - s = self.secret and self.secret(addr) - protocol = self.protocol(self.messages, self.manager, s, - self.contextFactory, *self.pArgs, **self.pKwArgs) - protocol.factory = self - return protocol - - - -class Queue: - """ - A queue for messages to be relayed. - - @ivar directory: See L{__init__} - - @type n: L{int} - @ivar n: A number used to form unique filenames. - - @type waiting: L{dict} of L{bytes} - @ivar waiting: The base filenames of messages waiting to be relayed. - - @type relayed: L{dict} of L{bytes} - @ivar relayed: The base filenames of messages in the process of being - relayed. - - @type noisy: L{bool} - @ivar noisy: A flag which determines whether informational log messages - will be generated (C{True}) or not (C{False}). - """ - noisy = True - - def __init__(self, directory): - """ - Initialize non-volatile state. - - @type directory: L{bytes} - @param directory: The pathname of the directory holding messages in the - queue. - """ - self.directory = directory - self._init() - - - def _init(self): - """ - Initialize volatile state. - """ - self.n = 0 - self.waiting = {} - self.relayed = {} - self.readDirectory() - - - def __getstate__(self): - """ - Create a representation of the non-volatile state of the queue. - - @rtype: L{dict} mapping L{bytes} to L{object} - @return: The non-volatile state of the queue. - """ - return {'directory': self.directory} - - - def __setstate__(self, state): - """ - Restore the non-volatile state of the queue and recreate the volatile - state. - - @type state: L{dict} mapping L{bytes} to L{object} - @param state: The non-volatile state of the queue. - """ - self.__dict__.update(state) - self._init() - - - def readDirectory(self): - """ - Scan the message directory for new messages. - """ - for message in os.listdir(self.directory): - # Skip non data files - if message[-2:] != '-D': - continue - self.addMessage(message[:-2]) - - - def getWaiting(self): - """ - Return the base filenames of messages waiting to be relayed. - - @rtype: L{list} of L{bytes} - @return: The base filenames of messages waiting to be relayed. - """ - return self.waiting.keys() - - - def hasWaiting(self): - """ - Return an indication of whether the queue has messages waiting to be - relayed. - - @rtype: L{bool} - @return: C{True} if messages are waiting to be relayed. C{False} - otherwise. - """ - return len(self.waiting) > 0 - - - def getRelayed(self): - """ - Return the base filenames of messages in the process of being relayed. - - @rtype: L{list} of L{bytes} - @return: The base filenames of messages in the process of being - relayed. - """ - return self.relayed.keys() - - - def setRelaying(self, message): - """ - Mark a message as being relayed. - - @type message: L{bytes} - @param message: The base filename of a message. - """ - del self.waiting[message] - self.relayed[message] = 1 - - - def setWaiting(self, message): - """ - Mark a message as waiting to be relayed. - - @type message: L{bytes} - @param message: The base filename of a message. - """ - del self.relayed[message] - self.waiting[message] = 1 - - - def addMessage(self, message): - """ - Mark a message as waiting to be relayed unless it is in the process of - being relayed. - - @type message: L{bytes} - @param message: The base filename of a message. - """ - if message not in self.relayed: - self.waiting[message] = 1 - if self.noisy: - log.msg('Set ' + message + ' waiting') - - - def done(self, message): - """ - Remove a message from the queue. - - @type message: L{bytes} - @param message: The base filename of a message. - """ - message = os.path.basename(message) - os.remove(self.getPath(message) + '-D') - os.remove(self.getPath(message) + '-H') - del self.relayed[message] - - - def getPath(self, message): - """ - Return the full base pathname of a message in the queue. - - @type message: L{bytes} - @param message: The base filename of a message. - - @rtype: L{bytes} - @return: The full base pathname of the message. - """ - return os.path.join(self.directory, message) - - - def getEnvelope(self, message): - """ - Get the envelope for a message. - - @type message: L{bytes} - @param message: The base filename of a message. - - @rtype: L{list} of two L{bytes} - @return: A list containing the origination and destination addresses - for the message. - """ - return pickle.load(self.getEnvelopeFile(message)) - - - def getEnvelopeFile(self, message): - """ - Return the envelope file for a message in the queue. - - @type message: L{bytes} - @param message: The base filename of a message. - - @rtype: L{file} - @return: The envelope file for the message. - """ - return open(os.path.join(self.directory, message + '-H'), 'rb') - - - def createNewMessage(self): - """ - Create a new message in the queue. - - @rtype: 2-L{tuple} of (0) L{file}, (1) L{FileMessage} - @return: The envelope file and a message receiver for a new message in - the queue. - """ - fname = "%s_%s_%s_%s" % (os.getpid(), time.time(), self.n, id(self)) - self.n = self.n + 1 - headerFile = open(os.path.join(self.directory, fname + '-H'), 'wb') - tempFilename = os.path.join(self.directory, fname + '-C') - finalFilename = os.path.join(self.directory, fname + '-D') - messageFile = open(tempFilename, 'wb') - - from twisted.mail.mail import FileMessage - return headerFile, FileMessage(messageFile, tempFilename, - finalFilename) - - - -class _AttemptManager(object): - """ - A manager for an attempt to relay a set of messages to a mail exchange - server. - - @ivar manager: See L{__init__} - - @type _completionDeferreds: L{list} of L{Deferred} - @ivar _completionDeferreds: Deferreds which are to be notified when the - attempt to relay is finished. - """ - def __init__(self, manager, noisy=True, reactor=None): - """ - @type manager: L{SmartHostSMTPRelayingManager} - @param manager: A smart host. - - @type noisy: L{bool} - @param noisy: A flag which determines whether informational log - messages will be generated (L{True}) or not (L{False}). - - @type reactor: L{IReactorTime - } provider - @param reactor: A reactor which will be used to schedule delayed calls. - """ - self.manager = manager - self._completionDeferreds = [] - self.noisy = noisy - - if not reactor: - from twisted.internet import reactor - self.reactor = reactor - - - def getCompletionDeferred(self): - """ - Return a deferred which will fire when the attempt to relay is - finished. - - @rtype: L{Deferred} - @return: A deferred which will fire when the attempt to relay is - finished. - """ - self._completionDeferreds.append(Deferred()) - return self._completionDeferreds[-1] - - - def _finish(self, relay, message): - """ - Remove a message from the relay queue and from the smart host's list of - messages being relayed. - - @type relay: L{SMTPManagedRelayerFactory} - @param relay: The factory for the relayer which sent the message. - - @type message: L{bytes} - @param message: The path of the file holding the message. - """ - self.manager.managed[relay].remove(os.path.basename(message)) - self.manager.queue.done(message) - - - def notifySuccess(self, relay, message): - """ - Remove a message from the relay queue after it has been successfully - sent. - - @type relay: L{SMTPManagedRelayerFactory} - @param relay: The factory for the relayer which sent the message. - - @type message: L{bytes} - @param message: The path of the file holding the message. - """ - if self.noisy: - log.msg("success sending %s, removing from queue" % message) - self._finish(relay, message) - - - def notifyFailure(self, relay, message): - """ - Generate a bounce message for a message which cannot be relayed. - - @type relay: L{SMTPManagedRelayerFactory} - @param relay: The factory for the relayer responsible for the message. - - @type message: L{bytes} - @param message: The path of the file holding the message. - """ - if self.noisy: - log.msg("could not relay " + message) - # Moshe - Bounce E-mail here - # Be careful: if it's a bounced bounce, silently - # discard it - message = os.path.basename(message) - fp = self.manager.queue.getEnvelopeFile(message) - from_, to = pickle.load(fp) - fp.close() - from_, to, bounceMessage = bounce.generateBounce( - open(self.manager.queue.getPath(message) + '-D'), from_, to) - fp, outgoingMessage = self.manager.queue.createNewMessage() - pickle.dump([from_, to], fp) - fp.close() - for line in bounceMessage.splitlines(): - outgoingMessage.lineReceived(line) - outgoingMessage.eomReceived() - self._finish(relay, self.manager.queue.getPath(message)) - - - def notifyDone(self, relay): - """ - When the connection is lost or cannot be established, prepare to - resend unsent messages and fire all deferred which are waiting for - the completion of the attempt to relay. - - @type relay: L{SMTPManagedRelayerFactory} - @param relay: The factory for the relayer for the connection. - """ - for message in self.manager.managed.get(relay, ()): - if self.noisy: - log.msg("Setting " + message + " waiting") - self.manager.queue.setWaiting(message) - try: - del self.manager.managed[relay] - except KeyError: - pass - notifications = self._completionDeferreds - self._completionDeferreds = None - for d in notifications: - d.callback(None) - - - def notifyNoConnection(self, relay): - """ - When a connection to the mail exchange server cannot be established, - prepare to resend messages later. - - @type relay: L{SMTPManagedRelayerFactory} - @param relay: The factory for the relayer meant to use the connection. - """ - # Back off a bit - try: - msgs = self.manager.managed[relay] - except KeyError: - log.msg("notifyNoConnection passed unknown relay!") - return - - if self.noisy: - log.msg("Backing off on delivery of " + str(msgs)) - - def setWaiting(queue, messages): - map(queue.setWaiting, messages) - self.reactor.callLater(30, setWaiting, self.manager.queue, msgs) - del self.manager.managed[relay] - - - -class SmartHostSMTPRelayingManager: - """ - A smart host which uses SMTP managed relayers to send messages from the - relay queue. - - L{checkState} must be called periodically at which time the state of the - relay queue is checked and new relayers are created as needed. - - In order to relay a set of messages to a mail exchange server, a smart host - creates an attempt manager and a managed relayer factory for that set of - messages. When a connection is made with the mail exchange server, the - managed relayer factory creates a managed relayer to send the messages. - The managed relayer reports on its progress to the attempt manager which, - in turn, updates the smart host's relay queue and information about its - managed relayers. - - @ivar queue: See L{__init__}. - @ivar maxConnections: See L{__init__}. - @ivar maxMessagesPerConnection: See L{__init__}. - - @type fArgs: 3-L{tuple} of (0) L{list} of L{bytes}, - (1) L{_AttemptManager}, (2) L{bytes} or 4-L{tuple} of (0) L{list} - of L{bytes}, (1) L{_AttemptManager}, (2) L{bytes}, (3) L{int} - @ivar fArgs: Positional arguments for - L{SMTPManagedRelayerFactory.__init__}. - - @type fKwArgs: L{dict} - @ivar fKwArgs: Keyword arguments for L{SMTPManagedRelayerFactory.__init__}. - - @type factory: callable which returns L{SMTPManagedRelayerFactory} - @ivar factory: A callable which creates a factory for creating a managed - relayer. See L{SMTPManagedRelayerFactory.__init__} for parameters to - the callable. - - @type PORT: L{int} - @ivar PORT: The port over which to connect to the SMTP server. - - @type mxcalc: L{NoneType } or L{MXCalculator} - @ivar mxcalc: A resource for mail exchange host lookups. - - @type managed: L{dict} mapping L{SMTPManagedRelayerFactory} to L{list} of - L{bytes} - @ivar managed: A mapping of factory for a managed relayer to - filenames of messages the managed relayer is responsible for. - """ - factory = SMTPManagedRelayerFactory - - PORT = 25 - - mxcalc = None - - def __init__(self, queue, maxConnections=2, maxMessagesPerConnection=10): - """ - Initialize a smart host. - - The default values specify connection limits appropriate for a - low-volume smart host. - - @type queue: L{Queue} - @param queue: A relay queue. - - @type maxConnections: L{int} - @param maxConnections: The maximum number of concurrent connections to - SMTP servers. - - @type maxMessagesPerConnection: L{int} - @param maxMessagesPerConnection: The maximum number of messages for - which a relayer will be given responsibility. - """ - self.maxConnections = maxConnections - self.maxMessagesPerConnection = maxMessagesPerConnection - self.managed = {} # SMTP clients we're managing - self.queue = queue - self.fArgs = () - self.fKwArgs = {} - - - def __getstate__(self): - """ - Create a representation of the non-volatile state of this object. - - @rtype: L{dict} mapping L{bytes} to L{object} - @return: The non-volatile state of the queue. - """ - dct = self.__dict__.copy() - del dct['managed'] - return dct - - - def __setstate__(self, state): - """ - Restore the non-volatile state of this object and recreate the volatile - state. - - @type state: L{dict} mapping L{bytes} to L{object} - @param state: The non-volatile state of the queue. - """ - self.__dict__.update(state) - self.managed = {} - - - def checkState(self): - """ - Check the state of the relay queue and, if possible, launch relayers to - handle waiting messages. - - @rtype: L{NoneType } or L{Deferred} - @return: No return value if no further messages can be relayed or a - deferred which fires when all of the SMTP connections initiated by - this call have disconnected. - """ - self.queue.readDirectory() - if (len(self.managed) >= self.maxConnections): - return - if not self.queue.hasWaiting(): - return - - return self._checkStateMX() - - - def _checkStateMX(self): - nextMessages = self.queue.getWaiting() - nextMessages.reverse() - - exchanges = {} - for msg in nextMessages: - from_, to = self.queue.getEnvelope(msg) - name, addr = rfc822.parseaddr(to) - parts = addr.split('@', 1) - if len(parts) != 2: - log.err("Illegal message destination: " + to) - continue - domain = parts[1] - - self.queue.setRelaying(msg) - exchanges.setdefault(domain, []).append(self.queue.getPath(msg)) - if len(exchanges) >= (self.maxConnections - len(self.managed)): - break - - if self.mxcalc is None: - self.mxcalc = MXCalculator() - - relays = [] - for (domain, msgs) in exchanges.iteritems(): - manager = _AttemptManager(self, self.queue.noisy) - factory = self.factory(msgs, manager, *self.fArgs, **self.fKwArgs) - self.managed[factory] = map(os.path.basename, msgs) - relayAttemptDeferred = manager.getCompletionDeferred() - connectSetupDeferred = self.mxcalc.getMX(domain) - connectSetupDeferred.addCallback(lambda mx: str(mx.name)) - connectSetupDeferred.addCallback(self._cbExchange, self.PORT, - factory) - connectSetupDeferred.addErrback(lambda err: ( - relayAttemptDeferred.errback(err), err)[1]) - connectSetupDeferred.addErrback(self._ebExchange, factory, domain) - relays.append(relayAttemptDeferred) - return DeferredList(relays) - - - def _cbExchange(self, address, port, factory): - """ - Initiate a connection with a mail exchange server. - - This callback function runs after mail exchange server for the domain - has been looked up. - - @type address: L{bytes} - @param address: The hostname of a mail exchange server. - - @type port: L{int} - @param port: A port number. - - @type factory: L{SMTPManagedRelayerFactory} - @param factory: A factory which can create a relayer for the mail - exchange server. - """ - from twisted.internet import reactor - reactor.connectTCP(address, port, factory) - - - def _ebExchange(self, failure, factory, domain): - """ - Prepare to resend messages later. - - This errback function runs when no mail exchange server for the domain - can be found. - - @type failure: L{Failure} - @param failure: The reason the mail exchange lookup failed. - - @type factory: L{SMTPManagedRelayerFactory} - @param factory: A factory which can create a relayer for the mail - exchange server. - - @type domain: L{bytes} - @param domain: A domain. - """ - log.err('Error setting up managed relay factory for ' + domain) - log.err(failure) - - def setWaiting(queue, messages): - map(queue.setWaiting, messages) - - from twisted.internet import reactor - reactor.callLater(30, setWaiting, self.queue, self.managed[factory]) - del self.managed[factory] - - - -class SmartHostESMTPRelayingManager(SmartHostSMTPRelayingManager): - """ - A smart host which uses ESMTP managed relayers to send messages from the - relay queue. - - @type factory: callable which returns L{ESMTPManagedRelayerFactory} - @ivar factory: A callable which creates a factory for creating a managed - relayer. See L{ESMTPManagedRelayerFactory.__init__} for parameters to - the callable. - """ - factory = ESMTPManagedRelayerFactory - - - -def _checkState(manager): - """ - Prompt a relaying manager to check state. - - @type manager: L{SmartHostSMTPRelayingManager} - @param manager: A relaying manager. - """ - manager.checkState() - - - -def RelayStateHelper(manager, delay): - """ - Set up a periodic call to prompt a relaying manager to check state. - - @type manager: L{SmartHostSMTPRelayingManager} - @param manager: A relaying manager. - - @type delay: L{float} - @param delay: The number of seconds between calls. - - @rtype: L{TimerService } - @return: A service which periodically reminds a relaying manager to check - state. - """ - return internet.TimerService(delay, _checkState, manager) - - - -class CanonicalNameLoop(Exception): - """ - An error indicating that when trying to look up a mail exchange host, a set - of canonical name records was found which form a cycle and resolution was - abandoned. - """ - - - -class CanonicalNameChainTooLong(Exception): - """ - An error indicating that when trying to look up a mail exchange host, too - many canonical name records which point to other canonical name records - were encountered and resolution was abandoned. - """ - - - -class MXCalculator: - """ - A utility for looking up mail exchange hosts and tracking whether they are - working or not. - - @type clock: L{IReactorTime } - provider - @ivar clock: A reactor which will be used to schedule timeouts. - - @type resolver: L{IResolver } - @ivar resolver: A resolver. - - @type badMXs: L{dict} mapping L{bytes} to L{float} - @ivar badMXs: A mapping of non-functioning mail exchange hostname to time - at which another attempt at contacting it may be made. - - @type timeOutBadMX: L{int} - @ivar timeOutBadMX: Period in seconds between attempts to contact a - non-functioning mail exchange host. - - @type fallbackToDomain: L{bool} - @ivar fallbackToDomain: A flag indicating whether to attempt to use the - hostname directly when no mail exchange can be found (C{True}) or - not (C{False}). - """ - timeOutBadMX = 60 * 60 # One hour - fallbackToDomain = True - - def __init__(self, resolver=None, clock=None): - """ - @type resolver: L{IResolver } - provider or L{NoneType } - @param: A resolver. - - @type clock: L{IReactorTime } - provider or L{NoneType } - @param clock: A reactor which will be used to schedule timeouts. - """ - self.badMXs = {} - if resolver is None: - from twisted.names.client import createResolver - resolver = createResolver() - self.resolver = resolver - if clock is None: - from twisted.internet import reactor as clock - self.clock = clock - - - def markBad(self, mx): - """ - Record that a mail exchange host is not currently functioning. - - @type mx: L{bytes} - @param mx: The hostname of a mail exchange host. - """ - self.badMXs[str(mx)] = self.clock.seconds() + self.timeOutBadMX - - - def markGood(self, mx): - """ - Record that a mail exchange host is functioning. - - @type mx: L{bytes} - @param mx: The hostname of a mail exchange host. - """ - try: - del self.badMXs[mx] - except KeyError: - pass - - - def getMX(self, domain, maximumCanonicalChainLength=3): - """ - Find the name of a host that acts as a mail exchange server - for a domain. - - @type domain: L{bytes} - @param domain: A domain name. - - @type maximumCanonicalChainLength: L{int} - @param maximumCanonicalChainLength: The maximum number of unique - canonical name records to follow while looking up the mail exchange - host. - - @rtype: L{Deferred} which successfully fires with L{Record_MX} - @return: A deferred which succeeds with the MX record for the mail - exchange server for the domain or fails if none can be found. - """ - mailExchangeDeferred = self.resolver.lookupMailExchange(domain) - mailExchangeDeferred.addCallback(self._filterRecords) - mailExchangeDeferred.addCallback( - self._cbMX, domain, maximumCanonicalChainLength) - mailExchangeDeferred.addErrback(self._ebMX, domain) - return mailExchangeDeferred - - - def _filterRecords(self, records): - """ - Organize the records of a DNS response by record name. - - @type records: 3-L{tuple} of (0) L{list} of L{RRHeader - }, (1) L{list} of L{RRHeader - }, (2) L{list} of L{RRHeader - } - @param records: Answer resource records, authority resource records and - additional resource records. - - @rtype: L{dict} mapping L{bytes} to L{list} of L{IRecord - } provider - @return: A mapping of record name to record payload. - """ - recordBag = {} - for answer in records[0]: - recordBag.setdefault(str(answer.name), []).append(answer.payload) - return recordBag - - - def _cbMX(self, answers, domain, cnamesLeft): - """ - Try to find the mail exchange host for a domain from the given DNS - records. - - This will attempt to resolve canonical name record results. It can - recognize loops and will give up on non-cyclic chains after a specified - number of lookups. - - @type answers: L{dict} mapping L{bytes} to L{list} of L{IRecord - } provider - @param answers: A mapping of record name to record payload. - - @type domain: L{bytes} - @param domain: A domain name. - - @type cnamesLeft: L{int} - @param cnamesLeft: The number of unique canonical name records - left to follow while looking up the mail exchange host. - - @rtype: L{Record_MX } or L{Failure} - @return: An MX record for the mail exchange host or a failure if one - cannot be found. - """ - # Do this import here so that relaymanager.py doesn't depend on - # twisted.names, only MXCalculator will. - from twisted.names import dns, error - - seenAliases = set() - exchanges = [] - # Examine the answers for the domain we asked about - pertinentRecords = answers.get(domain, []) - while pertinentRecords: - record = pertinentRecords.pop() - - # If it's a CNAME, we'll need to do some more processing - if record.TYPE == dns.CNAME: - - # Remember that this name was an alias. - seenAliases.add(domain) - - canonicalName = str(record.name) - # See if we have some local records which might be relevant. - if canonicalName in answers: - - # Make sure it isn't a loop contained entirely within the - # results we have here. - if canonicalName in seenAliases: - return Failure(CanonicalNameLoop(record)) - - pertinentRecords = answers[canonicalName] - exchanges = [] - else: - if cnamesLeft: - # Request more information from the server. - return self.getMX(canonicalName, cnamesLeft - 1) - else: - # Give up. - return Failure(CanonicalNameChainTooLong(record)) - - # If it's an MX, collect it. - if record.TYPE == dns.MX: - exchanges.append((record.preference, record)) - - if exchanges: - exchanges.sort() - for (preference, record) in exchanges: - host = str(record.name) - if host not in self.badMXs: - return record - t = self.clock.seconds() - self.badMXs[host] - if t >= 0: - del self.badMXs[host] - return record - return exchanges[0][1] - else: - # Treat no answers the same as an error - jump to the errback to - # try to look up an A record. This provides behavior described as - # a special case in RFC 974 in the section headed I{Interpreting - # the List of MX RRs}. - return Failure( - error.DNSNameError("No MX records for %r" % (domain,))) - - - def _ebMX(self, failure, domain): - """ - Attempt to use the name of the domain directly when mail exchange - lookup fails. - - @type failure: L{Failure} - @param failure: The reason for the lookup failure. - - @type domain: L{bytes} - @param domain: The domain name. - - @rtype: L{Record_MX } or L{Failure} - @return: An MX record for the domain or a failure if the fallback to - domain option is not in effect and an error, other than not - finding an MX record, occurred during lookup. - - @raise IOError: When no MX record could be found and the fallback to - domain option is not in effect. - - @raise DNSLookupError: When no MX record could be found and the - fallback to domain option is in effect but no address for the - domain could be found. - """ - from twisted.names import error, dns - - if self.fallbackToDomain: - failure.trap(error.DNSNameError) - log.msg("MX lookup failed; attempting to use hostname (%s) directly" % (domain,)) - - # Alright, I admit, this is a bit icky. - d = self.resolver.getHostByName(domain) - - def cbResolved(addr): - return dns.Record_MX(name=addr) - - def ebResolved(err): - err.trap(error.DNSNameError) - raise DNSLookupError() - - d.addCallbacks(cbResolved, ebResolved) - return d - elif failure.check(error.DNSNameError): - raise IOError("No MX found for %r" % (domain,)) - return failure diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/scripts/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/scripts/__init__.py deleted file mode 100644 index f653cc7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/scripts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"mail scripts" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/scripts/mailmail.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/scripts/mailmail.py deleted file mode 100644 index 98e27cb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/scripts/mailmail.py +++ /dev/null @@ -1,365 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mailmail -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Implementation module for the I{mailmail} command. -""" - -import os -import sys -import rfc822 -import getpass -from ConfigParser import ConfigParser - -try: - import cStringIO as StringIO -except: - import StringIO - -from twisted.copyright import version -from twisted.internet import reactor -from twisted.mail import smtp - -GLOBAL_CFG = "/etc/mailmail" -LOCAL_CFG = os.path.expanduser("~/.twisted/mailmail") -SMARTHOST = '127.0.0.1' - -ERROR_FMT = """\ -Subject: Failed Message Delivery - - Message delivery failed. The following occurred: - - %s --- -The Twisted sendmail application. -""" - -def log(message, *args): - sys.stderr.write(str(message) % args + '\n') - -class Options: - """ - @type to: C{list} of C{str} - @ivar to: The addresses to which to deliver this message. - - @type sender: C{str} - @ivar sender: The address from which this message is being sent. - - @type body: C{file} - @ivar body: The object from which the message is to be read. - """ - -def getlogin(): - try: - return os.getlogin() - except: - return getpass.getuser() - - -_unsupportedOption = SystemExit("Unsupported option.") - -def parseOptions(argv): - o = Options() - o.to = [e for e in argv if not e.startswith('-')] - o.sender = getlogin() - - # Just be very stupid - - # Skip -bm -- it is the default - - # Add a non-standard option for querying the version of this tool. - if '--version' in argv: - print 'mailmail version:', version - raise SystemExit() - - # -bp lists queue information. Screw that. - if '-bp' in argv: - raise _unsupportedOption - - # -bs makes sendmail use stdin/stdout as its transport. Screw that. - if '-bs' in argv: - raise _unsupportedOption - - # -F sets who the mail is from, but is overridable by the From header - if '-F' in argv: - o.sender = argv[argv.index('-F') + 1] - o.to.remove(o.sender) - - # -i and -oi makes us ignore lone "." - if ('-i' in argv) or ('-oi' in argv): - raise _unsupportedOption - - # -odb is background delivery - if '-odb' in argv: - o.background = True - else: - o.background = False - - # -odf is foreground delivery - if '-odf' in argv: - o.background = False - else: - o.background = True - - # -oem and -em cause errors to be mailed back to the sender. - # It is also the default. - - # -oep and -ep cause errors to be printed to stderr - if ('-oep' in argv) or ('-ep' in argv): - o.printErrors = True - else: - o.printErrors = False - - # -om causes a copy of the message to be sent to the sender if the sender - # appears in an alias expansion. We do not support aliases. - if '-om' in argv: - raise _unsupportedOption - - # -t causes us to pick the recipients of the message from the To, Cc, and Bcc - # headers, and to remove the Bcc header if present. - if '-t' in argv: - o.recipientsFromHeaders = True - o.excludeAddresses = o.to - o.to = [] - else: - o.recipientsFromHeaders = False - o.exludeAddresses = [] - - requiredHeaders = { - 'from': [], - 'to': [], - 'cc': [], - 'bcc': [], - 'date': [], - } - - buffer = StringIO.StringIO() - while 1: - write = 1 - line = sys.stdin.readline() - if not line.strip(): - break - - hdrs = line.split(': ', 1) - - hdr = hdrs[0].lower() - if o.recipientsFromHeaders and hdr in ('to', 'cc', 'bcc'): - o.to.extend([ - a[1] for a in rfc822.AddressList(hdrs[1]).addresslist - ]) - if hdr == 'bcc': - write = 0 - elif hdr == 'from': - o.sender = rfc822.parseaddr(hdrs[1])[1] - - if hdr in requiredHeaders: - requiredHeaders[hdr].append(hdrs[1]) - - if write: - buffer.write(line) - - if not requiredHeaders['from']: - buffer.write('From: %s\r\n' % (o.sender,)) - if not requiredHeaders['to']: - if not o.to: - raise SystemExit("No recipients specified.") - buffer.write('To: %s\r\n' % (', '.join(o.to),)) - if not requiredHeaders['date']: - buffer.write('Date: %s\r\n' % (smtp.rfc822date(),)) - - buffer.write(line) - - if o.recipientsFromHeaders: - for a in o.excludeAddresses: - try: - o.to.remove(a) - except: - pass - - buffer.seek(0, 0) - o.body = StringIO.StringIO(buffer.getvalue() + sys.stdin.read()) - return o - -class Configuration: - """ - @ivar allowUIDs: A list of UIDs which are allowed to send mail. - @ivar allowGIDs: A list of GIDs which are allowed to send mail. - @ivar denyUIDs: A list of UIDs which are not allowed to send mail. - @ivar denyGIDs: A list of GIDs which are not allowed to send mail. - - @type defaultAccess: C{bool} - @ivar defaultAccess: C{True} if access will be allowed when no other access - control rule matches or C{False} if it will be denied in that case. - - @ivar useraccess: Either C{'allow'} to check C{allowUID} first - or C{'deny'} to check C{denyUID} first. - - @ivar groupaccess: Either C{'allow'} to check C{allowGID} first or - C{'deny'} to check C{denyGID} first. - - @ivar identities: A C{dict} mapping hostnames to credentials to use when - sending mail to that host. - - @ivar smarthost: C{None} or a hostname through which all outgoing mail will - be sent. - - @ivar domain: C{None} or the hostname with which to identify ourselves when - connecting to an MTA. - """ - def __init__(self): - self.allowUIDs = [] - self.denyUIDs = [] - self.allowGIDs = [] - self.denyGIDs = [] - self.useraccess = 'deny' - self.groupaccess= 'deny' - - self.identities = {} - self.smarthost = None - self.domain = None - - self.defaultAccess = True - - -def loadConfig(path): - # [useraccess] - # allow=uid1,uid2,... - # deny=uid1,uid2,... - # order=allow,deny - # [groupaccess] - # allow=gid1,gid2,... - # deny=gid1,gid2,... - # order=deny,allow - # [identity] - # host1=username:password - # host2=username:password - # [addresses] - # smarthost=a.b.c.d - # default_domain=x.y.z - - c = Configuration() - - if not os.access(path, os.R_OK): - return c - - p = ConfigParser() - p.read(path) - - au = c.allowUIDs - du = c.denyUIDs - ag = c.allowGIDs - dg = c.denyGIDs - for (section, a, d) in (('useraccess', au, du), ('groupaccess', ag, dg)): - if p.has_section(section): - for (mode, L) in (('allow', a), ('deny', d)): - if p.has_option(section, mode) and p.get(section, mode): - for id in p.get(section, mode).split(','): - try: - id = int(id) - except ValueError: - log("Illegal %sID in [%s] section: %s", section[0].upper(), section, id) - else: - L.append(id) - order = p.get(section, 'order') - order = map(str.split, map(str.lower, order.split(','))) - if order[0] == 'allow': - setattr(c, section, 'allow') - else: - setattr(c, section, 'deny') - - if p.has_section('identity'): - for (host, up) in p.items('identity'): - parts = up.split(':', 1) - if len(parts) != 2: - log("Illegal entry in [identity] section: %s", up) - continue - p.identities[host] = parts - - if p.has_section('addresses'): - if p.has_option('addresses', 'smarthost'): - c.smarthost = p.get('addresses', 'smarthost') - if p.has_option('addresses', 'default_domain'): - c.domain = p.get('addresses', 'default_domain') - - return c - -def success(result): - reactor.stop() - -failed = None -def failure(f): - global failed - reactor.stop() - failed = f - -def sendmail(host, options, ident): - d = smtp.sendmail(host, options.sender, options.to, options.body) - d.addCallbacks(success, failure) - reactor.run() - -def senderror(failure, options): - recipient = [options.sender] - sender = '"Internally Generated Message (%s)"' % (sys.argv[0], smtp.DNSNAME) - error = StringIO.StringIO() - failure.printTraceback(file=error) - body = StringIO.StringIO(ERROR_FMT % error.getvalue()) - - d = smtp.sendmail('localhost', sender, recipient, body) - d.addBoth(lambda _: reactor.stop()) - -def deny(conf): - uid = os.getuid() - gid = os.getgid() - - if conf.useraccess == 'deny': - if uid in conf.denyUIDs: - return True - if uid in conf.allowUIDs: - return False - else: - if uid in conf.allowUIDs: - return False - if uid in conf.denyUIDs: - return True - - if conf.groupaccess == 'deny': - if gid in conf.denyGIDs: - return True - if gid in conf.allowGIDs: - return False - else: - if gid in conf.allowGIDs: - return False - if gid in conf.denyGIDs: - return True - - return not conf.defaultAccess - -def run(): - o = parseOptions(sys.argv[1:]) - gConf = loadConfig(GLOBAL_CFG) - lConf = loadConfig(LOCAL_CFG) - - if deny(gConf) or deny(lConf): - log("Permission denied") - return - - host = lConf.smarthost or gConf.smarthost or SMARTHOST - - ident = gConf.identities.copy() - ident.update(lConf.identities) - - if lConf.domain: - smtp.DNSNAME = lConf.domain - elif gConf.domain: - smtp.DNSNAME = gConf.domain - - sendmail(host, o, ident) - - if failed: - if o.printErrors: - failed.printTraceback(file=sys.stderr) - raise SystemExit(1) - else: - senderror(failed, o) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/smtp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/smtp.py deleted file mode 100644 index edb38c1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/smtp.py +++ /dev/null @@ -1,2233 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_smtp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Simple Mail Transfer Protocol implementation. -""" - -import time, re, base64, types, socket, os, random, rfc822 -import binascii -import warnings -from email.base64MIME import encode as encode_base64 - -from zope.interface import implements, Interface - -from twisted.copyright import longversion -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import protocol -from twisted.internet import defer -from twisted.internet import error -from twisted.internet import reactor -from twisted.internet.interfaces import ITLSTransport, ISSLTransport -from twisted.python import log -from twisted.python import util - -from twisted import cred -from twisted.python.runtime import platform - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -# Cache the hostname (XXX Yes - this is broken) -if platform.isMacOSX(): - # On OS X, getfqdn() is ridiculously slow - use the - # probably-identical-but-sometimes-not gethostname() there. - DNSNAME = socket.gethostname() -else: - DNSNAME = socket.getfqdn() - -# Used for fast success code lookup -SUCCESS = dict.fromkeys(xrange(200,300)) - -class IMessageDelivery(Interface): - def receivedHeader(helo, origin, recipients): - """ - Generate the Received header for a message - - @type helo: C{(str, str)} - @param helo: The argument to the HELO command and the client's IP - address. - - @type origin: C{Address} - @param origin: The address the message is from - - @type recipients: C{list} of L{User} - @param recipients: A list of the addresses for which this message - is bound. - - @rtype: C{str} - @return: The full \"Received\" header string. - """ - - def validateTo(user): - """ - Validate the address for which the message is destined. - - @type user: C{User} - @param user: The address to validate. - - @rtype: no-argument callable - @return: A C{Deferred} which becomes, or a callable which - takes no arguments and returns an object implementing C{IMessage}. - This will be called and the returned object used to deliver the - message when it arrives. - - @raise SMTPBadRcpt: Raised if messages to the address are - not to be accepted. - """ - - def validateFrom(helo, origin): - """ - Validate the address from which the message originates. - - @type helo: C{(str, str)} - @param helo: The argument to the HELO command and the client's IP - address. - - @type origin: C{Address} - @param origin: The address the message is from - - @rtype: C{Deferred} or C{Address} - @return: C{origin} or a C{Deferred} whose callback will be - passed C{origin}. - - @raise SMTPBadSender: Raised of messages from this address are - not to be accepted. - """ - -class IMessageDeliveryFactory(Interface): - """An alternate interface to implement for handling message delivery. - - It is useful to implement this interface instead of L{IMessageDelivery} - directly because it allows the implementor to distinguish between - different messages delivery over the same connection. This can be - used to optimize delivery of a single message to multiple recipients, - something which cannot be done by L{IMessageDelivery} implementors - due to their lack of information. - """ - def getMessageDelivery(): - """Return an L{IMessageDelivery} object. - - This will be called once per message. - """ - -class SMTPError(Exception): - pass - - - -class SMTPClientError(SMTPError): - """Base class for SMTP client errors. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=False, retry=False): - """ - @param code: The SMTP response code associated with this error. - @param resp: The string response associated with this error. - - @param log: A string log of the exchange leading up to and including - the error. - @type log: L{str} - - @param isFatal: A boolean indicating whether this connection can - proceed or not. If True, the connection will be dropped. - - @param retry: A boolean indicating whether the delivery should be - retried. If True and the factory indicates further retries are - desirable, they will be attempted, otherwise the delivery will - be failed. - """ - self.code = code - self.resp = resp - self.log = log - self.addresses = addresses - self.isFatal = isFatal - self.retry = retry - - - def __str__(self): - if self.code > 0: - res = ["%.3d %s" % (self.code, self.resp)] - else: - res = [self.resp] - if self.log: - res.append(self.log) - res.append('') - return '\n'.join(res) - - -class ESMTPClientError(SMTPClientError): - """Base class for ESMTP client errors. - """ - -class EHLORequiredError(ESMTPClientError): - """The server does not support EHLO. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class AUTHRequiredError(ESMTPClientError): - """Authentication was required but the server does not support it. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class TLSRequiredError(ESMTPClientError): - """Transport security was required but the server does not support it. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class AUTHDeclinedError(ESMTPClientError): - """The server rejected our credentials. - - Either the username, password, or challenge response - given to the server was rejected. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class AuthenticationError(ESMTPClientError): - """An error occurred while authenticating. - - Either the server rejected our request for authentication or the - challenge received was malformed. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class TLSError(ESMTPClientError): - """An error occurred while negiotiating for transport security. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class SMTPConnectError(SMTPClientError): - """Failed to connect to the mail exchange host. - - This is considered a fatal error. A retry will be made. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=True, retry=True): - SMTPClientError.__init__(self, code, resp, log, addresses, isFatal, retry) - -class SMTPTimeoutError(SMTPClientError): - """Failed to receive a response from the server in the expected time period. - - This is considered a fatal error. A retry will be made. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=True, retry=True): - SMTPClientError.__init__(self, code, resp, log, addresses, isFatal, retry) - -class SMTPProtocolError(SMTPClientError): - """The server sent a mangled response. - - This is considered a fatal error. A retry will not be made. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=True, retry=False): - SMTPClientError.__init__(self, code, resp, log, addresses, isFatal, retry) - -class SMTPDeliveryError(SMTPClientError): - """Indicates that a delivery attempt has had an error. - """ - -class SMTPServerError(SMTPError): - def __init__(self, code, resp): - self.code = code - self.resp = resp - - def __str__(self): - return "%.3d %s" % (self.code, self.resp) - -class SMTPAddressError(SMTPServerError): - def __init__(self, addr, code, resp): - SMTPServerError.__init__(self, code, resp) - self.addr = Address(addr) - - def __str__(self): - return "%.3d <%s>... %s" % (self.code, self.addr, self.resp) - -class SMTPBadRcpt(SMTPAddressError): - def __init__(self, addr, code=550, - resp='Cannot receive for specified address'): - SMTPAddressError.__init__(self, addr, code, resp) - -class SMTPBadSender(SMTPAddressError): - def __init__(self, addr, code=550, resp='Sender not acceptable'): - SMTPAddressError.__init__(self, addr, code, resp) - -def rfc822date(timeinfo=None,local=1): - """ - Format an RFC-2822 compliant date string. - - @param timeinfo: (optional) A sequence as returned by C{time.localtime()} - or C{time.gmtime()}. Default is now. - @param local: (optional) Indicates if the supplied time is local or - universal time, or if no time is given, whether now should be local or - universal time. Default is local, as suggested (SHOULD) by rfc-2822. - - @returns: A string representing the time and date in RFC-2822 format. - """ - if not timeinfo: - if local: - timeinfo = time.localtime() - else: - timeinfo = time.gmtime() - if local: - if timeinfo[8]: - # DST - tz = -time.altzone - else: - tz = -time.timezone - - (tzhr, tzmin) = divmod(abs(tz), 3600) - if tz: - tzhr *= int(abs(tz)//tz) - (tzmin, tzsec) = divmod(tzmin, 60) - else: - (tzhr, tzmin) = (0,0) - - return "%s, %02d %s %04d %02d:%02d:%02d %+03d%02d" % ( - ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][timeinfo[6]], - timeinfo[2], - ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][timeinfo[1] - 1], - timeinfo[0], timeinfo[3], timeinfo[4], timeinfo[5], - tzhr, tzmin) - -def idGenerator(): - i = 0 - while True: - yield i - i += 1 - -def messageid(uniq=None, N=idGenerator().next): - """Return a globally unique random string in RFC 2822 Message-ID format - - - - Optional uniq string will be added to strengthen uniqueness if given. - """ - datetime = time.strftime('%Y%m%d%H%M%S', time.gmtime()) - pid = os.getpid() - rand = random.randrange(2**31L-1) - if uniq is None: - uniq = '' - else: - uniq = '.' + uniq - - return '<%s.%s.%s%s.%s@%s>' % (datetime, pid, rand, uniq, N(), DNSNAME) - -def quoteaddr(addr): - """Turn an email address, possibly with realname part etc, into - a form suitable for and SMTP envelope. - """ - - if isinstance(addr, Address): - return '<%s>' % str(addr) - - res = rfc822.parseaddr(addr) - - if res == (None, None): - # It didn't parse, use it as-is - return '<%s>' % str(addr) - else: - return '<%s>' % str(res[1]) - -COMMAND, DATA, AUTH = 'COMMAND', 'DATA', 'AUTH' - -class AddressError(SMTPError): - "Parse error in address" - -# Character classes for parsing addresses -atom = r"[-A-Za-z0-9!\#$%&'*+/=?^_`{|}~]" - -class Address: - """Parse and hold an RFC 2821 address. - - Source routes are stipped and ignored, UUCP-style bang-paths - and %-style routing are not parsed. - - @type domain: C{str} - @ivar domain: The domain within which this address resides. - - @type local: C{str} - @ivar local: The local (\"user\") portion of this address. - """ - - tstring = re.compile(r'''( # A string of - (?:"[^"]*" # quoted string - |\\. # backslash-escaped characted - |''' + atom + r''' # atom character - )+|.) # or any single character''',re.X) - atomre = re.compile(atom) # match any one atom character - - def __init__(self, addr, defaultDomain=None): - if isinstance(addr, User): - addr = addr.dest - if isinstance(addr, Address): - self.__dict__ = addr.__dict__.copy() - return - elif not isinstance(addr, types.StringTypes): - addr = str(addr) - self.addrstr = addr - - # Tokenize - atl = filter(None,self.tstring.split(addr)) - - local = [] - domain = [] - - while atl: - if atl[0] == '<': - if atl[-1] != '>': - raise AddressError, "Unbalanced <>" - atl = atl[1:-1] - elif atl[0] == '@': - atl = atl[1:] - if not local: - # Source route - while atl and atl[0] != ':': - # remove it - atl = atl[1:] - if not atl: - raise AddressError, "Malformed source route" - atl = atl[1:] # remove : - elif domain: - raise AddressError, "Too many @" - else: - # Now in domain - domain = [''] - elif len(atl[0]) == 1 and not self.atomre.match(atl[0]) and atl[0] != '.': - raise AddressError, "Parse error at %r of %r" % (atl[0], (addr, atl)) - else: - if not domain: - local.append(atl[0]) - else: - domain.append(atl[0]) - atl = atl[1:] - - self.local = ''.join(local) - self.domain = ''.join(domain) - if self.local != '' and self.domain == '': - if defaultDomain is None: - defaultDomain = DNSNAME - self.domain = defaultDomain - - dequotebs = re.compile(r'\\(.)') - - def dequote(self,addr): - """Remove RFC-2821 quotes from address.""" - res = [] - - atl = filter(None,self.tstring.split(str(addr))) - - for t in atl: - if t[0] == '"' and t[-1] == '"': - res.append(t[1:-1]) - elif '\\' in t: - res.append(self.dequotebs.sub(r'\1',t)) - else: - res.append(t) - - return ''.join(res) - - def __str__(self): - if self.local or self.domain: - return '@'.join((self.local, self.domain)) - else: - return '' - - def __repr__(self): - return "%s.%s(%s)" % (self.__module__, self.__class__.__name__, - repr(str(self))) - -class User: - """Hold information about and SMTP message recipient, - including information on where the message came from - """ - - def __init__(self, destination, helo, protocol, orig): - host = getattr(protocol, 'host', None) - self.dest = Address(destination, host) - self.helo = helo - self.protocol = protocol - if isinstance(orig, Address): - self.orig = orig - else: - self.orig = Address(orig, host) - - def __getstate__(self): - """Helper for pickle. - - protocol isn't picklabe, but we want User to be, so skip it in - the pickle. - """ - return { 'dest' : self.dest, - 'helo' : self.helo, - 'protocol' : None, - 'orig' : self.orig } - - def __str__(self): - return str(self.dest) - -class IMessage(Interface): - """Interface definition for messages that can be sent via SMTP.""" - - def lineReceived(line): - """handle another line""" - - def eomReceived(): - """handle end of message - - return a deferred. The deferred should be called with either: - callback(string) or errback(error) - """ - - def connectionLost(): - """handle message truncated - - semantics should be to discard the message - """ - -class SMTP(basic.LineOnlyReceiver, policies.TimeoutMixin): - """ - SMTP server-side protocol. - """ - - timeout = 600 - host = DNSNAME - portal = None - - # Control whether we log SMTP events - noisy = True - - # A factory for IMessageDelivery objects. If an - # avatar implementing IMessageDeliveryFactory can - # be acquired from the portal, it will be used to - # create a new IMessageDelivery object for each - # message which is received. - deliveryFactory = None - - # An IMessageDelivery object. A new instance is - # used for each message received if we can get an - # IMessageDeliveryFactory from the portal. Otherwise, - # a single instance is used throughout the lifetime - # of the connection. - delivery = None - - # Cred cleanup function. - _onLogout = None - - def __init__(self, delivery=None, deliveryFactory=None): - self.mode = COMMAND - self._from = None - self._helo = None - self._to = [] - self.delivery = delivery - self.deliveryFactory = deliveryFactory - - def timeoutConnection(self): - msg = '%s Timeout. Try talking faster next time!' % (self.host,) - self.sendCode(421, msg) - self.transport.loseConnection() - - def greeting(self): - return '%s NO UCE NO UBE NO RELAY PROBES' % (self.host,) - - def connectionMade(self): - # Ensure user-code always gets something sane for _helo - peer = self.transport.getPeer() - try: - host = peer.host - except AttributeError: # not an IPv4Address - host = str(peer) - self._helo = (None, host) - self.sendCode(220, self.greeting()) - self.setTimeout(self.timeout) - - def sendCode(self, code, message=''): - "Send an SMTP code with a message." - lines = message.splitlines() - lastline = lines[-1:] - for line in lines[:-1]: - self.sendLine('%3.3d-%s' % (code, line)) - self.sendLine('%3.3d %s' % (code, - lastline and lastline[0] or '')) - - def lineReceived(self, line): - self.resetTimeout() - return getattr(self, 'state_' + self.mode)(line) - - def state_COMMAND(self, line): - # Ignore leading and trailing whitespace, as well as an arbitrary - # amount of whitespace between the command and its argument, though - # it is not required by the protocol, for it is a nice thing to do. - line = line.strip() - - parts = line.split(None, 1) - if parts: - method = self.lookupMethod(parts[0]) or self.do_UNKNOWN - if len(parts) == 2: - method(parts[1]) - else: - method('') - else: - self.sendSyntaxError() - - def sendSyntaxError(self): - self.sendCode(500, 'Error: bad syntax') - - def lookupMethod(self, command): - return getattr(self, 'do_' + command.upper(), None) - - def lineLengthExceeded(self, line): - if self.mode is DATA: - for message in self.__messages: - message.connectionLost() - self.mode = COMMAND - del self.__messages - self.sendCode(500, 'Line too long') - - def do_UNKNOWN(self, rest): - self.sendCode(500, 'Command not implemented') - - def do_HELO(self, rest): - peer = self.transport.getPeer() - try: - host = peer.host - except AttributeError: - host = str(peer) - self._helo = (rest, host) - self._from = None - self._to = [] - self.sendCode(250, '%s Hello %s, nice to meet you' % (self.host, host)) - - def do_QUIT(self, rest): - self.sendCode(221, 'See you later') - self.transport.loseConnection() - - # A string of quoted strings, backslash-escaped character or - # atom characters + '@.,:' - qstring = r'("[^"]*"|\\.|' + atom + r'|[@.,:])+' - - mail_re = re.compile(r'''\s*FROM:\s*(?P<> # Empty <> - |<''' + qstring + r'''> # - |''' + qstring + r''' # addr - )\s*(\s(?P.*))? # Optional WS + ESMTP options - $''',re.I|re.X) - rcpt_re = re.compile(r'\s*TO:\s*(?P<' + qstring + r'''> # - |''' + qstring + r''' # addr - )\s*(\s(?P.*))? # Optional WS + ESMTP options - $''',re.I|re.X) - - def do_MAIL(self, rest): - if self._from: - self.sendCode(503,"Only one sender per message, please") - return - # Clear old recipient list - self._to = [] - m = self.mail_re.match(rest) - if not m: - self.sendCode(501, "Syntax error") - return - - try: - addr = Address(m.group('path'), self.host) - except AddressError, e: - self.sendCode(553, str(e)) - return - - validated = defer.maybeDeferred(self.validateFrom, self._helo, addr) - validated.addCallbacks(self._cbFromValidate, self._ebFromValidate) - - - def _cbFromValidate(self, from_, code=250, msg='Sender address accepted'): - self._from = from_ - self.sendCode(code, msg) - - - def _ebFromValidate(self, failure): - if failure.check(SMTPBadSender): - self.sendCode(failure.value.code, - 'Cannot receive from specified address %s: %s' - % (quoteaddr(failure.value.addr), failure.value.resp)) - elif failure.check(SMTPServerError): - self.sendCode(failure.value.code, failure.value.resp) - else: - log.err(failure, "SMTP sender validation failure") - self.sendCode( - 451, - 'Requested action aborted: local error in processing') - - - def do_RCPT(self, rest): - if not self._from: - self.sendCode(503, "Must have sender before recipient") - return - m = self.rcpt_re.match(rest) - if not m: - self.sendCode(501, "Syntax error") - return - - try: - user = User(m.group('path'), self._helo, self, self._from) - except AddressError, e: - self.sendCode(553, str(e)) - return - - d = defer.maybeDeferred(self.validateTo, user) - d.addCallbacks( - self._cbToValidate, - self._ebToValidate, - callbackArgs=(user,) - ) - - def _cbToValidate(self, to, user=None, code=250, msg='Recipient address accepted'): - if user is None: - user = to - self._to.append((user, to)) - self.sendCode(code, msg) - - def _ebToValidate(self, failure): - if failure.check(SMTPBadRcpt, SMTPServerError): - self.sendCode(failure.value.code, failure.value.resp) - else: - log.err(failure) - self.sendCode( - 451, - 'Requested action aborted: local error in processing' - ) - - def _disconnect(self, msgs): - for msg in msgs: - try: - msg.connectionLost() - except: - log.msg("msg raised exception from connectionLost") - log.err() - - def do_DATA(self, rest): - if self._from is None or (not self._to): - self.sendCode(503, 'Must have valid receiver and originator') - return - self.mode = DATA - helo, origin = self._helo, self._from - recipients = self._to - - self._from = None - self._to = [] - self.datafailed = None - - msgs = [] - for (user, msgFunc) in recipients: - try: - msg = msgFunc() - rcvdhdr = self.receivedHeader(helo, origin, [user]) - if rcvdhdr: - msg.lineReceived(rcvdhdr) - msgs.append(msg) - except SMTPServerError, e: - self.sendCode(e.code, e.resp) - self.mode = COMMAND - self._disconnect(msgs) - return - except: - log.err() - self.sendCode(550, "Internal server error") - self.mode = COMMAND - self._disconnect(msgs) - return - self.__messages = msgs - - self.__inheader = self.__inbody = 0 - self.sendCode(354, 'Continue') - - if self.noisy: - fmt = 'Receiving message for delivery: from=%s to=%s' - log.msg(fmt % (origin, [str(u) for (u, f) in recipients])) - - def connectionLost(self, reason): - # self.sendCode(421, 'Dropping connection.') # This does nothing... - # Ideally, if we (rather than the other side) lose the connection, - # we should be able to tell the other side that we are going away. - # RFC-2821 requires that we try. - if self.mode is DATA: - try: - for message in self.__messages: - try: - message.connectionLost() - except: - log.err() - del self.__messages - except AttributeError: - pass - if self._onLogout: - self._onLogout() - self._onLogout = None - self.setTimeout(None) - - def do_RSET(self, rest): - self._from = None - self._to = [] - self.sendCode(250, 'I remember nothing.') - - def dataLineReceived(self, line): - if line[:1] == '.': - if line == '.': - self.mode = COMMAND - if self.datafailed: - self.sendCode(self.datafailed.code, - self.datafailed.resp) - return - if not self.__messages: - self._messageHandled("thrown away") - return - defer.DeferredList([ - m.eomReceived() for m in self.__messages - ], consumeErrors=True).addCallback(self._messageHandled - ) - del self.__messages - return - line = line[1:] - - if self.datafailed: - return - - try: - # Add a blank line between the generated Received:-header - # and the message body if the message comes in without any - # headers - if not self.__inheader and not self.__inbody: - if ':' in line: - self.__inheader = 1 - elif line: - for message in self.__messages: - message.lineReceived('') - self.__inbody = 1 - - if not line: - self.__inbody = 1 - - for message in self.__messages: - message.lineReceived(line) - except SMTPServerError, e: - self.datafailed = e - for message in self.__messages: - message.connectionLost() - state_DATA = dataLineReceived - - def _messageHandled(self, resultList): - failures = 0 - for (success, result) in resultList: - if not success: - failures += 1 - log.err(result) - if failures: - msg = 'Could not send e-mail' - L = len(resultList) - if L > 1: - msg += ' (%d failures out of %d recipients)' % (failures, L) - self.sendCode(550, msg) - else: - self.sendCode(250, 'Delivery in progress') - - - def _cbAnonymousAuthentication(self, (iface, avatar, logout)): - """ - Save the state resulting from a successful anonymous cred login. - """ - if issubclass(iface, IMessageDeliveryFactory): - self.deliveryFactory = avatar - self.delivery = None - elif issubclass(iface, IMessageDelivery): - self.deliveryFactory = None - self.delivery = avatar - else: - raise RuntimeError("%s is not a supported interface" % (iface.__name__,)) - self._onLogout = logout - self.challenger = None - - - # overridable methods: - def validateFrom(self, helo, origin): - """ - Validate the address from which the message originates. - - @type helo: C{(str, str)} - @param helo: The argument to the HELO command and the client's IP - address. - - @type origin: C{Address} - @param origin: The address the message is from - - @rtype: C{Deferred} or C{Address} - @return: C{origin} or a C{Deferred} whose callback will be - passed C{origin}. - - @raise SMTPBadSender: Raised of messages from this address are - not to be accepted. - """ - if self.deliveryFactory is not None: - self.delivery = self.deliveryFactory.getMessageDelivery() - - if self.delivery is not None: - return defer.maybeDeferred(self.delivery.validateFrom, - helo, origin) - - # No login has been performed, no default delivery object has been - # provided: try to perform an anonymous login and then invoke this - # method again. - if self.portal: - - result = self.portal.login( - cred.credentials.Anonymous(), - None, - IMessageDeliveryFactory, IMessageDelivery) - - def ebAuthentication(err): - """ - Translate cred exceptions into SMTP exceptions so that the - protocol code which invokes C{validateFrom} can properly report - the failure. - """ - if err.check(cred.error.UnauthorizedLogin): - exc = SMTPBadSender(origin) - elif err.check(cred.error.UnhandledCredentials): - exc = SMTPBadSender( - origin, resp="Unauthenticated senders not allowed") - else: - return err - return defer.fail(exc) - - result.addCallbacks( - self._cbAnonymousAuthentication, ebAuthentication) - - def continueValidation(ignored): - """ - Re-attempt from address validation. - """ - return self.validateFrom(helo, origin) - - result.addCallback(continueValidation) - return result - - raise SMTPBadSender(origin) - - - def validateTo(self, user): - """ - Validate the address for which the message is destined. - - @type user: L{User} - @param user: The address to validate. - - @rtype: no-argument callable - @return: A C{Deferred} which becomes, or a callable which - takes no arguments and returns an object implementing C{IMessage}. - This will be called and the returned object used to deliver the - message when it arrives. - - @raise SMTPBadRcpt: Raised if messages to the address are - not to be accepted. - """ - if self.delivery is not None: - return self.delivery.validateTo(user) - raise SMTPBadRcpt(user) - - def receivedHeader(self, helo, origin, recipients): - if self.delivery is not None: - return self.delivery.receivedHeader(helo, origin, recipients) - - heloStr = "" - if helo[0]: - heloStr = " helo=%s" % (helo[0],) - domain = self.transport.getHost().host - from_ = "from %s ([%s]%s)" % (helo[0], helo[1], heloStr) - by = "by %s with %s (%s)" % (domain, - self.__class__.__name__, - longversion) - for_ = "for %s; %s" % (' '.join(map(str, recipients)), - rfc822date()) - return "Received: %s\n\t%s\n\t%s" % (from_, by, for_) - - - -class SMTPFactory(protocol.ServerFactory): - """Factory for SMTP.""" - - # override in instances or subclasses - domain = DNSNAME - timeout = 600 - protocol = SMTP - - portal = None - - def __init__(self, portal = None): - self.portal = portal - - def buildProtocol(self, addr): - p = protocol.ServerFactory.buildProtocol(self, addr) - p.portal = self.portal - p.host = self.domain - return p - -class SMTPClient(basic.LineReceiver, policies.TimeoutMixin): - """ - SMTP client for sending emails. - - After the client has connected to the SMTP server, it repeatedly calls - L{SMTPClient.getMailFrom}, L{SMTPClient.getMailTo} and - L{SMTPClient.getMailData} and uses this information to send an email. - It then calls L{SMTPClient.getMailFrom} again; if it returns C{None}, the - client will disconnect, otherwise it will continue as normal i.e. call - L{SMTPClient.getMailTo} and L{SMTPClient.getMailData} and send a new email. - """ - - # If enabled then log SMTP client server communication - debug = True - - # Number of seconds to wait before timing out a connection. If - # None, perform no timeout checking. - timeout = None - - def __init__(self, identity, logsize=10): - self.identity = identity or '' - self.toAddressesResult = [] - self.successAddresses = [] - self._from = None - self.resp = [] - self.code = -1 - self.log = util.LineLog(logsize) - - def sendLine(self, line): - # Log sendLine only if you are in debug mode for performance - if self.debug: - self.log.append('>>> ' + line) - - basic.LineReceiver.sendLine(self,line) - - def connectionMade(self): - self.setTimeout(self.timeout) - - self._expected = [ 220 ] - self._okresponse = self.smtpState_helo - self._failresponse = self.smtpConnectionFailed - - def connectionLost(self, reason=protocol.connectionDone): - """We are no longer connected""" - self.setTimeout(None) - self.mailFile = None - - def timeoutConnection(self): - self.sendError( - SMTPTimeoutError( - -1, "Timeout waiting for SMTP server response", - self.log.str())) - - def lineReceived(self, line): - self.resetTimeout() - - # Log lineReceived only if you are in debug mode for performance - if self.debug: - self.log.append('<<< ' + line) - - why = None - - try: - self.code = int(line[:3]) - except ValueError: - # This is a fatal error and will disconnect the transport lineReceived will not be called again - self.sendError(SMTPProtocolError(-1, "Invalid response from SMTP server: %s" % line, self.log.str())) - return - - if line[0] == '0': - # Verbose informational message, ignore it - return - - self.resp.append(line[4:]) - - if line[3:4] == '-': - # continuation - return - - if self.code in self._expected: - why = self._okresponse(self.code,'\n'.join(self.resp)) - else: - why = self._failresponse(self.code,'\n'.join(self.resp)) - - self.code = -1 - self.resp = [] - return why - - def smtpConnectionFailed(self, code, resp): - self.sendError(SMTPConnectError(code, resp, self.log.str())) - - def smtpTransferFailed(self, code, resp): - if code < 0: - self.sendError(SMTPProtocolError(code, resp, self.log.str())) - else: - self.smtpState_msgSent(code, resp) - - def smtpState_helo(self, code, resp): - self.sendLine('HELO ' + self.identity) - self._expected = SUCCESS - self._okresponse = self.smtpState_from - - def smtpState_from(self, code, resp): - self._from = self.getMailFrom() - self._failresponse = self.smtpTransferFailed - if self._from is not None: - self.sendLine('MAIL FROM:%s' % quoteaddr(self._from)) - self._expected = [250] - self._okresponse = self.smtpState_to - else: - # All messages have been sent, disconnect - self._disconnectFromServer() - - def smtpState_disconnect(self, code, resp): - self.transport.loseConnection() - - def smtpState_to(self, code, resp): - self.toAddresses = iter(self.getMailTo()) - self.toAddressesResult = [] - self.successAddresses = [] - self._okresponse = self.smtpState_toOrData - self._expected = xrange(0,1000) - self.lastAddress = None - return self.smtpState_toOrData(0, '') - - def smtpState_toOrData(self, code, resp): - if self.lastAddress is not None: - self.toAddressesResult.append((self.lastAddress, code, resp)) - if code in SUCCESS: - self.successAddresses.append(self.lastAddress) - try: - self.lastAddress = self.toAddresses.next() - except StopIteration: - if self.successAddresses: - self.sendLine('DATA') - self._expected = [ 354 ] - self._okresponse = self.smtpState_data - else: - return self.smtpState_msgSent(code,'No recipients accepted') - else: - self.sendLine('RCPT TO:%s' % quoteaddr(self.lastAddress)) - - def smtpState_data(self, code, resp): - s = basic.FileSender() - d = s.beginFileTransfer( - self.getMailData(), self.transport, self.transformChunk) - def ebTransfer(err): - self.sendError(err.value) - d.addCallbacks(self.finishedFileTransfer, ebTransfer) - self._expected = SUCCESS - self._okresponse = self.smtpState_msgSent - - - def smtpState_msgSent(self, code, resp): - if self._from is not None: - self.sentMail(code, resp, len(self.successAddresses), - self.toAddressesResult, self.log) - - self.toAddressesResult = [] - self._from = None - self.sendLine('RSET') - self._expected = SUCCESS - self._okresponse = self.smtpState_from - - ## - ## Helpers for FileSender - ## - def transformChunk(self, chunk): - """ - Perform the necessary local to network newline conversion and escape - leading periods. - - This method also resets the idle timeout so that as long as process is - being made sending the message body, the client will not time out. - """ - self.resetTimeout() - return chunk.replace('\n', '\r\n').replace('\r\n.', '\r\n..') - - def finishedFileTransfer(self, lastsent): - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - - ## - # these methods should be overridden in subclasses - def getMailFrom(self): - """Return the email address the mail is from.""" - raise NotImplementedError - - def getMailTo(self): - """Return a list of emails to send to.""" - raise NotImplementedError - - def getMailData(self): - """Return file-like object containing data of message to be sent. - - Lines in the file should be delimited by '\\n'. - """ - raise NotImplementedError - - def sendError(self, exc): - """ - If an error occurs before a mail message is sent sendError will be - called. This base class method sends a QUIT if the error is - non-fatal and disconnects the connection. - - @param exc: The SMTPClientError (or child class) raised - @type exc: C{SMTPClientError} - """ - if isinstance(exc, SMTPClientError) and not exc.isFatal: - self._disconnectFromServer() - else: - # If the error was fatal then the communication channel with the - # SMTP Server is broken so just close the transport connection - self.smtpState_disconnect(-1, None) - - - def sentMail(self, code, resp, numOk, addresses, log): - """Called when an attempt to send an email is completed. - - If some addresses were accepted, code and resp are the response - to the DATA command. If no addresses were accepted, code is -1 - and resp is an informative message. - - @param code: the code returned by the SMTP Server - @param resp: The string response returned from the SMTP Server - @param numOK: the number of addresses accepted by the remote host. - @param addresses: is a list of tuples (address, code, resp) listing - the response to each RCPT command. - @param log: is the SMTP session log - """ - raise NotImplementedError - - def _disconnectFromServer(self): - self._expected = xrange(0, 1000) - self._okresponse = self.smtpState_disconnect - self.sendLine('QUIT') - - - -class ESMTPClient(SMTPClient): - """ - A client for sending emails over ESMTP. - - @ivar heloFallback: Whether or not to fall back to plain SMTP if the C{EHLO} - command is not recognised by the server. If L{requireAuthentication} is - C{True}, or L{requireTransportSecurity} is C{True} and the connection is - not over TLS, this fallback flag will not be honored. - @type heloFallback: L{bool} - - @ivar requireAuthentication: If C{True}, refuse to proceed if authentication - cannot be performed. Overrides L{heloFallback}. - @type requireAuthentication: L{bool} - - @ivar requireTransportSecurity: If C{True}, refuse to proceed if the - transport cannot be secured. If the transport layer is not already - secured via TLS, this will override L{heloFallback}. - @type requireAuthentication: L{bool} - - @ivar context: The context factory to use for STARTTLS, if desired. - @type context: L{ssl.ClientContextFactory} - - @ivar _tlsMode: Whether or not the connection is over TLS. - @type _tlsMode: L{bool} - """ - heloFallback = True - requireAuthentication = False - requireTransportSecurity = False - context = None - _tlsMode = False - - def __init__(self, secret, contextFactory=None, *args, **kw): - SMTPClient.__init__(self, *args, **kw) - self.authenticators = [] - self.secret = secret - self.context = contextFactory - - - def __getattr__(self, name): - if name == "tlsMode": - warnings.warn( - "tlsMode attribute of twisted.mail.smtp.ESMTPClient " - "is deprecated since Twisted 13.0", - category=DeprecationWarning, stacklevel=2) - return self._tlsMode - else: - raise AttributeError( - '%s instance has no attribute %r' % ( - self.__class__.__name__, name,)) - - - def __setattr__(self, name, value): - if name == "tlsMode": - warnings.warn( - "tlsMode attribute of twisted.mail.smtp.ESMTPClient " - "is deprecated since Twisted 13.0", - category=DeprecationWarning, stacklevel=2) - self._tlsMode = value - else: - self.__dict__[name] = value - - - def esmtpEHLORequired(self, code=-1, resp=None): - """ - Fail because authentication is required, but the server does not support - ESMTP, which is required for authentication. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - """ - self.sendError(EHLORequiredError(502, b"Server does not support ESMTP " - b"Authentication", self.log.str())) - - - def esmtpAUTHRequired(self, code=-1, resp=None): - """ - Fail because authentication is required, but the server does not support - any schemes we support. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - """ - tmp = [] - - for a in self.authenticators: - tmp.append(a.getName().upper()) - - auth = b"[%s]" % b", ".join(tmp) - - self.sendError(AUTHRequiredError(502, b"Server does not support Client " - b"Authentication schemes %s" % auth, self.log.str())) - - - def esmtpTLSRequired(self, code=-1, resp=None): - """ - Fail because TLS is required and the server does not support it. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - """ - self.sendError(TLSRequiredError(502, b"Server does not support secure " - b"communication via TLS / SSL", self.log.str())) - - - def esmtpTLSFailed(self, code=-1, resp=None): - """ - Fail because the TLS handshake wasn't able to be completed. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - """ - self.sendError(TLSError(code, b"Could not complete the SSL/TLS " - b"handshake", self.log.str())) - - - def esmtpAUTHDeclined(self, code=-1, resp=None): - """ - Fail because the authentication was rejected. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - """ - self.sendError(AUTHDeclinedError(code, resp, self.log.str())) - - - def esmtpAUTHMalformedChallenge(self, code=-1, resp=None): - """ - Fail because the server sent a malformed authentication challenge. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - """ - self.sendError(AuthenticationError(501, b"Login failed because the " - b"SMTP Server returned a malformed Authentication Challenge", - self.log.str())) - - - def esmtpAUTHServerError(self, code=-1, resp=None): - """ - Fail because of some other authentication error. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - """ - self.sendError(AuthenticationError(code, resp, self.log.str())) - - - def registerAuthenticator(self, auth): - """ - Registers an Authenticator with the ESMTPClient. The ESMTPClient will - attempt to login to the SMTP Server in the order the Authenticators are - registered. The most secure Authentication mechanism should be - registered first. - - @param auth: The Authentication mechanism to register - @type auth: L{IClientAuthentication} implementor - - @return C{None} - """ - self.authenticators.append(auth) - - - def connectionMade(self): - """ - Called when a connection has been made, and triggers sending an C{EHLO} - to the server. - """ - self._tlsMode = ISSLTransport.providedBy(self.transport) - SMTPClient.connectionMade(self) - self._okresponse = self.esmtpState_ehlo - - - def esmtpState_ehlo(self, code, resp): - """ - Send an C{EHLO} to the server. - - If L{heloFallback} is C{True}, and there is no requirement for TLS or - authentication, the client will fall back to basic SMTP. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - - @return: C{None} - """ - self._expected = SUCCESS - - self._okresponse = self.esmtpState_serverConfig - self._failresponse = self.esmtpEHLORequired - - if self._tlsMode: - needTLS = False - else: - needTLS = self.requireTransportSecurity - - if self.heloFallback and not self.requireAuthentication and not needTLS: - self._failresponse = self.smtpState_helo - - self.sendLine(b"EHLO " + self.identity) - - - def esmtpState_serverConfig(self, code, resp): - """ - Handle a positive response to the I{EHLO} command by parsing the - capabilities in the server's response and then taking the most - appropriate next step towards entering a mail transaction. - """ - items = {} - for line in resp.splitlines(): - e = line.split(None, 1) - if len(e) > 1: - items[e[0]] = e[1] - else: - items[e[0]] = None - - self.tryTLS(code, resp, items) - - - def tryTLS(self, code, resp, items): - """ - Take a necessary step towards being able to begin a mail transaction. - - The step may be to ask the server to being a TLS session. If TLS is - already in use or not necessary and not available then the step may be - to authenticate with the server. If TLS is necessary and not available, - fail the mail transmission attempt. - - This is an internal helper method. - - @param code: The server status code from the most recently received - server message. - @type code: L{int} - - @param resp: The server status response from the most recently received - server message. - @type resp: L{bytes} - - @param items: A mapping of ESMTP extensions offered by the server. Keys - are extension identifiers and values are the associated values. - @type items: L{dict} mapping L{bytes} to L{bytes} - - @return: C{None} - """ - - # has tls can tls must tls result - # t t t authenticate - # t t f authenticate - # t f t authenticate - # t f f authenticate - - # f t t STARTTLS - # f t f STARTTLS - # f f t esmtpTLSRequired - # f f f authenticate - - hasTLS = self._tlsMode - canTLS = self.context and b"STARTTLS" in items - mustTLS = self.requireTransportSecurity - - if hasTLS or not (canTLS or mustTLS): - self.authenticate(code, resp, items) - elif canTLS: - self._expected = [220] - self._okresponse = self.esmtpState_starttls - self._failresponse = self.esmtpTLSFailed - self.sendLine(b"STARTTLS") - else: - self.esmtpTLSRequired() - - - def esmtpState_starttls(self, code, resp): - """ - Handle a positive response to the I{STARTTLS} command by starting a new - TLS session on C{self.transport}. - - Upon success, re-handshake with the server to discover what capabilities - it has when TLS is in use. - """ - try: - self.transport.startTLS(self.context) - self._tlsMode = True - except: - log.err() - self.esmtpTLSFailed(451) - - # Send another EHLO once TLS has been started to - # get the TLS / AUTH schemes. Some servers only allow AUTH in TLS mode. - self.esmtpState_ehlo(code, resp) - - - def authenticate(self, code, resp, items): - if self.secret and items.get('AUTH'): - schemes = items['AUTH'].split() - tmpSchemes = {} - - #XXX: May want to come up with a more efficient way to do this - for s in schemes: - tmpSchemes[s.upper()] = 1 - - for a in self.authenticators: - auth = a.getName().upper() - - if auth in tmpSchemes: - self._authinfo = a - - # Special condition handled - if auth == b"PLAIN": - self._okresponse = self.smtpState_from - self._failresponse = self._esmtpState_plainAuth - self._expected = [235] - challenge = encode_base64( - self._authinfo.challengeResponse(self.secret, 1), - eol=b"") - self.sendLine(b"AUTH %s %s" % (auth, challenge)) - else: - self._expected = [334] - self._okresponse = self.esmtpState_challenge - # If some error occurs here, the server declined the - # AUTH before the user / password phase. This would be - # a very rare case - self._failresponse = self.esmtpAUTHServerError - self.sendLine(b'AUTH ' + auth) - return - - if self.requireAuthentication: - self.esmtpAUTHRequired() - else: - self.smtpState_from(code, resp) - - - def _esmtpState_plainAuth(self, code, resp): - self._okresponse = self.smtpState_from - self._failresponse = self.esmtpAUTHDeclined - self._expected = [235] - challenge = encode_base64(self._authinfo.challengeResponse(self.secret, 2), eol="") - self.sendLine('AUTH PLAIN ' + challenge) - - - def esmtpState_challenge(self, code, resp): - self._authResponse(self._authinfo, resp) - - - def _authResponse(self, auth, challenge): - self._failresponse = self.esmtpAUTHDeclined - try: - challenge = base64.decodestring(challenge) - except binascii.Error: - # Illegal challenge, give up, then quit - self.sendLine('*') - self._okresponse = self.esmtpAUTHMalformedChallenge - self._failresponse = self.esmtpAUTHMalformedChallenge - else: - resp = auth.challengeResponse(self.secret, challenge) - self._expected = [235, 334] - self._okresponse = self.smtpState_maybeAuthenticated - self.sendLine(encode_base64(resp, eol="")) - - - def smtpState_maybeAuthenticated(self, code, resp): - """ - Called to handle the next message from the server after sending a - response to a SASL challenge. The server response might be another - challenge or it might indicate authentication has succeeded. - """ - if code == 235: - # Yes, authenticated! - del self._authinfo - self.smtpState_from(code, resp) - else: - # No, not authenticated yet. Keep trying. - self._authResponse(self._authinfo, resp) - - - -class ESMTP(SMTP): - - ctx = None - canStartTLS = False - startedTLS = False - - authenticated = False - - def __init__(self, chal = None, contextFactory = None): - SMTP.__init__(self) - if chal is None: - chal = {} - self.challengers = chal - self.authenticated = False - self.ctx = contextFactory - - def connectionMade(self): - SMTP.connectionMade(self) - self.canStartTLS = ITLSTransport.providedBy(self.transport) - self.canStartTLS = self.canStartTLS and (self.ctx is not None) - - - def greeting(self): - return SMTP.greeting(self) + ' ESMTP' - - - def extensions(self): - ext = {'AUTH': self.challengers.keys()} - if self.canStartTLS and not self.startedTLS: - ext['STARTTLS'] = None - return ext - - def lookupMethod(self, command): - m = SMTP.lookupMethod(self, command) - if m is None: - m = getattr(self, 'ext_' + command.upper(), None) - return m - - def listExtensions(self): - r = [] - for (c, v) in self.extensions().iteritems(): - if v is not None: - if v: - # Intentionally omit extensions with empty argument lists - r.append('%s %s' % (c, ' '.join(v))) - else: - r.append(c) - return '\n'.join(r) - - def do_EHLO(self, rest): - peer = self.transport.getPeer().host - self._helo = (rest, peer) - self._from = None - self._to = [] - self.sendCode( - 250, - '%s Hello %s, nice to meet you\n%s' % ( - self.host, peer, - self.listExtensions(), - ) - ) - - def ext_STARTTLS(self, rest): - if self.startedTLS: - self.sendCode(503, 'TLS already negotiated') - elif self.ctx and self.canStartTLS: - self.sendCode(220, 'Begin TLS negotiation now') - self.transport.startTLS(self.ctx) - self.startedTLS = True - else: - self.sendCode(454, 'TLS not available') - - def ext_AUTH(self, rest): - if self.authenticated: - self.sendCode(503, 'Already authenticated') - return - parts = rest.split(None, 1) - chal = self.challengers.get(parts[0].upper(), lambda: None)() - if not chal: - self.sendCode(504, 'Unrecognized authentication type') - return - - self.mode = AUTH - self.challenger = chal - - if len(parts) > 1: - chal.getChallenge() # Discard it, apparently the client does not - # care about it. - rest = parts[1] - else: - rest = None - self.state_AUTH(rest) - - - def _cbAuthenticated(self, loginInfo): - """ - Save the state resulting from a successful cred login and mark this - connection as authenticated. - """ - result = SMTP._cbAnonymousAuthentication(self, loginInfo) - self.authenticated = True - return result - - - def _ebAuthenticated(self, reason): - """ - Handle cred login errors by translating them to the SMTP authenticate - failed. Translate all other errors into a generic SMTP error code and - log the failure for inspection. Stop all errors from propagating. - """ - self.challenge = None - if reason.check(cred.error.UnauthorizedLogin): - self.sendCode(535, 'Authentication failed') - else: - log.err(reason, "SMTP authentication failure") - self.sendCode( - 451, - 'Requested action aborted: local error in processing') - - - def state_AUTH(self, response): - """ - Handle one step of challenge/response authentication. - - @param response: The text of a response. If None, this - function has been called as a result of an AUTH command with - no initial response. A response of '*' aborts authentication, - as per RFC 2554. - """ - if self.portal is None: - self.sendCode(454, 'Temporary authentication failure') - self.mode = COMMAND - return - - if response is None: - challenge = self.challenger.getChallenge() - encoded = challenge.encode('base64') - self.sendCode(334, encoded) - return - - if response == '*': - self.sendCode(501, 'Authentication aborted') - self.challenger = None - self.mode = COMMAND - return - - try: - uncoded = response.decode('base64') - except binascii.Error: - self.sendCode(501, 'Syntax error in parameters or arguments') - self.challenger = None - self.mode = COMMAND - return - - self.challenger.setResponse(uncoded) - if self.challenger.moreChallenges(): - challenge = self.challenger.getChallenge() - coded = challenge.encode('base64')[:-1] - self.sendCode(334, coded) - return - - self.mode = COMMAND - result = self.portal.login( - self.challenger, None, - IMessageDeliveryFactory, IMessageDelivery) - result.addCallback(self._cbAuthenticated) - result.addCallback(lambda ign: self.sendCode(235, 'Authentication successful.')) - result.addErrback(self._ebAuthenticated) - - - -class SenderMixin: - """Utility class for sending emails easily. - - Use with SMTPSenderFactory or ESMTPSenderFactory. - """ - done = 0 - - def getMailFrom(self): - if not self.done: - self.done = 1 - return str(self.factory.fromEmail) - else: - return None - - def getMailTo(self): - return self.factory.toEmail - - def getMailData(self): - return self.factory.file - - def sendError(self, exc): - # Call the base class to close the connection with the SMTP server - SMTPClient.sendError(self, exc) - - # Do not retry to connect to SMTP Server if: - # 1. No more retries left (This allows the correct error to be returned to the errorback) - # 2. retry is false - # 3. The error code is not in the 4xx range (Communication Errors) - - if (self.factory.retries >= 0 or - (not exc.retry and not (exc.code >= 400 and exc.code < 500))): - self.factory.sendFinished = True - self.factory.result.errback(exc) - - def sentMail(self, code, resp, numOk, addresses, log): - # Do not retry, the SMTP server acknowledged the request - self.factory.sendFinished = True - if code not in SUCCESS: - errlog = [] - for addr, acode, aresp in addresses: - if acode not in SUCCESS: - errlog.append("%s: %03d %s" % (addr, acode, aresp)) - - errlog.append(log.str()) - - exc = SMTPDeliveryError(code, resp, '\n'.join(errlog), addresses) - self.factory.result.errback(exc) - else: - self.factory.result.callback((numOk, addresses)) - - -class SMTPSender(SenderMixin, SMTPClient): - """ - SMTP protocol that sends a single email based on information it - gets from its factory, a L{SMTPSenderFactory}. - """ - - -class SMTPSenderFactory(protocol.ClientFactory): - """ - Utility factory for sending emails easily. - - @type currentProtocol: L{SMTPSender} - @ivar currentProtocol: The current running protocol returned by - L{buildProtocol}. - - @type sendFinished: C{bool} - @ivar sendFinished: When the value is set to True, it means the message has - been sent or there has been an unrecoverable error or the sending has - been cancelled. The default value is False. - """ - - domain = DNSNAME - protocol = SMTPSender - - def __init__(self, fromEmail, toEmail, file, deferred, retries=5, - timeout=None): - """ - @param fromEmail: The RFC 2821 address from which to send this - message. - - @param toEmail: A sequence of RFC 2821 addresses to which to - send this message. - - @param file: A file-like object containing the message to send. - - @param deferred: A Deferred to callback or errback when sending - of this message completes. - @type deferred: L{defer.Deferred} - - @param retries: The number of times to retry delivery of this - message. - - @param timeout: Period, in seconds, for which to wait for - server responses, or None to wait forever. - """ - assert isinstance(retries, (int, long)) - - if isinstance(toEmail, types.StringTypes): - toEmail = [toEmail] - self.fromEmail = Address(fromEmail) - self.nEmails = len(toEmail) - self.toEmail = toEmail - self.file = file - self.result = deferred - self.result.addBoth(self._removeDeferred) - self.sendFinished = False - self.currentProtocol = None - - self.retries = -retries - self.timeout = timeout - - def _removeDeferred(self, result): - del self.result - return result - - def clientConnectionFailed(self, connector, err): - self._processConnectionError(connector, err) - - def clientConnectionLost(self, connector, err): - self._processConnectionError(connector, err) - - def _processConnectionError(self, connector, err): - self.currentProtocol = None - if (self.retries < 0) and (not self.sendFinished): - log.msg("SMTP Client retrying server. Retry: %s" % -self.retries) - - # Rewind the file in case part of it was read while attempting to - # send the message. - self.file.seek(0, 0) - connector.connect() - self.retries += 1 - elif not self.sendFinished: - # If we were unable to communicate with the SMTP server a ConnectionDone will be - # returned. We want a more clear error message for debugging - if err.check(error.ConnectionDone): - err.value = SMTPConnectError(-1, "Unable to connect to server.") - self.result.errback(err.value) - - def buildProtocol(self, addr): - p = self.protocol(self.domain, self.nEmails*2+2) - p.factory = self - p.timeout = self.timeout - self.currentProtocol = p - self.result.addBoth(self._removeProtocol) - return p - - def _removeProtocol(self, result): - """ - Remove the protocol created in C{buildProtocol}. - - @param result: The result/error passed to the callback/errback of - L{defer.Deferred}. - - @return: The C{result} untouched. - """ - if self.currentProtocol: - self.currentProtocol = None - return result - - - -from twisted.mail.imap4 import IClientAuthentication -from twisted.mail.imap4 import CramMD5ClientAuthenticator, LOGINAuthenticator -from twisted.mail.imap4 import LOGINCredentials as _lcredentials - -class LOGINCredentials(_lcredentials): - """ - L{LOGINCredentials} generates challenges for I{LOGIN} authentication. - - For interoperability with Outlook, the challenge generated does not exactly - match the one defined in the - U{draft specification}. - """ - - def __init__(self): - _lcredentials.__init__(self) - self.challenges = ['Password:', 'Username:'] - - - -class PLAINAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "PLAIN" - - def challengeResponse(self, secret, chal=1): - if chal == 1: - return "%s\0%s\0%s" % (self.user, self.user, secret) - else: - return "%s\0%s" % (self.user, secret) - - - -class ESMTPSender(SenderMixin, ESMTPClient): - - requireAuthentication = True - requireTransportSecurity = True - - def __init__(self, username, secret, contextFactory=None, *args, **kw): - self.heloFallback = 0 - self.username = username - - if contextFactory is None: - contextFactory = self._getContextFactory() - - ESMTPClient.__init__(self, secret, contextFactory, *args, **kw) - - self._registerAuthenticators() - - def _registerAuthenticators(self): - # Register Authenticator in order from most secure to least secure - self.registerAuthenticator(CramMD5ClientAuthenticator(self.username)) - self.registerAuthenticator(LOGINAuthenticator(self.username)) - self.registerAuthenticator(PLAINAuthenticator(self.username)) - - def _getContextFactory(self): - if self.context is not None: - return self.context - try: - from twisted.internet import ssl - except ImportError: - return None - else: - try: - context = ssl.ClientContextFactory() - context.method = ssl.SSL.TLSv1_METHOD - return context - except AttributeError: - return None - - - -class ESMTPSenderFactory(SMTPSenderFactory): - """ - Utility factory for sending emails easily. - - @type currentProtocol: L{ESMTPSender} - @ivar currentProtocol: The current running protocol as made by - L{buildProtocol}. - """ - protocol = ESMTPSender - - def __init__(self, username, password, fromEmail, toEmail, file, - deferred, retries=5, timeout=None, - contextFactory=None, heloFallback=False, - requireAuthentication=True, - requireTransportSecurity=True): - - SMTPSenderFactory.__init__(self, fromEmail, toEmail, file, deferred, retries, timeout) - self.username = username - self.password = password - self._contextFactory = contextFactory - self._heloFallback = heloFallback - self._requireAuthentication = requireAuthentication - self._requireTransportSecurity = requireTransportSecurity - - - def buildProtocol(self, addr): - """ - Build an L{ESMTPSender} protocol configured with C{heloFallback}, - C{requireAuthentication}, and C{requireTransportSecurity} as specified - in L{__init__}. - - This sets L{currentProtocol} on the factory, as well as returning it. - - @rtype: L{ESMTPSender} - """ - p = self.protocol(self.username, self.password, self._contextFactory, - self.domain, self.nEmails*2+2) - p.heloFallback = self._heloFallback - p.requireAuthentication = self._requireAuthentication - p.requireTransportSecurity = self._requireTransportSecurity - p.factory = self - p.timeout = self.timeout - self.currentProtocol = p - self.result.addBoth(self._removeProtocol) - return p - - - -def sendmail(smtphost, from_addr, to_addrs, msg, senderDomainName=None, port=25, - reactor=reactor, username=None, password=None, - requireAuthentication=False, requireTransportSecurity=False): - """ - Send an email. - - This interface is intended to be a replacement for L{smtplib.SMTP.sendmail} - and related methods. To maintain backwards compatibility, it will fall back - to plain SMTP, if ESMTP support is not available. If ESMTP support is - available, it will attempt to provide encryption via STARTTLS and - authentication if a secret is provided. - - @param smtphost: The host the message should be sent to. - @type smtphost: L{bytes} - - @param from_addr: The (envelope) address sending this mail. - @type from_addr: L{bytes} - - @param to_addrs: A list of addresses to send this mail to. A string will - be treated as a list of one address. - @type to_addr: L{list} of L{bytes} or L{bytes} - - @param msg: The message, including headers, either as a file or a string. - File-like objects need to support read() and close(). Lines must be - delimited by '\\n'. If you pass something that doesn't look like a file, - we try to convert it to a string (so you should be able to pass an - L{email.Message} directly, but doing the conversion with - L{email.Generator} manually will give you more control over the process). - - @param senderDomainName: Name by which to identify. If None, try to pick - something sane (but this depends on external configuration and may not - succeed). - @type senderDomainName: L{bytes} - - @param port: Remote port to which to connect. - @type port: L{int} - - @param username: The username to use, if wanting to authenticate. - @type username: L{bytes} - - @param password: The secret to use, if wanting to authenticate. If you do - not specify this, SMTP authentication will not occur. - @type password: L{bytes} - - @param requireTransportSecurity: Whether or not STARTTLS is required. - @type requireTransportSecurity: L{bool} - - @param requireAuthentication: Whether or not authentication is required. - @type requireAuthentication: L{bool} - - @param reactor: The L{reactor} used to make the TCP connection. - - @rtype: L{Deferred} - @returns: A cancellable L{Deferred}, its callback will be called if a - message is sent to ANY address, the errback if no message is sent. When - the C{cancel} method is called, it will stop retrying and disconnect - the connection immediately. - - The callback will be called with a tuple (numOk, addresses) where numOk - is the number of successful recipient addresses and addresses is a list - of tuples (address, code, resp) giving the response to the RCPT command - for each address. - """ - if not hasattr(msg, 'read'): - # It's not a file - msg = StringIO(str(msg)) - - def cancel(d): - """ - Cancel the L{twisted.mail.smtp.sendmail} call, tell the factory not to - retry and disconnect the connection. - - @param d: The L{defer.Deferred} to be cancelled. - """ - factory.sendFinished = True - if factory.currentProtocol: - factory.currentProtocol.transport.abortConnection() - else: - # Connection hasn't been made yet - connector.disconnect() - - d = defer.Deferred(cancel) - factory = ESMTPSenderFactory(username, password, from_addr, to_addrs, msg, - d, heloFallback=True, requireAuthentication=requireAuthentication, - requireTransportSecurity=requireTransportSecurity) - - if senderDomainName is not None: - factory.domain = senderDomainName - - connector = reactor.connectTCP(smtphost, port, factory) - - return d - - - -## -## Yerg. Codecs! -## -import codecs -def xtext_encode(s, errors=None): - r = [] - for ch in s: - o = ord(ch) - if ch == '+' or ch == '=' or o < 33 or o > 126: - r.append('+%02X' % o) - else: - r.append(chr(o)) - return (''.join(r), len(s)) - - -def xtext_decode(s, errors=None): - """ - Decode the xtext-encoded string C{s}. - """ - r = [] - i = 0 - while i < len(s): - if s[i] == '+': - try: - r.append(chr(int(s[i + 1:i + 3], 16))) - except ValueError: - r.append(s[i:i + 3]) - i += 3 - else: - r.append(s[i]) - i += 1 - return (''.join(r), len(s)) - -class xtextStreamReader(codecs.StreamReader): - def decode(self, s, errors='strict'): - return xtext_decode(s) - -class xtextStreamWriter(codecs.StreamWriter): - def decode(self, s, errors='strict'): - return xtext_encode(s) - -def xtext_codec(name): - if name == 'xtext': - return (xtext_encode, xtext_decode, xtextStreamReader, xtextStreamWriter) -codecs.register(xtext_codec) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/tap.py deleted file mode 100644 index 677cd74..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/tap.py +++ /dev/null @@ -1,467 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_options -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support for creating mail servers with twistd. -""" - -import os -import warnings - -from twisted.mail import mail -from twisted.mail import maildir -from twisted.mail import relay -from twisted.mail import relaymanager -from twisted.mail import alias - -from twisted.internet import endpoints - -from twisted.python import usage - -from twisted.cred import checkers -from twisted.cred import strcred - -from twisted.application import internet - - -class Options(usage.Options, strcred.AuthOptionMixin): - """ - An options list parser for twistd mail. - - @type synopsis: L{bytes} - @ivar synopsis: A description of options for use in the usage message. - - @type optParameters: L{list} of L{list} of (0) L{bytes}, (1) L{bytes}, - (2) L{object}, (3) L{bytes}, (4) L{NoneType } or - callable which takes L{bytes} and returns L{object} - @ivar optParameters: Information about supported parameters. See - L{Options } for details. - - @type optFlags: L{list} of L{list} of (0) L{bytes}, (1) L{bytes} or - L{NoneType }, (2) L{bytes} - @ivar optFlags: Information about supported flags. See - L{Options } for details. - - @type _protoDefaults: L{dict} mapping L{bytes} to L{int} - @ivar _protoDefaults: A mapping of default service to port. - - @type compData: L{Completions } - @ivar compData: Metadata for the shell tab completion system. - - @type longdesc: L{bytes} - @ivar longdesc: A long description of the plugin for use in the usage - message. - - @type service: L{MailService} - @ivar service: The email service. - - @type last_domain: L{IDomain} provider or L{NoneType } - @ivar last_domain: The most recently specified domain. - """ - synopsis = "[options]" - - optParameters = [ - ["pop3s", "S", 0, - "Port to start the POP3-over-SSL server on (0 to disable). " - "DEPRECATED: use " - "'--pop3 ssl:port:privateKey=pkey.pem:certKey=cert.pem'"], - - ["certificate", "c", None, - "Certificate file to use for SSL connections. " - "DEPRECATED: use " - "'--pop3 ssl:port:privateKey=pkey.pem:certKey=cert.pem'"], - - ["relay", "R", None, - "Relay messages according to their envelope 'To', using " - "the given path as a queue directory."], - - ["hostname", "H", None, - "The hostname by which to identify this server."], - ] - - optFlags = [ - ["esmtp", "E", "Use RFC 1425/1869 SMTP extensions"], - ["disable-anonymous", None, - "Disallow non-authenticated SMTP connections"], - ["no-pop3", None, "Disable the default POP3 server."], - ["no-smtp", None, "Disable the default SMTP server."], - ] - - _protoDefaults = { - "pop3": 8110, - "smtp": 8025, - } - - compData = usage.Completions( - optActions={"hostname" : usage.CompleteHostnames(), - "certificate" : usage.CompleteFiles("*.pem")} - ) - - longdesc = """ - An SMTP / POP3 email server plugin for twistd. - - Examples: - - 1. SMTP and POP server - - twistd mail --maildirdbmdomain=example.com=/tmp/example.com - --user=joe=password - - Starts an SMTP server that only accepts emails to joe@example.com and saves - them to /tmp/example.com. - - Also starts a POP mail server which will allow a client to log in using - username: joe@example.com and password: password and collect any email that - has been saved in /tmp/example.com. - - 2. SMTP relay - - twistd mail --relay=/tmp/mail_queue - - Starts an SMTP server that accepts emails to any email address and relays - them to an appropriate remote SMTP server. Queued emails will be - temporarily stored in /tmp/mail_queue. - """ - - def __init__(self): - """ - Parse options and create a mail service. - """ - usage.Options.__init__(self) - self.service = mail.MailService() - self.last_domain = None - for service in self._protoDefaults: - self[service] = [] - - - def addEndpoint(self, service, description, certificate=None): - """ - Add an endpoint to a service. - - @type service: L{bytes} - @param service: A service, either C{b'smtp'} or C{b'pop3'}. - - @type description: L{bytes} - @param description: An endpoint description string or a TCP port - number. - - @type certificate: L{bytes} or L{NoneType } - @param certificate: The name of a file containing an SSL certificate. - """ - self[service].append( - _toEndpoint(description, certificate=certificate)) - - - def opt_pop3(self, description): - """ - Add a POP3 port listener on the specified endpoint. - - You can listen on multiple ports by specifying multiple --pop3 options. - For backwards compatibility, a bare TCP port number can be specified, - but this is deprecated. [SSL Example: ssl:8995:privateKey=mycert.pem] - [default: tcp:8110] - """ - self.addEndpoint('pop3', description) - opt_p = opt_pop3 - - - def opt_smtp(self, description): - """ - Add an SMTP port listener on the specified endpoint. - - You can listen on multiple ports by specifying multiple --smtp options. - For backwards compatibility, a bare TCP port number can be specified, - but this is deprecated. [SSL Example: ssl:8465:privateKey=mycert.pem] - [default: tcp:8025] - """ - self.addEndpoint('smtp', description) - opt_s = opt_smtp - - - def opt_default(self): - """ - Make the most recently specified domain the default domain. - """ - if self.last_domain: - self.service.addDomain('', self.last_domain) - else: - raise usage.UsageError("Specify a domain before specifying using --default") - opt_D = opt_default - - - def opt_maildirdbmdomain(self, domain): - """ - Generate an SMTP/POP3 virtual domain. - - This option requires an argument of the form 'NAME=PATH' where NAME is - the DNS domain name for which email will be accepted and where PATH is - a the filesystem path to a Maildir folder. - [Example: 'example.com=/tmp/example.com'] - """ - try: - name, path = domain.split('=') - except ValueError: - raise usage.UsageError("Argument to --maildirdbmdomain must be of the form 'name=path'") - - self.last_domain = maildir.MaildirDirdbmDomain(self.service, os.path.abspath(path)) - self.service.addDomain(name, self.last_domain) - opt_d = opt_maildirdbmdomain - - def opt_user(self, user_pass): - """ - Add a user and password to the last specified domain. - """ - try: - user, password = user_pass.split('=', 1) - except ValueError: - raise usage.UsageError("Argument to --user must be of the form 'user=password'") - if self.last_domain: - self.last_domain.addUser(user, password) - else: - raise usage.UsageError("Specify a domain before specifying users") - opt_u = opt_user - - - def opt_bounce_to_postmaster(self): - """ - Send undeliverable messages to the postmaster. - """ - self.last_domain.postmaster = 1 - opt_b = opt_bounce_to_postmaster - - - def opt_aliases(self, filename): - """ - Specify an aliases(5) file to use for the last specified domain. - """ - if self.last_domain is not None: - if mail.IAliasableDomain.providedBy(self.last_domain): - aliases = alias.loadAliasFile(self.service.domains, filename) - self.last_domain.setAliasGroup(aliases) - self.service.monitor.monitorFile( - filename, - AliasUpdater(self.service.domains, self.last_domain) - ) - else: - raise usage.UsageError( - "%s does not support alias files" % ( - self.last_domain.__class__.__name__, - ) - ) - else: - raise usage.UsageError("Specify a domain before specifying aliases") - opt_A = opt_aliases - - - def _getEndpoints(self, reactor, service): - """ - Return a list of endpoints for the specified service, constructing - defaults if necessary. - - If no endpoints were configured for the service and the protocol - was not explicitly disabled with a I{--no-*} option, a default - endpoint for the service is created. - - @type reactor: L{IReactorTCP } - provider - @param reactor: If any endpoints are created, the reactor with - which they are created. - - @type service: L{bytes} - @param service: The type of service for which to retrieve endpoints, - either C{b'pop3'} or C{b'smtp'}. - - @rtype: L{list} of L{IStreamServerEndpoint - } provider - @return: The endpoints for the specified service as configured by the - command line parameters. - """ - if service == 'pop3' and self['pop3s'] and len(self[service]) == 1: - # The single endpoint here is the POP3S service we added in - # postOptions. Include the default endpoint alongside it. - return self[service] + [ - endpoints.TCP4ServerEndpoint( - reactor, self._protoDefaults[service])] - elif self[service]: - # For any non-POP3S case, if there are any services set up, just - # return those. - return self[service] - elif self['no-' + service]: - # If there are no services, but the service was explicitly disabled, - # return nothing. - return [] - else: - # Otherwise, return the old default service. - return [ - endpoints.TCP4ServerEndpoint( - reactor, self._protoDefaults[service])] - - - def postOptions(self): - """ - Check the validity of the specified set of options and - configure authentication. - - @raise UsageError: When the set of options is invalid. - """ - from twisted.internet import reactor - - if self['pop3s']: - if not self['certificate']: - raise usage.UsageError("Cannot specify --pop3s without " - "--certificate") - elif not os.path.exists(self['certificate']): - raise usage.UsageError("Certificate file %r does not exist." - % self['certificate']) - else: - self.addEndpoint( - 'pop3', self['pop3s'], certificate=self['certificate']) - - if self['esmtp'] and self['hostname'] is None: - raise usage.UsageError("--esmtp requires --hostname") - - # If the --auth option was passed, this will be present -- otherwise, - # it won't be, which is also a perfectly valid state. - if 'credCheckers' in self: - for ch in self['credCheckers']: - self.service.smtpPortal.registerChecker(ch) - - if not self['disable-anonymous']: - self.service.smtpPortal.registerChecker(checkers.AllowAnonymousAccess()) - - anything = False - for service in self._protoDefaults: - self[service] = self._getEndpoints(reactor, service) - if self[service]: - anything = True - - if not anything: - raise usage.UsageError("You cannot disable all protocols") - - - -class AliasUpdater: - """ - A callable object which updates the aliases for a domain from an aliases(5) - file. - - @ivar domains: See L{__init__}. - @ivar domain: See L{__init__}. - """ - def __init__(self, domains, domain): - """ - @type domains: L{dict} mapping L{bytes} to L{IDomain} provider - @param domains: A mapping of domain name to domain object - - @type domain: L{IAliasableDomain} provider - @param domain: The domain to update. - """ - self.domains = domains - self.domain = domain - - - def __call__(self, new): - """ - Update the aliases for a domain from an aliases(5) file. - - @type new: L{bytes} - @param new: The name of an aliases(5) file. - """ - self.domain.setAliasGroup(alias.loadAliasFile(self.domains, new)) - - - -def _toEndpoint(description, certificate=None): - """ - Create an endpoint based on a description. - - @type description: L{bytes} - @param description: An endpoint description string or a TCP port - number. - - @type certificate: L{bytes} or L{NoneType } - @param certificate: The name of a file containing an SSL certificate. - - @rtype: L{IStreamServerEndpoint - } provider - @return: An endpoint. - """ - from twisted.internet import reactor - try: - port = int(description) - except ValueError: - return endpoints.serverFromString(reactor, description) - - warnings.warn( - "Specifying plain ports and/or a certificate is deprecated since " - "Twisted 11.0; use endpoint descriptions instead.", - category=DeprecationWarning, stacklevel=3) - - if certificate: - from twisted.internet.ssl import DefaultOpenSSLContextFactory - ctx = DefaultOpenSSLContextFactory(certificate, certificate) - return endpoints.SSL4ServerEndpoint(reactor, port, ctx) - return endpoints.TCP4ServerEndpoint(reactor, port) - - - -def makeService(config): - """ - Configure a service for operating a mail server. - - The returned service may include POP3 servers, SMTP servers, or both, - depending on the configuration passed in. If there are multiple servers, - they will share all of their non-network state (i.e. the same user accounts - are available on all of them). - - @type config: L{Options } - @param config: Configuration options specifying which servers to include in - the returned service and where they should keep mail data. - - @rtype: L{IService } provider - @return: A service which contains the requested mail servers. - """ - if config['esmtp']: - rmType = relaymanager.SmartHostESMTPRelayingManager - smtpFactory = config.service.getESMTPFactory - else: - rmType = relaymanager.SmartHostSMTPRelayingManager - smtpFactory = config.service.getSMTPFactory - - if config['relay']: - dir = config['relay'] - if not os.path.isdir(dir): - os.mkdir(dir) - - config.service.setQueue(relaymanager.Queue(dir)) - default = relay.DomainQueuer(config.service) - - manager = rmType(config.service.queue) - if config['esmtp']: - manager.fArgs += (None, None) - manager.fArgs += (config['hostname'],) - - helper = relaymanager.RelayStateHelper(manager, 1) - helper.setServiceParent(config.service) - config.service.domains.setDefaultDomain(default) - - if config['pop3']: - f = config.service.getPOP3Factory() - for endpoint in config['pop3']: - svc = internet.StreamServerEndpointService(endpoint, f) - svc.setServiceParent(config.service) - - if config['smtp']: - f = smtpFactory() - if config['hostname']: - f.domain = config['hostname'] - f.fArgs = (f.domain,) - if config['esmtp']: - f.fArgs = (None, None) + f.fArgs - for endpoint in config['smtp']: - svc = internet.StreamServerEndpointService(endpoint, f) - svc.setServiceParent(config.service) - - return config.service diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/__init__.py deleted file mode 100644 index f8ec705..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"Tests for twistd.mail" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/pop3testserver.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/pop3testserver.py deleted file mode 100644 index fd85821..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/pop3testserver.py +++ /dev/null @@ -1,314 +0,0 @@ -#!/usr/bin/env python -# -*- test-case-name: twisted.mail.test.test_pop3client -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.internet.protocol import Factory -from twisted.protocols import basic -from twisted.internet import reactor -import sys - -USER = "test" -PASS = "twisted" - -PORT = 1100 - -SSL_SUPPORT = True -UIDL_SUPPORT = True -INVALID_SERVER_RESPONSE = False -INVALID_CAPABILITY_RESPONSE = False -INVALID_LOGIN_RESPONSE = False -DENY_CONNECTION = False -DROP_CONNECTION = False -BAD_TLS_RESPONSE = False -TIMEOUT_RESPONSE = False -TIMEOUT_DEFERRED = False -SLOW_GREETING = False - -"""Commands""" -CONNECTION_MADE = "+OK POP3 localhost v2003.83 server ready" - -CAPABILITIES = [ -"TOP", -"LOGIN-DELAY 180", -"USER", -"SASL LOGIN" -] - -CAPABILITIES_SSL = "STLS" -CAPABILITIES_UIDL = "UIDL" - - -INVALID_RESPONSE = "-ERR Unknown request" -VALID_RESPONSE = "+OK Command Completed" -AUTH_DECLINED = "-ERR LOGIN failed" -AUTH_ACCEPTED = "+OK Mailbox open, 0 messages" -TLS_ERROR = "-ERR server side error start TLS handshake" -LOGOUT_COMPLETE = "+OK quit completed" -NOT_LOGGED_IN = "-ERR Unknown AUHORIZATION state command" -STAT = "+OK 0 0" -UIDL = "+OK Unique-ID listing follows\r\n." -LIST = "+OK Mailbox scan listing follows\r\n." -CAP_START = "+OK Capability list follows:" - - -class POP3TestServer(basic.LineReceiver): - def __init__(self, contextFactory = None): - self.loggedIn = False - self.caps = None - self.tmpUser = None - self.ctx = contextFactory - - def sendSTATResp(self, req): - self.sendLine(STAT) - - def sendUIDLResp(self, req): - self.sendLine(UIDL) - - def sendLISTResp(self, req): - self.sendLine(LIST) - - def sendCapabilities(self): - if self.caps is None: - self.caps = [CAP_START] - - if UIDL_SUPPORT: - self.caps.append(CAPABILITIES_UIDL) - - if SSL_SUPPORT: - self.caps.append(CAPABILITIES_SSL) - - for cap in CAPABILITIES: - self.caps.append(cap) - resp = '\r\n'.join(self.caps) - resp += "\r\n." - - self.sendLine(resp) - - - def connectionMade(self): - if DENY_CONNECTION: - self.disconnect() - return - - if SLOW_GREETING: - reactor.callLater(20, self.sendGreeting) - - else: - self.sendGreeting() - - def sendGreeting(self): - self.sendLine(CONNECTION_MADE) - - def lineReceived(self, line): - """Error Conditions""" - - uline = line.upper() - find = lambda s: uline.find(s) != -1 - - if TIMEOUT_RESPONSE: - # Do not respond to clients request - return - - if DROP_CONNECTION: - self.disconnect() - return - - elif find("CAPA"): - if INVALID_CAPABILITY_RESPONSE: - self.sendLine(INVALID_RESPONSE) - else: - self.sendCapabilities() - - elif find("STLS") and SSL_SUPPORT: - self.startTLS() - - elif find("USER"): - if INVALID_LOGIN_RESPONSE: - self.sendLine(INVALID_RESPONSE) - return - - resp = None - try: - self.tmpUser = line.split(" ")[1] - resp = VALID_RESPONSE - except: - resp = AUTH_DECLINED - - self.sendLine(resp) - - elif find("PASS"): - resp = None - try: - pwd = line.split(" ")[1] - - if self.tmpUser is None or pwd is None: - resp = AUTH_DECLINED - elif self.tmpUser == USER and pwd == PASS: - resp = AUTH_ACCEPTED - self.loggedIn = True - else: - resp = AUTH_DECLINED - except: - resp = AUTH_DECLINED - - self.sendLine(resp) - - elif find("QUIT"): - self.loggedIn = False - self.sendLine(LOGOUT_COMPLETE) - self.disconnect() - - elif INVALID_SERVER_RESPONSE: - self.sendLine(INVALID_RESPONSE) - - elif not self.loggedIn: - self.sendLine(NOT_LOGGED_IN) - - elif find("NOOP"): - self.sendLine(VALID_RESPONSE) - - elif find("STAT"): - if TIMEOUT_DEFERRED: - return - self.sendLine(STAT) - - elif find("LIST"): - if TIMEOUT_DEFERRED: - return - self.sendLine(LIST) - - elif find("UIDL"): - if TIMEOUT_DEFERRED: - return - elif not UIDL_SUPPORT: - self.sendLine(INVALID_RESPONSE) - return - - self.sendLine(UIDL) - - def startTLS(self): - if self.ctx is None: - self.getContext() - - if SSL_SUPPORT and self.ctx is not None: - self.sendLine('+OK Begin TLS negotiation now') - self.transport.startTLS(self.ctx) - else: - self.sendLine('-ERR TLS not available') - - def disconnect(self): - self.transport.loseConnection() - - def getContext(self): - try: - from twisted.internet import ssl - except ImportError: - self.ctx = None - else: - self.ctx = ssl.ClientContextFactory() - self.ctx.method = ssl.SSL.TLSv1_METHOD - - -usage = """popServer.py [arg] (default is Standard POP Server with no messages) -no_ssl - Start with no SSL support -no_uidl - Start with no UIDL support -bad_resp - Send a non-RFC compliant response to the Client -bad_cap_resp - send a non-RFC compliant response when the Client sends a 'CAPABILITY' request -bad_login_resp - send a non-RFC compliant response when the Client sends a 'LOGIN' request -deny - Deny the connection -drop - Drop the connection after sending the greeting -bad_tls - Send a bad response to a STARTTLS -timeout - Do not return a response to a Client request -to_deferred - Do not return a response on a 'Select' request. This - will test Deferred callback handling -slow - Wait 20 seconds after the connection is made to return a Server Greeting -""" - -def printMessage(msg): - print "Server Starting in %s mode" % msg - -def processArg(arg): - - if arg.lower() == 'no_ssl': - global SSL_SUPPORT - SSL_SUPPORT = False - printMessage("NON-SSL") - - elif arg.lower() == 'no_uidl': - global UIDL_SUPPORT - UIDL_SUPPORT = False - printMessage("NON-UIDL") - - elif arg.lower() == 'bad_resp': - global INVALID_SERVER_RESPONSE - INVALID_SERVER_RESPONSE = True - printMessage("Invalid Server Response") - - elif arg.lower() == 'bad_cap_resp': - global INVALID_CAPABILITY_RESPONSE - INVALID_CAPABILITY_RESPONSE = True - printMessage("Invalid Capability Response") - - elif arg.lower() == 'bad_login_resp': - global INVALID_LOGIN_RESPONSE - INVALID_LOGIN_RESPONSE = True - printMessage("Invalid Capability Response") - - elif arg.lower() == 'deny': - global DENY_CONNECTION - DENY_CONNECTION = True - printMessage("Deny Connection") - - elif arg.lower() == 'drop': - global DROP_CONNECTION - DROP_CONNECTION = True - printMessage("Drop Connection") - - - elif arg.lower() == 'bad_tls': - global BAD_TLS_RESPONSE - BAD_TLS_RESPONSE = True - printMessage("Bad TLS Response") - - elif arg.lower() == 'timeout': - global TIMEOUT_RESPONSE - TIMEOUT_RESPONSE = True - printMessage("Timeout Response") - - elif arg.lower() == 'to_deferred': - global TIMEOUT_DEFERRED - TIMEOUT_DEFERRED = True - printMessage("Timeout Deferred Response") - - elif arg.lower() == 'slow': - global SLOW_GREETING - SLOW_GREETING = True - printMessage("Slow Greeting") - - elif arg.lower() == '--help': - print usage - sys.exit() - - else: - print usage - sys.exit() - -def main(): - - if len(sys.argv) < 2: - printMessage("POP3 with no messages") - else: - args = sys.argv[1:] - - for arg in args: - processArg(arg) - - f = Factory() - f.protocol = POP3TestServer - reactor.listenTCP(PORT, f) - reactor.run() - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/rfc822.message b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/rfc822.message deleted file mode 100644 index ee97ab9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/rfc822.message +++ /dev/null @@ -1,86 +0,0 @@ -Return-Path: -Delivered-To: exarkun@meson.dyndns.org -Received: from localhost [127.0.0.1] - by localhost with POP3 (fetchmail-6.2.1) - for exarkun@localhost (single-drop); Thu, 20 Mar 2003 14:50:20 -0500 (EST) -Received: from pyramid.twistedmatrix.com (adsl-64-123-27-105.dsl.austtx.swbell.net [64.123.27.105]) - by intarweb.us (Postfix) with ESMTP id 4A4A513EA4 - for ; Thu, 20 Mar 2003 14:49:27 -0500 (EST) -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18w648-0007Vl-00; Thu, 20 Mar 2003 13:51:04 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18w63j-0007VK-00 - for ; Thu, 20 Mar 2003 13:50:39 -0600 -To: twisted-commits@twistedmatrix.com -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -Message-Id: -Subject: [Twisted-commits] rebuild now works on python versions from 2.2.0 and up. -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Thu, 20 Mar 2003 13:50:39 -0600 - -Modified files: -Twisted/twisted/python/rebuild.py 1.19 1.20 - -Log message: -rebuild now works on python versions from 2.2.0 and up. - - -ViewCVS links: -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/twisted/python/rebuild.py.diff?r1=text&tr1=1.19&r2=text&tr2=1.20&cvsroot=Twisted - -Index: Twisted/twisted/python/rebuild.py -diff -u Twisted/twisted/python/rebuild.py:1.19 Twisted/twisted/python/rebuild.py:1.20 ---- Twisted/twisted/python/rebuild.py:1.19 Fri Jan 17 13:50:49 2003 -+++ Twisted/twisted/python/rebuild.py Thu Mar 20 11:50:08 2003 -@@ -206,15 +206,27 @@ - clazz.__dict__.clear() - clazz.__getattr__ = __getattr__ - clazz.__module__ = module.__name__ -+ if newclasses: -+ import gc -+ if (2, 2, 0) <= sys.version_info[:3] < (2, 2, 2): -+ hasBrokenRebuild = 1 -+ gc_objects = gc.get_objects() -+ else: -+ hasBrokenRebuild = 0 - for nclass in newclasses: - ga = getattr(module, nclass.__name__) - if ga is nclass: - log.msg("WARNING: new-class %s not replaced by reload!" % reflect.qual(nclass)) - else: -- import gc -- for r in gc.get_referrers(nclass): -- if isinstance(r, nclass): -+ if hasBrokenRebuild: -+ for r in gc_objects: -+ if not getattr(r, '__class__', None) is nclass: -+ continue - r.__class__ = ga -+ else: -+ for r in gc.get_referrers(nclass): -+ if getattr(r, '__class__', None) is nclass: -+ r.__class__ = ga - if doLog: - log.msg('') - log.msg(' (fixing %s): ' % str(module.__name__)) - - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/server.pem b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/server.pem deleted file mode 100644 index 80ef9dc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzEL -MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhv -c3QxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEB -BQADSwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh -5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQC -MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl -MB0GA1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7 -hyNp65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoT -CE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlw -dG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3Qx -LmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6 -BoJuVwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++ -7QGG/g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JE -WUQ9Ho4EzbYCOQ== ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIBPAIBAAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh -5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAQJBAIqm/bz4NA1H++Vx5Ewx -OcKp3w19QSaZAwlGRtsUxrP7436QjnREM3Bm8ygU11BjkPVmtrKm6AayQfCHqJoT -ZIECIQDW0BoMoL0HOYM/mrTLhaykYAVqgIeJsPjvkEhTFXWBuQIhAM3deFAvWNu4 -nklUQ37XsCT2c9tmNt1LAT+slG2JOTTRAiAuXDtC/m3NYVwyHfFm+zKHRzHkClk2 -HjubeEgjpj32AQIhAJqMGTaZVOwevTXvvHwNEH+vRWsAYU/gbx+OQB+7VOcBAiEA -oolb6NMg/R3enNPvS1O4UU1H8wpaF77L4yiSWlE0p4w= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE REQUEST----- -MIIBDTCBuAIBADBTMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xEjAQ -BgNVBAMTCWxvY2FsaG9zdDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20w -XDANBgkqhkiG9w0BAQEFAANLADBIAkEArL57d26W9fNXvOhNlZzlPOACmvwOZ5Ad -NgLzJ1/MfsQQJ7hHVeHmTAjM664V+fXvwUGJLziCeBo1ysWLRnl8CQIDAQABoAAw -DQYJKoZIhvcNAQEEBQADQQA7uqbrNTjVWpF6By5ZNPvhZ4YdFgkeXFVWi5ao/TaP -Vq4BG021fJ9nlHRtr4rotpgHDX1rr+iWeHKsx4+5DRSy ------END CERTIFICATE REQUEST----- diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_bounce.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_bounce.py deleted file mode 100644 index e607d6e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_bounce.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Test cases for bounce message generation -""" - -from twisted.trial import unittest -from twisted.mail import bounce -import rfc822, cStringIO - -class BounceTests(unittest.TestCase): - """ - testcases for bounce message generation - """ - - def testBounceFormat(self): - from_, to, s = bounce.generateBounce(cStringIO.StringIO('''\ -From: Moshe Zadka -To: nonexistent@example.org -Subject: test - -'''), 'moshez@example.com', 'nonexistent@example.org') - self.assertEqual(from_, '') - self.assertEqual(to, 'moshez@example.com') - mess = rfc822.Message(cStringIO.StringIO(s)) - self.assertEqual(mess['To'], 'moshez@example.com') - self.assertEqual(mess['From'], 'postmaster@example.org') - self.assertEqual(mess['subject'], 'Returned Mail: see transcript for details') - - def testBounceMIME(self): - pass diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_imap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_imap.py deleted file mode 100644 index 0183c23..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_imap.py +++ /dev/null @@ -1,5028 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_imap -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test case for twisted.mail.imap4 -""" - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -import codecs -import locale -import os -import types - -from zope.interface import implements - -from twisted.python.filepath import FilePath -from twisted.mail.imap4 import MessageSet -from twisted.mail import imap4 -from twisted.protocols import loopback -from twisted.internet import defer -from twisted.internet import error -from twisted.internet import reactor -from twisted.internet import interfaces -from twisted.internet.task import Clock -from twisted.trial import unittest -from twisted.python import util, log -from twisted.python import failure - -from twisted.cred.portal import Portal -from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse -from twisted.cred.error import UnauthorizedLogin -from twisted.cred.credentials import ( - IUsernameHashedPassword, IUsernamePassword, CramMD5Credentials) - -from twisted.test.proto_helpers import StringTransport, StringTransportWithDisconnection - -try: - from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext -except ImportError: - ClientTLSContext = ServerTLSContext = None - -def strip(f): - return lambda result, f=f: f() - -def sortNest(l): - l = l[:] - l.sort() - for i in range(len(l)): - if isinstance(l[i], types.ListType): - l[i] = sortNest(l[i]) - elif isinstance(l[i], types.TupleType): - l[i] = tuple(sortNest(list(l[i]))) - return l - -class IMAP4UTF7Tests(unittest.TestCase): - tests = [ - [u'Hello world', 'Hello world'], - [u'Hello & world', 'Hello &- world'], - [u'Hello\xffworld', 'Hello&AP8-world'], - [u'\xff\xfe\xfd\xfc', '&AP8A,gD9APw-'], - [u'~peter/mail/\u65e5\u672c\u8a9e/\u53f0\u5317', - '~peter/mail/&ZeVnLIqe-/&U,BTFw-'], # example from RFC 2060 - ] - - def test_encodeWithErrors(self): - """ - Specifying an error policy to C{unicode.encode} with the - I{imap4-utf-7} codec should produce the same result as not - specifying the error policy. - """ - text = u'Hello world' - self.assertEqual( - text.encode('imap4-utf-7', 'strict'), - text.encode('imap4-utf-7')) - - - def test_decodeWithErrors(self): - """ - Similar to L{test_encodeWithErrors}, but for C{str.decode}. - """ - bytes = 'Hello world' - self.assertEqual( - bytes.decode('imap4-utf-7', 'strict'), - bytes.decode('imap4-utf-7')) - - - def test_getreader(self): - """ - C{codecs.getreader('imap4-utf-7')} returns the I{imap4-utf-7} stream - reader class. - """ - reader = codecs.getreader('imap4-utf-7')(StringIO('Hello&AP8-world')) - self.assertEqual(reader.read(), u'Hello\xffworld') - - - def test_getwriter(self): - """ - C{codecs.getwriter('imap4-utf-7')} returns the I{imap4-utf-7} stream - writer class. - """ - output = StringIO() - writer = codecs.getwriter('imap4-utf-7')(output) - writer.write(u'Hello\xffworld') - self.assertEqual(output.getvalue(), 'Hello&AP8-world') - - - def test_encode(self): - """ - The I{imap4-utf-7} can be used to encode a unicode string into a byte - string according to the IMAP4 modified UTF-7 encoding rules. - """ - for (input, output) in self.tests: - self.assertEqual(input.encode('imap4-utf-7'), output) - - - def test_decode(self): - """ - The I{imap4-utf-7} can be used to decode a byte string into a unicode - string according to the IMAP4 modified UTF-7 encoding rules. - """ - for (input, output) in self.tests: - self.assertEqual(input, output.decode('imap4-utf-7')) - - - def test_printableSingletons(self): - """ - The IMAP4 modified UTF-7 implementation encodes all printable - characters which are in ASCII using the corresponding ASCII byte. - """ - # All printables represent themselves - for o in range(0x20, 0x26) + range(0x27, 0x7f): - self.assertEqual(chr(o), chr(o).encode('imap4-utf-7')) - self.assertEqual(chr(o), chr(o).decode('imap4-utf-7')) - self.assertEqual('&'.encode('imap4-utf-7'), '&-') - self.assertEqual('&-'.decode('imap4-utf-7'), '&') - - - -class BufferingConsumer: - def __init__(self): - self.buffer = [] - - def write(self, bytes): - self.buffer.append(bytes) - if self.consumer: - self.consumer.resumeProducing() - - def registerProducer(self, consumer, streaming): - self.consumer = consumer - self.consumer.resumeProducing() - - def unregisterProducer(self): - self.consumer = None - -class MessageProducerTests(unittest.TestCase): - def testSinglePart(self): - body = 'This is body text. Rar.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'text/plain' - - msg = FakeyMessage(headers, (), None, body, 123, None ) - - c = BufferingConsumer() - p = imap4.MessageProducer(msg) - d = p.beginProducing(c) - - def cbProduced(result): - self.assertIdentical(result, p) - self.assertEqual( - ''.join(c.buffer), - - '{119}\r\n' - 'From: sender@host\r\n' - 'To: recipient@domain\r\n' - 'Subject: booga booga boo\r\n' - 'Content-Type: text/plain\r\n' - '\r\n' - + body) - return d.addCallback(cbProduced) - - - def testSingleMultiPart(self): - outerBody = '' - innerBody = 'Contained body message text. Squarge.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'multipart/alternative; boundary="xyz"' - - innerHeaders = util.OrderedDict() - innerHeaders['subject'] = 'this is subject text' - innerHeaders['content-type'] = 'text/plain' - msg = FakeyMessage(headers, (), None, outerBody, 123, - [FakeyMessage(innerHeaders, (), None, innerBody, - None, None)], - ) - - c = BufferingConsumer() - p = imap4.MessageProducer(msg) - d = p.beginProducing(c) - - def cbProduced(result): - self.failUnlessIdentical(result, p) - - self.assertEqual( - ''.join(c.buffer), - - '{239}\r\n' - 'From: sender@host\r\n' - 'To: recipient@domain\r\n' - 'Subject: booga booga boo\r\n' - 'Content-Type: multipart/alternative; boundary="xyz"\r\n' - '\r\n' - '\r\n' - '--xyz\r\n' - 'Subject: this is subject text\r\n' - 'Content-Type: text/plain\r\n' - '\r\n' - + innerBody - + '\r\n--xyz--\r\n') - - return d.addCallback(cbProduced) - - - def testMultipleMultiPart(self): - outerBody = '' - innerBody1 = 'Contained body message text. Squarge.' - innerBody2 = 'Secondary message text of squarge body.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'multipart/alternative; boundary="xyz"' - innerHeaders = util.OrderedDict() - innerHeaders['subject'] = 'this is subject text' - innerHeaders['content-type'] = 'text/plain' - innerHeaders2 = util.OrderedDict() - innerHeaders2['subject'] = 'this is subject' - innerHeaders2['content-type'] = 'text/html' - msg = FakeyMessage(headers, (), None, outerBody, 123, [ - FakeyMessage(innerHeaders, (), None, innerBody1, None, None), - FakeyMessage(innerHeaders2, (), None, innerBody2, None, None) - ], - ) - - c = BufferingConsumer() - p = imap4.MessageProducer(msg) - d = p.beginProducing(c) - - def cbProduced(result): - self.failUnlessIdentical(result, p) - - self.assertEqual( - ''.join(c.buffer), - - '{354}\r\n' - 'From: sender@host\r\n' - 'To: recipient@domain\r\n' - 'Subject: booga booga boo\r\n' - 'Content-Type: multipart/alternative; boundary="xyz"\r\n' - '\r\n' - '\r\n' - '--xyz\r\n' - 'Subject: this is subject text\r\n' - 'Content-Type: text/plain\r\n' - '\r\n' - + innerBody1 - + '\r\n--xyz\r\n' - 'Subject: this is subject\r\n' - 'Content-Type: text/html\r\n' - '\r\n' - + innerBody2 - + '\r\n--xyz--\r\n') - return d.addCallback(cbProduced) - - - -class IMAP4HelperTests(unittest.TestCase): - """ - Tests for various helper utilities in the IMAP4 module. - """ - - def test_fileProducer(self): - b = (('x' * 1) + ('y' * 1) + ('z' * 1)) * 10 - c = BufferingConsumer() - f = StringIO(b) - p = imap4.FileProducer(f) - d = p.beginProducing(c) - - def cbProduced(result): - self.failUnlessIdentical(result, p) - self.assertEqual( - ('{%d}\r\n' % len(b))+ b, - ''.join(c.buffer)) - return d.addCallback(cbProduced) - - - def test_wildcard(self): - cases = [ - ['foo/%gum/bar', - ['foo/bar', 'oo/lalagum/bar', 'foo/gumx/bar', 'foo/gum/baz'], - ['foo/xgum/bar', 'foo/gum/bar'], - ], ['foo/x%x/bar', - ['foo', 'bar', 'fuz fuz fuz', 'foo/*/bar', 'foo/xyz/bar', 'foo/xx/baz'], - ['foo/xyx/bar', 'foo/xx/bar', 'foo/xxxxxxxxxxxxxx/bar'], - ], ['foo/xyz*abc/bar', - ['foo/xyz/bar', 'foo/abc/bar', 'foo/xyzab/cbar', 'foo/xyza/bcbar'], - ['foo/xyzabc/bar', 'foo/xyz/abc/bar', 'foo/xyz/123/abc/bar'], - ] - ] - - for (wildcard, fail, succeed) in cases: - wildcard = imap4.wildcardToRegexp(wildcard, '/') - for x in fail: - self.failIf(wildcard.match(x)) - for x in succeed: - self.failUnless(wildcard.match(x)) - - - def test_wildcardNoDelim(self): - cases = [ - ['foo/%gum/bar', - ['foo/bar', 'oo/lalagum/bar', 'foo/gumx/bar', 'foo/gum/baz'], - ['foo/xgum/bar', 'foo/gum/bar', 'foo/x/gum/bar'], - ], ['foo/x%x/bar', - ['foo', 'bar', 'fuz fuz fuz', 'foo/*/bar', 'foo/xyz/bar', 'foo/xx/baz'], - ['foo/xyx/bar', 'foo/xx/bar', 'foo/xxxxxxxxxxxxxx/bar', 'foo/x/x/bar'], - ], ['foo/xyz*abc/bar', - ['foo/xyz/bar', 'foo/abc/bar', 'foo/xyzab/cbar', 'foo/xyza/bcbar'], - ['foo/xyzabc/bar', 'foo/xyz/abc/bar', 'foo/xyz/123/abc/bar'], - ] - ] - - for (wildcard, fail, succeed) in cases: - wildcard = imap4.wildcardToRegexp(wildcard, None) - for x in fail: - self.failIf(wildcard.match(x), x) - for x in succeed: - self.failUnless(wildcard.match(x), x) - - - def test_headerFormatter(self): - """ - L{imap4._formatHeaders} accepts a C{dict} of header name/value pairs and - returns a string representing those headers in the standard multiline, - C{":"}-separated format. - """ - cases = [ - ({'Header1': 'Value1', 'Header2': 'Value2'}, 'Header2: Value2\r\nHeader1: Value1\r\n'), - ] - - for (input, expected) in cases: - output = imap4._formatHeaders(input) - self.assertEqual(sorted(output.splitlines(True)), - sorted(expected.splitlines(True))) - - - def test_messageSet(self): - m1 = MessageSet() - m2 = MessageSet() - - self.assertEqual(m1, m2) - - m1 = m1 + (1, 3) - self.assertEqual(len(m1), 3) - self.assertEqual(list(m1), [1, 2, 3]) - - m2 = m2 + (1, 3) - self.assertEqual(m1, m2) - self.assertEqual(list(m1 + m2), [1, 2, 3]) - - - def test_messageSetStringRepresentationWithWildcards(self): - """ - In a L{MessageSet}, in the presence of wildcards, if the highest message - id is known, the wildcard should get replaced by that high value. - """ - inputs = [ - MessageSet(imap4.parseIdList('*')), - MessageSet(imap4.parseIdList('3:*', 6)), - MessageSet(imap4.parseIdList('*:2', 6)), - ] - - outputs = [ - "*", - "3:6", - "2:6", - ] - - for i, o in zip(inputs, outputs): - self.assertEqual(str(i), o) - - - def test_messageSetStringRepresentationWithInversion(self): - """ - In a L{MessageSet}, inverting the high and low numbers in a range - doesn't affect the meaning of the range. For example, 3:2 displays just - like 2:3, because according to the RFC they have the same meaning. - """ - inputs = [ - MessageSet(imap4.parseIdList('2:3')), - MessageSet(imap4.parseIdList('3:2')), - ] - - outputs = [ - "2:3", - "2:3", - ] - - for i, o in zip(inputs, outputs): - self.assertEqual(str(i), o) - - - def test_quotedSplitter(self): - cases = [ - '''Hello World''', - '''Hello "World!"''', - '''World "Hello" "How are you?"''', - '''"Hello world" How "are you?"''', - '''foo bar "baz buz" NIL''', - '''foo bar "baz buz" "NIL"''', - '''foo NIL "baz buz" bar''', - '''foo "NIL" "baz buz" bar''', - '''"NIL" bar "baz buz" foo''', - 'oo \\"oo\\" oo', - '"oo \\"oo\\" oo"', - 'oo \t oo', - '"oo \t oo"', - 'oo \\t oo', - '"oo \\t oo"', - 'oo \o oo', - '"oo \o oo"', - 'oo \\o oo', - '"oo \\o oo"', - ] - - answers = [ - ['Hello', 'World'], - ['Hello', 'World!'], - ['World', 'Hello', 'How are you?'], - ['Hello world', 'How', 'are you?'], - ['foo', 'bar', 'baz buz', None], - ['foo', 'bar', 'baz buz', 'NIL'], - ['foo', None, 'baz buz', 'bar'], - ['foo', 'NIL', 'baz buz', 'bar'], - ['NIL', 'bar', 'baz buz', 'foo'], - ['oo', '"oo"', 'oo'], - ['oo "oo" oo'], - ['oo', 'oo'], - ['oo \t oo'], - ['oo', '\\t', 'oo'], - ['oo \\t oo'], - ['oo', '\o', 'oo'], - ['oo \o oo'], - ['oo', '\\o', 'oo'], - ['oo \\o oo'], - - ] - - errors = [ - '"mismatched quote', - 'mismatched quote"', - 'mismatched"quote', - '"oops here is" another"', - ] - - for s in errors: - self.assertRaises(imap4.MismatchedQuoting, imap4.splitQuoted, s) - - for (case, expected) in zip(cases, answers): - self.assertEqual(imap4.splitQuoted(case), expected) - - - def test_stringCollapser(self): - cases = [ - ['a', 'b', 'c', 'd', 'e'], - ['a', ' ', '"', 'b', 'c', ' ', '"', ' ', 'd', 'e'], - [['a', 'b', 'c'], 'd', 'e'], - ['a', ['b', 'c', 'd'], 'e'], - ['a', 'b', ['c', 'd', 'e']], - ['"', 'a', ' ', '"', ['b', 'c', 'd'], '"', ' ', 'e', '"'], - ['a', ['"', ' ', 'b', 'c', ' ', ' ', '"'], 'd', 'e'], - ] - - answers = [ - ['abcde'], - ['a', 'bc ', 'de'], - [['abc'], 'de'], - ['a', ['bcd'], 'e'], - ['ab', ['cde']], - ['a ', ['bcd'], ' e'], - ['a', [' bc '], 'de'], - ] - - for (case, expected) in zip(cases, answers): - self.assertEqual(imap4.collapseStrings(case), expected) - - - def test_parenParser(self): - s = '\r\n'.join(['xx'] * 4) - cases = [ - '(BODY.PEEK[HEADER.FIELDS.NOT (subject bcc cc)] {%d}\r\n%s)' % (len(s), s,), - -# '(FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700" ' -# 'RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)" ' -# '"IMAP4rev1 WG mtg summary and minutes" ' -# '(("Terry Gray" NIL "gray" "cac.washington.edu")) ' -# '(("Terry Gray" NIL "gray" "cac.washington.edu")) ' -# '(("Terry Gray" NIL "gray" "cac.washington.edu")) ' -# '((NIL NIL "imap" "cac.washington.edu")) ' -# '((NIL NIL "minutes" "CNRI.Reston.VA.US") ' -# '("John Klensin" NIL "KLENSIN" "INFOODS.MIT.EDU")) NIL NIL ' -# '"") ' -# 'BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 3028 92))', - - '(FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700" ' - 'RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)" ' - '"IMAP4rev1 WG mtg summary and minutes" ' - '(("Terry Gray" NIL gray cac.washington.edu)) ' - '(("Terry Gray" NIL gray cac.washington.edu)) ' - '(("Terry Gray" NIL gray cac.washington.edu)) ' - '((NIL NIL imap cac.washington.edu)) ' - '((NIL NIL minutes CNRI.Reston.VA.US) ' - '("John Klensin" NIL KLENSIN INFOODS.MIT.EDU)) NIL NIL ' - ') ' - 'BODY (TEXT PLAIN (CHARSET US-ASCII) NIL NIL 7BIT 3028 92))', - '("oo \\"oo\\" oo")', - '("oo \\\\ oo")', - '("oo \\ oo")', - '("oo \\o")', - '("oo \o")', - '(oo \o)', - '(oo \\o)', - - ] - - answers = [ - ['BODY.PEEK', ['HEADER.FIELDS.NOT', ['subject', 'bcc', 'cc']], s], - - ['FLAGS', [r'\Seen'], 'INTERNALDATE', - '17-Jul-1996 02:44:25 -0700', 'RFC822.SIZE', '4286', 'ENVELOPE', - ['Wed, 17 Jul 1996 02:23:25 -0700 (PDT)', - 'IMAP4rev1 WG mtg summary and minutes', [["Terry Gray", None, - "gray", "cac.washington.edu"]], [["Terry Gray", None, - "gray", "cac.washington.edu"]], [["Terry Gray", None, - "gray", "cac.washington.edu"]], [[None, None, "imap", - "cac.washington.edu"]], [[None, None, "minutes", - "CNRI.Reston.VA.US"], ["John Klensin", None, "KLENSIN", - "INFOODS.MIT.EDU"]], None, None, - ""], "BODY", ["TEXT", "PLAIN", - ["CHARSET", "US-ASCII"], None, None, "7BIT", "3028", "92"]], - ['oo "oo" oo'], - ['oo \\\\ oo'], - ['oo \\ oo'], - ['oo \\o'], - ['oo \o'], - ['oo', '\o'], - ['oo', '\\o'], - ] - - for (case, expected) in zip(cases, answers): - self.assertEqual(imap4.parseNestedParens(case), [expected]) - - # XXX This code used to work, but changes occurred within the - # imap4.py module which made it no longer necessary for *all* of it - # to work. In particular, only the part that makes - # 'BODY.PEEK[HEADER.FIELDS.NOT (Subject Bcc Cc)]' come out correctly - # no longer needs to work. So, I am loathe to delete the entire - # section of the test. --exarkun - # - -# for (case, expected) in zip(answers, cases): -# self.assertEqual('(' + imap4.collapseNestedLists(case) + ')', expected) - - - def test_fetchParserSimple(self): - cases = [ - ['ENVELOPE', 'Envelope'], - ['FLAGS', 'Flags'], - ['INTERNALDATE', 'InternalDate'], - ['RFC822.HEADER', 'RFC822Header'], - ['RFC822.SIZE', 'RFC822Size'], - ['RFC822.TEXT', 'RFC822Text'], - ['RFC822', 'RFC822'], - ['UID', 'UID'], - ['BODYSTRUCTURE', 'BodyStructure'], - ] - - for (inp, outp) in cases: - p = imap4._FetchParser() - p.parseString(inp) - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], getattr(p, outp))) - - - def test_fetchParserMacros(self): - cases = [ - ['ALL', (4, ['flags', 'internaldate', 'rfc822.size', 'envelope'])], - ['FULL', (5, ['flags', 'internaldate', 'rfc822.size', 'envelope', 'body'])], - ['FAST', (3, ['flags', 'internaldate', 'rfc822.size'])], - ] - - for (inp, outp) in cases: - p = imap4._FetchParser() - p.parseString(inp) - self.assertEqual(len(p.result), outp[0]) - expectedResult = [str(token).lower() for token in p.result] - expectedResult.sort() - outp[1].sort() - self.assertEqual(expectedResult, outp[1]) - - - def test_fetchParserBody(self): - P = imap4._FetchParser - - p = P() - p.parseString('BODY') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, False) - self.assertEqual(p.result[0].header, None) - self.assertEqual(str(p.result[0]), 'BODY') - - p = P() - p.parseString('BODY.PEEK') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, True) - self.assertEqual(str(p.result[0]), 'BODY') - - p = P() - p.parseString('BODY[]') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].empty, True) - self.assertEqual(str(p.result[0]), 'BODY[]') - - p = P() - p.parseString('BODY[HEADER]') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, False) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEqual(p.result[0].header.negate, True) - self.assertEqual(p.result[0].header.fields, ()) - self.assertEqual(p.result[0].empty, False) - self.assertEqual(str(p.result[0]), 'BODY[HEADER]') - - p = P() - p.parseString('BODY.PEEK[HEADER]') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEqual(p.result[0].header.negate, True) - self.assertEqual(p.result[0].header.fields, ()) - self.assertEqual(p.result[0].empty, False) - self.assertEqual(str(p.result[0]), 'BODY[HEADER]') - - p = P() - p.parseString('BODY[HEADER.FIELDS (Subject Cc Message-Id)]') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, False) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEqual(p.result[0].header.negate, False) - self.assertEqual(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEqual(p.result[0].empty, False) - self.assertEqual(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') - - p = P() - p.parseString('BODY.PEEK[HEADER.FIELDS (Subject Cc Message-Id)]') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEqual(p.result[0].header.negate, False) - self.assertEqual(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEqual(p.result[0].empty, False) - self.assertEqual(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') - - p = P() - p.parseString('BODY.PEEK[HEADER.FIELDS.NOT (Subject Cc Message-Id)]') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEqual(p.result[0].header.negate, True) - self.assertEqual(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEqual(p.result[0].empty, False) - self.assertEqual(str(p.result[0]), 'BODY[HEADER.FIELDS.NOT (Subject Cc Message-Id)]') - - p = P() - p.parseString('BODY[1.MIME]<10.50>') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, False) - self.failUnless(isinstance(p.result[0].mime, p.MIME)) - self.assertEqual(p.result[0].part, (0,)) - self.assertEqual(p.result[0].partialBegin, 10) - self.assertEqual(p.result[0].partialLength, 50) - self.assertEqual(p.result[0].empty, False) - self.assertEqual(str(p.result[0]), 'BODY[1.MIME]<10.50>') - - p = P() - p.parseString('BODY.PEEK[1.3.9.11.HEADER.FIELDS.NOT (Message-Id Date)]<103.69>') - self.assertEqual(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEqual(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEqual(p.result[0].part, (0, 2, 8, 10)) - self.assertEqual(p.result[0].header.fields, ['MESSAGE-ID', 'DATE']) - self.assertEqual(p.result[0].partialBegin, 103) - self.assertEqual(p.result[0].partialLength, 69) - self.assertEqual(p.result[0].empty, False) - self.assertEqual(str(p.result[0]), 'BODY[1.3.9.11.HEADER.FIELDS.NOT (Message-Id Date)]<103.69>') - - - def test_files(self): - inputStructure = [ - 'foo', 'bar', 'baz', StringIO('this is a file\r\n'), 'buz' - ] - - output = '"foo" "bar" "baz" {16}\r\nthis is a file\r\n "buz"' - - self.assertEqual(imap4.collapseNestedLists(inputStructure), output) - - - def test_quoteAvoider(self): - input = [ - 'foo', imap4.DontQuoteMe('bar'), "baz", StringIO('this is a file\r\n'), - imap4.DontQuoteMe('buz'), "" - ] - - output = '"foo" bar "baz" {16}\r\nthis is a file\r\n buz ""' - - self.assertEqual(imap4.collapseNestedLists(input), output) - - - def test_literals(self): - cases = [ - ('({10}\r\n0123456789)', [['0123456789']]), - ] - - for (case, expected) in cases: - self.assertEqual(imap4.parseNestedParens(case), expected) - - - def test_queryBuilder(self): - inputs = [ - imap4.Query(flagged=1), - imap4.Query(sorted=1, unflagged=1, deleted=1), - imap4.Or(imap4.Query(flagged=1), imap4.Query(deleted=1)), - imap4.Query(before='today'), - imap4.Or( - imap4.Query(deleted=1), - imap4.Query(unseen=1), - imap4.Query(new=1) - ), - imap4.Or( - imap4.Not( - imap4.Or( - imap4.Query(sorted=1, since='yesterday', smaller=1000), - imap4.Query(sorted=1, before='tuesday', larger=10000), - imap4.Query(sorted=1, unseen=1, deleted=1, before='today'), - imap4.Not( - imap4.Query(subject='spam') - ), - ), - ), - imap4.Not( - imap4.Query(uid='1:5') - ), - ) - ] - - outputs = [ - 'FLAGGED', - '(DELETED UNFLAGGED)', - '(OR FLAGGED DELETED)', - '(BEFORE "today")', - '(OR DELETED (OR UNSEEN NEW))', - '(OR (NOT (OR (SINCE "yesterday" SMALLER 1000) ' # Continuing - '(OR (BEFORE "tuesday" LARGER 10000) (OR (BEFORE ' # Some more - '"today" DELETED UNSEEN) (NOT (SUBJECT "spam")))))) ' # And more - '(NOT (UID 1:5)))', - ] - - for (query, expected) in zip(inputs, outputs): - self.assertEqual(query, expected) - - - def test_queryKeywordFlagWithQuotes(self): - """ - When passed the C{keyword} argument, L{imap4.Query} returns an unquoted - string. - - @see: U{http://tools.ietf.org/html/rfc3501#section-9} - @see: U{http://tools.ietf.org/html/rfc3501#section-6.4.4} - """ - query = imap4.Query(keyword='twisted') - self.assertEqual('(KEYWORD twisted)', query) - - - def test_queryUnkeywordFlagWithQuotes(self): - """ - When passed the C{unkeyword} argument, L{imap4.Query} returns an - unquoted string. - - @see: U{http://tools.ietf.org/html/rfc3501#section-9} - @see: U{http://tools.ietf.org/html/rfc3501#section-6.4.4} - """ - query = imap4.Query(unkeyword='twisted') - self.assertEqual('(UNKEYWORD twisted)', query) - - - def _keywordFilteringTest(self, keyword): - """ - Helper to implement tests for value filtering of KEYWORD and UNKEYWORD - queries. - - @param keyword: A native string giving the name of the L{imap4.Query} - keyword argument to test. - """ - # Check all the printable exclusions - self.assertEqual( - '(%s twistedrocks)' % (keyword.upper(),), - imap4.Query(**{keyword: r'twisted (){%*"\] rocks'})) - - # Check all the non-printable exclusions - self.assertEqual( - '(%s twistedrocks)' % (keyword.upper(),), - imap4.Query(**{ - keyword: 'twisted %s rocks' % ( - ''.join(chr(ch) for ch in range(33)),)})) - - - def test_queryKeywordFlag(self): - """ - When passed the C{keyword} argument, L{imap4.Query} returns an - C{atom} that consists of one or more non-special characters. - - List of the invalid characters: - - ( ) { % * " \ ] CTL SP - - @see: U{ABNF definition of CTL and SP} - @see: U{IMAP4 grammar} - @see: U{IMAP4 SEARCH specification} - """ - self._keywordFilteringTest("keyword") - - - def test_queryUnkeywordFlag(self): - """ - When passed the C{unkeyword} argument, L{imap4.Query} returns an - C{atom} that consists of one or more non-special characters. - - List of the invalid characters: - - ( ) { % * " \ ] CTL SP - - @see: U{ABNF definition of CTL and SP} - @see: U{IMAP4 grammar} - @see: U{IMAP4 SEARCH specification} - """ - self._keywordFilteringTest("unkeyword") - - - def test_invalidIdListParser(self): - """ - Trying to parse an invalid representation of a sequence range raises an - L{IllegalIdentifierError}. - """ - inputs = [ - '*:*', - 'foo', - '4:', - 'bar:5' - ] - - for input in inputs: - self.assertRaises(imap4.IllegalIdentifierError, - imap4.parseIdList, input, 12345) - - - def test_invalidIdListParserNonPositive(self): - """ - Zeroes and negative values are not accepted in id range expressions. RFC - 3501 states that sequence numbers and sequence ranges consist of - non-negative numbers (RFC 3501 section 9, the seq-number grammar item). - """ - inputs = [ - '0:5', - '0:0', - '*:0', - '0', - '-3:5', - '1:-2', - '-1' - ] - - for input in inputs: - self.assertRaises(imap4.IllegalIdentifierError, - imap4.parseIdList, input, 12345) - - - def test_parseIdList(self): - """ - The function to parse sequence ranges yields appropriate L{MessageSet} - objects. - """ - inputs = [ - '1:*', - '5:*', - '1:2,5:*', - '*', - '1', - '1,2', - '1,3,5', - '1:10', - '1:10,11', - '1:5,10:20', - '1,5:10', - '1,5:10,15:20', - '1:10,15,20:25', - '4:2' - ] - - outputs = [ - MessageSet(1, None), - MessageSet(5, None), - MessageSet(5, None) + MessageSet(1, 2), - MessageSet(None, None), - MessageSet(1), - MessageSet(1, 2), - MessageSet(1) + MessageSet(3) + MessageSet(5), - MessageSet(1, 10), - MessageSet(1, 11), - MessageSet(1, 5) + MessageSet(10, 20), - MessageSet(1) + MessageSet(5, 10), - MessageSet(1) + MessageSet(5, 10) + MessageSet(15, 20), - MessageSet(1, 10) + MessageSet(15) + MessageSet(20, 25), - MessageSet(2, 4), - ] - - lengths = [ - None, None, None, - 1, 1, 2, 3, 10, 11, 16, 7, 13, 17, 3 - ] - - for (input, expected) in zip(inputs, outputs): - self.assertEqual(imap4.parseIdList(input), expected) - - for (input, expected) in zip(inputs, lengths): - if expected is None: - self.assertRaises(TypeError, len, imap4.parseIdList(input)) - else: - L = len(imap4.parseIdList(input)) - self.assertEqual(L, expected, - "len(%r) = %r != %r" % (input, L, expected)) - -class SimpleMailbox: - implements(imap4.IMailboxInfo, imap4.IMailbox, imap4.ICloseableMailbox) - - flags = ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag') - messages = [] - mUID = 0 - rw = 1 - closed = False - - def __init__(self): - self.listeners = [] - self.addListener = self.listeners.append - self.removeListener = self.listeners.remove - - def getFlags(self): - return self.flags - - def getUIDValidity(self): - return 42 - - def getUIDNext(self): - return len(self.messages) + 1 - - def getMessageCount(self): - return 9 - - def getRecentCount(self): - return 3 - - def getUnseenCount(self): - return 4 - - def isWriteable(self): - return self.rw - - def destroy(self): - pass - - def getHierarchicalDelimiter(self): - return '/' - - def requestStatus(self, names): - r = {} - if 'MESSAGES' in names: - r['MESSAGES'] = self.getMessageCount() - if 'RECENT' in names: - r['RECENT'] = self.getRecentCount() - if 'UIDNEXT' in names: - r['UIDNEXT'] = self.getMessageCount() + 1 - if 'UIDVALIDITY' in names: - r['UIDVALIDITY'] = self.getUID() - if 'UNSEEN' in names: - r['UNSEEN'] = self.getUnseenCount() - return defer.succeed(r) - - def addMessage(self, message, flags, date = None): - self.messages.append((message, flags, date, self.mUID)) - self.mUID += 1 - return defer.succeed(None) - - def expunge(self): - delete = [] - for i in self.messages: - if '\\Deleted' in i[1]: - delete.append(i) - for i in delete: - self.messages.remove(i) - return [i[3] for i in delete] - - def close(self): - self.closed = True - -class Account(imap4.MemoryAccount): - mailboxFactory = SimpleMailbox - def _emptyMailbox(self, name, id): - return self.mailboxFactory() - - def select(self, name, rw=1): - mbox = imap4.MemoryAccount.select(self, name) - if mbox is not None: - mbox.rw = rw - return mbox - -class SimpleServer(imap4.IMAP4Server): - def __init__(self, *args, **kw): - imap4.IMAP4Server.__init__(self, *args, **kw) - realm = TestRealm() - realm.theAccount = Account('testuser') - portal = Portal(realm) - c = InMemoryUsernamePasswordDatabaseDontUse() - self.checker = c - self.portal = portal - portal.registerChecker(c) - self.timeoutTest = False - - def lineReceived(self, line): - if self.timeoutTest: - #Do not send a respones - return - - imap4.IMAP4Server.lineReceived(self, line) - - _username = 'testuser' - _password = 'password-test' - def authenticateLogin(self, username, password): - if username == self._username and password == self._password: - return imap4.IAccount, self.theAccount, lambda: None - raise UnauthorizedLogin() - - -class SimpleClient(imap4.IMAP4Client): - def __init__(self, deferred, contextFactory = None): - imap4.IMAP4Client.__init__(self, contextFactory) - self.deferred = deferred - self.events = [] - - def serverGreeting(self, caps): - self.deferred.callback(None) - - def modeChanged(self, writeable): - self.events.append(['modeChanged', writeable]) - self.transport.loseConnection() - - def flagsChanged(self, newFlags): - self.events.append(['flagsChanged', newFlags]) - self.transport.loseConnection() - - def newMessages(self, exists, recent): - self.events.append(['newMessages', exists, recent]) - self.transport.loseConnection() - - - -class IMAP4HelperMixin: - - serverCTX = None - clientCTX = None - - def setUp(self): - d = defer.Deferred() - self.server = SimpleServer(contextFactory=self.serverCTX) - self.client = SimpleClient(d, contextFactory=self.clientCTX) - self.connected = d - - SimpleMailbox.messages = [] - theAccount = Account('testuser') - theAccount.mboxType = SimpleMailbox - SimpleServer.theAccount = theAccount - - - def tearDown(self): - del self.server - del self.client - del self.connected - - - def _cbStopClient(self, ignore): - self.client.transport.loseConnection() - - - def _ebGeneral(self, failure): - self.client.transport.loseConnection() - self.server.transport.loseConnection() - log.err(failure, "Problem with %r" % (self.function,)) - - - def loopback(self): - return loopback.loopbackAsync(self.server, self.client) - - - -class IMAP4ServerTests(IMAP4HelperMixin, unittest.TestCase): - def testCapability(self): - caps = {} - def getCaps(): - def gotCaps(c): - caps.update(c) - self.server.transport.loseConnection() - return self.client.getCapabilities().addCallback(gotCaps) - d1 = self.connected.addCallback(strip(getCaps)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - expected = {'IMAP4rev1': None, 'NAMESPACE': None, 'IDLE': None} - return d.addCallback(lambda _: self.assertEqual(expected, caps)) - - def testCapabilityWithAuth(self): - caps = {} - self.server.challengers['CRAM-MD5'] = CramMD5Credentials - def getCaps(): - def gotCaps(c): - caps.update(c) - self.server.transport.loseConnection() - return self.client.getCapabilities().addCallback(gotCaps) - d1 = self.connected.addCallback(strip(getCaps)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - - expCap = {'IMAP4rev1': None, 'NAMESPACE': None, - 'IDLE': None, 'AUTH': ['CRAM-MD5']} - - return d.addCallback(lambda _: self.assertEqual(expCap, caps)) - - def testLogout(self): - self.loggedOut = 0 - def logout(): - def setLoggedOut(): - self.loggedOut = 1 - self.client.logout().addCallback(strip(setLoggedOut)) - self.connected.addCallback(strip(logout)).addErrback(self._ebGeneral) - d = self.loopback() - return d.addCallback(lambda _: self.assertEqual(self.loggedOut, 1)) - - def testNoop(self): - self.responses = None - def noop(): - def setResponses(responses): - self.responses = responses - self.server.transport.loseConnection() - self.client.noop().addCallback(setResponses) - self.connected.addCallback(strip(noop)).addErrback(self._ebGeneral) - d = self.loopback() - return d.addCallback(lambda _: self.assertEqual(self.responses, [])) - - def testLogin(self): - def login(): - d = self.client.login('testuser', 'password-test') - d.addCallback(self._cbStopClient) - d1 = self.connected.addCallback(strip(login)).addErrback(self._ebGeneral) - d = defer.gatherResults([d1, self.loopback()]) - return d.addCallback(self._cbTestLogin) - - def _cbTestLogin(self, ignored): - self.assertEqual(self.server.account, SimpleServer.theAccount) - self.assertEqual(self.server.state, 'auth') - - def testFailedLogin(self): - def login(): - d = self.client.login('testuser', 'wrong-password') - d.addBoth(self._cbStopClient) - - d1 = self.connected.addCallback(strip(login)).addErrback(self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestFailedLogin) - - def _cbTestFailedLogin(self, ignored): - self.assertEqual(self.server.account, None) - self.assertEqual(self.server.state, 'unauth') - - - def testLoginRequiringQuoting(self): - self.server._username = '{test}user' - self.server._password = '{test}password' - - def login(): - d = self.client.login('{test}user', '{test}password') - d.addBoth(self._cbStopClient) - - d1 = self.connected.addCallback(strip(login)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestLoginRequiringQuoting) - - def _cbTestLoginRequiringQuoting(self, ignored): - self.assertEqual(self.server.account, SimpleServer.theAccount) - self.assertEqual(self.server.state, 'auth') - - - def testNamespace(self): - self.namespaceArgs = None - def login(): - return self.client.login('testuser', 'password-test') - def namespace(): - def gotNamespace(args): - self.namespaceArgs = args - self._cbStopClient(None) - return self.client.namespace().addCallback(gotNamespace) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(namespace)) - d1.addErrback(self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEqual(self.namespaceArgs, - [[['', '/']], [], []])) - return d - - def testSelect(self): - SimpleServer.theAccount.addMailbox('test-mailbox') - self.selectedArgs = None - def login(): - return self.client.login('testuser', 'password-test') - def select(): - def selected(args): - self.selectedArgs = args - self._cbStopClient(None) - d = self.client.select('test-mailbox') - d.addCallback(selected) - return d - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(select)) - d1.addErrback(self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d1, d2]).addCallback(self._cbTestSelect) - - def _cbTestSelect(self, ignored): - mbox = SimpleServer.theAccount.mailboxes['TEST-MAILBOX'] - self.assertEqual(self.server.mbox, mbox) - self.assertEqual(self.selectedArgs, { - 'EXISTS': 9, 'RECENT': 3, 'UIDVALIDITY': 42, - 'FLAGS': ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag'), - 'READ-WRITE': 1 - }) - - - def test_examine(self): - """ - L{IMAP4Client.examine} issues an I{EXAMINE} command to the server and - returns a L{Deferred} which fires with a C{dict} with as many of the - following keys as the server includes in its response: C{'FLAGS'}, - C{'EXISTS'}, C{'RECENT'}, C{'UNSEEN'}, C{'READ-WRITE'}, C{'READ-ONLY'}, - C{'UIDVALIDITY'}, and C{'PERMANENTFLAGS'}. - - Unfortunately the server doesn't generate all of these so it's hard to - test the client's handling of them here. See - L{IMAP4ClientExamineTests} below. - - See U{RFC 3501}, section 6.3.2, - for details. - """ - SimpleServer.theAccount.addMailbox('test-mailbox') - self.examinedArgs = None - def login(): - return self.client.login('testuser', 'password-test') - def examine(): - def examined(args): - self.examinedArgs = args - self._cbStopClient(None) - d = self.client.examine('test-mailbox') - d.addCallback(examined) - return d - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(examine)) - d1.addErrback(self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestExamine) - - - def _cbTestExamine(self, ignored): - mbox = SimpleServer.theAccount.mailboxes['TEST-MAILBOX'] - self.assertEqual(self.server.mbox, mbox) - self.assertEqual(self.examinedArgs, { - 'EXISTS': 9, 'RECENT': 3, 'UIDVALIDITY': 42, - 'FLAGS': ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag'), - 'READ-WRITE': False}) - - - def testCreate(self): - succeed = ('testbox', 'test/box', 'test/', 'test/box/box', 'INBOX') - fail = ('testbox', 'test/box') - - def cb(): self.result.append(1) - def eb(failure): self.result.append(0) - - def login(): - return self.client.login('testuser', 'password-test') - def create(): - for name in succeed + fail: - d = self.client.create(name) - d.addCallback(strip(cb)).addErrback(eb) - d.addCallbacks(self._cbStopClient, self._ebGeneral) - - self.result = [] - d1 = self.connected.addCallback(strip(login)).addCallback(strip(create)) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestCreate, succeed, fail) - - def _cbTestCreate(self, ignored, succeed, fail): - self.assertEqual(self.result, [1] * len(succeed) + [0] * len(fail)) - mbox = SimpleServer.theAccount.mailboxes.keys() - answers = ['inbox', 'testbox', 'test/box', 'test', 'test/box/box'] - mbox.sort() - answers.sort() - self.assertEqual(mbox, [a.upper() for a in answers]) - - def testDelete(self): - SimpleServer.theAccount.addMailbox('delete/me') - - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('delete/me') - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(delete), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEqual(SimpleServer.theAccount.mailboxes.keys(), [])) - return d - - def testIllegalInboxDelete(self): - self.stashed = None - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('inbox') - def stash(result): - self.stashed = result - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(delete), self._ebGeneral) - d1.addBoth(stash) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.failUnless(isinstance(self.stashed, - failure.Failure))) - return d - - - def testNonExistentDelete(self): - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('delete/me') - def deleteFailed(failure): - self.failure = failure - - self.failure = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(delete)).addErrback(deleteFailed) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEqual(str(self.failure.value), - 'No such mailbox')) - return d - - - def testIllegalDelete(self): - m = SimpleMailbox() - m.flags = (r'\Noselect',) - SimpleServer.theAccount.addMailbox('delete', m) - SimpleServer.theAccount.addMailbox('delete/me') - - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('delete') - def deleteFailed(failure): - self.failure = failure - - self.failure = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(delete)).addErrback(deleteFailed) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - expected = "Hierarchically inferior mailboxes exist and \\Noselect is set" - d.addCallback(lambda _: - self.assertEqual(str(self.failure.value), expected)) - return d - - def testRename(self): - SimpleServer.theAccount.addMailbox('oldmbox') - def login(): - return self.client.login('testuser', 'password-test') - def rename(): - return self.client.rename('oldmbox', 'newname') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(rename), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEqual(SimpleServer.theAccount.mailboxes.keys(), - ['NEWNAME'])) - return d - - def testIllegalInboxRename(self): - self.stashed = None - def login(): - return self.client.login('testuser', 'password-test') - def rename(): - return self.client.rename('inbox', 'frotz') - def stash(stuff): - self.stashed = stuff - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(rename), self._ebGeneral) - d1.addBoth(stash) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.failUnless(isinstance(self.stashed, failure.Failure))) - return d - - def testHierarchicalRename(self): - SimpleServer.theAccount.create('oldmbox/m1') - SimpleServer.theAccount.create('oldmbox/m2') - def login(): - return self.client.login('testuser', 'password-test') - def rename(): - return self.client.rename('oldmbox', 'newname') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(rename), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestHierarchicalRename) - - def _cbTestHierarchicalRename(self, ignored): - mboxes = SimpleServer.theAccount.mailboxes.keys() - expected = ['newname', 'newname/m1', 'newname/m2'] - mboxes.sort() - self.assertEqual(mboxes, [s.upper() for s in expected]) - - def testSubscribe(self): - def login(): - return self.client.login('testuser', 'password-test') - def subscribe(): - return self.client.subscribe('this/mbox') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(subscribe), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEqual(SimpleServer.theAccount.subscriptions, - ['THIS/MBOX'])) - return d - - def testUnsubscribe(self): - SimpleServer.theAccount.subscriptions = ['THIS/MBOX', 'THAT/MBOX'] - def login(): - return self.client.login('testuser', 'password-test') - def unsubscribe(): - return self.client.unsubscribe('this/mbox') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(unsubscribe), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEqual(SimpleServer.theAccount.subscriptions, - ['THAT/MBOX'])) - return d - - def _listSetup(self, f): - SimpleServer.theAccount.addMailbox('root/subthing') - SimpleServer.theAccount.addMailbox('root/another-thing') - SimpleServer.theAccount.addMailbox('non-root/subthing') - - def login(): - return self.client.login('testuser', 'password-test') - def listed(answers): - self.listed = answers - - self.listed = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(f), self._ebGeneral) - d1.addCallbacks(listed, self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d1, d2]).addCallback(lambda _: self.listed) - - def testList(self): - def list(): - return self.client.list('root', '%') - d = self._listSetup(list) - d.addCallback(lambda listed: self.assertEqual( - sortNest(listed), - sortNest([ - (SimpleMailbox.flags, "/", "ROOT/SUBTHING"), - (SimpleMailbox.flags, "/", "ROOT/ANOTHER-THING") - ]) - )) - return d - - def testLSub(self): - SimpleServer.theAccount.subscribe('ROOT/SUBTHING') - def lsub(): - return self.client.lsub('root', '%') - d = self._listSetup(lsub) - d.addCallback(self.assertEqual, - [(SimpleMailbox.flags, "/", "ROOT/SUBTHING")]) - return d - - def testStatus(self): - SimpleServer.theAccount.addMailbox('root/subthing') - def login(): - return self.client.login('testuser', 'password-test') - def status(): - return self.client.status('root/subthing', 'MESSAGES', 'UIDNEXT', 'UNSEEN') - def statused(result): - self.statused = result - - self.statused = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(status), self._ebGeneral) - d1.addCallbacks(statused, self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEqual( - self.statused, - {'MESSAGES': 9, 'UIDNEXT': '10', 'UNSEEN': 4} - )) - return d - - def testFailedStatus(self): - def login(): - return self.client.login('testuser', 'password-test') - def status(): - return self.client.status('root/nonexistent', 'MESSAGES', 'UIDNEXT', 'UNSEEN') - def statused(result): - self.statused = result - def failed(failure): - self.failure = failure - - self.statused = self.failure = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(status), self._ebGeneral) - d1.addCallbacks(statused, failed) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d1, d2]).addCallback(self._cbTestFailedStatus) - - def _cbTestFailedStatus(self, ignored): - self.assertEqual( - self.statused, None - ) - self.assertEqual( - self.failure.value.args, - ('Could not open mailbox',) - ) - - def testFullAppend(self): - infile = util.sibpath(__file__, 'rfc822.message') - message = open(infile) - SimpleServer.theAccount.addMailbox('root/subthing') - def login(): - return self.client.login('testuser', 'password-test') - def append(): - return self.client.append( - 'root/subthing', - message, - ('\\SEEN', '\\DELETED'), - 'Tue, 17 Jun 2003 11:22:16 -0600 (MDT)', - ) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(append), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestFullAppend, infile) - - def _cbTestFullAppend(self, ignored, infile): - mb = SimpleServer.theAccount.mailboxes['ROOT/SUBTHING'] - self.assertEqual(1, len(mb.messages)) - self.assertEqual( - (['\\SEEN', '\\DELETED'], 'Tue, 17 Jun 2003 11:22:16 -0600 (MDT)', 0), - mb.messages[0][1:] - ) - self.assertEqual(open(infile).read(), mb.messages[0][0].getvalue()) - - def testPartialAppend(self): - infile = util.sibpath(__file__, 'rfc822.message') - # Create the initial file. - FilePath(infile).touch() - SimpleServer.theAccount.addMailbox('PARTIAL/SUBTHING') - def login(): - return self.client.login('testuser', 'password-test') - def append(): - message = file(infile) - return self.client.sendCommand( - imap4.Command( - 'APPEND', - 'PARTIAL/SUBTHING (\\SEEN) "Right now" {%d}' % os.path.getsize(infile), - (), self.client._IMAP4Client__cbContinueAppend, message - ) - ) - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(append), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestPartialAppend, infile) - - def _cbTestPartialAppend(self, ignored, infile): - mb = SimpleServer.theAccount.mailboxes['PARTIAL/SUBTHING'] - self.assertEqual(1, len(mb.messages)) - self.assertEqual( - (['\\SEEN'], 'Right now', 0), - mb.messages[0][1:] - ) - self.assertEqual(open(infile).read(), mb.messages[0][0].getvalue()) - - def testCheck(self): - SimpleServer.theAccount.addMailbox('root/subthing') - def login(): - return self.client.login('testuser', 'password-test') - def select(): - return self.client.select('root/subthing') - def check(): - return self.client.check() - - d = self.connected.addCallback(strip(login)) - d.addCallbacks(strip(select), self._ebGeneral) - d.addCallbacks(strip(check), self._ebGeneral) - d.addCallbacks(self._cbStopClient, self._ebGeneral) - return self.loopback() - - # Okay, that was fun - - def testClose(self): - m = SimpleMailbox() - m.messages = [ - ('Message 1', ('\\Deleted', 'AnotherFlag'), None, 0), - ('Message 2', ('AnotherFlag',), None, 1), - ('Message 3', ('\\Deleted',), None, 2), - ] - SimpleServer.theAccount.addMailbox('mailbox', m) - def login(): - return self.client.login('testuser', 'password-test') - def select(): - return self.client.select('mailbox') - def close(): - return self.client.close() - - d = self.connected.addCallback(strip(login)) - d.addCallbacks(strip(select), self._ebGeneral) - d.addCallbacks(strip(close), self._ebGeneral) - d.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d, d2]).addCallback(self._cbTestClose, m) - - def _cbTestClose(self, ignored, m): - self.assertEqual(len(m.messages), 1) - self.assertEqual(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) - self.failUnless(m.closed) - - def testExpunge(self): - m = SimpleMailbox() - m.messages = [ - ('Message 1', ('\\Deleted', 'AnotherFlag'), None, 0), - ('Message 2', ('AnotherFlag',), None, 1), - ('Message 3', ('\\Deleted',), None, 2), - ] - SimpleServer.theAccount.addMailbox('mailbox', m) - def login(): - return self.client.login('testuser', 'password-test') - def select(): - return self.client.select('mailbox') - def expunge(): - return self.client.expunge() - def expunged(results): - self.failIf(self.server.mbox is None) - self.results = results - - self.results = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(select), self._ebGeneral) - d1.addCallbacks(strip(expunge), self._ebGeneral) - d1.addCallbacks(expunged, self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestExpunge, m) - - def _cbTestExpunge(self, ignored, m): - self.assertEqual(len(m.messages), 1) - self.assertEqual(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) - - self.assertEqual(self.results, [0, 2]) - - - -class IMAP4ServerSearchTests(IMAP4HelperMixin, unittest.TestCase): - """ - Tests for the behavior of the search_* functions in L{imap4.IMAP4Server}. - """ - def setUp(self): - IMAP4HelperMixin.setUp(self) - self.earlierQuery = ["10-Dec-2009"] - self.sameDateQuery = ["13-Dec-2009"] - self.laterQuery = ["16-Dec-2009"] - self.seq = 0 - self.msg = FakeyMessage({"date" : "Mon, 13 Dec 2009 21:25:10 GMT"}, [], - '', '', 1234, None) - - - def test_searchSentBefore(self): - """ - L{imap4.IMAP4Server.search_SENTBEFORE} returns True if the message date - is earlier than the query date. - """ - self.assertFalse( - self.server.search_SENTBEFORE(self.earlierQuery, self.seq, self.msg)) - self.assertTrue( - self.server.search_SENTBEFORE(self.laterQuery, self.seq, self.msg)) - - def test_searchWildcard(self): - """ - L{imap4.IMAP4Server.search_UID} returns True if the message UID is in - the search range. - """ - self.assertFalse( - self.server.search_UID(['2:3'], self.seq, self.msg, (1, 1234))) - # 2:* should get translated to 2: and then to 1:2 - self.assertTrue( - self.server.search_UID(['2:*'], self.seq, self.msg, (1, 1234))) - self.assertTrue( - self.server.search_UID(['*'], self.seq, self.msg, (1, 1234))) - - def test_searchWildcardHigh(self): - """ - L{imap4.IMAP4Server.search_UID} should return True if there is a - wildcard, because a wildcard means "highest UID in the mailbox". - """ - self.assertTrue( - self.server.search_UID(['1235:*'], self.seq, self.msg, (1234, 1))) - - def test_reversedSearchTerms(self): - """ - L{imap4.IMAP4Server.search_SENTON} returns True if the message date is - the same as the query date. - """ - msgset = imap4.parseIdList('4:2') - self.assertEqual(list(msgset), [2, 3, 4]) - - def test_searchSentOn(self): - """ - L{imap4.IMAP4Server.search_SENTON} returns True if the message date is - the same as the query date. - """ - self.assertFalse( - self.server.search_SENTON(self.earlierQuery, self.seq, self.msg)) - self.assertTrue( - self.server.search_SENTON(self.sameDateQuery, self.seq, self.msg)) - self.assertFalse( - self.server.search_SENTON(self.laterQuery, self.seq, self.msg)) - - - def test_searchSentSince(self): - """ - L{imap4.IMAP4Server.search_SENTSINCE} returns True if the message date - is later than the query date. - """ - self.assertTrue( - self.server.search_SENTSINCE(self.earlierQuery, self.seq, self.msg)) - self.assertFalse( - self.server.search_SENTSINCE(self.laterQuery, self.seq, self.msg)) - - - def test_searchOr(self): - """ - L{imap4.IMAP4Server.search_OR} returns true if either of the two - expressions supplied to it returns true and returns false if neither - does. - """ - self.assertTrue( - self.server.search_OR( - ["SENTSINCE"] + self.earlierQuery + - ["SENTSINCE"] + self.laterQuery, - self.seq, self.msg, (None, None))) - self.assertTrue( - self.server.search_OR( - ["SENTSINCE"] + self.laterQuery + - ["SENTSINCE"] + self.earlierQuery, - self.seq, self.msg, (None, None))) - self.assertFalse( - self.server.search_OR( - ["SENTON"] + self.laterQuery + - ["SENTSINCE"] + self.laterQuery, - self.seq, self.msg, (None, None))) - - - def test_searchNot(self): - """ - L{imap4.IMAP4Server.search_NOT} returns the negation of the result - of the expression supplied to it. - """ - self.assertFalse(self.server.search_NOT( - ["SENTSINCE"] + self.earlierQuery, self.seq, self.msg, - (None, None))) - self.assertTrue(self.server.search_NOT( - ["SENTON"] + self.laterQuery, self.seq, self.msg, - (None, None))) - - - -class TestRealm: - theAccount = None - - def requestAvatar(self, avatarId, mind, *interfaces): - return imap4.IAccount, self.theAccount, lambda: None - -class TestChecker: - credentialInterfaces = (IUsernameHashedPassword, IUsernamePassword) - - users = { - 'testuser': 'secret' - } - - def requestAvatarId(self, credentials): - if credentials.username in self.users: - return defer.maybeDeferred( - credentials.checkPassword, self.users[credentials.username] - ).addCallback(self._cbCheck, credentials.username) - - def _cbCheck(self, result, username): - if result: - return username - raise UnauthorizedLogin() - -class AuthenticatorTests(IMAP4HelperMixin, unittest.TestCase): - def setUp(self): - IMAP4HelperMixin.setUp(self) - - realm = TestRealm() - realm.theAccount = Account('testuser') - portal = Portal(realm) - portal.registerChecker(TestChecker()) - self.server.portal = portal - - self.authenticated = 0 - self.account = realm.theAccount - - def testCramMD5(self): - self.server.challengers['CRAM-MD5'] = CramMD5Credentials - cAuth = imap4.CramMD5ClientAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def auth(): - return self.client.authenticate('secret') - def authed(): - self.authenticated = 1 - - d1 = self.connected.addCallback(strip(auth)) - d1.addCallbacks(strip(authed), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestCramMD5) - - def _cbTestCramMD5(self, ignored): - self.assertEqual(self.authenticated, 1) - self.assertEqual(self.server.account, self.account) - - def testFailedCramMD5(self): - self.server.challengers['CRAM-MD5'] = CramMD5Credentials - cAuth = imap4.CramMD5ClientAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def misauth(): - return self.client.authenticate('not the secret') - def authed(): - self.authenticated = 1 - def misauthed(): - self.authenticated = -1 - - d1 = self.connected.addCallback(strip(misauth)) - d1.addCallbacks(strip(authed), strip(misauthed)) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFailedCramMD5) - - def _cbTestFailedCramMD5(self, ignored): - self.assertEqual(self.authenticated, -1) - self.assertEqual(self.server.account, None) - - def testLOGIN(self): - self.server.challengers['LOGIN'] = imap4.LOGINCredentials - cAuth = imap4.LOGINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def auth(): - return self.client.authenticate('secret') - def authed(): - self.authenticated = 1 - - d1 = self.connected.addCallback(strip(auth)) - d1.addCallbacks(strip(authed), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestLOGIN) - - def _cbTestLOGIN(self, ignored): - self.assertEqual(self.authenticated, 1) - self.assertEqual(self.server.account, self.account) - - def testFailedLOGIN(self): - self.server.challengers['LOGIN'] = imap4.LOGINCredentials - cAuth = imap4.LOGINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def misauth(): - return self.client.authenticate('not the secret') - def authed(): - self.authenticated = 1 - def misauthed(): - self.authenticated = -1 - - d1 = self.connected.addCallback(strip(misauth)) - d1.addCallbacks(strip(authed), strip(misauthed)) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFailedLOGIN) - - def _cbTestFailedLOGIN(self, ignored): - self.assertEqual(self.authenticated, -1) - self.assertEqual(self.server.account, None) - - def testPLAIN(self): - self.server.challengers['PLAIN'] = imap4.PLAINCredentials - cAuth = imap4.PLAINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def auth(): - return self.client.authenticate('secret') - def authed(): - self.authenticated = 1 - - d1 = self.connected.addCallback(strip(auth)) - d1.addCallbacks(strip(authed), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestPLAIN) - - def _cbTestPLAIN(self, ignored): - self.assertEqual(self.authenticated, 1) - self.assertEqual(self.server.account, self.account) - - def testFailedPLAIN(self): - self.server.challengers['PLAIN'] = imap4.PLAINCredentials - cAuth = imap4.PLAINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def misauth(): - return self.client.authenticate('not the secret') - def authed(): - self.authenticated = 1 - def misauthed(): - self.authenticated = -1 - - d1 = self.connected.addCallback(strip(misauth)) - d1.addCallbacks(strip(authed), strip(misauthed)) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFailedPLAIN) - - def _cbTestFailedPLAIN(self, ignored): - self.assertEqual(self.authenticated, -1) - self.assertEqual(self.server.account, None) - - - -class SASLPLAINTests(unittest.TestCase): - """ - Tests for I{SASL PLAIN} authentication, as implemented by - L{imap4.PLAINAuthenticator} and L{imap4.PLAINCredentials}. - - @see: U{http://www.faqs.org/rfcs/rfc2595.html} - @see: U{http://www.faqs.org/rfcs/rfc4616.html} - """ - def test_authenticatorChallengeResponse(self): - """ - L{PLAINAuthenticator.challengeResponse} returns challenge strings of - the form:: - - NULNUL - """ - username = 'testuser' - secret = 'secret' - chal = 'challenge' - cAuth = imap4.PLAINAuthenticator(username) - response = cAuth.challengeResponse(secret, chal) - self.assertEqual(response, '\0%s\0%s' % (username, secret)) - - - def test_credentialsSetResponse(self): - """ - L{PLAINCredentials.setResponse} parses challenge strings of the - form:: - - NULNUL - """ - cred = imap4.PLAINCredentials() - cred.setResponse('\0testuser\0secret') - self.assertEqual(cred.username, 'testuser') - self.assertEqual(cred.password, 'secret') - - - def test_credentialsInvalidResponse(self): - """ - L{PLAINCredentials.setResponse} raises L{imap4.IllegalClientResponse} - when passed a string not of the expected form. - """ - cred = imap4.PLAINCredentials() - self.assertRaises( - imap4.IllegalClientResponse, cred.setResponse, 'hello') - self.assertRaises( - imap4.IllegalClientResponse, cred.setResponse, 'hello\0world') - self.assertRaises( - imap4.IllegalClientResponse, cred.setResponse, - 'hello\0world\0Zoom!\0') - - - -class UnsolicitedResponseTests(IMAP4HelperMixin, unittest.TestCase): - def testReadWrite(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.modeChanged(1) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestReadWrite) - - def _cbTestReadWrite(self, ignored): - E = self.client.events - self.assertEqual(E, [['modeChanged', 1]]) - - def testReadOnly(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.modeChanged(0) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestReadOnly) - - def _cbTestReadOnly(self, ignored): - E = self.client.events - self.assertEqual(E, [['modeChanged', 0]]) - - def testFlagChange(self): - flags = { - 1: ['\\Answered', '\\Deleted'], - 5: [], - 10: ['\\Recent'] - } - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.flagsChanged(flags) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFlagChange, flags) - - def _cbTestFlagChange(self, ignored, flags): - E = self.client.events - expect = [['flagsChanged', {x[0]: x[1]}] for x in flags.items()] - E.sort() - expect.sort() - self.assertEqual(E, expect) - - def testNewMessages(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.newMessages(10, None) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestNewMessages) - - def _cbTestNewMessages(self, ignored): - E = self.client.events - self.assertEqual(E, [['newMessages', 10, None]]) - - def testNewRecentMessages(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.newMessages(None, 10) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestNewRecentMessages) - - def _cbTestNewRecentMessages(self, ignored): - E = self.client.events - self.assertEqual(E, [['newMessages', None, 10]]) - - def testNewMessagesAndRecent(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.newMessages(20, 10) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestNewMessagesAndRecent) - - def _cbTestNewMessagesAndRecent(self, ignored): - E = self.client.events - self.assertEqual(E, [['newMessages', 20, None], ['newMessages', None, 10]]) - - -class ClientCapabilityTests(unittest.TestCase): - """ - Tests for issuance of the CAPABILITY command and handling of its response. - """ - def setUp(self): - """ - Create an L{imap4.IMAP4Client} connected to a L{StringTransport}. - """ - self.transport = StringTransport() - self.protocol = imap4.IMAP4Client() - self.protocol.makeConnection(self.transport) - self.protocol.dataReceived('* OK [IMAP4rev1]\r\n') - - - def test_simpleAtoms(self): - """ - A capability response consisting only of atoms without C{'='} in them - should result in a dict mapping those atoms to C{None}. - """ - capabilitiesResult = self.protocol.getCapabilities(useCache=False) - self.protocol.dataReceived('* CAPABILITY IMAP4rev1 LOGINDISABLED\r\n') - self.protocol.dataReceived('0001 OK Capability completed.\r\n') - def gotCapabilities(capabilities): - self.assertEqual( - capabilities, {'IMAP4rev1': None, 'LOGINDISABLED': None}) - capabilitiesResult.addCallback(gotCapabilities) - return capabilitiesResult - - - def test_categoryAtoms(self): - """ - A capability response consisting of atoms including C{'='} should have - those atoms split on that byte and have capabilities in the same - category aggregated into lists in the resulting dictionary. - - (n.b. - I made up the word "category atom"; the protocol has no notion - of structure here, but rather allows each capability to define the - semantics of its entry in the capability response in a freeform manner. - If I had realized this earlier, the API for capabilities would look - different. As it is, we can hope that no one defines any crazy - semantics which are incompatible with this API, or try to figure out a - better API when someone does. -exarkun) - """ - capabilitiesResult = self.protocol.getCapabilities(useCache=False) - self.protocol.dataReceived('* CAPABILITY IMAP4rev1 AUTH=LOGIN AUTH=PLAIN\r\n') - self.protocol.dataReceived('0001 OK Capability completed.\r\n') - def gotCapabilities(capabilities): - self.assertEqual( - capabilities, {'IMAP4rev1': None, 'AUTH': ['LOGIN', 'PLAIN']}) - capabilitiesResult.addCallback(gotCapabilities) - return capabilitiesResult - - - def test_mixedAtoms(self): - """ - A capability response consisting of both simple and category atoms of - the same type should result in a list containing C{None} as well as the - values for the category. - """ - capabilitiesResult = self.protocol.getCapabilities(useCache=False) - # Exercise codepath for both orderings of =-having and =-missing - # capabilities. - self.protocol.dataReceived( - '* CAPABILITY IMAP4rev1 FOO FOO=BAR BAR=FOO BAR\r\n') - self.protocol.dataReceived('0001 OK Capability completed.\r\n') - def gotCapabilities(capabilities): - self.assertEqual(capabilities, {'IMAP4rev1': None, - 'FOO': [None, 'BAR'], - 'BAR': ['FOO', None]}) - capabilitiesResult.addCallback(gotCapabilities) - return capabilitiesResult - - - -class StillSimplerClient(imap4.IMAP4Client): - """ - An IMAP4 client which keeps track of unsolicited flag changes. - """ - def __init__(self): - imap4.IMAP4Client.__init__(self) - self.flags = {} - - - def flagsChanged(self, newFlags): - self.flags.update(newFlags) - - - -class HandCraftedTests(IMAP4HelperMixin, unittest.TestCase): - def testTrailingLiteral(self): - transport = StringTransport() - c = imap4.IMAP4Client() - c.makeConnection(transport) - c.lineReceived('* OK [IMAP4rev1]') - - def cbSelect(ignored): - d = c.fetchMessage('1') - c.dataReceived('* 1 FETCH (RFC822 {10}\r\n0123456789\r\n RFC822.SIZE 10)\r\n') - c.dataReceived('0003 OK FETCH\r\n') - return d - - def cbLogin(ignored): - d = c.select('inbox') - c.lineReceived('0002 OK SELECT') - d.addCallback(cbSelect) - return d - - d = c.login('blah', 'blah') - c.dataReceived('0001 OK LOGIN\r\n') - d.addCallback(cbLogin) - return d - - - def testPathelogicalScatteringOfLiterals(self): - self.server.checker.addUser('testuser', 'password-test') - transport = StringTransport() - self.server.makeConnection(transport) - - transport.clear() - self.server.dataReceived("01 LOGIN {8}\r\n") - self.assertEqual(transport.value(), "+ Ready for 8 octets of text\r\n") - - transport.clear() - self.server.dataReceived("testuser {13}\r\n") - self.assertEqual(transport.value(), "+ Ready for 13 octets of text\r\n") - - transport.clear() - self.server.dataReceived("password-test\r\n") - self.assertEqual(transport.value(), "01 OK LOGIN succeeded\r\n") - self.assertEqual(self.server.state, 'auth') - - self.server.connectionLost(error.ConnectionDone("Connection done.")) - - - def test_unsolicitedResponseMixedWithSolicitedResponse(self): - """ - If unsolicited data is received along with solicited data in the - response to a I{FETCH} command issued by L{IMAP4Client.fetchSpecific}, - the unsolicited data is passed to the appropriate callback and not - included in the result with which the L{Deferred} returned by - L{IMAP4Client.fetchSpecific} fires. - """ - transport = StringTransport() - c = StillSimplerClient() - c.makeConnection(transport) - c.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = c.login('blah', 'blah') - c.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = c.select('inbox') - c.lineReceived('0002 OK SELECT') - return d - def fetch(): - d = c.fetchSpecific('1:*', - headerType='HEADER.FIELDS', - headerArgs=['SUBJECT']) - c.dataReceived('* 1 FETCH (BODY[HEADER.FIELDS ("SUBJECT")] {38}\r\n') - c.dataReceived('Subject: Suprise for your woman...\r\n') - c.dataReceived('\r\n') - c.dataReceived(')\r\n') - c.dataReceived('* 1 FETCH (FLAGS (\Seen))\r\n') - c.dataReceived('* 2 FETCH (BODY[HEADER.FIELDS ("SUBJECT")] {75}\r\n') - c.dataReceived('Subject: What you been doing. Order your meds here . ,. handcuff madsen\r\n') - c.dataReceived('\r\n') - c.dataReceived(')\r\n') - c.dataReceived('0003 OK FETCH completed\r\n') - return d - def test(res): - self.assertEqual(res, { - 1: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], - 'Subject: Suprise for your woman...\r\n\r\n']], - 2: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], - 'Subject: What you been doing. Order your meds here . ,. handcuff madsen\r\n\r\n']] - }) - - self.assertEqual(c.flags, {1: ['\\Seen']}) - - return login( - ).addCallback(strip(select) - ).addCallback(strip(fetch) - ).addCallback(test) - - - def test_literalWithoutPrecedingWhitespace(self): - """ - Literals should be recognized even when they are not preceded by - whitespace. - """ - transport = StringTransport() - protocol = imap4.IMAP4Client() - - protocol.makeConnection(transport) - protocol.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = protocol.login('blah', 'blah') - protocol.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = protocol.select('inbox') - protocol.lineReceived('0002 OK SELECT') - return d - def fetch(): - d = protocol.fetchSpecific('1:*', - headerType='HEADER.FIELDS', - headerArgs=['SUBJECT']) - protocol.dataReceived( - '* 1 FETCH (BODY[HEADER.FIELDS ({7}\r\nSUBJECT)] "Hello")\r\n') - protocol.dataReceived('0003 OK FETCH completed\r\n') - return d - def test(result): - self.assertEqual( - result, {1: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], 'Hello']]}) - - d = login() - d.addCallback(strip(select)) - d.addCallback(strip(fetch)) - d.addCallback(test) - return d - - - def test_nonIntegerLiteralLength(self): - """ - If the server sends a literal length which cannot be parsed as an - integer, L{IMAP4Client.lineReceived} should cause the protocol to be - disconnected by raising L{imap4.IllegalServerResponse}. - """ - transport = StringTransport() - protocol = imap4.IMAP4Client() - - protocol.makeConnection(transport) - protocol.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = protocol.login('blah', 'blah') - protocol.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = protocol.select('inbox') - protocol.lineReceived('0002 OK SELECT') - return d - def fetch(): - protocol.fetchSpecific( - '1:*', - headerType='HEADER.FIELDS', - headerArgs=['SUBJECT']) - self.assertRaises( - imap4.IllegalServerResponse, - protocol.dataReceived, - '* 1 FETCH {xyz}\r\n...') - d = login() - d.addCallback(strip(select)) - d.addCallback(strip(fetch)) - return d - - - def test_flagsChangedInsideFetchSpecificResponse(self): - """ - Any unrequested flag information received along with other requested - information in an untagged I{FETCH} received in response to a request - issued with L{IMAP4Client.fetchSpecific} is passed to the - C{flagsChanged} callback. - """ - transport = StringTransport() - c = StillSimplerClient() - c.makeConnection(transport) - c.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = c.login('blah', 'blah') - c.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = c.select('inbox') - c.lineReceived('0002 OK SELECT') - return d - def fetch(): - d = c.fetchSpecific('1:*', - headerType='HEADER.FIELDS', - headerArgs=['SUBJECT']) - # This response includes FLAGS after the requested data. - c.dataReceived('* 1 FETCH (BODY[HEADER.FIELDS ("SUBJECT")] {22}\r\n') - c.dataReceived('Subject: subject one\r\n') - c.dataReceived(' FLAGS (\\Recent))\r\n') - # And this one includes it before! Either is possible. - c.dataReceived('* 2 FETCH (FLAGS (\\Seen) BODY[HEADER.FIELDS ("SUBJECT")] {22}\r\n') - c.dataReceived('Subject: subject two\r\n') - c.dataReceived(')\r\n') - c.dataReceived('0003 OK FETCH completed\r\n') - return d - - def test(res): - self.assertEqual(res, { - 1: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], - 'Subject: subject one\r\n']], - 2: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], - 'Subject: subject two\r\n']] - }) - - self.assertEqual(c.flags, {1: ['\\Recent'], 2: ['\\Seen']}) - - return login( - ).addCallback(strip(select) - ).addCallback(strip(fetch) - ).addCallback(test) - - - def test_flagsChangedInsideFetchMessageResponse(self): - """ - Any unrequested flag information received along with other requested - information in an untagged I{FETCH} received in response to a request - issued with L{IMAP4Client.fetchMessage} is passed to the - C{flagsChanged} callback. - """ - transport = StringTransport() - c = StillSimplerClient() - c.makeConnection(transport) - c.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = c.login('blah', 'blah') - c.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = c.select('inbox') - c.lineReceived('0002 OK SELECT') - return d - def fetch(): - d = c.fetchMessage('1:*') - c.dataReceived('* 1 FETCH (RFC822 {24}\r\n') - c.dataReceived('Subject: first subject\r\n') - c.dataReceived(' FLAGS (\Seen))\r\n') - c.dataReceived('* 2 FETCH (FLAGS (\Recent \Seen) RFC822 {25}\r\n') - c.dataReceived('Subject: second subject\r\n') - c.dataReceived(')\r\n') - c.dataReceived('0003 OK FETCH completed\r\n') - return d - - def test(res): - self.assertEqual(res, { - 1: {'RFC822': 'Subject: first subject\r\n'}, - 2: {'RFC822': 'Subject: second subject\r\n'}}) - - self.assertEqual( - c.flags, {1: ['\\Seen'], 2: ['\\Recent', '\\Seen']}) - - return login( - ).addCallback(strip(select) - ).addCallback(strip(fetch) - ).addCallback(test) - - - def test_authenticationChallengeDecodingException(self): - """ - When decoding a base64 encoded authentication message from the server, - decoding errors are logged and then the client closes the connection. - """ - transport = StringTransportWithDisconnection() - protocol = imap4.IMAP4Client() - transport.protocol = protocol - - protocol.makeConnection(transport) - protocol.lineReceived( - '* OK [CAPABILITY IMAP4rev1 IDLE NAMESPACE AUTH=CRAM-MD5] ' - 'Twisted IMAP4rev1 Ready') - cAuth = imap4.CramMD5ClientAuthenticator('testuser') - protocol.registerAuthenticator(cAuth) - - d = protocol.authenticate('secret') - # Should really be something describing the base64 decode error. See - # #6021. - self.assertFailure(d, error.ConnectionDone) - - protocol.dataReceived('+ Something bad! and bad\r\n') - - # This should not really be logged. See #6021. - logged = self.flushLoggedErrors(imap4.IllegalServerResponse) - self.assertEqual(len(logged), 1) - self.assertEqual(logged[0].value.args[0], "Something bad! and bad") - return d - - - -class PreauthIMAP4ClientMixin: - """ - Mixin for L{unittest.TestCase} subclasses which provides a C{setUp} method - which creates an L{IMAP4Client} connected to a L{StringTransport} and puts - it into the I{authenticated} state. - - @ivar transport: A L{StringTransport} to which C{client} is connected. - @ivar client: An L{IMAP4Client} which is connected to C{transport}. - """ - clientProtocol = imap4.IMAP4Client - - def setUp(self): - """ - Create an IMAP4Client connected to a fake transport and in the - authenticated state. - """ - self.transport = StringTransport() - self.client = self.clientProtocol() - self.client.makeConnection(self.transport) - self.client.dataReceived('* PREAUTH Hello unittest\r\n') - - - def _extractDeferredResult(self, d): - """ - Synchronously extract the result of the given L{Deferred}. Fail the - test if that is not possible. - """ - result = [] - error = [] - d.addCallbacks(result.append, error.append) - if result: - return result[0] - elif error: - error[0].raiseException() - else: - self.fail("Expected result not available") - - - -class SelectionTestsMixin(PreauthIMAP4ClientMixin): - """ - Mixin for test cases which defines tests which apply to both I{EXAMINE} and - I{SELECT} support. - """ - def _examineOrSelect(self): - """ - Issue either an I{EXAMINE} or I{SELECT} command (depending on - C{self.method}), assert that the correct bytes are written to the - transport, and return the L{Deferred} returned by whichever method was - called. - """ - d = getattr(self.client, self.method)('foobox') - self.assertEqual( - self.transport.value(), '0001 %s foobox\r\n' % (self.command,)) - return d - - - def _response(self, *lines): - """ - Deliver the given (unterminated) response lines to C{self.client} and - then deliver a tagged SELECT or EXAMINE completion line to finish the - SELECT or EXAMINE response. - """ - for line in lines: - self.client.dataReceived(line + '\r\n') - self.client.dataReceived( - '0001 OK [READ-ONLY] %s completed\r\n' % (self.command,)) - - - def test_exists(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{EXISTS} response, the L{Deferred} return by L{IMAP4Client.select} or - L{IMAP4Client.examine} fires with a C{dict} including the value - associated with the C{'EXISTS'} key. - """ - d = self._examineOrSelect() - self._response('* 3 EXISTS') - self.assertEqual( - self._extractDeferredResult(d), - {'READ-WRITE': False, 'EXISTS': 3}) - - - def test_nonIntegerExists(self): - """ - If the server returns a non-integer EXISTS value in its response to a - I{SELECT} or I{EXAMINE} command, the L{Deferred} returned by - L{IMAP4Client.select} or L{IMAP4Client.examine} fails with - L{IllegalServerResponse}. - """ - d = self._examineOrSelect() - self._response('* foo EXISTS') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_recent(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{RECENT} response, the L{Deferred} return by L{IMAP4Client.select} or - L{IMAP4Client.examine} fires with a C{dict} including the value - associated with the C{'RECENT'} key. - """ - d = self._examineOrSelect() - self._response('* 5 RECENT') - self.assertEqual( - self._extractDeferredResult(d), - {'READ-WRITE': False, 'RECENT': 5}) - - - def test_nonIntegerRecent(self): - """ - If the server returns a non-integer RECENT value in its response to a - I{SELECT} or I{EXAMINE} command, the L{Deferred} returned by - L{IMAP4Client.select} or L{IMAP4Client.examine} fails with - L{IllegalServerResponse}. - """ - d = self._examineOrSelect() - self._response('* foo RECENT') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_unseen(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{UNSEEN} response, the L{Deferred} returned by L{IMAP4Client.select} or - L{IMAP4Client.examine} fires with a C{dict} including the value - associated with the C{'UNSEEN'} key. - """ - d = self._examineOrSelect() - self._response('* OK [UNSEEN 8] Message 8 is first unseen') - self.assertEqual( - self._extractDeferredResult(d), - {'READ-WRITE': False, 'UNSEEN': 8}) - - - def test_nonIntegerUnseen(self): - """ - If the server returns a non-integer UNSEEN value in its response to a - I{SELECT} or I{EXAMINE} command, the L{Deferred} returned by - L{IMAP4Client.select} or L{IMAP4Client.examine} fails with - L{IllegalServerResponse}. - """ - d = self._examineOrSelect() - self._response('* OK [UNSEEN foo] Message foo is first unseen') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_uidvalidity(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{UIDVALIDITY} response, the L{Deferred} returned by - L{IMAP4Client.select} or L{IMAP4Client.examine} fires with a C{dict} - including the value associated with the C{'UIDVALIDITY'} key. - """ - d = self._examineOrSelect() - self._response('* OK [UIDVALIDITY 12345] UIDs valid') - self.assertEqual( - self._extractDeferredResult(d), - {'READ-WRITE': False, 'UIDVALIDITY': 12345}) - - - def test_nonIntegerUIDVALIDITY(self): - """ - If the server returns a non-integer UIDVALIDITY value in its response to - a I{SELECT} or I{EXAMINE} command, the L{Deferred} returned by - L{IMAP4Client.select} or L{IMAP4Client.examine} fails with - L{IllegalServerResponse}. - """ - d = self._examineOrSelect() - self._response('* OK [UIDVALIDITY foo] UIDs valid') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_uidnext(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{UIDNEXT} response, the L{Deferred} returned by L{IMAP4Client.select} - or L{IMAP4Client.examine} fires with a C{dict} including the value - associated with the C{'UIDNEXT'} key. - """ - d = self._examineOrSelect() - self._response('* OK [UIDNEXT 4392] Predicted next UID') - self.assertEqual( - self._extractDeferredResult(d), - {'READ-WRITE': False, 'UIDNEXT': 4392}) - - - def test_nonIntegerUIDNEXT(self): - """ - If the server returns a non-integer UIDNEXT value in its response to a - I{SELECT} or I{EXAMINE} command, the L{Deferred} returned by - L{IMAP4Client.select} or L{IMAP4Client.examine} fails with - L{IllegalServerResponse}. - """ - d = self._examineOrSelect() - self._response('* OK [UIDNEXT foo] Predicted next UID') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_flags(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{FLAGS} response, the L{Deferred} returned by L{IMAP4Client.select} or - L{IMAP4Client.examine} fires with a C{dict} including the value - associated with the C{'FLAGS'} key. - """ - d = self._examineOrSelect() - self._response( - '* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)') - self.assertEqual( - self._extractDeferredResult(d), { - 'READ-WRITE': False, - 'FLAGS': ('\\Answered', '\\Flagged', '\\Deleted', '\\Seen', - '\\Draft')}) - - - def test_permanentflags(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{FLAGS} response, the L{Deferred} returned by L{IMAP4Client.select} or - L{IMAP4Client.examine} fires with a C{dict} including the value - associated with the C{'FLAGS'} key. - """ - d = self._examineOrSelect() - self._response( - '* OK [PERMANENTFLAGS (\\Starred)] Just one permanent flag in ' - 'that list up there') - self.assertEqual( - self._extractDeferredResult(d), { - 'READ-WRITE': False, - 'PERMANENTFLAGS': ('\\Starred',)}) - - - def test_unrecognizedOk(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{OK} with unrecognized response code text, parsing does not fail. - """ - d = self._examineOrSelect() - self._response( - '* OK [X-MADE-UP] I just made this response text up.') - # The value won't show up in the result. It would be okay if it did - # someday, perhaps. This shouldn't ever happen, though. - self.assertEqual( - self._extractDeferredResult(d), {'READ-WRITE': False}) - - - def test_bareOk(self): - """ - If the server response to a I{SELECT} or I{EXAMINE} command includes an - I{OK} with no response code text, parsing does not fail. - """ - d = self._examineOrSelect() - self._response('* OK') - self.assertEqual( - self._extractDeferredResult(d), {'READ-WRITE': False}) - - - -class IMAP4ClientExamineTests(SelectionTestsMixin, unittest.TestCase): - """ - Tests for the L{IMAP4Client.examine} method. - - An example of usage of the EXAMINE command from RFC 3501, section 6.3.2:: - - S: * 17 EXISTS - S: * 2 RECENT - S: * OK [UNSEEN 8] Message 8 is first unseen - S: * OK [UIDVALIDITY 3857529045] UIDs valid - S: * OK [UIDNEXT 4392] Predicted next UID - S: * FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft) - S: * OK [PERMANENTFLAGS ()] No permanent flags permitted - S: A932 OK [READ-ONLY] EXAMINE completed - """ - method = 'examine' - command = 'EXAMINE' - - - - -class IMAP4ClientSelectTests(SelectionTestsMixin, unittest.TestCase): - """ - Tests for the L{IMAP4Client.select} method. - - An example of usage of the SELECT command from RFC 3501, section 6.3.1:: - - C: A142 SELECT INBOX - S: * 172 EXISTS - S: * 1 RECENT - S: * OK [UNSEEN 12] Message 12 is first unseen - S: * OK [UIDVALIDITY 3857529045] UIDs valid - S: * OK [UIDNEXT 4392] Predicted next UID - S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) - S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited - S: A142 OK [READ-WRITE] SELECT completed - """ - method = 'select' - command = 'SELECT' - - - -class IMAP4ClientExpungeTests(PreauthIMAP4ClientMixin, unittest.TestCase): - """ - Tests for the L{IMAP4Client.expunge} method. - - An example of usage of the EXPUNGE command from RFC 3501, section 6.4.3:: - - C: A202 EXPUNGE - S: * 3 EXPUNGE - S: * 3 EXPUNGE - S: * 5 EXPUNGE - S: * 8 EXPUNGE - S: A202 OK EXPUNGE completed - """ - def _expunge(self): - d = self.client.expunge() - self.assertEqual(self.transport.value(), '0001 EXPUNGE\r\n') - self.transport.clear() - return d - - - def _response(self, sequenceNumbers): - for number in sequenceNumbers: - self.client.lineReceived('* %s EXPUNGE' % (number,)) - self.client.lineReceived('0001 OK EXPUNGE COMPLETED') - - - def test_expunge(self): - """ - L{IMAP4Client.expunge} sends the I{EXPUNGE} command and returns a - L{Deferred} which fires with a C{list} of message sequence numbers - given by the server's response. - """ - d = self._expunge() - self._response([3, 3, 5, 8]) - self.assertEqual(self._extractDeferredResult(d), [3, 3, 5, 8]) - - - def test_nonIntegerExpunged(self): - """ - If the server responds with a non-integer where a message sequence - number is expected, the L{Deferred} returned by L{IMAP4Client.expunge} - fails with L{IllegalServerResponse}. - """ - d = self._expunge() - self._response([3, 3, 'foo', 8]) - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - -class IMAP4ClientSearchTests(PreauthIMAP4ClientMixin, unittest.TestCase): - """ - Tests for the L{IMAP4Client.search} method. - - An example of usage of the SEARCH command from RFC 3501, section 6.4.4:: - - C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith" - S: * SEARCH 2 84 882 - S: A282 OK SEARCH completed - C: A283 SEARCH TEXT "string not in mailbox" - S: * SEARCH - S: A283 OK SEARCH completed - C: A284 SEARCH CHARSET UTF-8 TEXT {6} - C: XXXXXX - S: * SEARCH 43 - S: A284 OK SEARCH completed - """ - def _search(self): - d = self.client.search(imap4.Query(text="ABCDEF")) - self.assertEqual( - self.transport.value(), '0001 SEARCH (TEXT "ABCDEF")\r\n') - return d - - - def _response(self, messageNumbers): - self.client.lineReceived( - "* SEARCH " + " ".join(map(str, messageNumbers))) - self.client.lineReceived("0001 OK SEARCH completed") - - - def test_search(self): - """ - L{IMAP4Client.search} sends the I{SEARCH} command and returns a - L{Deferred} which fires with a C{list} of message sequence numbers - given by the server's response. - """ - d = self._search() - self._response([2, 5, 10]) - self.assertEqual(self._extractDeferredResult(d), [2, 5, 10]) - - - def test_nonIntegerFound(self): - """ - If the server responds with a non-integer where a message sequence - number is expected, the L{Deferred} returned by L{IMAP4Client.search} - fails with L{IllegalServerResponse}. - """ - d = self._search() - self._response([2, "foo", 10]) - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - -class IMAP4ClientFetchTests(PreauthIMAP4ClientMixin, unittest.TestCase): - """ - Tests for the L{IMAP4Client.fetch} method. - - See RFC 3501, section 6.4.5. - """ - def test_fetchUID(self): - """ - L{IMAP4Client.fetchUID} sends the I{FETCH UID} command and returns a - L{Deferred} which fires with a C{dict} mapping message sequence numbers - to C{dict}s mapping C{'UID'} to that message's I{UID} in the server's - response. - """ - d = self.client.fetchUID('1:7') - self.assertEqual(self.transport.value(), '0001 FETCH 1:7 (UID)\r\n') - self.client.lineReceived('* 2 FETCH (UID 22)') - self.client.lineReceived('* 3 FETCH (UID 23)') - self.client.lineReceived('* 4 FETCH (UID 24)') - self.client.lineReceived('* 5 FETCH (UID 25)') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), { - 2: {'UID': '22'}, - 3: {'UID': '23'}, - 4: {'UID': '24'}, - 5: {'UID': '25'}}) - - - def test_fetchUIDNonIntegerFound(self): - """ - If the server responds with a non-integer where a message sequence - number is expected, the L{Deferred} returned by L{IMAP4Client.fetchUID} - fails with L{IllegalServerResponse}. - """ - d = self.client.fetchUID('1') - self.assertEqual(self.transport.value(), '0001 FETCH 1 (UID)\r\n') - self.client.lineReceived('* foo FETCH (UID 22)') - self.client.lineReceived('0001 OK FETCH completed') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_incompleteFetchUIDResponse(self): - """ - If the server responds with an incomplete I{FETCH} response line, the - L{Deferred} returned by L{IMAP4Client.fetchUID} fails with - L{IllegalServerResponse}. - """ - d = self.client.fetchUID('1:7') - self.assertEqual(self.transport.value(), '0001 FETCH 1:7 (UID)\r\n') - self.client.lineReceived('* 2 FETCH (UID 22)') - self.client.lineReceived('* 3 FETCH (UID)') - self.client.lineReceived('* 4 FETCH (UID 24)') - self.client.lineReceived('0001 OK FETCH completed') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_fetchBody(self): - """ - L{IMAP4Client.fetchBody} sends the I{FETCH BODY} command and returns a - L{Deferred} which fires with a C{dict} mapping message sequence numbers - to C{dict}s mapping C{'RFC822.TEXT'} to that message's body as given in - the server's response. - """ - d = self.client.fetchBody('3') - self.assertEqual( - self.transport.value(), '0001 FETCH 3 (RFC822.TEXT)\r\n') - self.client.lineReceived('* 3 FETCH (RFC822.TEXT "Message text")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), - {3: {'RFC822.TEXT': 'Message text'}}) - - - def test_fetchSpecific(self): - """ - L{IMAP4Client.fetchSpecific} sends the I{BODY[]} command if no - parameters beyond the message set to retrieve are given. It returns a - L{Deferred} which fires with a C{dict} mapping message sequence numbers - to C{list}s of corresponding message data given by the server's - response. - """ - d = self.client.fetchSpecific('7') - self.assertEqual( - self.transport.value(), '0001 FETCH 7 BODY[]\r\n') - self.client.lineReceived('* 7 FETCH (BODY[] "Some body")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), {7: [['BODY', [], "Some body"]]}) - - - def test_fetchSpecificPeek(self): - """ - L{IMAP4Client.fetchSpecific} issues a I{BODY.PEEK[]} command if passed - C{True} for the C{peek} parameter. - """ - d = self.client.fetchSpecific('6', peek=True) - self.assertEqual( - self.transport.value(), '0001 FETCH 6 BODY.PEEK[]\r\n') - # BODY.PEEK responses are just BODY - self.client.lineReceived('* 6 FETCH (BODY[] "Some body")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), {6: [['BODY', [], "Some body"]]}) - - - def test_fetchSpecificNumbered(self): - """ - L{IMAP4Client.fetchSpecific}, when passed a sequence for - C{headerNumber}, sends the I{BODY[N.M]} command. It returns a - L{Deferred} which fires with a C{dict} mapping message sequence numbers - to C{list}s of corresponding message data given by the server's - response. - """ - d = self.client.fetchSpecific('7', headerNumber=(1, 2, 3)) - self.assertEqual( - self.transport.value(), '0001 FETCH 7 BODY[1.2.3]\r\n') - self.client.lineReceived('* 7 FETCH (BODY[1.2.3] "Some body")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), - {7: [['BODY', ['1.2.3'], "Some body"]]}) - - - def test_fetchSpecificText(self): - """ - L{IMAP4Client.fetchSpecific}, when passed C{'TEXT'} for C{headerType}, - sends the I{BODY[TEXT]} command. It returns a L{Deferred} which fires - with a C{dict} mapping message sequence numbers to C{list}s of - corresponding message data given by the server's response. - """ - d = self.client.fetchSpecific('8', headerType='TEXT') - self.assertEqual( - self.transport.value(), '0001 FETCH 8 BODY[TEXT]\r\n') - self.client.lineReceived('* 8 FETCH (BODY[TEXT] "Some body")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), - {8: [['BODY', ['TEXT'], "Some body"]]}) - - - def test_fetchSpecificNumberedText(self): - """ - If passed a value for the C{headerNumber} parameter and C{'TEXT'} for - the C{headerType} parameter, L{IMAP4Client.fetchSpecific} sends a - I{BODY[number.TEXT]} request and returns a L{Deferred} which fires with - a C{dict} mapping message sequence numbers to C{list}s of message data - given by the server's response. - """ - d = self.client.fetchSpecific('4', headerType='TEXT', headerNumber=7) - self.assertEqual( - self.transport.value(), '0001 FETCH 4 BODY[7.TEXT]\r\n') - self.client.lineReceived('* 4 FETCH (BODY[7.TEXT] "Some body")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), - {4: [['BODY', ['7.TEXT'], "Some body"]]}) - - - def test_incompleteFetchSpecificTextResponse(self): - """ - If the server responds to a I{BODY[TEXT]} request with a I{FETCH} line - which is truncated after the I{BODY[TEXT]} tokens, the L{Deferred} - returned by L{IMAP4Client.fetchUID} fails with - L{IllegalServerResponse}. - """ - d = self.client.fetchSpecific('8', headerType='TEXT') - self.assertEqual( - self.transport.value(), '0001 FETCH 8 BODY[TEXT]\r\n') - self.client.lineReceived('* 8 FETCH (BODY[TEXT])') - self.client.lineReceived('0001 OK FETCH completed') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_fetchSpecificMIME(self): - """ - L{IMAP4Client.fetchSpecific}, when passed C{'MIME'} for C{headerType}, - sends the I{BODY[MIME]} command. It returns a L{Deferred} which fires - with a C{dict} mapping message sequence numbers to C{list}s of - corresponding message data given by the server's response. - """ - d = self.client.fetchSpecific('8', headerType='MIME') - self.assertEqual( - self.transport.value(), '0001 FETCH 8 BODY[MIME]\r\n') - self.client.lineReceived('* 8 FETCH (BODY[MIME] "Some body")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), - {8: [['BODY', ['MIME'], "Some body"]]}) - - - def test_fetchSpecificPartial(self): - """ - L{IMAP4Client.fetchSpecific}, when passed C{offset} and C{length}, - sends a partial content request (like I{BODY[TEXT]}). - It returns a L{Deferred} which fires with a C{dict} mapping message - sequence numbers to C{list}s of corresponding message data given by the - server's response. - """ - d = self.client.fetchSpecific( - '9', headerType='TEXT', offset=17, length=3) - self.assertEqual( - self.transport.value(), '0001 FETCH 9 BODY[TEXT]<17.3>\r\n') - self.client.lineReceived('* 9 FETCH (BODY[TEXT]<17> "foo")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), - {9: [['BODY', ['TEXT'], '<17>', 'foo']]}) - - - def test_incompleteFetchSpecificPartialResponse(self): - """ - If the server responds to a I{BODY[TEXT]} request with a I{FETCH} line - which is truncated after the I{BODY[TEXT]} tokens, the - L{Deferred} returned by L{IMAP4Client.fetchUID} fails with - L{IllegalServerResponse}. - """ - d = self.client.fetchSpecific('8', headerType='TEXT') - self.assertEqual( - self.transport.value(), '0001 FETCH 8 BODY[TEXT]\r\n') - self.client.lineReceived('* 8 FETCH (BODY[TEXT]<17>)') - self.client.lineReceived('0001 OK FETCH completed') - self.assertRaises( - imap4.IllegalServerResponse, self._extractDeferredResult, d) - - - def test_fetchSpecificHTML(self): - """ - If the body of a message begins with I{<} and ends with I{>} (as, - for example, HTML bodies typically will), this is still interpreted - as the body by L{IMAP4Client.fetchSpecific} (and particularly, not - as a length indicator for a response to a request for a partial - body). - """ - d = self.client.fetchSpecific('7') - self.assertEqual( - self.transport.value(), '0001 FETCH 7 BODY[]\r\n') - self.client.lineReceived('* 7 FETCH (BODY[] "test")') - self.client.lineReceived('0001 OK FETCH completed') - self.assertEqual( - self._extractDeferredResult(d), {7: [['BODY', [], "test"]]}) - - - -class IMAP4ClientStoreTests(PreauthIMAP4ClientMixin, unittest.TestCase): - """ - Tests for the L{IMAP4Client.setFlags}, L{IMAP4Client.addFlags}, and - L{IMAP4Client.removeFlags} methods. - - An example of usage of the STORE command, in terms of which these three - methods are implemented, from RFC 3501, section 6.4.6:: - - C: A003 STORE 2:4 +FLAGS (\Deleted) - S: * 2 FETCH (FLAGS (\Deleted \Seen)) - S: * 3 FETCH (FLAGS (\Deleted)) - S: * 4 FETCH (FLAGS (\Deleted \Flagged \Seen)) - S: A003 OK STORE completed - """ - clientProtocol = StillSimplerClient - - def _flagsTest(self, method, item): - """ - Test a non-silent flag modifying method. Call the method, assert that - the correct bytes are sent, deliver a I{FETCH} response, and assert - that the result of the Deferred returned by the method is correct. - - @param method: The name of the method to test. - @param item: The data item which is expected to be specified. - """ - d = getattr(self.client, method)('3', ('\\Read', '\\Seen'), False) - self.assertEqual( - self.transport.value(), - '0001 STORE 3 ' + item + ' (\\Read \\Seen)\r\n') - self.client.lineReceived('* 3 FETCH (FLAGS (\\Read \\Seen))') - self.client.lineReceived('0001 OK STORE completed') - self.assertEqual( - self._extractDeferredResult(d), - {3: {'FLAGS': ['\\Read', '\\Seen']}}) - - - def _flagsSilentlyTest(self, method, item): - """ - Test a silent flag modifying method. Call the method, assert that the - correct bytes are sent, deliver an I{OK} response, and assert that the - result of the Deferred returned by the method is correct. - - @param method: The name of the method to test. - @param item: The data item which is expected to be specified. - """ - d = getattr(self.client, method)('3', ('\\Read', '\\Seen'), True) - self.assertEqual( - self.transport.value(), - '0001 STORE 3 ' + item + ' (\\Read \\Seen)\r\n') - self.client.lineReceived('0001 OK STORE completed') - self.assertEqual(self._extractDeferredResult(d), {}) - - - def _flagsSilentlyWithUnsolicitedDataTest(self, method, item): - """ - Test unsolicited data received in response to a silent flag modifying - method. Call the method, assert that the correct bytes are sent, - deliver the unsolicited I{FETCH} response, and assert that the result - of the Deferred returned by the method is correct. - - @param method: The name of the method to test. - @param item: The data item which is expected to be specified. - """ - d = getattr(self.client, method)('3', ('\\Read', '\\Seen'), True) - self.assertEqual( - self.transport.value(), - '0001 STORE 3 ' + item + ' (\\Read \\Seen)\r\n') - self.client.lineReceived('* 2 FETCH (FLAGS (\\Read \\Seen))') - self.client.lineReceived('0001 OK STORE completed') - self.assertEqual(self._extractDeferredResult(d), {}) - self.assertEqual(self.client.flags, {2: ['\\Read', '\\Seen']}) - - - def test_setFlags(self): - """ - When passed a C{False} value for the C{silent} parameter, - L{IMAP4Client.setFlags} sends the I{STORE} command with a I{FLAGS} data - item and returns a L{Deferred} which fires with a C{dict} mapping - message sequence numbers to C{dict}s mapping C{'FLAGS'} to the new - flags of those messages. - """ - self._flagsTest('setFlags', 'FLAGS') - - - def test_setFlagsSilently(self): - """ - When passed a C{True} value for the C{silent} parameter, - L{IMAP4Client.setFlags} sends the I{STORE} command with a - I{FLAGS.SILENT} data item and returns a L{Deferred} which fires with an - empty dictionary. - """ - self._flagsSilentlyTest('setFlags', 'FLAGS.SILENT') - - - def test_setFlagsSilentlyWithUnsolicitedData(self): - """ - If unsolicited flag data is received in response to a I{STORE} - I{FLAGS.SILENT} request, that data is passed to the C{flagsChanged} - callback. - """ - self._flagsSilentlyWithUnsolicitedDataTest('setFlags', 'FLAGS.SILENT') - - - def test_addFlags(self): - """ - L{IMAP4Client.addFlags} is like L{IMAP4Client.setFlags}, but sends - I{+FLAGS} instead of I{FLAGS}. - """ - self._flagsTest('addFlags', '+FLAGS') - - - def test_addFlagsSilently(self): - """ - L{IMAP4Client.addFlags} with a C{True} value for C{silent} behaves like - L{IMAP4Client.setFlags} with a C{True} value for C{silent}, but it - sends I{+FLAGS.SILENT} instead of I{FLAGS.SILENT}. - """ - self._flagsSilentlyTest('addFlags', '+FLAGS.SILENT') - - - def test_addFlagsSilentlyWithUnsolicitedData(self): - """ - L{IMAP4Client.addFlags} behaves like L{IMAP4Client.setFlags} when used - in silent mode and unsolicited data is received. - """ - self._flagsSilentlyWithUnsolicitedDataTest('addFlags', '+FLAGS.SILENT') - - - def test_removeFlags(self): - """ - L{IMAP4Client.removeFlags} is like L{IMAP4Client.setFlags}, but sends - I{-FLAGS} instead of I{FLAGS}. - """ - self._flagsTest('removeFlags', '-FLAGS') - - - def test_removeFlagsSilently(self): - """ - L{IMAP4Client.removeFlags} with a C{True} value for C{silent} behaves - like L{IMAP4Client.setFlags} with a C{True} value for C{silent}, but it - sends I{-FLAGS.SILENT} instead of I{FLAGS.SILENT}. - """ - self._flagsSilentlyTest('removeFlags', '-FLAGS.SILENT') - - - def test_removeFlagsSilentlyWithUnsolicitedData(self): - """ - L{IMAP4Client.removeFlags} behaves like L{IMAP4Client.setFlags} when - used in silent mode and unsolicited data is received. - """ - self._flagsSilentlyWithUnsolicitedDataTest('removeFlags', '-FLAGS.SILENT') - - - -class FakeyServer(imap4.IMAP4Server): - state = 'select' - timeout = None - - def sendServerGreeting(self): - pass - -class FakeyMessage(util.FancyStrMixin): - implements(imap4.IMessage) - - showAttributes = ('headers', 'flags', 'date', 'body', 'uid') - - def __init__(self, headers, flags, date, body, uid, subpart): - self.headers = headers - self.flags = flags - self._body = body - self.size = len(body) - self.date = date - self.uid = uid - self.subpart = subpart - - def getHeaders(self, negate, *names): - self.got_headers = negate, names - return self.headers - - def getFlags(self): - return self.flags - - def getInternalDate(self): - return self.date - - def getBodyFile(self): - return StringIO(self._body) - - def getSize(self): - return self.size - - def getUID(self): - return self.uid - - def isMultipart(self): - return self.subpart is not None - - def getSubPart(self, part): - self.got_subpart = part - return self.subpart[part] - -class NewStoreTests(unittest.TestCase, IMAP4HelperMixin): - result = None - storeArgs = None - - def setUp(self): - self.received_messages = self.received_uid = None - - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.mbox = self - self.connected = defer.Deferred() - self.client = SimpleClient(self.connected) - - def addListener(self, x): - pass - def removeListener(self, x): - pass - - def store(self, *args, **kw): - self.storeArgs = args, kw - return self.response - - def _storeWork(self): - def connected(): - return self.function(self.messages, self.flags, self.silent, self.uid) - def result(R): - self.result = R - - self.connected.addCallback(strip(connected) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - def check(ignored): - self.assertEqual(self.result, self.expected) - self.assertEqual(self.storeArgs, self.expectedArgs) - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(check) - return d - - def testSetFlags(self, uid=0): - self.function = self.client.setFlags - self.messages = '1,5,9' - self.flags = ['\\A', '\\B', 'C'] - self.silent = False - self.uid = uid - self.response = { - 1: ['\\A', '\\B', 'C'], - 5: ['\\A', '\\B', 'C'], - 9: ['\\A', '\\B', 'C'], - } - self.expected = { - 1: {'FLAGS': ['\\A', '\\B', 'C']}, - 5: {'FLAGS': ['\\A', '\\B', 'C']}, - 9: {'FLAGS': ['\\A', '\\B', 'C']}, - } - msg = imap4.MessageSet() - msg.add(1) - msg.add(5) - msg.add(9) - self.expectedArgs = ((msg, ['\\A', '\\B', 'C'], 0), {'uid': 0}) - return self._storeWork() - - - -class GetBodyStructureTests(unittest.TestCase): - """ - Tests for L{imap4.getBodyStructure}, a helper for constructing a list which - directly corresponds to the wire information needed for a I{BODY} or - I{BODYSTRUCTURE} response. - """ - def test_singlePart(self): - """ - L{imap4.getBodyStructure} accepts a L{IMessagePart} provider and returns - a list giving the basic fields for the I{BODY} response for that - message. - """ - body = 'hello, world' - major = 'image' - minor = 'jpeg' - charset = 'us-ascii' - identifier = 'some kind of id' - description = 'great justice' - encoding = 'maximum' - msg = FakeyMessage({ - 'content-type': '%s/%s; charset=%s; x=y' % ( - major, minor, charset), - 'content-id': identifier, - 'content-description': description, - 'content-transfer-encoding': encoding, - }, (), '', body, 123, None) - structure = imap4.getBodyStructure(msg) - self.assertEqual( - [major, minor, ["charset", charset, 'x', 'y'], identifier, - description, encoding, len(body)], - structure) - - - def test_singlePartExtended(self): - """ - L{imap4.getBodyStructure} returns a list giving the basic and extended - fields for a I{BODYSTRUCTURE} response if passed C{True} for the - C{extended} parameter. - """ - body = 'hello, world' - major = 'image' - minor = 'jpeg' - charset = 'us-ascii' - identifier = 'some kind of id' - description = 'great justice' - encoding = 'maximum' - md5 = 'abcdefabcdef' - msg = FakeyMessage({ - 'content-type': '%s/%s; charset=%s; x=y' % ( - major, minor, charset), - 'content-id': identifier, - 'content-description': description, - 'content-transfer-encoding': encoding, - 'content-md5': md5, - 'content-disposition': 'attachment; name=foo; size=bar', - 'content-language': 'fr', - 'content-location': 'France', - }, (), '', body, 123, None) - structure = imap4.getBodyStructure(msg, extended=True) - self.assertEqual( - [major, minor, ["charset", charset, 'x', 'y'], identifier, - description, encoding, len(body), md5, - ['attachment', ['name', 'foo', 'size', 'bar']], 'fr', 'France'], - structure) - - - def test_singlePartWithMissing(self): - """ - For fields with no information contained in the message headers, - L{imap4.getBodyStructure} fills in C{None} values in its result. - """ - major = 'image' - minor = 'jpeg' - body = 'hello, world' - msg = FakeyMessage({ - 'content-type': '%s/%s' % (major, minor), - }, (), '', body, 123, None) - structure = imap4.getBodyStructure(msg, extended=True) - self.assertEqual( - [major, minor, None, None, None, None, len(body), None, None, - None, None], - structure) - - - def test_textPart(self): - """ - For a I{text/*} message, the number of lines in the message body are - included after the common single-part basic fields. - """ - body = 'hello, world\nhow are you?\ngoodbye\n' - major = 'text' - minor = 'jpeg' - charset = 'us-ascii' - identifier = 'some kind of id' - description = 'great justice' - encoding = 'maximum' - msg = FakeyMessage({ - 'content-type': '%s/%s; charset=%s; x=y' % ( - major, minor, charset), - 'content-id': identifier, - 'content-description': description, - 'content-transfer-encoding': encoding, - }, (), '', body, 123, None) - structure = imap4.getBodyStructure(msg) - self.assertEqual( - [major, minor, ["charset", charset, 'x', 'y'], identifier, - description, encoding, len(body), len(body.splitlines())], - structure) - - - def test_rfc822Message(self): - """ - For a I{message/rfc822} message, the common basic fields are followed - by information about the contained message. - """ - body = 'hello, world\nhow are you?\ngoodbye\n' - major = 'text' - minor = 'jpeg' - charset = 'us-ascii' - identifier = 'some kind of id' - description = 'great justice' - encoding = 'maximum' - msg = FakeyMessage({ - 'content-type': '%s/%s; charset=%s; x=y' % ( - major, minor, charset), - 'from': 'Alice ', - 'to': 'Bob ', - 'content-id': identifier, - 'content-description': description, - 'content-transfer-encoding': encoding, - }, (), '', body, 123, None) - - container = FakeyMessage({ - 'content-type': 'message/rfc822', - }, (), '', '', 123, [msg]) - - structure = imap4.getBodyStructure(container) - self.assertEqual( - ['message', 'rfc822', None, None, None, None, 0, - imap4.getEnvelope(msg), imap4.getBodyStructure(msg), 3], - structure) - - - def test_multiPart(self): - """ - For a I{multipart/*} message, L{imap4.getBodyStructure} returns a list - containing the body structure information for each part of the message - followed by an element giving the MIME subtype of the message. - """ - oneSubPart = FakeyMessage({ - 'content-type': 'image/jpeg; x=y', - 'content-id': 'some kind of id', - 'content-description': 'great justice', - 'content-transfer-encoding': 'maximum', - }, (), '', 'hello world', 123, None) - - anotherSubPart = FakeyMessage({ - 'content-type': 'text/plain; charset=us-ascii', - }, (), '', 'some stuff', 321, None) - - container = FakeyMessage({ - 'content-type': 'multipart/related', - }, (), '', '', 555, [oneSubPart, anotherSubPart]) - - self.assertEqual( - [imap4.getBodyStructure(oneSubPart), - imap4.getBodyStructure(anotherSubPart), - 'related'], - imap4.getBodyStructure(container)) - - - def test_multiPartExtended(self): - """ - When passed a I{multipart/*} message and C{True} for the C{extended} - argument, L{imap4.getBodyStructure} includes extended structure - information from the parts of the multipart message and extended - structure information about the multipart message itself. - """ - oneSubPart = FakeyMessage({ - 'content-type': 'image/jpeg; x=y', - 'content-id': 'some kind of id', - 'content-description': 'great justice', - 'content-transfer-encoding': 'maximum', - }, (), '', 'hello world', 123, None) - - anotherSubPart = FakeyMessage({ - 'content-type': 'text/plain; charset=us-ascii', - }, (), '', 'some stuff', 321, None) - - container = FakeyMessage({ - 'content-type': 'multipart/related; foo=bar', - 'content-language': 'es', - 'content-location': 'Spain', - 'content-disposition': 'attachment; name=monkeys', - }, (), '', '', 555, [oneSubPart, anotherSubPart]) - - self.assertEqual( - [imap4.getBodyStructure(oneSubPart, extended=True), - imap4.getBodyStructure(anotherSubPart, extended=True), - 'related', ['foo', 'bar'], ['attachment', ['name', 'monkeys']], - 'es', 'Spain'], - imap4.getBodyStructure(container, extended=True)) - - - -class NewFetchTests(unittest.TestCase, IMAP4HelperMixin): - def setUp(self): - self.received_messages = self.received_uid = None - self.result = None - - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.mbox = self - self.connected = defer.Deferred() - self.client = SimpleClient(self.connected) - - def addListener(self, x): - pass - def removeListener(self, x): - pass - - def fetch(self, messages, uid): - self.received_messages = messages - self.received_uid = uid - return iter(zip(range(len(self.msgObjs)), self.msgObjs)) - - def _fetchWork(self, uid): - if uid: - for (i, msg) in zip(range(len(self.msgObjs)), self.msgObjs): - self.expected[i]['UID'] = str(msg.getUID()) - - def result(R): - self.result = R - - self.connected.addCallback(lambda _: self.function(self.messages, uid) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda x : self.assertEqual(self.result, self.expected)) - return d - - def testFetchUID(self): - self.function = lambda m, u: self.client.fetchUID(m) - - self.messages = '7' - self.msgObjs = [ - FakeyMessage({}, (), '', '', 12345, None), - FakeyMessage({}, (), '', '', 999, None), - FakeyMessage({}, (), '', '', 10101, None), - ] - self.expected = { - 0: {'UID': '12345'}, - 1: {'UID': '999'}, - 2: {'UID': '10101'}, - } - return self._fetchWork(0) - - def testFetchFlags(self, uid=0): - self.function = self.client.fetchFlags - self.messages = '9' - self.msgObjs = [ - FakeyMessage({}, ['FlagA', 'FlagB', '\\FlagC'], '', '', 54321, None), - FakeyMessage({}, ['\\FlagC', 'FlagA', 'FlagB'], '', '', 12345, None), - ] - self.expected = { - 0: {'FLAGS': ['FlagA', 'FlagB', '\\FlagC']}, - 1: {'FLAGS': ['\\FlagC', 'FlagA', 'FlagB']}, - } - return self._fetchWork(uid) - - def testFetchFlagsUID(self): - return self.testFetchFlags(1) - - def testFetchInternalDate(self, uid=0): - self.function = self.client.fetchInternalDate - self.messages = '13' - self.msgObjs = [ - FakeyMessage({}, (), 'Fri, 02 Nov 2003 21:25:10 GMT', '', 23232, None), - FakeyMessage({}, (), 'Thu, 29 Dec 2013 11:31:52 EST', '', 101, None), - FakeyMessage({}, (), 'Mon, 10 Mar 1992 02:44:30 CST', '', 202, None), - FakeyMessage({}, (), 'Sat, 11 Jan 2000 14:40:24 PST', '', 303, None), - ] - self.expected = { - 0: {'INTERNALDATE': '02-Nov-2003 21:25:10 +0000'}, - 1: {'INTERNALDATE': '29-Dec-2013 11:31:52 -0500'}, - 2: {'INTERNALDATE': '10-Mar-1992 02:44:30 -0600'}, - 3: {'INTERNALDATE': '11-Jan-2000 14:40:24 -0800'}, - } - return self._fetchWork(uid) - - def testFetchInternalDateUID(self): - return self.testFetchInternalDate(1) - - - def test_fetchInternalDateLocaleIndependent(self): - """ - The month name in the date is locale independent. - """ - # Fake that we're in a language where December is not Dec - currentLocale = locale.setlocale(locale.LC_ALL, None) - locale.setlocale(locale.LC_ALL, "es_AR.UTF8") - self.addCleanup(locale.setlocale, locale.LC_ALL, currentLocale) - return self.testFetchInternalDate(1) - - # if alternate locale is not available, the previous test will be skipped, - # please install this locale for it to run. Avoid using locale.getlocale to - # learn the current locale; its values don't round-trip well on all - # platforms. Fortunately setlocale returns a value which does round-trip - # well. - currentLocale = locale.setlocale(locale.LC_ALL, None) - try: - locale.setlocale(locale.LC_ALL, "es_AR.UTF8") - except locale.Error: - test_fetchInternalDateLocaleIndependent.skip = ( - "The es_AR.UTF8 locale is not installed.") - else: - locale.setlocale(locale.LC_ALL, currentLocale) - - - def testFetchEnvelope(self, uid=0): - self.function = self.client.fetchEnvelope - self.messages = '15' - self.msgObjs = [ - FakeyMessage({ - 'from': 'user@domain', 'to': 'resu@domain', - 'date': 'thursday', 'subject': 'it is a message', - 'message-id': 'id-id-id-yayaya'}, (), '', '', 65656, - None), - ] - self.expected = { - 0: {'ENVELOPE': - ['thursday', 'it is a message', - [[None, None, 'user', 'domain']], - [[None, None, 'user', 'domain']], - [[None, None, 'user', 'domain']], - [[None, None, 'resu', 'domain']], - None, None, None, 'id-id-id-yayaya'] - } - } - return self._fetchWork(uid) - - def testFetchEnvelopeUID(self): - return self.testFetchEnvelope(1) - - - def test_fetchBodyStructure(self, uid=0): - """ - L{IMAP4Client.fetchBodyStructure} issues a I{FETCH BODYSTRUCTURE} - command and returns a Deferred which fires with a structure giving the - result of parsing the server's response. The structure is a list - reflecting the parenthesized data sent by the server, as described by - RFC 3501, section 7.4.2. - """ - self.function = self.client.fetchBodyStructure - self.messages = '3:9,10:*' - self.msgObjs = [FakeyMessage({ - 'content-type': 'text/plain; name=thing; key="value"', - 'content-id': 'this-is-the-content-id', - 'content-description': 'describing-the-content-goes-here!', - 'content-transfer-encoding': '8BIT', - 'content-md5': 'abcdef123456', - 'content-disposition': 'attachment; filename=monkeys', - 'content-language': 'es', - 'content-location': 'http://example.com/monkeys', - }, (), '', 'Body\nText\nGoes\nHere\n', 919293, None)] - self.expected = {0: {'BODYSTRUCTURE': [ - 'text', 'plain', ['key', 'value', 'name', 'thing'], - 'this-is-the-content-id', 'describing-the-content-goes-here!', - '8BIT', '20', '4', 'abcdef123456', - ['attachment', ['filename', 'monkeys']], 'es', - 'http://example.com/monkeys']}} - return self._fetchWork(uid) - - - def testFetchBodyStructureUID(self): - """ - If passed C{True} for the C{uid} argument, C{fetchBodyStructure} can - also issue a I{UID FETCH BODYSTRUCTURE} command. - """ - return self.test_fetchBodyStructure(1) - - - def test_fetchBodyStructureMultipart(self, uid=0): - """ - L{IMAP4Client.fetchBodyStructure} can also parse the response to a - I{FETCH BODYSTRUCTURE} command for a multipart message. - """ - self.function = self.client.fetchBodyStructure - self.messages = '3:9,10:*' - innerMessage = FakeyMessage({ - 'content-type': 'text/plain; name=thing; key="value"', - 'content-id': 'this-is-the-content-id', - 'content-description': 'describing-the-content-goes-here!', - 'content-transfer-encoding': '8BIT', - 'content-language': 'fr', - 'content-md5': '123456abcdef', - 'content-disposition': 'inline', - 'content-location': 'outer space', - }, (), '', 'Body\nText\nGoes\nHere\n', 919293, None) - self.msgObjs = [FakeyMessage({ - 'content-type': 'multipart/mixed; boundary="xyz"', - 'content-language': 'en', - 'content-location': 'nearby', - }, (), '', '', 919293, [innerMessage])] - self.expected = {0: {'BODYSTRUCTURE': [ - ['text', 'plain', ['key', 'value', 'name', 'thing'], - 'this-is-the-content-id', 'describing-the-content-goes-here!', - '8BIT', '20', '4', '123456abcdef', ['inline', None], 'fr', - 'outer space'], - 'mixed', ['boundary', 'xyz'], None, 'en', 'nearby' - ]}} - return self._fetchWork(uid) - - - def testFetchSimplifiedBody(self, uid=0): - self.function = self.client.fetchSimplifiedBody - self.messages = '21' - self.msgObjs = [FakeyMessage({}, (), '', 'Yea whatever', 91825, - [FakeyMessage({'content-type': 'image/jpg'}, (), '', - 'Body Body Body', None, None - )] - )] - self.expected = {0: - {'BODY': - [None, None, None, None, None, None, - '12' - ] - } - } - - return self._fetchWork(uid) - - def testFetchSimplifiedBodyUID(self): - return self.testFetchSimplifiedBody(1) - - def testFetchSimplifiedBodyText(self, uid=0): - self.function = self.client.fetchSimplifiedBody - self.messages = '21' - self.msgObjs = [FakeyMessage({'content-type': 'text/plain'}, - (), '', 'Yea whatever', 91825, None)] - self.expected = {0: - {'BODY': - ['text', 'plain', None, None, None, None, - '12', '1' - ] - } - } - - return self._fetchWork(uid) - - def testFetchSimplifiedBodyTextUID(self): - return self.testFetchSimplifiedBodyText(1) - - def testFetchSimplifiedBodyRFC822(self, uid=0): - self.function = self.client.fetchSimplifiedBody - self.messages = '21' - self.msgObjs = [FakeyMessage({'content-type': 'message/rfc822'}, - (), '', 'Yea whatever', 91825, - [FakeyMessage({'content-type': 'image/jpg'}, (), '', - 'Body Body Body', None, None - )] - )] - self.expected = {0: - {'BODY': - ['message', 'rfc822', None, None, None, None, - '12', [None, None, [[None, None, None]], - [[None, None, None]], None, None, None, - None, None, None], ['image', 'jpg', None, - None, None, None, '14'], '1' - ] - } - } - - return self._fetchWork(uid) - - def testFetchSimplifiedBodyRFC822UID(self): - return self.testFetchSimplifiedBodyRFC822(1) - - - def test_fetchSimplifiedBodyMultipart(self): - """ - L{IMAP4Client.fetchSimplifiedBody} returns a dictionary mapping message - sequence numbers to fetch responses for the corresponding messages. In - particular, for a multipart message, the value in the dictionary maps - the string C{"BODY"} to a list giving the body structure information for - that message, in the form of a list of subpart body structure - information followed by the subtype of the message (eg C{"alternative"} - for a I{multipart/alternative} message). This structure is self-similar - in the case where a subpart is itself multipart. - """ - self.function = self.client.fetchSimplifiedBody - self.messages = '21' - - # A couple non-multipart messages to use as the inner-most payload - singles = [ - FakeyMessage( - {'content-type': 'text/plain'}, - (), 'date', 'Stuff', 54321, None), - FakeyMessage( - {'content-type': 'text/html'}, - (), 'date', 'Things', 32415, None)] - - # A multipart/alternative message containing the above non-multipart - # messages. This will be the payload of the outer-most message. - alternative = FakeyMessage( - {'content-type': 'multipart/alternative'}, - (), '', 'Irrelevant', 12345, singles) - - # The outer-most message, also with a multipart type, containing just - # the single middle message. - mixed = FakeyMessage( - # The message is multipart/mixed - {'content-type': 'multipart/mixed'}, - (), '', 'RootOf', 98765, [alternative]) - - self.msgObjs = [mixed] - - self.expected = { - 0: {'BODY': [ - [['text', 'plain', None, None, None, None, '5', '1'], - ['text', 'html', None, None, None, None, '6', '1'], - 'alternative'], - 'mixed']}} - - return self._fetchWork(False) - - - def testFetchMessage(self, uid=0): - self.function = self.client.fetchMessage - self.messages = '1,3,7,10101' - self.msgObjs = [ - FakeyMessage({'Header': 'Value'}, (), '', 'BODY TEXT\r\n', 91, None), - ] - self.expected = { - 0: {'RFC822': 'Header: Value\r\n\r\nBODY TEXT\r\n'} - } - return self._fetchWork(uid) - - def testFetchMessageUID(self): - return self.testFetchMessage(1) - - def testFetchHeaders(self, uid=0): - self.function = self.client.fetchHeaders - self.messages = '9,6,2' - self.msgObjs = [ - FakeyMessage({'H1': 'V1', 'H2': 'V2'}, (), '', '', 99, None), - ] - self.expected = { - 0: {'RFC822.HEADER': imap4._formatHeaders({'H1': 'V1', 'H2': 'V2'})}, - } - return self._fetchWork(uid) - - def testFetchHeadersUID(self): - return self.testFetchHeaders(1) - - def testFetchBody(self, uid=0): - self.function = self.client.fetchBody - self.messages = '1,2,3,4,5,6,7' - self.msgObjs = [ - FakeyMessage({'Header': 'Value'}, (), '', 'Body goes here\r\n', 171, None), - ] - self.expected = { - 0: {'RFC822.TEXT': 'Body goes here\r\n'}, - } - return self._fetchWork(uid) - - def testFetchBodyUID(self): - return self.testFetchBody(1) - - def testFetchBodyParts(self): - """ - Test the server's handling of requests for specific body sections. - """ - self.function = self.client.fetchSpecific - self.messages = '1' - outerBody = '' - innerBody1 = 'Contained body message text. Squarge.' - innerBody2 = 'Secondary message text of squarge body.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'multipart/alternative; boundary="xyz"' - innerHeaders = util.OrderedDict() - innerHeaders['subject'] = 'this is subject text' - innerHeaders['content-type'] = 'text/plain' - innerHeaders2 = util.OrderedDict() - innerHeaders2['subject'] = 'this is subject' - innerHeaders2['content-type'] = 'text/html' - self.msgObjs = [FakeyMessage( - headers, (), None, outerBody, 123, - [FakeyMessage(innerHeaders, (), None, innerBody1, None, None), - FakeyMessage(innerHeaders2, (), None, innerBody2, None, None)])] - self.expected = { - 0: [['BODY', ['1'], 'Contained body message text. Squarge.']]} - - def result(R): - self.result = R - - self.connected.addCallback( - lambda _: self.function(self.messages, headerNumber=1)) - self.connected.addCallback(result) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda ign: self.assertEqual(self.result, self.expected)) - return d - - - def test_fetchBodyPartOfNonMultipart(self): - """ - Single-part messages have an implicit first part which clients - should be able to retrieve explicitly. Test that a client - requesting part 1 of a text/plain message receives the body of the - text/plain part. - """ - self.function = self.client.fetchSpecific - self.messages = '1' - parts = [1] - outerBody = 'DA body' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'text/plain' - self.msgObjs = [FakeyMessage( - headers, (), None, outerBody, 123, None)] - - self.expected = {0: [['BODY', ['1'], 'DA body']]} - - def result(R): - self.result = R - - self.connected.addCallback( - lambda _: self.function(self.messages, headerNumber=parts)) - self.connected.addCallback(result) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda ign: self.assertEqual(self.result, self.expected)) - return d - - - def testFetchSize(self, uid=0): - self.function = self.client.fetchSize - self.messages = '1:100,2:*' - self.msgObjs = [ - FakeyMessage({}, (), '', 'x' * 20, 123, None), - ] - self.expected = { - 0: {'RFC822.SIZE': '20'}, - } - return self._fetchWork(uid) - - def testFetchSizeUID(self): - return self.testFetchSize(1) - - def testFetchFull(self, uid=0): - self.function = self.client.fetchFull - self.messages = '1,3' - self.msgObjs = [ - FakeyMessage({}, ('\\XYZ', '\\YZX', 'Abc'), - 'Sun, 25 Jul 2010 06:20:30 -0400 (EDT)', - 'xyz' * 2, 654, None), - FakeyMessage({}, ('\\One', '\\Two', 'Three'), - 'Mon, 14 Apr 2003 19:43:44 -0400', - 'abc' * 4, 555, None), - ] - self.expected = { - 0: {'FLAGS': ['\\XYZ', '\\YZX', 'Abc'], - 'INTERNALDATE': '25-Jul-2010 06:20:30 -0400', - 'RFC822.SIZE': '6', - 'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'BODY': [None, None, None, None, None, None, '6']}, - 1: {'FLAGS': ['\\One', '\\Two', 'Three'], - 'INTERNALDATE': '14-Apr-2003 19:43:44 -0400', - 'RFC822.SIZE': '12', - 'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'BODY': [None, None, None, None, None, None, '12']}, - } - return self._fetchWork(uid) - - def testFetchFullUID(self): - return self.testFetchFull(1) - - def testFetchAll(self, uid=0): - self.function = self.client.fetchAll - self.messages = '1,2:3' - self.msgObjs = [ - FakeyMessage({}, (), 'Mon, 14 Apr 2003 19:43:44 +0400', - 'Lalala', 10101, None), - FakeyMessage({}, (), 'Tue, 15 Apr 2003 19:43:44 +0200', - 'Alalal', 20202, None), - ] - self.expected = { - 0: {'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'RFC822.SIZE': '6', - 'INTERNALDATE': '14-Apr-2003 19:43:44 +0400', - 'FLAGS': []}, - 1: {'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'RFC822.SIZE': '6', - 'INTERNALDATE': '15-Apr-2003 19:43:44 +0200', - 'FLAGS': []}, - } - return self._fetchWork(uid) - - def testFetchAllUID(self): - return self.testFetchAll(1) - - def testFetchFast(self, uid=0): - self.function = self.client.fetchFast - self.messages = '1' - self.msgObjs = [ - FakeyMessage({}, ('\\X',), '19 Mar 2003 19:22:21 -0500', '', 9, None), - ] - self.expected = { - 0: {'FLAGS': ['\\X'], - 'INTERNALDATE': '19-Mar-2003 19:22:21 -0500', - 'RFC822.SIZE': '0'}, - } - return self._fetchWork(uid) - - def testFetchFastUID(self): - return self.testFetchFast(1) - - - -class DefaultSearchTests(IMAP4HelperMixin, unittest.TestCase): - """ - Test the behavior of the server's SEARCH implementation, particularly in - the face of unhandled search terms. - """ - def setUp(self): - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.mbox = self - self.connected = defer.Deferred() - self.client = SimpleClient(self.connected) - self.msgObjs = [ - FakeyMessage({}, (), '', '', 999, None), - FakeyMessage({}, (), '', '', 10101, None), - FakeyMessage({}, (), '', '', 12345, None), - FakeyMessage({}, (), '', '', 20001, None), - FakeyMessage({}, (), '', '', 20002, None), - ] - - - def fetch(self, messages, uid): - """ - Pretend to be a mailbox and let C{self.server} lookup messages on me. - """ - return zip(range(1, len(self.msgObjs) + 1), self.msgObjs) - - - def _messageSetSearchTest(self, queryTerms, expectedMessages): - """ - Issue a search with given query and verify that the returned messages - match the given expected messages. - - @param queryTerms: A string giving the search query. - @param expectedMessages: A list of the message sequence numbers - expected as the result of the search. - @return: A L{Deferred} which fires when the test is complete. - """ - def search(): - return self.client.search(queryTerms) - - d = self.connected.addCallback(strip(search)) - def searched(results): - self.assertEqual(results, expectedMessages) - d.addCallback(searched) - d.addCallback(self._cbStopClient) - d.addErrback(self._ebGeneral) - self.loopback() - return d - - - def test_searchMessageSet(self): - """ - Test that a search which starts with a message set properly limits - the search results to messages in that set. - """ - return self._messageSetSearchTest('1', [1]) - - - def test_searchMessageSetWithStar(self): - """ - If the search filter ends with a star, all the message from the - starting point are returned. - """ - return self._messageSetSearchTest('2:*', [2, 3, 4, 5]) - - - def test_searchMessageSetWithStarFirst(self): - """ - If the search filter starts with a star, the result should be identical - with if the filter would end with a star. - """ - return self._messageSetSearchTest('*:2', [2, 3, 4, 5]) - - - def test_searchMessageSetUIDWithStar(self): - """ - If the search filter ends with a star, all the message from the - starting point are returned (also for the SEARCH UID case). - """ - return self._messageSetSearchTest('UID 10000:*', [2, 3, 4, 5]) - - - def test_searchMessageSetUIDWithStarFirst(self): - """ - If the search filter starts with a star, the result should be identical - with if the filter would end with a star (also for the SEARCH UID case). - """ - return self._messageSetSearchTest('UID *:10000', [2, 3, 4, 5]) - - - def test_searchMessageSetUIDWithStarAndHighStart(self): - """ - A search filter of 1234:* should include the UID of the last message in - the mailbox, even if its UID is less than 1234. - """ - # in our fake mbox the highest message UID is 20002 - return self._messageSetSearchTest('UID 30000:*', [5]) - - - def test_searchMessageSetWithList(self): - """ - If the search filter contains nesting terms, one of which includes a - message sequence set with a wildcard, IT ALL WORKS GOOD. - """ - # 6 is bigger than the biggest message sequence number, but that's - # okay, because N:* includes the biggest message sequence number even - # if N is bigger than that (read the rfc nub). - return self._messageSetSearchTest('(6:*)', [5]) - - - def test_searchOr(self): - """ - If the search filter contains an I{OR} term, all messages - which match either subexpression are returned. - """ - return self._messageSetSearchTest('OR 1 2', [1, 2]) - - - def test_searchOrMessageSet(self): - """ - If the search filter contains an I{OR} term with a - subexpression which includes a message sequence set wildcard, - all messages in that set are considered for inclusion in the - results. - """ - return self._messageSetSearchTest('OR 2:* 2:*', [2, 3, 4, 5]) - - - def test_searchNot(self): - """ - If the search filter contains a I{NOT} term, all messages - which do not match the subexpression are returned. - """ - return self._messageSetSearchTest('NOT 3', [1, 2, 4, 5]) - - - def test_searchNotMessageSet(self): - """ - If the search filter contains a I{NOT} term with a - subexpression which includes a message sequence set wildcard, - no messages in that set are considered for inclusion in the - result. - """ - return self._messageSetSearchTest('NOT 2:*', [1]) - - - def test_searchAndMessageSet(self): - """ - If the search filter contains multiple terms implicitly - conjoined with a message sequence set wildcard, only the - intersection of the results of each term are returned. - """ - return self._messageSetSearchTest('2:* 3', [3]) - - def test_searchInvalidCriteria(self): - """ - If the search criteria is not a valid key, a NO result is returned to - the client (resulting in an error callback), and an IllegalQueryError is - logged on the server side. - """ - queryTerms = 'FOO' - def search(): - return self.client.search(queryTerms) - - d = self.connected.addCallback(strip(search)) - d = self.assertFailure(d, imap4.IMAP4Exception) - - def errorReceived(results): - """ - Verify that the server logs an IllegalQueryError and the - client raises an IMAP4Exception with 'Search failed:...' - """ - self.client.transport.loseConnection() - self.server.transport.loseConnection() - - # Check what the server logs - errors = self.flushLoggedErrors(imap4.IllegalQueryError) - self.assertEqual(len(errors), 1) - - # Verify exception given to client has the correct message - self.assertEqual( - "SEARCH failed: Invalid search command FOO", str(results)) - - d.addCallback(errorReceived) - d.addErrback(self._ebGeneral) - self.loopback() - return d - - - -class FetchSearchStoreTests(unittest.TestCase, IMAP4HelperMixin): - implements(imap4.ISearchableMailbox) - - def setUp(self): - self.expected = self.result = None - self.server_received_query = None - self.server_received_uid = None - self.server_received_parts = None - self.server_received_messages = None - - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.mbox = self - self.connected = defer.Deferred() - self.client = SimpleClient(self.connected) - - def search(self, query, uid): - # Look for a specific bad query, so we can verify we handle it properly - if query == ['FOO']: - raise imap4.IllegalQueryError("FOO is not a valid search criteria") - - self.server_received_query = query - self.server_received_uid = uid - return self.expected - - def addListener(self, *a, **kw): - pass - removeListener = addListener - - def _searchWork(self, uid): - def search(): - return self.client.search(self.query, uid=uid) - def result(R): - self.result = R - - self.connected.addCallback(strip(search) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - def check(ignored): - # Ensure no short-circuiting weirdness is going on - self.failIf(self.result is self.expected) - - self.assertEqual(self.result, self.expected) - self.assertEqual(self.uid, self.server_received_uid) - self.assertEqual( - imap4.parseNestedParens(self.query), - self.server_received_query - ) - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(check) - return d - - def testSearch(self): - self.query = imap4.Or( - imap4.Query(header=('subject', 'substring')), - imap4.Query(larger=1024, smaller=4096), - ) - self.expected = [1, 4, 5, 7] - self.uid = 0 - return self._searchWork(0) - - def testUIDSearch(self): - self.query = imap4.Or( - imap4.Query(header=('subject', 'substring')), - imap4.Query(larger=1024, smaller=4096), - ) - self.uid = 1 - self.expected = [1, 2, 3] - return self._searchWork(1) - - def getUID(self, msg): - try: - return self.expected[msg]['UID'] - except (TypeError, IndexError): - return self.expected[msg-1] - except KeyError: - return 42 - - def fetch(self, messages, uid): - self.server_received_uid = uid - self.server_received_messages = str(messages) - return self.expected - - def _fetchWork(self, fetch): - def result(R): - self.result = R - - self.connected.addCallback(strip(fetch) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - def check(ignored): - # Ensure no short-circuiting weirdness is going on - self.failIf(self.result is self.expected) - - self.parts and self.parts.sort() - self.server_received_parts and self.server_received_parts.sort() - - if self.uid: - for (k, v) in self.expected.items(): - v['UID'] = str(k) - - self.assertEqual(self.result, self.expected) - self.assertEqual(self.uid, self.server_received_uid) - self.assertEqual(self.parts, self.server_received_parts) - self.assertEqual(imap4.parseIdList(self.messages), - imap4.parseIdList(self.server_received_messages)) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(check) - return d - - - def test_invalidTerm(self): - """ - If, as part of a search, an ISearchableMailbox raises an - IllegalQueryError (e.g. due to invalid search criteria), client sees a - failure response, and an IllegalQueryError is logged on the server. - """ - query = 'FOO' - - def search(): - return self.client.search(query) - - d = self.connected.addCallback(strip(search)) - d = self.assertFailure(d, imap4.IMAP4Exception) - - def errorReceived(results): - """ - Verify that the server logs an IllegalQueryError and the - client raises an IMAP4Exception with 'Search failed:...' - """ - self.client.transport.loseConnection() - self.server.transport.loseConnection() - - # Check what the server logs - errors = self.flushLoggedErrors(imap4.IllegalQueryError) - self.assertEqual(len(errors), 1) - - # Verify exception given to client has the correct message - self.assertEqual( - "SEARCH failed: FOO is not a valid search criteria", - str(results)) - - d.addCallback(errorReceived) - d.addErrback(self._ebGeneral) - self.loopback() - return d - - - -class FakeMailbox: - def __init__(self): - self.args = [] - def addMessage(self, body, flags, date): - self.args.append((body, flags, date)) - return defer.succeed(None) - -class FeaturefulMessage: - implements(imap4.IMessageFile) - - def getFlags(self): - return 'flags' - - def getInternalDate(self): - return 'internaldate' - - def open(self): - return StringIO("open") - -class MessageCopierMailbox: - implements(imap4.IMessageCopier) - - def __init__(self): - self.msgs = [] - - def copy(self, msg): - self.msgs.append(msg) - return len(self.msgs) - -class CopyWorkerTests(unittest.TestCase): - def testFeaturefulMessage(self): - s = imap4.IMAP4Server() - - # Yes. I am grabbing this uber-non-public method to test it. - # It is complex. It needs to be tested directly! - # Perhaps it should be refactored, simplified, or split up into - # not-so-private components, but that is a task for another day. - - # Ha ha! Addendum! Soon it will be split up, and this test will - # be re-written to just use the default adapter for IMailbox to - # IMessageCopier and call .copy on that adapter. - f = s._IMAP4Server__cbCopy - - m = FakeMailbox() - d = f([(i, FeaturefulMessage()) for i in range(1, 11)], 'tag', m) - - def cbCopy(results): - for a in m.args: - self.assertEqual(a[0].read(), "open") - self.assertEqual(a[1], "flags") - self.assertEqual(a[2], "internaldate") - - for (status, result) in results: - self.failUnless(status) - self.assertEqual(result, None) - - return d.addCallback(cbCopy) - - - def testUnfeaturefulMessage(self): - s = imap4.IMAP4Server() - - # See above comment - f = s._IMAP4Server__cbCopy - - m = FakeMailbox() - msgs = [FakeyMessage({'Header-Counter': str(i)}, (), 'Date', 'Body %d' % (i,), i + 10, None) for i in range(1, 11)] - d = f([im for im in zip(range(1, 11), msgs)], 'tag', m) - - def cbCopy(results): - seen = [] - for a in m.args: - seen.append(a[0].read()) - self.assertEqual(a[1], ()) - self.assertEqual(a[2], "Date") - - seen.sort() - exp = ["Header-Counter: %d\r\n\r\nBody %d" % (i, i) for i in range(1, 11)] - exp.sort() - self.assertEqual(seen, exp) - - for (status, result) in results: - self.failUnless(status) - self.assertEqual(result, None) - - return d.addCallback(cbCopy) - - def testMessageCopier(self): - s = imap4.IMAP4Server() - - # See above comment - f = s._IMAP4Server__cbCopy - - m = MessageCopierMailbox() - msgs = [object() for i in range(1, 11)] - d = f([im for im in zip(range(1, 11), msgs)], 'tag', m) - - def cbCopy(results): - self.assertEqual(results, zip([1] * 10, range(1, 11))) - for (orig, new) in zip(msgs, m.msgs): - self.assertIdentical(orig, new) - - return d.addCallback(cbCopy) - - -class TLSTests(IMAP4HelperMixin, unittest.TestCase): - serverCTX = ServerTLSContext and ServerTLSContext() - clientCTX = ClientTLSContext and ClientTLSContext() - - def loopback(self): - return loopback.loopbackTCP(self.server, self.client, noisy=False) - - def testAPileOfThings(self): - SimpleServer.theAccount.addMailbox('inbox') - called = [] - def login(): - called.append(None) - return self.client.login('testuser', 'password-test') - def list(): - called.append(None) - return self.client.list('inbox', '%') - def status(): - called.append(None) - return self.client.status('inbox', 'UIDNEXT') - def examine(): - called.append(None) - return self.client.examine('inbox') - def logout(): - called.append(None) - return self.client.logout() - - self.client.requireTransportSecurity = True - - methods = [login, list, status, examine, logout] - map(self.connected.addCallback, map(strip, methods)) - self.connected.addCallbacks(self._cbStopClient, self._ebGeneral) - def check(ignored): - self.assertEqual(self.server.startedTLS, True) - self.assertEqual(self.client.startedTLS, True) - self.assertEqual(len(called), len(methods)) - d = self.loopback() - d.addCallback(check) - return d - - def testLoginLogin(self): - self.server.checker.addUser('testuser', 'password-test') - success = [] - self.client.registerAuthenticator(imap4.LOGINAuthenticator('testuser')) - self.connected.addCallback( - lambda _: self.client.authenticate('password-test') - ).addCallback( - lambda _: self.client.logout() - ).addCallback(success.append - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - d = self.loopback() - d.addCallback(lambda x : self.assertEqual(len(success), 1)) - return d - - - def test_startTLS(self): - """ - L{IMAP4Client.startTLS} triggers TLS negotiation and returns a - L{Deferred} which fires after the client's transport is using - encryption. - """ - success = [] - self.connected.addCallback(lambda _: self.client.startTLS()) - def checkSecure(ignored): - self.assertTrue( - interfaces.ISSLTransport.providedBy(self.client.transport)) - self.connected.addCallback(checkSecure) - self.connected.addCallback(self._cbStopClient) - self.connected.addCallback(success.append) - self.connected.addErrback(self._ebGeneral) - - d = self.loopback() - d.addCallback(lambda x : self.failUnless(success)) - return defer.gatherResults([d, self.connected]) - - - def testFailedStartTLS(self): - failures = [] - def breakServerTLS(ign): - self.server.canStartTLS = False - - self.connected.addCallback(breakServerTLS) - self.connected.addCallback(lambda ign: self.client.startTLS()) - self.connected.addErrback( - lambda err: failures.append(err.trap(imap4.IMAP4Exception))) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - - def check(ignored): - self.failUnless(failures) - self.assertIdentical(failures[0], imap4.IMAP4Exception) - return self.loopback().addCallback(check) - - - -class SlowMailbox(SimpleMailbox): - howSlow = 2 - callLater = None - fetchDeferred = None - - # Not a very nice implementation of fetch(), but it'll - # do for the purposes of testing. - def fetch(self, messages, uid): - d = defer.Deferred() - self.callLater(self.howSlow, d.callback, ()) - self.fetchDeferred.callback(None) - return d - -class TimeoutTests(IMAP4HelperMixin, unittest.TestCase): - - def test_serverTimeout(self): - """ - The *client* has a timeout mechanism which will close connections that - are inactive for a period. - """ - c = Clock() - self.server.timeoutTest = True - self.client.timeout = 5 #seconds - self.client.callLater = c.callLater - self.selectedArgs = None - - def login(): - d = self.client.login('testuser', 'password-test') - c.advance(5) - d.addErrback(timedOut) - return d - - def timedOut(failure): - self._cbStopClient(None) - failure.trap(error.TimeoutError) - - d = self.connected.addCallback(strip(login)) - d.addErrback(self._ebGeneral) - return defer.gatherResults([d, self.loopback()]) - - - def test_longFetchDoesntTimeout(self): - """ - The connection timeout does not take effect during fetches. - """ - c = Clock() - SlowMailbox.callLater = c.callLater - SlowMailbox.fetchDeferred = defer.Deferred() - self.server.callLater = c.callLater - SimpleServer.theAccount.mailboxFactory = SlowMailbox - SimpleServer.theAccount.addMailbox('mailbox-test') - - self.server.setTimeout(1) - - def login(): - return self.client.login('testuser', 'password-test') - def select(): - self.server.setTimeout(1) - return self.client.select('mailbox-test') - def fetch(): - return self.client.fetchUID('1:*') - def stillConnected(): - self.assertNotEquals(self.server.state, 'timeout') - - def cbAdvance(ignored): - for i in xrange(4): - c.advance(.5) - - SlowMailbox.fetchDeferred.addCallback(cbAdvance) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(select)) - d1.addCallback(strip(fetch)) - d1.addCallback(strip(stillConnected)) - d1.addCallback(self._cbStopClient) - d1.addErrback(self._ebGeneral) - d = defer.gatherResults([d1, self.loopback()]) - return d - - - def test_idleClientDoesDisconnect(self): - """ - The *server* has a timeout mechanism which will close connections that - are inactive for a period. - """ - c = Clock() - # Hook up our server protocol - transport = StringTransportWithDisconnection() - transport.protocol = self.server - self.server.callLater = c.callLater - self.server.makeConnection(transport) - - # Make sure we can notice when the connection goes away - lost = [] - connLost = self.server.connectionLost - self.server.connectionLost = lambda reason: (lost.append(None), connLost(reason))[1] - - # 2/3rds of the idle timeout elapses... - c.pump([0.0] + [self.server.timeOut / 3.0] * 2) - self.failIf(lost, lost) - - # Now some more - c.pump([0.0, self.server.timeOut / 2.0]) - self.failUnless(lost) - - - -class DisconnectionTests(unittest.TestCase): - def testClientDisconnectFailsDeferreds(self): - c = imap4.IMAP4Client() - t = StringTransportWithDisconnection() - c.makeConnection(t) - d = self.assertFailure(c.login('testuser', 'example.com'), error.ConnectionDone) - c.connectionLost(error.ConnectionDone("Connection closed")) - return d - - - -class SynchronousMailbox(object): - """ - Trivial, in-memory mailbox implementation which can produce a message - synchronously. - """ - def __init__(self, messages): - self.messages = messages - - - def fetch(self, msgset, uid): - assert not uid, "Cannot handle uid requests." - for msg in msgset: - yield msg, self.messages[msg - 1] - - - -class StringTransportConsumer(StringTransport): - producer = None - streaming = None - - def registerProducer(self, producer, streaming): - self.producer = producer - self.streaming = streaming - - - -class PipeliningTests(unittest.TestCase): - """ - Tests for various aspects of the IMAP4 server's pipelining support. - """ - messages = [ - FakeyMessage({}, [], '', '0', None, None), - FakeyMessage({}, [], '', '1', None, None), - FakeyMessage({}, [], '', '2', None, None), - ] - - def setUp(self): - self.iterators = [] - - self.transport = StringTransportConsumer() - self.server = imap4.IMAP4Server(None, None, self.iterateInReactor) - self.server.makeConnection(self.transport) - - - def iterateInReactor(self, iterator): - d = defer.Deferred() - self.iterators.append((iterator, d)) - return d - - - def tearDown(self): - self.server.connectionLost(failure.Failure(error.ConnectionDone())) - - - def test_synchronousFetch(self): - """ - Test that pipelined FETCH commands which can be responded to - synchronously are responded to correctly. - """ - mailbox = SynchronousMailbox(self.messages) - - # Skip over authentication and folder selection - self.server.state = 'select' - self.server.mbox = mailbox - - # Get rid of any greeting junk - self.transport.clear() - - # Here's some pipelined stuff - self.server.dataReceived( - '01 FETCH 1 BODY[]\r\n' - '02 FETCH 2 BODY[]\r\n' - '03 FETCH 3 BODY[]\r\n') - - # Flush anything the server has scheduled to run - while self.iterators: - for e in self.iterators[0][0]: - break - else: - self.iterators.pop(0)[1].callback(None) - - # The bodies are empty because we aren't simulating a transport - # exactly correctly (we have StringTransportConsumer but we never - # call resumeProducing on its producer). It doesn't matter: just - # make sure the surrounding structure is okay, and that no - # exceptions occurred. - self.assertEqual( - self.transport.value(), - '* 1 FETCH (BODY[] )\r\n' - '01 OK FETCH completed\r\n' - '* 2 FETCH (BODY[] )\r\n' - '02 OK FETCH completed\r\n' - '* 3 FETCH (BODY[] )\r\n' - '03 OK FETCH completed\r\n') - - - -if ClientTLSContext is None: - for case in (TLSTests,): - case.skip = "OpenSSL not present" -elif interfaces.IReactorSSL(reactor, None) is None: - for case in (TLSTests,): - case.skip = "Reactor doesn't support SSL" - - - -class IMAP4ServerFetchTests(unittest.TestCase): - """ - This test case is for the FETCH tests that require - a C{StringTransport}. - """ - - def setUp(self): - self.transport = StringTransport() - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.makeConnection(self.transport) - - - def test_fetchWithPartialValidArgument(self): - """ - If by any chance, extra bytes got appended at the end of a valid - FETCH arguments, the client should get a BAD - arguments invalid - response. - - See U{RFC 3501}, - section 6.4.5, - """ - # We need to clear out the welcome message. - self.transport.clear() - # Let's send out the faulty command. - self.server.dataReceived("0001 FETCH 1 FULLL\r\n") - expected = "0001 BAD Illegal syntax: Invalid Argument\r\n" - self.assertEqual(self.transport.value(), expected) - self.transport.clear() - self.server.connectionLost(error.ConnectionDone("Connection closed")) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_mail.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_mail.py deleted file mode 100644 index 7019ca2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_mail.py +++ /dev/null @@ -1,2538 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for large portions of L{twisted.mail}. -""" - -import os -import errno -import shutil -import pickle -import StringIO -import rfc822 -import tempfile -import signal -import time -from hashlib import md5 - -from zope.interface.verify import verifyClass -from zope.interface import Interface, implements - -from twisted.trial import unittest -from twisted.mail import smtp -from twisted.mail import pop3 -from twisted.names import dns -from twisted.internet import protocol -from twisted.internet import defer -from twisted.internet.defer import Deferred -from twisted.internet import reactor -from twisted.internet import interfaces -from twisted.internet import task -from twisted.internet.error import DNSLookupError, CannotListenError -from twisted.internet.error import ProcessDone, ProcessTerminated -from twisted.internet import address -from twisted.python import failure -from twisted.python.filepath import FilePath -from twisted.python import log -from twisted.mail.relaymanager import _AttemptManager -from twisted.test.proto_helpers import MemoryReactorClock - -from twisted import mail -import twisted.mail.mail -import twisted.mail.maildir -import twisted.mail.relay -import twisted.mail.relaymanager -import twisted.mail.protocols -import twisted.mail.alias - -from twisted.names.error import DNSNameError -from twisted.names.dns import RRHeader, Record_CNAME, Record_MX - -from twisted import cred -import twisted.cred.credentials -import twisted.cred.checkers -import twisted.cred.portal - -from twisted.test.proto_helpers import LineSendingProtocol - -class DomainWithDefaultsTests(unittest.TestCase): - def testMethods(self): - d = dict([(x, x + 10) for x in range(10)]) - d = mail.mail.DomainWithDefaultDict(d, 'Default') - - self.assertEqual(len(d), 10) - self.assertEqual(list(iter(d)), range(10)) - self.assertEqual(list(d.iterkeys()), list(iter(d))) - - items = list(d.iteritems()) - items.sort() - self.assertEqual(items, [(x, x + 10) for x in range(10)]) - - values = list(d.itervalues()) - values.sort() - self.assertEqual(values, range(10, 20)) - - items = d.items() - items.sort() - self.assertEqual(items, [(x, x + 10) for x in range(10)]) - - values = d.values() - values.sort() - self.assertEqual(values, range(10, 20)) - - for x in range(10): - self.assertEqual(d[x], x + 10) - self.assertEqual(d.get(x), x + 10) - self.failUnless(x in d) - self.failUnless(d.has_key(x)) - - del d[2], d[4], d[6] - - self.assertEqual(len(d), 7) - self.assertEqual(d[2], 'Default') - self.assertEqual(d[4], 'Default') - self.assertEqual(d[6], 'Default') - - d.update({'a': None, 'b': (), 'c': '*'}) - self.assertEqual(len(d), 10) - self.assertEqual(d['a'], None) - self.assertEqual(d['b'], ()) - self.assertEqual(d['c'], '*') - - d.clear() - self.assertEqual(len(d), 0) - - self.assertEqual(d.setdefault('key', 'value'), 'value') - self.assertEqual(d['key'], 'value') - - self.assertEqual(d.popitem(), ('key', 'value')) - self.assertEqual(len(d), 0) - - dcopy = d.copy() - self.assertEqual(d.domains, dcopy.domains) - self.assertEqual(d.default, dcopy.default) - - - def _stringificationTest(self, stringifier): - """ - Assert that the class name of a L{mail.mail.DomainWithDefaultDict} - instance and the string-formatted underlying domain dictionary both - appear in the string produced by the given string-returning function. - - @type stringifier: one-argument callable - @param stringifier: either C{str} or C{repr}, to be used to get a - string to make assertions against. - """ - domain = mail.mail.DomainWithDefaultDict({}, 'Default') - self.assertIn(domain.__class__.__name__, stringifier(domain)) - domain['key'] = 'value' - self.assertIn(str({'key': 'value'}), stringifier(domain)) - - - def test_str(self): - """ - L{DomainWithDefaultDict.__str__} should return a string including - the class name and the domain mapping held by the instance. - """ - self._stringificationTest(str) - - - def test_repr(self): - """ - L{DomainWithDefaultDict.__repr__} should return a string including - the class name and the domain mapping held by the instance. - """ - self._stringificationTest(repr) - - - -class BounceTests(unittest.TestCase): - def setUp(self): - self.domain = mail.mail.BounceDomain() - - - def testExists(self): - self.assertRaises(smtp.AddressError, self.domain.exists, "any user") - - - def testRelay(self): - self.assertEqual( - self.domain.willRelay("random q emailer", "protocol"), - False - ) - - - def testAddUser(self): - self.domain.addUser("bob", "password") - self.assertRaises(smtp.SMTPBadRcpt, self.domain.exists, "bob") - - - -class FileMessageTests(unittest.TestCase): - def setUp(self): - self.name = "fileMessage.testFile" - self.final = "final.fileMessage.testFile" - self.f = file(self.name, 'w') - self.fp = mail.mail.FileMessage(self.f, self.name, self.final) - - def tearDown(self): - try: - self.f.close() - except: - pass - try: - os.remove(self.name) - except: - pass - try: - os.remove(self.final) - except: - pass - - def testFinalName(self): - return self.fp.eomReceived().addCallback(self._cbFinalName) - - def _cbFinalName(self, result): - self.assertEqual(result, self.final) - self.failUnless(self.f.closed) - self.failIf(os.path.exists(self.name)) - - def testContents(self): - contents = "first line\nsecond line\nthird line\n" - for line in contents.splitlines(): - self.fp.lineReceived(line) - self.fp.eomReceived() - self.assertEqual(file(self.final).read(), contents) - - def testInterrupted(self): - contents = "first line\nsecond line\n" - for line in contents.splitlines(): - self.fp.lineReceived(line) - self.fp.connectionLost() - self.failIf(os.path.exists(self.name)) - self.failIf(os.path.exists(self.final)) - -class MailServiceTests(unittest.TestCase): - def setUp(self): - self.service = mail.mail.MailService() - - def testFactories(self): - f = self.service.getPOP3Factory() - self.failUnless(isinstance(f, protocol.ServerFactory)) - self.failUnless(f.buildProtocol(('127.0.0.1', 12345)), pop3.POP3) - - f = self.service.getSMTPFactory() - self.failUnless(isinstance(f, protocol.ServerFactory)) - self.failUnless(f.buildProtocol(('127.0.0.1', 12345)), smtp.SMTP) - - f = self.service.getESMTPFactory() - self.failUnless(isinstance(f, protocol.ServerFactory)) - self.failUnless(f.buildProtocol(('127.0.0.1', 12345)), smtp.ESMTP) - - def testPortals(self): - o1 = object() - o2 = object() - self.service.portals['domain'] = o1 - self.service.portals[''] = o2 - - self.failUnless(self.service.lookupPortal('domain') is o1) - self.failUnless(self.service.defaultPortal() is o2) - - -class StringListMailboxTests(unittest.TestCase): - """ - Tests for L{StringListMailbox}, an in-memory only implementation of - L{pop3.IMailbox}. - """ - def test_listOneMessage(self): - """ - L{StringListMailbox.listMessages} returns the length of the message at - the offset into the mailbox passed to it. - """ - mailbox = mail.maildir.StringListMailbox(["abc", "ab", "a"]) - self.assertEqual(mailbox.listMessages(0), 3) - self.assertEqual(mailbox.listMessages(1), 2) - self.assertEqual(mailbox.listMessages(2), 1) - - - def test_listAllMessages(self): - """ - L{StringListMailbox.listMessages} returns a list of the lengths of all - messages if not passed an index. - """ - mailbox = mail.maildir.StringListMailbox(["a", "abc", "ab"]) - self.assertEqual(mailbox.listMessages(), [1, 3, 2]) - - - def test_getMessage(self): - """ - L{StringListMailbox.getMessage} returns a file-like object from which - the contents of the message at the given offset into the mailbox can be - read. - """ - mailbox = mail.maildir.StringListMailbox(["foo", "real contents"]) - self.assertEqual(mailbox.getMessage(1).read(), "real contents") - - - def test_getUidl(self): - """ - L{StringListMailbox.getUidl} returns a unique identifier for the - message at the given offset into the mailbox. - """ - mailbox = mail.maildir.StringListMailbox(["foo", "bar"]) - self.assertNotEqual(mailbox.getUidl(0), mailbox.getUidl(1)) - - - def test_deleteMessage(self): - """ - L{StringListMailbox.deleteMessage} marks a message for deletion causing - further requests for its length to return 0. - """ - mailbox = mail.maildir.StringListMailbox(["foo"]) - mailbox.deleteMessage(0) - self.assertEqual(mailbox.listMessages(0), 0) - self.assertEqual(mailbox.listMessages(), [0]) - - - def test_undeleteMessages(self): - """ - L{StringListMailbox.undeleteMessages} causes any messages marked for - deletion to be returned to their original state. - """ - mailbox = mail.maildir.StringListMailbox(["foo"]) - mailbox.deleteMessage(0) - mailbox.undeleteMessages() - self.assertEqual(mailbox.listMessages(0), 3) - self.assertEqual(mailbox.listMessages(), [3]) - - - def test_sync(self): - """ - L{StringListMailbox.sync} causes any messages as marked for deletion to - be permanently deleted. - """ - mailbox = mail.maildir.StringListMailbox(["foo"]) - mailbox.deleteMessage(0) - mailbox.sync() - mailbox.undeleteMessages() - self.assertEqual(mailbox.listMessages(0), 0) - self.assertEqual(mailbox.listMessages(), [0]) - - - -class FailingMaildirMailboxAppendMessageTask(mail.maildir._MaildirMailboxAppendMessageTask): - _openstate = True - _writestate = True - _renamestate = True - def osopen(self, fn, attr, mode): - if self._openstate: - return os.open(fn, attr, mode) - else: - raise OSError(errno.EPERM, "Faked Permission Problem") - def oswrite(self, fh, data): - if self._writestate: - return os.write(fh, data) - else: - raise OSError(errno.ENOSPC, "Faked Space problem") - def osrename(self, oldname, newname): - if self._renamestate: - return os.rename(oldname, newname) - else: - raise OSError(errno.EPERM, "Faked Permission Problem") - - -class _AppendTestMixin(object): - """ - Mixin for L{MaildirMailbox.appendMessage} test cases which defines a helper - for serially appending multiple messages to a mailbox. - """ - def _appendMessages(self, mbox, messages): - """ - Deliver the given messages one at a time. Delivery is serialized to - guarantee a predictable order in the mailbox (overlapped message deliver - makes no guarantees about which message which appear first). - """ - results = [] - def append(): - for m in messages: - d = mbox.appendMessage(m) - d.addCallback(results.append) - yield d - d = task.cooperate(append()).whenDone() - d.addCallback(lambda ignored: results) - return d - - - -class MaildirAppendStringTests(unittest.TestCase, _AppendTestMixin): - """ - Tests for L{MaildirMailbox.appendMessage} when invoked with a C{str}. - """ - def setUp(self): - self.d = self.mktemp() - mail.maildir.initializeMaildir(self.d) - - - def _append(self, ignored, mbox): - d = mbox.appendMessage('TEST') - return self.assertFailure(d, Exception) - - - def _setState(self, ignored, mbox, rename=None, write=None, open=None): - """ - Change the behavior of future C{rename}, C{write}, or C{open} calls made - by the mailbox C{mbox}. - - @param rename: If not C{None}, a new value for the C{_renamestate} - attribute of the mailbox's append factory. The original value will - be restored at the end of the test. - - @param write: Like C{rename}, but for the C{_writestate} attribute. - - @param open: Like C{rename}, but for the C{_openstate} attribute. - """ - if rename is not None: - self.addCleanup( - setattr, mbox.AppendFactory, '_renamestate', - mbox.AppendFactory._renamestate) - mbox.AppendFactory._renamestate = rename - if write is not None: - self.addCleanup( - setattr, mbox.AppendFactory, '_writestate', - mbox.AppendFactory._writestate) - mbox.AppendFactory._writestate = write - if open is not None: - self.addCleanup( - setattr, mbox.AppendFactory, '_openstate', - mbox.AppendFactory._openstate) - mbox.AppendFactory._openstate = open - - - def test_append(self): - """ - L{MaildirMailbox.appendMessage} returns a L{Deferred} which fires when - the message has been added to the end of the mailbox. - """ - mbox = mail.maildir.MaildirMailbox(self.d) - mbox.AppendFactory = FailingMaildirMailboxAppendMessageTask - - d = self._appendMessages(mbox, ["X" * i for i in range(1, 11)]) - d.addCallback(self.assertEqual, [None] * 10) - d.addCallback(self._cbTestAppend, mbox) - return d - - - def _cbTestAppend(self, ignored, mbox): - """ - Check that the mailbox has the expected number (ten) of messages in it, - and that each has the expected contents, and that they are in the same - order as that in which they were appended. - """ - self.assertEqual(len(mbox.listMessages()), 10) - self.assertEqual( - [len(mbox.getMessage(i).read()) for i in range(10)], - range(1, 11)) - # test in the right order: last to first error location. - self._setState(None, mbox, rename=False) - d = self._append(None, mbox) - d.addCallback(self._setState, mbox, rename=True, write=False) - d.addCallback(self._append, mbox) - d.addCallback(self._setState, mbox, write=True, open=False) - d.addCallback(self._append, mbox) - d.addCallback(self._setState, mbox, open=True) - return d - - - -class MaildirAppendFileTests(unittest.TestCase, _AppendTestMixin): - """ - Tests for L{MaildirMailbox.appendMessage} when invoked with a C{str}. - """ - def setUp(self): - self.d = self.mktemp() - mail.maildir.initializeMaildir(self.d) - - - def test_append(self): - """ - L{MaildirMailbox.appendMessage} returns a L{Deferred} which fires when - the message has been added to the end of the mailbox. - """ - mbox = mail.maildir.MaildirMailbox(self.d) - messages = [] - for i in xrange(1, 11): - temp = tempfile.TemporaryFile() - temp.write("X" * i) - temp.seek(0, 0) - messages.append(temp) - self.addCleanup(temp.close) - - d = self._appendMessages(mbox, messages) - d.addCallback(self._cbTestAppend, mbox) - return d - - - def _cbTestAppend(self, result, mbox): - """ - Check that the mailbox has the expected number (ten) of messages in it, - and that each has the expected contents, and that they are in the same - order as that in which they were appended. - """ - self.assertEqual(len(mbox.listMessages()), 10) - self.assertEqual( - [len(mbox.getMessage(i).read()) for i in range(10)], - range(1, 11)) - - - -class MaildirTests(unittest.TestCase): - def setUp(self): - self.d = self.mktemp() - mail.maildir.initializeMaildir(self.d) - - def tearDown(self): - shutil.rmtree(self.d) - - def testInitializer(self): - d = self.d - trash = os.path.join(d, '.Trash') - - self.failUnless(os.path.exists(d) and os.path.isdir(d)) - self.failUnless(os.path.exists(os.path.join(d, 'new'))) - self.failUnless(os.path.exists(os.path.join(d, 'cur'))) - self.failUnless(os.path.exists(os.path.join(d, 'tmp'))) - self.failUnless(os.path.isdir(os.path.join(d, 'new'))) - self.failUnless(os.path.isdir(os.path.join(d, 'cur'))) - self.failUnless(os.path.isdir(os.path.join(d, 'tmp'))) - - self.failUnless(os.path.exists(os.path.join(trash, 'new'))) - self.failUnless(os.path.exists(os.path.join(trash, 'cur'))) - self.failUnless(os.path.exists(os.path.join(trash, 'tmp'))) - self.failUnless(os.path.isdir(os.path.join(trash, 'new'))) - self.failUnless(os.path.isdir(os.path.join(trash, 'cur'))) - self.failUnless(os.path.isdir(os.path.join(trash, 'tmp'))) - - - def test_nameGenerator(self): - """ - Each call to L{_MaildirNameGenerator.generate} returns a unique - string suitable for use as the basename of a new message file. The - names are ordered such that those generated earlier sort less than - those generated later. - """ - clock = task.Clock() - clock.advance(0.05) - generator = mail.maildir._MaildirNameGenerator(clock) - - firstName = generator.generate() - clock.advance(0.05) - secondName = generator.generate() - - self.assertTrue(firstName < secondName) - - - def test_mailbox(self): - """ - Exercise the methods of L{IMailbox} as implemented by - L{MaildirMailbox}. - """ - j = os.path.join - n = mail.maildir._generateMaildirName - msgs = [j(b, n()) for b in ('cur', 'new') for x in range(5)] - - # Toss a few files into the mailbox - i = 1 - for f in msgs: - fObj = file(j(self.d, f), 'w') - fObj.write('x' * i) - fObj.close() - i = i + 1 - - mb = mail.maildir.MaildirMailbox(self.d) - self.assertEqual(mb.listMessages(), range(1, 11)) - self.assertEqual(mb.listMessages(1), 2) - self.assertEqual(mb.listMessages(5), 6) - - self.assertEqual(mb.getMessage(6).read(), 'x' * 7) - self.assertEqual(mb.getMessage(1).read(), 'x' * 2) - - d = {} - for i in range(10): - u = mb.getUidl(i) - self.failIf(u in d) - d[u] = None - - p, f = os.path.split(msgs[5]) - - mb.deleteMessage(5) - self.assertEqual(mb.listMessages(5), 0) - self.failUnless(os.path.exists(j(self.d, '.Trash', 'cur', f))) - self.failIf(os.path.exists(j(self.d, msgs[5]))) - - mb.undeleteMessages() - self.assertEqual(mb.listMessages(5), 6) - self.failIf(os.path.exists(j(self.d, '.Trash', 'cur', f))) - self.failUnless(os.path.exists(j(self.d, msgs[5]))) - - - -class AbstractMaildirDomainTests(unittest.TestCase): - """ - Tests for L{twisted.mail.maildir.AbstractMaildirDomain}. - """ - def test_interface(self): - """ - L{maildir.AbstractMaildirDomain} implements L{mail.IAliasableDomain}. - """ - verifyClass(mail.mail.IAliasableDomain, - mail.maildir.AbstractMaildirDomain) - - - -class MaildirDirdbmDomainTests(unittest.TestCase): - """ - Tests for L{MaildirDirdbmDomain}. - """ - def setUp(self): - """ - Create a temporary L{MaildirDirdbmDomain} and parent - L{MailService} before running each test. - """ - self.P = self.mktemp() - self.S = mail.mail.MailService() - self.D = mail.maildir.MaildirDirdbmDomain(self.S, self.P) - - - def tearDown(self): - """ - Remove the temporary C{maildir} directory when the test has - finished. - """ - shutil.rmtree(self.P) - - - def test_addUser(self): - """ - L{MaildirDirdbmDomain.addUser} accepts a user and password - argument. It stores those in a C{dbm} dictionary - attribute and creates a directory for each user. - """ - toAdd = (('user1', 'pwd1'), ('user2', 'pwd2'), ('user3', 'pwd3')) - for (u, p) in toAdd: - self.D.addUser(u, p) - - for (u, p) in toAdd: - self.failUnless(u in self.D.dbm) - self.assertEqual(self.D.dbm[u], p) - self.failUnless(os.path.exists(os.path.join(self.P, u))) - - - def test_credentials(self): - """ - L{MaildirDirdbmDomain.getCredentialsCheckers} initializes and - returns one L{ICredentialsChecker} checker by default. - """ - creds = self.D.getCredentialsCheckers() - - self.assertEqual(len(creds), 1) - self.failUnless(cred.checkers.ICredentialsChecker.providedBy(creds[0])) - self.failUnless(cred.credentials.IUsernamePassword in creds[0].credentialInterfaces) - - - def test_requestAvatar(self): - """ - L{MaildirDirdbmDomain.requestAvatar} raises L{NotImplementedError} - unless it is supplied with an L{pop3.IMailbox} interface. - When called with an L{pop3.IMailbox}, it returns a 3-tuple - containing L{pop3.IMailbox}, an implementation of that interface - and a NOOP callable. - """ - class ISomething(Interface): - pass - - self.D.addUser('user', 'password') - self.assertRaises( - NotImplementedError, - self.D.requestAvatar, 'user', None, ISomething - ) - - t = self.D.requestAvatar('user', None, pop3.IMailbox) - self.assertEqual(len(t), 3) - self.failUnless(t[0] is pop3.IMailbox) - self.failUnless(pop3.IMailbox.providedBy(t[1])) - - t[2]() - - - def test_requestAvatarId(self): - """ - L{DirdbmDatabase.requestAvatarId} raises L{UnauthorizedLogin} if - supplied with invalid user credentials. - When called with valid credentials, L{requestAvatarId} returns - the username associated with the supplied credentials. - """ - self.D.addUser('user', 'password') - database = self.D.getCredentialsCheckers()[0] - - creds = cred.credentials.UsernamePassword('user', 'wrong password') - self.assertRaises( - cred.error.UnauthorizedLogin, - database.requestAvatarId, creds - ) - - creds = cred.credentials.UsernamePassword('user', 'password') - self.assertEqual(database.requestAvatarId(creds), 'user') - - - def test_userDirectory(self): - """ - L{MaildirDirdbmDomain.userDirectory} is supplied with a user name - and returns the path to that user's maildir subdirectory. - Calling L{MaildirDirdbmDomain.userDirectory} with a - non-existent user returns the 'postmaster' directory if there - is a postmaster or returns L{None} if there is no postmaster. - """ - self.D.addUser('user', 'password') - self.assertEqual(self.D.userDirectory('user'), - os.path.join(self.D.root, 'user')) - - self.D.postmaster = False - self.assertIdentical(self.D.userDirectory('nouser'), None) - - self.D.postmaster = True - self.assertEqual(self.D.userDirectory('nouser'), - os.path.join(self.D.root, 'postmaster')) - - - -class StubAliasableDomain(object): - """ - Minimal testable implementation of IAliasableDomain. - """ - implements(mail.mail.IAliasableDomain) - - def exists(self, user): - """ - No test coverage for invocations of this method on domain objects, - so we just won't implement it. - """ - raise NotImplementedError() - - - def addUser(self, user, password): - """ - No test coverage for invocations of this method on domain objects, - so we just won't implement it. - """ - raise NotImplementedError() - - - def getCredentialsCheckers(self): - """ - This needs to succeed in order for other tests to complete - successfully, but we don't actually assert anything about its - behavior. Return an empty list. Sometime later we should return - something else and assert that a portal got set up properly. - """ - return [] - - - def setAliasGroup(self, aliases): - """ - Just record the value so the test can check it later. - """ - self.aliasGroup = aliases - - -class ServiceDomainTests(unittest.TestCase): - def setUp(self): - self.S = mail.mail.MailService() - self.D = mail.protocols.DomainDeliveryBase(self.S, None) - self.D.service = self.S - self.D.protocolName = 'TEST' - self.D.host = 'hostname' - - self.tmpdir = self.mktemp() - domain = mail.maildir.MaildirDirdbmDomain(self.S, self.tmpdir) - domain.addUser('user', 'password') - self.S.addDomain('test.domain', domain) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - - def testAddAliasableDomain(self): - """ - Test that adding an IAliasableDomain to a mail service properly sets - up alias group references and such. - """ - aliases = object() - domain = StubAliasableDomain() - self.S.aliases = aliases - self.S.addDomain('example.com', domain) - self.assertIdentical(domain.aliasGroup, aliases) - - - def testReceivedHeader(self): - hdr = self.D.receivedHeader( - ('remotehost', '123.232.101.234'), - smtp.Address(''), - ['user@host.name'] - ) - fp = StringIO.StringIO(hdr) - m = rfc822.Message(fp) - self.assertEqual(len(m.items()), 1) - self.assertIn('Received', m) - - def testValidateTo(self): - user = smtp.User('user@test.domain', 'helo', None, 'wherever@whatever') - return defer.maybeDeferred(self.D.validateTo, user - ).addCallback(self._cbValidateTo - ) - - def _cbValidateTo(self, result): - self.failUnless(callable(result)) - - def testValidateToBadUsername(self): - user = smtp.User('resu@test.domain', 'helo', None, 'wherever@whatever') - return self.assertFailure( - defer.maybeDeferred(self.D.validateTo, user), - smtp.SMTPBadRcpt) - - def testValidateToBadDomain(self): - user = smtp.User('user@domain.test', 'helo', None, 'wherever@whatever') - return self.assertFailure( - defer.maybeDeferred(self.D.validateTo, user), - smtp.SMTPBadRcpt) - - def testValidateFrom(self): - helo = ('hostname', '127.0.0.1') - origin = smtp.Address('') - self.failUnless(self.D.validateFrom(helo, origin) is origin) - - helo = ('hostname', '1.2.3.4') - origin = smtp.Address('') - self.failUnless(self.D.validateFrom(helo, origin) is origin) - - helo = ('hostname', '1.2.3.4') - origin = smtp.Address('<>') - self.failUnless(self.D.validateFrom(helo, origin) is origin) - - self.assertRaises( - smtp.SMTPBadSender, - self.D.validateFrom, None, origin - ) - -class VirtualPOP3Tests(unittest.TestCase): - def setUp(self): - self.tmpdir = self.mktemp() - self.S = mail.mail.MailService() - self.D = mail.maildir.MaildirDirdbmDomain(self.S, self.tmpdir) - self.D.addUser('user', 'password') - self.S.addDomain('test.domain', self.D) - - portal = cred.portal.Portal(self.D) - map(portal.registerChecker, self.D.getCredentialsCheckers()) - self.S.portals[''] = self.S.portals['test.domain'] = portal - - self.P = mail.protocols.VirtualPOP3() - self.P.service = self.S - self.P.magic = '' - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def testAuthenticateAPOP(self): - resp = md5(self.P.magic + 'password').hexdigest() - return self.P.authenticateUserAPOP('user', resp - ).addCallback(self._cbAuthenticateAPOP - ) - - def _cbAuthenticateAPOP(self, result): - self.assertEqual(len(result), 3) - self.assertEqual(result[0], pop3.IMailbox) - self.failUnless(pop3.IMailbox.providedBy(result[1])) - result[2]() - - def testAuthenticateIncorrectUserAPOP(self): - resp = md5(self.P.magic + 'password').hexdigest() - return self.assertFailure( - self.P.authenticateUserAPOP('resu', resp), - cred.error.UnauthorizedLogin) - - def testAuthenticateIncorrectResponseAPOP(self): - resp = md5('wrong digest').hexdigest() - return self.assertFailure( - self.P.authenticateUserAPOP('user', resp), - cred.error.UnauthorizedLogin) - - def testAuthenticatePASS(self): - return self.P.authenticateUserPASS('user', 'password' - ).addCallback(self._cbAuthenticatePASS - ) - - def _cbAuthenticatePASS(self, result): - self.assertEqual(len(result), 3) - self.assertEqual(result[0], pop3.IMailbox) - self.failUnless(pop3.IMailbox.providedBy(result[1])) - result[2]() - - def testAuthenticateBadUserPASS(self): - return self.assertFailure( - self.P.authenticateUserPASS('resu', 'password'), - cred.error.UnauthorizedLogin) - - def testAuthenticateBadPasswordPASS(self): - return self.assertFailure( - self.P.authenticateUserPASS('user', 'wrong password'), - cred.error.UnauthorizedLogin) - - - -class empty(smtp.User): - def __init__(self): - pass - - - -class RelayTests(unittest.TestCase): - def testExists(self): - service = mail.mail.MailService() - domain = mail.relay.DomainQueuer(service) - - doRelay = [ - address.UNIXAddress('/var/run/mail-relay'), - address.IPv4Address('TCP', '127.0.0.1', 12345), - ] - - dontRelay = [ - address.IPv4Address('TCP', '192.168.2.1', 62), - address.IPv4Address('TCP', '1.2.3.4', 1943), - ] - - for peer in doRelay: - user = empty() - user.orig = 'user@host' - user.dest = 'tsoh@resu' - user.protocol = empty() - user.protocol.transport = empty() - user.protocol.transport.getPeer = lambda: peer - - self.failUnless(callable(domain.exists(user))) - - for peer in dontRelay: - user = empty() - user.orig = 'some@place' - user.protocol = empty() - user.protocol.transport = empty() - user.protocol.transport.getPeer = lambda: peer - user.dest = 'who@cares' - - self.assertRaises(smtp.SMTPBadRcpt, domain.exists, user) - - - -class RelayerTests(unittest.TestCase): - def setUp(self): - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - self.messageFiles = [] - for i in range(10): - name = os.path.join(self.tmpdir, 'body-%d' % (i,)) - f = file(name + '-H', 'w') - pickle.dump(['from-%d' % (i,), 'to-%d' % (i,)], f) - f.close() - - f = file(name + '-D', 'w') - f.write(name) - f.seek(0, 0) - self.messageFiles.append(name) - - self.R = mail.relay.RelayerMixin() - self.R.loadMessages(self.messageFiles) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def testMailFrom(self): - for i in range(10): - self.assertEqual(self.R.getMailFrom(), 'from-%d' % (i,)) - self.R.sentMail(250, None, None, None, None) - self.assertEqual(self.R.getMailFrom(), None) - - def testMailTo(self): - for i in range(10): - self.assertEqual(self.R.getMailTo(), ['to-%d' % (i,)]) - self.R.sentMail(250, None, None, None, None) - self.assertEqual(self.R.getMailTo(), None) - - def testMailData(self): - for i in range(10): - name = os.path.join(self.tmpdir, 'body-%d' % (i,)) - self.assertEqual(self.R.getMailData().read(), name) - self.R.sentMail(250, None, None, None, None) - self.assertEqual(self.R.getMailData(), None) - -class Manager: - def __init__(self): - self.success = [] - self.failure = [] - self.done = [] - - def notifySuccess(self, factory, message): - self.success.append((factory, message)) - - def notifyFailure(self, factory, message): - self.failure.append((factory, message)) - - def notifyDone(self, factory): - self.done.append(factory) - -class ManagedRelayerTests(unittest.TestCase): - def setUp(self): - self.manager = Manager() - self.messages = range(0, 20, 2) - self.factory = object() - self.relay = mail.relaymanager.ManagedRelayerMixin(self.manager) - self.relay.messages = self.messages[:] - self.relay.names = self.messages[:] - self.relay.factory = self.factory - - def testSuccessfulSentMail(self): - for i in self.messages: - self.relay.sentMail(250, None, None, None, None) - - self.assertEqual( - self.manager.success, - [(self.factory, m) for m in self.messages] - ) - - def testFailedSentMail(self): - for i in self.messages: - self.relay.sentMail(550, None, None, None, None) - - self.assertEqual( - self.manager.failure, - [(self.factory, m) for m in self.messages] - ) - - def testConnectionLost(self): - self.relay.connectionLost(failure.Failure(Exception())) - self.assertEqual(self.manager.done, [self.factory]) - -class DirectoryQueueTests(unittest.TestCase): - def setUp(self): - # This is almost a test case itself. - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - self.queue = mail.relaymanager.Queue(self.tmpdir) - self.queue.noisy = False - for m in range(25): - hdrF, msgF = self.queue.createNewMessage() - pickle.dump(['header', m], hdrF) - hdrF.close() - msgF.lineReceived('body: %d' % (m,)) - msgF.eomReceived() - self.queue.readDirectory() - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def testWaiting(self): - self.failUnless(self.queue.hasWaiting()) - self.assertEqual(len(self.queue.getWaiting()), 25) - - waiting = self.queue.getWaiting() - self.queue.setRelaying(waiting[0]) - self.assertEqual(len(self.queue.getWaiting()), 24) - - self.queue.setWaiting(waiting[0]) - self.assertEqual(len(self.queue.getWaiting()), 25) - - def testRelaying(self): - for m in self.queue.getWaiting(): - self.queue.setRelaying(m) - self.assertEqual( - len(self.queue.getRelayed()), - 25 - len(self.queue.getWaiting()) - ) - - self.failIf(self.queue.hasWaiting()) - - relayed = self.queue.getRelayed() - self.queue.setWaiting(relayed[0]) - self.assertEqual(len(self.queue.getWaiting()), 1) - self.assertEqual(len(self.queue.getRelayed()), 24) - - def testDone(self): - msg = self.queue.getWaiting()[0] - self.queue.setRelaying(msg) - self.queue.done(msg) - - self.assertEqual(len(self.queue.getWaiting()), 24) - self.assertEqual(len(self.queue.getRelayed()), 0) - - self.failIf(msg in self.queue.getWaiting()) - self.failIf(msg in self.queue.getRelayed()) - - def testEnvelope(self): - envelopes = [] - - for msg in self.queue.getWaiting(): - envelopes.append(self.queue.getEnvelope(msg)) - - envelopes.sort() - for i in range(25): - self.assertEqual( - envelopes.pop(0), - ['header', i] - ) - -from twisted.names import server -from twisted.names import client -from twisted.names import common - -class TestAuthority(common.ResolverBase): - def __init__(self): - common.ResolverBase.__init__(self) - self.addresses = {} - - def _lookup(self, name, cls, type, timeout = None): - if name in self.addresses and type == dns.MX: - results = [] - for a in self.addresses[name]: - hdr = dns.RRHeader( - name, dns.MX, dns.IN, 60, dns.Record_MX(0, a) - ) - results.append(hdr) - return defer.succeed((results, [], [])) - return defer.fail(failure.Failure(dns.DomainError(name))) - -def setUpDNS(self): - self.auth = TestAuthority() - factory = server.DNSServerFactory([self.auth]) - protocol = dns.DNSDatagramProtocol(factory) - while 1: - self.port = reactor.listenTCP(0, factory, interface='127.0.0.1') - portNumber = self.port.getHost().port - - try: - self.udpPort = reactor.listenUDP(portNumber, protocol, interface='127.0.0.1') - except CannotListenError: - self.port.stopListening() - else: - break - self.resolver = client.Resolver(servers=[('127.0.0.1', portNumber)]) - - -def tearDownDNS(self): - dl = [] - dl.append(defer.maybeDeferred(self.port.stopListening)) - dl.append(defer.maybeDeferred(self.udpPort.stopListening)) - try: - self.resolver._parseCall.cancel() - except: - pass - return defer.DeferredList(dl) - -class MXTests(unittest.TestCase): - """ - Tests for L{mail.relaymanager.MXCalculator}. - """ - def setUp(self): - setUpDNS(self) - self.clock = task.Clock() - self.mx = mail.relaymanager.MXCalculator(self.resolver, self.clock) - - def tearDown(self): - return tearDownDNS(self) - - - def test_defaultClock(self): - """ - L{MXCalculator}'s default clock is C{twisted.internet.reactor}. - """ - self.assertIdentical( - mail.relaymanager.MXCalculator(self.resolver).clock, - reactor) - - - def testSimpleSuccess(self): - self.auth.addresses['test.domain'] = ['the.email.test.domain'] - return self.mx.getMX('test.domain').addCallback(self._cbSimpleSuccess) - - def _cbSimpleSuccess(self, mx): - self.assertEqual(mx.preference, 0) - self.assertEqual(str(mx.name), 'the.email.test.domain') - - def testSimpleFailure(self): - self.mx.fallbackToDomain = False - return self.assertFailure(self.mx.getMX('test.domain'), IOError) - - def testSimpleFailureWithFallback(self): - return self.assertFailure(self.mx.getMX('test.domain'), DNSLookupError) - - - def _exchangeTest(self, domain, records, correctMailExchange): - """ - Issue an MX request for the given domain and arrange for it to be - responded to with the given records. Verify that the resulting mail - exchange is the indicated host. - - @type domain: C{str} - @type records: C{list} of L{RRHeader} - @type correctMailExchange: C{str} - @rtype: L{Deferred} - """ - class DummyResolver(object): - def lookupMailExchange(self, name): - if name == domain: - return defer.succeed(( - records, - [], - [])) - return defer.fail(DNSNameError(domain)) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(domain) - def gotMailExchange(record): - self.assertEqual(str(record.name), correctMailExchange) - d.addCallback(gotMailExchange) - return d - - - def test_mailExchangePreference(self): - """ - The MX record with the lowest preference is returned by - L{MXCalculator.getMX}. - """ - domain = "example.com" - good = "good.example.com" - bad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, bad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, good)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(2, bad))] - return self._exchangeTest(domain, records, good) - - - def test_badExchangeExcluded(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - which is not also marked as bad. - """ - domain = "example.com" - good = "good.example.com" - bad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, bad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, good))] - self.mx.markBad(bad) - return self._exchangeTest(domain, records, good) - - - def test_fallbackForAllBadExchanges(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - if all the MX records in the response have been marked bad. - """ - domain = "example.com" - bad = "bad.example.com" - worse = "worse.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, bad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, worse))] - self.mx.markBad(bad) - self.mx.markBad(worse) - return self._exchangeTest(domain, records, bad) - - - def test_badExchangeExpires(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - if it was last marked bad longer than L{MXCalculator.timeOutBadMX} - seconds ago. - """ - domain = "example.com" - good = "good.example.com" - previouslyBad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, previouslyBad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, good))] - self.mx.markBad(previouslyBad) - self.clock.advance(self.mx.timeOutBadMX) - return self._exchangeTest(domain, records, previouslyBad) - - - def test_goodExchangeUsed(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - if it was marked good after it was marked bad. - """ - domain = "example.com" - good = "good.example.com" - previouslyBad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, previouslyBad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, good))] - self.mx.markBad(previouslyBad) - self.mx.markGood(previouslyBad) - self.clock.advance(self.mx.timeOutBadMX) - return self._exchangeTest(domain, records, previouslyBad) - - - def test_successWithoutResults(self): - """ - If an MX lookup succeeds but the result set is empty, - L{MXCalculator.getMX} should try to look up an I{A} record for the - requested name and call back its returned Deferred with that - address. - """ - ip = '1.2.3.4' - domain = 'example.org' - - class DummyResolver(object): - """ - Fake resolver which will respond to an MX lookup with an empty - result set. - - @ivar mx: A dictionary mapping hostnames to three-tuples of - results to be returned from I{MX} lookups. - - @ivar a: A dictionary mapping hostnames to addresses to be - returned from I{A} lookups. - """ - mx = {domain: ([], [], [])} - a = {domain: ip} - - def lookupMailExchange(self, domain): - return defer.succeed(self.mx[domain]) - - def getHostByName(self, domain): - return defer.succeed(self.a[domain]) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(domain) - d.addCallback(self.assertEqual, Record_MX(name=ip)) - return d - - - def test_failureWithSuccessfulFallback(self): - """ - Test that if the MX record lookup fails, fallback is enabled, and an A - record is available for the name, then the Deferred returned by - L{MXCalculator.getMX} ultimately fires with a Record_MX instance which - gives the address in the A record for the name. - """ - class DummyResolver(object): - """ - Fake resolver which will fail an MX lookup but then succeed a - getHostByName call. - """ - def lookupMailExchange(self, domain): - return defer.fail(DNSNameError()) - - def getHostByName(self, domain): - return defer.succeed("1.2.3.4") - - self.mx.resolver = DummyResolver() - d = self.mx.getMX("domain") - d.addCallback(self.assertEqual, Record_MX(name="1.2.3.4")) - return d - - - def test_cnameWithoutGlueRecords(self): - """ - If an MX lookup returns a single CNAME record as a result, MXCalculator - will perform an MX lookup for the canonical name indicated and return - the MX record which results. - """ - alias = "alias.example.com" - canonical = "canonical.example.com" - exchange = "mail.example.com" - - class DummyResolver(object): - """ - Fake resolver which will return a CNAME for an MX lookup of a name - which is an alias and an MX for an MX lookup of the canonical name. - """ - def lookupMailExchange(self, domain): - if domain == alias: - return defer.succeed(( - [RRHeader(name=domain, - type=Record_CNAME.TYPE, - payload=Record_CNAME(canonical))], - [], [])) - elif domain == canonical: - return defer.succeed(( - [RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, exchange))], - [], [])) - else: - return defer.fail(DNSNameError(domain)) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(alias) - d.addCallback(self.assertEqual, Record_MX(name=exchange)) - return d - - - def test_cnameChain(self): - """ - If L{MXCalculator.getMX} encounters a CNAME chain which is longer than - the length specified, the returned L{Deferred} should errback with - L{CanonicalNameChainTooLong}. - """ - class DummyResolver(object): - """ - Fake resolver which generates a CNAME chain of infinite length in - response to MX lookups. - """ - chainCounter = 0 - - def lookupMailExchange(self, domain): - self.chainCounter += 1 - name = 'x-%d.example.com' % (self.chainCounter,) - return defer.succeed(( - [RRHeader(name=domain, - type=Record_CNAME.TYPE, - payload=Record_CNAME(name))], - [], [])) - - cnameLimit = 3 - self.mx.resolver = DummyResolver() - d = self.mx.getMX("mail.example.com", cnameLimit) - self.assertFailure( - d, twisted.mail.relaymanager.CanonicalNameChainTooLong) - def cbChainTooLong(error): - self.assertEqual(error.args[0], Record_CNAME("x-%d.example.com" % (cnameLimit + 1,))) - self.assertEqual(self.mx.resolver.chainCounter, cnameLimit + 1) - d.addCallback(cbChainTooLong) - return d - - - def test_cnameWithGlueRecords(self): - """ - If an MX lookup returns a CNAME and the MX record for the CNAME, the - L{Deferred} returned by L{MXCalculator.getMX} should be called back - with the name from the MX record without further lookups being - attempted. - """ - lookedUp = [] - alias = "alias.example.com" - canonical = "canonical.example.com" - exchange = "mail.example.com" - - class DummyResolver(object): - def lookupMailExchange(self, domain): - if domain != alias or lookedUp: - # Don't give back any results for anything except the alias - # or on any request after the first. - return ([], [], []) - return defer.succeed(( - [RRHeader(name=alias, - type=Record_CNAME.TYPE, - payload=Record_CNAME(canonical)), - RRHeader(name=canonical, - type=Record_MX.TYPE, - payload=Record_MX(name=exchange))], - [], [])) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(alias) - d.addCallback(self.assertEqual, Record_MX(name=exchange)) - return d - - - def test_cnameLoopWithGlueRecords(self): - """ - If an MX lookup returns two CNAME records which point to each other, - the loop should be detected and the L{Deferred} returned by - L{MXCalculator.getMX} should be errbacked with L{CanonicalNameLoop}. - """ - firstAlias = "cname1.example.com" - secondAlias = "cname2.example.com" - - class DummyResolver(object): - def lookupMailExchange(self, domain): - return defer.succeed(( - [RRHeader(name=firstAlias, - type=Record_CNAME.TYPE, - payload=Record_CNAME(secondAlias)), - RRHeader(name=secondAlias, - type=Record_CNAME.TYPE, - payload=Record_CNAME(firstAlias))], - [], [])) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(firstAlias) - self.assertFailure(d, twisted.mail.relaymanager.CanonicalNameLoop) - return d - - - def testManyRecords(self): - self.auth.addresses['test.domain'] = [ - 'mx1.test.domain', 'mx2.test.domain', 'mx3.test.domain' - ] - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsSuccessfulLookup - ) - - def _cbManyRecordsSuccessfulLookup(self, mx): - self.failUnless(str(mx.name).split('.', 1)[0] in ('mx1', 'mx2', 'mx3')) - self.mx.markBad(str(mx.name)) - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsDifferentResult, mx - ) - - def _cbManyRecordsDifferentResult(self, nextMX, mx): - self.assertNotEqual(str(mx.name), str(nextMX.name)) - self.mx.markBad(str(nextMX.name)) - - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsLastResult, mx, nextMX - ) - - def _cbManyRecordsLastResult(self, lastMX, mx, nextMX): - self.assertNotEqual(str(mx.name), str(lastMX.name)) - self.assertNotEqual(str(nextMX.name), str(lastMX.name)) - - self.mx.markBad(str(lastMX.name)) - self.mx.markGood(str(nextMX.name)) - - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsRepeatSpecificResult, nextMX - ) - - def _cbManyRecordsRepeatSpecificResult(self, againMX, nextMX): - self.assertEqual(str(againMX.name), str(nextMX.name)) - -class LiveFireExerciseTests(unittest.TestCase): - if interfaces.IReactorUDP(reactor, None) is None: - skip = "UDP support is required to determining MX records" - - def setUp(self): - setUpDNS(self) - self.tmpdirs = [ - 'domainDir', 'insertionDomain', 'insertionQueue', - 'destinationDomain', 'destinationQueue' - ] - - def tearDown(self): - for d in self.tmpdirs: - if os.path.exists(d): - shutil.rmtree(d) - return tearDownDNS(self) - - def testLocalDelivery(self): - service = mail.mail.MailService() - service.smtpPortal.registerChecker(cred.checkers.AllowAnonymousAccess()) - domain = mail.maildir.MaildirDirdbmDomain(service, 'domainDir') - domain.addUser('user', 'password') - service.addDomain('test.domain', domain) - service.portals[''] = service.portals['test.domain'] - map(service.portals[''].registerChecker, domain.getCredentialsCheckers()) - - service.setQueue(mail.relay.DomainQueuer(service)) - - f = service.getSMTPFactory() - - self.smtpServer = reactor.listenTCP(0, f, interface='127.0.0.1') - - client = LineSendingProtocol([ - 'HELO meson', - 'MAIL FROM: ', - 'RCPT TO: ', - 'DATA', - 'This is the message', - '.', - 'QUIT' - ]) - - done = Deferred() - f = protocol.ClientFactory() - f.protocol = lambda: client - f.clientConnectionLost = lambda *args: done.callback(None) - reactor.connectTCP('127.0.0.1', self.smtpServer.getHost().port, f) - - def finished(ign): - mbox = domain.requestAvatar('user', None, pop3.IMailbox)[1] - msg = mbox.getMessage(0).read() - self.failIfEqual(msg.find('This is the message'), -1) - - return self.smtpServer.stopListening() - done.addCallback(finished) - return done - - - def testRelayDelivery(self): - # Here is the service we will connect to and send mail from - insServ = mail.mail.MailService() - insServ.smtpPortal.registerChecker(cred.checkers.AllowAnonymousAccess()) - domain = mail.maildir.MaildirDirdbmDomain(insServ, 'insertionDomain') - insServ.addDomain('insertion.domain', domain) - os.mkdir('insertionQueue') - insServ.setQueue(mail.relaymanager.Queue('insertionQueue')) - insServ.domains.setDefaultDomain(mail.relay.DomainQueuer(insServ)) - manager = mail.relaymanager.SmartHostSMTPRelayingManager(insServ.queue) - manager.fArgs += ('test.identity.hostname',) - helper = mail.relaymanager.RelayStateHelper(manager, 1) - # Yoink! Now the internet obeys OUR every whim! - manager.mxcalc = mail.relaymanager.MXCalculator(self.resolver) - # And this is our whim. - self.auth.addresses['destination.domain'] = ['127.0.0.1'] - - f = insServ.getSMTPFactory() - self.insServer = reactor.listenTCP(0, f, interface='127.0.0.1') - - # Here is the service the previous one will connect to for final - # delivery - destServ = mail.mail.MailService() - destServ.smtpPortal.registerChecker(cred.checkers.AllowAnonymousAccess()) - domain = mail.maildir.MaildirDirdbmDomain(destServ, 'destinationDomain') - domain.addUser('user', 'password') - destServ.addDomain('destination.domain', domain) - os.mkdir('destinationQueue') - destServ.setQueue(mail.relaymanager.Queue('destinationQueue')) - helper = mail.relaymanager.RelayStateHelper(manager, 1) - helper.startService() - - f = destServ.getSMTPFactory() - self.destServer = reactor.listenTCP(0, f, interface='127.0.0.1') - - # Update the port number the *first* relay will connect to, because we can't use - # port 25 - manager.PORT = self.destServer.getHost().port - - client = LineSendingProtocol([ - 'HELO meson', - 'MAIL FROM: ', - 'RCPT TO: ', - 'DATA', - 'This is the message', - '.', - 'QUIT' - ]) - - done = Deferred() - f = protocol.ClientFactory() - f.protocol = lambda: client - f.clientConnectionLost = lambda *args: done.callback(None) - reactor.connectTCP('127.0.0.1', self.insServer.getHost().port, f) - - def finished(ign): - # First part of the delivery is done. Poke the queue manually now - # so we don't have to wait for the queue to be flushed. - delivery = manager.checkState() - def delivered(ign): - mbox = domain.requestAvatar('user', None, pop3.IMailbox)[1] - msg = mbox.getMessage(0).read() - self.failIfEqual(msg.find('This is the message'), -1) - - self.insServer.stopListening() - self.destServer.stopListening() - helper.stopService() - delivery.addCallback(delivered) - return delivery - done.addCallback(finished) - return done - - -aliasFile = StringIO.StringIO("""\ -# Here's a comment - # woop another one -testuser: address1,address2, address3, - continuation@address, |/bin/process/this - -usertwo:thisaddress,thataddress, lastaddress -lastuser: :/includable, /filename, |/program, address -""") - -class LineBufferMessage: - def __init__(self): - self.lines = [] - self.eom = False - self.lost = False - - def lineReceived(self, line): - self.lines.append(line) - - def eomReceived(self): - self.eom = True - return defer.succeed('') - - def connectionLost(self): - self.lost = True - -class AliasTests(unittest.TestCase): - lines = [ - 'First line', - 'Next line', - '', - 'After a blank line', - 'Last line' - ] - - def setUp(self): - aliasFile.seek(0) - - def testHandle(self): - result = {} - lines = [ - 'user: another@host\n', - 'nextuser: |/bin/program\n', - 'user: me@again\n', - 'moreusers: :/etc/include/filename\n', - 'multiuser: first@host, second@host,last@anotherhost', - ] - - for l in lines: - mail.alias.handle(result, l, 'TestCase', None) - - self.assertEqual(result['user'], ['another@host', 'me@again']) - self.assertEqual(result['nextuser'], ['|/bin/program']) - self.assertEqual(result['moreusers'], [':/etc/include/filename']) - self.assertEqual(result['multiuser'], ['first@host', 'second@host', 'last@anotherhost']) - - def testFileLoader(self): - domains = {'': object()} - result = mail.alias.loadAliasFile(domains, fp=aliasFile) - - self.assertEqual(len(result), 3) - - group = result['testuser'] - s = str(group) - for a in ('address1', 'address2', 'address3', 'continuation@address', '/bin/process/this'): - self.failIfEqual(s.find(a), -1) - self.assertEqual(len(group), 5) - - group = result['usertwo'] - s = str(group) - for a in ('thisaddress', 'thataddress', 'lastaddress'): - self.failIfEqual(s.find(a), -1) - self.assertEqual(len(group), 3) - - group = result['lastuser'] - s = str(group) - self.assertEqual(s.find('/includable'), -1) - for a in ('/filename', 'program', 'address'): - self.failIfEqual(s.find(a), -1, '%s not found' % a) - self.assertEqual(len(group), 3) - - def testMultiWrapper(self): - msgs = LineBufferMessage(), LineBufferMessage(), LineBufferMessage() - msg = mail.alias.MultiWrapper(msgs) - - for L in self.lines: - msg.lineReceived(L) - return msg.eomReceived().addCallback(self._cbMultiWrapper, msgs) - - def _cbMultiWrapper(self, ignored, msgs): - for m in msgs: - self.failUnless(m.eom) - self.failIf(m.lost) - self.assertEqual(self.lines, m.lines) - - def testFileAlias(self): - tmpfile = self.mktemp() - a = mail.alias.FileAlias(tmpfile, None, None) - m = a.createMessageReceiver() - - for l in self.lines: - m.lineReceived(l) - return m.eomReceived().addCallback(self._cbTestFileAlias, tmpfile) - - def _cbTestFileAlias(self, ignored, tmpfile): - lines = file(tmpfile).readlines() - self.assertEqual([L[:-1] for L in lines], self.lines) - - - -class DummyDomain(object): - """ - Test domain for L{AddressAliasTests}. - """ - def __init__(self, address): - self.address = address - - - def exists(self, user, memo=None): - """ - @returns: When a C{memo} is passed in this will raise a - L{smtp.SMTPBadRcpt} exception, otherwise a boolean - indicating if the C{user} and string version of - L{self.address} are equal or not. - @rtype: C{bool} - """ - if memo: - raise mail.smtp.SMTPBadRcpt('ham') - - return lambda: user == str(self.address) - - - -class AddressAliasTests(unittest.TestCase): - """ - Tests for L{twisted.mail.alias.AddressAlias}. - """ - - def setUp(self): - """ - Setup an L{AddressAlias}. - """ - self.address = mail.smtp.Address('foo@bar') - domains = {self.address.domain: DummyDomain(self.address)} - self.alias = mail.alias.AddressAlias(self.address, domains, - self.address) - - - def test_createMessageReceiver(self): - """ - L{createMessageReceiever} calls C{exists()} on the domain object - which key matches the C{alias} passed to L{AddressAlias}. - """ - self.assertTrue(self.alias.createMessageReceiver()) - - - def test_str(self): - """ - The string presentation of L{AddressAlias} includes the alias. - """ - self.assertEqual(str(self.alias), '
') - - - def test_resolve(self): - """ - L{resolve} will look for additional aliases when an C{aliasmap} - dictionary is passed, and returns C{None} if none were found. - """ - self.assertEqual(self.alias.resolve({self.address: 'bar'}), None) - - - def test_resolveWithoutAliasmap(self): - """ - L{resolve} returns C{None} when the alias could not be found in the - C{aliasmap} and no L{mail.smtp.User} with this alias exists either. - """ - self.assertEqual(self.alias.resolve({}), None) - - - -class DummyProcess(object): - __slots__ = ['onEnd'] - - - -class MockProcessAlias(mail.alias.ProcessAlias): - """ - A alias processor that doesn't actually launch processes. - """ - - def spawnProcess(self, proto, program, path): - """ - Don't spawn a process. - """ - - - -class MockAliasGroup(mail.alias.AliasGroup): - """ - An alias group using C{MockProcessAlias}. - """ - processAliasFactory = MockProcessAlias - - - -class StubProcess(object): - """ - Fake implementation of L{IProcessTransport}. - - @ivar signals: A list of all the signals which have been sent to this fake - process. - """ - def __init__(self): - self.signals = [] - - - def loseConnection(self): - """ - No-op implementation of disconnection. - """ - - - def signalProcess(self, signal): - """ - Record a signal sent to this process for later inspection. - """ - self.signals.append(signal) - - - -class ProcessAliasTests(unittest.TestCase): - """ - Tests for alias resolution. - """ - if interfaces.IReactorProcess(reactor, None) is None: - skip = "IReactorProcess not supported" - - lines = [ - 'First line', - 'Next line', - '', - 'After a blank line', - 'Last line' - ] - - def exitStatus(self, code): - """ - Construct a status from the given exit code. - - @type code: L{int} between 0 and 255 inclusive. - @param code: The exit status which the code will represent. - - @rtype: L{int} - @return: A status integer for the given exit code. - """ - # /* Macros for constructing status values. */ - # #define __W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) - status = (code << 8) | 0 - - # Sanity check - self.assertTrue(os.WIFEXITED(status)) - self.assertEqual(os.WEXITSTATUS(status), code) - self.assertFalse(os.WIFSIGNALED(status)) - - return status - - - def signalStatus(self, signal): - """ - Construct a status from the given signal. - - @type signal: L{int} between 0 and 255 inclusive. - @param signal: The signal number which the status will represent. - - @rtype: L{int} - @return: A status integer for the given signal. - """ - # /* If WIFSIGNALED(STATUS), the terminating signal. */ - # #define __WTERMSIG(status) ((status) & 0x7f) - # /* Nonzero if STATUS indicates termination by a signal. */ - # #define __WIFSIGNALED(status) \ - # (((signed char) (((status) & 0x7f) + 1) >> 1) > 0) - status = signal - - # Sanity check - self.assertTrue(os.WIFSIGNALED(status)) - self.assertEqual(os.WTERMSIG(status), signal) - self.assertFalse(os.WIFEXITED(status)) - - return status - - - def setUp(self): - """ - Replace L{smtp.DNSNAME} with a well-known value. - """ - self.DNSNAME = smtp.DNSNAME - smtp.DNSNAME = '' - - - def tearDown(self): - """ - Restore the original value of L{smtp.DNSNAME}. - """ - smtp.DNSNAME = self.DNSNAME - - - def test_processAlias(self): - """ - Standard call to C{mail.alias.ProcessAlias}: check that the specified - script is called, and that the input is correctly transferred to it. - """ - sh = FilePath(self.mktemp()) - sh.setContent("""\ -#!/bin/sh -rm -f process.alias.out -while read i; do - echo $i >> process.alias.out -done""") - os.chmod(sh.path, 0700) - a = mail.alias.ProcessAlias(sh.path, None, None) - m = a.createMessageReceiver() - - for l in self.lines: - m.lineReceived(l) - - def _cbProcessAlias(ignored): - lines = file('process.alias.out').readlines() - self.assertEqual([L[:-1] for L in lines], self.lines) - - return m.eomReceived().addCallback(_cbProcessAlias) - - - def test_processAliasTimeout(self): - """ - If the alias child process does not exit within a particular period of - time, the L{Deferred} returned by L{MessageWrapper.eomReceived} should - fail with L{ProcessAliasTimeout} and send the I{KILL} signal to the - child process.. - """ - reactor = task.Clock() - transport = StubProcess() - proto = mail.alias.ProcessAliasProtocol() - proto.makeConnection(transport) - - receiver = mail.alias.MessageWrapper(proto, None, reactor) - d = receiver.eomReceived() - reactor.advance(receiver.completionTimeout) - def timedOut(ignored): - self.assertEqual(transport.signals, ['KILL']) - # Now that it has been killed, disconnect the protocol associated - # with it. - proto.processEnded( - ProcessTerminated(self.signalStatus(signal.SIGKILL))) - self.assertFailure(d, mail.alias.ProcessAliasTimeout) - d.addCallback(timedOut) - return d - - - def test_earlyProcessTermination(self): - """ - If the process associated with an L{mail.alias.MessageWrapper} exits - before I{eomReceived} is called, the L{Deferred} returned by - I{eomReceived} should fail. - """ - transport = StubProcess() - protocol = mail.alias.ProcessAliasProtocol() - protocol.makeConnection(transport) - receiver = mail.alias.MessageWrapper(protocol, None, None) - protocol.processEnded(failure.Failure(ProcessDone(0))) - return self.assertFailure(receiver.eomReceived(), ProcessDone) - - - def _terminationTest(self, status): - """ - Verify that if the process associated with an - L{mail.alias.MessageWrapper} exits with the given status, the - L{Deferred} returned by I{eomReceived} fails with L{ProcessTerminated}. - """ - transport = StubProcess() - protocol = mail.alias.ProcessAliasProtocol() - protocol.makeConnection(transport) - receiver = mail.alias.MessageWrapper(protocol, None, None) - protocol.processEnded( - failure.Failure(ProcessTerminated(status))) - return self.assertFailure(receiver.eomReceived(), ProcessTerminated) - - - def test_errorProcessTermination(self): - """ - If the process associated with an L{mail.alias.MessageWrapper} exits - with a non-zero exit code, the L{Deferred} returned by I{eomReceived} - should fail. - """ - return self._terminationTest(self.exitStatus(1)) - - - def test_signalProcessTermination(self): - """ - If the process associated with an L{mail.alias.MessageWrapper} exits - because it received a signal, the L{Deferred} returned by - I{eomReceived} should fail. - """ - return self._terminationTest(self.signalStatus(signal.SIGHUP)) - - - def test_aliasResolution(self): - """ - Check that the C{resolve} method of alias processors produce the correct - set of objects: - - direct alias with L{mail.alias.AddressAlias} if a simple input is passed - - aliases in a file with L{mail.alias.FileWrapper} if an input in the format - '/file' is given - - aliases resulting of a process call wrapped by L{mail.alias.MessageWrapper} - if the format is '|process' - """ - aliases = {} - domain = {'': TestDomain(aliases, ['user1', 'user2', 'user3'])} - A1 = MockAliasGroup(['user1', '|echo', '/file'], domain, 'alias1') - A2 = MockAliasGroup(['user2', 'user3'], domain, 'alias2') - A3 = mail.alias.AddressAlias('alias1', domain, 'alias3') - aliases.update({ - 'alias1': A1, - 'alias2': A2, - 'alias3': A3, - }) - - res1 = A1.resolve(aliases) - r1 = map(str, res1.objs) - r1.sort() - expected = map(str, [ - mail.alias.AddressAlias('user1', None, None), - mail.alias.MessageWrapper(DummyProcess(), 'echo'), - mail.alias.FileWrapper('/file'), - ]) - expected.sort() - self.assertEqual(r1, expected) - - res2 = A2.resolve(aliases) - r2 = map(str, res2.objs) - r2.sort() - expected = map(str, [ - mail.alias.AddressAlias('user2', None, None), - mail.alias.AddressAlias('user3', None, None) - ]) - expected.sort() - self.assertEqual(r2, expected) - - res3 = A3.resolve(aliases) - r3 = map(str, res3.objs) - r3.sort() - expected = map(str, [ - mail.alias.AddressAlias('user1', None, None), - mail.alias.MessageWrapper(DummyProcess(), 'echo'), - mail.alias.FileWrapper('/file'), - ]) - expected.sort() - self.assertEqual(r3, expected) - - - def test_cyclicAlias(self): - """ - Check that a cycle in alias resolution is correctly handled. - """ - aliases = {} - domain = {'': TestDomain(aliases, [])} - A1 = mail.alias.AddressAlias('alias2', domain, 'alias1') - A2 = mail.alias.AddressAlias('alias3', domain, 'alias2') - A3 = mail.alias.AddressAlias('alias1', domain, 'alias3') - aliases.update({ - 'alias1': A1, - 'alias2': A2, - 'alias3': A3 - }) - - self.assertEqual(aliases['alias1'].resolve(aliases), None) - self.assertEqual(aliases['alias2'].resolve(aliases), None) - self.assertEqual(aliases['alias3'].resolve(aliases), None) - - A4 = MockAliasGroup(['|echo', 'alias1'], domain, 'alias4') - aliases['alias4'] = A4 - - res = A4.resolve(aliases) - r = map(str, res.objs) - r.sort() - expected = map(str, [ - mail.alias.MessageWrapper(DummyProcess(), 'echo') - ]) - expected.sort() - self.assertEqual(r, expected) - - - - - - -class TestDomain: - def __init__(self, aliases, users): - self.aliases = aliases - self.users = users - - def exists(self, user, memo=None): - user = user.dest.local - if user in self.users: - return lambda: mail.alias.AddressAlias(user, None, None) - try: - a = self.aliases[user] - except: - raise smtp.SMTPBadRcpt(user) - else: - aliases = a.resolve(self.aliases, memo) - if aliases: - return lambda: aliases - raise smtp.SMTPBadRcpt(user) - - - -class SSLContextFactoryTests(unittest.TestCase): - """ - Tests for twisted.mail.protocols.SSLContextFactory. - """ - def test_deprecation(self): - """ - Accessing L{twisted.mail.protocols.SSLContextFactory} emits a - deprecation warning recommending the use of the more general SSL context - factory from L{twisted.internet.ssl}. - """ - mail.protocols.SSLContextFactory - warningsShown = self.flushWarnings([self.test_deprecation]) - self.assertEqual(len(warningsShown), 1) - self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEqual( - warningsShown[0]['message'], - 'twisted.mail.protocols.SSLContextFactory was deprecated in ' - 'Twisted 12.2.0: Use twisted.internet.ssl.' - 'DefaultOpenSSLContextFactory instead.') - - - -class DummyQueue(object): - """ - A fake relay queue to use for testing. - - This queue doesn't keep track of which messages are waiting to be relayed - or are in the process of being relayed. - - @ivar directory: See L{__init__}. - """ - def __init__(self, directory): - """ - @type directory: L{bytes} - @param directory: The pathname of the directory holding messages in the - queue. - """ - self.directory = directory - - - def done(self, message): - """ - Remove a message from the queue. - - @type message: L{bytes} - @param message: The base filename of a message. - """ - message = os.path.basename(message) - os.remove(self.getPath(message) + '-D') - os.remove(self.getPath(message) + '-H') - - - def getEnvelopeFile(self, message): - """ - Get the envelope file for a message in the queue. - - @type message: L{bytes} - @param message: The base filename of a message. - - @rtype: L{file} - @return: The envelope file for the message. - """ - return open(os.path.join(self.directory, message+'-H'), 'rb') - - - def getPath(self, message): - """ - Return the full base pathname of a message in the queue. - - @type message: L{bytes} - @param message: The base filename of a message. - - @rtype: L{bytes} - @return: The full base pathname of the message. - """ - return os.path.join(self.directory, message) - - - def createNewMessage(self): - """ - Create a new message in the queue. - - @rtype: 2-L{tuple} of (E{1}) L{file}, (E{2}) L{FileMessage} - @return: The envelope file and a message receiver for a new message in - the queue. - """ - fname = "%s_%s" % (time.time(), id(self)) - headerFile = open(os.path.join(self.directory, fname+'-H'), 'wb') - tempFilename = os.path.join(self.directory, fname+'-C') - finalFilename = os.path.join(self.directory, fname+'-D') - messageFile = open(tempFilename, 'wb') - - return headerFile, mail.mail.FileMessage(messageFile, tempFilename, - finalFilename) - - - def setWaiting(self, message): - """ - Ignore the request to mark a message as waiting to be relayed. - - @type message: L{bytes} - @param message: The base filename of a message. - """ - pass - - - -class DummySmartHostSMTPRelayingManager(object): - """ - A fake smart host to use for testing. - - @type managed: L{dict} of L{bytes} -> L{list} of - L{list} of L{bytes} - @ivar managed: A mapping of a string identifying a managed relayer to - filenames of messages the managed relayer is responsible for. - - @ivar queue: See L{__init__}. - """ - def __init__(self, queue): - """ - Initialize the minimum necessary members of a smart host. - - @type queue: L{DummyQueue} - @param queue: A queue that can be used for testing purposes. - """ - self.managed = {} - self.queue = queue - - - -class _AttemptManagerTests(unittest.TestCase): - """ - Test the behavior of L{_AttemptManager}. - - @type tmpdir: L{bytes} - @ivar tmpdir: The path to a temporary directory holding the message files. - - @type reactor: L{MemoryReactorClock} - @ivar reactor: The reactor used for test purposes. - - @type eventLog: L{types.NoneType} or L{dict} of L{bytes} -> L{object} - @ivar eventLog: Information about the last informational log message - generated or none if no log message has been generated. - - @type noisyAttemptMgr: L{_AttemptManager} - @ivar noisyAttemptMgr: An attempt manager which generates informational - log messages. - - @type quietAttemptMgr: L{_AttemptManager} - @ivar quietAttemptMgr: An attempt manager which does not generate - informational log messages. - - @type noisyMessage: L{bytes} - @ivar noisyMessage: The full base pathname of the message to be used with - the noisy attempt manager. - - @type quietMessage: L{bytes} - @ivar quietMessage: The full base pathname of the message to be used with - the quiet. - """ - def setUp(self): - """ - Set up a temporary directory for the queue, attempt managers with the - noisy flag on and off, message files for use with each attempt manager, - and a reactor. Also, register to be notified when log messages are - generated. - """ - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - - self.reactor = MemoryReactorClock() - - self.eventLog = None - log.addObserver(self._logObserver) - - self.noisyAttemptMgr = _AttemptManager( - DummySmartHostSMTPRelayingManager(DummyQueue(self.tmpdir)), - True, self.reactor) - self.quietAttemptMgr = _AttemptManager( - DummySmartHostSMTPRelayingManager(DummyQueue(self.tmpdir)), - False, self.reactor) - - noisyBaseName = "noisyMessage" - quietBaseName = "quietMessage" - - self.noisyMessage = os.path.join(self.tmpdir, noisyBaseName) - self.quietMessage = os.path.join(self.tmpdir, quietBaseName) - - message = file(self.noisyMessage+'-D', "w") - message.close() - - message = file(self.quietMessage+'-D', "w") - message.close() - - self.noisyAttemptMgr.manager.managed['noisyRelayer'] = [ - noisyBaseName] - self.quietAttemptMgr.manager.managed['quietRelayer'] = [ - quietBaseName] - - envelope = file(self.noisyMessage+'-H', 'w') - pickle.dump(['from-noisy@domain', 'to-noisy@domain'], envelope) - envelope.close() - - envelope = file(self.quietMessage+'-H', 'w') - pickle.dump(['from-quiet@domain', 'to-quiet@domain'], envelope) - envelope.close() - - - def tearDown(self): - """ - Unregister for log events and remove the temporary directory. - """ - log.removeObserver(self._logObserver) - shutil.rmtree(self.tmpdir) - - - def _logObserver(self, eventDict): - """ - A log observer. - - @type eventDict: L{dict} of L{bytes} -> L{object} - @param eventDict: Information about the last informational log message - generated. - """ - self.eventLog = eventDict - - - def test_initNoisyDefault(self): - """ - When an attempt manager is created without the noisy parameter, the - noisy instance variable should default to true. - """ - am = _AttemptManager(DummySmartHostSMTPRelayingManager( - DummyQueue(self.tmpdir))) - self.assertTrue(am.noisy) - - - def test_initNoisy(self): - """ - When an attempt manager is created with the noisy parameter set to - true, the noisy instance variable should be set to true. - """ - self.assertTrue(self.noisyAttemptMgr.noisy) - - - def test_initQuiet(self): - """ - When an attempt manager is created with the noisy parameter set to - false, the noisy instance variable should be set to false. - """ - self.assertFalse(self.quietAttemptMgr.noisy) - - - def test_initReactorDefault(self): - """ - When an attempt manager is created without the reactor parameter, the - reactor instance variable should default to the global reactor. - """ - am = _AttemptManager(DummySmartHostSMTPRelayingManager( - DummyQueue(self.tmpdir))) - self.assertEqual(am.reactor, reactor) - - - def test_initReactor(self): - """ - When an attempt manager is created with a reactor provided, the - reactor instance variable should default to that reactor. - """ - self.assertEqual(self.noisyAttemptMgr.reactor, self.reactor) - - - def test_notifySuccessNoisy(self): - """ - For an attempt manager with the noisy flag set, notifySuccess should - result in a log message. - """ - self.noisyAttemptMgr.notifySuccess('noisyRelayer', self.noisyMessage) - self.assertTrue(self.eventLog) - - - def test_notifySuccessQuiet(self): - """ - For an attempt manager with the noisy flag not set, notifySuccess - should result in no log message. - """ - self.quietAttemptMgr.notifySuccess('quietRelayer', self.quietMessage) - self.assertFalse(self.eventLog) - - - def test_notifyFailureNoisy(self): - """ - For an attempt manager with the noisy flag set, notifyFailure should - result in a log message. - """ - self.noisyAttemptMgr.notifyFailure('noisyRelayer', self.noisyMessage) - self.assertTrue(self.eventLog) - - - def test_notifyFailureQuiet(self): - """ - For an attempt manager with the noisy flag not set, notifyFailure - should result in no log message. - """ - self.quietAttemptMgr.notifyFailure('quietRelayer', self.quietMessage) - self.assertFalse(self.eventLog) - - - def test_notifyDoneNoisy(self): - """ - For an attempt manager with the noisy flag set, notifyDone should - result in a log message. - """ - self.noisyAttemptMgr.notifyDone('noisyRelayer') - self.assertTrue(self.eventLog) - - - def test_notifyDoneQuiet(self): - """ - For an attempt manager with the noisy flag not set, notifyDone - should result in no log message. - """ - self.quietAttemptMgr.notifyDone('quietRelayer') - self.assertFalse(self.eventLog) - - - def test_notifyNoConnectionNoisy(self): - """ - For an attempt manager with the noisy flag set, notifyNoConnection - should result in a log message. - """ - self.noisyAttemptMgr.notifyNoConnection('noisyRelayer') - self.assertTrue(self.eventLog) - self.reactor.advance(60) - - - def test_notifyNoConnectionQuiet(self): - """ - For an attempt manager with the noisy flag not set, notifyNoConnection - should result in no log message. - """ - self.quietAttemptMgr.notifyNoConnection('quietRelayer') - self.assertFalse(self.eventLog) - self.reactor.advance(60) - - - -from twisted.python.runtime import platformType -import types -if platformType != "posix": - for o in locals().values(): - if isinstance(o, (types.ClassType, type)) and issubclass(o, unittest.TestCase): - o.skip = "twisted.mail only works on posix" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_mailmail.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_mailmail.py deleted file mode 100644 index 8b9e4d8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_mailmail.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.mail.scripts.mailmail}, the implementation of the -command line program I{mailmail}. -""" - -import sys -from StringIO import StringIO - -from twisted.trial.unittest import TestCase -from twisted.mail.scripts.mailmail import parseOptions - - -class OptionsTests(TestCase): - """ - Tests for L{parseOptions} which parses command line arguments and reads - message text from stdin to produce an L{Options} instance which can be - used to send a message. - """ - def test_unspecifiedRecipients(self): - """ - If no recipients are given in the argument list and there is no - recipient header in the message text, L{parseOptions} raises - L{SystemExit} with a string describing the problem. - """ - self.addCleanup(setattr, sys, 'stdin', sys.stdin) - sys.stdin = StringIO( - 'Subject: foo\n' - '\n' - 'Hello, goodbye.\n') - exc = self.assertRaises(SystemExit, parseOptions, []) - self.assertEqual(exc.args, ('No recipients specified.',)) - - - def test_listQueueInformation(self): - """ - The I{-bp} option for listing queue information is unsupported and - if it is passed to L{parseOptions}, L{SystemExit} is raised. - """ - exc = self.assertRaises(SystemExit, parseOptions, ['-bp']) - self.assertEqual(exc.args, ("Unsupported option.",)) - - - def test_stdioTransport(self): - """ - The I{-bs} option for using stdin and stdout as the SMTP transport - is unsupported and if it is passed to L{parseOptions}, L{SystemExit} - is raised. - """ - exc = self.assertRaises(SystemExit, parseOptions, ['-bs']) - self.assertEqual(exc.args, ("Unsupported option.",)) - - - def test_ignoreFullStop(self): - """ - The I{-i} and I{-oi} options for ignoring C{"."} by itself on a line - are unsupported and if either is passed to L{parseOptions}, - L{SystemExit} is raised. - """ - exc = self.assertRaises(SystemExit, parseOptions, ['-i']) - self.assertEqual(exc.args, ("Unsupported option.",)) - exc = self.assertRaises(SystemExit, parseOptions, ['-oi']) - self.assertEqual(exc.args, ("Unsupported option.",)) - - - def test_copyAliasedSender(self): - """ - The I{-om} option for copying the sender if they appear in an alias - expansion is unsupported and if it is passed to L{parseOptions}, - L{SystemExit} is raised. - """ - exc = self.assertRaises(SystemExit, parseOptions, ['-om']) - self.assertEqual(exc.args, ("Unsupported option.",)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_options.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_options.py deleted file mode 100644 index 4d76bbb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_options.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.mail.tap}. -""" - -from twisted.trial.unittest import TestCase - -from twisted.python.usage import UsageError -from twisted.mail import protocols -from twisted.mail.tap import Options, makeService -from twisted.python.filepath import FilePath -from twisted.python.reflect import requireModule -from twisted.internet import endpoints, defer - -if requireModule('OpenSSL') is None: - sslSkip = 'Missing OpenSSL package.' -else: - sslSkip = None - - -class OptionsTests(TestCase): - """ - Tests for the command line option parser used for I{twistd mail}. - """ - def setUp(self): - self.aliasFilename = self.mktemp() - aliasFile = file(self.aliasFilename, 'w') - aliasFile.write('someuser:\tdifferentuser\n') - aliasFile.close() - - - def testAliasesWithoutDomain(self): - """ - Test that adding an aliases(5) file before adding a domain raises a - UsageError. - """ - self.assertRaises( - UsageError, - Options().parseOptions, - ['--aliases', self.aliasFilename]) - - - def testAliases(self): - """ - Test that adding an aliases(5) file to an IAliasableDomain at least - doesn't raise an unhandled exception. - """ - Options().parseOptions([ - '--maildirdbmdomain', 'example.com=example.com', - '--aliases', self.aliasFilename]) - - - def test_barePort(self): - """ - A bare port passed to I{--pop3} results in deprecation warning in - addition to a TCP4ServerEndpoint. - """ - options = Options() - options.parseOptions(['--pop3', '8110']) - self.assertEqual(len(options['pop3']), 1) - self.assertIsInstance( - options['pop3'][0], endpoints.TCP4ServerEndpoint) - warnings = self.flushWarnings([options.opt_pop3]) - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "Specifying plain ports and/or a certificate is deprecated since " - "Twisted 11.0; use endpoint descriptions instead.") - - - def _endpointTest(self, service): - """ - Use L{Options} to parse a single service configuration parameter and - verify that an endpoint of the correct type is added to the list for - that service. - """ - options = Options() - options.parseOptions(['--' + service, 'tcp:1234']) - self.assertEqual(len(options[service]), 1) - self.assertIsInstance( - options[service][0], endpoints.TCP4ServerEndpoint) - - - def test_endpointSMTP(self): - """ - When I{--smtp} is given a TCP endpoint description as an argument, a - TCPServerEndpoint is added to the list of SMTP endpoints. - """ - self._endpointTest('smtp') - - - def test_endpointPOP3(self): - """ - When I{--pop3} is given a TCP endpoint description as an argument, a - TCPServerEndpoint is added to the list of POP3 endpoints. - """ - self._endpointTest('pop3') - - - def test_protoDefaults(self): - """ - POP3 and SMTP each listen on a TCP4ServerEndpoint by default. - """ - options = Options() - options.parseOptions([]) - - self.assertEqual(len(options['pop3']), 1) - self.assertIsInstance( - options['pop3'][0], endpoints.TCP4ServerEndpoint) - - self.assertEqual(len(options['smtp']), 1) - self.assertIsInstance( - options['smtp'][0], endpoints.TCP4ServerEndpoint) - - - def test_protoDisable(self): - """ - The I{--no-pop3} and I{--no-smtp} options disable POP3 and SMTP - respectively. - """ - options = Options() - options.parseOptions(['--no-pop3']) - self.assertEqual(options._getEndpoints(None, 'pop3'), []) - self.assertNotEquals(options._getEndpoints(None, 'smtp'), []) - - options = Options() - options.parseOptions(['--no-smtp']) - self.assertNotEquals(options._getEndpoints(None, 'pop3'), []) - self.assertEqual(options._getEndpoints(None, 'smtp'), []) - - - def test_allProtosDisabledError(self): - """ - If all protocols are disabled, L{UsageError} is raised. - """ - options = Options() - self.assertRaises( - UsageError, options.parseOptions, (['--no-pop3', '--no-smtp'])) - - - def test_pop3sBackwardCompatibility(self): - """ - The deprecated I{--pop3s} and I{--certificate} options set up a POP3 SSL - server. - """ - cert = FilePath(__file__).sibling("server.pem") - options = Options() - options.parseOptions(['--pop3s', '8995', - '--certificate', cert.path]) - self.assertEqual(len(options['pop3']), 2) - self.assertIsInstance( - options['pop3'][0], endpoints.SSL4ServerEndpoint) - self.assertIsInstance( - options['pop3'][1], endpoints.TCP4ServerEndpoint) - - warnings = self.flushWarnings([options.postOptions]) - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "Specifying plain ports and/or a certificate is deprecated since " - "Twisted 11.0; use endpoint descriptions instead.") - if sslSkip is not None: - test_pop3sBackwardCompatibility.skip = sslSkip - - - def test_esmtpWithoutHostname(self): - """ - If I{--esmtp} is given without I{--hostname}, L{Options.parseOptions} - raises L{UsageError}. - """ - options = Options() - exc = self.assertRaises(UsageError, options.parseOptions, ['--esmtp']) - self.assertEqual("--esmtp requires --hostname", str(exc)) - - - def test_auth(self): - """ - Tests that the --auth option registers a checker. - """ - options = Options() - options.parseOptions(['--auth', 'memory:admin:admin:bob:password']) - self.assertEqual(len(options['credCheckers']), 1) - checker = options['credCheckers'][0] - interfaces = checker.credentialInterfaces - registered_checkers = options.service.smtpPortal.checkers - for iface in interfaces: - self.assertEqual(checker, registered_checkers[iface]) - - - -class SpyEndpoint(object): - """ - SpyEndpoint remembers what factory it is told to listen with. - """ - listeningWith = None - def listen(self, factory): - self.listeningWith = factory - return defer.succeed(None) - - - -class MakeServiceTests(TestCase): - """ - Tests for L{twisted.mail.tap.makeService} - """ - def _endpointServerTest(self, key, factoryClass): - """ - Configure a service with two endpoints for the protocol associated with - C{key} and verify that when the service is started a factory of type - C{factoryClass} is used to listen on each of them. - """ - cleartext = SpyEndpoint() - secure = SpyEndpoint() - config = Options() - config[key] = [cleartext, secure] - service = makeService(config) - service.privilegedStartService() - service.startService() - self.addCleanup(service.stopService) - self.assertIsInstance(cleartext.listeningWith, factoryClass) - self.assertIsInstance(secure.listeningWith, factoryClass) - - - def test_pop3(self): - """ - If one or more endpoints is included in the configuration passed to - L{makeService} for the C{"pop3"} key, a service for starting a POP3 - server is constructed for each of them and attached to the returned - service. - """ - self._endpointServerTest("pop3", protocols.POP3Factory) - - - def test_smtp(self): - """ - If one or more endpoints is included in the configuration passed to - L{makeService} for the C{"smtp"} key, a service for starting an SMTP - server is constructed for each of them and attached to the returned - service. - """ - self._endpointServerTest("smtp", protocols.SMTPFactory) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_pop3.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_pop3.py deleted file mode 100644 index 3ce04a8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_pop3.py +++ /dev/null @@ -1,1070 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for Ltwisted.mail.pop3} module. -""" - -import StringIO -import hmac -import base64 -import itertools - -from zope.interface import implements - -from twisted.internet import defer - -from twisted.trial import unittest, util -from twisted import mail -import twisted.mail.protocols -import twisted.mail.pop3 -import twisted.internet.protocol -from twisted import internet -from twisted.mail import pop3 -from twisted.protocols import loopback -from twisted.python import failure -from twisted.python.util import OrderedDict - -from twisted import cred -import twisted.cred.portal -import twisted.cred.checkers -import twisted.cred.credentials - -from twisted.test.proto_helpers import LineSendingProtocol - - -class UtilityTests(unittest.TestCase): - """ - Test the various helper functions and classes used by the POP3 server - protocol implementation. - """ - - def testLineBuffering(self): - """ - Test creating a LineBuffer and feeding it some lines. The lines should - build up in its internal buffer for a while and then get spat out to - the writer. - """ - output = [] - input = iter(itertools.cycle(['012', '345', '6', '7', '8', '9'])) - c = pop3._IteratorBuffer(output.extend, input, 6) - i = iter(c) - self.assertEqual(output, []) # nothing is buffer - i.next() - self.assertEqual(output, []) # '012' is buffered - i.next() - self.assertEqual(output, []) # '012345' is buffered - i.next() - self.assertEqual(output, ['012', '345', '6']) # nothing is buffered - for n in range(5): - i.next() - self.assertEqual(output, ['012', '345', '6', '7', '8', '9', '012', '345']) - - - def testFinishLineBuffering(self): - """ - Test that a LineBuffer flushes everything when its iterator is - exhausted, and itself raises StopIteration. - """ - output = [] - input = iter(['a', 'b', 'c']) - c = pop3._IteratorBuffer(output.extend, input, 5) - for i in c: - pass - self.assertEqual(output, ['a', 'b', 'c']) - - - def testSuccessResponseFormatter(self): - """ - Test that the thing that spits out POP3 'success responses' works - right. - """ - self.assertEqual( - pop3.successResponse('Great.'), - '+OK Great.\r\n') - - - def testStatLineFormatter(self): - """ - Test that the function which formats stat lines does so appropriately. - """ - statLine = list(pop3.formatStatResponse([]))[-1] - self.assertEqual(statLine, '+OK 0 0\r\n') - - statLine = list(pop3.formatStatResponse([10, 31, 0, 10101]))[-1] - self.assertEqual(statLine, '+OK 4 10142\r\n') - - - def testListLineFormatter(self): - """ - Test that the function which formats the lines in response to a LIST - command does so appropriately. - """ - listLines = list(pop3.formatListResponse([])) - self.assertEqual( - listLines, - ['+OK 0\r\n', '.\r\n']) - - listLines = list(pop3.formatListResponse([1, 2, 3, 100])) - self.assertEqual( - listLines, - ['+OK 4\r\n', '1 1\r\n', '2 2\r\n', '3 3\r\n', '4 100\r\n', '.\r\n']) - - - - def testUIDListLineFormatter(self): - """ - Test that the function which formats lines in response to a UIDL - command does so appropriately. - """ - UIDs = ['abc', 'def', 'ghi'] - listLines = list(pop3.formatUIDListResponse([], UIDs.__getitem__)) - self.assertEqual( - listLines, - ['+OK \r\n', '.\r\n']) - - listLines = list(pop3.formatUIDListResponse([123, 431, 591], UIDs.__getitem__)) - self.assertEqual( - listLines, - ['+OK \r\n', '1 abc\r\n', '2 def\r\n', '3 ghi\r\n', '.\r\n']) - - listLines = list(pop3.formatUIDListResponse([0, None, 591], UIDs.__getitem__)) - self.assertEqual( - listLines, - ['+OK \r\n', '1 abc\r\n', '3 ghi\r\n', '.\r\n']) - - - -class MyVirtualPOP3(mail.protocols.VirtualPOP3): - - magic = '' - - def authenticateUserAPOP(self, user, digest): - user, domain = self.lookupDomain(user) - return self.service.domains['baz.com'].authenticateUserAPOP(user, digest, self.magic, domain) - -class DummyDomain: - - def __init__(self): - self.users = {} - - def addUser(self, name): - self.users[name] = [] - - def addMessage(self, name, message): - self.users[name].append(message) - - def authenticateUserAPOP(self, name, digest, magic, domain): - return pop3.IMailbox, ListMailbox(self.users[name]), lambda: None - - -class ListMailbox: - - def __init__(self, list): - self.list = list - - def listMessages(self, i=None): - if i is None: - return map(len, self.list) - return len(self.list[i]) - - def getMessage(self, i): - return StringIO.StringIO(self.list[i]) - - def getUidl(self, i): - return i - - def deleteMessage(self, i): - self.list[i] = '' - - def sync(self): - pass - -class MyPOP3Downloader(pop3.POP3Client): - - def handle_WELCOME(self, line): - pop3.POP3Client.handle_WELCOME(self, line) - self.apop('hello@baz.com', 'world') - - def handle_APOP(self, line): - parts = line.split() - code = parts[0] - if code != '+OK': - print parts - raise AssertionError, 'code is ' + code - self.lines = [] - self.retr(1) - - def handle_RETR_continue(self, line): - self.lines.append(line) - - def handle_RETR_end(self): - self.message = '\n'.join(self.lines) + '\n' - self.quit() - - def handle_QUIT(self, line): - if line[:3] != '+OK': - raise AssertionError, 'code is ' + line - - -class POP3Tests(unittest.TestCase): - - message = '''\ -Subject: urgent - -Someone set up us the bomb! -''' - - expectedOutput = '''\ -+OK \015 -+OK Authentication succeeded\015 -+OK \015 -1 0\015 -.\015 -+OK %d\015 -Subject: urgent\015 -\015 -Someone set up us the bomb!\015 -.\015 -+OK \015 -''' % len(message) - - def setUp(self): - self.factory = internet.protocol.Factory() - self.factory.domains = {} - self.factory.domains['baz.com'] = DummyDomain() - self.factory.domains['baz.com'].addUser('hello') - self.factory.domains['baz.com'].addMessage('hello', self.message) - - def testMessages(self): - client = LineSendingProtocol([ - 'APOP hello@baz.com world', - 'UIDL', - 'RETR 1', - 'QUIT', - ]) - server = MyVirtualPOP3() - server.service = self.factory - def check(ignored): - output = '\r\n'.join(client.response) + '\r\n' - self.assertEqual(output, self.expectedOutput) - return loopback.loopbackTCP(server, client).addCallback(check) - - def testLoopback(self): - protocol = MyVirtualPOP3() - protocol.service = self.factory - clientProtocol = MyPOP3Downloader() - def check(ignored): - self.assertEqual(clientProtocol.message, self.message) - protocol.connectionLost( - failure.Failure(Exception("Test harness disconnect"))) - d = loopback.loopbackAsync(protocol, clientProtocol) - return d.addCallback(check) - testLoopback.suppress = [util.suppress(message="twisted.mail.pop3.POP3Client is deprecated")] - - - -class DummyPOP3(pop3.POP3): - - magic = '' - - def authenticateUserAPOP(self, user, password): - return pop3.IMailbox, DummyMailbox(ValueError), lambda: None - - - -class DummyMailbox(pop3.Mailbox): - - messages = ['From: moshe\nTo: moshe\n\nHow are you, friend?\n'] - - def __init__(self, exceptionType): - self.messages = DummyMailbox.messages[:] - self.exceptionType = exceptionType - - def listMessages(self, i=None): - if i is None: - return map(len, self.messages) - if i >= len(self.messages): - raise self.exceptionType() - return len(self.messages[i]) - - def getMessage(self, i): - return StringIO.StringIO(self.messages[i]) - - def getUidl(self, i): - if i >= len(self.messages): - raise self.exceptionType() - return str(i) - - def deleteMessage(self, i): - self.messages[i] = '' - - -class AnotherPOP3Tests(unittest.TestCase): - - def runTest(self, lines, expectedOutput): - dummy = DummyPOP3() - client = LineSendingProtocol(lines) - d = loopback.loopbackAsync(dummy, client) - return d.addCallback(self._cbRunTest, client, dummy, expectedOutput) - - - def _cbRunTest(self, ignored, client, dummy, expectedOutput): - self.assertEqual('\r\n'.join(expectedOutput), - '\r\n'.join(client.response)) - dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - return ignored - - - def test_buffer(self): - """ - Test a lot of different POP3 commands in an extremely pipelined - scenario. - - This test may cover legitimate behavior, but the intent and - granularity are not very good. It would likely be an improvement to - split it into a number of smaller, more focused tests. - """ - return self.runTest( - ["APOP moshez dummy", - "LIST", - "UIDL", - "RETR 1", - "RETR 2", - "DELE 1", - "RETR 1", - "QUIT"], - ['+OK ', - '+OK Authentication succeeded', - '+OK 1', - '1 44', - '.', - '+OK ', - '1 0', - '.', - '+OK 44', - 'From: moshe', - 'To: moshe', - '', - 'How are you, friend?', - '.', - '-ERR Bad message number argument', - '+OK ', - '-ERR message deleted', - '+OK ']) - - - def test_noop(self): - """ - Test the no-op command. - """ - return self.runTest( - ['APOP spiv dummy', - 'NOOP', - 'QUIT'], - ['+OK ', - '+OK Authentication succeeded', - '+OK ', - '+OK ']) - - - def testAuthListing(self): - p = DummyPOP3() - p.factory = internet.protocol.Factory() - p.factory.challengers = {'Auth1': None, 'secondAuth': None, 'authLast': None} - client = LineSendingProtocol([ - "AUTH", - "QUIT", - ]) - - d = loopback.loopbackAsync(p, client) - return d.addCallback(self._cbTestAuthListing, client) - - def _cbTestAuthListing(self, ignored, client): - self.failUnless(client.response[1].startswith('+OK')) - self.assertEqual(sorted(client.response[2:5]), - ["AUTH1", "AUTHLAST", "SECONDAUTH"]) - self.assertEqual(client.response[5], ".") - - def testIllegalPASS(self): - dummy = DummyPOP3() - client = LineSendingProtocol([ - "PASS fooz", - "QUIT" - ]) - d = loopback.loopbackAsync(dummy, client) - return d.addCallback(self._cbTestIllegalPASS, client, dummy) - - def _cbTestIllegalPASS(self, ignored, client, dummy): - expected_output = '+OK \r\n-ERR USER required before PASS\r\n+OK \r\n' - self.assertEqual(expected_output, '\r\n'.join(client.response) + '\r\n') - dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - def testEmptyPASS(self): - dummy = DummyPOP3() - client = LineSendingProtocol([ - "PASS ", - "QUIT" - ]) - d = loopback.loopbackAsync(dummy, client) - return d.addCallback(self._cbTestEmptyPASS, client, dummy) - - def _cbTestEmptyPASS(self, ignored, client, dummy): - expected_output = '+OK \r\n-ERR USER required before PASS\r\n+OK \r\n' - self.assertEqual(expected_output, '\r\n'.join(client.response) + '\r\n') - dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - -class TestServerFactory: - implements(pop3.IServerFactory) - - def cap_IMPLEMENTATION(self): - return "Test Implementation String" - - def cap_EXPIRE(self): - return 60 - - challengers = OrderedDict([("SCHEME_1", None), ("SCHEME_2", None)]) - - def cap_LOGIN_DELAY(self): - return 120 - - pue = True - def perUserExpiration(self): - return self.pue - - puld = True - def perUserLoginDelay(self): - return self.puld - - -class TestMailbox: - loginDelay = 100 - messageExpiration = 25 - - -class CapabilityTests(unittest.TestCase): - def setUp(self): - s = StringIO.StringIO() - p = pop3.POP3() - p.factory = TestServerFactory() - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - p.do_CAPA() - - self.caps = p.listCapabilities() - self.pcaps = s.getvalue().splitlines() - - s = StringIO.StringIO() - p.mbox = TestMailbox() - p.transport = internet.protocol.FileWrapper(s) - p.do_CAPA() - - self.lpcaps = s.getvalue().splitlines() - p.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - def contained(self, s, *caps): - for c in caps: - self.assertIn(s, c) - - def testUIDL(self): - self.contained("UIDL", self.caps, self.pcaps, self.lpcaps) - - def testTOP(self): - self.contained("TOP", self.caps, self.pcaps, self.lpcaps) - - def testUSER(self): - self.contained("USER", self.caps, self.pcaps, self.lpcaps) - - def testEXPIRE(self): - self.contained("EXPIRE 60 USER", self.caps, self.pcaps) - self.contained("EXPIRE 25", self.lpcaps) - - def testIMPLEMENTATION(self): - self.contained( - "IMPLEMENTATION Test Implementation String", - self.caps, self.pcaps, self.lpcaps - ) - - def testSASL(self): - self.contained( - "SASL SCHEME_1 SCHEME_2", - self.caps, self.pcaps, self.lpcaps - ) - - def testLOGIN_DELAY(self): - self.contained("LOGIN-DELAY 120 USER", self.caps, self.pcaps) - self.assertIn("LOGIN-DELAY 100", self.lpcaps) - - - -class GlobalCapabilitiesTests(unittest.TestCase): - def setUp(self): - s = StringIO.StringIO() - p = pop3.POP3() - p.factory = TestServerFactory() - p.factory.pue = p.factory.puld = False - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - p.do_CAPA() - - self.caps = p.listCapabilities() - self.pcaps = s.getvalue().splitlines() - - s = StringIO.StringIO() - p.mbox = TestMailbox() - p.transport = internet.protocol.FileWrapper(s) - p.do_CAPA() - - self.lpcaps = s.getvalue().splitlines() - p.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - def contained(self, s, *caps): - for c in caps: - self.assertIn(s, c) - - def testEXPIRE(self): - self.contained("EXPIRE 60", self.caps, self.pcaps, self.lpcaps) - - def testLOGIN_DELAY(self): - self.contained("LOGIN-DELAY 120", self.caps, self.pcaps, self.lpcaps) - - - -class TestRealm: - def requestAvatar(self, avatarId, mind, *interfaces): - if avatarId == 'testuser': - return pop3.IMailbox, DummyMailbox(ValueError), lambda: None - assert False - - - -class SASLTests(unittest.TestCase): - def testValidLogin(self): - p = pop3.POP3() - p.factory = TestServerFactory() - p.factory.challengers = {'CRAM-MD5': cred.credentials.CramMD5Credentials} - p.portal = cred.portal.Portal(TestRealm()) - ch = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse() - ch.addUser('testuser', 'testpassword') - p.portal.registerChecker(ch) - - s = StringIO.StringIO() - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - - p.lineReceived("CAPA") - self.failUnless(s.getvalue().find("SASL CRAM-MD5") >= 0) - - p.lineReceived("AUTH CRAM-MD5") - chal = s.getvalue().splitlines()[-1][2:] - chal = base64.decodestring(chal) - response = hmac.HMAC('testpassword', chal).hexdigest() - - p.lineReceived(base64.encodestring('testuser ' + response).rstrip('\n')) - self.failUnless(p.mbox) - self.failUnless(s.getvalue().splitlines()[-1].find("+OK") >= 0) - p.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - - -class CommandMixin: - """ - Tests for all the commands a POP3 server is allowed to receive. - """ - - extraMessage = '''\ -From: guy -To: fellow - -More message text for you. -''' - - - def setUp(self): - """ - Make a POP3 server protocol instance hooked up to a simple mailbox and - a transport that buffers output to a StringIO. - """ - p = pop3.POP3() - p.mbox = self.mailboxType(self.exceptionType) - p.schedule = list - self.pop3Server = p - - s = StringIO.StringIO() - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - s.truncate(0) - self.pop3Transport = s - - - def tearDown(self): - """ - Disconnect the server protocol so it can clean up anything it might - need to clean up. - """ - self.pop3Server.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - - def _flush(self): - """ - Do some of the things that the reactor would take care of, if the - reactor were actually running. - """ - # Oh man FileWrapper is pooh. - self.pop3Server.transport._checkProducer() - - - def testLIST(self): - """ - Test the two forms of list: with a message index number, which should - return a short-form response, and without a message index number, which - should return a long-form response, one line per message. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("LIST 1") - self._flush() - self.assertEqual(s.getvalue(), "+OK 1 44\r\n") - s.truncate(0) - - p.lineReceived("LIST") - self._flush() - self.assertEqual(s.getvalue(), "+OK 1\r\n1 44\r\n.\r\n") - - - def testLISTWithBadArgument(self): - """ - Test that non-integers and out-of-bound integers produce appropriate - error responses. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("LIST a") - self.assertEqual( - s.getvalue(), - "-ERR Invalid message-number: 'a'\r\n") - s.truncate(0) - - p.lineReceived("LIST 0") - self.assertEqual( - s.getvalue(), - "-ERR Invalid message-number: 0\r\n") - s.truncate(0) - - p.lineReceived("LIST 2") - self.assertEqual( - s.getvalue(), - "-ERR Invalid message-number: 2\r\n") - s.truncate(0) - - - def testUIDL(self): - """ - Test the two forms of the UIDL command. These are just like the two - forms of the LIST command. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("UIDL 1") - self.assertEqual(s.getvalue(), "+OK 0\r\n") - s.truncate(0) - - p.lineReceived("UIDL") - self._flush() - self.assertEqual(s.getvalue(), "+OK \r\n1 0\r\n.\r\n") - - - def testUIDLWithBadArgument(self): - """ - Test that UIDL with a non-integer or an out-of-bounds integer produces - the appropriate error response. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("UIDL a") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("UIDL 0") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("UIDL 2") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - - def testSTAT(self): - """ - Test the single form of the STAT command, which returns a short-form - response of the number of messages in the mailbox and their total size. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("STAT") - self._flush() - self.assertEqual(s.getvalue(), "+OK 1 44\r\n") - - - def testRETR(self): - """ - Test downloading a message. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("RETR 1") - self._flush() - self.assertEqual( - s.getvalue(), - "+OK 44\r\n" - "From: moshe\r\n" - "To: moshe\r\n" - "\r\n" - "How are you, friend?\r\n" - ".\r\n") - s.truncate(0) - - - def testRETRWithBadArgument(self): - """ - Test that trying to download a message with a bad argument, either not - an integer or an out-of-bounds integer, fails with the appropriate - error response. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("RETR a") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("RETR 0") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("RETR 2") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - - def testTOP(self): - """ - Test downloading the headers and part of the body of a message. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived("TOP 1 0") - self._flush() - self.assertEqual( - s.getvalue(), - "+OK Top of message follows\r\n" - "From: moshe\r\n" - "To: moshe\r\n" - "\r\n" - ".\r\n") - - - def testTOPWithBadArgument(self): - """ - Test that trying to download a message with a bad argument, either a - message number which isn't an integer or is an out-of-bounds integer or - a number of lines which isn't an integer or is a negative integer, - fails with the appropriate error response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived("TOP 1 a") - self.assertEqual( - s.getvalue(), - "-ERR Bad line count argument\r\n") - s.truncate(0) - - p.lineReceived("TOP 1 -1") - self.assertEqual( - s.getvalue(), - "-ERR Bad line count argument\r\n") - s.truncate(0) - - p.lineReceived("TOP a 1") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("TOP 0 1") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("TOP 3 1") - self.assertEqual( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - - def testLAST(self): - """ - Test the exceedingly pointless LAST command, which tells you the - highest message index which you have already downloaded. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('LAST') - self.assertEqual( - s.getvalue(), - "+OK 0\r\n") - s.truncate(0) - - - def testRetrieveUpdatesHighest(self): - """ - Test that issuing a RETR command updates the LAST response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('RETR 2') - self._flush() - s.truncate(0) - p.lineReceived('LAST') - self.assertEqual( - s.getvalue(), - '+OK 2\r\n') - s.truncate(0) - - - def testTopUpdatesHighest(self): - """ - Test that issuing a TOP command updates the LAST response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('TOP 2 10') - self._flush() - s.truncate(0) - p.lineReceived('LAST') - self.assertEqual( - s.getvalue(), - '+OK 2\r\n') - - - def testHighestOnlyProgresses(self): - """ - Test that downloading a message with a smaller index than the current - LAST response doesn't change the LAST response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('RETR 2') - self._flush() - p.lineReceived('TOP 1 10') - self._flush() - s.truncate(0) - p.lineReceived('LAST') - self.assertEqual( - s.getvalue(), - '+OK 2\r\n') - - - def testResetClearsHighest(self): - """ - Test that issuing RSET changes the LAST response to 0. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('RETR 2') - self._flush() - p.lineReceived('RSET') - s.truncate(0) - p.lineReceived('LAST') - self.assertEqual( - s.getvalue(), - '+OK 0\r\n') - - - -_listMessageDeprecation = ( - "twisted.mail.pop3.IMailbox.listMessages may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.") -_listMessageSuppression = util.suppress( - message=_listMessageDeprecation, - category=PendingDeprecationWarning) - -_getUidlDeprecation = ( - "twisted.mail.pop3.IMailbox.getUidl may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.") -_getUidlSuppression = util.suppress( - message=_getUidlDeprecation, - category=PendingDeprecationWarning) - -class IndexErrorCommandTests(CommandMixin, unittest.TestCase): - """ - Run all of the command tests against a mailbox which raises IndexError - when an out of bounds request is made. This behavior will be deprecated - shortly and then removed. - """ - exceptionType = IndexError - mailboxType = DummyMailbox - - def testLISTWithBadArgument(self): - return CommandMixin.testLISTWithBadArgument(self) - testLISTWithBadArgument.suppress = [_listMessageSuppression] - - - def testUIDLWithBadArgument(self): - return CommandMixin.testUIDLWithBadArgument(self) - testUIDLWithBadArgument.suppress = [_getUidlSuppression] - - - def testTOPWithBadArgument(self): - return CommandMixin.testTOPWithBadArgument(self) - testTOPWithBadArgument.suppress = [_listMessageSuppression] - - - def testRETRWithBadArgument(self): - return CommandMixin.testRETRWithBadArgument(self) - testRETRWithBadArgument.suppress = [_listMessageSuppression] - - - -class ValueErrorCommandTests(CommandMixin, unittest.TestCase): - """ - Run all of the command tests against a mailbox which raises ValueError - when an out of bounds request is made. This is the correct behavior and - after support for mailboxes which raise IndexError is removed, this will - become just C{CommandTestCase}. - """ - exceptionType = ValueError - mailboxType = DummyMailbox - - - -class SyncDeferredMailbox(DummyMailbox): - """ - Mailbox which has a listMessages implementation which returns a Deferred - which has already fired. - """ - def listMessages(self, n=None): - return defer.succeed(DummyMailbox.listMessages(self, n)) - - - -class IndexErrorSyncDeferredCommandTests(IndexErrorCommandTests): - """ - Run all of the L{IndexErrorCommandTests} tests with a - synchronous-Deferred returning IMailbox implementation. - """ - mailboxType = SyncDeferredMailbox - - - -class ValueErrorSyncDeferredCommandTests(ValueErrorCommandTests): - """ - Run all of the L{ValueErrorCommandTests} tests with a - synchronous-Deferred returning IMailbox implementation. - """ - mailboxType = SyncDeferredMailbox - - - -class AsyncDeferredMailbox(DummyMailbox): - """ - Mailbox which has a listMessages implementation which returns a Deferred - which has not yet fired. - """ - def __init__(self, *a, **kw): - self.waiting = [] - DummyMailbox.__init__(self, *a, **kw) - - - def listMessages(self, n=None): - d = defer.Deferred() - # See AsyncDeferredMailbox._flush - self.waiting.append((d, DummyMailbox.listMessages(self, n))) - return d - - - -class IndexErrorAsyncDeferredCommandTests(IndexErrorCommandTests): - """ - Run all of the L{IndexErrorCommandTests} tests with an asynchronous-Deferred - returning IMailbox implementation. - """ - mailboxType = AsyncDeferredMailbox - - def _flush(self): - """ - Fire whatever Deferreds we've built up in our mailbox. - """ - while self.pop3Server.mbox.waiting: - d, a = self.pop3Server.mbox.waiting.pop() - d.callback(a) - IndexErrorCommandTests._flush(self) - - - -class ValueErrorAsyncDeferredCommandTests(ValueErrorCommandTests): - """ - Run all of the L{IndexErrorCommandTests} tests with an asynchronous-Deferred - returning IMailbox implementation. - """ - mailboxType = AsyncDeferredMailbox - - def _flush(self): - """ - Fire whatever Deferreds we've built up in our mailbox. - """ - while self.pop3Server.mbox.waiting: - d, a = self.pop3Server.mbox.waiting.pop() - d.callback(a) - ValueErrorCommandTests._flush(self) - -class POP3MiscTests(unittest.TestCase): - """ - Miscellaneous tests more to do with module/package structure than - anything to do with the Post Office Protocol. - """ - def test_all(self): - """ - This test checks that all names listed in - twisted.mail.pop3.__all__ are actually present in the module. - """ - mod = twisted.mail.pop3 - for attr in mod.__all__: - self.failUnless(hasattr(mod, attr)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_pop3client.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_pop3client.py deleted file mode 100644 index eb5a427..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_pop3client.py +++ /dev/null @@ -1,620 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_pop3client -*- -# Copyright (c) 2001-2004 Divmod Inc. -# See LICENSE for details. - -import sys -import inspect - -from zope.interface import directlyProvides - -from twisted.mail.pop3 import AdvancedPOP3Client as POP3Client -from twisted.mail.pop3 import InsecureAuthenticationDisallowed -from twisted.mail.pop3 import ServerErrorResponse -from twisted.protocols import loopback -from twisted.internet import reactor, defer, error, protocol, interfaces -from twisted.python import log - -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport -from twisted.protocols import basic - -from twisted.mail.test import pop3testserver - -try: - from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext -except ImportError: - ClientTLSContext = ServerTLSContext = None - - -class StringTransportWithConnectionLosing(StringTransport): - def loseConnection(self): - self.protocol.connectionLost(error.ConnectionDone()) - - -capCache = {"TOP": None, "LOGIN-DELAY": "180", "UIDL": None, \ - "STLS": None, "USER": None, "SASL": "LOGIN"} -def setUp(greet=True): - p = POP3Client() - - # Skip the CAPA login will issue if it doesn't already have a - # capability cache - p._capCache = capCache - - t = StringTransportWithConnectionLosing() - t.protocol = p - p.makeConnection(t) - - if greet: - p.dataReceived('+OK Hello!\r\n') - - return p, t - -def strip(f): - return lambda result, f=f: f() - -class POP3ClientLoginTests(unittest.TestCase): - def testNegativeGreeting(self): - p, t = setUp(greet=False) - p.allowInsecureLogin = True - d = p.login("username", "password") - p.dataReceived('-ERR Offline for maintenance\r\n') - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "Offline for maintenance")) - - - def testOkUser(self): - p, t = setUp() - d = p.user("username") - self.assertEqual(t.value(), "USER username\r\n") - p.dataReceived("+OK send password\r\n") - return d.addCallback(self.assertEqual, "send password") - - def testBadUser(self): - p, t = setUp() - d = p.user("username") - self.assertEqual(t.value(), "USER username\r\n") - p.dataReceived("-ERR account suspended\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "account suspended")) - - def testOkPass(self): - p, t = setUp() - d = p.password("password") - self.assertEqual(t.value(), "PASS password\r\n") - p.dataReceived("+OK you're in!\r\n") - return d.addCallback(self.assertEqual, "you're in!") - - def testBadPass(self): - p, t = setUp() - d = p.password("password") - self.assertEqual(t.value(), "PASS password\r\n") - p.dataReceived("-ERR go away\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "go away")) - - def testOkLogin(self): - p, t = setUp() - p.allowInsecureLogin = True - d = p.login("username", "password") - self.assertEqual(t.value(), "USER username\r\n") - p.dataReceived("+OK go ahead\r\n") - self.assertEqual(t.value(), "USER username\r\nPASS password\r\n") - p.dataReceived("+OK password accepted\r\n") - return d.addCallback(self.assertEqual, "password accepted") - - def testBadPasswordLogin(self): - p, t = setUp() - p.allowInsecureLogin = True - d = p.login("username", "password") - self.assertEqual(t.value(), "USER username\r\n") - p.dataReceived("+OK waiting on you\r\n") - self.assertEqual(t.value(), "USER username\r\nPASS password\r\n") - p.dataReceived("-ERR bogus login\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "bogus login")) - - def testBadUsernameLogin(self): - p, t = setUp() - p.allowInsecureLogin = True - d = p.login("username", "password") - self.assertEqual(t.value(), "USER username\r\n") - p.dataReceived("-ERR bogus login\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "bogus login")) - - def testServerGreeting(self): - p, t = setUp(greet=False) - p.dataReceived("+OK lalala this has no challenge\r\n") - self.assertEqual(p.serverChallenge, None) - - def testServerGreetingWithChallenge(self): - p, t = setUp(greet=False) - p.dataReceived("+OK \r\n") - self.assertEqual(p.serverChallenge, "") - - def testAPOP(self): - p, t = setUp(greet=False) - p.dataReceived("+OK \r\n") - d = p.login("username", "password") - self.assertEqual(t.value(), "APOP username f34f1e464d0d7927607753129cabe39a\r\n") - p.dataReceived("+OK Welcome!\r\n") - return d.addCallback(self.assertEqual, "Welcome!") - - def testInsecureLoginRaisesException(self): - p, t = setUp(greet=False) - p.dataReceived("+OK Howdy\r\n") - d = p.login("username", "password") - self.failIf(t.value()) - return self.assertFailure( - d, InsecureAuthenticationDisallowed) - - - def testSSLTransportConsideredSecure(self): - """ - If a server doesn't offer APOP but the transport is secured using - SSL or TLS, a plaintext login should be allowed, not rejected with - an InsecureAuthenticationDisallowed exception. - """ - p, t = setUp(greet=False) - directlyProvides(t, interfaces.ISSLTransport) - p.dataReceived("+OK Howdy\r\n") - d = p.login("username", "password") - self.assertEqual(t.value(), "USER username\r\n") - t.clear() - p.dataReceived("+OK\r\n") - self.assertEqual(t.value(), "PASS password\r\n") - p.dataReceived("+OK\r\n") - return d - - - -class ListConsumer: - def __init__(self): - self.data = {} - - def consume(self, (item, value)): - self.data.setdefault(item, []).append(value) - -class MessageConsumer: - def __init__(self): - self.data = [] - - def consume(self, line): - self.data.append(line) - -class POP3ClientListTests(unittest.TestCase): - def testListSize(self): - p, t = setUp() - d = p.listSize() - self.assertEqual(t.value(), "LIST\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 3\r\n2 2\r\n3 1\r\n.\r\n") - return d.addCallback(self.assertEqual, [3, 2, 1]) - - def testListSizeWithConsumer(self): - p, t = setUp() - c = ListConsumer() - f = c.consume - d = p.listSize(f) - self.assertEqual(t.value(), "LIST\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 3\r\n2 2\r\n3 1\r\n") - self.assertEqual(c.data, {0: [3], 1: [2], 2: [1]}) - p.dataReceived("5 3\r\n6 2\r\n7 1\r\n") - self.assertEqual(c.data, {0: [3], 1: [2], 2: [1], 4: [3], 5: [2], 6: [1]}) - p.dataReceived(".\r\n") - return d.addCallback(self.assertIdentical, f) - - def testFailedListSize(self): - p, t = setUp() - d = p.listSize() - self.assertEqual(t.value(), "LIST\r\n") - p.dataReceived("-ERR Fatal doom server exploded\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "Fatal doom server exploded")) - - def testListUID(self): - p, t = setUp() - d = p.listUID() - self.assertEqual(t.value(), "UIDL\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 abc\r\n2 def\r\n3 ghi\r\n.\r\n") - return d.addCallback(self.assertEqual, ["abc", "def", "ghi"]) - - def testListUIDWithConsumer(self): - p, t = setUp() - c = ListConsumer() - f = c.consume - d = p.listUID(f) - self.assertEqual(t.value(), "UIDL\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 xyz\r\n2 abc\r\n5 mno\r\n") - self.assertEqual(c.data, {0: ["xyz"], 1: ["abc"], 4: ["mno"]}) - p.dataReceived(".\r\n") - return d.addCallback(self.assertIdentical, f) - - def testFailedListUID(self): - p, t = setUp() - d = p.listUID() - self.assertEqual(t.value(), "UIDL\r\n") - p.dataReceived("-ERR Fatal doom server exploded\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "Fatal doom server exploded")) - -class POP3ClientMessageTests(unittest.TestCase): - def testRetrieve(self): - p, t = setUp() - d = p.retrieve(7) - self.assertEqual(t.value(), "RETR 8\r\n") - p.dataReceived("+OK Message incoming\r\n") - p.dataReceived("La la la here is message text\r\n") - p.dataReceived("..Further message text tra la la\r\n") - p.dataReceived(".\r\n") - return d.addCallback( - self.assertEqual, - ["La la la here is message text", - ".Further message text tra la la"]) - - def testRetrieveWithConsumer(self): - p, t = setUp() - c = MessageConsumer() - f = c.consume - d = p.retrieve(7, f) - self.assertEqual(t.value(), "RETR 8\r\n") - p.dataReceived("+OK Message incoming\r\n") - p.dataReceived("La la la here is message text\r\n") - p.dataReceived("..Further message text\r\n.\r\n") - return d.addCallback(self._cbTestRetrieveWithConsumer, f, c) - - def _cbTestRetrieveWithConsumer(self, result, f, c): - self.assertIdentical(result, f) - self.assertEqual(c.data, ["La la la here is message text", - ".Further message text"]) - - def testPartialRetrieve(self): - p, t = setUp() - d = p.retrieve(7, lines=2) - self.assertEqual(t.value(), "TOP 8 2\r\n") - p.dataReceived("+OK 2 lines on the way\r\n") - p.dataReceived("Line the first! Woop\r\n") - p.dataReceived("Line the last! Bye\r\n") - p.dataReceived(".\r\n") - return d.addCallback( - self.assertEqual, - ["Line the first! Woop", - "Line the last! Bye"]) - - def testPartialRetrieveWithConsumer(self): - p, t = setUp() - c = MessageConsumer() - f = c.consume - d = p.retrieve(7, f, lines=2) - self.assertEqual(t.value(), "TOP 8 2\r\n") - p.dataReceived("+OK 2 lines on the way\r\n") - p.dataReceived("Line the first! Woop\r\n") - p.dataReceived("Line the last! Bye\r\n") - p.dataReceived(".\r\n") - return d.addCallback(self._cbTestPartialRetrieveWithConsumer, f, c) - - def _cbTestPartialRetrieveWithConsumer(self, result, f, c): - self.assertIdentical(result, f) - self.assertEqual(c.data, ["Line the first! Woop", - "Line the last! Bye"]) - - def testFailedRetrieve(self): - p, t = setUp() - d = p.retrieve(0) - self.assertEqual(t.value(), "RETR 1\r\n") - p.dataReceived("-ERR Fatal doom server exploded\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "Fatal doom server exploded")) - - - def test_concurrentRetrieves(self): - """ - Issue three retrieve calls immediately without waiting for any to - succeed and make sure they all do succeed eventually. - """ - p, t = setUp() - messages = [ - p.retrieve(i).addCallback( - self.assertEqual, - ["First line of %d." % (i + 1,), - "Second line of %d." % (i + 1,)]) - for i - in range(3)] - - for i in range(1, 4): - self.assertEqual(t.value(), "RETR %d\r\n" % (i,)) - t.clear() - p.dataReceived("+OK 2 lines on the way\r\n") - p.dataReceived("First line of %d.\r\n" % (i,)) - p.dataReceived("Second line of %d.\r\n" % (i,)) - self.assertEqual(t.value(), "") - p.dataReceived(".\r\n") - - return defer.DeferredList(messages, fireOnOneErrback=True) - - - -class POP3ClientMiscTests(unittest.TestCase): - def testCapability(self): - p, t = setUp() - d = p.capabilities(useCache=0) - self.assertEqual(t.value(), "CAPA\r\n") - p.dataReceived("+OK Capabilities on the way\r\n") - p.dataReceived("X\r\nY\r\nZ\r\nA 1 2 3\r\nB 1 2\r\nC 1\r\n.\r\n") - return d.addCallback( - self.assertEqual, - {"X": None, "Y": None, "Z": None, - "A": ["1", "2", "3"], - "B": ["1", "2"], - "C": ["1"]}) - - def testCapabilityError(self): - p, t = setUp() - d = p.capabilities(useCache=0) - self.assertEqual(t.value(), "CAPA\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return d.addCallback(self.assertEqual, {}) - - def testStat(self): - p, t = setUp() - d = p.stat() - self.assertEqual(t.value(), "STAT\r\n") - p.dataReceived("+OK 1 1212\r\n") - return d.addCallback(self.assertEqual, (1, 1212)) - - def testStatError(self): - p, t = setUp() - d = p.stat() - self.assertEqual(t.value(), "STAT\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "This server is lame!")) - - def testNoop(self): - p, t = setUp() - d = p.noop() - self.assertEqual(t.value(), "NOOP\r\n") - p.dataReceived("+OK No-op to you too!\r\n") - return d.addCallback(self.assertEqual, "No-op to you too!") - - def testNoopError(self): - p, t = setUp() - d = p.noop() - self.assertEqual(t.value(), "NOOP\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "This server is lame!")) - - def testRset(self): - p, t = setUp() - d = p.reset() - self.assertEqual(t.value(), "RSET\r\n") - p.dataReceived("+OK Reset state\r\n") - return d.addCallback(self.assertEqual, "Reset state") - - def testRsetError(self): - p, t = setUp() - d = p.reset() - self.assertEqual(t.value(), "RSET\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "This server is lame!")) - - def testDelete(self): - p, t = setUp() - d = p.delete(3) - self.assertEqual(t.value(), "DELE 4\r\n") - p.dataReceived("+OK Hasta la vista\r\n") - return d.addCallback(self.assertEqual, "Hasta la vista") - - def testDeleteError(self): - p, t = setUp() - d = p.delete(3) - self.assertEqual(t.value(), "DELE 4\r\n") - p.dataReceived("-ERR Winner is not you.\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEqual(exc.args[0], "Winner is not you.")) - - -class SimpleClient(POP3Client): - def __init__(self, deferred, contextFactory = None): - self.deferred = deferred - self.allowInsecureLogin = True - - def serverGreeting(self, challenge): - self.deferred.callback(None) - -class POP3HelperMixin: - serverCTX = None - clientCTX = None - - def setUp(self): - d = defer.Deferred() - self.server = pop3testserver.POP3TestServer(contextFactory=self.serverCTX) - self.client = SimpleClient(d, contextFactory=self.clientCTX) - self.client.timeout = 30 - self.connected = d - - def tearDown(self): - del self.server - del self.client - del self.connected - - def _cbStopClient(self, ignore): - self.client.transport.loseConnection() - - def _ebGeneral(self, failure): - self.client.transport.loseConnection() - self.server.transport.loseConnection() - return failure - - def loopback(self): - return loopback.loopbackTCP(self.server, self.client, noisy=False) - - -class TLSServerFactory(protocol.ServerFactory): - class protocol(basic.LineReceiver): - context = None - output = [] - def connectionMade(self): - self.factory.input = [] - self.output = self.output[:] - map(self.sendLine, self.output.pop(0)) - def lineReceived(self, line): - self.factory.input.append(line) - map(self.sendLine, self.output.pop(0)) - if line == 'STLS': - self.transport.startTLS(self.context) - - -class POP3TLSTests(unittest.TestCase): - """ - Tests for POP3Client's support for TLS connections. - """ - - def test_startTLS(self): - """ - POP3Client.startTLS starts a TLS session over its existing TCP - connection. - """ - sf = TLSServerFactory() - sf.protocol.output = [ - ['+OK'], # Server greeting - ['+OK', 'STLS', '.'], # CAPA response - ['+OK'], # STLS response - ['+OK', '.'], # Second CAPA response - ['+OK'] # QUIT response - ] - sf.protocol.context = ServerTLSContext() - port = reactor.listenTCP(0, sf, interface='127.0.0.1') - self.addCleanup(port.stopListening) - H = port.getHost().host - P = port.getHost().port - - connLostDeferred = defer.Deferred() - cp = SimpleClient(defer.Deferred(), ClientTLSContext()) - def connectionLost(reason): - SimpleClient.connectionLost(cp, reason) - connLostDeferred.callback(None) - cp.connectionLost = connectionLost - cf = protocol.ClientFactory() - cf.protocol = lambda: cp - - conn = reactor.connectTCP(H, P, cf) - - def cbConnected(ignored): - log.msg("Connected to server; starting TLS") - return cp.startTLS() - - def cbStartedTLS(ignored): - log.msg("Started TLS; disconnecting") - return cp.quit() - - def cbDisconnected(ign): - log.msg("Disconnected; asserting correct input received") - self.assertEqual( - sf.input, - ['CAPA', 'STLS', 'CAPA', 'QUIT']) - - def cleanup(result): - log.msg("Asserted correct input; disconnecting client and shutting down server") - conn.disconnect() - return connLostDeferred - - cp.deferred.addCallback(cbConnected) - cp.deferred.addCallback(cbStartedTLS) - cp.deferred.addCallback(cbDisconnected) - cp.deferred.addBoth(cleanup) - - return cp.deferred - - -class POP3TimeoutTests(POP3HelperMixin, unittest.TestCase): - def testTimeout(self): - def login(): - d = self.client.login('test', 'twisted') - d.addCallback(loggedIn) - d.addErrback(timedOut) - return d - - def loggedIn(result): - self.fail("Successfully logged in!? Impossible!") - - - def timedOut(failure): - failure.trap(error.TimeoutError) - self._cbStopClient(None) - - def quit(): - return self.client.quit() - - self.client.timeout = 0.01 - - # Tell the server to not return a response to client. This - # will trigger a timeout. - pop3testserver.TIMEOUT_RESPONSE = True - - methods = [login, quit] - map(self.connected.addCallback, map(strip, methods)) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - return self.loopback() - - -if ClientTLSContext is None: - for case in (POP3TLSTests,): - case.skip = "OpenSSL not present" -elif interfaces.IReactorSSL(reactor, None) is None: - for case in (POP3TLSTests,): - case.skip = "Reactor doesn't support SSL" - - - -import twisted.mail.pop3client - -class POP3ClientModuleStructureTests(unittest.TestCase): - """ - Miscellaneous tests more to do with module/package structure than - anything to do with the POP3 client. - """ - def test_all(self): - """ - twisted.mail.pop3client.__all__ should be empty because all classes - should be imported through twisted.mail.pop3. - """ - self.assertEqual(twisted.mail.pop3client.__all__, []) - - - def test_import(self): - """ - Every public class in twisted.mail.pop3client should be available as a - member of twisted.mail.pop3 with the exception of - twisted.mail.pop3client.POP3Client which should be available as - twisted.mail.pop3.AdvancedClient. - """ - publicClasses = [c[0] for c in inspect.getmembers( - sys.modules['twisted.mail.pop3client'], - inspect.isclass) - if not c[0][0] == '_'] - - for pc in publicClasses: - if not pc == 'POP3Client': - self.failUnless(hasattr(twisted.mail.pop3, pc)) - else: - self.failUnless(hasattr(twisted.mail.pop3, - 'AdvancedPOP3Client')) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_scripts.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_scripts.py deleted file mode 100644 index cc14061..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_scripts.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for the command-line mailer tool provided by Twisted Mail. -""" - -from twisted.trial.unittest import TestCase -from twisted.scripts.test.test_scripts import ScriptTestsMixin - - - -class ScriptTests(TestCase, ScriptTestsMixin): - """ - Tests for all one of mail's scripts. - """ - def test_mailmail(self): - self.scriptTest("mail/mailmail") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_smtp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_smtp.py deleted file mode 100644 index 1bf5868..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/test/test_smtp.py +++ /dev/null @@ -1,1923 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.mail.smtp module. -""" -import inspect - -from zope.interface import implements, directlyProvides - -from twisted.python.util import LineLog -from twisted.trial import unittest, util -from twisted.protocols import basic, loopback -from twisted.mail import smtp -from twisted.internet import defer, protocol, reactor, interfaces -from twisted.internet import address, error, task -from twisted.test.proto_helpers import MemoryReactor, StringTransport - -from twisted import cred -import twisted.cred.error -import twisted.cred.portal -import twisted.cred.checkers -import twisted.cred.credentials - -from twisted.cred.portal import IRealm, Portal -from twisted.cred.checkers import ICredentialsChecker, AllowAnonymousAccess -from twisted.cred.credentials import IAnonymous -from twisted.cred.error import UnauthorizedLogin - -from twisted.mail import imap4 - - -try: - from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext -except ImportError: - sslSkip = "OpenSSL not present" -else: - sslSkip = None - -import re - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - - -def spameater(*spam, **eggs): - return None - - - -class BrokenMessage(object): - """ - L{BrokenMessage} is an L{IMessage} which raises an unexpected exception - from its C{eomReceived} method. This is useful for creating a server which - can be used to test client retry behavior. - """ - implements(smtp.IMessage) - - def __init__(self, user): - pass - - - def lineReceived(self, line): - pass - - - def eomReceived(self): - raise RuntimeError("Some problem, delivery is failing.") - - - def connectionLost(self): - pass - - - -class DummyMessage(object): - """ - L{BrokenMessage} is an L{IMessage} which saves the message delivered to it - to its domain object. - - @ivar domain: A L{DummyDomain} which will be used to store the message once - it is received. - """ - def __init__(self, domain, user): - self.domain = domain - self.user = user - self.buffer = [] - - - def lineReceived(self, line): - # Throw away the generated Received: header - if not re.match('Received: From yyy.com \(\[.*\]\) by localhost;', line): - self.buffer.append(line) - - - def eomReceived(self): - message = '\n'.join(self.buffer) + '\n' - self.domain.messages[self.user.dest.local].append(message) - deferred = defer.Deferred() - deferred.callback("saved") - return deferred - - - -class DummyDomain(object): - """ - L{DummyDomain} is an L{IDomain} which keeps track of messages delivered to - it in memory. - """ - def __init__(self, names): - self.messages = {} - for name in names: - self.messages[name] = [] - - - def exists(self, user): - if user.dest.local in self.messages: - return defer.succeed(lambda: DummyMessage(self, user)) - return defer.fail(smtp.SMTPBadRcpt(user)) - - - -class SMTPTests(unittest.TestCase): - - messages = [('foo@bar.com', ['foo@baz.com', 'qux@baz.com'], '''\ -Subject: urgent\015 -\015 -Someone set up us the bomb!\015 -''')] - - mbox = {'foo': ['Subject: urgent\n\nSomeone set up us the bomb!\n']} - - def setUp(self): - """ - Create an in-memory mail domain to which messages may be delivered by - tests and create a factory and transport to do the delivering. - """ - self.factory = smtp.SMTPFactory() - self.factory.domains = {} - self.factory.domains['baz.com'] = DummyDomain(['foo']) - self.transport = StringTransport() - - - def testMessages(self): - from twisted.mail import protocols - protocol = protocols.DomainSMTP() - protocol.service = self.factory - protocol.factory = self.factory - protocol.receivedHeader = spameater - protocol.makeConnection(self.transport) - protocol.lineReceived('HELO yyy.com') - for message in self.messages: - protocol.lineReceived('MAIL FROM:<%s>' % message[0]) - for target in message[1]: - protocol.lineReceived('RCPT TO:<%s>' % target) - protocol.lineReceived('DATA') - protocol.dataReceived(message[2]) - protocol.lineReceived('.') - protocol.lineReceived('QUIT') - if self.mbox != self.factory.domains['baz.com'].messages: - raise AssertionError(self.factory.domains['baz.com'].messages) - protocol.setTimeout(None) - - testMessages.suppress = [util.suppress(message='DomainSMTP', category=DeprecationWarning)] - -mail = '''\ -Subject: hello - -Goodbye -''' - -class MyClient: - def __init__(self, messageInfo=None): - if messageInfo is None: - messageInfo = ( - 'moshez@foo.bar', ['moshez@foo.bar'], StringIO(mail)) - self._sender = messageInfo[0] - self._recipient = messageInfo[1] - self._data = messageInfo[2] - - - def getMailFrom(self): - return self._sender - - - def getMailTo(self): - return self._recipient - - - def getMailData(self): - return self._data - - - def sendError(self, exc): - self._error = exc - - - def sentMail(self, code, resp, numOk, addresses, log): - # Prevent another mail from being sent. - self._sender = None - self._recipient = None - self._data = None - - - -class MySMTPClient(MyClient, smtp.SMTPClient): - def __init__(self, messageInfo=None): - smtp.SMTPClient.__init__(self, 'foo.baz') - MyClient.__init__(self, messageInfo) - -class MyESMTPClient(MyClient, smtp.ESMTPClient): - def __init__(self, secret = '', contextFactory = None): - smtp.ESMTPClient.__init__(self, secret, contextFactory, 'foo.baz') - MyClient.__init__(self) - -class LoopbackMixin: - def loopback(self, server, client): - return loopback.loopbackTCP(server, client) - -class LoopbackTestCase(LoopbackMixin): - def testMessages(self): - factory = smtp.SMTPFactory() - factory.domains = {} - factory.domains['foo.bar'] = DummyDomain(['moshez']) - from twisted.mail.protocols import DomainSMTP - protocol = DomainSMTP() - protocol.service = factory - protocol.factory = factory - clientProtocol = self.clientClass() - return self.loopback(protocol, clientProtocol) - testMessages.suppress = [util.suppress(message='DomainSMTP', category=DeprecationWarning)] - -class LoopbackSMTPTests(LoopbackTestCase, unittest.TestCase): - clientClass = MySMTPClient - -class LoopbackESMTPTests(LoopbackTestCase, unittest.TestCase): - clientClass = MyESMTPClient - - -class FakeSMTPServer(basic.LineReceiver): - - clientData = [ - '220 hello', '250 nice to meet you', - '250 great', '250 great', '354 go on, lad' - ] - - def connectionMade(self): - self.buffer = [] - self.clientData = self.clientData[:] - self.clientData.reverse() - self.sendLine(self.clientData.pop()) - - def lineReceived(self, line): - self.buffer.append(line) - if line == "QUIT": - self.transport.write("221 see ya around\r\n") - self.transport.loseConnection() - elif line == ".": - self.transport.write("250 gotcha\r\n") - elif line == "RSET": - self.transport.loseConnection() - - if self.clientData: - self.sendLine(self.clientData.pop()) - - -class SMTPClientTests(unittest.TestCase, LoopbackMixin): - """ - Tests for L{smtp.SMTPClient}. - """ - - def test_timeoutConnection(self): - """ - L{smtp.SMTPClient.timeoutConnection} calls the C{sendError} hook with a - fatal L{SMTPTimeoutError} with the current line log. - """ - errors = [] - client = MySMTPClient() - client.sendError = errors.append - client.makeConnection(StringTransport()) - client.lineReceived("220 hello") - client.timeoutConnection() - self.assertIsInstance(errors[0], smtp.SMTPTimeoutError) - self.assertTrue(errors[0].isFatal) - self.assertEqual( - str(errors[0]), - "Timeout waiting for SMTP server response\n" - "<<< 220 hello\n" - ">>> HELO foo.baz\n") - - - expected_output = [ - 'HELO foo.baz', 'MAIL FROM:', - 'RCPT TO:', 'DATA', - 'Subject: hello', '', 'Goodbye', '.', 'RSET' - ] - - def test_messages(self): - """ - L{smtp.SMTPClient} sends I{HELO}, I{MAIL FROM}, I{RCPT TO}, and I{DATA} - commands based on the return values of its C{getMailFrom}, - C{getMailTo}, and C{getMailData} methods. - """ - client = MySMTPClient() - server = FakeSMTPServer() - d = self.loopback(server, client) - d.addCallback(lambda x : - self.assertEqual(server.buffer, self.expected_output)) - return d - - - def test_transferError(self): - """ - If there is an error while producing the message body to the - connection, the C{sendError} callback is invoked. - """ - client = MySMTPClient( - ('alice@example.com', ['bob@example.com'], StringIO("foo"))) - transport = StringTransport() - client.makeConnection(transport) - client.dataReceived( - '220 Ok\r\n' # Greeting - '250 Ok\r\n' # EHLO response - '250 Ok\r\n' # MAIL FROM response - '250 Ok\r\n' # RCPT TO response - '354 Ok\r\n' # DATA response - ) - - # Sanity check - a pull producer should be registered now. - self.assertNotIdentical(transport.producer, None) - self.assertFalse(transport.streaming) - - # Now stop the producer prematurely, meaning the message was not sent. - transport.producer.stopProducing() - - # The sendError hook should have been invoked as a result. - self.assertIsInstance(client._error, Exception) - - - def test_sendFatalError(self): - """ - If L{smtp.SMTPClient.sendError} is called with an L{SMTPClientError} - which is fatal, it disconnects its transport without writing anything - more to it. - """ - client = smtp.SMTPClient(None) - transport = StringTransport() - client.makeConnection(transport) - client.sendError(smtp.SMTPClientError(123, "foo", isFatal=True)) - self.assertEqual(transport.value(), "") - self.assertTrue(transport.disconnecting) - - - def test_sendNonFatalError(self): - """ - If L{smtp.SMTPClient.sendError} is called with an L{SMTPClientError} - which is not fatal, it sends C{"QUIT"} and waits for the server to - close the connection. - """ - client = smtp.SMTPClient(None) - transport = StringTransport() - client.makeConnection(transport) - client.sendError(smtp.SMTPClientError(123, "foo", isFatal=False)) - self.assertEqual(transport.value(), "QUIT\r\n") - self.assertFalse(transport.disconnecting) - - - def test_sendOtherError(self): - """ - If L{smtp.SMTPClient.sendError} is called with an exception which is - not an L{SMTPClientError}, it disconnects its transport without - writing anything more to it. - """ - client = smtp.SMTPClient(None) - transport = StringTransport() - client.makeConnection(transport) - client.sendError(Exception("foo")) - self.assertEqual(transport.value(), "") - self.assertTrue(transport.disconnecting) - - - -class DummySMTPMessage: - - def __init__(self, protocol, users): - self.protocol = protocol - self.users = users - self.buffer = [] - - def lineReceived(self, line): - self.buffer.append(line) - - def eomReceived(self): - message = '\n'.join(self.buffer) + '\n' - helo, origin = self.users[0].helo[0], str(self.users[0].orig) - recipients = [] - for user in self.users: - recipients.append(str(user)) - self.protocol.message[tuple(recipients)] = (helo, origin, recipients, message) - return defer.succeed("saved") - - - -class DummyProto: - def connectionMade(self): - self.dummyMixinBase.connectionMade(self) - self.message = {} - - - def receivedHeader(*spam): - return None - - - def validateTo(self, user): - self.delivery = SimpleDelivery(None) - return lambda: DummySMTPMessage(self, [user]) - - - def validateFrom(self, helo, origin): - return origin - - - -class DummySMTP(DummyProto, smtp.SMTP): - dummyMixinBase = smtp.SMTP - -class DummyESMTP(DummyProto, smtp.ESMTP): - dummyMixinBase = smtp.ESMTP - -class AnotherTestCase: - serverClass = None - clientClass = None - - messages = [ ('foo.com', 'moshez@foo.com', ['moshez@bar.com'], - 'moshez@foo.com', ['moshez@bar.com'], '''\ -From: Moshe -To: Moshe - -Hi, -how are you? -'''), - ('foo.com', 'tttt@rrr.com', ['uuu@ooo', 'yyy@eee'], - 'tttt@rrr.com', ['uuu@ooo', 'yyy@eee'], '''\ -Subject: pass - -..rrrr.. -'''), - ('foo.com', '@this,@is,@ignored:foo@bar.com', - ['@ignore,@this,@too:bar@foo.com'], - 'foo@bar.com', ['bar@foo.com'], '''\ -Subject: apa -To: foo - -123 -. -456 -'''), - ] - - data = [ - ('', '220.*\r\n$', None, None), - ('HELO foo.com\r\n', '250.*\r\n$', None, None), - ('RSET\r\n', '250.*\r\n$', None, None), - ] - for helo_, from_, to_, realfrom, realto, msg in messages: - data.append(('MAIL FROM:<%s>\r\n' % from_, '250.*\r\n', - None, None)) - for rcpt in to_: - data.append(('RCPT TO:<%s>\r\n' % rcpt, '250.*\r\n', - None, None)) - - data.append(('DATA\r\n','354.*\r\n', - msg, ('250.*\r\n', - (helo_, realfrom, realto, msg)))) - - - def test_buffer(self): - """ - Exercise a lot of the SMTP client code. This is a "shotgun" style unit - test. It does a lot of things and hopes that something will go really - wrong if it is going to go wrong. This test should be replaced with a - suite of nicer tests. - """ - transport = StringTransport() - a = self.serverClass() - class fooFactory: - domain = 'foo.com' - - a.factory = fooFactory() - a.makeConnection(transport) - for (send, expect, msg, msgexpect) in self.data: - if send: - a.dataReceived(send) - data = transport.value() - transport.clear() - if not re.match(expect, data): - raise AssertionError, (send, expect, data) - if data[:3] == '354': - for line in msg.splitlines(): - if line and line[0] == '.': - line = '.' + line - a.dataReceived(line + '\r\n') - a.dataReceived('.\r\n') - # Special case for DATA. Now we want a 250, and then - # we compare the messages - data = transport.value() - transport.clear() - resp, msgdata = msgexpect - if not re.match(resp, data): - raise AssertionError, (resp, data) - for recip in msgdata[2]: - expected = list(msgdata[:]) - expected[2] = [recip] - self.assertEqual( - a.message[(recip,)], - tuple(expected) - ) - a.setTimeout(None) - - -class AnotherESMTPTests(AnotherTestCase, unittest.TestCase): - serverClass = DummyESMTP - clientClass = MyESMTPClient - -class AnotherSMTPTests(AnotherTestCase, unittest.TestCase): - serverClass = DummySMTP - clientClass = MySMTPClient - - - -class DummyChecker: - implements(cred.checkers.ICredentialsChecker) - - users = { - 'testuser': 'testpassword' - } - - credentialInterfaces = (cred.credentials.IUsernamePassword, - cred.credentials.IUsernameHashedPassword) - - def requestAvatarId(self, credentials): - return defer.maybeDeferred( - credentials.checkPassword, self.users[credentials.username] - ).addCallback(self._cbCheck, credentials.username) - - def _cbCheck(self, result, username): - if result: - return username - raise cred.error.UnauthorizedLogin() - - - -class SimpleDelivery(object): - """ - L{SimpleDelivery} is a message delivery factory with no interesting - behavior. - """ - implements(smtp.IMessageDelivery) - - def __init__(self, messageFactory): - self._messageFactory = messageFactory - - - def receivedHeader(self, helo, origin, recipients): - return None - - - def validateFrom(self, helo, origin): - return origin - - - def validateTo(self, user): - return lambda: self._messageFactory(user) - - - -class DummyRealm: - def requestAvatar(self, avatarId, mind, *interfaces): - return smtp.IMessageDelivery, SimpleDelivery(None), lambda: None - - - -class AuthTests(unittest.TestCase, LoopbackMixin): - def test_crammd5Auth(self): - """ - L{ESMTPClient} can authenticate using the I{CRAM-MD5} SASL mechanism. - - @see: U{http://tools.ietf.org/html/rfc2195} - """ - realm = DummyRealm() - p = cred.portal.Portal(realm) - p.registerChecker(DummyChecker()) - - server = DummyESMTP({'CRAM-MD5': cred.credentials.CramMD5Credentials}) - server.portal = p - client = MyESMTPClient('testpassword') - - cAuth = smtp.CramMD5ClientAuthenticator('testuser') - client.registerAuthenticator(cAuth) - - d = self.loopback(server, client) - d.addCallback(lambda x : self.assertEqual(server.authenticated, 1)) - return d - - - def test_loginAuth(self): - """ - L{ESMTPClient} can authenticate using the I{LOGIN} SASL mechanism. - - @see: U{http://sepp.oetiker.ch/sasl-2.1.19-ds/draft-murchison-sasl-login-00.txt} - """ - realm = DummyRealm() - p = cred.portal.Portal(realm) - p.registerChecker(DummyChecker()) - - server = DummyESMTP({'LOGIN': imap4.LOGINCredentials}) - server.portal = p - client = MyESMTPClient('testpassword') - - cAuth = smtp.LOGINAuthenticator('testuser') - client.registerAuthenticator(cAuth) - - d = self.loopback(server, client) - d.addCallback(lambda x: self.assertTrue(server.authenticated)) - return d - - - def test_loginAgainstWeirdServer(self): - """ - When communicating with a server which implements the I{LOGIN} SASL - mechanism using C{"Username:"} as the challenge (rather than C{"User - Name\\0"}), L{ESMTPClient} can still authenticate successfully using - the I{LOGIN} mechanism. - """ - realm = DummyRealm() - p = cred.portal.Portal(realm) - p.registerChecker(DummyChecker()) - - server = DummyESMTP({'LOGIN': smtp.LOGINCredentials}) - server.portal = p - - client = MyESMTPClient('testpassword') - cAuth = smtp.LOGINAuthenticator('testuser') - client.registerAuthenticator(cAuth) - - d = self.loopback(server, client) - d.addCallback(lambda x: self.assertTrue(server.authenticated)) - return d - - - -class SMTPHelperTests(unittest.TestCase): - def testMessageID(self): - d = {} - for i in range(1000): - m = smtp.messageid('testcase') - self.failIf(m in d) - d[m] = None - - def testQuoteAddr(self): - cases = [ - ['user@host.name', ''], - ['"User Name" ', ''], - [smtp.Address('someguy@someplace'), ''], - ['', '<>'], - [smtp.Address(''), '<>'], - ] - - for (c, e) in cases: - self.assertEqual(smtp.quoteaddr(c), e) - - def testUser(self): - u = smtp.User('user@host', 'helo.host.name', None, None) - self.assertEqual(str(u), 'user@host') - - def testXtextEncoding(self): - cases = [ - ('Hello world', 'Hello+20world'), - ('Hello+world', 'Hello+2Bworld'), - ('\0\1\2\3\4\5', '+00+01+02+03+04+05'), - ('e=mc2@example.com', 'e+3Dmc2@example.com') - ] - - for (case, expected) in cases: - self.assertEqual(smtp.xtext_encode(case), (expected, len(case))) - self.assertEqual(case.encode('xtext'), expected) - self.assertEqual( - smtp.xtext_decode(expected), (case, len(expected))) - self.assertEqual(expected.decode('xtext'), case) - - - def test_encodeWithErrors(self): - """ - Specifying an error policy to C{unicode.encode} with the - I{xtext} codec should produce the same result as not - specifying the error policy. - """ - text = u'Hello world' - self.assertEqual( - smtp.xtext_encode(text, 'strict'), - (text.encode('xtext'), len(text))) - self.assertEqual( - text.encode('xtext', 'strict'), - text.encode('xtext')) - - - def test_decodeWithErrors(self): - """ - Similar to L{test_encodeWithErrors}, but for C{str.decode}. - """ - bytes = 'Hello world' - self.assertEqual( - smtp.xtext_decode(bytes, 'strict'), - (bytes.decode('xtext'), len(bytes))) - self.assertEqual( - bytes.decode('xtext', 'strict'), - bytes.decode('xtext')) - - - -class NoticeTLSClient(MyESMTPClient): - tls = False - - def esmtpState_starttls(self, code, resp): - MyESMTPClient.esmtpState_starttls(self, code, resp) - self.tls = True - - - -class TLSTests(unittest.TestCase, LoopbackMixin): - if sslSkip is not None: - skip = sslSkip - - def testTLS(self): - clientCTX = ClientTLSContext() - serverCTX = ServerTLSContext() - - client = NoticeTLSClient(contextFactory=clientCTX) - server = DummyESMTP(contextFactory=serverCTX) - - def check(ignored): - self.assertEqual(client.tls, True) - self.assertEqual(server.startedTLS, True) - - return self.loopback(server, client).addCallback(check) - -if not interfaces.IReactorSSL.providedBy(reactor): - for case in (TLSTests,): - case.skip = "Reactor doesn't support SSL" - - - -class EmptyLineTests(unittest.TestCase): - def test_emptyLineSyntaxError(self): - """ - If L{smtp.SMTP} receives an empty line, it responds with a 500 error - response code and a message about a syntax error. - """ - proto = smtp.SMTP() - transport = StringTransport() - proto.makeConnection(transport) - proto.lineReceived('') - proto.setTimeout(None) - - out = transport.value().splitlines() - self.assertEqual(len(out), 2) - self.failUnless(out[0].startswith('220')) - self.assertEqual(out[1], "500 Error: bad syntax") - - - -class TimeoutTests(unittest.TestCase, LoopbackMixin): - """ - Check that SMTP client factories correctly use the timeout. - """ - - def _timeoutTest(self, onDone, clientFactory): - """ - Connect the clientFactory, and check the timeout on the request. - """ - clock = task.Clock() - client = clientFactory.buildProtocol( - address.IPv4Address('TCP', 'example.net', 25)) - client.callLater = clock.callLater - t = StringTransport() - client.makeConnection(t) - t.protocol = client - def check(ign): - self.assertEqual(clock.seconds(), 0.5) - d = self.assertFailure(onDone, smtp.SMTPTimeoutError - ).addCallback(check) - # The first call should not trigger the timeout - clock.advance(0.1) - # But this one should - clock.advance(0.4) - return d - - - def test_SMTPClient(self): - """ - Test timeout for L{smtp.SMTPSenderFactory}: the response L{Deferred} - should be errback with a L{smtp.SMTPTimeoutError}. - """ - onDone = defer.Deferred() - clientFactory = smtp.SMTPSenderFactory( - 'source@address', 'recipient@address', - StringIO("Message body"), onDone, - retries=0, timeout=0.5) - return self._timeoutTest(onDone, clientFactory) - - - def test_ESMTPClient(self): - """ - Test timeout for L{smtp.ESMTPSenderFactory}: the response L{Deferred} - should be errback with a L{smtp.SMTPTimeoutError}. - """ - onDone = defer.Deferred() - clientFactory = smtp.ESMTPSenderFactory( - 'username', 'password', - 'source@address', 'recipient@address', - StringIO("Message body"), onDone, - retries=0, timeout=0.5) - return self._timeoutTest(onDone, clientFactory) - - - def test_resetTimeoutWhileSending(self): - """ - The timeout is not allowed to expire after the server has accepted a - DATA command and the client is actively sending data to it. - """ - class SlowFile: - """ - A file-like which returns one byte from each read call until the - specified number of bytes have been returned. - """ - def __init__(self, size): - self._size = size - - def read(self, max=None): - if self._size: - self._size -= 1 - return 'x' - return '' - - failed = [] - onDone = defer.Deferred() - onDone.addErrback(failed.append) - clientFactory = smtp.SMTPSenderFactory( - 'source@address', 'recipient@address', - SlowFile(1), onDone, retries=0, timeout=3) - clientFactory.domain = "example.org" - clock = task.Clock() - client = clientFactory.buildProtocol( - address.IPv4Address('TCP', 'example.net', 25)) - client.callLater = clock.callLater - transport = StringTransport() - client.makeConnection(transport) - - client.dataReceived( - "220 Ok\r\n" # Greet the client - "250 Ok\r\n" # Respond to HELO - "250 Ok\r\n" # Respond to MAIL FROM - "250 Ok\r\n" # Respond to RCPT TO - "354 Ok\r\n" # Respond to DATA - ) - - # Now the client is producing data to the server. Any time - # resumeProducing is called on the producer, the timeout should be - # extended. First, a sanity check. This test is only written to - # handle pull producers. - self.assertNotIdentical(transport.producer, None) - self.assertFalse(transport.streaming) - - # Now, allow 2 seconds (1 less than the timeout of 3 seconds) to - # elapse. - clock.advance(2) - - # The timeout has not expired, so the failure should not have happened. - self.assertEqual(failed, []) - - # Let some bytes be produced, extending the timeout. Then advance the - # clock some more and verify that the timeout still hasn't happened. - transport.producer.resumeProducing() - clock.advance(2) - self.assertEqual(failed, []) - - # The file has been completely produced - the next resume producing - # finishes the upload, successfully. - transport.producer.resumeProducing() - client.dataReceived("250 Ok\r\n") - self.assertEqual(failed, []) - - # Verify that the client actually did send the things expected. - self.assertEqual( - transport.value(), - "HELO example.org\r\n" - "MAIL FROM:\r\n" - "RCPT TO:\r\n" - "DATA\r\n" - "x\r\n" - ".\r\n" - # This RSET is just an implementation detail. It's nice, but this - # test doesn't really care about it. - "RSET\r\n") - - - -class MultipleDeliveryFactorySMTPServerFactory(protocol.ServerFactory): - """ - L{MultipleDeliveryFactorySMTPServerFactory} creates SMTP server protocol - instances with message delivery factory objects supplied to it. Each - factory is used for one connection and then discarded. Factories are used - in the order they are supplied. - """ - def __init__(self, messageFactories): - self._messageFactories = messageFactories - - - def buildProtocol(self, addr): - p = protocol.ServerFactory.buildProtocol(self, addr) - p.delivery = SimpleDelivery(self._messageFactories.pop(0)) - return p - - - -class SMTPSenderFactoryTests(unittest.TestCase): - """ - Tests for L{smtp.SMTPSenderFactory}. - """ - def test_removeCurrentProtocolWhenClientConnectionLost(self): - """ - L{smtp.SMTPSenderFactory} removes the current protocol when the client - connection is lost. - """ - reactor = MemoryReactor() - sentDeferred = defer.Deferred() - clientFactory = smtp.SMTPSenderFactory( - "source@address", "recipient@address", - StringIO("message"), sentDeferred) - connector = reactor.connectTCP("localhost", 25, clientFactory) - clientFactory.buildProtocol(None) - clientFactory.clientConnectionLost(connector, - error.ConnectionDone("Bye.")) - self.assertEqual(clientFactory.currentProtocol, None) - - - def test_removeCurrentProtocolWhenClientConnectionFailed(self): - """ - L{smtp.SMTPSenderFactory} removes the current protocol when the client - connection is failed. - """ - reactor = MemoryReactor() - sentDeferred = defer.Deferred() - clientFactory = smtp.SMTPSenderFactory( - "source@address", "recipient@address", - StringIO("message"), sentDeferred) - connector = reactor.connectTCP("localhost", 25, clientFactory) - clientFactory.buildProtocol(None) - clientFactory.clientConnectionFailed(connector, - error.ConnectionDone("Bye.")) - self.assertEqual(clientFactory.currentProtocol, None) - - - -class SMTPSenderFactoryRetryTests(unittest.TestCase): - """ - Tests for the retry behavior of L{smtp.SMTPSenderFactory}. - """ - def test_retryAfterDisconnect(self): - """ - If the protocol created by L{SMTPSenderFactory} loses its connection - before receiving confirmation of message delivery, it reconnects and - tries to deliver the message again. - """ - recipient = 'alice' - message = "some message text" - domain = DummyDomain([recipient]) - - class CleanSMTP(smtp.SMTP): - """ - An SMTP subclass which ensures that its transport will be - disconnected before the test ends. - """ - def makeConnection(innerSelf, transport): - self.addCleanup(transport.loseConnection) - smtp.SMTP.makeConnection(innerSelf, transport) - - # Create a server which will fail the first message deliver attempt to - # it with a 500 and a disconnect, but which will accept a message - # delivered over the 2nd connection to it. - serverFactory = MultipleDeliveryFactorySMTPServerFactory([ - BrokenMessage, - lambda user: DummyMessage(domain, user)]) - serverFactory.protocol = CleanSMTP - serverPort = reactor.listenTCP(0, serverFactory, interface='127.0.0.1') - serverHost = serverPort.getHost() - self.addCleanup(serverPort.stopListening) - - # Set up a client to try to deliver a message to the above created - # server. - sentDeferred = defer.Deferred() - clientFactory = smtp.SMTPSenderFactory( - "bob@example.org", recipient + "@example.com", - StringIO(message), sentDeferred) - clientFactory.domain = "example.org" - clientConnector = reactor.connectTCP( - serverHost.host, serverHost.port, clientFactory) - self.addCleanup(clientConnector.disconnect) - - def cbSent(ignored): - """ - Verify that the message was successfully delivered and flush the - error which caused the first attempt to fail. - """ - self.assertEqual( - domain.messages, - {recipient: ["\n%s\n" % (message,)]}) - # Flush the RuntimeError that BrokenMessage caused to be logged. - self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1) - sentDeferred.addCallback(cbSent) - return sentDeferred - - - -class SingletonRealm(object): - """ - Trivial realm implementation which is constructed with an interface and an - avatar and returns that avatar when asked for that interface. - """ - implements(IRealm) - - def __init__(self, interface, avatar): - self.interface = interface - self.avatar = avatar - - - def requestAvatar(self, avatarId, mind, *interfaces): - for iface in interfaces: - if iface is self.interface: - return iface, self.avatar, lambda: None - - - -class NotImplementedDelivery(object): - """ - Non-implementation of L{smtp.IMessageDelivery} which only has methods which - raise L{NotImplementedError}. Subclassed by various tests to provide the - particular behavior being tested. - """ - def validateFrom(self, helo, origin): - raise NotImplementedError("This oughtn't be called in the course of this test.") - - - def validateTo(self, user): - raise NotImplementedError("This oughtn't be called in the course of this test.") - - - def receivedHeader(self, helo, origin, recipients): - raise NotImplementedError("This oughtn't be called in the course of this test.") - - - -class SMTPServerTests(unittest.TestCase): - """ - Test various behaviors of L{twisted.mail.smtp.SMTP} and - L{twisted.mail.smtp.ESMTP}. - """ - def testSMTPGreetingHost(self, serverClass=smtp.SMTP): - """ - Test that the specified hostname shows up in the SMTP server's - greeting. - """ - s = serverClass() - s.host = "example.com" - t = StringTransport() - s.makeConnection(t) - s.connectionLost(error.ConnectionDone()) - self.assertIn("example.com", t.value()) - - - def testSMTPGreetingNotExtended(self): - """ - Test that the string "ESMTP" does not appear in the SMTP server's - greeting since that string strongly suggests the presence of support - for various SMTP extensions which are not supported by L{smtp.SMTP}. - """ - s = smtp.SMTP() - t = StringTransport() - s.makeConnection(t) - s.connectionLost(error.ConnectionDone()) - self.assertNotIn("ESMTP", t.value()) - - - def testESMTPGreetingHost(self): - """ - Similar to testSMTPGreetingHost, but for the L{smtp.ESMTP} class. - """ - self.testSMTPGreetingHost(smtp.ESMTP) - - - def testESMTPGreetingExtended(self): - """ - Test that the string "ESMTP" does appear in the ESMTP server's - greeting since L{smtp.ESMTP} does support the SMTP extensions which - that advertises to the client. - """ - s = smtp.ESMTP() - t = StringTransport() - s.makeConnection(t) - s.connectionLost(error.ConnectionDone()) - self.assertIn("ESMTP", t.value()) - - - def test_acceptSenderAddress(self): - """ - Test that a C{MAIL FROM} command with an acceptable address is - responded to with the correct success code. - """ - class AcceptanceDelivery(NotImplementedDelivery): - """ - Delivery object which accepts all senders as valid. - """ - def validateFrom(self, helo, origin): - return origin - - realm = SingletonRealm(smtp.IMessageDelivery, AcceptanceDelivery()) - portal = Portal(realm, [AllowAnonymousAccess()]) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '250 Sender address accepted\r\n') - - - def test_deliveryRejectedSenderAddress(self): - """ - Test that a C{MAIL FROM} command with an address rejected by a - L{smtp.IMessageDelivery} instance is responded to with the correct - error code. - """ - class RejectionDelivery(NotImplementedDelivery): - """ - Delivery object which rejects all senders as invalid. - """ - def validateFrom(self, helo, origin): - raise smtp.SMTPBadSender(origin) - - realm = SingletonRealm(smtp.IMessageDelivery, RejectionDelivery()) - portal = Portal(realm, [AllowAnonymousAccess()]) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '550 Cannot receive from specified address ' - ': Sender not acceptable\r\n') - - - def test_portalRejectedSenderAddress(self): - """ - Test that a C{MAIL FROM} command with an address rejected by an - L{smtp.SMTP} instance's portal is responded to with the correct error - code. - """ - class DisallowAnonymousAccess(object): - """ - Checker for L{IAnonymous} which rejects authentication attempts. - """ - implements(ICredentialsChecker) - - credentialInterfaces = (IAnonymous,) - - def requestAvatarId(self, credentials): - return defer.fail(UnauthorizedLogin()) - - realm = SingletonRealm(smtp.IMessageDelivery, NotImplementedDelivery()) - portal = Portal(realm, [DisallowAnonymousAccess()]) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '550 Cannot receive from specified address ' - ': Sender not acceptable\r\n') - - - def test_portalRejectedAnonymousSender(self): - """ - Test that a C{MAIL FROM} command issued without first authenticating - when a portal has been configured to disallow anonymous logins is - responded to with the correct error code. - """ - realm = SingletonRealm(smtp.IMessageDelivery, NotImplementedDelivery()) - portal = Portal(realm, []) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '550 Cannot receive from specified address ' - ': Unauthenticated senders not allowed\r\n') - - - -class ESMTPAuthenticationTests(unittest.TestCase): - def assertServerResponse(self, bytes, response): - """ - Assert that when the given bytes are delivered to the ESMTP server - instance, it responds with the indicated lines. - - @type bytes: str - @type response: list of str - """ - self.transport.clear() - self.server.dataReceived(bytes) - self.assertEqual( - response, - self.transport.value().splitlines()) - - - def assertServerAuthenticated(self, loginArgs, username="username", password="password"): - """ - Assert that a login attempt has been made, that the credentials and - interfaces passed to it are correct, and that when the login request - is satisfied, a successful response is sent by the ESMTP server - instance. - - @param loginArgs: A C{list} previously passed to L{portalFactory}. - """ - d, credentials, mind, interfaces = loginArgs.pop() - self.assertEqual(loginArgs, []) - self.failUnless(twisted.cred.credentials.IUsernamePassword.providedBy(credentials)) - self.assertEqual(credentials.username, username) - self.failUnless(credentials.checkPassword(password)) - self.assertIn(smtp.IMessageDeliveryFactory, interfaces) - self.assertIn(smtp.IMessageDelivery, interfaces) - d.callback((smtp.IMessageDeliveryFactory, None, lambda: None)) - - self.assertEqual( - ["235 Authentication successful."], - self.transport.value().splitlines()) - - - def setUp(self): - """ - Create an ESMTP instance attached to a StringTransport. - """ - self.server = smtp.ESMTP({ - 'LOGIN': imap4.LOGINCredentials}) - self.server.host = 'localhost' - self.transport = StringTransport( - peerAddress=address.IPv4Address('TCP', '127.0.0.1', 12345)) - self.server.makeConnection(self.transport) - - - def tearDown(self): - """ - Disconnect the ESMTP instance to clean up its timeout DelayedCall. - """ - self.server.connectionLost(error.ConnectionDone()) - - - def portalFactory(self, loginList): - class DummyPortal: - def login(self, credentials, mind, *interfaces): - d = defer.Deferred() - loginList.append((d, credentials, mind, interfaces)) - return d - return DummyPortal() - - - def test_authenticationCapabilityAdvertised(self): - """ - Test that AUTH is advertised to clients which issue an EHLO command. - """ - self.transport.clear() - self.server.dataReceived('EHLO\r\n') - responseLines = self.transport.value().splitlines() - self.assertEqual( - responseLines[0], - "250-localhost Hello 127.0.0.1, nice to meet you") - self.assertEqual( - responseLines[1], - "250 AUTH LOGIN") - self.assertEqual(len(responseLines), 2) - - - def test_plainAuthentication(self): - """ - Test that the LOGIN authentication mechanism can be used - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.transport.clear() - - self.assertServerResponse( - 'AUTH LOGIN\r\n', - ["334 " + "User Name\0".encode('base64').strip()]) - - self.assertServerResponse( - 'username'.encode('base64') + '\r\n', - ["334 " + "Password\0".encode('base64').strip()]) - - self.assertServerResponse( - 'password'.encode('base64').strip() + '\r\n', - []) - - self.assertServerAuthenticated(loginArgs) - - - def test_plainAuthenticationEmptyPassword(self): - """ - Test that giving an empty password for plain auth succeeds. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.transport.clear() - - self.assertServerResponse( - 'AUTH LOGIN\r\n', - ["334 " + "User Name\0".encode('base64').strip()]) - - self.assertServerResponse( - 'username'.encode('base64') + '\r\n', - ["334 " + "Password\0".encode('base64').strip()]) - - self.assertServerResponse('\r\n', []) - self.assertServerAuthenticated(loginArgs, password='') - - - def test_plainAuthenticationInitialResponse(self): - """ - The response to the first challenge may be included on the AUTH command - line. Test that this is also supported. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.transport.clear() - - self.assertServerResponse( - 'AUTH LOGIN ' + "username".encode('base64').strip() + '\r\n', - ["334 " + "Password\0".encode('base64').strip()]) - - self.assertServerResponse( - 'password'.encode('base64').strip() + '\r\n', - []) - - self.assertServerAuthenticated(loginArgs) - - - def test_abortAuthentication(self): - """ - Test that a challenge/response sequence can be aborted by the client. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.server.dataReceived('AUTH LOGIN\r\n') - - self.assertServerResponse( - '*\r\n', - ['501 Authentication aborted']) - - - def test_invalidBase64EncodedResponse(self): - """ - Test that a response which is not properly Base64 encoded results in - the appropriate error code. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.server.dataReceived('AUTH LOGIN\r\n') - - self.assertServerResponse( - 'x\r\n', - ['501 Syntax error in parameters or arguments']) - - self.assertEqual(loginArgs, []) - - - def test_invalidBase64EncodedInitialResponse(self): - """ - Like L{test_invalidBase64EncodedResponse} but for the case of an - initial response included with the C{AUTH} command. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.assertServerResponse( - 'AUTH LOGIN x\r\n', - ['501 Syntax error in parameters or arguments']) - - self.assertEqual(loginArgs, []) - - - def test_unexpectedLoginFailure(self): - """ - If the L{Deferred} returned by L{Portal.login} fires with an - exception of any type other than L{UnauthorizedLogin}, the exception - is logged and the client is informed that the authentication attempt - has failed. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.transport.clear() - - self.assertServerResponse( - 'AUTH LOGIN ' + 'username'.encode('base64').strip() + '\r\n', - ['334 ' + 'Password\0'.encode('base64').strip()]) - self.assertServerResponse( - 'password'.encode('base64').strip() + '\r\n', - []) - - d, credentials, mind, interfaces = loginArgs.pop() - d.errback(RuntimeError("Something wrong with the server")) - - self.assertEqual( - '451 Requested action aborted: local error in processing\r\n', - self.transport.value()) - - self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1) - - - -class SMTPClientErrorTests(unittest.TestCase): - """ - Tests for L{smtp.SMTPClientError}. - """ - def test_str(self): - """ - The string representation of a L{SMTPClientError} instance includes - the response code and response string. - """ - err = smtp.SMTPClientError(123, "some text") - self.assertEqual(str(err), "123 some text") - - - def test_strWithNegativeCode(self): - """ - If the response code supplied to L{SMTPClientError} is negative, it - is excluded from the string representation. - """ - err = smtp.SMTPClientError(-1, "foo bar") - self.assertEqual(str(err), "foo bar") - - - def test_strWithLog(self): - """ - If a line log is supplied to L{SMTPClientError}, its contents are - included in the string representation of the exception instance. - """ - log = LineLog(10) - log.append("testlog") - log.append("secondline") - err = smtp.SMTPClientError(100, "test error", log=log.str()) - self.assertEqual( - str(err), - "100 test error\n" - "testlog\n" - "secondline\n") - - - -class SenderMixinSentMailTests(unittest.TestCase): - """ - Tests for L{smtp.SenderMixin.sentMail}, used in particular by - L{smtp.SMTPSenderFactory} and L{smtp.ESMTPSenderFactory}. - """ - def test_onlyLogFailedAddresses(self): - """ - L{smtp.SenderMixin.sentMail} adds only the addresses with failing - SMTP response codes to the log passed to the factory's errback. - """ - onDone = self.assertFailure(defer.Deferred(), smtp.SMTPDeliveryError) - onDone.addCallback(lambda e: self.assertEqual( - e.log, "bob@example.com: 199 Error in sending.\n")) - - clientFactory = smtp.SMTPSenderFactory( - 'source@address', 'recipient@address', - StringIO("Message body"), onDone, - retries=0, timeout=0.5) - - client = clientFactory.buildProtocol( - address.IPv4Address('TCP', 'example.net', 25)) - - addresses = [("alice@example.com", 200, "No errors here!"), - ("bob@example.com", 199, "Error in sending.")] - client.sentMail(199, "Test response", 1, addresses, client.log) - - return onDone - - - -class ESMTPDowngradeTestCase(unittest.TestCase): - """ - Tests for the ESMTP -> SMTP downgrade functionality in L{smtp.ESMTPClient}. - """ - def setUp(self): - self.clientProtocol = smtp.ESMTPClient( - b"testpassword", None, b"testuser") - - def test_requireHELOFallbackOperates(self): - """ - If both authentication and transport security are not required, and it - is asked for, it will fall back to allowing HELO. - """ - transport = StringTransport() - self.clientProtocol.requireAuthentication = False - self.clientProtocol.requireTransportSecurity = False - self.clientProtocol.heloFallback = True - self.clientProtocol.makeConnection(transport) - - self.clientProtocol.dataReceived(b"220 localhost\r\n") - transport.clear() - self.clientProtocol.dataReceived(b"500 not an esmtp server\r\n") - self.assertEqual(b"HELO testuser\r\n", transport.value()) - - - def test_requireAuthFailsHELOFallback(self): - """ - If authentication is required, and HELO fallback is on, HELO fallback - must not be honoured, as authentication requires EHLO to succeed. - """ - transport = StringTransport() - self.clientProtocol.requireAuthentication = True - self.clientProtocol.requireTransportSecurity = False - self.clientProtocol.heloFallback = True - self.clientProtocol.makeConnection(transport) - - self.clientProtocol.dataReceived(b"220 localhost\r\n") - transport.clear() - self.clientProtocol.dataReceived(b"500 not an esmtp server\r\n") - self.assertEqual("QUIT\r\n", transport.value()) - - - def test_requireTLSFailsHELOFallback(self): - """ - If TLS is required and the connection is insecure, HELO fallback must - not be honoured, as STARTTLS requires EHLO to succeed. - """ - transport = StringTransport() - self.clientProtocol.requireAuthentication = False - self.clientProtocol.requireTransportSecurity = True - self.clientProtocol.heloFallback = True - self.clientProtocol.makeConnection(transport) - - self.clientProtocol.dataReceived(b"220 localhost\r\n") - transport.clear() - self.clientProtocol.dataReceived(b"500 not an esmtp server\r\n") - self.assertEqual(b"QUIT\r\n", transport.value()) - - - def test_requireTLSAndHELOFallbackSucceedsIfOverTLS(self): - """ - If TLS is provided at the transport level, we can honour the HELO - fallback if we're set to require TLS. - """ - transport = StringTransport() - directlyProvides(transport, interfaces.ISSLTransport) - self.clientProtocol.requireAuthentication = False - self.clientProtocol.requireTransportSecurity = True - self.clientProtocol.heloFallback = True - self.clientProtocol.makeConnection(transport) - - self.clientProtocol.dataReceived(b"220 localhost\r\n") - transport.clear() - self.clientProtocol.dataReceived(b"500 not an esmtp server\r\n") - self.assertEqual(b"HELO testuser\r\n", transport.value()) - - - -class SSLTestCase(unittest.TestCase): - """ - Tests for the TLS negotiation done by L{smtp.ESMTPClient}. - """ - if sslSkip is not None: - skip = sslSkip - - SERVER_GREETING = "220 localhost NO UCE NO UBE NO RELAY PROBES ESMTP\r\n" - EHLO_RESPONSE = "250-localhost Hello 127.0.0.1, nice to meet you\r\n" - - def setUp(self): - self.clientProtocol = smtp.ESMTPClient( - "testpassword", ClientTLSContext(), "testuser") - self.clientProtocol.requireTransportSecurity = True - self.clientProtocol.getMailFrom = lambda: "test@example.org" - - - def _requireTransportSecurityOverSSLTest(self, capabilities): - """ - Verify that when L{smtp.ESMTPClient} connects to a server over a - transport providing L{ISSLTransport}, C{requireTransportSecurity} is - C{True}, and it is presented with the given capabilities, it will try - to send its mail and not first attempt to negotiate TLS using the - I{STARTTLS} protocol action. - - @param capabilities: Bytes to include in the test server's capability - response. These must be formatted exactly as required by the - protocol, including a line which ends the capability response. - @type param: L{bytes} - - @raise: C{self.failureException} if the behavior of - C{self.clientProtocol} is not as described. - """ - transport = StringTransport() - directlyProvides(transport, interfaces.ISSLTransport) - self.clientProtocol.makeConnection(transport) - - # Get the handshake out of the way - self.clientProtocol.dataReceived(self.SERVER_GREETING) - transport.clear() - - # Tell the client about the server's capabilities - self.clientProtocol.dataReceived(self.EHLO_RESPONSE + capabilities) - - # The client should now try to send a message - without first trying to - # negotiate TLS, since the transport is already secure. - self.assertEqual( - b"MAIL FROM:\r\n", - transport.value()) - - - def test_requireTransportSecurityOverSSL(self): - """ - When C{requireTransportSecurity} is C{True} and the client is connected - over an SSL transport, mail may be delivered. - """ - self._requireTransportSecurityOverSSLTest(b"250 AUTH LOGIN\r\n") - - - def test_requireTransportSecurityTLSOffered(self): - """ - When C{requireTransportSecurity} is C{True} and the client is connected - over a non-SSL transport, if the server offers the I{STARTTLS} - extension, it is used before mail is delivered. - """ - transport = StringTransport() - self.clientProtocol.makeConnection(transport) - - # Get the handshake out of the way - self.clientProtocol.dataReceived(self.SERVER_GREETING) - transport.clear() - - # Tell the client about the server's capabilities - including STARTTLS - self.clientProtocol.dataReceived( - self.EHLO_RESPONSE + - "250-AUTH LOGIN\r\n" - "250 STARTTLS\r\n") - - # The client should try to start TLS before sending the message. - self.assertEqual("STARTTLS\r\n", transport.value()) - - - def test_requireTransportSecurityTLSOfferedOverSSL(self): - """ - When C{requireTransportSecurity} is C{True} and the client is connected - over an SSL transport, if the server offers the I{STARTTLS} - extension, it is not used before mail is delivered. - """ - self._requireTransportSecurityOverSSLTest( - b"250-AUTH LOGIN\r\n" - b"250 STARTTLS\r\n") - - - def test_requireTransportSecurityTLSNotOffered(self): - """ - When C{requireTransportSecurity} is C{True} and the client is connected - over a non-SSL transport, if the server does not offer the I{STARTTLS} - extension, mail is not delivered. - """ - transport = StringTransport() - self.clientProtocol.makeConnection(transport) - - # Get the handshake out of the way - self.clientProtocol.dataReceived(self.SERVER_GREETING) - transport.clear() - - # Tell the client about the server's capabilities - excluding STARTTLS - self.clientProtocol.dataReceived( - self.EHLO_RESPONSE + - "250 AUTH LOGIN\r\n") - - # The client give up - self.assertEqual("QUIT\r\n", transport.value()) - - - def test_esmtpClientTlsModeDeprecationGet(self): - """ - L{smtp.ESMTPClient.tlsMode} is deprecated. - """ - val = self.clientProtocol.tlsMode - del val - warningsShown = self.flushWarnings( - offendingFunctions=[self.test_esmtpClientTlsModeDeprecationGet]) - self.assertEqual(len(warningsShown), 1) - self.assertIdentical( - warningsShown[0]['category'], DeprecationWarning) - self.assertEqual( - warningsShown[0]['message'], - "tlsMode attribute of twisted.mail.smtp.ESMTPClient " - "is deprecated since Twisted 13.0") - - - def test_esmtpClientTlsModeDeprecationGetAttributeError(self): - """ - L{smtp.ESMTPClient.__getattr__} raises an attribute error for other - attribute names which do not exist. - """ - self.assertRaises( - AttributeError, lambda: self.clientProtocol.doesNotExist) - - - def test_esmtpClientTlsModeDeprecationSet(self): - """ - L{smtp.ESMTPClient.tlsMode} is deprecated. - """ - self.clientProtocol.tlsMode = False - warningsShown = self.flushWarnings( - offendingFunctions=[self.test_esmtpClientTlsModeDeprecationSet]) - self.assertEqual(len(warningsShown), 1) - self.assertIdentical( - warningsShown[0]['category'], DeprecationWarning) - self.assertEqual( - warningsShown[0]['message'], - "tlsMode attribute of twisted.mail.smtp.ESMTPClient " - "is deprecated since Twisted 13.0") - - - -class AbortableStringTransport(StringTransport): - """ - A version of L{StringTransport} that supports C{abortConnection}. - """ - # This should be replaced by a common version in #6530. - aborting = False - - - def abortConnection(self): - """ - A testable version of the C{ITCPTransport.abortConnection} method. - - Since this is a special case of closing the connection, - C{loseConnection} is also called. - """ - self.aborting = True - self.loseConnection() - - - -class SendmailTests(unittest.TestCase): - """ - Tests for L{twisted.mail.smtp.sendmail}. - """ - def test_defaultReactorIsGlobalReactor(self): - """ - The default C{reactor} parameter of L{twisted.mail.smtp.sendmail} is - L{twisted.internet.reactor}. - """ - args, varArgs, keywords, defaults = inspect.getargspec(smtp.sendmail) - self.assertEqual(reactor, defaults[2]) - - - def test_honorsESMTPArguments(self): - """ - L{twisted.mail.smtp.sendmail} creates the ESMTP factory with the ESMTP - arguments. - """ - reactor = MemoryReactor() - smtp.sendmail("localhost", "source@address", "recipient@address", - "message", reactor=reactor, username="foo", - password="bar", requireTransportSecurity=True, - requireAuthentication=True) - factory = reactor.tcpClients[0][2] - self.assertEqual(factory._requireTransportSecurity, True) - self.assertEqual(factory._requireAuthentication, True) - self.assertEqual(factory.username, "foo") - self.assertEqual(factory.password, "bar") - - - def test_messageFilePassthrough(self): - """ - L{twisted.mail.smtp.sendmail} will pass through the message untouched - if it is a file-like object. - """ - reactor = MemoryReactor() - messageFile = StringIO(b"File!") - - smtp.sendmail("localhost", "source@address", "recipient@address", - messageFile, reactor=reactor) - factory = reactor.tcpClients[0][2] - self.assertIs(factory.file, messageFile) - - - def test_messageStringMadeFile(self): - """ - L{twisted.mail.smtp.sendmail} will turn non-file-like objects - (eg. strings) into file-like objects before sending. - """ - reactor = MemoryReactor() - smtp.sendmail("localhost", "source@address", "recipient@address", - "message", reactor=reactor) - factory = reactor.tcpClients[0][2] - messageFile = factory.file - messageFile.seek(0) - self.assertEqual(messageFile.read(), "message") - - - def test_senderDomainName(self): - """ - L{twisted.mail.smtp.sendmail} passes through the sender domain name, if - provided. - """ - reactor = MemoryReactor() - smtp.sendmail("localhost", "source@address", "recipient@address", - "message", reactor=reactor, senderDomainName="foo") - factory = reactor.tcpClients[0][2] - self.assertEqual(factory.domain, "foo") - - - def test_cancelBeforeConnectionMade(self): - """ - When a user cancels L{twisted.mail.smtp.sendmail} before the connection - is made, the connection is closed by - L{twisted.internet.interfaces.IConnector.disconnect}. - """ - reactor = MemoryReactor() - d = smtp.sendmail("localhost", "source@address", "recipient@address", - "message", reactor=reactor) - d.cancel() - self.assertEqual(reactor.connectors[0]._disconnected, True) - failure = self.failureResultOf(d) - failure.trap(defer.CancelledError) - - - def test_cancelAfterConnectionMade(self): - """ - When a user cancels L{twisted.mail.smtp.sendmail} after the connection - is made, the connection is closed by - L{twisted.internet.interfaces.ITransport.abortConnection}. - """ - reactor = MemoryReactor() - transport = AbortableStringTransport() - d = smtp.sendmail("localhost", "source@address", "recipient@address", - "message", reactor=reactor) - factory = reactor.tcpClients[0][2] - p = factory.buildProtocol(None) - p.makeConnection(transport) - d.cancel() - self.assertEqual(transport.aborting, True) - self.assertEqual(transport.disconnecting, True) - failure = self.failureResultOf(d) - failure.trap(defer.CancelledError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/NEWS deleted file mode 100644 index 5bfb9aa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/NEWS +++ /dev/null @@ -1,462 +0,0 @@ -Ticket numbers in this file can be looked up by visiting -http://twistedmatrix.com/trac/ticket/ - -Twisted Mail 15.2.1 (2015-05-23) -================================ - -No significant changes have been made for this release. - - -Twisted Mail 15.2.0 (2015-05-18) -================================ - -Features --------- - - twisted.mail.smtp.sendmail now uses ESMTP. It will - opportunistically enable encryption and allow the use of - authentication. (#7257) - - -Twisted Mail 15.1.0 (2015-04-02) -================================ - -Bugfixes --------- - - twisted.mail.smtp.ESMTPClient now does not fall back to plain SMTP - if authentication or TLS is required and not able to occur. (#7258) - -Other ------ - - #6705 - - -Twisted Mail 15.0.0 (2015-01-24) -================================ - -No significant changes have been made for this release. - -Other ------ - - #6999, #7708 - - -Twisted Mail 14.0.2 (2014-09-18) -================================ - -No significant changes have been made for this release. - - -Twisted Mail 14.0.1 (2014-09-17) -================================ - -No significant changes have been made for this release. - - -Twisted Mail 14.0.0 (2014-05-08) -================================ - -Improved Documentation ----------------------- - - twisted.mail.alias now has full API documentation. (#6637) - - twisted.mail.tap now has full API documentation. (#6648) - - twisted.mail.maildir now has full API documentation. (#6651) - - twisted.mail.pop3client now has full API documentation. (#6653) - - twisted.mail.protocols now has full API documentation. (#6654) - - twisted.mail.pop now has full API documentation. (#6666) - - twisted.mail.relay and twisted.mail.relaymanager now have full API - documentation. (#6739) - - twisted.mail.pop3client public classes now appear as part of the - twisted.mail.pop3 API. (#6761) - -Other ------ - - #6696 - - -Twisted Mail 13.2.0 (2013-10-29) -================================ - -Features --------- - - twisted.mail.smtp.sendmail now returns a cancellable Deferred. - (#6572) - -Improved Documentation ----------------------- - - twisted.mail.mail now has full API documentation. (#6649) - - twisted.mail.bounce now has full API documentation. (#6652) - -Other ------ - - #5387, #6486 - - -Twisted Mail 13.1.0 (2013-06-23) -================================ - -Bugfixes --------- - - twisted.mail.smtp.ESMTPClient no longer tries to use a STARTTLS - capability offered by a server after TLS has already been - negotiated. (#6524) - -Deprecations and Removals -------------------------- - - twisted.mail.IDomain.startMessage, deprecated since 2003, is - removed now. (#4151) - -Other ------ - - #6342 - - -Twisted Mail 13.0.0 (2013-03-19) -================================ - -Bugfixes --------- - - twisted.mail.smtp.ESMTPClient no longer attempts to negotiate a TLS - session if transport security has been requested and the protocol - is already running on a TLS connection. (#3989) - - twisted.mail.imap4.Query now filters illegal characters from the - values of KEYWORD and UNKEYWORD and also emits them without adding - quotes (which are also illegal). (#4392) - - twisted.mail.imap4.IMAP4Client can now interpret the BODY response - for multipart/* messages with parts which are also multipart/*. - (#4631) - -Deprecations and Removals -------------------------- - - tlsMode attribute of twisted.mail.smtp.ESMTPClient is deprecated. - (#5852) - -Other ------ - - #6218, #6297 - - -Twisted Mail 12.3.0 (2012-12-20) -================================ - -Bugfixes --------- - - twisted.mail.imap4._FetchParser now raises - IllegalClientResponse("Invalid Argument") when protocol encounters - extra bytes at the end of a valid FETCH command. (#4000) - -Improved Documentation ----------------------- - - twisted.mail.tap now documents example usage in its longdesc - output for the 'mail' plugin (#5922) - -Other ------ - - #3751 - - -Twisted Mail 12.2.0 (2012-08-26) -================================ - -Bugfixes --------- - - twisted.mail.imap4.IMAP4Server will now generate an error response - when it receives an illegal SEARCH term from a client. (#4080) - - twisted.mail.imap4 now serves BODYSTRUCTURE responses which provide - more information and conform to the IMAP4 RFC more closely. (#5763) - -Deprecations and Removals -------------------------- - - twisted.mail.protocols.SSLContextFactory is now deprecated. (#4963) - - The --passwordfile option to twistd mail is now removed. (#5541) - -Other ------ - - #5697, #5750, #5751, #5783 - - -Twisted Mail 12.1.0 (2012-06-02) -================================ - -Bugfixes --------- - - twistd mail --auth, broken in 11.0, now correctly connects - authentication to the portal being used (#5219) - -Other ------ - - #5686 - - -Twisted Mail 12.0.0 (2012-02-10) -================================ - -No significant changes have been made for this release. - - -Twisted Mail 11.1.0 (2011-11-15) -================================ - -Features --------- - - twisted.mail.smtp.LOGINCredentials now generates challenges with - ":" instead of "\0" for interoperability with Microsoft Outlook. - (#4692) - -Bugfixes --------- - - When run from an unpacked source tarball or a VCS checkout, - bin/mail/mailmail will now use the version of Twisted it is part - of. (#3526) - -Other ------ - - #4796, #5006 - - -Twisted Mail 11.0.0 (2011-04-01) -================================ - -Features --------- - - The `twistd mail` command line now accepts endpoint descriptions - for POP3 and SMTP servers. (#4739) - - The twistd mail plugin now accepts new authentication options via - strcred.AuthOptionMixin. These include --auth, --auth-help, and - authentication type-specific help options. (#4740) - -Bugfixes --------- - - twisted.mail.imap4.IMAP4Server now generates INTERNALDATE strings - which do not consider the locale. (#4937) - -Improved Documentation ----------------------- - - Added a simple SMTP example, showing how to use sendmail. (#4042) - -Other ------ - - - #4162 - - -Twisted Mail 10.2.0 (2010-11-29) -================================ - -Improved Documentation ----------------------- - - The email server example now demonstrates how to set up - authentication and authorization using twisted.cred. (#4609) - -Deprecations and Removals -------------------------- - - twisted.mail.smtp.sendEmail, deprecated since mid 2003 (before - Twisted 2.0), has been removed. (#4529) - -Other ------ - - #4038, #4572 - - -Twisted Mail 10.1.0 (2010-06-27) -================================ - -Bugfixes --------- - - twisted.mail.imap4.IMAP4Server no longer fails on search queries - that contain wildcards. (#2278) - - A case which would cause twisted.mail.imap4.IMAP4Server to loop - indefinitely when handling a search command has been fixed. (#4385) - -Other ------ - - #4069, #4271, #4467 - - -Twisted Mail 10.0.0 (2010-03-01) -================================ - -Bugfixes --------- - - twisted.mail.smtp.ESMTPClient and - twisted.mail.smtp.LOGINAuthenticator now implement the (obsolete) - LOGIN SASL mechanism according to the draft specification. (#4031) - - - twisted.mail.imap4.IMAP4Client will no longer misparse all html- - formatted message bodies received in response to a fetch command. - (#4049) - - - The regression in IMAP4 search handling of "OR" and "NOT" terms has - been fixed. (#4178) - -Other ------ - - #4028, #4170, #4200 - - -Twisted Mail 9.0.0 (2009-11-24) -=============================== - -Features --------- - - maildir.StringListMailbox, an in-memory maildir mailbox, now supports - deletion, undeletion, and syncing (#3547) - - SMTPClient's callbacks are now more completely documented (#684) - -Fixes ------ - - Parse UNSEEN response data and include it in the result of - IMAP4Client.examine (#3550) - - The IMAP4 client now delivers more unsolicited server responses to callbacks - rather than ignoring them, and also won't ignore solicited responses that - arrive on the same line as an unsolicited one (#1105) - - Several bugs in the SMTP client's idle timeout support were fixed (#3641, - #1219) - - A case where the SMTP client could skip some recipients when retrying - delivery has been fixed (#3638) - - Errors during certain data transfers will no longer be swallowed. They will - now bubble up to the higher-level API (such as the sendmail function) (#3642) - - Escape sequences inside quoted strings in IMAP4 should now be parsed - correctly by the IMAP4 server protocol (#3659) - - The "imap4-utf-7" codec that is registered by twisted.mail.imap4 had a number - of fixes that allow it to work better with the Python codecs system, and to - actually work (#3663) - - The Maildir implementation now ensures time-based ordering of filenames so - that the lexical sorting of messages matches the order in which they were - received (#3812) - - SASL PLAIN credentials generated by the IMAP4 protocol implementations - (client and server) should now be RFC-compliant (#3939) - - Searching for a set of sequences using the IMAP4 "SEARCH" command should - now work on the IMAP4 server protocol implementation. This at least improves - support for the Pine mail client (#1977) - -Other ------ - - #2763, #3647, #3750, #3819, #3540, #3846, #2023, #4050 - - -Mail 8.2.0 (2008-12-16) -======================= - -Fixes ------ - - The mailmail tool now provides better error messages for usage errors (#3339) - - The SMTP protocol implementation now works on PyPy (#2976) - -Other ------ - - #3475 - - -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Support CAPABILITY responses that include atoms of the form "FOO" and - "FOO=BAR" in IMAP4 (#2695) - - Parameterize error handling behavior of imap4.encoder and imap4.decoder. - (#2929) - -Fixes ------ - - Handle empty passwords in SMTP auth. (#2521) - - Fix IMAP4Client's parsing of literals which are not preceeded by whitespace. - (#2700) - - Handle MX lookup suceeding without answers. (#2807) - - Fix issues with aliases(5) process support. (#2729) - -Misc ----- - - #2371, #2123, #2378, #739, #2640, #2746, #1917, #2266, #2864, #2832, #2063, - #2865, #2847 - - -0.4.0 (2007-01-06) -================== - -Features --------- - - Plaintext POP3 logins are now possible over SSL or TLS (#1809) - -Fixes ------ - - ESMTP servers now greet with an "ESMTP" string (#1891) - - The POP3 client can now correctly deal with concurrent POP3 - retrievals (#1988, #1691) - - In the IMAP4 server, a bug involving retrieving the first part - of a single-part message was fixed. This improves compatibility - with Pine (#1978) - - A bug in the IMAP4 server which caused corruption under heavy - pipelining was fixed (#1992) - - More strict support for the AUTH command was added to the SMTP - server, to support the AUTH - form of the command (#1552) - - An SMTP bug involving the interaction with validateFrom, which - caused multiple conflicting SMTP messages to be sent over the wire, - was fixed (#2158) - -Misc ----- - - #1648, #1801, #1636, #2003, #1936, #1202, #2051, #2072, #2248, #2250 - -0.3.0 (2006-05-21) -================== - -Features --------- - - Support Deferred results from POP3's IMailbox.listMessages (#1701). - -Fixes ------ - - Quote usernames and passwords automatically in the IMAP client (#1411). - - Improved parsing of literals in IMAP4 client and server (#1417). - - Recognize unsolicted FLAGS response in IMAP4 client (#1105). - - Parse and respond to requests with multiple BODY arguments in IMAP4 - server (#1307). - - Misc: #1356, #1290, #1602 - -0.2.0: - - SMTP server: - - Now gives application-level code opportunity to set a different - Received header for each recipient of a multi-recipient message. - - IMAP client: - - New `startTLS' method to allow explicit negotiation of transport - security. -- POP client: - - Support for per-command timeouts - - New `startTLS' method, similar to the one added to the IMAP - client. - - NOOP, RSET, and STAT support added -- POP server: - - Bug handling passwords of "" fixed - - -0.1.0: - - Tons of bugfixes in IMAP4, POP3, and SMTP protocols - - Maildir append support - - Brand new, improved POP3 client (twisted.mail.pop3.AdvancedPOP3Client) - - Deprecated the old POP3 client (twisted.mail.pop3.POP3Client) - - SMTP client: - - Support SMTP AUTH - - Allow user to supply SSL context - - Improved error handling, via new exception classes and an overridable - hook to customize handling. - - Order to try the authenication schemes is user-definable. - - Timeout support. - - SMTP server: - - Properly understand <> sender. - - Parameterize remote port - - IMAP4: - - LOGIN authentication compatibility improved - - Improved unicode mailbox support - - Fix parsing/handling of "FETCH BODY[HEADER]" - - Many many quoting fixes - - Timeout support on client diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/README deleted file mode 100644 index 90590e1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/README +++ /dev/null @@ -1,6 +0,0 @@ -Twisted Mail 15.2.1 - -Twisted Mail depends on Twisted Core and (sometimes) Twisted Names. For TLS -support, pyOpenSSL () is also required. Aside -from protocol implementations, much of Twisted Mail also only runs on POSIX -platforms. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/setup.py deleted file mode 100644 index 6e1b89e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/mail/topfiles/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - extraMeta = dict( - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Communications :: Email :: Post-Office :: IMAP", - "Topic :: Communications :: Email :: Post-Office :: POP3", - "Topic :: Software Development :: Libraries :: Python Modules", - ]) - - dist.setup( - twisted_subproject="mail", - scripts=dist.getScripts("mail"), - # metadata - name="Twisted Mail", - description="A Twisted Mail library, server and client.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - url="http://twistedmatrix.com/trac/wiki/TwistedMail", - license="MIT", - long_description="""\ -An SMTP, IMAP and POP protocol implementation together with clients -and servers. - -Twisted Mail contains high-level, efficient protocol implementations -for both clients and servers of SMTP, POP3, and IMAP4. Additionally, -it contains an "out of the box" combination SMTP/POP3 virtual-hosting -mail server. Also included is a read/write Maildir implementation and -a basic Mail Exchange calculator. -""", - **extraMeta) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/__init__.py deleted file mode 100644 index c3e8dba..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Manhole: interactive interpreter and direct manipulation support for -Twisted. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/_inspectro.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/_inspectro.py deleted file mode 100644 index fc9a305..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/_inspectro.py +++ /dev/null @@ -1,369 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""An input/output window for the glade reactor inspector. -""" - -import time -import gtk -import gobject -import gtk.glade -from twisted.python.util import sibpath -from twisted.python import reflect - -from twisted.manhole.ui import gtk2manhole -from twisted.python.components import Adapter, registerAdapter -from twisted.python import log -from twisted.protocols import policies -from zope.interface import implements, Interface - -# the glade file uses stock icons, which requires gnome to be installed -import gnome -version = "$Revision: 1.1 $"[11:-2] -gnome.init("gladereactor Inspector", version) - -class ConsoleOutput(gtk2manhole.ConsoleOutput): - def _captureLocalLog(self): - self.fobs = log.FileLogObserver(gtk2manhole._Notafile(self, "log")) - self.fobs.start() - - def stop(self): - self.fobs.stop() - del self.fobs - -class ConsoleInput(gtk2manhole.ConsoleInput): - def sendMessage(self): - buffer = self.textView.get_buffer() - iter1, iter2 = buffer.get_bounds() - text = buffer.get_text(iter1, iter2, False) - self.do(text) - - def do(self, text): - self.toplevel.do(text) - -class INode(Interface): - """A node in the inspector tree model. - """ - - def __adapt__(adaptable, default): - if hasattr(adaptable, "__dict__"): - return InstanceNode(adaptable) - return AttributesNode(adaptable) - -class InspectorNode(Adapter): - implements(INode) - - def postInit(self, offset, parent, slot): - self.offset = offset - self.parent = parent - self.slot = slot - - def getPath(self): - L = [] - x = self - while x.parent is not None: - L.append(x.offset) - x = x.parent - L.reverse() - return L - - def __getitem__(self, index): - slot, o = self.get(index) - n = INode(o, persist=False) - n.postInit(index, self, slot) - return n - - def origstr(self): - return str(self.original) - - def format(self): - return (self.slot, self.origstr()) - - -class ConstantNode(InspectorNode): - def __len__(self): - return 0 - -class DictionaryNode(InspectorNode): - def get(self, index): - L = self.original.items() - L.sort() - return L[index] - - def __len__(self): - return len(self.original) - - def origstr(self): - return "Dictionary" - -class ListNode(InspectorNode): - def get(self, index): - return index, self.original[index] - - def origstr(self): - return "List" - - def __len__(self): - return len(self.original) - -class AttributesNode(InspectorNode): - def __len__(self): - return len(dir(self.original)) - - def get(self, index): - L = dir(self.original) - L.sort() - return L[index], getattr(self.original, L[index]) - -class InstanceNode(InspectorNode): - def __len__(self): - return len(self.original.__dict__) + 1 - - def get(self, index): - if index == 0: - if hasattr(self.original, "__class__"): - v = self.original.__class__ - else: - v = type(self.original) - return "__class__", v - else: - index -= 1 - L = self.original.__dict__.items() - L.sort() - return L[index] - -import types - -for x in dict, types.DictProxyType: - registerAdapter(DictionaryNode, x, INode) -for x in list, tuple: - registerAdapter(ListNode, x, INode) -for x in int, str: - registerAdapter(ConstantNode, x, INode) - - -class InspectorTreeModel(gtk.GenericTreeModel): - def __init__(self, root): - gtk.GenericTreeModel.__init__(self) - self.root = INode(root, persist=False) - self.root.postInit(0, None, 'root') - - def on_get_flags(self): - return 0 - - def on_get_n_columns(self): - return 1 - - def on_get_column_type(self, index): - return gobject.TYPE_STRING - - def on_get_path(self, node): - return node.getPath() - - def on_get_iter(self, path): - x = self.root - for elem in path: - x = x[elem] - return x - - def on_get_value(self, node, column): - return node.format()[column] - - def on_iter_next(self, node): - try: - return node.parent[node.offset + 1] - except IndexError: - return None - - def on_iter_children(self, node): - return node[0] - - def on_iter_has_child(self, node): - return len(node) - - def on_iter_n_children(self, node): - return len(node) - - def on_iter_nth_child(self, node, n): - if node is None: - return None - return node[n] - - def on_iter_parent(self, node): - return node.parent - - -class Inspectro: - selected = None - def __init__(self, o=None): - self.xml = x = gtk.glade.XML(sibpath(__file__, "inspectro.glade")) - self.tree_view = x.get_widget("treeview") - colnames = ["Name", "Value"] - for i in range(len(colnames)): - self.tree_view.append_column( - gtk.TreeViewColumn( - colnames[i], gtk.CellRendererText(), text=i)) - d = {} - for m in reflect.prefixedMethods(self, "on_"): - d[m.im_func.__name__] = m - self.xml.signal_autoconnect(d) - if o is not None: - self.inspect(o) - self.ns = {'inspect': self.inspect} - iwidget = x.get_widget('input') - self.input = ConsoleInput(iwidget) - self.input.toplevel = self - iwidget.connect("key_press_event", self.input._on_key_press_event) - self.output = ConsoleOutput(x.get_widget('output')) - - def select(self, o): - self.selected = o - self.ns['it'] = o - self.xml.get_widget("itname").set_text(repr(o)) - self.xml.get_widget("itpath").set_text("???") - - def inspect(self, o): - self.model = InspectorTreeModel(o) - self.tree_view.set_model(self.model) - self.inspected = o - - def do(self, command): - filename = '' - try: - print repr(command) - try: - code = compile(command, filename, 'eval') - except: - code = compile(command, filename, 'single') - val = eval(code, self.ns, self.ns) - if val is not None: - print repr(val) - self.ns['_'] = val - except: - log.err() - - def on_inspect(self, *a): - self.inspect(self.selected) - - def on_inspect_new(self, *a): - Inspectro(self.selected) - - def on_row_activated(self, tv, path, column): - self.select(self.model.on_get_iter(path).original) - - -class LoggingProtocol(policies.ProtocolWrapper): - """Log network traffic.""" - - logging = True - logViewer = None - - def __init__(self, *args): - policies.ProtocolWrapper.__init__(self, *args) - self.inLog = [] - self.outLog = [] - - def write(self, data): - if self.logging: - self.outLog.append((time.time(), data)) - if self.logViewer: - self.logViewer.updateOut(self.outLog[-1]) - policies.ProtocolWrapper.write(self, data) - - def dataReceived(self, data): - if self.logging: - self.inLog.append((time.time(), data)) - if self.logViewer: - self.logViewer.updateIn(self.inLog[-1]) - policies.ProtocolWrapper.dataReceived(self, data) - - def __repr__(self): - r = "wrapped " + repr(self.wrappedProtocol) - if self.logging: - r += " (logging)" - return r - - -class LoggingFactory(policies.WrappingFactory): - """Wrap protocols with logging wrappers.""" - - protocol = LoggingProtocol - logging = True - - def buildProtocol(self, addr): - p = self.protocol(self, self.wrappedFactory.buildProtocol(addr)) - p.logging = self.logging - return p - - def __repr__(self): - r = "wrapped " + repr(self.wrappedFactory) - if self.logging: - r += " (logging)" - return r - - -class LogViewer: - """Display log of network traffic.""" - - def __init__(self, p): - self.p = p - vals = [time.time()] - if p.inLog: - vals.append(p.inLog[0][0]) - if p.outLog: - vals.append(p.outLog[0][0]) - self.startTime = min(vals) - p.logViewer = self - self.xml = gtk.glade.XML(sibpath(__file__, "logview.glade")) - self.xml.signal_autoconnect(self) - self.loglist = self.xml.get_widget("loglist") - # setup model, connect it to my treeview - self.model = gtk.ListStore(str, str, str) - self.loglist.set_model(self.model) - self.loglist.set_reorderable(1) - self.loglist.set_headers_clickable(1) - # self.servers.set_headers_draggable(1) - # add a column - for col in [ - gtk.TreeViewColumn('Time', - gtk.CellRendererText(), - text=0), - gtk.TreeViewColumn('D', - gtk.CellRendererText(), - text=1), - gtk.TreeViewColumn('Data', - gtk.CellRendererText(), - text=2)]: - self.loglist.append_column(col) - col.set_resizable(1) - r = [] - for t, data in p.inLog: - r.append(((str(t - self.startTime), "R", repr(data)[1:-1]))) - for t, data in p.outLog: - r.append(((str(t - self.startTime), "S", repr(data)[1:-1]))) - r.sort() - for i in r: - self.model.append(i) - - def updateIn(self, (time, data)): - self.model.append((str(time - self.startTime), "R", repr(data)[1:-1])) - - def updateOut(self, (time, data)): - self.model.append((str(time - self.startTime), "S", repr(data)[1:-1])) - - def on_logview_destroy(self, w): - self.p.logViewer = None - del self.p - - -def main(): - x = Inspectro() - x.inspect(x) - gtk.main() - -if __name__ == '__main__': - import sys - log.startLogging(sys.stdout) - main() - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/explorer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/explorer.py deleted file mode 100644 index b52693c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/explorer.py +++ /dev/null @@ -1,654 +0,0 @@ -# -*- test-case-name: twisted.test.test_explorer -*- -# $Id: explorer.py,v 1.6 2003/02/18 21:15:30 acapnotic Exp $ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Support for python object introspection and exploration. - -Note that Explorers, what with their list of attributes, are much like -manhole.coil.Configurables. Someone should investigate this further. (TODO) - -Also TODO: Determine how much code in here (particularly the function -signature stuff) can be replaced with functions available in the -L{inspect} module available in Python 2.1. -""" - -# System Imports -import inspect, string, sys, types -import UserDict - -# Twisted Imports -from twisted.spread import pb -from twisted.python import reflect - - -True=(1==1) -False=not True - -class Pool(UserDict.UserDict): - def getExplorer(self, object, identifier): - oid = id(object) - if oid in self.data: - # XXX: This potentially returns something with - # 'identifier' set to a different value. - return self.data[oid] - else: - klass = typeTable.get(type(object), ExplorerGeneric) - e = types.InstanceType(klass, {}) - self.data[oid] = e - klass.__init__(e, object, identifier) - return e - -explorerPool = Pool() - -class Explorer(pb.Cacheable): - properties = ["id", "identifier"] - attributeGroups = [] - accessors = ["get_refcount"] - - id = None - identifier = None - - def __init__(self, object, identifier): - self.object = object - self.identifier = identifier - self.id = id(object) - - self.properties = [] - reflect.accumulateClassList(self.__class__, 'properties', - self.properties) - - self.attributeGroups = [] - reflect.accumulateClassList(self.__class__, 'attributeGroups', - self.attributeGroups) - - self.accessors = [] - reflect.accumulateClassList(self.__class__, 'accessors', - self.accessors) - - def getStateToCopyFor(self, perspective): - all = ["properties", "attributeGroups", "accessors"] - all.extend(self.properties) - all.extend(self.attributeGroups) - - state = {} - for key in all: - state[key] = getattr(self, key) - - state['view'] = pb.ViewPoint(perspective, self) - state['explorerClass'] = self.__class__.__name__ - return state - - def view_get_refcount(self, perspective): - return sys.getrefcount(self) - -class ExplorerGeneric(Explorer): - properties = ["str", "repr", "typename"] - - def __init__(self, object, identifier): - Explorer.__init__(self, object, identifier) - self.str = str(object) - self.repr = repr(object) - self.typename = type(object).__name__ - - -class ExplorerImmutable(Explorer): - properties = ["value"] - - def __init__(self, object, identifier): - Explorer.__init__(self, object, identifier) - self.value = object - - -class ExplorerSequence(Explorer): - properties = ["len"] - attributeGroups = ["elements"] - accessors = ["get_elements"] - - def __init__(self, seq, identifier): - Explorer.__init__(self, seq, identifier) - self.seq = seq - self.len = len(seq) - - # Use accessor method to fill me in. - self.elements = [] - - def get_elements(self): - self.len = len(self.seq) - l = [] - for i in xrange(self.len): - identifier = "%s[%s]" % (self.identifier, i) - - # GLOBAL: using global explorerPool - l.append(explorerPool.getExplorer(self.seq[i], identifier)) - - return l - - def view_get_elements(self, perspective): - # XXX: set the .elements member of all my remoteCaches - return self.get_elements() - - -class ExplorerMapping(Explorer): - properties = ["len"] - attributeGroups = ["keys"] - accessors = ["get_keys", "get_item"] - - def __init__(self, dct, identifier): - Explorer.__init__(self, dct, identifier) - - self.dct = dct - self.len = len(dct) - - # Use accessor method to fill me in. - self.keys = [] - - def get_keys(self): - keys = self.dct.keys() - self.len = len(keys) - l = [] - for i in xrange(self.len): - identifier = "%s.keys()[%s]" % (self.identifier, i) - - # GLOBAL: using global explorerPool - l.append(explorerPool.getExplorer(keys[i], identifier)) - - return l - - def view_get_keys(self, perspective): - # XXX: set the .keys member of all my remoteCaches - return self.get_keys() - - def view_get_item(self, perspective, key): - if type(key) is types.InstanceType: - key = key.object - - item = self.dct[key] - - identifier = "%s[%s]" % (self.identifier, repr(key)) - # GLOBAL: using global explorerPool - item = explorerPool.getExplorer(item, identifier) - return item - - -class ExplorerBuiltin(Explorer): - """ - @ivar name: the name the function was defined as - @ivar doc: function's docstring, or C{None} if unavailable - @ivar self: if not C{None}, the function is a method of this object. - """ - properties = ["doc", "name", "self"] - def __init__(self, function, identifier): - Explorer.__init__(self, function, identifier) - self.doc = function.__doc__ - self.name = function.__name__ - self.self = function.__self__ - - -class ExplorerInstance(Explorer): - """ - Attribute groups: - - B{methods} -- dictionary of methods - - B{data} -- dictionary of data members - - Note these are only the *instance* methods and members -- - if you want the class methods, you'll have to look up the class. - - TODO: Detail levels (me, me & class, me & class ancestry) - - @ivar klass: the class this is an instance of. - """ - properties = ["klass"] - attributeGroups = ["methods", "data"] - - def __init__(self, instance, identifier): - Explorer.__init__(self, instance, identifier) - members = {} - methods = {} - for i in dir(instance): - # TODO: Make screening of private attributes configurable. - if i[0] == '_': - continue - mIdentifier = string.join([identifier, i], ".") - member = getattr(instance, i) - mType = type(member) - - if mType is types.MethodType: - methods[i] = explorerPool.getExplorer(member, mIdentifier) - else: - members[i] = explorerPool.getExplorer(member, mIdentifier) - - self.klass = explorerPool.getExplorer(instance.__class__, - self.identifier + - '.__class__') - self.data = members - self.methods = methods - - -class ExplorerClass(Explorer): - """ - @ivar name: the name the class was defined with - @ivar doc: the class's docstring - @ivar bases: a list of this class's base classes. - @ivar module: the module the class is defined in - - Attribute groups: - - B{methods} -- class methods - - B{data} -- other members of the class - """ - properties = ["name", "doc", "bases", "module"] - attributeGroups = ["methods", "data"] - def __init__(self, theClass, identifier): - Explorer.__init__(self, theClass, identifier) - if not identifier: - identifier = theClass.__name__ - members = {} - methods = {} - for i in dir(theClass): - if (i[0] == '_') and (i != '__init__'): - continue - - mIdentifier = string.join([identifier, i], ".") - member = getattr(theClass, i) - mType = type(member) - - if mType is types.MethodType: - methods[i] = explorerPool.getExplorer(member, mIdentifier) - else: - members[i] = explorerPool.getExplorer(member, mIdentifier) - - self.name = theClass.__name__ - self.doc = inspect.getdoc(theClass) - self.data = members - self.methods = methods - self.bases = explorerPool.getExplorer(theClass.__bases__, - identifier + ".__bases__") - self.module = getattr(theClass, '__module__', None) - - -class ExplorerFunction(Explorer): - properties = ["name", "doc", "file", "line","signature"] - """ - name -- the name the function was defined as - signature -- the function's calling signature (Signature instance) - doc -- the function's docstring - file -- the file the function is defined in - line -- the line in the file the function begins on - """ - def __init__(self, function, identifier): - Explorer.__init__(self, function, identifier) - code = function.func_code - argcount = code.co_argcount - takesList = (code.co_flags & 0x04) and 1 - takesKeywords = (code.co_flags & 0x08) and 1 - - n = (argcount + takesList + takesKeywords) - signature = Signature(code.co_varnames[:n]) - - if function.func_defaults: - i_d = 0 - for i in xrange(argcount - len(function.func_defaults), - argcount): - default = function.func_defaults[i_d] - default = explorerPool.getExplorer( - default, '%s.func_defaults[%d]' % (identifier, i_d)) - signature.set_default(i, default) - - i_d = i_d + 1 - - if takesKeywords: - signature.set_keyword(n - 1) - - if takesList: - signature.set_varlist(n - 1 - takesKeywords) - - # maybe also: function.func_globals, - # or at least func_globals.__name__? - # maybe the bytecode, for disassembly-view? - - self.name = function.__name__ - self.signature = signature - self.doc = inspect.getdoc(function) - self.file = code.co_filename - self.line = code.co_firstlineno - - -class ExplorerMethod(ExplorerFunction): - properties = ["self", "klass"] - """ - In addition to ExplorerFunction properties: - self -- the object I am bound to, or None if unbound - klass -- the class I am a method of - """ - def __init__(self, method, identifier): - - function = method.im_func - if type(function) is types.InstanceType: - function = function.__call__.im_func - - ExplorerFunction.__init__(self, function, identifier) - self.id = id(method) - self.klass = explorerPool.getExplorer(method.im_class, - identifier + '.im_class') - self.self = explorerPool.getExplorer(method.im_self, - identifier + '.im_self') - - if method.im_self: - # I'm a bound method -- eat the 'self' arg. - self.signature.discardSelf() - - -class ExplorerModule(Explorer): - """ - @ivar name: the name the module was defined as - @ivar doc: documentation string for the module - @ivar file: the file the module is defined in - - Attribute groups: - - B{classes} -- the public classes provided by the module - - B{functions} -- the public functions provided by the module - - B{data} -- the public data members provided by the module - - (\"Public\" is taken to be \"anything that doesn't start with _\") - """ - properties = ["name","doc","file"] - attributeGroups = ["classes", "functions", "data"] - - def __init__(self, module, identifier): - Explorer.__init__(self, module, identifier) - functions = {} - classes = {} - data = {} - for key, value in module.__dict__.items(): - if key[0] == '_': - continue - - mIdentifier = "%s.%s" % (identifier, key) - - if type(value) is types.ClassType: - classes[key] = explorerPool.getExplorer(value, - mIdentifier) - elif type(value) is types.FunctionType: - functions[key] = explorerPool.getExplorer(value, - mIdentifier) - elif type(value) is types.ModuleType: - pass # pass on imported modules - else: - data[key] = explorerPool.getExplorer(value, mIdentifier) - - self.name = module.__name__ - self.doc = inspect.getdoc(module) - self.file = getattr(module, '__file__', None) - self.classes = classes - self.functions = functions - self.data = data - -typeTable = {types.InstanceType: ExplorerInstance, - types.ClassType: ExplorerClass, - types.MethodType: ExplorerMethod, - types.FunctionType: ExplorerFunction, - types.ModuleType: ExplorerModule, - types.BuiltinFunctionType: ExplorerBuiltin, - types.ListType: ExplorerSequence, - types.TupleType: ExplorerSequence, - types.DictType: ExplorerMapping, - types.StringType: ExplorerImmutable, - types.NoneType: ExplorerImmutable, - types.IntType: ExplorerImmutable, - types.FloatType: ExplorerImmutable, - types.LongType: ExplorerImmutable, - types.ComplexType: ExplorerImmutable, - } - -class Signature(pb.Copyable): - """I represent the signature of a callable. - - Signatures are immutable, so don't expect my contents to change once - they've been set. - """ - _FLAVOURLESS = None - _HAS_DEFAULT = 2 - _VAR_LIST = 4 - _KEYWORD_DICT = 8 - - def __init__(self, argNames): - self.name = argNames - self.default = [None] * len(argNames) - self.flavour = [None] * len(argNames) - - def get_name(self, arg): - return self.name[arg] - - def get_default(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - # Wouldn't it be nice if we just returned "None" when there - # wasn't a default? Well, yes, but oftentimes "None" *is* - # the default, so return a tuple instead. - if self.flavour[arg] == self._HAS_DEFAULT: - return (True, self.default[arg]) - else: - return (False, None) - - def set_default(self, arg, value): - if arg is types.StringType: - arg = self.name.index(arg) - - self.flavour[arg] = self._HAS_DEFAULT - self.default[arg] = value - - def set_varlist(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - self.flavour[arg] = self._VAR_LIST - - def set_keyword(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - self.flavour[arg] = self._KEYWORD_DICT - - def is_varlist(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - return (self.flavour[arg] == self._VAR_LIST) - - def is_keyword(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - return (self.flavour[arg] == self._KEYWORD_DICT) - - def discardSelf(self): - """Invoke me to discard the first argument if this is a bound method. - """ - ## if self.name[0] != 'self': - ## log.msg("Warning: Told to discard self, but name is %s" % - ## self.name[0]) - self.name = self.name[1:] - self.default.pop(0) - self.flavour.pop(0) - - def getStateToCopy(self): - return {'name': tuple(self.name), - 'flavour': tuple(self.flavour), - 'default': tuple(self.default)} - - def __len__(self): - return len(self.name) - - def __str__(self): - arglist = [] - for arg in xrange(len(self)): - name = self.get_name(arg) - hasDefault, default = self.get_default(arg) - if hasDefault: - a = "%s=%s" % (name, default) - elif self.is_varlist(arg): - a = "*%s" % (name,) - elif self.is_keyword(arg): - a = "**%s" % (name,) - else: - a = name - arglist.append(a) - - return string.join(arglist,", ") - - - - - -class CRUFT_WatchyThingie: - # TODO: - # - # * an exclude mechanism for the watcher's browser, to avoid - # sending back large and uninteresting data structures. - # - # * an exclude mechanism for the watcher's trigger, to avoid - # triggering on some frequently-called-method-that-doesn't- - # actually-change-anything. - # - # * XXX! need removeWatch() - - def watchIdentifier(self, identifier, callback): - """Watch the object returned by evaluating the identifier. - - Whenever I think the object might have changed, I'll send an - ObjectLink of it to the callback. - - WARNING: This calls eval() on its argument! - """ - object = eval(identifier, - self.globalNamespace, - self.localNamespace) - return self.watchObject(object, identifier, callback) - - def watchObject(self, object, identifier, callback): - """Watch the given object. - - Whenever I think the object might have changed, I'll send an - ObjectLink of it to the callback. - - The identifier argument is used to generate identifiers for - objects which are members of this one. - """ - if type(object) is not types.InstanceType: - raise TypeError, "Sorry, can only place a watch on Instances." - - # uninstallers = [] - - dct = {} - reflect.addMethodNamesToDict(object.__class__, dct, '') - for k in object.__dict__.keys(): - dct[k] = 1 - - members = dct.keys() - - clazzNS = {} - clazz = types.ClassType('Watching%s%X' % - (object.__class__.__name__, id(object)), - (_MonkeysSetattrMixin, object.__class__,), - clazzNS) - - clazzNS['_watchEmitChanged'] = types.MethodType( - lambda slf, i=identifier, b=self, cb=callback: - cb(b.browseObject(slf, i)), - None, clazz) - - # orig_class = object.__class__ - object.__class__ = clazz - - for name in members: - m = getattr(object, name) - # Only hook bound methods. - if ((type(m) is types.MethodType) - and (m.im_self is not None)): - # What's the use of putting watch monkeys on methods - # in addition to __setattr__? Well, um, uh, if the - # methods modify their attributes (i.e. add a key to - # a dictionary) instead of [re]setting them, then - # we wouldn't know about it unless we did this. - # (Is that convincing?) - - monkey = _WatchMonkey(object) - monkey.install(name) - # uninstallers.append(monkey.uninstall) - - # XXX: This probably prevents these objects from ever having a - # zero refcount. Leak, Leak! - ## self.watchUninstallers[object] = uninstallers - - -class _WatchMonkey: - """I hang on a method and tell you what I see. - - TODO: Aya! Now I just do browseObject all the time, but I could - tell you what got called with what when and returning what. - """ - oldMethod = None - - def __init__(self, instance): - """Make a monkey to hang on this instance object. - """ - self.instance = instance - - def install(self, methodIdentifier): - """Install myself on my instance in place of this method. - """ - oldMethod = getattr(self.instance, methodIdentifier, None) - - # XXX: this conditional probably isn't effective. - if oldMethod is not self: - # avoid triggering __setattr__ - self.instance.__dict__[methodIdentifier] = types.MethodType( - self, self.instance, self.instance.__class__) - self.oldMethod = (methodIdentifier, oldMethod) - - def uninstall(self): - """Remove myself from this instance and restore the original method. - - (I hope.) - """ - if self.oldMethod is None: - return - - # XXX: This probably doesn't work if multiple monkeys are hanging - # on a method and they're not removed in order. - if self.oldMethod[1] is None: - delattr(self.instance, self.oldMethod[0]) - else: - setattr(self.instance, self.oldMethod[0], self.oldMethod[1]) - - def __call__(self, instance, *a, **kw): - """Pretend to be the method I replaced, and ring the bell. - """ - if self.oldMethod[1]: - rval = apply(self.oldMethod[1], a, kw) - else: - rval = None - - instance._watchEmitChanged() - return rval - - -class _MonkeysSetattrMixin: - """A mix-in class providing __setattr__ for objects being watched. - """ - def __setattr__(self, k, v): - """Set the attribute and ring the bell. - """ - if hasattr(self.__class__.__bases__[1], '__setattr__'): - # Hack! Using __bases__[1] is Bad, but since we created - # this class, we can be reasonably sure it'll work. - self.__class__.__bases__[1].__setattr__(self, k, v) - else: - self.__dict__[k] = v - - # XXX: Hey, waitasec, did someone just hang a new method on me? - # Do I need to put a monkey on it? - - self._watchEmitChanged() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/gladereactor.glade b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/gladereactor.glade deleted file mode 100644 index c78dd5a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/gladereactor.glade +++ /dev/null @@ -1,342 +0,0 @@ - - - - - - - True - Twisted Daemon - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 256 - 300 - True - False - - - - True - False - 0 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - True - True - - - - - 0 - True - True - - - - - - True - GTK_BUTTONBOX_DEFAULT_STYLE - 0 - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-undo - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Suspend - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-dialog-warning - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Disconnect - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-open - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Inspect - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-dialog-info - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - View Log - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - gtk-quit - True - GTK_RELIEF_NORMAL - - - - - - 0 - False - True - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/gladereactor.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/gladereactor.py deleted file mode 100644 index 6fc7cfd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/gladereactor.py +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A modified gtk2 reactor with a Glade dialog in-process that allows you to stop, -suspend, resume and inspect transports interactively. -""" - -__all__ = ['install'] - -# Twisted Imports -from twisted.python import util, reflect -from twisted.internet.gtk2reactor import Gtk2Reactor as sup - -import gtk -import gobject -import gtk.glade - -COLUMN_DESCRIPTION = 0 -COLUMN_TRANSPORT = 1 -COLUMN_READING = 2 -COLUMN_WRITING = 3 - - -class GladeReactor(sup): - """GTK+-2 event loop reactor with GUI. - """ - - def listenTCP(self, port, factory, backlog=50, interface=''): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.listenTCP(self, port, factory, backlog, interface) - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.connectTCP(self, host, port, factory, timeout, bindAddress) - - def listenSSL(self, port, factory, contextFactory, backlog=50, interface=''): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.listenSSL(self, port, factory, contextFactory, backlog, interface) - - def connectSSL(self, host, port, factory, contextFactory, timeout=30, bindAddress=None): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.connectSSL(self, host, port, factory, contextFactory, timeout, bindAddress) - - def connectUNIX(self, address, factory, timeout=30): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.connectUNIX(self, address, factory, timeout) - - def listenUNIX(self, address, factory, backlog=50, mode=0666): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.listenUNIX(self, address, factory, backlog, mode) - - def on_disconnect_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - store[iter][COLUMN_TRANSPORT].loseConnection() - - def on_viewlog_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - data = store[iter][1] - from _inspectro import LogViewer - if hasattr(data, "protocol") and not data.protocol.logViewer: - LogViewer(data.protocol) - - def on_inspect_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - data = store[iter] - from _inspectro import Inspectro - Inspectro(data[1]) - - def on_suspend_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - data = store[iter] - sup.removeReader(self, data[1]) - sup.removeWriter(self, data[1]) - if data[COLUMN_DESCRIPTION].endswith('(suspended)'): - if data[COLUMN_READING]: - sup.addReader(self, data[COLUMN_TRANSPORT]) - if data[COLUMN_WRITING]: - sup.addWriter(self, data[COLUMN_TRANSPORT]) - data[COLUMN_DESCRIPTION] = str(data[COLUMN_TRANSPORT]) - self.toggle_suspend(1) - else: - data[0] += ' (suspended)' - self.toggle_suspend(0) - - def toggle_suspend(self, suspending=0): - stock, nonstock = [('gtk-redo', 'Resume'), - ('gtk-undo', 'Suspend')][suspending] - b = self.xml.get_widget("suspend") - b.set_use_stock(1) - b.set_label(stock) - b.get_child().get_child().get_children()[1].set_label(nonstock) - - def servers_selection_changed(self, w): - store, iter = w.get_selected() - if iter is None: - self.xml.get_widget("suspend").set_sensitive(0) - self.xml.get_widget('disconnect').set_sensitive(0) - else: - data = store[iter] - self.toggle_suspend(not - data[COLUMN_DESCRIPTION].endswith('(suspended)')) - self.xml.get_widget("suspend").set_sensitive(1) - self.xml.get_widget('disconnect').set_sensitive(1) - - def on_quit_clicked(self, w): - self.stop() - - def __init__(self): - self.xml = gtk.glade.XML(util.sibpath(__file__,"gladereactor.glade")) - d = {} - for m in reflect.prefixedMethods(self, "on_"): - d[m.im_func.__name__] = m - self.xml.signal_autoconnect(d) - self.xml.get_widget('window1').connect('destroy', - lambda w: self.stop()) - self.servers = self.xml.get_widget("servertree") - sel = self.servers.get_selection() - sel.set_mode(gtk.SELECTION_SINGLE) - sel.connect("changed", - self.servers_selection_changed) - ## argh coredump: self.servers_selection_changed(sel) - self.xml.get_widget('suspend').set_sensitive(0) - self.xml.get_widget('disconnect').set_sensitive(0) - # setup model, connect it to my treeview - self.model = gtk.ListStore(str, object, gobject.TYPE_BOOLEAN, - gobject.TYPE_BOOLEAN) - self.servers.set_model(self.model) - self.servers.set_reorderable(1) - self.servers.set_headers_clickable(1) - # self.servers.set_headers_draggable(1) - # add a column - for col in [ - gtk.TreeViewColumn('Server', - gtk.CellRendererText(), - text=0), - gtk.TreeViewColumn('Reading', - gtk.CellRendererToggle(), - active=2), - gtk.TreeViewColumn('Writing', - gtk.CellRendererToggle(), - active=3)]: - - self.servers.append_column(col) - col.set_resizable(1) - sup.__init__(self) - - def addReader(self, reader): - sup.addReader(self, reader) -## gtk docs suggest this - but it's stupid -## self.model.set(self.model.append(), -## 0, str(reader), -## 1, reader) - self._maybeAddServer(reader, read=1) - - def _goAway(self,reader): - for p in range(len(self.model)): - if self.model[p][1] == reader: - self.model.remove(self.model.get_iter_from_string(str(p))) - return - - - def _maybeAddServer(self, reader, read=0, write=0): - p = 0 - for x in self.model: - if x[1] == reader: - if reader == 0: - reader += 1 - x[2] += read - x[3] += write - x[2] = max(x[2],0) - x[3] = max(x[3],0) - - if not (x[2] or x[3]): - x[0] = x[0] + '(disconnected)' - self.callLater(5, self._goAway, reader) - return - p += 1 - else: - read = max(read,0) - write = max(write, 0) - if read or write: - self.model.append((reader,reader,read,write)) - - def addWriter(self, writer): - sup.addWriter(self, writer) - self._maybeAddServer(writer, write=1) - - def removeReader(self, reader): - sup.removeReader(self, reader) - self._maybeAddServer(reader, read=-1) - - def removeWriter(self, writer): - sup.removeWriter(self, writer) - self._maybeAddServer(writer, write=-1) - - def crash(self): - gtk.main_quit() - - def run(self, installSignalHandlers=1): - self.startRunning(installSignalHandlers=installSignalHandlers) - self.simulate() - gtk.main() - - -def install(): - """Configure the twisted mainloop to be run inside the gtk mainloop. - """ - reactor = GladeReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/inspectro.glade b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/inspectro.glade deleted file mode 100644 index 94b8717..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/inspectro.glade +++ /dev/null @@ -1,510 +0,0 @@ - - - - - - - - - True - Inspectro - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 480 - True - False - True - - - - True - True - - - - True - GTK_SHADOW_NONE - - - - True - - - - True - Inspector - True - - - - - - - True - Select - True - - - - - - - True - Inspect - True - - - - - - - True - Inspect New - True - - - - - - - - - - - True - GNOMEUIINFO_MENU_HELP_TREE - - - - - - - True - GNOMEUIINFO_MENU_ABOUT_ITEM - - - - - - - - - - - - BONOBO_DOCK_TOP - 0 - 0 - 0 - BONOBO_DOCK_ITEM_BEH_EXCLUSIVE|BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL|BONOBO_DOCK_ITEM_BEH_LOCKED - - - - - - True - GTK_SHADOW_OUT - - - - True - GTK_ORIENTATION_HORIZONTAL - GTK_TOOLBAR_BOTH - True - - - - True - Select - True - gtk-convert - - - - - - - True - Inspect - True - gtk-jump-to - - - - - - - True - Inspect New - True - gtk-redo - - - - - - - - BONOBO_DOCK_TOP - 1 - 0 - 0 - BONOBO_DOCK_ITEM_BEH_EXCLUSIVE - - - - - - 350 - True - True - 250 - - - - True - False - 0 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - False - True - - - - - - 0 - True - True - - - - - - True - 2 - 2 - False - 0 - 0 - - - - True - None - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 0 - 1 - - - - - - - True - [] - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 1 - 2 - - - - - - - True - It: - False - False - GTK_JUSTIFY_RIGHT - False - False - 0 - 0.5 - 0 - 0 - - - 0 - 1 - 0 - 1 - 3 - fill - - - - - - - True - Path: - False - False - GTK_JUSTIFY_RIGHT - False - False - 0 - 0.5 - 0 - 0 - - - 0 - 1 - 1 - 2 - 3 - fill - - - - - - 3 - False - True - - - - - True - False - - - - - - True - True - 303 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - False - GTK_JUSTIFY_LEFT - GTK_WRAP_NONE - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - False - True - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - GTK_SHADOW_IN - - - - True - False - 0 - - - - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-execute - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - >>> - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - 0 - False - False - - - - - - 25 - True - True - True - True - GTK_JUSTIFY_LEFT - GTK_WRAP_NONE - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - 0 - True - True - - - - - - - - - False - True - - - - - True - True - - - - - - - 0 - True - True - - - - - - True - False - True - - - 0 - True - True - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/logview.glade b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/logview.glade deleted file mode 100644 index 1ec0b1f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/logview.glade +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - True - Log - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - - - - - True - True - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - False - True - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/service.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/service.py deleted file mode 100644 index 84fb589..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/service.py +++ /dev/null @@ -1,395 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""L{twisted.manhole} L{PB} service implementation. -""" - -# twisted imports -from twisted import copyright -from twisted.spread import pb -from twisted.python import log, failure -from twisted.cred import portal -from twisted.application import service -from zope.interface import implements, Interface - -# sibling imports -import explorer - -import string -import sys -import traceback - - -class FakeStdIO: - def __init__(self, type_, list): - self.type = type_ - self.list = list - - def write(self, text): - log.msg("%s: %s" % (self.type, string.strip(str(text)))) - self.list.append((self.type, text)) - - def flush(self): - pass - - def consolidate(self): - """Concatenate adjacent messages of same type into one. - - Greatly cuts down on the number of elements, increasing - network transport friendliness considerably. - """ - if not self.list: - return - - inlist = self.list - outlist = [] - last_type = inlist[0] - block_begin = 0 - for i in xrange(1, len(self.list)): - (mtype, message) = inlist[i] - if mtype == last_type: - continue - else: - if (i - block_begin) == 1: - outlist.append(inlist[block_begin]) - else: - messages = map(lambda l: l[1], - inlist[block_begin:i]) - message = string.join(messages, '') - outlist.append((last_type, message)) - last_type = mtype - block_begin = i - - -class IManholeClient(Interface): - def console(list_of_messages): - """Takes a list of (type, message) pairs to display. - - Types include: - - \"stdout\" -- string sent to sys.stdout - - - \"stderr\" -- string sent to sys.stderr - - - \"result\" -- string repr of the resulting value - of the expression - - - \"exception\" -- a L{failure.Failure} - """ - - def receiveExplorer(xplorer): - """Receives an explorer.Explorer - """ - - def listCapabilities(): - """List what manholey things I am capable of doing. - - i.e. C{\"Explorer\"}, C{\"Failure\"} - """ - -def runInConsole(command, console, globalNS=None, localNS=None, - filename=None, args=None, kw=None, unsafeTracebacks=False): - """Run this, directing all output to the specified console. - - If command is callable, it will be called with the args and keywords - provided. Otherwise, command will be compiled and eval'd. - (Wouldn't you like a macro?) - - Returns the command's return value. - - The console is called with a list of (type, message) pairs for - display, see L{IManholeClient.console}. - """ - output = [] - fakeout = FakeStdIO("stdout", output) - fakeerr = FakeStdIO("stderr", output) - errfile = FakeStdIO("exception", output) - code = None - val = None - if filename is None: - filename = str(console) - if args is None: - args = () - if kw is None: - kw = {} - if localNS is None: - localNS = globalNS - if (globalNS is None) and (not callable(command)): - raise ValueError("Need a namespace to evaluate the command in.") - - try: - out = sys.stdout - err = sys.stderr - sys.stdout = fakeout - sys.stderr = fakeerr - try: - if callable(command): - val = apply(command, args, kw) - else: - try: - code = compile(command, filename, 'eval') - except: - code = compile(command, filename, 'single') - - if code: - val = eval(code, globalNS, localNS) - finally: - sys.stdout = out - sys.stderr = err - except: - (eType, eVal, tb) = sys.exc_info() - fail = failure.Failure(eVal, eType, tb) - del tb - # In CVS reversion 1.35, there was some code here to fill in the - # source lines in the traceback for frames in the local command - # buffer. But I can't figure out when that's triggered, so it's - # going away in the conversion to Failure, until you bring it back. - errfile.write(pb.failure2Copyable(fail, unsafeTracebacks)) - - if console: - fakeout.consolidate() - console(output) - - return val - -def _failureOldStyle(fail): - """Pre-Failure manhole representation of exceptions. - - For compatibility with manhole clients without the \"Failure\" - capability. - - A dictionary with two members: - - \'traceback\' -- traceback.extract_tb output; a list of tuples - (filename, line number, function name, text) suitable for - feeding to traceback.format_list. - - - \'exception\' -- a list of one or more strings, each - ending in a newline. (traceback.format_exception_only output) - """ - import linecache - tb = [] - for f in fail.frames: - # (filename, line number, function name, text) - tb.append((f[1], f[2], f[0], linecache.getline(f[1], f[2]))) - - return { - 'traceback': tb, - 'exception': traceback.format_exception_only(fail.type, fail.value) - } - -# Capabilities clients are likely to have before they knew how to answer a -# "listCapabilities" query. -_defaultCapabilities = { - "Explorer": 'Set' - } - -class Perspective(pb.Avatar): - lastDeferred = 0 - def __init__(self, service): - self.localNamespace = { - "service": service, - "avatar": self, - "_": None, - } - self.clients = {} - self.service = service - - def __getstate__(self): - state = self.__dict__.copy() - state['clients'] = {} - if state['localNamespace'].has_key("__builtins__"): - del state['localNamespace']['__builtins__'] - return state - - def attached(self, client, identity): - """A client has attached -- welcome them and add them to the list. - """ - self.clients[client] = identity - - host = ':'.join(map(str, client.broker.transport.getHost()[1:])) - - msg = self.service.welcomeMessage % { - 'you': getattr(identity, 'name', str(identity)), - 'host': host, - 'longversion': copyright.longversion, - } - - client.callRemote('console', [("stdout", msg)]) - - client.capabilities = _defaultCapabilities - client.callRemote('listCapabilities').addCallbacks( - self._cbClientCapable, self._ebClientCapable, - callbackArgs=(client,),errbackArgs=(client,)) - - def detached(self, client, identity): - try: - del self.clients[client] - except KeyError: - pass - - def runInConsole(self, command, *args, **kw): - """Convience method to \"runInConsole with my stuff\". - """ - return runInConsole(command, - self.console, - self.service.namespace, - self.localNamespace, - str(self.service), - args=args, - kw=kw, - unsafeTracebacks=self.service.unsafeTracebacks) - - - ### Methods for communicating to my clients. - - def console(self, message): - """Pass a message to my clients' console. - """ - clients = self.clients.keys() - origMessage = message - compatMessage = None - for client in clients: - try: - if "Failure" not in client.capabilities: - if compatMessage is None: - compatMessage = origMessage[:] - for i in xrange(len(message)): - if ((message[i][0] == "exception") and - isinstance(message[i][1], failure.Failure)): - compatMessage[i] = ( - message[i][0], - _failureOldStyle(message[i][1])) - client.callRemote('console', compatMessage) - else: - client.callRemote('console', message) - except pb.ProtocolError: - # Stale broker. - self.detached(client, None) - - def receiveExplorer(self, objectLink): - """Pass an Explorer on to my clients. - """ - clients = self.clients.keys() - for client in clients: - try: - client.callRemote('receiveExplorer', objectLink) - except pb.ProtocolError: - # Stale broker. - self.detached(client, None) - - - def _cbResult(self, val, dnum): - self.console([('result', "Deferred #%s Result: %r\n" %(dnum, val))]) - return val - - def _cbClientCapable(self, capabilities, client): - log.msg("client %x has %s" % (id(client), capabilities)) - client.capabilities = capabilities - - def _ebClientCapable(self, reason, client): - reason.trap(AttributeError) - log.msg("Couldn't get capabilities from %s, assuming defaults." % - (client,)) - - ### perspective_ methods, commands used by the client. - - def perspective_do(self, expr): - """Evaluate the given expression, with output to the console. - - The result is stored in the local variable '_', and its repr() - string is sent to the console as a \"result\" message. - """ - log.msg(">>> %s" % expr) - val = self.runInConsole(expr) - if val is not None: - self.localNamespace["_"] = val - from twisted.internet.defer import Deferred - # TODO: client support for Deferred. - if isinstance(val, Deferred): - self.lastDeferred += 1 - self.console([('result', "Waiting for Deferred #%s...\n" % self.lastDeferred)]) - val.addBoth(self._cbResult, self.lastDeferred) - else: - self.console([("result", repr(val) + '\n')]) - log.msg("<<<") - - def perspective_explore(self, identifier): - """Browse the object obtained by evaluating the identifier. - - The resulting ObjectLink is passed back through the client's - receiveBrowserObject method. - """ - object = self.runInConsole(identifier) - if object: - expl = explorer.explorerPool.getExplorer(object, identifier) - self.receiveExplorer(expl) - - def perspective_watch(self, identifier): - """Watch the object obtained by evaluating the identifier. - - Whenever I think this object might have changed, I will pass - an ObjectLink of it back to the client's receiveBrowserObject - method. - """ - raise NotImplementedError - object = self.runInConsole(identifier) - if object: - # Return an ObjectLink of this right away, before the watch. - oLink = self.runInConsole(self.browser.browseObject, - object, identifier) - self.receiveExplorer(oLink) - - self.runInConsole(self.browser.watchObject, - object, identifier, - self.receiveExplorer) - - -class Realm: - - implements(portal.IRealm) - - def __init__(self, service): - self.service = service - self._cache = {} - - def requestAvatar(self, avatarId, mind, *interfaces): - if pb.IPerspective not in interfaces: - raise NotImplementedError("no interface") - if avatarId in self._cache: - p = self._cache[avatarId] - else: - p = Perspective(self.service) - p.attached(mind, avatarId) - def detached(): - p.detached(mind, avatarId) - return (pb.IPerspective, p, detached) - - -class Service(service.Service): - - welcomeMessage = ( - "\nHello %(you)s, welcome to Manhole " - "on %(host)s.\n" - "%(longversion)s.\n\n") - - def __init__(self, unsafeTracebacks=False, namespace=None): - self.unsafeTracebacks = unsafeTracebacks - self.namespace = { - '__name__': '__manhole%x__' % (id(self),), - 'sys': sys - } - if namespace: - self.namespace.update(namespace) - - def __getstate__(self): - """This returns the persistent state of this shell factory. - """ - # TODO -- refactor this and twisted.reality.author.Author to - # use common functionality (perhaps the 'code' module?) - dict = self.__dict__.copy() - ns = dict['namespace'].copy() - dict['namespace'] = ns - if ns.has_key('__builtins__'): - del ns['__builtins__'] - return dict diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/telnet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/telnet.py deleted file mode 100644 index c689a16..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/telnet.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Telnet-based shell.""" - -# twisted imports -from twisted.protocols import telnet -from twisted.internet import protocol -from twisted.python import log, failure - -# system imports -import string, copy, sys - - -class Shell(telnet.Telnet): - """A Python command-line shell.""" - - def connectionMade(self): - telnet.Telnet.connectionMade(self) - self.lineBuffer = [] - - def loggedIn(self): - self.transport.write(">>> ") - - def checkUserAndPass(self, username, password): - return ((self.factory.username == username) and (password == self.factory.password)) - - def write(self, data): - """Write some data to the transport. - """ - self.transport.write(data) - - def telnet_Command(self, cmd): - if self.lineBuffer: - if not cmd: - cmd = string.join(self.lineBuffer, '\n') + '\n\n\n' - self.doCommand(cmd) - self.lineBuffer = [] - return "Command" - else: - self.lineBuffer.append(cmd) - self.transport.write("... ") - return "Command" - else: - self.doCommand(cmd) - return "Command" - - def doCommand(self, cmd): - - # TODO -- refactor this, Reality.author.Author, and the manhole shell - #to use common functionality (perhaps a twisted.python.code module?) - fn = '$telnet$' - result = None - try: - out = sys.stdout - sys.stdout = self - try: - code = compile(cmd,fn,'eval') - result = eval(code, self.factory.namespace) - except: - try: - code = compile(cmd, fn, 'exec') - exec code in self.factory.namespace - except SyntaxError, e: - if not self.lineBuffer and str(e)[:14] == "unexpected EOF": - self.lineBuffer.append(cmd) - self.transport.write("... ") - return - else: - failure.Failure().printTraceback(file=self) - log.deferr() - self.write('\r\n>>> ') - return - except: - failure.Failure().printTraceback(file=self) - log.deferr() - self.write('\r\n>>> ') - return - finally: - sys.stdout = out - - self.factory.namespace['_'] = result - if result is not None: - self.transport.write(repr(result)) - self.transport.write('\r\n') - self.transport.write(">>> ") - - - -class ShellFactory(protocol.Factory): - username = "admin" - password = "admin" - protocol = Shell - service = None - - def __init__(self): - self.namespace = { - 'factory': self, - 'service': None, - '_': None - } - - def setService(self, service): - self.namespace['service'] = self.service = service - - def __getstate__(self): - """This returns the persistent state of this shell factory. - """ - dict = self.__dict__ - ns = copy.copy(dict['namespace']) - dict['namespace'] = ns - if ns.has_key('__builtins__'): - del ns['__builtins__'] - return dict diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/test/__init__.py deleted file mode 100644 index 83c9ea1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.manhole}. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/test/test_explorer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/test/test_explorer.py deleted file mode 100644 index 2f21733..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/test/test_explorer.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.manhole.explorer}. -""" - -from twisted.trial import unittest -from twisted.manhole.explorer import ( - CRUFT_WatchyThingie, - ExplorerImmutable, - Pool, - _WatchMonkey, - ) - - -class Foo: - """ - Test helper. - """ - - -class PoolTests(unittest.TestCase): - """ - Tests for the Pool class. - """ - - def test_instanceBuilding(self): - """ - If the object is not in the pool a new instance is created and - returned. - """ - p = Pool() - e = p.getExplorer(123, 'id') - self.assertIsInstance(e, ExplorerImmutable) - self.assertEqual(e.value, 123) - self.assertEqual(e.identifier, 'id') - - - -class CRUFTWatchyThingieTests(unittest.TestCase): - """ - Tests for the CRUFT_WatchyThingie class. - """ - def test_watchObjectConstructedClass(self): - """ - L{CRUFT_WatchyThingie.watchObject} changes the class of its - first argument to a custom watching class. - """ - foo = Foo() - cwt = CRUFT_WatchyThingie() - cwt.watchObject(foo, 'id', 'cback') - - # check new constructed class - newClassName = foo.__class__.__name__ - self.assertEqual(newClassName, "WatchingFoo%X" % (id(foo),)) - - - def test_watchObjectConstructedInstanceMethod(self): - """ - L{CRUFT_WatchyThingie.watchingfoo} adds a C{_watchEmitChanged} - attribute which refers to a bound method on the instance - passed to it. - """ - foo = Foo() - cwt = CRUFT_WatchyThingie() - cwt.watchObject(foo, 'id', 'cback') - - # check new constructed instance method - self.assertIdentical(foo._watchEmitChanged.im_self, foo) - - - -class WatchMonkeyTests(unittest.TestCase): - """ - Tests for the _WatchMonkey class. - """ - def test_install(self): - """ - When _WatchMonkey is installed on a method, calling that - method calls the _WatchMonkey. - """ - class Foo: - """ - Helper. - """ - def someMethod(self): - """ - Just a method. - """ - - foo = Foo() - wm = _WatchMonkey(foo) - wm.install('someMethod') - - # patch wm's method to check that the method was exchanged - called = [] - wm.__call__ = lambda s: called.append(True) - - # call and check - foo.someMethod() - self.assertTrue(called) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/__init__.py deleted file mode 100644 index 14af615..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Twisted Manhole UI: User interface for direct manipulation in Twisted. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/gtk2manhole.glade b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/gtk2manhole.glade deleted file mode 100644 index 423b3fb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/gtk2manhole.glade +++ /dev/null @@ -1,268 +0,0 @@ - - - - - - - True - Manhole - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 620 - 320 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - - - - - True - False - 0 - - - - True - - - - True - _File - True - - - - - - - True - gtk-open - True - - - - - - - True - Reload the manhole client code. (Only useful for client development.) - _Reload self - True - - - - - True - gtk-revert-to-saved - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - gtk-quit - True - - - - - - - - - - - True - _Edit - True - - - - - - - True - gtk-cut - True - - - - - - - True - gtk-copy - True - - - - - - - True - gtk-paste - True - - - - - - - True - gtk-delete - True - - - - - - - - - - - True - _Help - True - - - - - - - True - _About - True - - - - - - - - - - 0 - False - False - - - - - - True - True - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - False - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_WORD - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - True - True - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - True - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_NONE - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - True - False - - - - - 0 - True - True - - - - - - True - True - - - 0 - False - False - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/gtk2manhole.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/gtk2manhole.py deleted file mode 100644 index 9985980..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/gtk2manhole.py +++ /dev/null @@ -1,374 +0,0 @@ -# -*- test-case-name: twisted.manhole.ui.test.test_gtk2manhole -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Manhole client with a GTK v2.x front-end. -""" - -__version__ = '$Revision: 1.9 $'[11:-2] - -from twisted import copyright -from twisted.internet import reactor -from twisted.python import components, failure, log, util -from twisted.python.reflect import prefixedMethodNames -from twisted.spread import pb -from twisted.spread.ui import gtk2util - -from twisted.manhole.service import IManholeClient -from zope.interface import implements - -# The pygtk.require for version 2.0 has already been done by the reactor. -import gtk - -import code, types, inspect - -# TODO: -# Make wrap-mode a run-time option. -# Explorer. -# Code doesn't cleanly handle opening a second connection. Fix that. -# Make some acknowledgement of when a command has completed, even if -# it has no return value so it doesn't print anything to the console. - -class OfflineError(Exception): - pass - -class ManholeWindow(components.Componentized, gtk2util.GladeKeeper): - gladefile = util.sibpath(__file__, "gtk2manhole.glade") - - _widgets = ('input','output','manholeWindow') - - def __init__(self): - self.defaults = {} - gtk2util.GladeKeeper.__init__(self) - components.Componentized.__init__(self) - - self.input = ConsoleInput(self._input) - self.input.toplevel = self - self.output = ConsoleOutput(self._output) - - # Ugh. GladeKeeper actually isn't so good for composite objects. - # I want this connected to the ConsoleInput's handler, not something - # on this class. - self._input.connect("key_press_event", self.input._on_key_press_event) - - def setDefaults(self, defaults): - self.defaults = defaults - - def login(self): - client = self.getComponent(IManholeClient) - d = gtk2util.login(client, **self.defaults) - d.addCallback(self._cbLogin) - d.addCallback(client._cbLogin) - d.addErrback(self._ebLogin) - - def _cbDisconnected(self, perspective): - self.output.append("%s went away. :(\n" % (perspective,), "local") - self._manholeWindow.set_title("Manhole") - - def _cbLogin(self, perspective): - peer = perspective.broker.transport.getPeer() - self.output.append("Connected to %s\n" % (peer,), "local") - perspective.notifyOnDisconnect(self._cbDisconnected) - self._manholeWindow.set_title("Manhole - %s" % (peer)) - return perspective - - def _ebLogin(self, reason): - self.output.append("Login FAILED %s\n" % (reason.value,), "exception") - - def _on_aboutMenuItem_activate(self, widget, *unused): - import sys - from os import path - self.output.append("""\ -a Twisted Manhole client - Versions: - %(twistedVer)s - Python %(pythonVer)s on %(platform)s - GTK %(gtkVer)s / PyGTK %(pygtkVer)s - %(module)s %(modVer)s -http://twistedmatrix.com/ -""" % {'twistedVer': copyright.longversion, - 'pythonVer': sys.version.replace('\n', '\n '), - 'platform': sys.platform, - 'gtkVer': ".".join(map(str, gtk.gtk_version)), - 'pygtkVer': ".".join(map(str, gtk.pygtk_version)), - 'module': path.basename(__file__), - 'modVer': __version__, - }, "local") - - def _on_openMenuItem_activate(self, widget, userdata=None): - self.login() - - def _on_manholeWindow_delete_event(self, widget, *unused): - reactor.stop() - - def _on_quitMenuItem_activate(self, widget, *unused): - reactor.stop() - - def on_reload_self_activate(self, *unused): - from twisted.python import rebuild - rebuild.rebuild(inspect.getmodule(self.__class__)) - - -tagdefs = { - 'default': {"family": "monospace"}, - # These are message types we get from the server. - 'stdout': {"foreground": "black"}, - 'stderr': {"foreground": "#AA8000"}, - 'result': {"foreground": "blue"}, - 'exception': {"foreground": "red"}, - # Messages generate locally. - 'local': {"foreground": "#008000"}, - 'log': {"foreground": "#000080"}, - 'command': {"foreground": "#666666"}, - } - -# TODO: Factor Python console stuff back out to pywidgets. - -class ConsoleOutput: - _willScroll = None - def __init__(self, textView): - self.textView = textView - self.buffer = textView.get_buffer() - - # TODO: Make this a singleton tag table. - for name, props in tagdefs.iteritems(): - tag = self.buffer.create_tag(name) - # This can be done in the constructor in newer pygtk (post 1.99.14) - for k, v in props.iteritems(): - tag.set_property(k, v) - - self.buffer.tag_table.lookup("default").set_priority(0) - - self._captureLocalLog() - - def _captureLocalLog(self): - return log.startLogging(_Notafile(self, "log"), setStdout=False) - - def append(self, text, kind=None): - # XXX: It seems weird to have to do this thing with always applying - # a 'default' tag. Can't we change the fundamental look instead? - tags = ["default"] - if kind is not None: - tags.append(kind) - - self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(), - text, *tags) - # Silly things, the TextView needs to update itself before it knows - # where the bottom is. - if self._willScroll is None: - self._willScroll = gtk.idle_add(self._scrollDown) - - def _scrollDown(self, *unused): - self.textView.scroll_to_iter(self.buffer.get_end_iter(), 0, - True, 1.0, 1.0) - self._willScroll = None - return False - -class History: - def __init__(self, maxhist=10000): - self.ringbuffer = [''] - self.maxhist = maxhist - self.histCursor = 0 - - def append(self, htext): - self.ringbuffer.insert(-1, htext) - if len(self.ringbuffer) > self.maxhist: - self.ringbuffer.pop(0) - self.histCursor = len(self.ringbuffer) - 1 - self.ringbuffer[-1] = '' - - def move(self, prevnext=1): - ''' - Return next/previous item in the history, stopping at top/bottom. - ''' - hcpn = self.histCursor + prevnext - if hcpn >= 0 and hcpn < len(self.ringbuffer): - self.histCursor = hcpn - return self.ringbuffer[hcpn] - else: - return None - - def histup(self, textbuffer): - if self.histCursor == len(self.ringbuffer) - 1: - si, ei = textbuffer.get_start_iter(), textbuffer.get_end_iter() - self.ringbuffer[-1] = textbuffer.get_text(si,ei) - newtext = self.move(-1) - if newtext is None: - return - textbuffer.set_text(newtext) - - def histdown(self, textbuffer): - newtext = self.move(1) - if newtext is None: - return - textbuffer.set_text(newtext) - - -class ConsoleInput: - toplevel, rkeymap = None, None - __debug = False - - def __init__(self, textView): - self.textView=textView - self.rkeymap = {} - self.history = History() - for name in prefixedMethodNames(self.__class__, "key_"): - keysymName = name.split("_")[-1] - self.rkeymap[getattr(gtk.keysyms, keysymName)] = keysymName - - def _on_key_press_event(self, entry, event): - ksym = self.rkeymap.get(event.keyval, None) - - mods = [] - for prefix, mask in [('ctrl', gtk.gdk.CONTROL_MASK), ('shift', gtk.gdk.SHIFT_MASK)]: - if event.state & mask: - mods.append(prefix) - - if mods: - ksym = '_'.join(mods + [ksym]) - - if ksym: - rvalue = getattr( - self, 'key_%s' % ksym, lambda *a, **kw: None)(entry, event) - - if self.__debug: - print ksym - return rvalue - - def getText(self): - buffer = self.textView.get_buffer() - iter1, iter2 = buffer.get_bounds() - text = buffer.get_text(iter1, iter2, False) - return text - - def setText(self, text): - self.textView.get_buffer().set_text(text) - - def key_Return(self, entry, event): - text = self.getText() - # Figure out if that Return meant "next line" or "execute." - try: - c = code.compile_command(text) - except SyntaxError, e: - # This could conceivably piss you off if the client's python - # doesn't accept keywords that are known to the manhole's - # python. - point = buffer.get_iter_at_line_offset(e.lineno, e.offset) - buffer.place(point) - # TODO: Componentize! - self.toplevel.output.append(str(e), "exception") - except (OverflowError, ValueError), e: - self.toplevel.output.append(str(e), "exception") - else: - if c is not None: - self.sendMessage() - # Don't insert Return as a newline in the buffer. - self.history.append(text) - self.clear() - # entry.emit_stop_by_name("key_press_event") - return True - else: - # not a complete code block - return False - - return False - - def key_Up(self, entry, event): - # if I'm at the top, previous history item. - textbuffer = self.textView.get_buffer() - if textbuffer.get_iter_at_mark(textbuffer.get_insert()).get_line() == 0: - self.history.histup(textbuffer) - return True - return False - - def key_Down(self, entry, event): - textbuffer = self.textView.get_buffer() - if textbuffer.get_iter_at_mark(textbuffer.get_insert()).get_line() == ( - textbuffer.get_line_count() - 1): - self.history.histdown(textbuffer) - return True - return False - - key_ctrl_p = key_Up - key_ctrl_n = key_Down - - def key_ctrl_shift_F9(self, entry, event): - if self.__debug: - import pdb; pdb.set_trace() - - def clear(self): - buffer = self.textView.get_buffer() - buffer.delete(*buffer.get_bounds()) - - def sendMessage(self): - buffer = self.textView.get_buffer() - iter1, iter2 = buffer.get_bounds() - text = buffer.get_text(iter1, iter2, False) - self.toplevel.output.append(pythonify(text), 'command') - # TODO: Componentize better! - try: - return self.toplevel.getComponent(IManholeClient).do(text) - except OfflineError: - self.toplevel.output.append("Not connected, command not sent.\n", - "exception") - - -def pythonify(text): - ''' - Make some text appear as though it was typed in at a Python prompt. - ''' - lines = text.split('\n') - lines[0] = '>>> ' + lines[0] - return '\n... '.join(lines) + '\n' - -class _Notafile: - """Curry to make failure.printTraceback work with the output widget.""" - def __init__(self, output, kind): - self.output = output - self.kind = kind - - def write(self, txt): - self.output.append(txt, self.kind) - - def flush(self): - pass - -class ManholeClient(components.Adapter, pb.Referenceable): - implements(IManholeClient) - - capabilities = { -# "Explorer": 'Set', - "Failure": 'Set' - } - - def _cbLogin(self, perspective): - self.perspective = perspective - perspective.notifyOnDisconnect(self._cbDisconnected) - return perspective - - def remote_console(self, messages): - for kind, content in messages: - if isinstance(content, types.StringTypes): - self.original.output.append(content, kind) - elif (kind == "exception") and isinstance(content, failure.Failure): - content.printTraceback(_Notafile(self.original.output, - "exception")) - else: - self.original.output.append(str(content), kind) - - def remote_receiveExplorer(self, xplorer): - pass - - def remote_listCapabilities(self): - return self.capabilities - - def _cbDisconnected(self, perspective): - self.perspective = None - - def do(self, text): - if self.perspective is None: - raise OfflineError - return self.perspective.callRemote("do", text) - -components.registerAdapter(ManholeClient, ManholeWindow, IManholeClient) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/test/__init__.py deleted file mode 100644 index 36214ba..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/test/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. -""" -Tests for the L{twisted.manhole.ui} package. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/test/test_gtk2manhole.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/test/test_gtk2manhole.py deleted file mode 100644 index b59f937..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/manhole/ui/test/test_gtk2manhole.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. -""" -Tests for GTK2 GUI manhole. -""" - -skip = False - -try: - import pygtk - pygtk.require("2.0") -except: - skip = "GTK 2.0 not available" -else: - try: - import gtk - except ImportError: - skip = "GTK 2.0 not available" - except RuntimeError: - skip = "Old version of GTK 2.0 requires DISPLAY, and we don't have one." - else: - if gtk.gtk_version[0] == 1: - skip = "Requested GTK 2.0, but 1.0 was already imported." - else: - from twisted.manhole.ui.gtk2manhole import ConsoleInput - -from twisted.trial.unittest import TestCase - -from twisted.python.reflect import prefixedMethodNames - -class ConsoleInputTests(TestCase): - """ - Tests for L{ConsoleInput}. - """ - - def test_reverseKeymap(self): - """ - Verify that a L{ConsoleInput} has a reverse mapping of the keysym names - it needs for event handling to their corresponding keysym. - """ - ci = ConsoleInput(None) - for eventName in prefixedMethodNames(ConsoleInput, 'key_'): - keysymName = eventName.split("_")[-1] - keysymValue = getattr(gtk.keysyms, keysymName) - self.assertEqual(ci.rkeymap[keysymValue], keysymName) - - - skip = skip - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/__init__.py deleted file mode 100644 index 63d1571..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Names: DNS server and client implementations. -""" - -from twisted.names._version import version -__version__ = version.short() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/_rfc1982.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/_rfc1982.py deleted file mode 100644 index a895d82..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/_rfc1982.py +++ /dev/null @@ -1,278 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_rfc1982 -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Utilities for handling RFC1982 Serial Number Arithmetic. - -@see: U{http://tools.ietf.org/html/rfc1982} - -@var RFC4034_TIME_FORMAT: RRSIG Time field presentation format. The Signature - Expiration Time and Inception Time field values MUST be represented either - as an unsigned decimal integer indicating seconds since 1 January 1970 - 00:00:00 UTC, or in the form YYYYMMDDHHmmSS in UTC. See U{RRSIG Presentation - Format} -""" - -from __future__ import division, absolute_import - -import calendar -from datetime import datetime, timedelta - -from twisted.python.compat import nativeString -from twisted.python.util import FancyStrMixin - - -RFC4034_TIME_FORMAT = '%Y%m%d%H%M%S' - - - -class SerialNumber(FancyStrMixin, object): - """ - An RFC1982 Serial Number. - - This class implements RFC1982 DNS Serial Number Arithmetic. - - SNA is used in DNS and specifically in DNSSEC as defined in RFC4034 in the - DNSSEC Signature Expiration and Inception Fields. - - @see: U{https://tools.ietf.org/html/rfc1982} - @see: U{https://tools.ietf.org/html/rfc4034} - - @ivar _serialBits: See C{serialBits} of L{__init__}. - @ivar _number: See C{number} of L{__init__}. - @ivar _modulo: The value at which wrapping will occur. - @ivar _halfRing: Half C{_modulo}. If another L{SerialNumber} value is larger - than this, it would lead to a wrapped value which is larger than the - first and comparisons are therefore ambiguous. - @ivar _maxAdd: Half C{_modulo} plus 1. If another L{SerialNumber} value is - larger than this, it would lead to a wrapped value which is larger than - the first. Comparisons with the original value would therefore be - ambiguous. - """ - - showAttributes = ( - ('_number', 'number', '%d'), - ('_serialBits', 'serialBits', '%d'), - ) - - def __init__(self, number, serialBits=32): - """ - Construct an L{SerialNumber} instance. - - @param number: An L{int} which will be stored as the modulo - C{number % 2 ^ serialBits} - @type number: L{int} - - @param serialBits: The size of the serial number space. The power of two - which results in one larger than the largest integer corresponding - to a serial number value. - @type serialBits: L{int} - """ - self._serialBits = serialBits - self._modulo = 2 ** serialBits - self._halfRing = 2 ** (serialBits - 1) - self._maxAdd = 2 ** (serialBits - 1) - 1 - self._number = int(number) % self._modulo - - - def _convertOther(self, other): - """ - Check that a foreign object is suitable for use in the comparison or - arithmetic magic methods of this L{SerialNumber} instance. Raise - L{TypeError} if not. - - @param other: The foreign L{object} to be checked. - @return: C{other} after compatibility checks and possible coercion. - @raises: L{TypeError} if C{other} is not compatible. - """ - if not isinstance(other, SerialNumber): - raise TypeError( - 'cannot compare or combine %r and %r' % (self, other)) - - if self._serialBits != other._serialBits: - raise TypeError( - 'cannot compare or combine SerialNumber instances with ' - 'different serialBits. %r and %r' % (self, other)) - - return other - - - def __str__(self): - """ - Return a string representation of this L{SerialNumber} instance. - - @rtype: L{nativeString} - """ - return nativeString('%d' % (self._number,)) - - - def __int__(self): - """ - @return: The integer value of this L{SerialNumber} instance. - @rtype: L{int} - """ - return self._number - - - def __eq__(self, other): - """ - Allow rich equality comparison with another L{SerialNumber} instance. - - @type other: L{SerialNumber} - """ - other = self._convertOther(other) - return other._number == self._number - - - def __ne__(self, other): - """ - Allow rich equality comparison with another L{SerialNumber} instance. - - @type other: L{SerialNumber} - """ - return not self.__eq__(other) - - - def __lt__(self, other): - """ - Allow I{less than} comparison with another L{SerialNumber} instance. - - @type other: L{SerialNumber} - """ - other = self._convertOther(other) - return ( - (self._number < other._number - and (other._number - self._number) < self._halfRing) - or - (self._number > other._number - and (self._number - other._number) > self._halfRing) - ) - - - def __gt__(self, other): - """ - Allow I{greater than} comparison with another L{SerialNumber} instance. - - @type other: L{SerialNumber} - @rtype: L{bool} - """ - other = self._convertOther(other) - return ( - (self._number < other._number - and (other._number - self._number) > self._halfRing) - or - (self._number > other._number - and (self._number - other._number) < self._halfRing) - ) - - - def __le__(self, other): - """ - Allow I{less than or equal} comparison with another L{SerialNumber} - instance. - - @type other: L{SerialNumber} - @rtype: L{bool} - """ - other = self._convertOther(other) - return self == other or self < other - - - def __ge__(self, other): - """ - Allow I{greater than or equal} comparison with another L{SerialNumber} - instance. - - @type other: L{SerialNumber} - @rtype: L{bool} - """ - other = self._convertOther(other) - return self == other or self > other - - - def __add__(self, other): - """ - Allow I{addition} with another L{SerialNumber} instance. - - Serial numbers may be incremented by the addition of a positive - integer n, where n is taken from the range of integers - [0 .. (2^(SERIAL_BITS - 1) - 1)]. For a sequence number s, the - result of such an addition, s', is defined as - - s' = (s + n) modulo (2 ^ SERIAL_BITS) - - where the addition and modulus operations here act upon values that are - non-negative values of unbounded size in the usual ways of integer - arithmetic. - - Addition of a value outside the range - [0 .. (2^(SERIAL_BITS - 1) - 1)] is undefined. - - @see: U{http://tools.ietf.org/html/rfc1982#section-3.1} - - @type other: L{SerialNumber} - @rtype: L{SerialNumber} - @raises: L{ArithmeticError} if C{other} is more than C{_maxAdd} - ie more than half the maximum value of this serial number. - """ - other = self._convertOther(other) - if other._number <= self._maxAdd: - return SerialNumber( - (self._number + other._number) % self._modulo, - serialBits=self._serialBits) - else: - raise ArithmeticError( - 'value %r outside the range 0 .. %r' % ( - other._number, self._maxAdd,)) - - - def __hash__(self): - """ - Allow L{SerialNumber} instances to be hashed for use as L{dict} keys. - - @rtype: L{int} - """ - return hash(self._number) - - - @classmethod - def fromRFC4034DateString(cls, utcDateString): - """ - Create an L{SerialNumber} instance from a date string in format - 'YYYYMMDDHHMMSS' described in U{RFC4034 - 3.2}. - - The L{SerialNumber} instance stores the date as a 32bit UNIX timestamp. - - @see: U{https://tools.ietf.org/html/rfc4034#section-3.1.5} - - @param utcDateString: A UTC date/time string of format I{YYMMDDhhmmss} - which will be converted to seconds since the UNIX epoch. - @type utcDateString: L{unicode} - - @return: An L{SerialNumber} instance containing the supplied date as a - 32bit UNIX timestamp. - """ - parsedDate = datetime.strptime(utcDateString, RFC4034_TIME_FORMAT) - secondsSinceEpoch = calendar.timegm(parsedDate.utctimetuple()) - return cls(secondsSinceEpoch, serialBits=32) - - - def toRFC4034DateString(self): - """ - Calculate a date by treating the current L{SerialNumber} value as a UNIX - timestamp and return a date string in the format described in - U{RFC4034 3.2}. - - @return: The date string. - """ - # Can't use datetime.utcfromtimestamp, because it seems to overflow the - # signed 32bit int used in the underlying C library. SNA is unsigned - # and capable of handling all timestamps up to 2**32. - d = datetime(1970, 1, 1) + timedelta(seconds=self._number) - return nativeString(d.strftime(RFC4034_TIME_FORMAT)) - - - -__all__ = ['SerialNumber'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/_version.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/_version.py deleted file mode 100644 index b1e2997..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/_version.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This is an auto-generated file. Do not edit it. - -""" -Provides Twisted version information. -""" - -from twisted.python import versions -version = versions.Version('twisted.names', 15, 2, 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/authority.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/authority.py deleted file mode 100644 index af1ffc6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/authority.py +++ /dev/null @@ -1,405 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Authoritative resolvers. -""" - -import os -import time - -from twisted.names import dns, error -from twisted.internet import defer -from twisted.python import failure -from twisted.python.compat import execfile - -import common - -def getSerial(filename = '/tmp/twisted-names.serial'): - """Return a monotonically increasing (across program runs) integer. - - State is stored in the given file. If it does not exist, it is - created with rw-/---/--- permissions. - """ - serial = time.strftime('%Y%m%d') - - o = os.umask(0177) - try: - if not os.path.exists(filename): - f = file(filename, 'w') - f.write(serial + ' 0') - f.close() - finally: - os.umask(o) - - serialFile = file(filename, 'r') - lastSerial, ID = serialFile.readline().split() - ID = (lastSerial == serial) and (int(ID) + 1) or 0 - serialFile.close() - serialFile = file(filename, 'w') - serialFile.write('%s %d' % (serial, ID)) - serialFile.close() - serial = serial + ('%02d' % (ID,)) - return serial - - -#class LookupCacherMixin(object): -# _cache = None -# -# def _lookup(self, name, cls, type, timeout = 10): -# if not self._cache: -# self._cache = {} -# self._meth = super(LookupCacherMixin, self)._lookup -# -# if self._cache.has_key((name, cls, type)): -# return self._cache[(name, cls, type)] -# else: -# r = self._meth(name, cls, type, timeout) -# self._cache[(name, cls, type)] = r -# return r - - - -class FileAuthority(common.ResolverBase): - """ - An Authority that is loaded from a file. - - @ivar _ADDITIONAL_PROCESSING_TYPES: Record types for which additional - processing will be done. - @ivar _ADDRESS_TYPES: Record types which are useful for inclusion in the - additional section generated during additional processing. - """ - # See https://twistedmatrix.com/trac/ticket/6650 - _ADDITIONAL_PROCESSING_TYPES = (dns.CNAME, dns.MX, dns.NS) - _ADDRESS_TYPES = (dns.A, dns.AAAA) - - soa = None - records = None - - def __init__(self, filename): - common.ResolverBase.__init__(self) - self.loadFile(filename) - self._cache = {} - - - def __setstate__(self, state): - self.__dict__ = state -# print 'setstate ', self.soa - - - def _additionalRecords(self, answer, authority, ttl): - """ - Find locally known information that could be useful to the consumer of - the response and construct appropriate records to include in the - I{additional} section of that response. - - Essentially, implement RFC 1034 section 4.3.2 step 6. - - @param answer: A L{list} of the records which will be included in the - I{answer} section of the response. - - @param authority: A L{list} of the records which will be included in - the I{authority} section of the response. - - @param ttl: The default TTL for records for which this is not otherwise - specified. - - @return: A generator of L{dns.RRHeader} instances for inclusion in the - I{additional} section. These instances represent extra information - about the records in C{answer} and C{authority}. - """ - for record in answer + authority: - if record.type in self._ADDITIONAL_PROCESSING_TYPES: - name = record.payload.name.name - for rec in self.records.get(name.lower(), ()): - if rec.TYPE in self._ADDRESS_TYPES: - yield dns.RRHeader( - name, rec.TYPE, dns.IN, - rec.ttl or ttl, rec, auth=True) - - - def _lookup(self, name, cls, type, timeout = None): - """ - Determine a response to a particular DNS query. - - @param name: The name which is being queried and for which to lookup a - response. - @type name: L{bytes} - - @param cls: The class which is being queried. Only I{IN} is - implemented here and this value is presently disregarded. - @type cls: L{int} - - @param type: The type of records being queried. See the types defined - in L{twisted.names.dns}. - @type type: L{int} - - @param timeout: All processing is done locally and a result is - available immediately, so the timeout value is ignored. - - @return: A L{Deferred} that fires with a L{tuple} of three sets of - response records (to comprise the I{answer}, I{authority}, and - I{additional} sections of a DNS response) or with a L{Failure} if - there is a problem processing the query. - """ - cnames = [] - results = [] - authority = [] - additional = [] - default_ttl = max(self.soa[1].minimum, self.soa[1].expire) - - domain_records = self.records.get(name.lower()) - - if domain_records: - for record in domain_records: - if record.ttl is not None: - ttl = record.ttl - else: - ttl = default_ttl - - if record.TYPE == dns.NS and name.lower() != self.soa[0].lower(): - # NS record belong to a child zone: this is a referral. As - # NS records are authoritative in the child zone, ours here - # are not. RFC 2181, section 6.1. - authority.append( - dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=False) - ) - elif record.TYPE == type or type == dns.ALL_RECORDS: - results.append( - dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=True) - ) - if record.TYPE == dns.CNAME: - cnames.append( - dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=True) - ) - if not results: - results = cnames - - # https://tools.ietf.org/html/rfc1034#section-4.3.2 - sort of. - # See https://twistedmatrix.com/trac/ticket/6732 - additionalInformation = self._additionalRecords( - results, authority, default_ttl) - if cnames: - results.extend(additionalInformation) - else: - additional.extend(additionalInformation) - - if not results and not authority: - # Empty response. Include SOA record to allow clients to cache - # this response. RFC 1034, sections 3.7 and 4.3.4, and RFC 2181 - # section 7.1. - authority.append( - dns.RRHeader(self.soa[0], dns.SOA, dns.IN, ttl, self.soa[1], auth=True) - ) - return defer.succeed((results, authority, additional)) - else: - if dns._isSubdomainOf(name, self.soa[0]): - # We may be the authority and we didn't find it. - # XXX: The QNAME may also be a in a delegated child zone. See - # #6581 and #6580 - return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name))) - else: - # The QNAME is not a descendant of this zone. Fail with - # DomainError so that the next chained authority or - # resolver will be queried. - return defer.fail(failure.Failure(error.DomainError(name))) - - - def lookupZone(self, name, timeout = 10): - if self.soa[0].lower() == name.lower(): - # Wee hee hee hooo yea - default_ttl = max(self.soa[1].minimum, self.soa[1].expire) - if self.soa[1].ttl is not None: - soa_ttl = self.soa[1].ttl - else: - soa_ttl = default_ttl - results = [dns.RRHeader(self.soa[0], dns.SOA, dns.IN, soa_ttl, self.soa[1], auth=True)] - for (k, r) in self.records.items(): - for rec in r: - if rec.ttl is not None: - ttl = rec.ttl - else: - ttl = default_ttl - if rec.TYPE != dns.SOA: - results.append(dns.RRHeader(k, rec.TYPE, dns.IN, ttl, rec, auth=True)) - results.append(results[0]) - return defer.succeed((results, (), ())) - return defer.fail(failure.Failure(dns.DomainError(name))) - - def _cbAllRecords(self, results): - ans, auth, add = [], [], [] - for res in results: - if res[0]: - ans.extend(res[1][0]) - auth.extend(res[1][1]) - add.extend(res[1][2]) - return ans, auth, add - - -class PySourceAuthority(FileAuthority): - """A FileAuthority that is built up from Python source code.""" - - def loadFile(self, filename): - g, l = self.setupConfigNamespace(), {} - execfile(filename, g, l) - if not l.has_key('zone'): - raise ValueError, "No zone defined in " + filename - - self.records = {} - for rr in l['zone']: - if isinstance(rr[1], dns.Record_SOA): - self.soa = rr - self.records.setdefault(rr[0].lower(), []).append(rr[1]) - - - def wrapRecord(self, type): - return lambda name, *arg, **kw: (name, type(*arg, **kw)) - - - def setupConfigNamespace(self): - r = {} - items = dns.__dict__.iterkeys() - for record in [x for x in items if x.startswith('Record_')]: - type = getattr(dns, record) - f = self.wrapRecord(type) - r[record[len('Record_'):]] = f - return r - - -class BindAuthority(FileAuthority): - """An Authority that loads BIND configuration files""" - - def loadFile(self, filename): - self.origin = os.path.basename(filename) + '.' # XXX - this might suck - lines = open(filename).readlines() - lines = self.stripComments(lines) - lines = self.collapseContinuations(lines) - self.parseLines(lines) - - - def stripComments(self, lines): - return [ - a.find(';') == -1 and a or a[:a.find(';')] for a in [ - b.strip() for b in lines - ] - ] - - - def collapseContinuations(self, lines): - L = [] - state = 0 - for line in lines: - if state == 0: - if line.find('(') == -1: - L.append(line) - else: - L.append(line[:line.find('(')]) - state = 1 - else: - if line.find(')') != -1: - L[-1] += ' ' + line[:line.find(')')] - state = 0 - else: - L[-1] += ' ' + line - lines = L - L = [] - for line in lines: - L.append(line.split()) - return filter(None, L) - - - def parseLines(self, lines): - TTL = 60 * 60 * 3 - ORIGIN = self.origin - - self.records = {} - - for (line, index) in zip(lines, range(len(lines))): - if line[0] == '$TTL': - TTL = dns.str2time(line[1]) - elif line[0] == '$ORIGIN': - ORIGIN = line[1] - elif line[0] == '$INCLUDE': # XXX - oh, fuck me - raise NotImplementedError('$INCLUDE directive not implemented') - elif line[0] == '$GENERATE': - raise NotImplementedError('$GENERATE directive not implemented') - else: - self.parseRecordLine(ORIGIN, TTL, line) - - - def addRecord(self, owner, ttl, type, domain, cls, rdata): - if not domain.endswith('.'): - domain = domain + '.' + owner - else: - domain = domain[:-1] - f = getattr(self, 'class_%s' % cls, None) - if f: - f(ttl, type, domain, rdata) - else: - raise NotImplementedError, "Record class %r not supported" % cls - - - def class_IN(self, ttl, type, domain, rdata): - record = getattr(dns, 'Record_%s' % type, None) - if record: - r = record(*rdata) - r.ttl = ttl - self.records.setdefault(domain.lower(), []).append(r) - - print 'Adding IN Record', domain, ttl, r - if type == 'SOA': - self.soa = (domain, r) - else: - raise NotImplementedError, "Record type %r not supported" % type - - - # - # This file ends here. Read no further. - # - def parseRecordLine(self, origin, ttl, line): - MARKERS = dns.QUERY_CLASSES.values() + dns.QUERY_TYPES.values() - cls = 'IN' - owner = origin - - if line[0] == '@': - line = line[1:] - owner = origin -# print 'default owner' - elif not line[0].isdigit() and line[0] not in MARKERS: - owner = line[0] - line = line[1:] -# print 'owner is ', owner - - if line[0].isdigit() or line[0] in MARKERS: - domain = owner - owner = origin -# print 'woops, owner is ', owner, ' domain is ', domain - else: - domain = line[0] - line = line[1:] -# print 'domain is ', domain - - if line[0] in dns.QUERY_CLASSES.values(): - cls = line[0] - line = line[1:] -# print 'cls is ', cls - if line[0].isdigit(): - ttl = int(line[0]) - line = line[1:] -# print 'ttl is ', ttl - elif line[0].isdigit(): - ttl = int(line[0]) - line = line[1:] -# print 'ttl is ', ttl - if line[0] in dns.QUERY_CLASSES.values(): - cls = line[0] - line = line[1:] -# print 'cls is ', cls - - type = line[0] -# print 'type is ', type - rdata = line[1:] -# print 'rdata is ', rdata - - self.addRecord(owner, ttl, type, domain, cls, rdata) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/cache.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/cache.py deleted file mode 100644 index fbd83c2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/cache.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- test-case-name: twisted.names.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An in-memory caching resolver. -""" - -from __future__ import division, absolute_import - -from twisted.names import dns, common -from twisted.python import failure, log -from twisted.internet import defer - - - -class CacheResolver(common.ResolverBase): - """ - A resolver that serves records from a local, memory cache. - - @ivar _reactor: A provider of L{interfaces.IReactorTime}. - """ - cache = None - - def __init__(self, cache=None, verbose=0, reactor=None): - common.ResolverBase.__init__(self) - - self.cache = {} - self.verbose = verbose - self.cancel = {} - if reactor is None: - from twisted.internet import reactor - self._reactor = reactor - - if cache: - for query, (seconds, payload) in cache.items(): - self.cacheResult(query, payload, seconds) - - - def __setstate__(self, state): - self.__dict__ = state - - now = self._reactor.seconds() - for (k, (when, (ans, add, ns))) in self.cache.items(): - diff = now - when - for rec in ans + add + ns: - if rec.ttl < diff: - del self.cache[k] - break - - - def __getstate__(self): - for c in self.cancel.values(): - c.cancel() - self.cancel.clear() - return self.__dict__ - - - def _lookup(self, name, cls, type, timeout): - now = self._reactor.seconds() - q = dns.Query(name, type, cls) - try: - when, (ans, auth, add) = self.cache[q] - except KeyError: - if self.verbose > 1: - log.msg('Cache miss for ' + repr(name)) - return defer.fail(failure.Failure(dns.DomainError(name))) - else: - if self.verbose: - log.msg('Cache hit for ' + repr(name)) - diff = now - when - - try: - result = ( - [dns.RRHeader(r.name.name, r.type, r.cls, r.ttl - diff, - r.payload) for r in ans], - [dns.RRHeader(r.name.name, r.type, r.cls, r.ttl - diff, - r.payload) for r in auth], - [dns.RRHeader(r.name.name, r.type, r.cls, r.ttl - diff, - r.payload) for r in add]) - except ValueError: - return defer.fail(failure.Failure(dns.DomainError(name))) - else: - return defer.succeed(result) - - - def lookupAllRecords(self, name, timeout = None): - return defer.fail(failure.Failure(dns.DomainError(name))) - - - def cacheResult(self, query, payload, cacheTime=None): - """ - Cache a DNS entry. - - @param query: a L{dns.Query} instance. - - @param payload: a 3-tuple of lists of L{dns.RRHeader} records, the - matching result of the query (answers, authority and additional). - - @param cacheTime: The time (seconds since epoch) at which the entry is - considered to have been added to the cache. If C{None} is given, - the current time is used. - """ - if self.verbose > 1: - log.msg('Adding %r to cache' % query) - - self.cache[query] = (cacheTime or self._reactor.seconds(), payload) - - if query in self.cancel: - self.cancel[query].cancel() - - s = list(payload[0]) + list(payload[1]) + list(payload[2]) - if s: - m = s[0].ttl - for r in s: - m = min(m, r.ttl) - else: - m = 0 - - self.cancel[query] = self._reactor.callLater(m, self.clearEntry, query) - - - def clearEntry(self, query): - del self.cache[query] - del self.cancel[query] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/client.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/client.py deleted file mode 100644 index e5e8176..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/client.py +++ /dev/null @@ -1,749 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Asynchronous client DNS - -The functions exposed in this module can be used for asynchronous name -resolution and dns queries. - -If you need to create a resolver with specific requirements, such as needing to -do queries against a particular host, the L{createResolver} function will -return an C{IResolver}. - -Future plans: Proper nameserver acquisition on Windows/MacOS, -better caching, respect timeouts -""" - -import os -import errno -import warnings - -from zope.interface import moduleProvides - -# Twisted imports -from twisted.python.compat import nativeString -from twisted.python.runtime import platform -from twisted.python.filepath import FilePath -from twisted.internet import error, defer, interfaces, protocol -from twisted.python import log, failure -from twisted.names import ( - dns, common, resolve, cache, root, hosts as hostsModule) - - - -moduleProvides(interfaces.IResolver) - - - -class Resolver(common.ResolverBase): - """ - @ivar _waiting: A C{dict} mapping tuple keys of query name/type/class to - Deferreds which will be called back with the result of those queries. - This is used to avoid issuing the same query more than once in - parallel. This is more efficient on the network and helps avoid a - "birthday paradox" attack by keeping the number of outstanding requests - for a particular query fixed at one instead of allowing the attacker to - raise it to an arbitrary number. - - @ivar _reactor: A provider of L{IReactorTCP}, L{IReactorUDP}, and - L{IReactorTime} which will be used to set up network resources and - track timeouts. - """ - index = 0 - timeout = None - - factory = None - servers = None - dynServers = () - pending = None - connections = None - - resolv = None - _lastResolvTime = None - _resolvReadInterval = 60 - - def __init__(self, resolv=None, servers=None, timeout=(1, 3, 11, 45), reactor=None): - """ - Construct a resolver which will query domain name servers listed in - the C{resolv.conf(5)}-format file given by C{resolv} as well as - those in the given C{servers} list. Servers are queried in a - round-robin fashion. If given, C{resolv} is periodically checked - for modification and re-parsed if it is noticed to have changed. - - @type servers: C{list} of C{(str, int)} or C{None} - @param servers: If not None, interpreted as a list of (host, port) - pairs specifying addresses of domain name servers to attempt to use - for this lookup. Host addresses should be in IPv4 dotted-quad - form. If specified, overrides C{resolv}. - - @type resolv: C{str} - @param resolv: Filename to read and parse as a resolver(5) - configuration file. - - @type timeout: Sequence of C{int} - @param timeout: Default number of seconds after which to reissue the - query. When the last timeout expires, the query is considered - failed. - - @param reactor: A provider of L{IReactorTime}, L{IReactorUDP}, and - L{IReactorTCP} which will be used to establish connections, listen - for DNS datagrams, and enforce timeouts. If not provided, the - global reactor will be used. - - @raise ValueError: Raised if no nameserver addresses can be found. - """ - common.ResolverBase.__init__(self) - - if reactor is None: - from twisted.internet import reactor - self._reactor = reactor - - self.timeout = timeout - - if servers is None: - self.servers = [] - else: - self.servers = servers - - self.resolv = resolv - - if not len(self.servers) and not resolv: - raise ValueError("No nameservers specified") - - self.factory = DNSClientFactory(self, timeout) - self.factory.noisy = 0 # Be quiet by default - - self.connections = [] - self.pending = [] - - self._waiting = {} - - self.maybeParseConfig() - - - def __getstate__(self): - d = self.__dict__.copy() - d['connections'] = [] - d['_parseCall'] = None - return d - - - def __setstate__(self, state): - self.__dict__.update(state) - self.maybeParseConfig() - - - def _openFile(self, path): - """ - Wrapper used for opening files in the class, exists primarily for unit - testing purposes. - """ - return FilePath(path).open() - - - def maybeParseConfig(self): - if self.resolv is None: - # Don't try to parse it, don't set up a call loop - return - - try: - resolvConf = self._openFile(self.resolv) - except IOError as e: - if e.errno == errno.ENOENT: - # Missing resolv.conf is treated the same as an empty resolv.conf - self.parseConfig(()) - else: - raise - else: - mtime = os.fstat(resolvConf.fileno()).st_mtime - if mtime != self._lastResolvTime: - log.msg('%s changed, reparsing' % (self.resolv,)) - self._lastResolvTime = mtime - self.parseConfig(resolvConf) - resolvConf.close() - - # Check again in a little while - self._parseCall = self._reactor.callLater( - self._resolvReadInterval, self.maybeParseConfig) - - - def parseConfig(self, resolvConf): - servers = [] - for L in resolvConf: - L = L.strip() - if L.startswith(b'nameserver'): - resolver = (nativeString(L.split()[1]), dns.PORT) - servers.append(resolver) - log.msg("Resolver added %r to server list" % (resolver,)) - elif L.startswith(b'domain'): - try: - self.domain = L.split()[1] - except IndexError: - self.domain = b'' - self.search = None - elif L.startswith(b'search'): - self.search = L.split()[1:] - self.domain = None - if not servers: - servers.append(('127.0.0.1', dns.PORT)) - self.dynServers = servers - - - def pickServer(self): - """ - Return the address of a nameserver. - - TODO: Weight servers for response time so faster ones can be - preferred. - """ - if not self.servers and not self.dynServers: - return None - serverL = len(self.servers) - dynL = len(self.dynServers) - - self.index += 1 - self.index %= (serverL + dynL) - if self.index < serverL: - return self.servers[self.index] - else: - return self.dynServers[self.index - serverL] - - - def _connectedProtocol(self): - """ - Return a new L{DNSDatagramProtocol} bound to a randomly selected port - number. - """ - proto = dns.DNSDatagramProtocol(self, reactor=self._reactor) - while True: - try: - self._reactor.listenUDP(dns.randomSource(), proto) - except error.CannotListenError: - pass - else: - return proto - - - def connectionMade(self, protocol): - """ - Called by associated L{dns.DNSProtocol} instances when they connect. - """ - self.connections.append(protocol) - for (d, q, t) in self.pending: - self.queryTCP(q, t).chainDeferred(d) - del self.pending[:] - - - def connectionLost(self, protocol): - """ - Called by associated L{dns.DNSProtocol} instances when they disconnect. - """ - if protocol in self.connections: - self.connections.remove(protocol) - - - def messageReceived(self, message, protocol, address = None): - log.msg("Unexpected message (%d) received from %r" % (message.id, address)) - - - def _query(self, *args): - """ - Get a new L{DNSDatagramProtocol} instance from L{_connectedProtocol}, - issue a query to it using C{*args}, and arrange for it to be - disconnected from its transport after the query completes. - - @param *args: Positional arguments to be passed to - L{DNSDatagramProtocol.query}. - - @return: A L{Deferred} which will be called back with the result of the - query. - """ - protocol = self._connectedProtocol() - d = protocol.query(*args) - def cbQueried(result): - protocol.transport.stopListening() - return result - d.addBoth(cbQueried) - return d - - - def queryUDP(self, queries, timeout = None): - """ - Make a number of DNS queries via UDP. - - @type queries: A C{list} of C{dns.Query} instances - @param queries: The queries to make. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - @raise C{twisted.internet.defer.TimeoutError}: When the query times - out. - """ - if timeout is None: - timeout = self.timeout - - addresses = self.servers + list(self.dynServers) - if not addresses: - return defer.fail(IOError("No domain name servers available")) - - # Make sure we go through servers in the list in the order they were - # specified. - addresses.reverse() - - used = addresses.pop() - d = self._query(used, queries, timeout[0]) - d.addErrback(self._reissue, addresses, [used], queries, timeout) - return d - - - def _reissue(self, reason, addressesLeft, addressesUsed, query, timeout): - reason.trap(dns.DNSQueryTimeoutError) - - # If there are no servers left to be tried, adjust the timeout - # to the next longest timeout period and move all the - # "used" addresses back to the list of addresses to try. - if not addressesLeft: - addressesLeft = addressesUsed - addressesLeft.reverse() - addressesUsed = [] - timeout = timeout[1:] - - # If all timeout values have been used this query has failed. Tell the - # protocol we're giving up on it and return a terminal timeout failure - # to our caller. - if not timeout: - return failure.Failure(defer.TimeoutError(query)) - - # Get an address to try. Take it out of the list of addresses - # to try and put it ino the list of already tried addresses. - address = addressesLeft.pop() - addressesUsed.append(address) - - # Issue a query to a server. Use the current timeout. Add this - # function as a timeout errback in case another retry is required. - d = self._query(address, query, timeout[0], reason.value.id) - d.addErrback(self._reissue, addressesLeft, addressesUsed, query, timeout) - return d - - - def queryTCP(self, queries, timeout = 10): - """ - Make a number of DNS queries via TCP. - - @type queries: Any non-zero number of C{dns.Query} instances - @param queries: The queries to make. - - @type timeout: C{int} - @param timeout: The number of seconds after which to fail. - - @rtype: C{Deferred} - """ - if not len(self.connections): - address = self.pickServer() - if address is None: - return defer.fail(IOError("No domain name servers available")) - host, port = address - self._reactor.connectTCP(host, port, self.factory) - self.pending.append((defer.Deferred(), queries, timeout)) - return self.pending[-1][0] - else: - return self.connections[0].query(queries, timeout) - - - def filterAnswers(self, message): - """ - Extract results from the given message. - - If the message was truncated, re-attempt the query over TCP and return - a Deferred which will fire with the results of that query. - - If the message's result code is not L{dns.OK}, return a Failure - indicating the type of error which occurred. - - Otherwise, return a three-tuple of lists containing the results from - the answers section, the authority section, and the additional section. - """ - if message.trunc: - return self.queryTCP(message.queries).addCallback(self.filterAnswers) - if message.rCode != dns.OK: - return failure.Failure(self.exceptionForCode(message.rCode)(message)) - return (message.answers, message.authority, message.additional) - - - def _lookup(self, name, cls, type, timeout): - """ - Build a L{dns.Query} for the given parameters and dispatch it via UDP. - - If this query is already outstanding, it will not be re-issued. - Instead, when the outstanding query receives a response, that response - will be re-used for this query as well. - - @type name: C{str} - @type type: C{int} - @type cls: C{int} - - @return: A L{Deferred} which fires with a three-tuple giving the - answer, authority, and additional sections of the response or with - a L{Failure} if the response code is anything other than C{dns.OK}. - """ - key = (name, type, cls) - waiting = self._waiting.get(key) - if waiting is None: - self._waiting[key] = [] - d = self.queryUDP([dns.Query(name, type, cls)], timeout) - def cbResult(result): - for d in self._waiting.pop(key): - d.callback(result) - return result - d.addCallback(self.filterAnswers) - d.addBoth(cbResult) - else: - d = defer.Deferred() - waiting.append(d) - return d - - - # This one doesn't ever belong on UDP - def lookupZone(self, name, timeout=10): - address = self.pickServer() - if address is None: - return defer.fail(IOError('No domain name servers available')) - host, port = address - d = defer.Deferred() - controller = AXFRController(name, d) - factory = DNSClientFactory(controller, timeout) - factory.noisy = False #stfu - - connector = self._reactor.connectTCP(host, port, factory) - controller.timeoutCall = self._reactor.callLater( - timeout or 10, self._timeoutZone, d, controller, - connector, timeout or 10) - return d.addCallback(self._cbLookupZone, connector) - - - def _timeoutZone(self, d, controller, connector, seconds): - connector.disconnect() - controller.timeoutCall = None - controller.deferred = None - d.errback(error.TimeoutError("Zone lookup timed out after %d seconds" % (seconds,))) - - - def _cbLookupZone(self, result, connector): - connector.disconnect() - return (result, [], []) - - - -class AXFRController: - timeoutCall = None - - def __init__(self, name, deferred): - self.name = name - self.deferred = deferred - self.soa = None - self.records = [] - - - def connectionMade(self, protocol): - # dig saids recursion-desired to 0, so I will too - message = dns.Message(protocol.pickID(), recDes=0) - message.queries = [dns.Query(self.name, dns.AXFR, dns.IN)] - protocol.writeMessage(message) - - - def connectionLost(self, protocol): - # XXX Do something here - see #3428 - pass - - - def messageReceived(self, message, protocol): - # Caveat: We have to handle two cases: All records are in 1 - # message, or all records are in N messages. - - # According to http://cr.yp.to/djbdns/axfr-notes.html, - # 'authority' and 'additional' are always empty, and only - # 'answers' is present. - self.records.extend(message.answers) - if not self.records: - return - if not self.soa: - if self.records[0].type == dns.SOA: - #print "first SOA!" - self.soa = self.records[0] - if len(self.records) > 1 and self.records[-1].type == dns.SOA: - #print "It's the second SOA! We're done." - if self.timeoutCall is not None: - self.timeoutCall.cancel() - self.timeoutCall = None - if self.deferred is not None: - self.deferred.callback(self.records) - self.deferred = None - - - -from twisted.internet.base import ThreadedResolver as _ThreadedResolverImpl - -class ThreadedResolver(_ThreadedResolverImpl): - def __init__(self, reactor=None): - if reactor is None: - from twisted.internet import reactor - _ThreadedResolverImpl.__init__(self, reactor) - warnings.warn( - "twisted.names.client.ThreadedResolver is deprecated since " - "Twisted 9.0, use twisted.internet.base.ThreadedResolver " - "instead.", - category=DeprecationWarning, stacklevel=2) - - - -class DNSClientFactory(protocol.ClientFactory): - def __init__(self, controller, timeout = 10): - self.controller = controller - self.timeout = timeout - - - def clientConnectionLost(self, connector, reason): - pass - - - def clientConnectionFailed(self, connector, reason): - """ - Fail all pending TCP DNS queries if the TCP connection attempt - fails. - - @see: L{twisted.internet.protocol.ClientFactory} - - @param connector: Not used. - @type connector: L{twisted.internet.interfaces.IConnector} - - @param reason: A C{Failure} containing information about the - cause of the connection failure. This will be passed as the - argument to C{errback} on every pending TCP query - C{deferred}. - @type reason: L{twisted.python.failure.Failure} - """ - # Copy the current pending deferreds then reset the master - # pending list. This prevents triggering new deferreds which - # may be added by callback or errback functions on the current - # deferreds. - pending = self.controller.pending[:] - del self.controller.pending[:] - for d, query, timeout in pending: - d.errback(reason) - - - def buildProtocol(self, addr): - p = dns.DNSProtocol(self.controller) - p.factory = self - return p - - - -def createResolver(servers=None, resolvconf=None, hosts=None): - """ - Create and return a Resolver. - - @type servers: C{list} of C{(str, int)} or C{None} - - @param servers: If not C{None}, interpreted as a list of domain name servers - to attempt to use. Each server is a tuple of address in C{str} dotted-quad - form and C{int} port number. - - @type resolvconf: C{str} or C{None} - @param resolvconf: If not C{None}, on posix systems will be interpreted as - an alternate resolv.conf to use. Will do nothing on windows systems. If - C{None}, /etc/resolv.conf will be used. - - @type hosts: C{str} or C{None} - @param hosts: If not C{None}, an alternate hosts file to use. If C{None} - on posix systems, /etc/hosts will be used. On windows, C:\windows\hosts - will be used. - - @rtype: C{IResolver} - """ - if platform.getType() == 'posix': - if resolvconf is None: - resolvconf = b'/etc/resolv.conf' - if hosts is None: - hosts = b'/etc/hosts' - theResolver = Resolver(resolvconf, servers) - hostResolver = hostsModule.Resolver(hosts) - else: - if hosts is None: - hosts = r'c:\windows\hosts' - from twisted.internet import reactor - bootstrap = _ThreadedResolverImpl(reactor) - hostResolver = hostsModule.Resolver(hosts) - theResolver = root.bootstrap(bootstrap, resolverFactory=Resolver) - - L = [hostResolver, cache.CacheResolver(), theResolver] - return resolve.ResolverChain(L) - - - -theResolver = None -def getResolver(): - """ - Get a Resolver instance. - - Create twisted.names.client.theResolver if it is C{None}, and then return - that value. - - @rtype: C{IResolver} - """ - global theResolver - if theResolver is None: - try: - theResolver = createResolver() - except ValueError: - theResolver = createResolver(servers=[('127.0.0.1', 53)]) - return theResolver - - - -def getHostByName(name, timeout=None, effort=10): - """ - Resolve a name to a valid ipv4 or ipv6 address. - - Will errback with C{DNSQueryTimeoutError} on a timeout, C{DomainError} or - C{AuthoritativeDomainError} (or subclasses) on other errors. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @type effort: C{int} - @param effort: How many times CNAME and NS records to follow while - resolving this name. - - @rtype: C{Deferred} - """ - return getResolver().getHostByName(name, timeout, effort) - - - -def query(query, timeout=None): - return getResolver().query(query, timeout) - - - -def lookupAddress(name, timeout=None): - return getResolver().lookupAddress(name, timeout) - - - -def lookupIPV6Address(name, timeout=None): - return getResolver().lookupIPV6Address(name, timeout) - - - -def lookupAddress6(name, timeout=None): - return getResolver().lookupAddress6(name, timeout) - - - -def lookupMailExchange(name, timeout=None): - return getResolver().lookupMailExchange(name, timeout) - - - -def lookupNameservers(name, timeout=None): - return getResolver().lookupNameservers(name, timeout) - - - -def lookupCanonicalName(name, timeout=None): - return getResolver().lookupCanonicalName(name, timeout) - - - -def lookupMailBox(name, timeout=None): - return getResolver().lookupMailBox(name, timeout) - - - -def lookupMailGroup(name, timeout=None): - return getResolver().lookupMailGroup(name, timeout) - - - -def lookupMailRename(name, timeout=None): - return getResolver().lookupMailRename(name, timeout) - - - -def lookupPointer(name, timeout=None): - return getResolver().lookupPointer(name, timeout) - - - -def lookupAuthority(name, timeout=None): - return getResolver().lookupAuthority(name, timeout) - - - -def lookupNull(name, timeout=None): - return getResolver().lookupNull(name, timeout) - - - -def lookupWellKnownServices(name, timeout=None): - return getResolver().lookupWellKnownServices(name, timeout) - - - -def lookupService(name, timeout=None): - return getResolver().lookupService(name, timeout) - - - -def lookupHostInfo(name, timeout=None): - return getResolver().lookupHostInfo(name, timeout) - - - -def lookupMailboxInfo(name, timeout=None): - return getResolver().lookupMailboxInfo(name, timeout) - - - -def lookupText(name, timeout=None): - return getResolver().lookupText(name, timeout) - - - -def lookupSenderPolicy(name, timeout=None): - return getResolver().lookupSenderPolicy(name, timeout) - - - -def lookupResponsibility(name, timeout=None): - return getResolver().lookupResponsibility(name, timeout) - - - -def lookupAFSDatabase(name, timeout=None): - return getResolver().lookupAFSDatabase(name, timeout) - - - -def lookupZone(name, timeout=None): - return getResolver().lookupZone(name, timeout) - - - -def lookupAllRecords(name, timeout=None): - return getResolver().lookupAllRecords(name, timeout) - - - -def lookupNamingAuthorityPointer(name, timeout=None): - return getResolver().lookupNamingAuthorityPointer(name, timeout) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/common.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/common.py deleted file mode 100644 index f4d961c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/common.py +++ /dev/null @@ -1,250 +0,0 @@ -# -*- test-case-name: twisted.names.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Base functionality useful to various parts of Twisted Names. -""" - -from __future__ import division, absolute_import - -import socket - -from zope.interface import implementer - -from twisted.names import dns -from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError -from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError -from twisted.names.error import DNSUnknownError - -from twisted.internet import defer, error, interfaces -from twisted.python import failure - -# Helpers for indexing the three-tuples that get thrown around by this code a -# lot. -_ANS, _AUTH, _ADD = range(3) - -EMPTY_RESULT = (), (), () - - - -@implementer(interfaces.IResolver) -class ResolverBase: - """ - L{ResolverBase} is a base class for implementations of - L{interfaces.IResolver} which deals with a lot - of the boilerplate of implementing all of the lookup methods. - - @cvar _errormap: A C{dict} mapping DNS protocol failure response codes - to exception classes which will be used to represent those failures. - """ - _errormap = { - dns.EFORMAT: DNSFormatError, - dns.ESERVER: DNSServerError, - dns.ENAME: DNSNameError, - dns.ENOTIMP: DNSNotImplementedError, - dns.EREFUSED: DNSQueryRefusedError} - - typeToMethod = None - - def __init__(self): - self.typeToMethod = {} - for (k, v) in typeToMethod.items(): - self.typeToMethod[k] = getattr(self, v) - - - def exceptionForCode(self, responseCode): - """ - Convert a response code (one of the possible values of - L{dns.Message.rCode} to an exception instance representing it. - - @since: 10.0 - """ - return self._errormap.get(responseCode, DNSUnknownError) - - - def query(self, query, timeout=None): - try: - method = self.typeToMethod[query.type] - except KeyError: - return defer.fail(failure.Failure(NotImplementedError( - str(self.__class__) + " " + str(query.type)))) - else: - return defer.maybeDeferred(method, query.name.name, timeout) - - - def _lookup(self, name, cls, type, timeout): - return defer.fail(NotImplementedError("ResolverBase._lookup")) - - - def lookupAddress(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.A, timeout) - - - def lookupIPV6Address(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.AAAA, timeout) - - - def lookupAddress6(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.A6, timeout) - - - def lookupMailExchange(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.MX, timeout) - - - def lookupNameservers(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.NS, timeout) - - - def lookupCanonicalName(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.CNAME, timeout) - - - def lookupMailBox(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.MB, timeout) - - - def lookupMailGroup(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.MG, timeout) - - - def lookupMailRename(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.MR, timeout) - - - def lookupPointer(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.PTR, timeout) - - - def lookupAuthority(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.SOA, timeout) - - - def lookupNull(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.NULL, timeout) - - - def lookupWellKnownServices(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.WKS, timeout) - - - def lookupService(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.SRV, timeout) - - - def lookupHostInfo(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.HINFO, timeout) - - - def lookupMailboxInfo(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.MINFO, timeout) - - - def lookupText(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.TXT, timeout) - - - def lookupSenderPolicy(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.SPF, timeout) - - - def lookupResponsibility(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.RP, timeout) - - - def lookupAFSDatabase(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.AFSDB, timeout) - - - def lookupZone(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.AXFR, timeout) - - - def lookupNamingAuthorityPointer(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.NAPTR, timeout) - - - def lookupAllRecords(self, name, timeout=None): - return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) - - - # IResolverSimple - def getHostByName(self, name, timeout=None, effort=10): - # XXX - respect timeout - return self.lookupAllRecords(name, timeout - ).addCallback(self._cbRecords, name, effort - ) - - - def _cbRecords(self, records, name, effort): - (ans, auth, add) = records - result = extractRecord(self, dns.Name(name), ans + auth + add, effort) - if not result: - raise error.DNSLookupError(name) - return result - - - -def extractRecord(resolver, name, answers, level=10): - if not level: - return None - if hasattr(socket, 'inet_ntop'): - for r in answers: - if r.name == name and r.type == dns.A6: - return socket.inet_ntop(socket.AF_INET6, r.payload.address) - for r in answers: - if r.name == name and r.type == dns.AAAA: - return socket.inet_ntop(socket.AF_INET6, r.payload.address) - for r in answers: - if r.name == name and r.type == dns.A: - return socket.inet_ntop(socket.AF_INET, r.payload.address) - for r in answers: - if r.name == name and r.type == dns.CNAME: - result = extractRecord( - resolver, r.payload.name, answers, level - 1) - if not result: - return resolver.getHostByName( - str(r.payload.name), effort=level - 1) - return result - # No answers, but maybe there's a hint at who we should be asking about - # this - for r in answers: - if r.type == dns.NS: - from twisted.names import client - r = client.Resolver(servers=[(str(r.payload.name), dns.PORT)]) - return r.lookupAddress(str(name) - ).addCallback( - lambda records: extractRecord( - r, name, - records[_ANS] + records[_AUTH] + records[_ADD], - level - 1)) - - - -typeToMethod = { - dns.A: 'lookupAddress', - dns.AAAA: 'lookupIPV6Address', - dns.A6: 'lookupAddress6', - dns.NS: 'lookupNameservers', - dns.CNAME: 'lookupCanonicalName', - dns.SOA: 'lookupAuthority', - dns.MB: 'lookupMailBox', - dns.MG: 'lookupMailGroup', - dns.MR: 'lookupMailRename', - dns.NULL: 'lookupNull', - dns.WKS: 'lookupWellKnownServices', - dns.PTR: 'lookupPointer', - dns.HINFO: 'lookupHostInfo', - dns.MINFO: 'lookupMailboxInfo', - dns.MX: 'lookupMailExchange', - dns.TXT: 'lookupText', - dns.SPF: 'lookupSenderPolicy', - - dns.RP: 'lookupResponsibility', - dns.AFSDB: 'lookupAFSDatabase', - dns.SRV: 'lookupService', - dns.NAPTR: 'lookupNamingAuthorityPointer', - dns.AXFR: 'lookupZone', - dns.ALL_RECORDS: 'lookupAllRecords', -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/dns.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/dns.py deleted file mode 100644 index 50fef18..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/dns.py +++ /dev/null @@ -1,2879 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_dns -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -DNS protocol implementation. - -Future Plans: - - Get rid of some toplevels, maybe. -""" - -from __future__ import division, absolute_import - -__all__ = [ - 'IEncodable', 'IRecord', - - 'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'HINFO', - 'MAILA', 'MAILB', 'MB', 'MD', 'MF', 'MG', 'MINFO', 'MR', 'MX', - 'NAPTR', 'NS', 'NULL', 'OPT', 'PTR', 'RP', 'SOA', 'SPF', 'SRV', 'TXT', - 'WKS', - - 'ANY', 'CH', 'CS', 'HS', 'IN', - - 'ALL_RECORDS', 'AXFR', 'IXFR', - - 'EFORMAT', 'ENAME', 'ENOTIMP', 'EREFUSED', 'ESERVER', 'EBADVERSION', - - 'Record_A', 'Record_A6', 'Record_AAAA', 'Record_AFSDB', 'Record_CNAME', - 'Record_DNAME', 'Record_HINFO', 'Record_MB', 'Record_MD', 'Record_MF', - 'Record_MG', 'Record_MINFO', 'Record_MR', 'Record_MX', 'Record_NAPTR', - 'Record_NS', 'Record_NULL', 'Record_PTR', 'Record_RP', 'Record_SOA', - 'Record_SPF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', - - 'QUERY_CLASSES', 'QUERY_TYPES', 'REV_CLASSES', 'REV_TYPES', 'EXT_QUERIES', - - 'Charstr', 'Message', 'Name', 'Query', 'RRHeader', 'SimpleRecord', - 'DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', - - 'OK', 'OP_INVERSE', 'OP_NOTIFY', 'OP_QUERY', 'OP_STATUS', 'OP_UPDATE', - 'PORT', - - 'AuthoritativeDomainError', 'DNSQueryTimeoutError', 'DomainError', - ] - - -# System imports -import inspect, struct, random, socket -from itertools import chain - -from io import BytesIO - -AF_INET6 = socket.AF_INET6 - -from zope.interface import implementer, Interface, Attribute - - -# Twisted imports -from twisted.internet import protocol, defer -from twisted.internet.error import CannotListenError -from twisted.python import log, failure -from twisted.python import util as tputil -from twisted.python import randbytes -from twisted.python.compat import _PY3, unicode, comparable, cmp, nativeString - - -if _PY3: - def _ord2bytes(ordinal): - """ - Construct a bytes object representing a single byte with the given - ordinal value. - - @type ordinal: C{int} - @rtype: C{bytes} - """ - return bytes([ordinal]) - - - def _nicebytes(bytes): - """ - Represent a mostly textful bytes object in a way suitable for presentation - to an end user. - - @param bytes: The bytes to represent. - @rtype: C{str} - """ - return repr(bytes)[1:] - - - def _nicebyteslist(list): - """ - Represent a list of mostly textful bytes objects in a way suitable for - presentation to an end user. - - @param list: The list of bytes to represent. - @rtype: C{str} - """ - return '[%s]' % ( - ', '.join([_nicebytes(b) for b in list]),) -else: - _ord2bytes = chr - _nicebytes = _nicebyteslist = repr - - - -def randomSource(): - """ - Wrapper around L{randbytes.secureRandom} to return 2 random chars. - """ - return struct.unpack('H', randbytes.secureRandom(2, fallback=True))[0] - - -PORT = 53 - -(A, NS, MD, MF, CNAME, SOA, MB, MG, MR, NULL, WKS, PTR, HINFO, MINFO, MX, TXT, - RP, AFSDB) = range(1, 19) -AAAA = 28 -SRV = 33 -NAPTR = 35 -A6 = 38 -DNAME = 39 -OPT = 41 -SPF = 99 - -QUERY_TYPES = { - A: 'A', - NS: 'NS', - MD: 'MD', - MF: 'MF', - CNAME: 'CNAME', - SOA: 'SOA', - MB: 'MB', - MG: 'MG', - MR: 'MR', - NULL: 'NULL', - WKS: 'WKS', - PTR: 'PTR', - HINFO: 'HINFO', - MINFO: 'MINFO', - MX: 'MX', - TXT: 'TXT', - RP: 'RP', - AFSDB: 'AFSDB', - - # 19 through 27? Eh, I'll get to 'em. - - AAAA: 'AAAA', - SRV: 'SRV', - NAPTR: 'NAPTR', - A6: 'A6', - DNAME: 'DNAME', - OPT: 'OPT', - SPF: 'SPF' -} - -IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) - -# "Extended" queries (Hey, half of these are deprecated, good job) -EXT_QUERIES = { - IXFR: 'IXFR', - AXFR: 'AXFR', - MAILB: 'MAILB', - MAILA: 'MAILA', - ALL_RECORDS: 'ALL_RECORDS' -} - -REV_TYPES = dict([ - (v, k) for (k, v) in chain(QUERY_TYPES.items(), EXT_QUERIES.items()) -]) - -IN, CS, CH, HS = range(1, 5) -ANY = 255 - -QUERY_CLASSES = { - IN: 'IN', - CS: 'CS', - CH: 'CH', - HS: 'HS', - ANY: 'ANY' -} -REV_CLASSES = dict([ - (v, k) for (k, v) in QUERY_CLASSES.items() -]) - - -# Opcodes -OP_QUERY, OP_INVERSE, OP_STATUS = range(3) -OP_NOTIFY = 4 # RFC 1996 -OP_UPDATE = 5 # RFC 2136 - - -# Response Codes -OK, EFORMAT, ESERVER, ENAME, ENOTIMP, EREFUSED = range(6) -# https://tools.ietf.org/html/rfc6891#section-9 -EBADVERSION = 16 - -class IRecord(Interface): - """ - An single entry in a zone of authority. - """ - - TYPE = Attribute("An indicator of what kind of record this is.") - - -# Backwards compatibility aliases - these should be deprecated or something I -# suppose. -exarkun -from twisted.names.error import DomainError, AuthoritativeDomainError -from twisted.names.error import DNSQueryTimeoutError - - - -def _nameToLabels(name): - """ - Split a domain name into its constituent labels. - - @type name: C{str} - @param name: A fully qualified domain name (with or without a - trailing dot). - - @return: A L{list} of labels ending with an empty label - representing the DNS root zone. - """ - if name in (b'', b'.'): - return [b''] - labels = name.split(b'.') - if labels[-1] != b'': - labels.append(b'') - return labels - - - -def _isSubdomainOf(descendantName, ancestorName): - """ - Test whether C{descendantName} is equal to or is a I{subdomain} of - C{ancestorName}. - - The names are compared case-insensitively. - - The names are treated as byte strings containing one or more - DNS labels separated by B{.}. - - C{descendantName} is considered equal if its sequence of labels - exactly matches the labels of C{ancestorName}. - - C{descendantName} is considered a I{subdomain} if its sequence of - labels ends with the labels of C{ancestorName}. - - @type descendantName: C{bytes} - @param descendantName: The DNS subdomain name. - - @type ancestorName: C{bytes} - @param ancestorName: The DNS parent or ancestor domain name. - - @return: C{True} if C{descendantName} is equal to or if it is a - subdomain of C{ancestorName}. Otherwise returns C{False}. - """ - descendantLabels = _nameToLabels(descendantName.lower()) - ancestorLabels = _nameToLabels(ancestorName.lower()) - return descendantLabels[-len(ancestorLabels):] == ancestorLabels - - - -def str2time(s): - """ - Parse a string description of an interval into an integer number of seconds. - - @param s: An interval definition constructed as an interval duration - followed by an interval unit. An interval duration is a base ten - representation of an integer. An interval unit is one of the following - letters: S (seconds), M (minutes), H (hours), D (days), W (weeks), or Y - (years). For example: C{"3S"} indicates an interval of three seconds; - C{"5D"} indicates an interval of five days. Alternatively, C{s} may be - any non-string and it will be returned unmodified. - @type s: text string (C{str}) for parsing; anything else for passthrough. - - @return: an C{int} giving the interval represented by the string C{s}, or - whatever C{s} is if it is not a string. - """ - suffixes = ( - ('S', 1), ('M', 60), ('H', 60 * 60), ('D', 60 * 60 * 24), - ('W', 60 * 60 * 24 * 7), ('Y', 60 * 60 * 24 * 365) - ) - if isinstance(s, str): - s = s.upper().strip() - for (suff, mult) in suffixes: - if s.endswith(suff): - return int(float(s[:-1]) * mult) - try: - s = int(s) - except ValueError: - raise ValueError("Invalid time interval specifier: " + s) - return s - - -def readPrecisely(file, l): - buff = file.read(l) - if len(buff) < l: - raise EOFError - return buff - - -class IEncodable(Interface): - """ - Interface for something which can be encoded to and decoded - from a file object. - """ - - def encode(strio, compDict = None): - """ - Write a representation of this object to the given - file object. - - @type strio: File-like object - @param strio: The stream to which to write bytes - - @type compDict: C{dict} or C{None} - @param compDict: A dictionary of backreference addresses that have - already been written to this stream and that may be used for - compression. - """ - - def decode(strio, length = None): - """ - Reconstruct an object from data read from the given - file object. - - @type strio: File-like object - @param strio: The stream from which bytes may be read - - @type length: C{int} or C{None} - @param length: The number of bytes in this RDATA field. Most - implementations can ignore this value. Only in the case of - records similar to TXT where the total length is in no way - encoded in the data is it necessary. - """ - - - -@implementer(IEncodable) -class Charstr(object): - - def __init__(self, string=b''): - if not isinstance(string, bytes): - raise ValueError("%r is not a byte string" % (string,)) - self.string = string - - - def encode(self, strio, compDict=None): - """ - Encode this Character string into the appropriate byte format. - - @type strio: file - @param strio: The byte representation of this Charstr will be written - to this file. - """ - string = self.string - ind = len(string) - strio.write(_ord2bytes(ind)) - strio.write(string) - - - def decode(self, strio, length=None): - """ - Decode a byte string into this Charstr. - - @type strio: file - @param strio: Bytes will be read from this file until the full string - is decoded. - - @raise EOFError: Raised when there are not enough bytes available from - C{strio}. - """ - self.string = b'' - l = ord(readPrecisely(strio, 1)) - self.string = readPrecisely(strio, l) - - - def __eq__(self, other): - if isinstance(other, Charstr): - return self.string == other.string - return NotImplemented - - - def __ne__(self, other): - if isinstance(other, Charstr): - return self.string != other.string - return NotImplemented - - - def __hash__(self): - return hash(self.string) - - - def __str__(self): - """ - Represent this L{Charstr} instance by its string value. - """ - return nativeString(self.string) - - - -@implementer(IEncodable) -class Name: - """ - A name in the domain name system, made up of multiple labels. For example, - I{twistedmatrix.com}. - - @ivar name: A byte string giving the name. - @type name: C{bytes} - """ - def __init__(self, name=b''): - if isinstance(name, unicode): - name = name.encode('idna') - if not isinstance(name, bytes): - raise TypeError("%r is not a byte string" % (name,)) - self.name = name - - - def encode(self, strio, compDict=None): - """ - Encode this Name into the appropriate byte format. - - @type strio: file - @param strio: The byte representation of this Name will be written to - this file. - - @type compDict: dict - @param compDict: dictionary of Names that have already been encoded - and whose addresses may be backreferenced by this Name (for the purpose - of reducing the message size). - """ - name = self.name - while name: - if compDict is not None: - if name in compDict: - strio.write( - struct.pack("!H", 0xc000 | compDict[name])) - return - else: - compDict[name] = strio.tell() + Message.headerSize - ind = name.find(b'.') - if ind > 0: - label, name = name[:ind], name[ind + 1:] - else: - # This is the last label, end the loop after handling it. - label = name - name = None - ind = len(label) - strio.write(_ord2bytes(ind)) - strio.write(label) - strio.write(b'\x00') - - - def decode(self, strio, length=None): - """ - Decode a byte string into this Name. - - @type strio: file - @param strio: Bytes will be read from this file until the full Name - is decoded. - - @raise EOFError: Raised when there are not enough bytes available - from C{strio}. - - @raise ValueError: Raised when the name cannot be decoded (for example, - because it contains a loop). - """ - visited = set() - self.name = b'' - off = 0 - while 1: - l = ord(readPrecisely(strio, 1)) - if l == 0: - if off > 0: - strio.seek(off) - return - if (l >> 6) == 3: - new_off = ((l&63) << 8 - | ord(readPrecisely(strio, 1))) - if new_off in visited: - raise ValueError("Compression loop in encoded name") - visited.add(new_off) - if off == 0: - off = strio.tell() - strio.seek(new_off) - continue - label = readPrecisely(strio, l) - if self.name == b'': - self.name = label - else: - self.name = self.name + b'.' + label - - def __eq__(self, other): - if isinstance(other, Name): - return self.name == other.name - return NotImplemented - - - def __ne__(self, other): - if isinstance(other, Name): - return self.name != other.name - return NotImplemented - - - def __hash__(self): - return hash(self.name) - - - def __str__(self): - """ - Represent this L{Name} instance by its string name. - """ - return nativeString(self.name) - - - -@comparable -@implementer(IEncodable) -class Query: - """ - Represent a single DNS query. - - @ivar name: The name about which this query is requesting information. - @ivar type: The query type. - @ivar cls: The query class. - """ - name = None - type = None - cls = None - - def __init__(self, name=b'', type=A, cls=IN): - """ - @type name: C{bytes} - @param name: The name about which to request information. - - @type type: C{int} - @param type: The query type. - - @type cls: C{int} - @param cls: The query class. - """ - self.name = Name(name) - self.type = type - self.cls = cls - - - def encode(self, strio, compDict=None): - self.name.encode(strio, compDict) - strio.write(struct.pack("!HH", self.type, self.cls)) - - - def decode(self, strio, length = None): - self.name.decode(strio) - buff = readPrecisely(strio, 4) - self.type, self.cls = struct.unpack("!HH", buff) - - - def __hash__(self): - return hash((str(self.name).lower(), self.type, self.cls)) - - - def __cmp__(self, other): - if isinstance(other, Query): - return cmp( - (str(self.name).lower(), self.type, self.cls), - (str(other.name).lower(), other.type, other.cls)) - return NotImplemented - - - def __str__(self): - t = QUERY_TYPES.get(self.type, EXT_QUERIES.get(self.type, 'UNKNOWN (%d)' % self.type)) - c = QUERY_CLASSES.get(self.cls, 'UNKNOWN (%d)' % self.cls) - return '' % (self.name, t, c) - - - def __repr__(self): - return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) - - - -@implementer(IEncodable) -class _OPTHeader(tputil.FancyStrMixin, tputil.FancyEqMixin, object): - """ - An OPT record header. - - @ivar name: The DNS name associated with this record. Since this - is a pseudo record, the name is always an L{Name} instance - with value b'', which represents the DNS root zone. This - attribute is a readonly property. - - @ivar type: The DNS record type. This is a fixed value of 41 - (C{dns.OPT} for OPT Record. This attribute is a readonly - property. - - @see: L{_OPTHeader.__init__} for documentation of other public - instance attributes. - - @see: L{https://tools.ietf.org/html/rfc6891#section-6.1.2} - - @since: 13.2 - """ - showAttributes = ( - ('name', lambda n: nativeString(n.name)), 'type', 'udpPayloadSize', - 'extendedRCODE', 'version', 'dnssecOK', 'options') - - compareAttributes = ( - 'name', 'type', 'udpPayloadSize', 'extendedRCODE', 'version', - 'dnssecOK', 'options') - - def __init__(self, udpPayloadSize=4096, extendedRCODE=0, version=0, - dnssecOK=False, options=None): - """ - @type udpPayloadSize: L{int} - @param payload: The number of octets of the largest UDP - payload that can be reassembled and delivered in the - requestor's network stack. - - @type extendedRCODE: L{int} - @param extendedRCODE: Forms the upper 8 bits of extended - 12-bit RCODE (together with the 4 bits defined in - [RFC1035]. Note that EXTENDED-RCODE value 0 indicates - that an unextended RCODE is in use (values 0 through 15). - - @type version: L{int} - @param version: Indicates the implementation level of the - setter. Full conformance with this specification is - indicated by version C{0}. - - @type dnssecOK: L{bool} - @param dnssecOK: DNSSEC OK bit as defined by [RFC3225]. - - @type options: L{list} - @param options: A L{list} of 0 or more L{_OPTVariableOption} - instances. - """ - self.udpPayloadSize = udpPayloadSize - self.extendedRCODE = extendedRCODE - self.version = version - self.dnssecOK = dnssecOK - - if options is None: - options = [] - self.options = options - - - @property - def name(self): - """ - A readonly property for accessing the C{name} attribute of - this record. - - @return: The DNS name associated with this record. Since this - is a pseudo record, the name is always an L{Name} instance - with value b'', which represents the DNS root zone. - """ - return Name(b'') - - - @property - def type(self): - """ - A readonly property for accessing the C{type} attribute of - this record. - - @return: The DNS record type. This is a fixed value of 41 - (C{dns.OPT} for OPT Record. - """ - return OPT - - - def encode(self, strio, compDict=None): - """ - Encode this L{_OPTHeader} instance to bytes. - - @type strio: L{file} - @param strio: the byte representation of this L{_OPTHeader} - will be written to this file. - - @type compDict: L{dict} or L{None} - @param compDict: A dictionary of backreference addresses that - have already been written to this stream and that may - be used for DNS name compression. - """ - b = BytesIO() - for o in self.options: - o.encode(b) - optionBytes = b.getvalue() - - RRHeader( - name=self.name.name, - type=self.type, - cls=self.udpPayloadSize, - ttl=( - self.extendedRCODE << 24 - | self.version << 16 - | self.dnssecOK << 15), - payload=UnknownRecord(optionBytes) - ).encode(strio, compDict) - - - def decode(self, strio, length=None): - """ - Decode bytes into an L{_OPTHeader} instance. - - @type strio: L{file} - @param strio: Bytes will be read from this file until the full - L{_OPTHeader} is decoded. - - @type length: L{int} or L{None} - @param length: Not used. - """ - - h = RRHeader() - h.decode(strio, length) - h.payload = UnknownRecord(readPrecisely(strio, h.rdlength)) - - newOptHeader = self.fromRRHeader(h) - - for attrName in self.compareAttributes: - if attrName not in ('name', 'type'): - setattr(self, attrName, getattr(newOptHeader, attrName)) - - - @classmethod - def fromRRHeader(cls, rrHeader): - """ - A classmethod for constructing a new L{_OPTHeader} from the - attributes and payload of an existing L{RRHeader} instance. - - @type rrHeader: L{RRHeader} - @param rrHeader: An L{RRHeader} instance containing an - L{UnknownRecord} payload. - - @return: An instance of L{_OPTHeader}. - @rtype: L{_OPTHeader} - """ - options = None - if rrHeader.payload is not None: - options = [] - optionsBytes = BytesIO(rrHeader.payload.data) - optionsBytesLength = len(rrHeader.payload.data) - while optionsBytes.tell() < optionsBytesLength: - o = _OPTVariableOption() - o.decode(optionsBytes) - options.append(o) - - # Decode variable options if present - return cls( - udpPayloadSize=rrHeader.cls, - extendedRCODE=rrHeader.ttl >> 24, - version=rrHeader.ttl >> 16 & 0xff, - dnssecOK=(rrHeader.ttl & 0xffff) >> 15, - options=options - ) - - - -@implementer(IEncodable) -class _OPTVariableOption(tputil.FancyStrMixin, tputil.FancyEqMixin, object): - """ - A class to represent OPT record variable options. - - @see: L{_OPTVariableOption.__init__} for documentation of public - instance attributes. - - @see: L{https://tools.ietf.org/html/rfc6891#section-6.1.2} - - @since: 13.2 - """ - showAttributes = ('code', ('data', nativeString)) - compareAttributes = ('code', 'data') - - _fmt = '!HH' - - def __init__(self, code=0, data=b''): - """ - @type code: L{int} - @param code: The option code - - @type data: L{bytes} - @param data: The option data - """ - self.code = code - self.data = data - - - def encode(self, strio, compDict=None): - """ - Encode this L{_OPTVariableOption} to bytes. - - @type strio: L{file} - @param strio: the byte representation of this - L{_OPTVariableOption} will be written to this file. - - @type compDict: L{dict} or L{None} - @param compDict: A dictionary of backreference addresses that - have already been written to this stream and that may - be used for DNS name compression. - """ - strio.write( - struct.pack(self._fmt, self.code, len(self.data)) + self.data) - - - def decode(self, strio, length=None): - """ - Decode bytes into an L{_OPTVariableOption} instance. - - @type strio: L{file} - @param strio: Bytes will be read from this file until the full - L{_OPTVariableOption} is decoded. - - @type length: L{int} or L{None} - @param length: Not used. - """ - l = struct.calcsize(self._fmt) - buff = readPrecisely(strio, l) - self.code, length = struct.unpack(self._fmt, buff) - self.data = readPrecisely(strio, length) - - - -@implementer(IEncodable) -class RRHeader(tputil.FancyEqMixin): - """ - A resource record header. - - @cvar fmt: C{str} specifying the byte format of an RR. - - @ivar name: The name about which this reply contains information. - @ivar type: The query type of the original request. - @ivar cls: The query class of the original request. - @ivar ttl: The time-to-live for this record. - @ivar payload: An object that implements the IEncodable interface - - @ivar auth: A C{bool} indicating whether this C{RRHeader} was parsed from an - authoritative message. - """ - compareAttributes = ('name', 'type', 'cls', 'ttl', 'payload', 'auth') - - fmt = "!HHIH" - - name = None - type = None - cls = None - ttl = None - payload = None - rdlength = None - - cachedResponse = None - - def __init__(self, name=b'', type=A, cls=IN, ttl=0, payload=None, auth=False): - """ - @type name: C{bytes} - @param name: The name about which this reply contains information. - - @type type: C{int} - @param type: The query type. - - @type cls: C{int} - @param cls: The query class. - - @type ttl: C{int} - @param ttl: Time to live for this record. - - @type payload: An object implementing C{IEncodable} - @param payload: A Query Type specific data object. - - @raises ValueError: if the ttl is negative. - """ - assert (payload is None) or isinstance(payload, UnknownRecord) or (payload.TYPE == type) - - if ttl < 0: - raise ValueError("TTL cannot be negative") - - self.name = Name(name) - self.type = type - self.cls = cls - self.ttl = ttl - self.payload = payload - self.auth = auth - - - def encode(self, strio, compDict=None): - self.name.encode(strio, compDict) - strio.write(struct.pack(self.fmt, self.type, self.cls, self.ttl, 0)) - if self.payload: - prefix = strio.tell() - self.payload.encode(strio, compDict) - aft = strio.tell() - strio.seek(prefix - 2, 0) - strio.write(struct.pack('!H', aft - prefix)) - strio.seek(aft, 0) - - - def decode(self, strio, length = None): - self.name.decode(strio) - l = struct.calcsize(self.fmt) - buff = readPrecisely(strio, l) - r = struct.unpack(self.fmt, buff) - self.type, self.cls, self.ttl, self.rdlength = r - - - def isAuthoritative(self): - return self.auth - - - def __str__(self): - t = QUERY_TYPES.get(self.type, EXT_QUERIES.get(self.type, 'UNKNOWN (%d)' % self.type)) - c = QUERY_CLASSES.get(self.cls, 'UNKNOWN (%d)' % self.cls) - return '' % (self.name, t, c, self.ttl, self.auth and 'True' or 'False') - - - __repr__ = __str__ - - - -@implementer(IEncodable, IRecord) -class SimpleRecord(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - A Resource Record which consists of a single RFC 1035 domain-name. - - @type name: L{Name} - @ivar name: The name associated with this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - showAttributes = (('name', 'name', '%s'), 'ttl') - compareAttributes = ('name', 'ttl') - - TYPE = None - name = None - - def __init__(self, name=b'', ttl=None): - self.name = Name(name) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.name.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.name = Name() - self.name.decode(strio) - - - def __hash__(self): - return hash(self.name) - - -# Kinds of RRs - oh my! -class Record_NS(SimpleRecord): - """ - An authoritative nameserver. - """ - TYPE = NS - fancybasename = 'NS' - - - -class Record_MD(SimpleRecord): - """ - A mail destination. - - This record type is obsolete. - - @see: L{Record_MX} - """ - TYPE = MD - fancybasename = 'MD' - - - -class Record_MF(SimpleRecord): - """ - A mail forwarder. - - This record type is obsolete. - - @see: L{Record_MX} - """ - TYPE = MF - fancybasename = 'MF' - - - -class Record_CNAME(SimpleRecord): - """ - The canonical name for an alias. - """ - TYPE = CNAME - fancybasename = 'CNAME' - - - -class Record_MB(SimpleRecord): - """ - A mailbox domain name. - - This is an experimental record type. - """ - TYPE = MB - fancybasename = 'MB' - - - -class Record_MG(SimpleRecord): - """ - A mail group member. - - This is an experimental record type. - """ - TYPE = MG - fancybasename = 'MG' - - - -class Record_MR(SimpleRecord): - """ - A mail rename domain name. - - This is an experimental record type. - """ - TYPE = MR - fancybasename = 'MR' - - - -class Record_PTR(SimpleRecord): - """ - A domain name pointer. - """ - TYPE = PTR - fancybasename = 'PTR' - - - -class Record_DNAME(SimpleRecord): - """ - A non-terminal DNS name redirection. - - This record type provides the capability to map an entire subtree of the - DNS name space to another domain. It differs from the CNAME record which - maps a single node of the name space. - - @see: U{http://www.faqs.org/rfcs/rfc2672.html} - @see: U{http://www.faqs.org/rfcs/rfc3363.html} - """ - TYPE = DNAME - fancybasename = 'DNAME' - - - -@implementer(IEncodable, IRecord) -class Record_A(tputil.FancyEqMixin): - """ - An IPv4 host address. - - @type address: C{str} - @ivar address: The packed network-order representation of the IPv4 address - associated with this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - compareAttributes = ('address', 'ttl') - - TYPE = A - address = None - - def __init__(self, address='0.0.0.0', ttl=None): - address = socket.inet_aton(address) - self.address = address - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.address) - - - def decode(self, strio, length = None): - self.address = readPrecisely(strio, 4) - - - def __hash__(self): - return hash(self.address) - - - def __str__(self): - return '' % (self.dottedQuad(), self.ttl) - __repr__ = __str__ - - - def dottedQuad(self): - return socket.inet_ntoa(self.address) - - - -@implementer(IEncodable, IRecord) -class Record_SOA(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - Marks the start of a zone of authority. - - This record describes parameters which are shared by all records within a - particular zone. - - @type mname: L{Name} - @ivar mname: The domain-name of the name server that was the original or - primary source of data for this zone. - - @type rname: L{Name} - @ivar rname: A domain-name which specifies the mailbox of the person - responsible for this zone. - - @type serial: C{int} - @ivar serial: The unsigned 32 bit version number of the original copy of - the zone. Zone transfers preserve this value. This value wraps and - should be compared using sequence space arithmetic. - - @type refresh: C{int} - @ivar refresh: A 32 bit time interval before the zone should be refreshed. - - @type minimum: C{int} - @ivar minimum: The unsigned 32 bit minimum TTL field that should be - exported with any RR from this zone. - - @type expire: C{int} - @ivar expire: A 32 bit time value that specifies the upper limit on the - time interval that can elapse before the zone is no longer - authoritative. - - @type retry: C{int} - @ivar retry: A 32 bit time interval that should elapse before a failed - refresh should be retried. - - @type ttl: C{int} - @ivar ttl: The default TTL to use for records served from this zone. - """ - fancybasename = 'SOA' - compareAttributes = ('serial', 'mname', 'rname', 'refresh', 'expire', 'retry', 'minimum', 'ttl') - showAttributes = (('mname', 'mname', '%s'), ('rname', 'rname', '%s'), 'serial', 'refresh', 'retry', 'expire', 'minimum', 'ttl') - - TYPE = SOA - - def __init__(self, mname=b'', rname=b'', serial=0, refresh=0, retry=0, - expire=0, minimum=0, ttl=None): - self.mname, self.rname = Name(mname), Name(rname) - self.serial, self.refresh = str2time(serial), str2time(refresh) - self.minimum, self.expire = str2time(minimum), str2time(expire) - self.retry = str2time(retry) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.mname.encode(strio, compDict) - self.rname.encode(strio, compDict) - strio.write( - struct.pack( - '!LlllL', - self.serial, self.refresh, self.retry, self.expire, - self.minimum - ) - ) - - - def decode(self, strio, length = None): - self.mname, self.rname = Name(), Name() - self.mname.decode(strio) - self.rname.decode(strio) - r = struct.unpack('!LlllL', readPrecisely(strio, 20)) - self.serial, self.refresh, self.retry, self.expire, self.minimum = r - - - def __hash__(self): - return hash(( - self.serial, self.mname, self.rname, - self.refresh, self.expire, self.retry - )) - - - -@implementer(IEncodable, IRecord) -class Record_NULL(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - A null record. - - This is an experimental record type. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - fancybasename = 'NULL' - showAttributes = (('payload', _nicebytes), 'ttl') - compareAttributes = ('payload', 'ttl') - - TYPE = NULL - - def __init__(self, payload=None, ttl=None): - self.payload = payload - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.payload) - - - def decode(self, strio, length = None): - self.payload = readPrecisely(strio, length) - - - def __hash__(self): - return hash(self.payload) - - - -@implementer(IEncodable, IRecord) -class Record_WKS(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - A well known service description. - - This record type is obsolete. See L{Record_SRV}. - - @type address: C{str} - @ivar address: The packed network-order representation of the IPv4 address - associated with this record. - - @type protocol: C{int} - @ivar protocol: The 8 bit IP protocol number for which this service map is - relevant. - - @type map: C{str} - @ivar map: A bitvector indicating the services available at the specified - address. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - fancybasename = "WKS" - compareAttributes = ('address', 'protocol', 'map', 'ttl') - showAttributes = [('_address', 'address', '%s'), 'protocol', 'ttl'] - - TYPE = WKS - - _address = property(lambda self: socket.inet_ntoa(self.address)) - - def __init__(self, address='0.0.0.0', protocol=0, map='', ttl=None): - self.address = socket.inet_aton(address) - self.protocol, self.map = protocol, map - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.address) - strio.write(struct.pack('!B', self.protocol)) - strio.write(self.map) - - - def decode(self, strio, length = None): - self.address = readPrecisely(strio, 4) - self.protocol = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.map = readPrecisely(strio, length - 5) - - - def __hash__(self): - return hash((self.address, self.protocol, self.map)) - - - -@implementer(IEncodable, IRecord) -class Record_AAAA(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - An IPv6 host address. - - @type address: C{str} - @ivar address: The packed network-order representation of the IPv6 address - associated with this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc1886.html} - """ - TYPE = AAAA - - fancybasename = 'AAAA' - showAttributes = (('_address', 'address', '%s'), 'ttl') - compareAttributes = ('address', 'ttl') - - _address = property(lambda self: socket.inet_ntop(AF_INET6, self.address)) - - def __init__(self, address='::', ttl=None): - self.address = socket.inet_pton(AF_INET6, address) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.address) - - - def decode(self, strio, length = None): - self.address = readPrecisely(strio, 16) - - - def __hash__(self): - return hash(self.address) - - - -@implementer(IEncodable, IRecord) -class Record_A6(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - An IPv6 address. - - This is an experimental record type. - - @type prefixLen: C{int} - @ivar prefixLen: The length of the suffix. - - @type suffix: C{str} - @ivar suffix: An IPv6 address suffix in network order. - - @type prefix: L{Name} - @ivar prefix: If specified, a name which will be used as a prefix for other - A6 records. - - @type bytes: C{int} - @ivar bytes: The length of the prefix. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc2874.html} - @see: U{http://www.faqs.org/rfcs/rfc3363.html} - @see: U{http://www.faqs.org/rfcs/rfc3364.html} - """ - TYPE = A6 - - fancybasename = 'A6' - showAttributes = (('_suffix', 'suffix', '%s'), ('prefix', 'prefix', '%s'), 'ttl') - compareAttributes = ('prefixLen', 'prefix', 'suffix', 'ttl') - - _suffix = property(lambda self: socket.inet_ntop(AF_INET6, self.suffix)) - - def __init__(self, prefixLen=0, suffix='::', prefix=b'', ttl=None): - self.prefixLen = prefixLen - self.suffix = socket.inet_pton(AF_INET6, suffix) - self.prefix = Name(prefix) - self.bytes = int((128 - self.prefixLen) / 8.0) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!B', self.prefixLen)) - if self.bytes: - strio.write(self.suffix[-self.bytes:]) - if self.prefixLen: - # This may not be compressed - self.prefix.encode(strio, None) - - - def decode(self, strio, length = None): - self.prefixLen = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.bytes = int((128 - self.prefixLen) / 8.0) - if self.bytes: - self.suffix = b'\x00' * (16 - self.bytes) + readPrecisely(strio, self.bytes) - if self.prefixLen: - self.prefix.decode(strio) - - - def __eq__(self, other): - if isinstance(other, Record_A6): - return (self.prefixLen == other.prefixLen and - self.suffix[-self.bytes:] == other.suffix[-self.bytes:] and - self.prefix == other.prefix and - self.ttl == other.ttl) - return NotImplemented - - - def __hash__(self): - return hash((self.prefixLen, self.suffix[-self.bytes:], self.prefix)) - - - def __str__(self): - return '' % ( - self.prefix, - socket.inet_ntop(AF_INET6, self.suffix), - self.prefixLen, self.ttl - ) - - - -@implementer(IEncodable, IRecord) -class Record_SRV(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - The location of the server(s) for a specific protocol and domain. - - This is an experimental record type. - - @type priority: C{int} - @ivar priority: The priority of this target host. A client MUST attempt to - contact the target host with the lowest-numbered priority it can reach; - target hosts with the same priority SHOULD be tried in an order defined - by the weight field. - - @type weight: C{int} - @ivar weight: Specifies a relative weight for entries with the same - priority. Larger weights SHOULD be given a proportionately higher - probability of being selected. - - @type port: C{int} - @ivar port: The port on this target host of this service. - - @type target: L{Name} - @ivar target: The domain name of the target host. There MUST be one or - more address records for this name, the name MUST NOT be an alias (in - the sense of RFC 1034 or RFC 2181). Implementors are urged, but not - required, to return the address record(s) in the Additional Data - section. Unless and until permitted by future standards action, name - compression is not to be used for this field. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc2782.html} - """ - TYPE = SRV - - fancybasename = 'SRV' - compareAttributes = ('priority', 'weight', 'target', 'port', 'ttl') - showAttributes = ('priority', 'weight', ('target', 'target', '%s'), 'port', 'ttl') - - def __init__(self, priority=0, weight=0, port=0, target=b'', ttl=None): - self.priority = int(priority) - self.weight = int(weight) - self.port = int(port) - self.target = Name(target) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!HHH', self.priority, self.weight, self.port)) - # This can't be compressed - self.target.encode(strio, None) - - - def decode(self, strio, length = None): - r = struct.unpack('!HHH', readPrecisely(strio, struct.calcsize('!HHH'))) - self.priority, self.weight, self.port = r - self.target = Name() - self.target.decode(strio) - - - def __hash__(self): - return hash((self.priority, self.weight, self.port, self.target)) - - - -@implementer(IEncodable, IRecord) -class Record_NAPTR(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - The location of the server(s) for a specific protocol and domain. - - @type order: C{int} - @ivar order: An integer specifying the order in which the NAPTR records - MUST be processed to ensure the correct ordering of rules. Low numbers - are processed before high numbers. - - @type preference: C{int} - @ivar preference: An integer that specifies the order in which NAPTR - records with equal "order" values SHOULD be processed, low numbers - being processed before high numbers. - - @type flag: L{Charstr} - @ivar flag: A containing flags to control aspects of the - rewriting and interpretation of the fields in the record. Flags - are single characters from the set [A-Z0-9]. The case of the alphabetic - characters is not significant. - - At this time only four flags, "S", "A", "U", and "P", are defined. - - @type service: L{Charstr} - @ivar service: Specifies the service(s) available down this rewrite path. - It may also specify the particular protocol that is used to talk with a - service. A protocol MUST be specified if the flags field states that - the NAPTR is terminal. - - @type regexp: L{Charstr} - @ivar regexp: A STRING containing a substitution expression that is applied - to the original string held by the client in order to construct the - next domain name to lookup. - - @type replacement: L{Name} - @ivar replacement: The next NAME to query for NAPTR, SRV, or address - records depending on the value of the flags field. This MUST be a - fully qualified domain-name. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc2915.html} - """ - TYPE = NAPTR - - compareAttributes = ('order', 'preference', 'flags', 'service', 'regexp', - 'replacement') - fancybasename = 'NAPTR' - - showAttributes = ('order', 'preference', ('flags', 'flags', '%s'), - ('service', 'service', '%s'), ('regexp', 'regexp', '%s'), - ('replacement', 'replacement', '%s'), 'ttl') - - def __init__(self, order=0, preference=0, flags=b'', service=b'', regexp=b'', - replacement=b'', ttl=None): - self.order = int(order) - self.preference = int(preference) - self.flags = Charstr(flags) - self.service = Charstr(service) - self.regexp = Charstr(regexp) - self.replacement = Name(replacement) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict=None): - strio.write(struct.pack('!HH', self.order, self.preference)) - # This can't be compressed - self.flags.encode(strio, None) - self.service.encode(strio, None) - self.regexp.encode(strio, None) - self.replacement.encode(strio, None) - - - def decode(self, strio, length=None): - r = struct.unpack('!HH', readPrecisely(strio, struct.calcsize('!HH'))) - self.order, self.preference = r - self.flags = Charstr() - self.service = Charstr() - self.regexp = Charstr() - self.replacement = Name() - self.flags.decode(strio) - self.service.decode(strio) - self.regexp.decode(strio) - self.replacement.decode(strio) - - - def __hash__(self): - return hash(( - self.order, self.preference, self.flags, - self.service, self.regexp, self.replacement)) - - - -@implementer(IEncodable, IRecord) -class Record_AFSDB(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - Map from a domain name to the name of an AFS cell database server. - - @type subtype: C{int} - @ivar subtype: In the case of subtype 1, the host has an AFS version 3.0 - Volume Location Server for the named AFS cell. In the case of subtype - 2, the host has an authenticated name server holding the cell-root - directory node for the named DCE/NCA cell. - - @type hostname: L{Name} - @ivar hostname: The domain name of a host that has a server for the cell - named by this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc1183.html} - """ - TYPE = AFSDB - - fancybasename = 'AFSDB' - compareAttributes = ('subtype', 'hostname', 'ttl') - showAttributes = ('subtype', ('hostname', 'hostname', '%s'), 'ttl') - - def __init__(self, subtype=0, hostname=b'', ttl=None): - self.subtype = int(subtype) - self.hostname = Name(hostname) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!H', self.subtype)) - self.hostname.encode(strio, compDict) - - - def decode(self, strio, length = None): - r = struct.unpack('!H', readPrecisely(strio, struct.calcsize('!H'))) - self.subtype, = r - self.hostname.decode(strio) - - - def __hash__(self): - return hash((self.subtype, self.hostname)) - - - -@implementer(IEncodable, IRecord) -class Record_RP(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - The responsible person for a domain. - - @type mbox: L{Name} - @ivar mbox: A domain name that specifies the mailbox for the responsible - person. - - @type txt: L{Name} - @ivar txt: A domain name for which TXT RR's exist (indirection through - which allows information sharing about the contents of this RP record). - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc1183.html} - """ - TYPE = RP - - fancybasename = 'RP' - compareAttributes = ('mbox', 'txt', 'ttl') - showAttributes = (('mbox', 'mbox', '%s'), ('txt', 'txt', '%s'), 'ttl') - - def __init__(self, mbox=b'', txt=b'', ttl=None): - self.mbox = Name(mbox) - self.txt = Name(txt) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.mbox.encode(strio, compDict) - self.txt.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.mbox = Name() - self.txt = Name() - self.mbox.decode(strio) - self.txt.decode(strio) - - - def __hash__(self): - return hash((self.mbox, self.txt)) - - - -@implementer(IEncodable, IRecord) -class Record_HINFO(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - Host information. - - @type cpu: C{str} - @ivar cpu: Specifies the CPU type. - - @type os: C{str} - @ivar os: Specifies the OS. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - TYPE = HINFO - - fancybasename = 'HINFO' - showAttributes = (('cpu', _nicebytes), ('os', _nicebytes), 'ttl') - compareAttributes = ('cpu', 'os', 'ttl') - - def __init__(self, cpu='', os='', ttl=None): - self.cpu, self.os = cpu, os - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!B', len(self.cpu)) + self.cpu) - strio.write(struct.pack('!B', len(self.os)) + self.os) - - - def decode(self, strio, length = None): - cpu = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.cpu = readPrecisely(strio, cpu) - os = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.os = readPrecisely(strio, os) - - - def __eq__(self, other): - if isinstance(other, Record_HINFO): - return (self.os.lower() == other.os.lower() and - self.cpu.lower() == other.cpu.lower() and - self.ttl == other.ttl) - return NotImplemented - - - def __hash__(self): - return hash((self.os.lower(), self.cpu.lower())) - - - -@implementer(IEncodable, IRecord) -class Record_MINFO(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - Mailbox or mail list information. - - This is an experimental record type. - - @type rmailbx: L{Name} - @ivar rmailbx: A domain-name which specifies a mailbox which is responsible - for the mailing list or mailbox. If this domain name names the root, - the owner of the MINFO RR is responsible for itself. - - @type emailbx: L{Name} - @ivar emailbx: A domain-name which specifies a mailbox which is to receive - error messages related to the mailing list or mailbox specified by the - owner of the MINFO record. If this domain name names the root, errors - should be returned to the sender of the message. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - TYPE = MINFO - - rmailbx = None - emailbx = None - - fancybasename = 'MINFO' - compareAttributes = ('rmailbx', 'emailbx', 'ttl') - showAttributes = (('rmailbx', 'responsibility', '%s'), - ('emailbx', 'errors', '%s'), - 'ttl') - - def __init__(self, rmailbx=b'', emailbx=b'', ttl=None): - self.rmailbx, self.emailbx = Name(rmailbx), Name(emailbx) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.rmailbx.encode(strio, compDict) - self.emailbx.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.rmailbx, self.emailbx = Name(), Name() - self.rmailbx.decode(strio) - self.emailbx.decode(strio) - - - def __hash__(self): - return hash((self.rmailbx, self.emailbx)) - - - -@implementer(IEncodable, IRecord) -class Record_MX(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - Mail exchange. - - @type preference: C{int} - @ivar preference: Specifies the preference given to this RR among others at - the same owner. Lower values are preferred. - - @type name: L{Name} - @ivar name: A domain-name which specifies a host willing to act as a mail - exchange. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - TYPE = MX - - fancybasename = 'MX' - compareAttributes = ('preference', 'name', 'ttl') - showAttributes = ('preference', ('name', 'name', '%s'), 'ttl') - - def __init__(self, preference=0, name=b'', ttl=None, **kwargs): - self.preference, self.name = int(preference), Name(kwargs.get('exchange', name)) - self.ttl = str2time(ttl) - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!H', self.preference)) - self.name.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.preference = struct.unpack('!H', readPrecisely(strio, 2))[0] - self.name = Name() - self.name.decode(strio) - - def __hash__(self): - return hash((self.preference, self.name)) - - - -@implementer(IEncodable, IRecord) -class Record_TXT(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - Freeform text. - - @type data: C{list} of C{bytes} - @ivar data: Freeform text which makes up this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be cached. - """ - TYPE = TXT - - fancybasename = 'TXT' - showAttributes = (('data', _nicebyteslist), 'ttl') - compareAttributes = ('data', 'ttl') - - def __init__(self, *data, **kw): - self.data = list(data) - # arg man python sucks so bad - self.ttl = str2time(kw.get('ttl', None)) - - - def encode(self, strio, compDict=None): - for d in self.data: - strio.write(struct.pack('!B', len(d)) + d) - - - def decode(self, strio, length=None): - soFar = 0 - self.data = [] - while soFar < length: - L = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.data.append(readPrecisely(strio, L)) - soFar += L + 1 - if soFar != length: - log.msg( - "Decoded %d bytes in %s record, but rdlength is %d" % ( - soFar, self.fancybasename, length - ) - ) - - - def __hash__(self): - return hash(tuple(self.data)) - - - -@implementer(IEncodable, IRecord) -class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): - """ - Encapsulate the wire data for unknown record types so that they can - pass through the system unchanged. - - @type data: C{bytes} - @ivar data: Wire data which makes up this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be cached. - - @since: 11.1 - """ - fancybasename = 'UNKNOWN' - compareAttributes = ('data', 'ttl') - showAttributes = (('data', _nicebytes), 'ttl') - - def __init__(self, data=b'', ttl=None): - self.data = data - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict=None): - """ - Write the raw bytes corresponding to this record's payload to the - stream. - """ - strio.write(self.data) - - - def decode(self, strio, length=None): - """ - Load the bytes which are part of this record from the stream and store - them unparsed and unmodified. - """ - if length is None: - raise Exception('must know length for unknown record types') - self.data = readPrecisely(strio, length) - - - def __hash__(self): - return hash((self.data, self.ttl)) - - - -class Record_SPF(Record_TXT): - """ - Structurally, freeform text. Semantically, a policy definition, formatted - as defined in U{rfc 4408}. - - @type data: C{list} of C{str} - @ivar data: Freeform text which makes up this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be cached. - """ - TYPE = SPF - fancybasename = 'SPF' - - - -def _responseFromMessage(responseConstructor, message, **kwargs): - """ - Generate a L{Message} like instance suitable for use as the response to - C{message}. - - The C{queries}, C{id} attributes will be copied from C{message} and the - C{answer} flag will be set to L{True}. - - @param responseConstructor: A response message constructor with an - initializer signature matching L{dns.Message.__init__}. - @type responseConstructor: C{callable} - - @param message: A request message. - @type message: L{Message} - - @param kwargs: Keyword arguments which will be passed to the initialiser - of the response message. - @type kwargs: L{dict} - - @return: A L{Message} like response instance. - @rtype: C{responseConstructor} - """ - response = responseConstructor(id=message.id, answer=True, **kwargs) - response.queries = message.queries[:] - return response - - - -def _compactRepr(obj, alwaysShow=None, flagNames=None, fieldNames=None, - sectionNames=None): - """ - Return a L{str} representation of C{obj} which only shows fields with - non-default values, flags which are True and sections which have been - explicitly set. - - @param obj: The instance whose repr is being generated. - @param alwaysShow: A L{list} of field names which should always be shown. - @param flagNames: A L{list} of flag attribute names which should be shown if - they are L{True}. - @param fieldNames: A L{list} of field attribute names which should be shown - if they have non-default values. - @param sectionNames: A L{list} of section attribute names which should be - shown if they have been assigned a value. - - @return: A L{str} representation of C{obj}. - """ - if alwaysShow is None: - alwaysShow = [] - - if flagNames is None: - flagNames = [] - - if fieldNames is None: - fieldNames = [] - - if sectionNames is None: - sectionNames = [] - - setFlags = [] - for name in flagNames: - if name in alwaysShow or getattr(obj, name, False) == True: - setFlags.append(name) - - out = ['<', obj.__class__.__name__] - - # Get the argument names and values from the constructor. - argspec = inspect.getargspec(obj.__class__.__init__) - # Reverse the args and defaults to avoid mapping positional arguments - # which don't have a default. - defaults = dict(zip(reversed(argspec.args), reversed(argspec.defaults))) - for name in fieldNames: - defaultValue = defaults.get(name) - fieldValue = getattr(obj, name, defaultValue) - if (name in alwaysShow) or (fieldValue != defaultValue): - out.append(' %s=%r' % (name, fieldValue)) - - if setFlags: - out.append(' flags=%s' % (','.join(setFlags),)) - - for name in sectionNames: - section = getattr(obj, name, []) - if section: - out.append(' %s=%r' % (name, section)) - - out.append('>') - - return ''.join(out) - - - -class Message(tputil.FancyEqMixin): - """ - L{Message} contains all the information represented by a single - DNS request or response. - - @ivar id: See L{__init__} - @ivar answer: See L{__init__} - @ivar opCode: See L{__init__} - @ivar recDes: See L{__init__} - @ivar recAv: See L{__init__} - @ivar auth: See L{__init__} - @ivar rCode: See L{__init__} - @ivar trunc: See L{__init__} - @ivar maxSize: See L{__init__} - @ivar authenticData: See L{__init__} - @ivar checkingDisabled: See L{__init__} - - @ivar queries: The queries which are being asked of or answered by - DNS server. - @type queries: L{list} of L{Query} - - @ivar answers: Records containing the answers to C{queries} if - this is a response message. - @type answers: L{list} of L{RRHeader} - - @ivar authority: Records containing information about the - authoritative DNS servers for the names in C{queries}. - @type authority: L{list} of L{RRHeader} - - @ivar additional: Records containing IP addresses of host names - in C{answers} and C{authority}. - @type additional: L{list} of L{RRHeader} - - @ivar _flagNames: The names of attributes representing the flag header - fields. - @ivar _fieldNames: The names of attributes representing non-flag fixed - header fields. - @ivar _sectionNames: The names of attributes representing the record - sections of this message. - """ - compareAttributes = ( - 'id', 'answer', 'opCode', 'recDes', 'recAv', - 'auth', 'rCode', 'trunc', 'maxSize', - 'authenticData', 'checkingDisabled', - 'queries', 'answers', 'authority', 'additional' - ) - - headerFmt = "!H2B4H" - headerSize = struct.calcsize(headerFmt) - - # Question, answer, additional, and nameserver lists - queries = answers = add = ns = None - - def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, - auth=0, rCode=OK, trunc=0, maxSize=512, - authenticData=0, checkingDisabled=0): - """ - @param id: A 16 bit identifier assigned by the program that - generates any kind of query. This identifier is copied to - the corresponding reply and can be used by the requester - to match up replies to outstanding queries. - @type id: L{int} - - @param answer: A one bit field that specifies whether this - message is a query (0), or a response (1). - @type answer: L{int} - - @param opCode: A four bit field that specifies kind of query in - this message. This value is set by the originator of a query - and copied into the response. - @type opCode: L{int} - - @param recDes: Recursion Desired - this bit may be set in a - query and is copied into the response. If RD is set, it - directs the name server to pursue the query recursively. - Recursive query support is optional. - @type recDes: L{int} - - @param recAv: Recursion Available - this bit is set or cleared - in a response and denotes whether recursive query support - is available in the name server. - @type recAv: L{int} - - @param auth: Authoritative Answer - this bit is valid in - responses and specifies that the responding name server - is an authority for the domain name in question section. - @type auth: L{int} - - @ivar rCode: A response code, used to indicate success or failure in a - message which is a response from a server to a client request. - @type rCode: C{0 <= int < 16} - - @param trunc: A flag indicating that this message was - truncated due to length greater than that permitted on the - transmission channel. - @type trunc: L{int} - - @param maxSize: The requestor's UDP payload size is the number - of octets of the largest UDP payload that can be - reassembled and delivered in the requestor's network - stack. - @type maxSize: L{int} - - @param authenticData: A flag indicating in a response that all - the data included in the answer and authority portion of - the response has been authenticated by the server - according to the policies of that server. - See U{RFC2535 section-6.1}. - @type authenticData: L{int} - - @param checkingDisabled: A flag indicating in a query that - pending (non-authenticated) data is acceptable to the - resolver sending the query. - See U{RFC2535 section-6.1}. - @type authenticData: L{int} - """ - self.maxSize = maxSize - self.id = id - self.answer = answer - self.opCode = opCode - self.auth = auth - self.trunc = trunc - self.recDes = recDes - self.recAv = recAv - self.rCode = rCode - self.authenticData = authenticData - self.checkingDisabled = checkingDisabled - - self.queries = [] - self.answers = [] - self.authority = [] - self.additional = [] - - - def __repr__(self): - """ - Generate a repr of this L{Message}. - - Only includes the non-default fields and sections and only includes - flags which are set. The C{id} is always shown. - - @return: The native string repr. - """ - return _compactRepr( - self, - flagNames=('answer', 'auth', 'trunc', 'recDes', 'recAv', - 'authenticData', 'checkingDisabled'), - fieldNames=('id', 'opCode', 'rCode', 'maxSize'), - sectionNames=('queries', 'answers', 'authority', 'additional'), - alwaysShow=('id',) - ) - - - def addQuery(self, name, type=ALL_RECORDS, cls=IN): - """ - Add another query to this Message. - - @type name: C{bytes} - @param name: The name to query. - - @type type: C{int} - @param type: Query type - - @type cls: C{int} - @param cls: Query class - """ - self.queries.append(Query(name, type, cls)) - - - def encode(self, strio): - compDict = {} - body_tmp = BytesIO() - for q in self.queries: - q.encode(body_tmp, compDict) - for q in self.answers: - q.encode(body_tmp, compDict) - for q in self.authority: - q.encode(body_tmp, compDict) - for q in self.additional: - q.encode(body_tmp, compDict) - body = body_tmp.getvalue() - size = len(body) + self.headerSize - if self.maxSize and size > self.maxSize: - self.trunc = 1 - body = body[:self.maxSize - self.headerSize] - byte3 = (( ( self.answer & 1 ) << 7 ) - | ((self.opCode & 0xf ) << 3 ) - | ((self.auth & 1 ) << 2 ) - | ((self.trunc & 1 ) << 1 ) - | ( self.recDes & 1 ) ) - byte4 = ( ( (self.recAv & 1 ) << 7 ) - | ((self.authenticData & 1) << 5) - | ((self.checkingDisabled & 1) << 4) - | (self.rCode & 0xf ) ) - - strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, - len(self.queries), len(self.answers), - len(self.authority), len(self.additional))) - strio.write(body) - - - def decode(self, strio, length=None): - self.maxSize = 0 - header = readPrecisely(strio, self.headerSize) - r = struct.unpack(self.headerFmt, header) - self.id, byte3, byte4, nqueries, nans, nns, nadd = r - self.answer = ( byte3 >> 7 ) & 1 - self.opCode = ( byte3 >> 3 ) & 0xf - self.auth = ( byte3 >> 2 ) & 1 - self.trunc = ( byte3 >> 1 ) & 1 - self.recDes = byte3 & 1 - self.recAv = ( byte4 >> 7 ) & 1 - self.authenticData = ( byte4 >> 5 ) & 1 - self.checkingDisabled = ( byte4 >> 4 ) & 1 - self.rCode = byte4 & 0xf - - self.queries = [] - for i in range(nqueries): - q = Query() - try: - q.decode(strio) - except EOFError: - return - self.queries.append(q) - - items = ( - (self.answers, nans), - (self.authority, nns), - (self.additional, nadd)) - - for (l, n) in items: - self.parseRecords(l, n, strio) - - - def parseRecords(self, list, num, strio): - for i in range(num): - header = RRHeader(auth=self.auth) - try: - header.decode(strio) - except EOFError: - return - t = self.lookupRecordType(header.type) - if not t: - continue - header.payload = t(ttl=header.ttl) - try: - header.payload.decode(strio, header.rdlength) - except EOFError: - return - list.append(header) - - - # Create a mapping from record types to their corresponding Record_* - # classes. This relies on the global state which has been created so - # far in initializing this module (so don't define Record classes after - # this). - _recordTypes = {} - for name in globals(): - if name.startswith('Record_'): - _recordTypes[globals()[name].TYPE] = globals()[name] - - # Clear the iteration variable out of the class namespace so it - # doesn't become an attribute. - del name - - - def lookupRecordType(self, type): - """ - Retrieve the L{IRecord} implementation for the given record type. - - @param type: A record type, such as L{A} or L{NS}. - @type type: C{int} - - @return: An object which implements L{IRecord} or C{None} if none - can be found for the given type. - @rtype: L{types.ClassType} - """ - return self._recordTypes.get(type, UnknownRecord) - - - def toStr(self): - """ - Encode this L{Message} into a byte string in the format described by RFC - 1035. - - @rtype: C{bytes} - """ - strio = BytesIO() - self.encode(strio) - return strio.getvalue() - - - def fromStr(self, str): - """ - Decode a byte string in the format described by RFC 1035 into this - L{Message}. - - @param str: L{bytes} - """ - strio = BytesIO(str) - self.decode(strio) - - - -class _EDNSMessage(tputil.FancyEqMixin, object): - """ - An I{EDNS} message. - - Designed for compatibility with L{Message} but with a narrower public - interface. - - Most importantly, L{_EDNSMessage.fromStr} will interpret and remove I{OPT} - records that are present in the additional records section. - - The I{OPT} records are used to populate certain I{EDNS} specific attributes. - - L{_EDNSMessage.toStr} will add suitable I{OPT} records to the additional - section to represent the extended EDNS information. - - @see: U{https://tools.ietf.org/html/rfc6891} - - @ivar id: See L{__init__} - @ivar answer: See L{__init__} - @ivar opCode: See L{__init__} - @ivar auth: See L{__init__} - @ivar trunc: See L{__init__} - @ivar recDes: See L{__init__} - @ivar recAv: See L{__init__} - @ivar rCode: See L{__init__} - @ivar ednsVersion: See L{__init__} - @ivar dnssecOK: See L{__init__} - @ivar authenticData: See L{__init__} - @ivar checkingDisabled: See L{__init__} - @ivar maxSize: See L{__init__} - - @ivar queries: See L{__init__} - @ivar answers: See L{__init__} - @ivar authority: See L{__init__} - @ivar additional: See L{__init__} - - @ivar _messageFactory: A constructor of L{Message} instances. Called by - C{_toMessage} and C{_fromMessage}. - """ - - compareAttributes = ( - 'id', 'answer', 'opCode', 'auth', 'trunc', - 'recDes', 'recAv', 'rCode', 'ednsVersion', 'dnssecOK', - 'authenticData', 'checkingDisabled', 'maxSize', - 'queries', 'answers', 'authority', 'additional') - - _messageFactory = Message - - def __init__(self, id=0, answer=False, opCode=OP_QUERY, auth=False, - trunc=False, recDes=False, recAv=False, rCode=0, - ednsVersion=0, dnssecOK=False, authenticData=False, - checkingDisabled=False, maxSize=512, - queries=None, answers=None, authority=None, additional=None): - """ - Construct a new L{_EDNSMessage} - - @see U{RFC1035 section-4.1.1} - @see U{RFC2535 section-6.1} - @see U{RFC3225 section-3} - @see U{RFC6891 section-6.1.3} - - @param id: A 16 bit identifier assigned by the program that generates - any kind of query. This identifier is copied the corresponding - reply and can be used by the requester to match up replies to - outstanding queries. - @type id: L{int} - - @param answer: A one bit field that specifies whether this message is a - query (0), or a response (1). - @type answer: L{bool} - - @param opCode: A four bit field that specifies kind of query in this - message. This value is set by the originator of a query and copied - into the response. - @type opCode: L{int} - - @param auth: Authoritative Answer - this bit is valid in responses, and - specifies that the responding name server is an authority for the - domain name in question section. - @type auth: L{bool} - - @param trunc: Truncation - specifies that this message was truncated due - to length greater than that permitted on the transmission channel. - @type trunc: L{bool} - - @param recDes: Recursion Desired - this bit may be set in a query and is - copied into the response. If set, it directs the name server to - pursue the query recursively. Recursive query support is optional. - @type recDes: L{bool} - - @param recAv: Recursion Available - this bit is set or cleared in a - response, and denotes whether recursive query support is available - in the name server. - @type recAv: L{bool} - - @param rCode: Extended 12-bit RCODE. Derived from the 4 bits defined in - U{RFC1035 4.1.1} - and the upper 8bits defined in U{RFC6891 - 6.1.3}. - @type rCode: L{int} - - @param ednsVersion: Indicates the EDNS implementation level. Set to - L{None} to prevent any EDNS attributes and options being added to - the encoded byte string. - @type ednsVersion: L{int} or L{None} - - @param dnssecOK: DNSSEC OK bit as defined by - U{RFC3225 3}. - @type dnssecOK: C{bool} - - @param authenticData: A flag indicating in a response that all the data - included in the answer and authority portion of the response has - been authenticated by the server according to the policies of that - server. - See U{RFC2535 section-6.1}. - @type authenticData: L{bool} - - @param checkingDisabled: A flag indicating in a query that pending - (non-authenticated) data is acceptable to the resolver sending the - query. - See U{RFC2535 section-6.1}. - @type authenticData: L{bool} - - @param maxSize: The requestor's UDP payload size is the number of octets - of the largest UDP payload that can be reassembled and delivered in - the requestor's network stack. - @type maxSize: L{int} - - @param queries: The L{list} of L{Query} associated with this message. - @type queries: L{list} of L{Query} - - @param answers: The L{list} of answers associated with this message. - @type answers: L{list} of L{RRHeader} - - @param authority: The L{list} of authority records associated with this - message. - @type authority: L{list} of L{RRHeader} - - @param additional: The L{list} of additional records associated with - this message. - @type additional: L{list} of L{RRHeader} - """ - self.id = id - self.answer = answer - self.opCode = opCode - self.auth = auth - self.trunc = trunc - self.recDes = recDes - self.recAv = recAv - self.rCode = rCode - self.ednsVersion = ednsVersion - self.dnssecOK = dnssecOK - self.authenticData = authenticData - self.checkingDisabled = checkingDisabled - self.maxSize = maxSize - - if queries is None: - queries = [] - self.queries = queries - - if answers is None: - answers = [] - self.answers = answers - - if authority is None: - authority = [] - self.authority = authority - - if additional is None: - additional = [] - self.additional = additional - - - def __repr__(self): - return _compactRepr( - self, - flagNames=('answer', 'auth', 'trunc', 'recDes', 'recAv', - 'authenticData', 'checkingDisabled', 'dnssecOK'), - fieldNames=('id', 'opCode', 'rCode', 'maxSize', 'ednsVersion'), - sectionNames=('queries', 'answers', 'authority', 'additional'), - alwaysShow=('id',) - ) - - - def _toMessage(self): - """ - Convert to a standard L{dns.Message}. - - If C{ednsVersion} is not None, an L{_OPTHeader} instance containing all - the I{EDNS} specific attributes and options will be appended to the list - of C{additional} records. - - @return: A L{dns.Message} - @rtype: L{dns.Message} - """ - m = self._messageFactory( - id=self.id, - answer=self.answer, - opCode=self.opCode, - auth=self.auth, - trunc=self.trunc, - recDes=self.recDes, - recAv=self.recAv, - # Assign the lower 4 bits to the message - rCode=self.rCode & 0xf, - authenticData=self.authenticData, - checkingDisabled=self.checkingDisabled) - - m.queries = self.queries[:] - m.answers = self.answers[:] - m.authority = self.authority[:] - m.additional = self.additional[:] - - if self.ednsVersion is not None: - o = _OPTHeader(version=self.ednsVersion, - dnssecOK=self.dnssecOK, - udpPayloadSize=self.maxSize, - # Assign the upper 8 bits to the OPT record - extendedRCODE=self.rCode >> 4) - m.additional.append(o) - - return m - - - def toStr(self): - """ - Encode to wire format by first converting to a standard L{dns.Message}. - - @return: A L{bytes} string. - """ - return self._toMessage().toStr() - - - @classmethod - def _fromMessage(cls, message): - """ - Construct and return a new L(_EDNSMessage} whose attributes and records - are derived from the attributes and records of C{message} (a L{Message} - instance) - - If present, an I{OPT} record will be extracted from the C{additional} - section and its attributes and options will be used to set the EDNS - specific attributes C{extendedRCODE}, c{ednsVersion}, c{dnssecOK}, - c{ednsOptions}. - - The C{extendedRCODE} will be combined with C{message.rCode} and assigned - to C{self.rCode}. - - @param message: The source L{Message}. - @type message: L{Message} - - @return: A new L{_EDNSMessage} - @rtype: L{_EDNSMessage} - """ - additional = [] - optRecords = [] - for r in message.additional: - if r.type == OPT: - optRecords.append(_OPTHeader.fromRRHeader(r)) - else: - additional.append(r) - - newMessage = cls( - id=message.id, - answer=message.answer, - opCode=message.opCode, - auth=message.auth, - trunc=message.trunc, - recDes=message.recDes, - recAv=message.recAv, - rCode=message.rCode, - authenticData=message.authenticData, - checkingDisabled=message.checkingDisabled, - # Default to None, it will be updated later when the OPT records are - # parsed. - ednsVersion=None, - dnssecOK=False, - queries=message.queries[:], - answers=message.answers[:], - authority=message.authority[:], - additional=additional, - ) - - if len(optRecords) == 1: - # XXX: If multiple OPT records are received, an EDNS server should - # respond with FORMERR. See ticket:5669#comment:1. - opt = optRecords[0] - newMessage.ednsVersion = opt.version - newMessage.dnssecOK = opt.dnssecOK - newMessage.maxSize = opt.udpPayloadSize - newMessage.rCode = opt.extendedRCODE << 4 | message.rCode - - return newMessage - - - def fromStr(self, bytes): - """ - Decode from wire format, saving flags, values and records to this - L{_EDNSMessage} instance in place. - - @param bytes: The full byte string to be decoded. - @type bytes: L{bytes} - """ - m = self._messageFactory() - m.fromStr(bytes) - - ednsMessage = self._fromMessage(m) - for attrName in self.compareAttributes: - setattr(self, attrName, getattr(ednsMessage, attrName)) - - - -class DNSMixin(object): - """ - DNS protocol mixin shared by UDP and TCP implementations. - - @ivar _reactor: A L{IReactorTime} and L{IReactorUDP} provider which will - be used to issue DNS queries and manage request timeouts. - """ - id = None - liveMessages = None - - def __init__(self, controller, reactor=None): - self.controller = controller - self.id = random.randrange(2 ** 10, 2 ** 15) - if reactor is None: - from twisted.internet import reactor - self._reactor = reactor - - - def pickID(self): - """ - Return a unique ID for queries. - """ - while True: - id = randomSource() - if id not in self.liveMessages: - return id - - - def callLater(self, period, func, *args): - """ - Wrapper around reactor.callLater, mainly for test purpose. - """ - return self._reactor.callLater(period, func, *args) - - - def _query(self, queries, timeout, id, writeMessage): - """ - Send out a message with the given queries. - - @type queries: C{list} of C{Query} instances - @param queries: The queries to transmit - - @type timeout: C{int} or C{float} - @param timeout: How long to wait before giving up - - @type id: C{int} - @param id: Unique key for this request - - @type writeMessage: C{callable} - @param writeMessage: One-parameter callback which writes the message - - @rtype: C{Deferred} - @return: a C{Deferred} which will be fired with the result of the - query, or errbacked with any errors that could happen (exceptions - during writing of the query, timeout errors, ...). - """ - m = Message(id, recDes=1) - m.queries = queries - - try: - writeMessage(m) - except: - return defer.fail() - - resultDeferred = defer.Deferred() - cancelCall = self.callLater(timeout, self._clearFailed, resultDeferred, id) - self.liveMessages[id] = (resultDeferred, cancelCall) - - return resultDeferred - - def _clearFailed(self, deferred, id): - """ - Clean the Deferred after a timeout. - """ - try: - del self.liveMessages[id] - except KeyError: - pass - deferred.errback(failure.Failure(DNSQueryTimeoutError(id))) - - -class DNSDatagramProtocol(DNSMixin, protocol.DatagramProtocol): - """ - DNS protocol over UDP. - """ - resends = None - - def stopProtocol(self): - """ - Stop protocol: reset state variables. - """ - self.liveMessages = {} - self.resends = {} - self.transport = None - - def startProtocol(self): - """ - Upon start, reset internal state. - """ - self.liveMessages = {} - self.resends = {} - - def writeMessage(self, message, address): - """ - Send a message holding DNS queries. - - @type message: L{Message} - """ - self.transport.write(message.toStr(), address) - - def startListening(self): - self._reactor.listenUDP(0, self, maxPacketSize=512) - - def datagramReceived(self, data, addr): - """ - Read a datagram, extract the message in it and trigger the associated - Deferred. - """ - m = Message() - try: - m.fromStr(data) - except EOFError: - log.msg("Truncated packet (%d bytes) from %s" % (len(data), addr)) - return - except: - # Nothing should trigger this, but since we're potentially - # invoking a lot of different decoding methods, we might as well - # be extra cautious. Anything that triggers this is itself - # buggy. - log.err(failure.Failure(), "Unexpected decoding error") - return - - if m.id in self.liveMessages: - d, canceller = self.liveMessages[m.id] - del self.liveMessages[m.id] - canceller.cancel() - # XXX we shouldn't need this hack of catching exception on callback() - try: - d.callback(m) - except: - log.err() - else: - if m.id not in self.resends: - self.controller.messageReceived(m, self, addr) - - - def removeResend(self, id): - """ - Mark message ID as no longer having duplication suppression. - """ - try: - del self.resends[id] - except KeyError: - pass - - def query(self, address, queries, timeout=10, id=None): - """ - Send out a message with the given queries. - - @type address: C{tuple} of C{str} and C{int} - @param address: The address to which to send the query - - @type queries: C{list} of C{Query} instances - @param queries: The queries to transmit - - @rtype: C{Deferred} - """ - if not self.transport: - # XXX transport might not get created automatically, use callLater? - try: - self.startListening() - except CannotListenError: - return defer.fail() - - if id is None: - id = self.pickID() - else: - self.resends[id] = 1 - - def writeMessage(m): - self.writeMessage(m, address) - - return self._query(queries, timeout, id, writeMessage) - - -class DNSProtocol(DNSMixin, protocol.Protocol): - """ - DNS protocol over TCP. - """ - length = None - buffer = b'' - - def writeMessage(self, message): - """ - Send a message holding DNS queries. - - @type message: L{Message} - """ - s = message.toStr() - self.transport.write(struct.pack('!H', len(s)) + s) - - def connectionMade(self): - """ - Connection is made: reset internal state, and notify the controller. - """ - self.liveMessages = {} - self.controller.connectionMade(self) - - - def connectionLost(self, reason): - """ - Notify the controller that this protocol is no longer - connected. - """ - self.controller.connectionLost(self) - - - def dataReceived(self, data): - self.buffer += data - - while self.buffer: - if self.length is None and len(self.buffer) >= 2: - self.length = struct.unpack('!H', self.buffer[:2])[0] - self.buffer = self.buffer[2:] - - if len(self.buffer) >= self.length: - myChunk = self.buffer[:self.length] - m = Message() - m.fromStr(myChunk) - - try: - d, canceller = self.liveMessages[m.id] - except KeyError: - self.controller.messageReceived(m, self) - else: - del self.liveMessages[m.id] - canceller.cancel() - # XXX we shouldn't need this hack - try: - d.callback(m) - except: - log.err() - - self.buffer = self.buffer[self.length:] - self.length = None - else: - break - - - def query(self, queries, timeout=60): - """ - Send out a message with the given queries. - - @type queries: C{list} of C{Query} instances - @param queries: The queries to transmit - - @rtype: C{Deferred} - """ - id = self.pickID() - return self._query(queries, timeout, id, self.writeMessage) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/error.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/error.py deleted file mode 100644 index db11ee9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/error.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- test-case-name: twisted.names.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Exception class definitions for Twisted Names. -""" - -from __future__ import division, absolute_import - -from twisted.internet.defer import TimeoutError - - -class DomainError(ValueError): - """ - Indicates a lookup failed because there were no records matching the given - C{name, class, type} triple. - """ - - - -class AuthoritativeDomainError(ValueError): - """ - Indicates a lookup failed for a name for which this server is authoritative - because there were no records matching the given C{name, class, type} - triple. - """ - - - -class DNSQueryTimeoutError(TimeoutError): - """ - Indicates a lookup failed due to a timeout. - - @ivar id: The id of the message which timed out. - """ - def __init__(self, id): - TimeoutError.__init__(self) - self.id = id - - - -class DNSFormatError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.EFORMAT}. - """ - - - -class DNSServerError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.ESERVER}. - """ - - - -class DNSNameError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.ENAME}. - """ - - - -class DNSNotImplementedError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.ENOTIMP}. - """ - - - -class DNSQueryRefusedError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.EREFUSED}. - """ - - - -class DNSUnknownError(DomainError): - """ - Indicates a query failed with an unknown result. - """ - - - -class ResolverError(Exception): - """ - Indicates a query failed because of a decision made by the local - resolver object. - """ - - -__all__ = [ - 'DomainError', 'AuthoritativeDomainError', 'DNSQueryTimeoutError', - - 'DNSFormatError', 'DNSServerError', 'DNSNameError', - 'DNSNotImplementedError', 'DNSQueryRefusedError', - 'DNSUnknownError', 'ResolverError'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/hosts.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/hosts.py deleted file mode 100644 index 499991d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/hosts.py +++ /dev/null @@ -1,149 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_hosts -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -hosts(5) support. -""" - -from __future__ import division, absolute_import - -from twisted.python.compat import nativeString -from twisted.names import dns -from twisted.python import failure -from twisted.python.filepath import FilePath -from twisted.internet import defer -from twisted.internet.abstract import isIPAddress - -from twisted.names import common - -def searchFileForAll(hostsFile, name): - """ - Search the given file, which is in hosts(5) standard format, for an address - entry with a given name. - - @param hostsFile: The name of the hosts(5)-format file to search. - @type hostsFile: L{FilePath} - - @param name: The name to search for. - @type name: C{str} - - @return: C{None} if the name is not found in the file, otherwise a - C{str} giving the address in the file associated with the name. - """ - results = [] - try: - lines = hostsFile.getContent().splitlines() - except: - return results - - name = name.lower() - for line in lines: - idx = line.find(b'#') - if idx != -1: - line = line[:idx] - if not line: - continue - parts = line.split() - - if name.lower() in [s.lower() for s in parts[1:]]: - results.append(nativeString(parts[0])) - return results - - - -def searchFileFor(file, name): - """ - Grep given file, which is in hosts(5) standard format, for an address - entry with a given name. - - @param file: The name of the hosts(5)-format file to search. - - @param name: The name to search for. - @type name: C{str} - - @return: C{None} if the name is not found in the file, otherwise a - C{str} giving the address in the file associated with the name. - """ - addresses = searchFileForAll(FilePath(file), name) - if addresses: - return addresses[0] - return None - - - -class Resolver(common.ResolverBase): - """ - A resolver that services hosts(5) format files. - """ - def __init__(self, file=b'/etc/hosts', ttl = 60 * 60): - common.ResolverBase.__init__(self) - self.file = file - self.ttl = ttl - - - def _aRecords(self, name): - """ - Return a tuple of L{dns.RRHeader} instances for all of the IPv4 - addresses in the hosts file. - """ - return tuple([ - dns.RRHeader(name, dns.A, dns.IN, self.ttl, - dns.Record_A(addr, self.ttl)) - for addr - in searchFileForAll(FilePath(self.file), name) - if isIPAddress(addr)]) - - - def _aaaaRecords(self, name): - """ - Return a tuple of L{dns.RRHeader} instances for all of the IPv6 - addresses in the hosts file. - """ - return tuple([ - dns.RRHeader(name, dns.AAAA, dns.IN, self.ttl, - dns.Record_AAAA(addr, self.ttl)) - for addr - in searchFileForAll(FilePath(self.file), name) - if not isIPAddress(addr)]) - - - def _respond(self, name, records): - """ - Generate a response for the given name containing the given result - records, or a failure if there are no result records. - - @param name: The DNS name the response is for. - @type name: C{str} - - @param records: A tuple of L{dns.RRHeader} instances giving the results - that will go into the response. - - @return: A L{Deferred} which will fire with a three-tuple of result - records, authority records, and additional records, or which will - fail with L{dns.DomainError} if there are no result records. - """ - if records: - return defer.succeed((records, (), ())) - return defer.fail(failure.Failure(dns.DomainError(name))) - - - def lookupAddress(self, name, timeout=None): - """ - Read any IPv4 addresses from C{self.file} and return them as L{Record_A} - instances. - """ - return self._respond(name, self._aRecords(name)) - - - def lookupIPV6Address(self, name, timeout=None): - """ - Read any IPv6 addresses from C{self.file} and return them as - L{Record_AAAA} instances. - """ - return self._respond(name, self._aaaaRecords(name)) - - # Someday this should include IPv6 addresses too, but that will cause - # problems if users of the API (mainly via getHostByName) aren't updated to - # know about IPv6 first. - lookupAllRecords = lookupAddress diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/resolve.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/resolve.py deleted file mode 100644 index 0cd39eb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/resolve.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_resolve -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Lookup a name using multiple resolvers. - -Future Plans: This needs someway to specify which resolver answered -the query, or someway to specify (authority|ttl|cache behavior|more?) -""" - -from __future__ import division, absolute_import - -from zope.interface import implementer - -from twisted.internet import defer, interfaces -from twisted.names import dns, common, error - - -class FailureHandler: - def __init__(self, resolver, query, timeout): - self.resolver = resolver - self.query = query - self.timeout = timeout - - - def __call__(self, failure): - # AuthoritativeDomainErrors should halt resolution attempts - failure.trap(dns.DomainError, defer.TimeoutError, NotImplementedError) - return self.resolver(self.query, self.timeout) - - - -@implementer(interfaces.IResolver) -class ResolverChain(common.ResolverBase): - """ - Lookup an address using multiple L{IResolver}s - """ - def __init__(self, resolvers): - """ - @type resolvers: L{list} - @param resolvers: A L{list} of L{IResolver} providers. - """ - common.ResolverBase.__init__(self) - self.resolvers = resolvers - - - def _lookup(self, name, cls, type, timeout): - """ - Build a L{dns.Query} for the given parameters and dispatch it - to each L{IResolver} in C{self.resolvers} until an answer or - L{error.AuthoritativeDomainError} is returned. - - @type name: C{str} - @param name: DNS name to resolve. - - @type type: C{int} - @param type: DNS record type. - - @type cls: C{int} - @param cls: DNS record class. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: L{Deferred} - @return: A L{Deferred} which fires with a three-tuple of lists of - L{twisted.names.dns.RRHeader} instances. The first element of the - tuple gives answers. The second element of the tuple gives - authorities. The third element of the tuple gives additional - information. The L{Deferred} may instead fail with one of the - exceptions defined in L{twisted.names.error} or with - C{NotImplementedError}. - """ - if not self.resolvers: - return defer.fail(error.DomainError()) - q = dns.Query(name, type, cls) - d = self.resolvers[0].query(q, timeout) - for r in self.resolvers[1:]: - d = d.addErrback( - FailureHandler(r.query, q, timeout) - ) - return d - - - def lookupAllRecords(self, name, timeout=None): - # XXX: Why is this necessary? dns.ALL_RECORDS queries should - # be handled just the same as any other type by _lookup - # above. If I remove this method all names tests still - # pass. See #6604 -rwall - if not self.resolvers: - return defer.fail(error.DomainError()) - d = self.resolvers[0].lookupAllRecords(name, timeout) - for r in self.resolvers[1:]: - d = d.addErrback( - FailureHandler(r.lookupAllRecords, name, timeout) - ) - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/root.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/root.py deleted file mode 100644 index 86c136c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/root.py +++ /dev/null @@ -1,333 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_rootresolve -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Resolver implementation for querying successive authoritative servers to -lookup a record, starting from the root nameservers. - -@author: Jp Calderone - -todo:: - robustify it - documentation -""" - -from twisted.python.failure import Failure -from twisted.internet import defer -from twisted.names import dns, common, error - - - -class _DummyController: - """ - A do-nothing DNS controller. This is useful when all messages received - will be responses to previously issued queries. Anything else received - will be ignored. - """ - def messageReceived(self, *args): - pass - - - -class Resolver(common.ResolverBase): - """ - L{Resolver} implements recursive lookup starting from a specified list of - root servers. - - @ivar hints: See C{hints} parameter of L{__init__} - @ivar _maximumQueries: See C{maximumQueries} parameter of L{__init__} - @ivar _reactor: See C{reactor} parameter of L{__init__} - @ivar _resolverFactory: See C{resolverFactory} parameter of L{__init__} - """ - def __init__(self, hints, maximumQueries=10, - reactor=None, resolverFactory=None): - """ - @param hints: A L{list} of L{str} giving the dotted quad - representation of IP addresses of root servers at which to - begin resolving names. - @type hints: L{list} of L{str} - - @param maximumQueries: An optional L{int} giving the maximum - number of queries which will be attempted to resolve a - single name. - @type maximumQueries: L{int} - - @param reactor: An optional L{IReactorTime} and L{IReactorUDP} - provider to use to bind UDP ports and manage timeouts. - @type reactor: L{IReactorTime} and L{IReactorUDP} provider - - @param resolverFactory: An optional callable which accepts C{reactor} - and C{servers} arguments and returns an instance that provides a - C{queryUDP} method. Defaults to L{twisted.names.client.Resolver}. - @type resolverFactory: callable - """ - common.ResolverBase.__init__(self) - self.hints = hints - self._maximumQueries = maximumQueries - self._reactor = reactor - if resolverFactory is None: - from twisted.names.client import Resolver as resolverFactory - self._resolverFactory = resolverFactory - - - def _roots(self): - """ - Return a list of two-tuples representing the addresses of the root - servers, as defined by C{self.hints}. - """ - return [(ip, dns.PORT) for ip in self.hints] - - - def _query(self, query, servers, timeout, filter): - """ - Issue one query and return a L{Deferred} which fires with its response. - - @param query: The query to issue. - @type query: L{dns.Query} - - @param servers: The servers which might have an answer for this - query. - @type servers: L{list} of L{tuple} of L{str} and L{int} - - @param timeout: A timeout on how long to wait for the response. - @type timeout: L{tuple} of L{int} - - @param filter: A flag indicating whether to filter the results. If - C{True}, the returned L{Deferred} will fire with a three-tuple of - lists of L{RRHeaders} (like the return value of the I{lookup*} - methods of L{IResolver}. IF C{False}, the result will be a - L{Message} instance. - @type filter: L{bool} - - @return: A L{Deferred} which fires with the response or a timeout - error. - @rtype: L{Deferred} - """ - r = self._resolverFactory(servers=servers, reactor=self._reactor) - d = r.queryUDP([query], timeout) - if filter: - d.addCallback(r.filterAnswers) - return d - - - def _lookup(self, name, cls, type, timeout): - """ - Implement name lookup by recursively discovering the authoritative - server for the name and then asking it, starting at one of the servers - in C{self.hints}. - """ - if timeout is None: - # A series of timeouts for semi-exponential backoff, summing to an - # arbitrary total of 60 seconds. - timeout = (1, 3, 11, 45) - return self._discoverAuthority( - dns.Query(name, type, cls), self._roots(), timeout, - self._maximumQueries) - - - def _discoverAuthority(self, query, servers, timeout, queriesLeft): - """ - Issue a query to a server and follow a delegation if necessary. - - @param query: The query to issue. - @type query: L{dns.Query} - - @param servers: The servers which might have an answer for this - query. - @type servers: L{list} of L{tuple} of L{str} and L{int} - - @param timeout: A C{tuple} of C{int} giving the timeout to use for this - query. - - @param queriesLeft: A C{int} giving the number of queries which may - yet be attempted to answer this query before the attempt will be - abandoned. - - @return: A L{Deferred} which fires with a three-tuple of lists of - L{RRHeaders} giving the response, or with a L{Failure} if there is - a timeout or response error. - """ - # Stop now if we've hit the query limit. - if queriesLeft <= 0: - return Failure( - error.ResolverError("Query limit reached without result")) - - d = self._query(query, servers, timeout, False) - d.addCallback( - self._discoveredAuthority, query, timeout, queriesLeft - 1) - return d - - - def _discoveredAuthority(self, response, query, timeout, queriesLeft): - """ - Interpret the response to a query, checking for error codes and - following delegations if necessary. - - @param response: The L{Message} received in response to issuing C{query}. - @type response: L{Message} - - @param query: The L{dns.Query} which was issued. - @type query: L{dns.Query}. - - @param timeout: The timeout to use if another query is indicated by - this response. - @type timeout: L{tuple} of L{int} - - @param queriesLeft: A C{int} giving the number of queries which may - yet be attempted to answer this query before the attempt will be - abandoned. - - @return: A L{Failure} indicating a response error, a three-tuple of - lists of L{RRHeaders} giving the response to C{query} or a - L{Deferred} which will fire with one of those. - """ - if response.rCode != dns.OK: - return Failure(self.exceptionForCode(response.rCode)(response)) - - # Turn the answers into a structure that's a little easier to work with. - records = {} - for answer in response.answers: - records.setdefault(answer.name, []).append(answer) - - def findAnswerOrCName(name, type, cls): - cname = None - for record in records.get(name, []): - if record.cls == cls: - if record.type == type: - return record - elif record.type == dns.CNAME: - cname = record - # If there were any CNAME records, return the last one. There's - # only supposed to be zero or one, though. - return cname - - seen = set() - name = query.name - record = None - while True: - seen.add(name) - previous = record - record = findAnswerOrCName(name, query.type, query.cls) - if record is None: - if name == query.name: - # If there's no answer for the original name, then this may - # be a delegation. Code below handles it. - break - else: - # Try to resolve the CNAME with another query. - d = self._discoverAuthority( - dns.Query(str(name), query.type, query.cls), - self._roots(), timeout, queriesLeft) - # We also want to include the CNAME in the ultimate result, - # otherwise this will be pretty confusing. - def cbResolved(results): - answers, authority, additional = results - answers.insert(0, previous) - return (answers, authority, additional) - d.addCallback(cbResolved) - return d - elif record.type == query.type: - return ( - response.answers, - response.authority, - response.additional) - else: - # It's a CNAME record. Try to resolve it from the records - # in this response with another iteration around the loop. - if record.payload.name in seen: - raise error.ResolverError("Cycle in CNAME processing") - name = record.payload.name - - - # Build a map to use to convert NS names into IP addresses. - addresses = {} - for rr in response.additional: - if rr.type == dns.A: - addresses[rr.name.name] = rr.payload.dottedQuad() - - hints = [] - traps = [] - for rr in response.authority: - if rr.type == dns.NS: - ns = rr.payload.name.name - if ns in addresses: - hints.append((addresses[ns], dns.PORT)) - else: - traps.append(ns) - if hints: - return self._discoverAuthority( - query, hints, timeout, queriesLeft) - elif traps: - d = self.lookupAddress(traps[0], timeout) - def getOneAddress(results): - answers, authority, additional = results - return answers[0].payload.dottedQuad() - d.addCallback(getOneAddress) - d.addCallback( - lambda hint: self._discoverAuthority( - query, [(hint, dns.PORT)], timeout, queriesLeft - 1)) - return d - else: - return Failure(error.ResolverError( - "Stuck at response without answers or delegation")) - - - -def makePlaceholder(deferred, name): - def placeholder(*args, **kw): - deferred.addCallback(lambda r: getattr(r, name)(*args, **kw)) - return deferred - return placeholder - -class DeferredResolver: - def __init__(self, resolverDeferred): - self.waiting = [] - resolverDeferred.addCallback(self.gotRealResolver) - - def gotRealResolver(self, resolver): - w = self.waiting - self.__dict__ = resolver.__dict__ - self.__class__ = resolver.__class__ - for d in w: - d.callback(resolver) - - def __getattr__(self, name): - if name.startswith('lookup') or name in ('getHostByName', 'query'): - self.waiting.append(defer.Deferred()) - return makePlaceholder(self.waiting[-1], name) - raise AttributeError(name) - - - -def bootstrap(resolver, resolverFactory=None): - """ - Lookup the root nameserver addresses using the given resolver - - Return a Resolver which will eventually become a C{root.Resolver} - instance that has references to all the root servers that we were able - to look up. - - @param resolver: The resolver instance which will be used to - lookup the root nameserver addresses. - @type resolver: L{twisted.internet.interfaces.IResolverSimple} - - @param resolverFactory: An optional callable which returns a - resolver instance. It will passed as the C{resolverFactory} - argument to L{Resolver.__init__}. - @type resolverFactory: callable - - @return: A L{DeferredResolver} which will be dynamically replaced - with L{Resolver} when the root nameservers have been looked up. - """ - domains = [chr(ord('a') + i) for i in range(13)] - L = [resolver.getHostByName('%s.root-servers.net' % d) for d in domains] - d = defer.DeferredList(L) - - def buildResolver(res): - return Resolver( - hints=[e[1] for e in res if e[0]], - resolverFactory=resolverFactory) - d.addCallback(buildResolver) - - return DeferredResolver(d) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/secondary.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/secondary.py deleted file mode 100644 index 6cf17a0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/secondary.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -__all__ = ['SecondaryAuthority', 'SecondaryAuthorityService'] - -from twisted.internet import task, defer -from twisted.names import dns -from twisted.names import common -from twisted.names import client -from twisted.names import resolve -from twisted.names.authority import FileAuthority - -from twisted.python import log, failure -from twisted.application import service - -class SecondaryAuthorityService(service.Service): - calls = None - - _port = 53 - - def __init__(self, primary, domains): - """ - @param primary: The IP address of the server from which to perform - zone transfers. - - @param domains: A sequence of domain names for which to perform - zone transfers. - """ - self.primary = primary - self.domains = [SecondaryAuthority(primary, d) for d in domains] - - - @classmethod - def fromServerAddressAndDomains(cls, serverAddress, domains): - """ - Construct a new L{SecondaryAuthorityService} from a tuple giving a - server address and a C{str} giving the name of a domain for which this - is an authority. - - @param serverAddress: A two-tuple, the first element of which is a - C{str} giving an IP address and the second element of which is a - C{int} giving a port number. Together, these define where zone - transfers will be attempted from. - - @param domain: A C{str} giving the domain to transfer. - - @return: A new instance of L{SecondaryAuthorityService}. - """ - service = cls(None, []) - service.primary = serverAddress[0] - service._port = serverAddress[1] - service.domains = [ - SecondaryAuthority.fromServerAddressAndDomain(serverAddress, d) - for d in domains] - return service - - - def getAuthority(self): - return resolve.ResolverChain(self.domains) - - def startService(self): - service.Service.startService(self) - self.calls = [task.LoopingCall(d.transfer) for d in self.domains] - i = 0 - from twisted.internet import reactor - for c in self.calls: - # XXX Add errbacks, respect proper timeouts - reactor.callLater(i, c.start, 60 * 60) - i += 1 - - def stopService(self): - service.Service.stopService(self) - for c in self.calls: - c.stop() - - - -class SecondaryAuthority(FileAuthority): - """ - An Authority that keeps itself updated by performing zone transfers. - - @ivar primary: The IP address of the server from which zone transfers will - be attempted. - @type primary: C{str} - - @ivar _port: The port number of the server from which zone transfers will be - attempted. - @type: C{int} - - @ivar _reactor: The reactor to use to perform the zone transfers, or C{None} - to use the global reactor. - """ - - transferring = False - soa = records = None - _port = 53 - _reactor = None - - def __init__(self, primaryIP, domain): - # Yep. Skip over FileAuthority.__init__. This is a hack until we have - # a good composition-based API for the complicated DNS record lookup - # logic we want to share. - common.ResolverBase.__init__(self) - self.primary = primaryIP - self.domain = domain - - - @classmethod - def fromServerAddressAndDomain(cls, serverAddress, domain): - """ - Construct a new L{SecondaryAuthority} from a tuple giving a server - address and a C{str} giving the name of a domain for which this is an - authority. - - @param serverAddress: A two-tuple, the first element of which is a - C{str} giving an IP address and the second element of which is a - C{int} giving a port number. Together, these define where zone - transfers will be attempted from. - - @param domain: A C{str} giving the domain to transfer. - - @return: A new instance of L{SecondaryAuthority}. - """ - secondary = cls(None, None) - secondary.primary = serverAddress[0] - secondary._port = serverAddress[1] - secondary.domain = domain - return secondary - - - def transfer(self): - if self.transferring: - return - self.transfering = True - - reactor = self._reactor - if reactor is None: - from twisted.internet import reactor - - resolver = client.Resolver( - servers=[(self.primary, self._port)], reactor=reactor) - return resolver.lookupZone(self.domain - ).addCallback(self._cbZone - ).addErrback(self._ebZone - ) - - - def _lookup(self, name, cls, type, timeout=None): - if not self.soa or not self.records: - return defer.fail(failure.Failure(dns.DomainError(name))) - return FileAuthority._lookup(self, name, cls, type, timeout) - - - def _cbZone(self, zone): - ans, _, _ = zone - self.records = r = {} - for rec in ans: - if not self.soa and rec.type == dns.SOA: - self.soa = (str(rec.name).lower(), rec.payload) - else: - r.setdefault(str(rec.name).lower(), []).append(rec.payload) - - - def _ebZone(self, failure): - log.msg("Updating %s from %s failed during zone transfer" % (self.domain, self.primary)) - log.err(failure) - - - def update(self): - self.transfer().addCallbacks(self._cbTransferred, self._ebTransferred) - - - def _cbTransferred(self, result): - self.transferring = False - - - def _ebTransferred(self, failure): - self.transferred = False - log.msg("Transferring %s from %s failed after zone transfer" % (self.domain, self.primary)) - log.err(failure) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/server.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/server.py deleted file mode 100644 index d2b895f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/server.py +++ /dev/null @@ -1,594 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names,twisted.names.test.test_server -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Async DNS server - -Future plans: - - Better config file format maybe - - Make sure to differentiate between different classes - - notice truncation bit - -Important: No additional processing is done on some of the record types. -This violates the most basic RFC and is just plain annoying -for resolvers to deal with. Fix it. - -@author: Jp Calderone -""" - -import time - -from twisted.internet import protocol -from twisted.names import dns, resolve -from twisted.python import log - - -class DNSServerFactory(protocol.ServerFactory): - """ - Server factory and tracker for L{DNSProtocol} connections. This class also - provides records for responses to DNS queries. - - @ivar cache: A L{Cache} instance whose - C{cacheResult} method is called when a response is received from one of - C{clients}. Defaults to L{None} if no caches are specified. See - C{caches} of L{__init__} for more details. - @type cache: L{Cache 0: - log.msg(*args, **kwargs) - - - def buildProtocol(self, addr): - p = self.protocol(self) - p.factory = self - return p - - - def connectionMade(self, protocol): - """ - Track a newly connected L{DNSProtocol}. - - @param protocol: The protocol instance to be tracked. - @type protocol: L{dns.DNSProtocol} - """ - self.connections.append(protocol) - - - def connectionLost(self, protocol): - """ - Stop tracking a no-longer connected L{DNSProtocol}. - - @param protocol: The tracked protocol instance to be which has been - lost. - @type protocol: L{dns.DNSProtocol} - """ - self.connections.remove(protocol) - - - def sendReply(self, protocol, message, address): - """ - Send a response C{message} to a given C{address} via the supplied - C{protocol}. - - Message payload will be logged if C{DNSServerFactory.verbose} is C{>1}. - - @param protocol: The DNS protocol instance to which to send the message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The DNS message to be sent. - @type message: L{dns.Message} - - @param address: The address to which the message will be sent or L{None} - if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - """ - if self.verbose > 1: - s = ' '.join([str(a.payload) for a in message.answers]) - auth = ' '.join([str(a.payload) for a in message.authority]) - add = ' '.join([str(a.payload) for a in message.additional]) - if not s: - log.msg("Replying with no answers") - else: - log.msg("Answers are " + s) - log.msg("Authority is " + auth) - log.msg("Additional is " + add) - - if address is None: - protocol.writeMessage(message) - else: - protocol.writeMessage(message, address) - - self._verboseLog( - "Processed query in %0.3f seconds" % ( - time.time() - message.timeReceived)) - - - def _responseFromMessage(self, message, rCode=dns.OK, - answers=None, authority=None, additional=None): - """ - Generate a L{Message} instance suitable for use as the response to - C{message}. - - C{queries} will be copied from the request to the response. - - C{rCode}, C{answers}, C{authority} and C{additional} will be assigned to - the response, if supplied. - - The C{recAv} flag will be set on the response if the C{canRecurse} flag - on this L{DNSServerFactory} is set to L{True}. - - The C{auth} flag will be set on the response if *any* of the supplied - C{answers} have their C{auth} flag set to L{True}. - - The response will have the same C{maxSize} as the request. - - Additionally, the response will have a C{timeReceived} attribute whose - value is that of the original request and the - - @see: L{dns._responseFromMessage} - - @param message: The request message - @type message: L{Message} - - @param rCode: The response code which will be assigned to the response. - @type message: L{int} - - @param answers: An optional list of answer records which will be - assigned to the response. - @type answers: L{list} of L{dns.RRHeader} - - @param authority: An optional list of authority records which will be - assigned to the response. - @type authority: L{list} of L{dns.RRHeader} - - @param additional: An optional list of additional records which will be - assigned to the response. - @type additional: L{list} of L{dns.RRHeader} - - @return: A response L{Message} instance. - @rtype: L{Message} - """ - if answers is None: - answers = [] - if authority is None: - authority = [] - if additional is None: - additional = [] - authoritativeAnswer = False - for x in answers: - if x.isAuthoritative(): - authoritativeAnswer = True - break - - response = dns._responseFromMessage( - responseConstructor=self._messageFactory, - message=message, - recAv=self.canRecurse, - rCode=rCode, - auth=authoritativeAnswer - ) - - # XXX: Timereceived is a hack which probably shouldn't be tacked onto - # the message. Use getattr here so that we don't have to set the - # timereceived on every message in the tests. See #6957. - response.timeReceived = getattr(message, 'timeReceived', None) - - # XXX: This is another hack. dns.Message.decode sets maxSize=0 which - # means that responses are never truncated. I'll maintain that behaviour - # here until #6949 is resolved. - response.maxSize = message.maxSize - - response.answers = answers - response.authority = authority - response.additional = additional - - return response - - - def gotResolverResponse(self, (ans, auth, add), protocol, message, address): - """ - A callback used by L{DNSServerFactory.handleQuery} for handling the - deferred response from C{self.resolver.query}. - - Constructs a response message by combining the original query message - with the resolved answer, authority and additional records. - - Marks the response message as authoritative if any of the resolved - answers are found to be authoritative. - - The resolved answers count will be logged if C{DNSServerFactory.verbose} - is C{>1}. - - @param ans: A list of answer records - @type ans: L{list} of L{dns.RRHeader} instances - - @param auth: A list of authority records - @type auth: L{list} of L{dns.RRHeader} instances - - @param add: A list of additional records - @type add: L{list} of L{dns.RRHeader} instances - - @param protocol: The DNS protocol instance to which to send a response - message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The original DNS query message for which a response - message will be constructed. - @type message: L{dns.Message} - - @param address: The address to which the response message will be sent - or L{None} if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - """ - response = self._responseFromMessage( - message=message, rCode=dns.OK, - answers=ans, authority=auth, additional=add) - self.sendReply(protocol, response, address) - - l = len(ans) + len(auth) + len(add) - self._verboseLog("Lookup found %d record%s" % (l, l != 1 and "s" or "")) - - if self.cache and l: - self.cache.cacheResult( - message.queries[0], (ans, auth, add) - ) - - - def gotResolverError(self, failure, protocol, message, address): - """ - A callback used by L{DNSServerFactory.handleQuery} for handling deferred - errors from C{self.resolver.query}. - - Constructs a response message from the original query message by - assigning a suitable error code to C{rCode}. - - An error message will be logged if C{DNSServerFactory.verbose} is C{>1}. - - @param failure: The reason for the failed resolution (as reported by - C{self.resolver.query}). - @type failure: L{Failure} - - @param protocol: The DNS protocol instance to which to send a response - message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The original DNS query message for which a response - message will be constructed. - @type message: L{dns.Message} - - @param address: The address to which the response message will be sent - or L{None} if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - """ - if failure.check(dns.DomainError, dns.AuthoritativeDomainError): - rCode = dns.ENAME - else: - rCode = dns.ESERVER - log.err(failure) - - response = self._responseFromMessage(message=message, rCode=rCode) - - self.sendReply(protocol, response, address) - self._verboseLog("Lookup failed") - - - def handleQuery(self, message, protocol, address): - """ - Called by L{DNSServerFactory.messageReceived} when a query message is - received. - - Takes the first query from the received message and dispatches it to - C{self.resolver.query}. - - Adds callbacks L{DNSServerFactory.gotResolverResponse} and - L{DNSServerFactory.gotResolverError} to the resulting deferred. - - Note: Multiple queries in a single message are not supported because - there is no standard way to respond with multiple rCodes, auth, - etc. This is consistent with other DNS server implementations. See - U{http://tools.ietf.org/html/draft-ietf-dnsext-edns1-03} for a proposed - solution. - - @param protocol: The DNS protocol instance to which to send a response - message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The original DNS query message for which a response - message will be constructed. - @type message: L{dns.Message} - - @param address: The address to which the response message will be sent - or L{None} if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - - @return: A C{deferred} which fires with the resolved result or error of - the first query in C{message}. - @rtype: L{Deferred} - """ - query = message.queries[0] - - return self.resolver.query(query).addCallback( - self.gotResolverResponse, protocol, message, address - ).addErrback( - self.gotResolverError, protocol, message, address - ) - - - def handleInverseQuery(self, message, protocol, address): - """ - Called by L{DNSServerFactory.messageReceived} when an inverse query - message is received. - - Replies with a I{Not Implemented} error by default. - - An error message will be logged if C{DNSServerFactory.verbose} is C{>1}. - - Override in a subclass. - - @param protocol: The DNS protocol instance to which to send a response - message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The original DNS query message for which a response - message will be constructed. - @type message: L{dns.Message} - - @param address: The address to which the response message will be sent - or L{None} if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - """ - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - self._verboseLog("Inverse query from %r" % (address,)) - - - def handleStatus(self, message, protocol, address): - """ - Called by L{DNSServerFactory.messageReceived} when a status message is - received. - - Replies with a I{Not Implemented} error by default. - - An error message will be logged if C{DNSServerFactory.verbose} is C{>1}. - - Override in a subclass. - - @param protocol: The DNS protocol instance to which to send a response - message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The original DNS query message for which a response - message will be constructed. - @type message: L{dns.Message} - - @param address: The address to which the response message will be sent - or L{None} if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - """ - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - self._verboseLog("Status request from %r" % (address,)) - - - def handleNotify(self, message, protocol, address): - """ - Called by L{DNSServerFactory.messageReceived} when a notify message is - received. - - Replies with a I{Not Implemented} error by default. - - An error message will be logged if C{DNSServerFactory.verbose} is C{>1}. - - Override in a subclass. - - @param protocol: The DNS protocol instance to which to send a response - message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The original DNS query message for which a response - message will be constructed. - @type message: L{dns.Message} - - @param address: The address to which the response message will be sent - or L{None} if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - """ - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - self._verboseLog("Notify message from %r" % (address,)) - - - def handleOther(self, message, protocol, address): - """ - Called by L{DNSServerFactory.messageReceived} when a message with - unrecognised I{OPCODE} is received. - - Replies with a I{Not Implemented} error by default. - - An error message will be logged if C{DNSServerFactory.verbose} is C{>1}. - - Override in a subclass. - - @param protocol: The DNS protocol instance to which to send a response - message. - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param message: The original DNS query message for which a response - message will be constructed. - @type message: L{dns.Message} - - @param address: The address to which the response message will be sent - or L{None} if C{protocol} is a stream protocol. - @type address: L{tuple} or L{None} - """ - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - self._verboseLog( - "Unknown op code (%d) from %r" % (message.opCode, address)) - - - def messageReceived(self, message, proto, address=None): - """ - L{DNSServerFactory.messageReceived} is called by protocols which are - under the control of this L{DNSServerFactory} whenever they receive a - DNS query message or an unexpected / duplicate / late DNS response - message. - - L{DNSServerFactory.allowQuery} is called with the received message, - protocol and origin address. If it returns L{False}, a C{dns.EREFUSED} - response is sent back to the client. - - Otherwise the received message is dispatched to one of - L{DNSServerFactory.handleQuery}, L{DNSServerFactory.handleInverseQuery}, - L{DNSServerFactory.handleStatus}, L{DNSServerFactory.handleNotify}, or - L{DNSServerFactory.handleOther} depending on the I{OPCODE} of the - received message. - - If C{DNSServerFactory.verbose} is C{>0} all received messages will be - logged in more or less detail depending on the value of C{verbose}. - - @param message: The DNS message that was received. - @type message: L{dns.Message} - - @param proto: The DNS protocol instance which received the message - @type proto: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param address: The address from which the message was received. Only - provided for messages received by datagram protocols. The origin of - Messages received from stream protocols can be gleaned from the - protocol C{transport} attribute. - @type address: L{tuple} or L{None} - """ - message.timeReceived = time.time() - - if self.verbose: - if self.verbose > 1: - s = ' '.join([str(q) for q in message.queries]) - else: - s = ' '.join([dns.QUERY_TYPES.get(q.type, 'UNKNOWN') - for q in message.queries]) - if not len(s): - log.msg( - "Empty query from %r" % ( - (address or proto.transport.getPeer()),)) - else: - log.msg( - "%s query from %r" % ( - s, address or proto.transport.getPeer())) - - if not self.allowQuery(message, proto, address): - message.rCode = dns.EREFUSED - self.sendReply(proto, message, address) - elif message.opCode == dns.OP_QUERY: - self.handleQuery(message, proto, address) - elif message.opCode == dns.OP_INVERSE: - self.handleInverseQuery(message, proto, address) - elif message.opCode == dns.OP_STATUS: - self.handleStatus(message, proto, address) - elif message.opCode == dns.OP_NOTIFY: - self.handleNotify(message, proto, address) - else: - self.handleOther(message, proto, address) - - - def allowQuery(self, message, protocol, address): - """ - Called by L{DNSServerFactory.messageReceived} to decide whether to - process a received message or to reply with C{dns.EREFUSED}. - - This default implementation permits anything but empty queries. - - Override in a subclass to implement alternative policies. - - @param message: The DNS message that was received. - @type message: L{dns.Message} - - @param protocol: The DNS protocol instance which received the message - @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol} - - @param address: The address from which the message was received. Only - provided for messages received by datagram protocols. The origin of - Messages received from stream protocols can be gleaned from the - protocol C{transport} attribute. - @type address: L{tuple} or L{None} - - @return: L{True} if the received message contained one or more queries, - else L{False}. - @rtype: L{bool} - """ - return len(message.queries) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/srvconnect.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/srvconnect.py deleted file mode 100644 index cf10b0d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/srvconnect.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_srvconnect -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from functools import reduce - -from zope.interface import implements - -from twisted.internet import error, interfaces -from twisted.names import client, dns -from twisted.names.error import DNSNameError -from twisted.python.compat import unicode - - -class _SRVConnector_ClientFactoryWrapper: - def __init__(self, connector, wrappedFactory): - self.__connector = connector - self.__wrappedFactory = wrappedFactory - - def startedConnecting(self, connector): - self.__wrappedFactory.startedConnecting(self.__connector) - - def clientConnectionFailed(self, connector, reason): - self.__connector.connectionFailed(reason) - - def clientConnectionLost(self, connector, reason): - self.__connector.connectionLost(reason) - - def __getattr__(self, key): - return getattr(self.__wrappedFactory, key) - - - -class SRVConnector: - """A connector that looks up DNS SRV records. See RFC2782.""" - - implements(interfaces.IConnector) - - stopAfterDNS=0 - - def __init__(self, reactor, service, domain, factory, - protocol='tcp', connectFuncName='connectTCP', - connectFuncArgs=(), - connectFuncKwArgs={}, - defaultPort=None, - ): - """ - @param domain: The domain to connect to. If passed as a unicode - string, it will be encoded using C{idna} encoding. - @type domain: L{bytes} or L{unicode} - @param defaultPort: Optional default port number to be used when SRV - lookup fails and the service name is unknown. This should be the - port number associated with the service name as defined by the IANA - registry. - @type defaultPort: C{int} - """ - self.reactor = reactor - self.service = service - if isinstance(domain, unicode): - domain = domain.encode('idna') - self.domain = domain - self.factory = factory - - self.protocol = protocol - self.connectFuncName = connectFuncName - self.connectFuncArgs = connectFuncArgs - self.connectFuncKwArgs = connectFuncKwArgs - self._defaultPort = defaultPort - - self.connector = None - self.servers = None - self.orderedServers = None # list of servers already used in this round - - def connect(self): - """Start connection to remote server.""" - self.factory.doStart() - self.factory.startedConnecting(self) - - if not self.servers: - if self.domain is None: - self.connectionFailed(error.DNSLookupError("Domain is not defined.")) - return - d = client.lookupService('_%s._%s.%s' % (self.service, - self.protocol, - self.domain)) - d.addCallbacks(self._cbGotServers, self._ebGotServers) - d.addCallback(lambda x, self=self: self._reallyConnect()) - if self._defaultPort: - d.addErrback(self._ebServiceUnknown) - d.addErrback(self.connectionFailed) - elif self.connector is None: - self._reallyConnect() - else: - self.connector.connect() - - def _ebGotServers(self, failure): - failure.trap(DNSNameError) - - # Some DNS servers reply with NXDOMAIN when in fact there are - # just no SRV records for that domain. Act as if we just got an - # empty response and use fallback. - - self.servers = [] - self.orderedServers = [] - - def _cbGotServers(self, (answers, auth, add)): - if len(answers) == 1 and answers[0].type == dns.SRV \ - and answers[0].payload \ - and answers[0].payload.target == dns.Name('.'): - # decidedly not available - raise error.DNSLookupError("Service %s not available for domain %s." - % (repr(self.service), repr(self.domain))) - - self.servers = [] - self.orderedServers = [] - for a in answers: - if a.type != dns.SRV or not a.payload: - continue - - self.orderedServers.append((a.payload.priority, a.payload.weight, - str(a.payload.target), a.payload.port)) - - def _ebServiceUnknown(self, failure): - """ - Connect to the default port when the service name is unknown. - - If no SRV records were found, the service name will be passed as the - port. If resolving the name fails with - L{error.ServiceNameUnknownError}, a final attempt is done using the - default port. - """ - failure.trap(error.ServiceNameUnknownError) - self.servers = [(0, 0, self.domain, self._defaultPort)] - self.orderedServers = [] - self.connect() - - def _serverCmp(self, a, b): - if a[0]!=b[0]: - return cmp(a[0], b[0]) - else: - return cmp(a[1], b[1]) - - def pickServer(self): - assert self.servers is not None - assert self.orderedServers is not None - - if not self.servers and not self.orderedServers: - # no SRV record, fall back.. - return self.domain, self.service - - if not self.servers and self.orderedServers: - # start new round - self.servers = self.orderedServers - self.orderedServers = [] - - assert self.servers - - self.servers.sort(self._serverCmp) - minPriority=self.servers[0][0] - - weightIndex = zip(xrange(len(self.servers)), [x[1] for x in self.servers - if x[0]==minPriority]) - weightSum = reduce(lambda x, y: (None, x[1]+y[1]), weightIndex, (None, 0))[1] - - for index, weight in weightIndex: - weightSum -= weight - if weightSum <= 0: - chosen = self.servers[index] - del self.servers[index] - self.orderedServers.append(chosen) - - p, w, host, port = chosen - return host, port - - raise RuntimeError, 'Impossible %s pickServer result.' % self.__class__.__name__ - - def _reallyConnect(self): - if self.stopAfterDNS: - self.stopAfterDNS=0 - return - - self.host, self.port = self.pickServer() - assert self.host is not None, 'Must have a host to connect to.' - assert self.port is not None, 'Must have a port to connect to.' - - connectFunc = getattr(self.reactor, self.connectFuncName) - self.connector=connectFunc( - self.host, self.port, - _SRVConnector_ClientFactoryWrapper(self, self.factory), - *self.connectFuncArgs, **self.connectFuncKwArgs) - - def stopConnecting(self): - """Stop attempting to connect.""" - if self.connector: - self.connector.stopConnecting() - else: - self.stopAfterDNS=1 - - def disconnect(self): - """Disconnect whatever our are state is.""" - if self.connector is not None: - self.connector.disconnect() - else: - self.stopConnecting() - - def getDestination(self): - assert self.connector - return self.connector.getDestination() - - def connectionFailed(self, reason): - self.factory.clientConnectionFailed(self, reason) - self.factory.doStop() - - def connectionLost(self, reason): - self.factory.clientConnectionLost(self, reason) - self.factory.doStop() - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/tap.py deleted file mode 100644 index d0e3b1d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/tap.py +++ /dev/null @@ -1,150 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_tap -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Domain Name Server -""" - -import os, traceback - -from twisted.python import usage -from twisted.names import dns -from twisted.application import internet, service - -from twisted.names import server -from twisted.names import authority -from twisted.names import secondary - -class Options(usage.Options): - optParameters = [ - ["interface", "i", "", "The interface to which to bind"], - ["port", "p", "53", "The port on which to listen"], - ["resolv-conf", None, None, - "Override location of resolv.conf (implies --recursive)"], - ["hosts-file", None, None, "Perform lookups with a hosts file"], - ] - - optFlags = [ - ["cache", "c", "Enable record caching"], - ["recursive", "r", "Perform recursive lookups"], - ["verbose", "v", "Log verbosely"], - ] - - compData = usage.Completions( - optActions={"interface" : usage.CompleteNetInterfaces()} - ) - - zones = None - zonefiles = None - - def __init__(self): - usage.Options.__init__(self) - self['verbose'] = 0 - self.bindfiles = [] - self.zonefiles = [] - self.secondaries = [] - - - def opt_pyzone(self, filename): - """Specify the filename of a Python syntax zone definition""" - if not os.path.exists(filename): - raise usage.UsageError(filename + ": No such file") - self.zonefiles.append(filename) - - def opt_bindzone(self, filename): - """Specify the filename of a BIND9 syntax zone definition""" - if not os.path.exists(filename): - raise usage.UsageError(filename + ": No such file") - self.bindfiles.append(filename) - - - def opt_secondary(self, ip_domain): - """Act as secondary for the specified domain, performing - zone transfers from the specified IP (IP/domain) - """ - args = ip_domain.split('/', 1) - if len(args) != 2: - raise usage.UsageError("Argument must be of the form IP[:port]/domain") - address = args[0].split(':') - if len(address) == 1: - address = (address[0], dns.PORT) - else: - try: - port = int(address[1]) - except ValueError: - raise usage.UsageError( - "Specify an integer port number, not %r" % (address[1],)) - address = (address[0], port) - self.secondaries.append((address, [args[1]])) - - - def opt_verbose(self): - """Increment verbosity level""" - self['verbose'] += 1 - - - def postOptions(self): - if self['resolv-conf']: - self['recursive'] = True - - self.svcs = [] - self.zones = [] - for f in self.zonefiles: - try: - self.zones.append(authority.PySourceAuthority(f)) - except Exception: - traceback.print_exc() - raise usage.UsageError("Invalid syntax in " + f) - for f in self.bindfiles: - try: - self.zones.append(authority.BindAuthority(f)) - except Exception: - traceback.print_exc() - raise usage.UsageError("Invalid syntax in " + f) - for f in self.secondaries: - svc = secondary.SecondaryAuthorityService.fromServerAddressAndDomains(*f) - self.svcs.append(svc) - self.zones.append(self.svcs[-1].getAuthority()) - try: - self['port'] = int(self['port']) - except ValueError: - raise usage.UsageError("Invalid port: %r" % (self['port'],)) - - -def _buildResolvers(config): - """ - Build DNS resolver instances in an order which leaves recursive - resolving as a last resort. - - @type config: L{Options} instance - @param config: Parsed command-line configuration - - @return: Two-item tuple of a list of cache resovers and a list of client - resolvers - """ - from twisted.names import client, cache, hosts - - ca, cl = [], [] - if config['cache']: - ca.append(cache.CacheResolver(verbose=config['verbose'])) - if config['hosts-file']: - cl.append(hosts.Resolver(file=config['hosts-file'])) - if config['recursive']: - cl.append(client.createResolver(resolvconf=config['resolv-conf'])) - return ca, cl - - -def makeService(config): - ca, cl = _buildResolvers(config) - - f = server.DNSServerFactory(config.zones, ca, cl, config['verbose']) - p = dns.DNSDatagramProtocol(f) - f.noisy = 0 - ret = service.MultiService() - for (klass, arg) in [(internet.TCPServer, f), (internet.UDPServer, p)]: - s = klass(config['port'], arg, interface=config['interface']) - s.setServiceParent(ret) - for svc in config.svcs: - svc.setServiceParent(ret) - return ret diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/__init__.py deleted file mode 100644 index f6b7e3a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"Tests for twisted.names" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_cache.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_cache.py deleted file mode 100644 index 165ed67..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_cache.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.names.cache}. -""" - -from __future__ import division, absolute_import - -import time - -from zope.interface.verify import verifyClass - -from twisted.trial import unittest - -from twisted.names import dns, cache -from twisted.internet import task, interfaces - - -class CachingTests(unittest.TestCase): - """ - Tests for L{cache.CacheResolver}. - """ - - def test_interface(self): - """ - L{cache.CacheResolver} implements L{interfaces.IResolver} - """ - verifyClass(interfaces.IResolver, cache.CacheResolver) - - - def test_lookup(self): - c = cache.CacheResolver({ - dns.Query(name=b'example.com', type=dns.MX, cls=dns.IN): - (time.time(), ([], [], []))}) - return c.lookupMailExchange(b'example.com').addCallback( - self.assertEqual, ([], [], [])) - - - def test_constructorExpires(self): - """ - Cache entries passed into L{cache.CacheResolver.__init__} get - cancelled just like entries added with cacheResult - """ - r = ([dns.RRHeader(b"example.com", dns.A, dns.IN, 60, - dns.Record_A("127.0.0.1", 60))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 50, - dns.Record_A("127.0.0.1", 50))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 40, - dns.Record_A("127.0.0.1", 40))]) - - clock = task.Clock() - query = dns.Query(name=b"example.com", type=dns.A, cls=dns.IN) - - c = cache.CacheResolver({ query : (clock.seconds(), r)}, reactor=clock) - - # 40 seconds is enough to expire the entry because expiration is based - # on the minimum TTL. - clock.advance(40) - - self.assertNotIn(query, c.cache) - - return self.assertFailure( - c.lookupAddress(b"example.com"), dns.DomainError) - - - def test_normalLookup(self): - """ - When a cache lookup finds a cached entry from 1 second ago, it is - returned with a TTL of original TTL minus the elapsed 1 second. - """ - r = ([dns.RRHeader(b"example.com", dns.A, dns.IN, 60, - dns.Record_A("127.0.0.1", 60))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 50, - dns.Record_A("127.0.0.1", 50))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 40, - dns.Record_A("127.0.0.1", 40))]) - - clock = task.Clock() - - c = cache.CacheResolver(reactor=clock) - c.cacheResult(dns.Query(name=b"example.com", type=dns.A, cls=dns.IN), r) - - clock.advance(1) - - def cbLookup(result): - self.assertEqual(result[0][0].ttl, 59) - self.assertEqual(result[1][0].ttl, 49) - self.assertEqual(result[2][0].ttl, 39) - self.assertEqual(result[0][0].name.name, b"example.com") - - return c.lookupAddress(b"example.com").addCallback(cbLookup) - - - def test_cachedResultExpires(self): - """ - Once the TTL has been exceeded, the result is removed from the cache. - """ - r = ([dns.RRHeader(b"example.com", dns.A, dns.IN, 60, - dns.Record_A("127.0.0.1", 60))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 50, - dns.Record_A("127.0.0.1", 50))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 40, - dns.Record_A("127.0.0.1", 40))]) - - clock = task.Clock() - - c = cache.CacheResolver(reactor=clock) - query = dns.Query(name=b"example.com", type=dns.A, cls=dns.IN) - c.cacheResult(query, r) - - clock.advance(40) - - self.assertNotIn(query, c.cache) - - return self.assertFailure( - c.lookupAddress(b"example.com"), dns.DomainError) - - - def test_expiredTTLLookup(self): - """ - When the cache is queried exactly as the cached entry should expire but - before it has actually been cleared, the cache does not return the - expired entry. - """ - r = ([dns.RRHeader(b"example.com", dns.A, dns.IN, 60, - dns.Record_A("127.0.0.1", 60))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 50, - dns.Record_A("127.0.0.1", 50))], - [dns.RRHeader(b"example.com", dns.A, dns.IN, 40, - dns.Record_A("127.0.0.1", 40))]) - - clock = task.Clock() - # Make sure timeouts never happen, so entries won't get cleared: - clock.callLater = lambda *args, **kwargs: None - - c = cache.CacheResolver({ - dns.Query(name=b"example.com", type=dns.A, cls=dns.IN) : - (clock.seconds(), r)}, reactor=clock) - - clock.advance(60.1) - - return self.assertFailure( - c.lookupAddress(b"example.com"), dns.DomainError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_client.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_client.py deleted file mode 100644 index 7f09b1c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_client.py +++ /dev/null @@ -1,1214 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.names.client}. -""" - -from __future__ import division, absolute_import - -from zope.interface.verify import verifyClass, verifyObject - -from twisted.python import failure -from twisted.python.filepath import FilePath -from twisted.python.runtime import platform - -from twisted.internet import defer -from twisted.internet.error import CannotListenError, ConnectionRefusedError -from twisted.internet.interfaces import IResolver -from twisted.internet.test.modulehelpers import AlternateReactor -from twisted.internet.task import Clock - -from twisted.names import error, client, dns, hosts, cache -from twisted.names.error import DNSQueryTimeoutError -from twisted.names.common import ResolverBase - -from twisted.names.test.test_hosts import GoodTempPathMixin -from twisted.names.test.test_util import MemoryReactor - -from twisted.test import proto_helpers - -from twisted.trial import unittest - -if platform.isWindows(): - windowsSkip = "These tests need more work before they'll work on Windows." -else: - windowsSkip = None - - - -class FakeResolver(ResolverBase): - - def _lookup(self, name, cls, qtype, timeout): - """ - The getHostByNameTest does a different type of query that requires it - return an A record from an ALL_RECORDS lookup, so we accommodate that - here. - """ - if name == b'getHostByNameTest': - rr = dns.RRHeader(name=name, type=dns.A, cls=cls, ttl=60, - payload=dns.Record_A(address='127.0.0.1', ttl=60)) - else: - rr = dns.RRHeader(name=name, type=qtype, cls=cls, ttl=60) - - results = [rr] - authority = [] - addtional = [] - return defer.succeed((results, authority, addtional)) - - - -class StubPort(object): - """ - A partial implementation of L{IListeningPort} which only keeps track of - whether it has been stopped. - - @ivar disconnected: A C{bool} which is C{False} until C{stopListening} is - called, C{True} afterwards. - """ - disconnected = False - - def stopListening(self): - self.disconnected = True - - - -class StubDNSDatagramProtocol(object): - """ - L{dns.DNSDatagramProtocol}-alike. - - @ivar queries: A C{list} of tuples giving the arguments passed to - C{query} along with the L{defer.Deferred} which was returned from - the call. - """ - def __init__(self): - self.queries = [] - self.transport = StubPort() - - - def query(self, address, queries, timeout=10, id=None): - """ - Record the given arguments and return a Deferred which will not be - called back by this code. - """ - result = defer.Deferred() - self.queries.append((address, queries, timeout, id, result)) - return result - - - -class GetResolverTests(unittest.TestCase): - """ - Tests for L{client.getResolver}. - """ - if windowsSkip: - skip = windowsSkip - - def test_interface(self): - """ - L{client.getResolver} returns an object providing L{IResolver}. - """ - with AlternateReactor(Clock()): - resolver = client.getResolver() - self.assertTrue(verifyObject(IResolver, resolver)) - - - def test_idempotent(self): - """ - Multiple calls to L{client.getResolver} return the same L{IResolver} - implementation. - """ - with AlternateReactor(Clock()): - a = client.getResolver() - b = client.getResolver() - self.assertIs(a, b) - - - -class CreateResolverTests(unittest.TestCase, GoodTempPathMixin): - """ - Tests for L{client.createResolver}. - """ - if windowsSkip: - skip = windowsSkip - - def _hostsTest(self, resolver, filename): - res = [r for r in resolver.resolvers if isinstance(r, hosts.Resolver)] - self.assertEqual(1, len(res)) - self.assertEqual(res[0].file, filename) - - - def test_defaultHosts(self): - """ - L{client.createResolver} returns a L{resolve.ResolverChain} including a - L{hosts.Resolver} using I{/etc/hosts} if no alternate hosts file is - specified. - """ - with AlternateReactor(Clock()): - resolver = client.createResolver() - self._hostsTest(resolver, b"/etc/hosts") - - - def test_overrideHosts(self): - """ - The I{hosts} parameter to L{client.createResolver} overrides the hosts - file used by the L{hosts.Resolver} in the L{resolve.ResolverChain} it - returns. - """ - with AlternateReactor(Clock()): - resolver = client.createResolver(hosts=b"/foo/bar") - self._hostsTest(resolver, b"/foo/bar") - - - def _resolvConfTest(self, resolver, filename): - """ - Verify that C{resolver} has a L{client.Resolver} with a configuration - filename set to C{filename}. - """ - res = [r for r in resolver.resolvers if isinstance(r, client.Resolver)] - self.assertEqual(1, len(res)) - self.assertEqual(res[0].resolv, filename) - - - def test_reactor(self): - """ - The L{client.Resolver} included in the L{resolve.ResolverChain} returned - by L{client.createResolver} uses the global reactor. - """ - reactor = Clock() - with AlternateReactor(reactor): - resolver = client.createResolver() - res = [r for r in resolver.resolvers if isinstance(r, client.Resolver)] - self.assertEqual(1, len(res)) - self.assertIs(reactor, res[0]._reactor) - - - def test_defaultResolvConf(self): - """ - L{client.createResolver} returns a L{resolve.ResolverChain} including a - L{client.Resolver} using I{/etc/resolv.conf} if no alternate resolver - configuration file is specified. - """ - with AlternateReactor(Clock()): - resolver = client.createResolver() - self._resolvConfTest(resolver, b"/etc/resolv.conf") - - - def test_overrideResolvConf(self): - """ - The I{resolvconf} parameter to L{client.createResolver} overrides the - resolver configuration file used by the L{client.Resolver} in the - L{resolve.ResolverChain} it returns. - """ - with AlternateReactor(Clock()): - resolver = client.createResolver(resolvconf=b"/foo/bar") - self._resolvConfTest(resolver, b"/foo/bar") - - - def test_defaultServers(self): - """ - If no servers are given, addresses are taken from the file given by the - I{resolvconf} parameter to L{client.createResolver}. - """ - resolvconf = self.path() - resolvconf.setContent(b"nameserver 127.1.2.3\n") - with AlternateReactor(Clock()): - resolver = client.createResolver(resolvconf=resolvconf.path) - res = [r for r in resolver.resolvers if isinstance(r, client.Resolver)] - self.assertEqual(1, len(res)) - self.assertEqual([], res[0].servers) - self.assertEqual([("127.1.2.3", 53)], res[0].dynServers) - - - def test_overrideServers(self): - """ - Servers passed to L{client.createResolver} are used in addition to any - found in the file given by the I{resolvconf} parameter. - """ - resolvconf = self.path() - resolvconf.setContent(b"nameserver 127.1.2.3\n") - with AlternateReactor(Clock()): - resolver = client.createResolver( - servers=[("127.3.2.1", 53)], resolvconf=resolvconf.path) - res = [r for r in resolver.resolvers if isinstance(r, client.Resolver)] - self.assertEqual(1, len(res)) - self.assertEqual([("127.3.2.1", 53)], res[0].servers) - self.assertEqual([("127.1.2.3", 53)], res[0].dynServers) - - - def test_cache(self): - """ - L{client.createResolver} returns a L{resolve.ResolverChain} including a - L{cache.CacheResolver}. - """ - with AlternateReactor(Clock()): - resolver = client.createResolver() - res = [r for r in resolver.resolvers if isinstance(r, cache.CacheResolver)] - self.assertEqual(1, len(res)) - - - - -class ResolverTests(unittest.TestCase): - """ - Tests for L{client.Resolver}. - """ - - def test_clientProvidesIResolver(self): - """ - L{client} provides L{IResolver} through a series of free - functions. - """ - verifyObject(IResolver, client) - - - def test_clientResolverProvidesIResolver(self): - """ - L{client.Resolver} provides L{IResolver}. - """ - verifyClass(IResolver, client.Resolver) - - - def test_noServers(self): - """ - L{client.Resolver} raises L{ValueError} if constructed with neither - servers nor a nameserver configuration file. - """ - self.assertRaises(ValueError, client.Resolver) - - - def test_missingConfiguration(self): - """ - A missing nameserver configuration file results in no server information - being loaded from it (ie, not an exception) and a default server being - provided. - """ - resolver = client.Resolver(resolv=self.mktemp(), reactor=Clock()) - self.assertEqual([("127.0.0.1", 53)], resolver.dynServers) - - - def test_closesResolvConf(self): - """ - As part of its constructor, C{StubResolver} opens C{/etc/resolv.conf}; - then, explicitly closes it and does not count on the GC to do so for - it. - """ - handle = FilePath(self.mktemp()) - resolvConf = handle.open(mode='w+') - class StubResolver(client.Resolver): - def _openFile(self, name): - return resolvConf - StubResolver(servers=["example.com", 53], resolv='/etc/resolv.conf', - reactor=Clock()) - self.assertTrue(resolvConf.closed) - - - def test_domainEmptyArgument(self): - """ - L{client.Resolver.parseConfig} treats a I{domain} line without an - argument as indicating a domain of C{b""}. - """ - resolver = client.Resolver(servers=[("127.0.0.1", 53)]) - resolver.parseConfig([b"domain\n"]) - self.assertEqual(b"", resolver.domain) - - - def test_searchEmptyArgument(self): - """ - L{client.Resolver.parseConfig} treats a I{search} line without an - argument as indicating an empty search suffix. - """ - resolver = client.Resolver(servers=[("127.0.0.1", 53)]) - resolver.parseConfig([b"search\n"]) - self.assertEqual([], resolver.search) - - - def test_datagramQueryServerOrder(self): - """ - L{client.Resolver.queryUDP} should issue queries to its - L{dns.DNSDatagramProtocol} with server addresses taken from its own - C{servers} and C{dynServers} lists, proceeding through them in order - as L{DNSQueryTimeoutError}s occur. - """ - protocol = StubDNSDatagramProtocol() - - servers = [object(), object()] - dynServers = [object(), object()] - resolver = client.Resolver(servers=servers) - resolver.dynServers = dynServers - resolver._connectedProtocol = lambda: protocol - - expectedResult = object() - queryResult = resolver.queryUDP(None) - queryResult.addCallback(self.assertEqual, expectedResult) - - self.assertEqual(len(protocol.queries), 1) - self.assertIs(protocol.queries[0][0], servers[0]) - protocol.queries[0][-1].errback(DNSQueryTimeoutError(0)) - self.assertEqual(len(protocol.queries), 2) - self.assertIs(protocol.queries[1][0], servers[1]) - protocol.queries[1][-1].errback(DNSQueryTimeoutError(1)) - self.assertEqual(len(protocol.queries), 3) - self.assertIs(protocol.queries[2][0], dynServers[0]) - protocol.queries[2][-1].errback(DNSQueryTimeoutError(2)) - self.assertEqual(len(protocol.queries), 4) - self.assertIs(protocol.queries[3][0], dynServers[1]) - protocol.queries[3][-1].callback(expectedResult) - - return queryResult - - - def test_singleConcurrentRequest(self): - """ - L{client.Resolver.query} only issues one request at a time per query. - Subsequent requests made before responses to prior ones are received - are queued and given the same response as is given to the first one. - """ - protocol = StubDNSDatagramProtocol() - resolver = client.Resolver(servers=[('example.com', 53)]) - resolver._connectedProtocol = lambda: protocol - queries = protocol.queries - - query = dns.Query(b'foo.example.com', dns.A, dns.IN) - # The first query should be passed to the underlying protocol. - firstResult = resolver.query(query) - self.assertEqual(len(queries), 1) - - # The same query again should not be passed to the underlying protocol. - secondResult = resolver.query(query) - self.assertEqual(len(queries), 1) - - # The response to the first query should be sent in response to both - # queries. - answer = object() - response = dns.Message() - response.answers.append(answer) - queries.pop()[-1].callback(response) - - d = defer.gatherResults([firstResult, secondResult]) - def cbFinished(responses): - firstResponse, secondResponse = responses - self.assertEqual(firstResponse, ([answer], [], [])) - self.assertEqual(secondResponse, ([answer], [], [])) - d.addCallback(cbFinished) - return d - - - def test_multipleConcurrentRequests(self): - """ - L{client.Resolver.query} issues a request for each different concurrent - query. - """ - protocol = StubDNSDatagramProtocol() - resolver = client.Resolver(servers=[('example.com', 53)]) - resolver._connectedProtocol = lambda: protocol - queries = protocol.queries - - # The first query should be passed to the underlying protocol. - firstQuery = dns.Query(b'foo.example.com', dns.A) - resolver.query(firstQuery) - self.assertEqual(len(queries), 1) - - # A query for a different name is also passed to the underlying - # protocol. - secondQuery = dns.Query(b'bar.example.com', dns.A) - resolver.query(secondQuery) - self.assertEqual(len(queries), 2) - - # A query for a different type is also passed to the underlying - # protocol. - thirdQuery = dns.Query(b'foo.example.com', dns.A6) - resolver.query(thirdQuery) - self.assertEqual(len(queries), 3) - - - def test_multipleSequentialRequests(self): - """ - After a response is received to a query issued with - L{client.Resolver.query}, another query with the same parameters - results in a new network request. - """ - protocol = StubDNSDatagramProtocol() - resolver = client.Resolver(servers=[('example.com', 53)]) - resolver._connectedProtocol = lambda: protocol - queries = protocol.queries - - query = dns.Query(b'foo.example.com', dns.A) - - # The first query should be passed to the underlying protocol. - resolver.query(query) - self.assertEqual(len(queries), 1) - - # Deliver the response. - queries.pop()[-1].callback(dns.Message()) - - # Repeating the first query should touch the protocol again. - resolver.query(query) - self.assertEqual(len(queries), 1) - - - def test_multipleConcurrentFailure(self): - """ - If the result of a request is an error response, the Deferreds for all - concurrently issued requests associated with that result fire with the - L{Failure}. - """ - protocol = StubDNSDatagramProtocol() - resolver = client.Resolver(servers=[('example.com', 53)]) - resolver._connectedProtocol = lambda: protocol - queries = protocol.queries - - query = dns.Query(b'foo.example.com', dns.A) - firstResult = resolver.query(query) - secondResult = resolver.query(query) - - class ExpectedException(Exception): - pass - - queries.pop()[-1].errback(failure.Failure(ExpectedException())) - - return defer.gatherResults([ - self.assertFailure(firstResult, ExpectedException), - self.assertFailure(secondResult, ExpectedException)]) - - - def test_connectedProtocol(self): - """ - L{client.Resolver._connectedProtocol} returns a new - L{DNSDatagramProtocol} connected to a new address with a - cryptographically secure random port number. - """ - resolver = client.Resolver(servers=[('example.com', 53)]) - firstProto = resolver._connectedProtocol() - secondProto = resolver._connectedProtocol() - - self.assertIsNot(firstProto.transport, None) - self.assertIsNot(secondProto.transport, None) - self.assertNotEqual( - firstProto.transport.getHost().port, - secondProto.transport.getHost().port) - - return defer.gatherResults([ - defer.maybeDeferred(firstProto.transport.stopListening), - defer.maybeDeferred(secondProto.transport.stopListening)]) - - - def test_resolverUsesOnlyParameterizedReactor(self): - """ - If a reactor instance is supplied to L{client.Resolver} - L{client.Resolver._connectedProtocol} should pass that reactor - to L{twisted.names.dns.DNSDatagramProtocol}. - """ - reactor = MemoryReactor() - resolver = client.Resolver(resolv=self.mktemp(), reactor=reactor) - proto = resolver._connectedProtocol() - self.assertIs(proto._reactor, reactor) - - - def test_differentProtocol(self): - """ - L{client.Resolver._connectedProtocol} is called once each time a UDP - request needs to be issued and the resulting protocol instance is used - for that request. - """ - resolver = client.Resolver(servers=[('example.com', 53)]) - protocols = [] - - class FakeProtocol(object): - def __init__(self): - self.transport = StubPort() - - def query(self, address, query, timeout=10, id=None): - protocols.append(self) - return defer.succeed(dns.Message()) - - resolver._connectedProtocol = FakeProtocol - resolver.query(dns.Query(b'foo.example.com')) - resolver.query(dns.Query(b'bar.example.com')) - self.assertEqual(len(set(protocols)), 2) - - - def test_disallowedPort(self): - """ - If a port number is initially selected which cannot be bound, the - L{CannotListenError} is handled and another port number is attempted. - """ - ports = [] - - class FakeReactor(object): - def listenUDP(self, port, *args): - ports.append(port) - if len(ports) == 1: - raise CannotListenError(None, port, None) - - resolver = client.Resolver(servers=[('example.com', 53)]) - resolver._reactor = FakeReactor() - - resolver._connectedProtocol() - self.assertEqual(len(set(ports)), 2) - - - def test_differentProtocolAfterTimeout(self): - """ - When a query issued by L{client.Resolver.query} times out, the retry - uses a new protocol instance. - """ - resolver = client.Resolver(servers=[('example.com', 53)]) - protocols = [] - results = [defer.fail(failure.Failure(DNSQueryTimeoutError(None))), - defer.succeed(dns.Message())] - - class FakeProtocol(object): - def __init__(self): - self.transport = StubPort() - - def query(self, address, query, timeout=10, id=None): - protocols.append(self) - return results.pop(0) - - resolver._connectedProtocol = FakeProtocol - resolver.query(dns.Query(b'foo.example.com')) - self.assertEqual(len(set(protocols)), 2) - - - def test_protocolShutDown(self): - """ - After the L{Deferred} returned by L{DNSDatagramProtocol.query} is - called back, the L{DNSDatagramProtocol} is disconnected from its - transport. - """ - resolver = client.Resolver(servers=[('example.com', 53)]) - protocols = [] - result = defer.Deferred() - - class FakeProtocol(object): - def __init__(self): - self.transport = StubPort() - - def query(self, address, query, timeout=10, id=None): - protocols.append(self) - return result - - resolver._connectedProtocol = FakeProtocol - resolver.query(dns.Query(b'foo.example.com')) - - self.assertFalse(protocols[0].transport.disconnected) - result.callback(dns.Message()) - self.assertTrue(protocols[0].transport.disconnected) - - - def test_protocolShutDownAfterTimeout(self): - """ - The L{DNSDatagramProtocol} created when an interim timeout occurs is - also disconnected from its transport after the Deferred returned by its - query method completes. - """ - resolver = client.Resolver(servers=[('example.com', 53)]) - protocols = [] - result = defer.Deferred() - results = [defer.fail(failure.Failure(DNSQueryTimeoutError(None))), - result] - - class FakeProtocol(object): - def __init__(self): - self.transport = StubPort() - - def query(self, address, query, timeout=10, id=None): - protocols.append(self) - return results.pop(0) - - resolver._connectedProtocol = FakeProtocol - resolver.query(dns.Query(b'foo.example.com')) - - self.assertFalse(protocols[1].transport.disconnected) - result.callback(dns.Message()) - self.assertTrue(protocols[1].transport.disconnected) - - - def test_protocolShutDownAfterFailure(self): - """ - If the L{Deferred} returned by L{DNSDatagramProtocol.query} fires with - a failure, the L{DNSDatagramProtocol} is still disconnected from its - transport. - """ - class ExpectedException(Exception): - pass - - resolver = client.Resolver(servers=[('example.com', 53)]) - protocols = [] - result = defer.Deferred() - - class FakeProtocol(object): - def __init__(self): - self.transport = StubPort() - - def query(self, address, query, timeout=10, id=None): - protocols.append(self) - return result - - resolver._connectedProtocol = FakeProtocol - queryResult = resolver.query(dns.Query(b'foo.example.com')) - - self.assertFalse(protocols[0].transport.disconnected) - result.errback(failure.Failure(ExpectedException())) - self.assertTrue(protocols[0].transport.disconnected) - - return self.assertFailure(queryResult, ExpectedException) - - - def test_tcpDisconnectRemovesFromConnections(self): - """ - When a TCP DNS protocol associated with a Resolver disconnects, it is - removed from the Resolver's connection list. - """ - resolver = client.Resolver(servers=[('example.com', 53)]) - protocol = resolver.factory.buildProtocol(None) - protocol.makeConnection(None) - self.assertIn(protocol, resolver.connections) - - # Disconnecting should remove the protocol from the connection list: - protocol.connectionLost(None) - self.assertNotIn(protocol, resolver.connections) - - - def test_singleTCPQueryErrbackOnConnectionFailure(self): - """ - The deferred returned by L{client.Resolver.queryTCP} will - errback when the TCP connection attempt fails. The reason for - the connection failure is passed as the argument to errback. - """ - reactor = proto_helpers.MemoryReactor() - resolver = client.Resolver( - servers=[('192.0.2.100', 53)], - reactor=reactor) - - d = resolver.queryTCP(dns.Query('example.com')) - host, port, factory, timeout, bindAddress = reactor.tcpClients[0] - - class SentinelException(Exception): - pass - - factory.clientConnectionFailed( - reactor.connectors[0], failure.Failure(SentinelException())) - - self.failureResultOf(d, SentinelException) - - - def test_multipleTCPQueryErrbackOnConnectionFailure(self): - """ - All pending L{resolver.queryTCP} C{deferred}s will C{errback} - with the same C{Failure} if the connection attempt fails. - """ - reactor = proto_helpers.MemoryReactor() - resolver = client.Resolver( - servers=[('192.0.2.100', 53)], - reactor=reactor) - - d1 = resolver.queryTCP(dns.Query('example.com')) - d2 = resolver.queryTCP(dns.Query('example.net')) - host, port, factory, timeout, bindAddress = reactor.tcpClients[0] - - class SentinelException(Exception): - pass - - factory.clientConnectionFailed( - reactor.connectors[0], failure.Failure(SentinelException())) - - f1 = self.failureResultOf(d1, SentinelException) - f2 = self.failureResultOf(d2, SentinelException) - self.assertIdentical(f1, f2) - - - def test_reentrantTCPQueryErrbackOnConnectionFailure(self): - """ - An errback on the deferred returned by - L{client.Resolver.queryTCP} may trigger another TCP query. - """ - reactor = proto_helpers.MemoryReactor() - resolver = client.Resolver( - servers=[('127.0.0.1', 10053)], - reactor=reactor) - - q = dns.Query('example.com') - - # First query sent - d = resolver.queryTCP(q) - - # Repeat the query when the first query fails - def reissue(e): - e.trap(ConnectionRefusedError) - return resolver.queryTCP(q) - d.addErrback(reissue) - - self.assertEqual(len(reactor.tcpClients), 1) - self.assertEqual(len(reactor.connectors), 1) - - host, port, factory, timeout, bindAddress = reactor.tcpClients[0] - - # First query fails - f1 = failure.Failure(ConnectionRefusedError()) - factory.clientConnectionFailed( - reactor.connectors[0], - f1) - - # A second TCP connection is immediately attempted - self.assertEqual(len(reactor.tcpClients), 2) - self.assertEqual(len(reactor.connectors), 2) - # No result expected until the second chained query returns - self.assertNoResult(d) - - # Second query fails - f2 = failure.Failure(ConnectionRefusedError()) - factory.clientConnectionFailed( - reactor.connectors[1], - f2) - - # Original deferred now fires with the second failure - f = self.failureResultOf(d, ConnectionRefusedError) - self.assertIdentical(f, f2) - - - def test_pendingEmptiedInPlaceOnError(self): - """ - When the TCP connection attempt fails, the - L{client.Resolver.pending} list is emptied in place. It is not - replaced with a new empty list. - """ - reactor = proto_helpers.MemoryReactor() - resolver = client.Resolver( - servers=[('192.0.2.100', 53)], - reactor=reactor) - - d = resolver.queryTCP(dns.Query('example.com')) - - host, port, factory, timeout, bindAddress = reactor.tcpClients[0] - - prePending = resolver.pending - self.assertEqual(len(prePending), 1) - - class SentinelException(Exception): - pass - - factory.clientConnectionFailed( - reactor.connectors[0], failure.Failure(SentinelException())) - - self.failureResultOf(d, SentinelException) - self.assertIdentical(resolver.pending, prePending) - self.assertEqual(len(prePending), 0) - - - -class ClientTests(unittest.TestCase): - - def setUp(self): - """ - Replace the resolver with a FakeResolver - """ - client.theResolver = FakeResolver() - self.hostname = b'example.com' - self.hostnameForGetHostByName = b'getHostByNameTest' - - def tearDown(self): - """ - By setting the resolver to None, it will be recreated next time a name - lookup is done. - """ - client.theResolver = None - - def checkResult(self, results, qtype): - """ - Verify that the result is the same query type as what is expected. - """ - answers, authority, additional = results - result = answers[0] - self.assertEqual(result.name.name, self.hostname) - self.assertEqual(result.type, qtype) - - def checkGetHostByName(self, result): - """ - Test that the getHostByName query returns the 127.0.0.1 address. - """ - self.assertEqual(result, '127.0.0.1') - - def test_getHostByName(self): - """ - do a getHostByName of a value that should return 127.0.0.1. - """ - d = client.getHostByName(self.hostnameForGetHostByName) - d.addCallback(self.checkGetHostByName) - return d - - def test_lookupAddress(self): - """ - Do a lookup and test that the resolver will issue the correct type of - query type. We do this by checking that FakeResolver returns a result - record with the same query type as what we issued. - """ - d = client.lookupAddress(self.hostname) - d.addCallback(self.checkResult, dns.A) - return d - - def test_lookupIPV6Address(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupIPV6Address(self.hostname) - d.addCallback(self.checkResult, dns.AAAA) - return d - - def test_lookupAddress6(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAddress6(self.hostname) - d.addCallback(self.checkResult, dns.A6) - return d - - def test_lookupNameservers(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupNameservers(self.hostname) - d.addCallback(self.checkResult, dns.NS) - return d - - def test_lookupCanonicalName(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupCanonicalName(self.hostname) - d.addCallback(self.checkResult, dns.CNAME) - return d - - def test_lookupAuthority(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAuthority(self.hostname) - d.addCallback(self.checkResult, dns.SOA) - return d - - def test_lookupMailBox(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailBox(self.hostname) - d.addCallback(self.checkResult, dns.MB) - return d - - def test_lookupMailGroup(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailGroup(self.hostname) - d.addCallback(self.checkResult, dns.MG) - return d - - def test_lookupMailRename(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailRename(self.hostname) - d.addCallback(self.checkResult, dns.MR) - return d - - def test_lookupNull(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupNull(self.hostname) - d.addCallback(self.checkResult, dns.NULL) - return d - - def test_lookupWellKnownServices(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupWellKnownServices(self.hostname) - d.addCallback(self.checkResult, dns.WKS) - return d - - def test_lookupPointer(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupPointer(self.hostname) - d.addCallback(self.checkResult, dns.PTR) - return d - - def test_lookupHostInfo(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupHostInfo(self.hostname) - d.addCallback(self.checkResult, dns.HINFO) - return d - - def test_lookupMailboxInfo(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailboxInfo(self.hostname) - d.addCallback(self.checkResult, dns.MINFO) - return d - - def test_lookupMailExchange(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailExchange(self.hostname) - d.addCallback(self.checkResult, dns.MX) - return d - - def test_lookupText(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupText(self.hostname) - d.addCallback(self.checkResult, dns.TXT) - return d - - def test_lookupSenderPolicy(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupSenderPolicy(self.hostname) - d.addCallback(self.checkResult, dns.SPF) - return d - - def test_lookupResponsibility(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupResponsibility(self.hostname) - d.addCallback(self.checkResult, dns.RP) - return d - - def test_lookupAFSDatabase(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAFSDatabase(self.hostname) - d.addCallback(self.checkResult, dns.AFSDB) - return d - - def test_lookupService(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupService(self.hostname) - d.addCallback(self.checkResult, dns.SRV) - return d - - - def test_lookupZone(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupZone(self.hostname) - d.addCallback(self.checkResult, dns.AXFR) - return d - - - def test_lookupAllRecords(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAllRecords(self.hostname) - d.addCallback(self.checkResult, dns.ALL_RECORDS) - return d - - - def test_lookupNamingAuthorityPointer(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupNamingAuthorityPointer(self.hostname) - d.addCallback(self.checkResult, dns.NAPTR) - return d - - - def test_query(self): - """ - L{client.query} accepts a L{dns.Query} instance and dispatches - it to L{client.theResolver}.C{query}, which in turn dispatches - to an appropriate C{lookup*} method of L{client.theResolver}, - based on the L{dns.Query} type. - """ - q = dns.Query(self.hostname, dns.A) - d = client.query(q) - d.addCallback(self.checkResult, dns.A) - return d - - - -class FilterAnswersTests(unittest.TestCase): - """ - Test L{twisted.names.client.Resolver.filterAnswers}'s handling of various - error conditions it might encounter. - """ - def setUp(self): - # Create a resolver pointed at an invalid server - we won't be hitting - # the network in any of these tests. - self.resolver = client.Resolver(servers=[('0.0.0.0', 0)]) - - - def test_truncatedMessage(self): - """ - Test that a truncated message results in an equivalent request made via - TCP. - """ - m = dns.Message(trunc=True) - m.addQuery(b'example.com') - - def queryTCP(queries): - self.assertEqual(queries, m.queries) - response = dns.Message() - response.answers = ['answer'] - response.authority = ['authority'] - response.additional = ['additional'] - return defer.succeed(response) - self.resolver.queryTCP = queryTCP - d = self.resolver.filterAnswers(m) - d.addCallback( - self.assertEqual, (['answer'], ['authority'], ['additional'])) - return d - - - def _rcodeTest(self, rcode, exc): - m = dns.Message(rCode=rcode) - err = self.resolver.filterAnswers(m) - err.trap(exc) - - - def test_formatError(self): - """ - Test that a message with a result code of C{EFORMAT} results in a - failure wrapped around L{DNSFormatError}. - """ - return self._rcodeTest(dns.EFORMAT, error.DNSFormatError) - - - def test_serverError(self): - """ - Like L{test_formatError} but for C{ESERVER}/L{DNSServerError}. - """ - return self._rcodeTest(dns.ESERVER, error.DNSServerError) - - - def test_nameError(self): - """ - Like L{test_formatError} but for C{ENAME}/L{DNSNameError}. - """ - return self._rcodeTest(dns.ENAME, error.DNSNameError) - - - def test_notImplementedError(self): - """ - Like L{test_formatError} but for C{ENOTIMP}/L{DNSNotImplementedError}. - """ - return self._rcodeTest(dns.ENOTIMP, error.DNSNotImplementedError) - - - def test_refusedError(self): - """ - Like L{test_formatError} but for C{EREFUSED}/L{DNSQueryRefusedError}. - """ - return self._rcodeTest(dns.EREFUSED, error.DNSQueryRefusedError) - - - def test_refusedErrorUnknown(self): - """ - Like L{test_formatError} but for an unrecognized error code and - L{DNSUnknownError}. - """ - return self._rcodeTest(dns.EREFUSED + 1, error.DNSUnknownError) - - - -class FakeDNSDatagramProtocol(object): - def __init__(self): - self.queries = [] - self.transport = StubPort() - - def query(self, address, queries, timeout=10, id=None): - self.queries.append((address, queries, timeout, id)) - return defer.fail(error.DNSQueryTimeoutError(queries)) - - def removeResend(self, id): - # Ignore this for the time being. - pass - - - -class RetryLogicTests(unittest.TestCase): - """ - Tests for query retrying implemented by L{client.Resolver}. - """ - testServers = [ - '1.2.3.4', - '4.3.2.1', - 'a.b.c.d', - 'z.y.x.w'] - - def test_roundRobinBackoff(self): - """ - When timeouts occur waiting for responses to queries, the next - configured server is issued the query. When the query has been issued - to all configured servers, the timeout is increased and the process - begins again at the beginning. - """ - addrs = [(x, 53) for x in self.testServers] - r = client.Resolver(resolv=None, servers=addrs) - proto = FakeDNSDatagramProtocol() - r._connectedProtocol = lambda: proto - return r.lookupAddress(b"foo.example.com" - ).addCallback(self._cbRoundRobinBackoff - ).addErrback(self._ebRoundRobinBackoff, proto - ) - - - def _cbRoundRobinBackoff(self, result): - self.fail("Lookup address succeeded, should have timed out") - - - def _ebRoundRobinBackoff(self, failure, fakeProto): - failure.trap(defer.TimeoutError) - - # Assert that each server is tried with a particular timeout - # before the timeout is increased and the attempts are repeated. - - for t in (1, 3, 11, 45): - tries = fakeProto.queries[:len(self.testServers)] - del fakeProto.queries[:len(self.testServers)] - - tries.sort() - expected = list(self.testServers) - expected.sort() - - for ((addr, query, timeout, id), expectedAddr) in zip(tries, expected): - self.assertEqual(addr, (expectedAddr, 53)) - self.assertEqual(timeout, t) - - self.assertFalse(fakeProto.queries) - - - -class ThreadedResolverTests(unittest.TestCase): - """ - Tests for L{client.ThreadedResolver}. - """ - def test_deprecated(self): - """ - L{client.ThreadedResolver} is deprecated. Instantiating it emits a - deprecation warning pointing at the code that does the instantiation. - """ - client.ThreadedResolver() - warnings = self.flushWarnings(offendingFunctions=[self.test_deprecated]) - self.assertEqual( - warnings[0]['message'], - "twisted.names.client.ThreadedResolver is deprecated since " - "Twisted 9.0, use twisted.internet.base.ThreadedResolver " - "instead.") - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual(len(warnings), 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_common.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_common.py deleted file mode 100644 index ed4b29d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_common.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.names.common}. -""" - -from __future__ import division, absolute_import - -from zope.interface.verify import verifyClass - -from twisted.internet.interfaces import IResolver -from twisted.trial.unittest import SynchronousTestCase -from twisted.python.failure import Failure -from twisted.names.common import ResolverBase -from twisted.names.dns import EFORMAT, ESERVER, ENAME, ENOTIMP, EREFUSED, Query -from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError -from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError -from twisted.names.error import DNSUnknownError - - -class ExceptionForCodeTests(SynchronousTestCase): - """ - Tests for L{ResolverBase.exceptionForCode}. - """ - def setUp(self): - self.exceptionForCode = ResolverBase().exceptionForCode - - - def test_eformat(self): - """ - L{ResolverBase.exceptionForCode} converts L{EFORMAT} to - L{DNSFormatError}. - """ - self.assertIs(self.exceptionForCode(EFORMAT), DNSFormatError) - - - def test_eserver(self): - """ - L{ResolverBase.exceptionForCode} converts L{ESERVER} to - L{DNSServerError}. - """ - self.assertIs(self.exceptionForCode(ESERVER), DNSServerError) - - - def test_ename(self): - """ - L{ResolverBase.exceptionForCode} converts L{ENAME} to L{DNSNameError}. - """ - self.assertIs(self.exceptionForCode(ENAME), DNSNameError) - - - def test_enotimp(self): - """ - L{ResolverBase.exceptionForCode} converts L{ENOTIMP} to - L{DNSNotImplementedError}. - """ - self.assertIs(self.exceptionForCode(ENOTIMP), DNSNotImplementedError) - - - def test_erefused(self): - """ - L{ResolverBase.exceptionForCode} converts L{EREFUSED} to - L{DNSQueryRefusedError}. - """ - self.assertIs(self.exceptionForCode(EREFUSED), DNSQueryRefusedError) - - - def test_other(self): - """ - L{ResolverBase.exceptionForCode} converts any other response code to - L{DNSUnknownError}. - """ - self.assertIs(self.exceptionForCode(object()), DNSUnknownError) - - - -class QueryTests(SynchronousTestCase): - """ - Tests for L{ResolverBase.query}. - """ - - def test_resolverBaseProvidesIResolver(self): - """ - L{ResolverBase} provides the L{IResolver} interface. - """ - verifyClass(IResolver, ResolverBase) - - - def test_typeToMethodDispatch(self): - """ - L{ResolverBase.query} looks up a method to invoke using the type of the - query passed to it and the C{typeToMethod} mapping on itself. - """ - results = [] - resolver = ResolverBase() - resolver.typeToMethod = { - 12345: lambda query, timeout: results.append((query, timeout))} - query = Query(name=b"example.com", type=12345) - resolver.query(query, 123) - self.assertEqual([(b"example.com", 123)], results) - - - def test_typeToMethodResult(self): - """ - L{ResolverBase.query} returns a L{Deferred} which fires with the result - of the method found in the C{typeToMethod} mapping for the type of the - query passed to it. - """ - expected = object() - resolver = ResolverBase() - resolver.typeToMethod = {54321: lambda query, timeout: expected} - query = Query(name=b"example.com", type=54321) - queryDeferred = resolver.query(query, 123) - result = [] - queryDeferred.addBoth(result.append) - self.assertEqual(expected, result[0]) - - - def test_unknownQueryType(self): - """ - L{ResolverBase.query} returns a L{Deferred} which fails with - L{NotImplementedError} when called with a query of a type not present in - its C{typeToMethod} dictionary. - """ - resolver = ResolverBase() - resolver.typeToMethod = {} - query = Query(name=b"example.com", type=12345) - queryDeferred = resolver.query(query, 123) - result = [] - queryDeferred.addBoth(result.append) - self.assertIsInstance(result[0], Failure) - result[0].trap(NotImplementedError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_dns.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_dns.py deleted file mode 100644 index 7b6bac3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_dns.py +++ /dev/null @@ -1,4777 +0,0 @@ -# test-case-name: twisted.names.test.test_dns -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for twisted.names.dns. -""" - -from __future__ import division, absolute_import - -from io import BytesIO - -import struct - -from zope.interface.verify import verifyClass - -from twisted.python.failure import Failure -from twisted.python.util import FancyEqMixin, FancyStrMixin -from twisted.internet import address, task -from twisted.internet.error import CannotListenError, ConnectionDone -from twisted.trial import unittest -from twisted.names import dns - -from twisted.test import proto_helpers -from twisted.test.testutils import ComparisonTestsMixin - -RECORD_TYPES = [ - dns.Record_NS, dns.Record_MD, dns.Record_MF, dns.Record_CNAME, - dns.Record_MB, dns.Record_MG, dns.Record_MR, dns.Record_PTR, - dns.Record_DNAME, dns.Record_A, dns.Record_SOA, dns.Record_NULL, - dns.Record_WKS, dns.Record_SRV, dns.Record_AFSDB, dns.Record_RP, - dns.Record_HINFO, dns.Record_MINFO, dns.Record_MX, dns.Record_TXT, - dns.Record_AAAA, dns.Record_A6, dns.Record_NAPTR, dns.UnknownRecord, - ] - - -class Ord2ByteTests(unittest.TestCase): - """ - Tests for L{dns._ord2bytes}. - """ - def test_ord2byte(self): - """ - L{dns._ord2byte} accepts an integer and returns a byte string of length - one with an ordinal value equal to the given integer. - """ - self.assertEqual(b'\x10', dns._ord2bytes(0x10)) - - - -class Str2TimeTests(unittest.TestCase): - """ - Tests for L{dns.str2name}. - """ - def test_nonString(self): - """ - When passed a non-string object, L{dns.str2name} returns it unmodified. - """ - time = object() - self.assertIs(time, dns.str2time(time)) - - - def test_seconds(self): - """ - Passed a string giving a number of seconds, L{dns.str2time} returns the - number of seconds represented. For example, C{"10S"} represents C{10} - seconds. - """ - self.assertEqual(10, dns.str2time("10S")) - - - def test_minutes(self): - """ - Like C{test_seconds}, but for the C{"M"} suffix which multiplies the - time value by C{60} (the number of seconds in a minute!). - """ - self.assertEqual(2 * 60, dns.str2time("2M")) - - - def test_hours(self): - """ - Like C{test_seconds}, but for the C{"H"} suffix which multiplies the - time value by C{3600}, the number of seconds in an hour. - """ - self.assertEqual(3 * 3600, dns.str2time("3H")) - - - def test_days(self): - """ - Like L{test_seconds}, but for the C{"D"} suffix which multiplies the - time value by C{86400}, the number of seconds in a day. - """ - self.assertEqual(4 * 86400, dns.str2time("4D")) - - - def test_weeks(self): - """ - Like L{test_seconds}, but for the C{"W"} suffix which multiplies the - time value by C{604800}, the number of seconds in a week. - """ - self.assertEqual(5 * 604800, dns.str2time("5W")) - - - def test_years(self): - """ - Like L{test_seconds}, but for the C{"Y"} suffix which multiplies the - time value by C{31536000}, the number of seconds in a year. - """ - self.assertEqual(6 * 31536000, dns.str2time("6Y")) - - - def test_invalidPrefix(self): - """ - If a non-integer prefix is given, L{dns.str2time} raises L{ValueError}. - """ - self.assertRaises(ValueError, dns.str2time, "fooS") - - - -class NameTests(unittest.TestCase): - """ - Tests for L{Name}, the representation of a single domain name with support - for encoding into and decoding from DNS message format. - """ - def test_nonStringName(self): - """ - When constructed with a name which is neither C{bytes} nor C{str}, - L{Name} raises L{TypeError}. - """ - self.assertRaises(TypeError, dns.Name, 123) - self.assertRaises(TypeError, dns.Name, object()) - self.assertRaises(TypeError, dns.Name, []) - - - def test_unicodeName(self): - """ - L{dns.Name} automatically encodes unicode domain name using C{idna} - encoding. - """ - name = dns.Name(u'\u00e9chec.example.org') - self.assertIsInstance(name.name, bytes) - self.assertEqual(b'xn--chec-9oa.example.org', name.name) - - - def test_decode(self): - """ - L{Name.decode} populates the L{Name} instance with name information read - from the file-like object passed to it. - """ - n = dns.Name() - n.decode(BytesIO(b"\x07example\x03com\x00")) - self.assertEqual(n.name, b"example.com") - - - def test_encode(self): - """ - L{Name.encode} encodes its name information and writes it to the - file-like object passed to it. - """ - name = dns.Name(b"foo.example.com") - stream = BytesIO() - name.encode(stream) - self.assertEqual(stream.getvalue(), b"\x03foo\x07example\x03com\x00") - - - def test_encodeWithCompression(self): - """ - If a compression dictionary is passed to it, L{Name.encode} uses offset - information from it to encode its name with references to existing - labels in the stream instead of including another copy of them in the - output. It also updates the compression dictionary with the location of - the name it writes to the stream. - """ - name = dns.Name(b"foo.example.com") - compression = {b"example.com": 0x17} - - # Some bytes already encoded into the stream for this message - previous = b"some prefix to change .tell()" - stream = BytesIO() - stream.write(previous) - - # The position at which the encoded form of this new name will appear in - # the stream. - expected = len(previous) + dns.Message.headerSize - name.encode(stream, compression) - self.assertEqual( - b"\x03foo\xc0\x17", - stream.getvalue()[len(previous):]) - self.assertEqual( - {b"example.com": 0x17, b"foo.example.com": expected}, - compression) - - - def test_unknown(self): - """ - A resource record of unknown type and class is parsed into an - L{UnknownRecord} instance with its data preserved, and an - L{UnknownRecord} instance is serialized to a string equal to the one it - was parsed from. - """ - wire = ( - b'\x01\x00' # Message ID - b'\x00' # answer bit, opCode nibble, auth bit, trunc bit, recursive - # bit - b'\x00' # recursion bit, empty bit, authenticData bit, - # checkingDisabled bit, response code nibble - b'\x00\x01' # number of queries - b'\x00\x01' # number of answers - b'\x00\x00' # number of authorities - b'\x00\x01' # number of additionals - - # query - b'\x03foo\x03bar\x00' # foo.bar - b'\xde\xad' # type=0xdead - b'\xbe\xef' # cls=0xbeef - - # 1st answer - b'\xc0\x0c' # foo.bar - compressed - b'\xde\xad' # type=0xdead - b'\xbe\xef' # cls=0xbeef - b'\x00\x00\x01\x01' # ttl=257 - b'\x00\x08somedata' # some payload data - - # 1st additional - b'\x03baz\x03ban\x00' # baz.ban - b'\x00\x01' # type=A - b'\x00\x01' # cls=IN - b'\x00\x00\x01\x01' # ttl=257 - b'\x00\x04' # len=4 - b'\x01\x02\x03\x04' # 1.2.3.4 - ) - - msg = dns.Message() - msg.fromStr(wire) - - self.assertEqual(msg.queries, [ - dns.Query(b'foo.bar', type=0xdead, cls=0xbeef), - ]) - self.assertEqual(msg.answers, [ - dns.RRHeader(b'foo.bar', type=0xdead, cls=0xbeef, ttl=257, - payload=dns.UnknownRecord(b'somedata', ttl=257)), - ]) - self.assertEqual(msg.additional, [ - dns.RRHeader(b'baz.ban', type=dns.A, cls=dns.IN, ttl=257, - payload=dns.Record_A('1.2.3.4', ttl=257)), - ]) - - enc = msg.toStr() - - self.assertEqual(enc, wire) - - - def test_decodeWithCompression(self): - """ - If the leading byte of an encoded label (in bytes read from a stream - passed to L{Name.decode}) has its two high bits set, the next byte is - treated as a pointer to another label in the stream and that label is - included in the name being decoded. - """ - # Slightly modified version of the example from RFC 1035, section 4.1.4. - stream = BytesIO( - b"x" * 20 + - b"\x01f\x03isi\x04arpa\x00" - b"\x03foo\xc0\x14" - b"\x03bar\xc0\x20") - stream.seek(20) - name = dns.Name() - name.decode(stream) - # Verify we found the first name in the stream and that the stream - # position is left at the first byte after the decoded name. - self.assertEqual(b"f.isi.arpa", name.name) - self.assertEqual(32, stream.tell()) - - # Get the second name from the stream and make the same assertions. - name.decode(stream) - self.assertEqual(name.name, b"foo.f.isi.arpa") - self.assertEqual(38, stream.tell()) - - # Get the third and final name - name.decode(stream) - self.assertEqual(name.name, b"bar.foo.f.isi.arpa") - self.assertEqual(44, stream.tell()) - - - def test_rejectCompressionLoop(self): - """ - L{Name.decode} raises L{ValueError} if the stream passed to it includes - a compression pointer which forms a loop, causing the name to be - undecodable. - """ - name = dns.Name() - stream = BytesIO(b"\xc0\x00") - self.assertRaises(ValueError, name.decode, stream) - - - -class RoundtripDNSTests(unittest.TestCase): - """ - Encoding and then decoding various objects. - """ - - names = [b"example.org", b"go-away.fish.tv", b"23strikesback.net"] - - def test_name(self): - for n in self.names: - # encode the name - f = BytesIO() - dns.Name(n).encode(f) - - # decode the name - f.seek(0, 0) - result = dns.Name() - result.decode(f) - self.assertEqual(result.name, n) - - def test_query(self): - """ - L{dns.Query.encode} returns a byte string representing the fields of the - query which can be decoded into a new L{dns.Query} instance using - L{dns.Query.decode}. - """ - for n in self.names: - for dnstype in range(1, 17): - for dnscls in range(1, 5): - # encode the query - f = BytesIO() - dns.Query(n, dnstype, dnscls).encode(f) - - # decode the result - f.seek(0, 0) - result = dns.Query() - result.decode(f) - self.assertEqual(result.name.name, n) - self.assertEqual(result.type, dnstype) - self.assertEqual(result.cls, dnscls) - - def test_resourceRecordHeader(self): - """ - L{dns.RRHeader.encode} encodes the record header's information and - writes it to the file-like object passed to it and - L{dns.RRHeader.decode} reads from a file-like object to re-construct a - L{dns.RRHeader} instance. - """ - # encode the RR - f = BytesIO() - dns.RRHeader(b"test.org", 3, 4, 17).encode(f) - - # decode the result - f.seek(0, 0) - result = dns.RRHeader() - result.decode(f) - self.assertEqual(result.name, dns.Name(b"test.org")) - self.assertEqual(result.type, 3) - self.assertEqual(result.cls, 4) - self.assertEqual(result.ttl, 17) - - - def test_resources(self): - """ - L{dns.SimpleRecord.encode} encodes the record's name information and - writes it to the file-like object passed to it and - L{dns.SimpleRecord.decode} reads from a file-like object to re-construct - a L{dns.SimpleRecord} instance. - """ - names = ( - b"this.are.test.name", - b"will.compress.will.this.will.name.will.hopefully", - b"test.CASE.preSErVatIOn.YeAH", - b"a.s.h.o.r.t.c.a.s.e.t.o.t.e.s.t", - b"singleton" - ) - for s in names: - f = BytesIO() - dns.SimpleRecord(s).encode(f) - f.seek(0, 0) - result = dns.SimpleRecord() - result.decode(f) - self.assertEqual(result.name, dns.Name(s)) - - - def test_hashable(self): - """ - Instances of all record types are hashable. - """ - for k in RECORD_TYPES: - k1, k2 = k(), k() - hk1 = hash(k1) - hk2 = hash(k2) - self.assertEqual(hk1, hk2, "%s != %s (for %s)" % (hk1,hk2,k)) - - - def test_Charstr(self): - """ - Test L{dns.Charstr} encode and decode. - """ - for n in self.names: - # encode the name - f = BytesIO() - dns.Charstr(n).encode(f) - - # decode the name - f.seek(0, 0) - result = dns.Charstr() - result.decode(f) - self.assertEqual(result.string, n) - - - def _recordRoundtripTest(self, record): - """ - Assert that encoding C{record} and then decoding the resulting bytes - creates a record which compares equal to C{record}. - """ - stream = BytesIO() - record.encode(stream) - - length = stream.tell() - stream.seek(0, 0) - replica = record.__class__() - replica.decode(stream, length) - self.assertEqual(record, replica) - - - def test_SOA(self): - """ - The byte stream written by L{dns.Record_SOA.encode} can be used by - L{dns.Record_SOA.decode} to reconstruct the state of the original - L{dns.Record_SOA} instance. - """ - self._recordRoundtripTest( - dns.Record_SOA( - mname=b'foo', rname=b'bar', serial=12, refresh=34, - retry=56, expire=78, minimum=90)) - - - def test_A(self): - """ - The byte stream written by L{dns.Record_A.encode} can be used by - L{dns.Record_A.decode} to reconstruct the state of the original - L{dns.Record_A} instance. - """ - self._recordRoundtripTest(dns.Record_A('1.2.3.4')) - - - def test_NULL(self): - """ - The byte stream written by L{dns.Record_NULL.encode} can be used by - L{dns.Record_NULL.decode} to reconstruct the state of the original - L{dns.Record_NULL} instance. - """ - self._recordRoundtripTest(dns.Record_NULL(b'foo bar')) - - - def test_WKS(self): - """ - The byte stream written by L{dns.Record_WKS.encode} can be used by - L{dns.Record_WKS.decode} to reconstruct the state of the original - L{dns.Record_WKS} instance. - """ - self._recordRoundtripTest(dns.Record_WKS('1.2.3.4', 3, b'xyz')) - - - def test_AAAA(self): - """ - The byte stream written by L{dns.Record_AAAA.encode} can be used by - L{dns.Record_AAAA.decode} to reconstruct the state of the original - L{dns.Record_AAAA} instance. - """ - self._recordRoundtripTest(dns.Record_AAAA('::1')) - - - def test_A6(self): - """ - The byte stream written by L{dns.Record_A6.encode} can be used by - L{dns.Record_A6.decode} to reconstruct the state of the original - L{dns.Record_A6} instance. - """ - self._recordRoundtripTest(dns.Record_A6(8, '::1:2', b'foo')) - - - def test_SRV(self): - """ - The byte stream written by L{dns.Record_SRV.encode} can be used by - L{dns.Record_SRV.decode} to reconstruct the state of the original - L{dns.Record_SRV} instance. - """ - self._recordRoundtripTest(dns.Record_SRV( - priority=1, weight=2, port=3, target=b'example.com')) - - - def test_NAPTR(self): - """ - Test L{dns.Record_NAPTR} encode and decode. - """ - naptrs = [ - (100, 10, b"u", b"sip+E2U", - b"!^.*$!sip:information@domain.tld!", b""), - (100, 50, b"s", b"http+I2L+I2C+I2R", - b"", b"_http._tcp.gatech.edu")] - - for (order, preference, flags, service, regexp, replacement) in naptrs: - rin = dns.Record_NAPTR(order, preference, flags, service, regexp, - replacement) - e = BytesIO() - rin.encode(e) - e.seek(0, 0) - rout = dns.Record_NAPTR() - rout.decode(e) - self.assertEqual(rin.order, rout.order) - self.assertEqual(rin.preference, rout.preference) - self.assertEqual(rin.flags, rout.flags) - self.assertEqual(rin.service, rout.service) - self.assertEqual(rin.regexp, rout.regexp) - self.assertEqual(rin.replacement.name, rout.replacement.name) - self.assertEqual(rin.ttl, rout.ttl) - - - def test_AFSDB(self): - """ - The byte stream written by L{dns.Record_AFSDB.encode} can be used by - L{dns.Record_AFSDB.decode} to reconstruct the state of the original - L{dns.Record_AFSDB} instance. - """ - self._recordRoundtripTest(dns.Record_AFSDB( - subtype=3, hostname=b'example.com')) - - - def test_RP(self): - """ - The byte stream written by L{dns.Record_RP.encode} can be used by - L{dns.Record_RP.decode} to reconstruct the state of the original - L{dns.Record_RP} instance. - """ - self._recordRoundtripTest(dns.Record_RP( - mbox=b'alice.example.com', txt=b'example.com')) - - - def test_HINFO(self): - """ - The byte stream written by L{dns.Record_HINFO.encode} can be used by - L{dns.Record_HINFO.decode} to reconstruct the state of the original - L{dns.Record_HINFO} instance. - """ - self._recordRoundtripTest(dns.Record_HINFO(cpu=b'fast', os=b'great')) - - - def test_MINFO(self): - """ - The byte stream written by L{dns.Record_MINFO.encode} can be used by - L{dns.Record_MINFO.decode} to reconstruct the state of the original - L{dns.Record_MINFO} instance. - """ - self._recordRoundtripTest(dns.Record_MINFO( - rmailbx=b'foo', emailbx=b'bar')) - - - def test_MX(self): - """ - The byte stream written by L{dns.Record_MX.encode} can be used by - L{dns.Record_MX.decode} to reconstruct the state of the original - L{dns.Record_MX} instance. - """ - self._recordRoundtripTest(dns.Record_MX( - preference=1, name=b'example.com')) - - - def test_TXT(self): - """ - The byte stream written by L{dns.Record_TXT.encode} can be used by - L{dns.Record_TXT.decode} to reconstruct the state of the original - L{dns.Record_TXT} instance. - """ - self._recordRoundtripTest(dns.Record_TXT(b'foo', b'bar')) - - - -MESSAGE_AUTHENTIC_DATA_BYTES = ( - b'\x00\x00' # ID - b'\x00' # - b'\x20' # RA, Z, AD=1, CD, RCODE - b'\x00\x00' # Query count - b'\x00\x00' # Answer count - b'\x00\x00' # Authority count - b'\x00\x00' # Additional count -) - - - -MESSAGE_CHECKING_DISABLED_BYTES = ( - b'\x00\x00' # ID - b'\x00' # - b'\x10' # RA, Z, AD, CD=1, RCODE - b'\x00\x00' # Query count - b'\x00\x00' # Answer count - b'\x00\x00' # Authority count - b'\x00\x00' # Additional count -) - - - -class MessageTests(unittest.SynchronousTestCase): - """ - Tests for L{twisted.names.dns.Message}. - """ - - def test_authenticDataDefault(self): - """ - L{dns.Message.authenticData} has default value 0. - """ - self.assertEqual(dns.Message().authenticData, 0) - - - def test_authenticDataOverride(self): - """ - L{dns.Message.__init__} accepts a C{authenticData} argument which - is assigned to L{dns.Message.authenticData}. - """ - self.assertEqual(dns.Message(authenticData=1).authenticData, 1) - - - def test_authenticDataEncode(self): - """ - L{dns.Message.toStr} encodes L{dns.Message.authenticData} into - byte4 of the byte string. - """ - self.assertEqual( - dns.Message(authenticData=1).toStr(), - MESSAGE_AUTHENTIC_DATA_BYTES - ) - - - def test_authenticDataDecode(self): - """ - L{dns.Message.fromStr} decodes byte4 and assigns bit3 to - L{dns.Message.authenticData}. - """ - m = dns.Message() - m.fromStr(MESSAGE_AUTHENTIC_DATA_BYTES) - - self.assertEqual(m.authenticData, 1) - - - def test_checkingDisabledDefault(self): - """ - L{dns.Message.checkingDisabled} has default value 0. - """ - self.assertEqual(dns.Message().checkingDisabled, 0) - - - def test_checkingDisabledOverride(self): - """ - L{dns.Message.__init__} accepts a C{checkingDisabled} argument which - is assigned to L{dns.Message.checkingDisabled}. - """ - self.assertEqual( - dns.Message(checkingDisabled=1).checkingDisabled, 1) - - - def test_checkingDisabledEncode(self): - """ - L{dns.Message.toStr} encodes L{dns.Message.checkingDisabled} into - byte4 of the byte string. - """ - self.assertEqual( - dns.Message(checkingDisabled=1).toStr(), - MESSAGE_CHECKING_DISABLED_BYTES - ) - - - def test_checkingDisabledDecode(self): - """ - L{dns.Message.fromStr} decodes byte4 and assigns bit4 to - L{dns.Message.checkingDisabled}. - """ - m = dns.Message() - m.fromStr(MESSAGE_CHECKING_DISABLED_BYTES) - - self.assertEqual(m.checkingDisabled, 1) - - - def test_reprDefaults(self): - """ - L{dns.Message.__repr__} omits field values and sections which are - identical to their defaults. The id field value is always shown. - """ - self.assertEqual( - '', - repr(dns.Message()) - ) - - - def test_reprFlagsIfSet(self): - """ - L{dns.Message.__repr__} displays flags if they are L{True}. - """ - m = dns.Message(answer=True, auth=True, trunc=True, recDes=True, - recAv=True, authenticData=True, checkingDisabled=True) - self.assertEqual( - '', - repr(m), - ) - - - def test_reprNonDefautFields(self): - """ - L{dns.Message.__repr__} displays field values if they differ from their - defaults. - """ - m = dns.Message(id=10, opCode=20, rCode=30, maxSize=40) - self.assertEqual( - '', - repr(m), - ) - - - def test_reprNonDefaultSections(self): - """ - L{dns.Message.__repr__} displays sections which differ from their - defaults. - """ - m = dns.Message() - m.queries = [1, 2, 3] - m.answers = [4, 5, 6] - m.authority = [7, 8, 9] - m.additional = [10, 11, 12] - self.assertEqual( - '', - repr(m), - ) - - - def test_emptyMessage(self): - """ - Test that a message which has been truncated causes an EOFError to - be raised when it is parsed. - """ - msg = dns.Message() - self.assertRaises(EOFError, msg.fromStr, b'') - - - def test_emptyQuery(self): - """ - Test that bytes representing an empty query message can be decoded - as such. - """ - msg = dns.Message() - msg.fromStr( - b'\x01\x00' # Message ID - b'\x00' # answer bit, opCode nibble, auth bit, trunc bit, recursive bit - b'\x00' # recursion bit, empty bit, authenticData bit, - # checkingDisabled bit, response code nibble - b'\x00\x00' # number of queries - b'\x00\x00' # number of answers - b'\x00\x00' # number of authorities - b'\x00\x00' # number of additionals - ) - self.assertEqual(msg.id, 256) - self.assertFalse( - msg.answer, "Message was not supposed to be an answer.") - self.assertEqual(msg.opCode, dns.OP_QUERY) - self.assertFalse( - msg.auth, "Message was not supposed to be authoritative.") - self.assertFalse( - msg.trunc, "Message was not supposed to be truncated.") - self.assertEqual(msg.queries, []) - self.assertEqual(msg.answers, []) - self.assertEqual(msg.authority, []) - self.assertEqual(msg.additional, []) - - - def test_NULL(self): - """ - A I{NULL} record with an arbitrary payload can be encoded and decoded as - part of a L{dns.Message}. - """ - bytes = b''.join([dns._ord2bytes(i) for i in range(256)]) - rec = dns.Record_NULL(bytes) - rr = dns.RRHeader(b'testname', dns.NULL, payload=rec) - msg1 = dns.Message() - msg1.answers.append(rr) - s = BytesIO() - msg1.encode(s) - s.seek(0, 0) - msg2 = dns.Message() - msg2.decode(s) - - self.assertIsInstance(msg2.answers[0].payload, dns.Record_NULL) - self.assertEqual(msg2.answers[0].payload.payload, bytes) - - - def test_lookupRecordTypeDefault(self): - """ - L{Message.lookupRecordType} returns C{dns.UnknownRecord} if it is - called with an integer which doesn't correspond to any known record - type. - """ - # 65280 is the first value in the range reserved for private - # use, so it shouldn't ever conflict with an officially - # allocated value. - self.assertIs(dns.Message().lookupRecordType(65280), dns.UnknownRecord) - - - def test_nonAuthoritativeMessage(self): - """ - The L{RRHeader} instances created by L{Message} from a non-authoritative - message are marked as not authoritative. - """ - buf = BytesIO() - answer = dns.RRHeader(payload=dns.Record_A('1.2.3.4', ttl=0)) - answer.encode(buf) - message = dns.Message() - message.fromStr( - b'\x01\x00' # Message ID - # answer bit, opCode nibble, auth bit, trunc bit, recursive bit - b'\x00' - # recursion bit, empty bit, authenticData bit, - # checkingDisabled bit, response code nibble - b'\x00' - b'\x00\x00' # number of queries - b'\x00\x01' # number of answers - b'\x00\x00' # number of authorities - b'\x00\x00' # number of additionals - + buf.getvalue() - ) - self.assertEqual(message.answers, [answer]) - self.assertFalse(message.answers[0].auth) - - - def test_authoritativeMessage(self): - """ - The L{RRHeader} instances created by L{Message} from an authoritative - message are marked as authoritative. - """ - buf = BytesIO() - answer = dns.RRHeader(payload=dns.Record_A('1.2.3.4', ttl=0)) - answer.encode(buf) - message = dns.Message() - message.fromStr( - b'\x01\x00' # Message ID - # answer bit, opCode nibble, auth bit, trunc bit, recursive bit - b'\x04' - # recursion bit, empty bit, authenticData bit, - # checkingDisabled bit, response code nibble - b'\x00' - b'\x00\x00' # number of queries - b'\x00\x01' # number of answers - b'\x00\x00' # number of authorities - b'\x00\x00' # number of additionals - + buf.getvalue() - ) - answer.auth = True - self.assertEqual(message.answers, [answer]) - self.assertTrue(message.answers[0].auth) - - - -class MessageComparisonTests(ComparisonTestsMixin, - unittest.SynchronousTestCase): - """ - Tests for the rich comparison of L{dns.Message} instances. - """ - def messageFactory(self, *args, **kwargs): - """ - Create a L{dns.Message}. - - The L{dns.Message} constructor doesn't accept C{queries}, C{answers}, - C{authority}, C{additional} arguments, so we extract them from the - kwargs supplied to this factory function and assign them to the message. - - @param args: Positional arguments. - @param kwargs: Keyword arguments. - @return: A L{dns.Message} instance. - """ - queries = kwargs.pop('queries', []) - answers = kwargs.pop('answers', []) - authority = kwargs.pop('authority', []) - additional = kwargs.pop('additional', []) - m = dns.Message(**kwargs) - if queries: - m.queries = queries - if answers: - m.answers = answers - if authority: - m.authority = authority - if additional: - m.additional = additional - return m - - - def test_id(self): - """ - Two L{dns.Message} instances compare equal if they have the same id - value. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(id=10), - self.messageFactory(id=10), - self.messageFactory(id=20), - ) - - - def test_answer(self): - """ - Two L{dns.Message} instances compare equal if they have the same answer - flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(answer=1), - self.messageFactory(answer=1), - self.messageFactory(answer=0), - ) - - - def test_opCode(self): - """ - Two L{dns.Message} instances compare equal if they have the same opCode - value. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(opCode=10), - self.messageFactory(opCode=10), - self.messageFactory(opCode=20), - ) - - - def test_recDes(self): - """ - Two L{dns.Message} instances compare equal if they have the same recDes - flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(recDes=1), - self.messageFactory(recDes=1), - self.messageFactory(recDes=0), - ) - - - def test_recAv(self): - """ - Two L{dns.Message} instances compare equal if they have the same recAv - flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(recAv=1), - self.messageFactory(recAv=1), - self.messageFactory(recAv=0), - ) - - - def test_auth(self): - """ - Two L{dns.Message} instances compare equal if they have the same auth - flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(auth=1), - self.messageFactory(auth=1), - self.messageFactory(auth=0), - ) - - - def test_rCode(self): - """ - Two L{dns.Message} instances compare equal if they have the same rCode - value. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(rCode=10), - self.messageFactory(rCode=10), - self.messageFactory(rCode=20), - ) - - - def test_trunc(self): - """ - Two L{dns.Message} instances compare equal if they have the same trunc - flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(trunc=1), - self.messageFactory(trunc=1), - self.messageFactory(trunc=0), - ) - - - def test_maxSize(self): - """ - Two L{dns.Message} instances compare equal if they have the same - maxSize value. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(maxSize=10), - self.messageFactory(maxSize=10), - self.messageFactory(maxSize=20), - ) - - - def test_authenticData(self): - """ - Two L{dns.Message} instances compare equal if they have the same - authenticData flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(authenticData=1), - self.messageFactory(authenticData=1), - self.messageFactory(authenticData=0), - ) - - - def test_checkingDisabled(self): - """ - Two L{dns.Message} instances compare equal if they have the same - checkingDisabled flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(checkingDisabled=1), - self.messageFactory(checkingDisabled=1), - self.messageFactory(checkingDisabled=0), - ) - - - def test_queries(self): - """ - Two L{dns.Message} instances compare equal if they have the same - queries. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(queries=[dns.Query(b'example.com')]), - self.messageFactory(queries=[dns.Query(b'example.com')]), - self.messageFactory(queries=[dns.Query(b'example.org')]), - ) - - - def test_answers(self): - """ - Two L{dns.Message} instances compare equal if they have the same - answers. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(answers=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(answers=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(answers=[dns.RRHeader( - b'example.org', payload=dns.Record_A('4.3.2.1'))]), - ) - - - def test_authority(self): - """ - Two L{dns.Message} instances compare equal if they have the same - authority records. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(authority=[dns.RRHeader( - b'example.com', - type=dns.SOA, payload=dns.Record_SOA())]), - self.messageFactory(authority=[dns.RRHeader( - b'example.com', - type=dns.SOA, payload=dns.Record_SOA())]), - self.messageFactory(authority=[dns.RRHeader( - b'example.org', - type=dns.SOA, payload=dns.Record_SOA())]), - ) - - - def test_additional(self): - """ - Two L{dns.Message} instances compare equal if they have the same - additional records. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(additional=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(additional=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(additional=[dns.RRHeader( - b'example.org', payload=dns.Record_A('1.2.3.4'))]), - ) - - - -class TestController(object): - """ - Pretend to be a DNS query processor for a DNSDatagramProtocol. - - @ivar messages: the list of received messages. - @type messages: C{list} of (msg, protocol, address) - """ - - def __init__(self): - """ - Initialize the controller: create a list of messages. - """ - self.messages = [] - - - def messageReceived(self, msg, proto, addr=None): - """ - Save the message so that it can be checked during the tests. - """ - self.messages.append((msg, proto, addr)) - - - -class DatagramProtocolTests(unittest.TestCase): - """ - Test various aspects of L{dns.DNSDatagramProtocol}. - """ - - def setUp(self): - """ - Create a L{dns.DNSDatagramProtocol} with a deterministic clock. - """ - self.clock = task.Clock() - self.controller = TestController() - self.proto = dns.DNSDatagramProtocol(self.controller) - transport = proto_helpers.FakeDatagramTransport() - self.proto.makeConnection(transport) - self.proto.callLater = self.clock.callLater - - - def test_truncatedPacket(self): - """ - Test that when a short datagram is received, datagramReceived does - not raise an exception while processing it. - """ - self.proto.datagramReceived( - b'', address.IPv4Address('UDP', '127.0.0.1', 12345)) - self.assertEqual(self.controller.messages, []) - - - def test_simpleQuery(self): - """ - Test content received after a query. - """ - d = self.proto.query(('127.0.0.1', 21345), [dns.Query(b'foo')]) - self.assertEqual(len(self.proto.liveMessages.keys()), 1) - m = dns.Message() - m.id = next(iter(self.proto.liveMessages.keys())) - m.answers = [dns.RRHeader(payload=dns.Record_A(address='1.2.3.4'))] - def cb(result): - self.assertEqual(result.answers[0].payload.dottedQuad(), '1.2.3.4') - d.addCallback(cb) - self.proto.datagramReceived(m.toStr(), ('127.0.0.1', 21345)) - return d - - - def test_queryTimeout(self): - """ - Test that query timeouts after some seconds. - """ - d = self.proto.query(('127.0.0.1', 21345), [dns.Query(b'foo')]) - self.assertEqual(len(self.proto.liveMessages), 1) - self.clock.advance(10) - self.assertFailure(d, dns.DNSQueryTimeoutError) - self.assertEqual(len(self.proto.liveMessages), 0) - return d - - - def test_writeError(self): - """ - Exceptions raised by the transport's write method should be turned into - C{Failure}s passed to errbacks of the C{Deferred} returned by - L{DNSDatagramProtocol.query}. - """ - def writeError(message, addr): - raise RuntimeError("bar") - self.proto.transport.write = writeError - - d = self.proto.query(('127.0.0.1', 21345), [dns.Query(b'foo')]) - return self.assertFailure(d, RuntimeError) - - - def test_listenError(self): - """ - Exception L{CannotListenError} raised by C{listenUDP} should be turned - into a C{Failure} passed to errback of the C{Deferred} returned by - L{DNSDatagramProtocol.query}. - """ - def startListeningError(): - raise CannotListenError(None, None, None) - self.proto.startListening = startListeningError - # Clean up transport so that the protocol calls startListening again - self.proto.transport = None - - d = self.proto.query(('127.0.0.1', 21345), [dns.Query(b'foo')]) - return self.assertFailure(d, CannotListenError) - - - def test_receiveMessageNotInLiveMessages(self): - """ - When receiving a message whose id is not in - L{DNSDatagramProtocol.liveMessages} or L{DNSDatagramProtocol.resends}, - the message will be received by L{DNSDatagramProtocol.controller}. - """ - message = dns.Message() - message.id = 1 - message.answers = [dns.RRHeader( - payload=dns.Record_A(address='1.2.3.4'))] - self.proto.datagramReceived(message.toStr(), ('127.0.0.1', 21345)) - self.assertEqual(self.controller.messages[-1][0].toStr(), - message.toStr()) - - - -class TestTCPController(TestController): - """ - Pretend to be a DNS query processor for a DNSProtocol. - - @ivar connections: A list of L{DNSProtocol} instances which have - notified this controller that they are connected and have not - yet notified it that their connection has been lost. - """ - def __init__(self): - TestController.__init__(self) - self.connections = [] - - - def connectionMade(self, proto): - self.connections.append(proto) - - - def connectionLost(self, proto): - self.connections.remove(proto) - - - -class DNSProtocolTests(unittest.TestCase): - """ - Test various aspects of L{dns.DNSProtocol}. - """ - - def setUp(self): - """ - Create a L{dns.DNSProtocol} with a deterministic clock. - """ - self.clock = task.Clock() - self.controller = TestTCPController() - self.proto = dns.DNSProtocol(self.controller) - self.proto.makeConnection(proto_helpers.StringTransport()) - self.proto.callLater = self.clock.callLater - - - def test_connectionTracking(self): - """ - L{dns.DNSProtocol} calls its controller's C{connectionMade} - method with itself when it is connected to a transport and its - controller's C{connectionLost} method when it is disconnected. - """ - self.assertEqual(self.controller.connections, [self.proto]) - self.proto.connectionLost( - Failure(ConnectionDone("Fake Connection Done"))) - self.assertEqual(self.controller.connections, []) - - - def test_queryTimeout(self): - """ - Test that query timeouts after some seconds. - """ - d = self.proto.query([dns.Query(b'foo')]) - self.assertEqual(len(self.proto.liveMessages), 1) - self.clock.advance(60) - self.assertFailure(d, dns.DNSQueryTimeoutError) - self.assertEqual(len(self.proto.liveMessages), 0) - return d - - - def test_simpleQuery(self): - """ - Test content received after a query. - """ - d = self.proto.query([dns.Query(b'foo')]) - self.assertEqual(len(self.proto.liveMessages.keys()), 1) - m = dns.Message() - m.id = next(iter(self.proto.liveMessages.keys())) - m.answers = [dns.RRHeader(payload=dns.Record_A(address='1.2.3.4'))] - def cb(result): - self.assertEqual(result.answers[0].payload.dottedQuad(), '1.2.3.4') - d.addCallback(cb) - s = m.toStr() - s = struct.pack('!H', len(s)) + s - self.proto.dataReceived(s) - return d - - - def test_writeError(self): - """ - Exceptions raised by the transport's write method should be turned into - C{Failure}s passed to errbacks of the C{Deferred} returned by - L{DNSProtocol.query}. - """ - def writeError(message): - raise RuntimeError("bar") - self.proto.transport.write = writeError - - d = self.proto.query([dns.Query(b'foo')]) - return self.assertFailure(d, RuntimeError) - - - def test_receiveMessageNotInLiveMessages(self): - """ - When receiving a message whose id is not in L{DNSProtocol.liveMessages} - the message will be received by L{DNSProtocol.controller}. - """ - message = dns.Message() - message.id = 1 - message.answers = [dns.RRHeader( - payload=dns.Record_A(address='1.2.3.4'))] - string = message.toStr() - string = struct.pack('!H', len(string)) + string - self.proto.dataReceived(string) - self.assertEqual(self.controller.messages[-1][0].toStr(), - message.toStr()) - - - -class ReprTests(unittest.TestCase): - """ - Tests for the C{__repr__} implementation of record classes. - """ - def test_ns(self): - """ - The repr of a L{dns.Record_NS} instance includes the name of the - nameserver and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_NS(b'example.com', 4321)), - "") - - - def test_md(self): - """ - The repr of a L{dns.Record_MD} instance includes the name of the - mail destination and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_MD(b'example.com', 4321)), - "") - - - def test_mf(self): - """ - The repr of a L{dns.Record_MF} instance includes the name of the - mail forwarder and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_MF(b'example.com', 4321)), - "") - - - def test_cname(self): - """ - The repr of a L{dns.Record_CNAME} instance includes the name of the - mail forwarder and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_CNAME(b'example.com', 4321)), - "") - - - def test_mb(self): - """ - The repr of a L{dns.Record_MB} instance includes the name of the - mailbox and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_MB(b'example.com', 4321)), - "") - - - def test_mg(self): - """ - The repr of a L{dns.Record_MG} instance includes the name of the - mail group member and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_MG(b'example.com', 4321)), - "") - - - def test_mr(self): - """ - The repr of a L{dns.Record_MR} instance includes the name of the - mail rename domain and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_MR(b'example.com', 4321)), - "") - - - def test_ptr(self): - """ - The repr of a L{dns.Record_PTR} instance includes the name of the - pointer and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_PTR(b'example.com', 4321)), - "") - - - def test_dname(self): - """ - The repr of a L{dns.Record_DNAME} instance includes the name of the - non-terminal DNS name redirection and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_DNAME(b'example.com', 4321)), - "") - - - def test_a(self): - """ - The repr of a L{dns.Record_A} instance includes the dotted-quad - string representation of the address it is for and the TTL of the - record. - """ - self.assertEqual( - repr(dns.Record_A('1.2.3.4', 567)), - '') - - - def test_soa(self): - """ - The repr of a L{dns.Record_SOA} instance includes all of the - authority fields. - """ - self.assertEqual( - repr(dns.Record_SOA(mname=b'mName', rname=b'rName', serial=123, - refresh=456, retry=789, expire=10, - minimum=11, ttl=12)), - "") - - - def test_null(self): - """ - The repr of a L{dns.Record_NULL} instance includes the repr of its - payload and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_NULL(b'abcd', 123)), - "") - - - def test_wks(self): - """ - The repr of a L{dns.Record_WKS} instance includes the dotted-quad - string representation of the address it is for, the IP protocol - number it is for, and the TTL of the record. - """ - self.assertEqual( - repr(dns.Record_WKS('2.3.4.5', 7, ttl=8)), - "") - - - def test_aaaa(self): - """ - The repr of a L{dns.Record_AAAA} instance includes the colon-separated - hex string representation of the address it is for and the TTL of the - record. - """ - self.assertEqual( - repr(dns.Record_AAAA('8765::1234', ttl=10)), - "") - - - def test_a6(self): - """ - The repr of a L{dns.Record_A6} instance includes the colon-separated - hex string representation of the address it is for and the TTL of the - record. - """ - self.assertEqual( - repr(dns.Record_A6(0, '1234::5678', b'foo.bar', ttl=10)), - "") - - - def test_srv(self): - """ - The repr of a L{dns.Record_SRV} instance includes the name and port of - the target and the priority, weight, and TTL of the record. - """ - self.assertEqual( - repr(dns.Record_SRV(1, 2, 3, b'example.org', 4)), - "") - - - def test_naptr(self): - """ - The repr of a L{dns.Record_NAPTR} instance includes the order, - preference, flags, service, regular expression, replacement, and TTL of - the record. - """ - record = dns.Record_NAPTR( - 5, 9, b"S", b"http", b"/foo/bar/i", b"baz", 3) - self.assertEqual( - repr(record), - "") - - - def test_afsdb(self): - """ - The repr of a L{dns.Record_AFSDB} instance includes the subtype, - hostname, and TTL of the record. - """ - self.assertEqual( - repr(dns.Record_AFSDB(3, b'example.org', 5)), - "") - - - def test_rp(self): - """ - The repr of a L{dns.Record_RP} instance includes the mbox, txt, and TTL - fields of the record. - """ - self.assertEqual( - repr(dns.Record_RP(b'alice.example.com', b'admin.example.com', 3)), - "") - - - def test_hinfo(self): - """ - The repr of a L{dns.Record_HINFO} instance includes the cpu, os, and - TTL fields of the record. - """ - self.assertEqual( - repr(dns.Record_HINFO(b'sparc', b'minix', 12)), - "") - - - def test_minfo(self): - """ - The repr of a L{dns.Record_MINFO} instance includes the rmailbx, - emailbx, and TTL fields of the record. - """ - record = dns.Record_MINFO( - b'alice.example.com', b'bob.example.com', 15) - self.assertEqual( - repr(record), - "") - - - def test_mx(self): - """ - The repr of a L{dns.Record_MX} instance includes the preference, name, - and TTL fields of the record. - """ - self.assertEqual( - repr(dns.Record_MX(13, b'mx.example.com', 2)), - "") - - - def test_txt(self): - """ - The repr of a L{dns.Record_TXT} instance includes the data and ttl - fields of the record. - """ - self.assertEqual( - repr(dns.Record_TXT(b"foo", b"bar", ttl=15)), - "") - - - def test_spf(self): - """ - The repr of a L{dns.Record_SPF} instance includes the data and ttl - fields of the record. - """ - self.assertEqual( - repr(dns.Record_SPF(b"foo", b"bar", ttl=15)), - "") - - - def test_unknown(self): - """ - The repr of a L{dns.UnknownRecord} instance includes the data and ttl - fields of the record. - """ - self.assertEqual( - repr(dns.UnknownRecord(b"foo\x1fbar", 12)), - "") - - - -class EqualityTests(ComparisonTestsMixin, unittest.TestCase): - """ - Tests for the equality and non-equality behavior of record classes. - """ - def _equalityTest(self, firstValueOne, secondValueOne, valueTwo): - return self.assertNormalEqualityImplementation( - firstValueOne, secondValueOne, valueTwo) - - - def test_charstr(self): - """ - Two L{dns.Charstr} instances compare equal if and only if they have the - same string value. - """ - self._equalityTest( - dns.Charstr(b'abc'), dns.Charstr(b'abc'), dns.Charstr(b'def')) - - - def test_name(self): - """ - Two L{dns.Name} instances compare equal if and only if they have the - same name value. - """ - self._equalityTest( - dns.Name(b'abc'), dns.Name(b'abc'), dns.Name(b'def')) - - - def _simpleEqualityTest(self, cls): - """ - Assert that instances of C{cls} with the same attributes compare equal - to each other and instances with different attributes compare as not - equal. - - @param cls: A L{dns.SimpleRecord} subclass. - """ - # Vary the TTL - self._equalityTest( - cls(b'example.com', 123), - cls(b'example.com', 123), - cls(b'example.com', 321)) - # Vary the name - self._equalityTest( - cls(b'example.com', 123), - cls(b'example.com', 123), - cls(b'example.org', 123)) - - - def test_rrheader(self): - """ - Two L{dns.RRHeader} instances compare equal if and only if they have - the same name, type, class, time to live, payload, and authoritative - bit. - """ - # Vary the name - self._equalityTest( - dns.RRHeader(b'example.com', payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.org', payload=dns.Record_A('1.2.3.4'))) - - # Vary the payload - self._equalityTest( - dns.RRHeader(b'example.com', payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', payload=dns.Record_A('1.2.3.5'))) - - # Vary the type. Leave the payload as None so that we don't have to - # provide non-equal values. - self._equalityTest( - dns.RRHeader(b'example.com', dns.A), - dns.RRHeader(b'example.com', dns.A), - dns.RRHeader(b'example.com', dns.MX)) - - # Probably not likely to come up. Most people use the internet. - self._equalityTest( - dns.RRHeader(b'example.com', cls=dns.IN, payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', cls=dns.IN, payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', cls=dns.CS, payload=dns.Record_A('1.2.3.4'))) - - # Vary the ttl - self._equalityTest( - dns.RRHeader(b'example.com', ttl=60, payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', ttl=60, payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', ttl=120, payload=dns.Record_A('1.2.3.4'))) - - # Vary the auth bit - self._equalityTest( - dns.RRHeader(b'example.com', auth=1, payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', auth=1, payload=dns.Record_A('1.2.3.4')), - dns.RRHeader(b'example.com', auth=0, payload=dns.Record_A('1.2.3.4'))) - - - def test_ns(self): - """ - Two L{dns.Record_NS} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_NS) - - - def test_md(self): - """ - Two L{dns.Record_MD} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_MD) - - - def test_mf(self): - """ - Two L{dns.Record_MF} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_MF) - - - def test_cname(self): - """ - Two L{dns.Record_CNAME} instances compare equal if and only if they - have the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_CNAME) - - - def test_mb(self): - """ - Two L{dns.Record_MB} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_MB) - - - def test_mg(self): - """ - Two L{dns.Record_MG} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_MG) - - - def test_mr(self): - """ - Two L{dns.Record_MR} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_MR) - - - def test_ptr(self): - """ - Two L{dns.Record_PTR} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_PTR) - - - def test_dname(self): - """ - Two L{dns.Record_MD} instances compare equal if and only if they have - the same name and TTL. - """ - self._simpleEqualityTest(dns.Record_DNAME) - - - def test_a(self): - """ - Two L{dns.Record_A} instances compare equal if and only if they have - the same address and TTL. - """ - # Vary the TTL - self._equalityTest( - dns.Record_A('1.2.3.4', 5), - dns.Record_A('1.2.3.4', 5), - dns.Record_A('1.2.3.4', 6)) - # Vary the address - self._equalityTest( - dns.Record_A('1.2.3.4', 5), - dns.Record_A('1.2.3.4', 5), - dns.Record_A('1.2.3.5', 5)) - - - def test_soa(self): - """ - Two L{dns.Record_SOA} instances compare equal if and only if they have - the same mname, rname, serial, refresh, minimum, expire, retry, and - ttl. - """ - # Vary the mname - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'xname', b'rname', 123, 456, 789, 10, 20, 30)) - # Vary the rname - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'xname', 123, 456, 789, 10, 20, 30)) - # Vary the serial - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 1, 456, 789, 10, 20, 30)) - # Vary the refresh - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 1, 789, 10, 20, 30)) - # Vary the minimum - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 1, 10, 20, 30)) - # Vary the expire - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 1, 20, 30)) - # Vary the retry - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 1, 30)) - # Vary the ttl - self._equalityTest( - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'rname', 123, 456, 789, 10, 20, 30), - dns.Record_SOA(b'mname', b'xname', 123, 456, 789, 10, 20, 1)) - - - def test_null(self): - """ - Two L{dns.Record_NULL} instances compare equal if and only if they have - the same payload and ttl. - """ - # Vary the payload - self._equalityTest( - dns.Record_NULL('foo bar', 10), - dns.Record_NULL('foo bar', 10), - dns.Record_NULL('bar foo', 10)) - # Vary the ttl - self._equalityTest( - dns.Record_NULL('foo bar', 10), - dns.Record_NULL('foo bar', 10), - dns.Record_NULL('foo bar', 100)) - - - def test_wks(self): - """ - Two L{dns.Record_WKS} instances compare equal if and only if they have - the same address, protocol, map, and ttl. - """ - # Vary the address - self._equalityTest( - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('4.3.2.1', 1, 'foo', 2)) - # Vary the protocol - self._equalityTest( - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('1.2.3.4', 100, 'foo', 2)) - # Vary the map - self._equalityTest( - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('1.2.3.4', 1, 'bar', 2)) - # Vary the ttl - self._equalityTest( - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('1.2.3.4', 1, 'foo', 2), - dns.Record_WKS('1.2.3.4', 1, 'foo', 200)) - - - def test_aaaa(self): - """ - Two L{dns.Record_AAAA} instances compare equal if and only if they have - the same address and ttl. - """ - # Vary the address - self._equalityTest( - dns.Record_AAAA('1::2', 1), - dns.Record_AAAA('1::2', 1), - dns.Record_AAAA('2::1', 1)) - # Vary the ttl - self._equalityTest( - dns.Record_AAAA('1::2', 1), - dns.Record_AAAA('1::2', 1), - dns.Record_AAAA('1::2', 10)) - - - def test_a6(self): - """ - Two L{dns.Record_A6} instances compare equal if and only if they have - the same prefix, prefix length, suffix, and ttl. - """ - # Note, A6 is crazy, I'm not sure these values are actually legal. - # Hopefully that doesn't matter for this test. -exarkun - - # Vary the prefix length - self._equalityTest( - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(32, '::abcd', b'example.com', 10)) - # Vary the suffix - self._equalityTest( - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(16, '::abcd:0', b'example.com', 10)) - # Vary the prefix - self._equalityTest( - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(16, '::abcd', b'example.org', 10)) - # Vary the ttl - self._equalityTest( - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(16, '::abcd', b'example.com', 10), - dns.Record_A6(16, '::abcd', b'example.com', 100)) - - - def test_srv(self): - """ - Two L{dns.Record_SRV} instances compare equal if and only if they have - the same priority, weight, port, target, and ttl. - """ - # Vary the priority - self._equalityTest( - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(100, 20, 30, b'example.com', 40)) - # Vary the weight - self._equalityTest( - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 200, 30, b'example.com', 40)) - # Vary the port - self._equalityTest( - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 300, b'example.com', 40)) - # Vary the target - self._equalityTest( - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 30, b'example.org', 40)) - # Vary the ttl - self._equalityTest( - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 30, b'example.com', 40), - dns.Record_SRV(10, 20, 30, b'example.com', 400)) - - - def test_naptr(self): - """ - Two L{dns.Record_NAPTR} instances compare equal if and only if they - have the same order, preference, flags, service, regexp, replacement, - and ttl. - """ - # Vary the order - self._equalityTest( - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(2, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12)) - # Vary the preference - self._equalityTest( - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 3, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12)) - # Vary the flags - self._equalityTest( - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"p", b"sip+E2U", b"/foo/bar/", b"baz", 12)) - # Vary the service - self._equalityTest( - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"http", b"/foo/bar/", b"baz", 12)) - # Vary the regexp - self._equalityTest( - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/bar/foo/", b"baz", 12)) - # Vary the replacement - self._equalityTest( - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/bar/foo/", b"quux", 12)) - # Vary the ttl - self._equalityTest( - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/foo/bar/", b"baz", 12), - dns.Record_NAPTR(1, 2, b"u", b"sip+E2U", b"/bar/foo/", b"baz", 5)) - - - def test_afsdb(self): - """ - Two L{dns.Record_AFSDB} instances compare equal if and only if they - have the same subtype, hostname, and ttl. - """ - # Vary the subtype - self._equalityTest( - dns.Record_AFSDB(1, b'example.com', 2), - dns.Record_AFSDB(1, b'example.com', 2), - dns.Record_AFSDB(2, b'example.com', 2)) - # Vary the hostname - self._equalityTest( - dns.Record_AFSDB(1, b'example.com', 2), - dns.Record_AFSDB(1, b'example.com', 2), - dns.Record_AFSDB(1, b'example.org', 2)) - # Vary the ttl - self._equalityTest( - dns.Record_AFSDB(1, b'example.com', 2), - dns.Record_AFSDB(1, b'example.com', 2), - dns.Record_AFSDB(1, b'example.com', 3)) - - - def test_rp(self): - """ - Two L{Record_RP} instances compare equal if and only if they have the - same mbox, txt, and ttl. - """ - # Vary the mbox - self._equalityTest( - dns.Record_RP(b'alice.example.com', b'alice is nice', 10), - dns.Record_RP(b'alice.example.com', b'alice is nice', 10), - dns.Record_RP(b'bob.example.com', b'alice is nice', 10)) - # Vary the txt - self._equalityTest( - dns.Record_RP(b'alice.example.com', b'alice is nice', 10), - dns.Record_RP(b'alice.example.com', b'alice is nice', 10), - dns.Record_RP(b'alice.example.com', b'alice is not nice', 10)) - # Vary the ttl - self._equalityTest( - dns.Record_RP(b'alice.example.com', b'alice is nice', 10), - dns.Record_RP(b'alice.example.com', b'alice is nice', 10), - dns.Record_RP(b'alice.example.com', b'alice is nice', 100)) - - - def test_hinfo(self): - """ - Two L{dns.Record_HINFO} instances compare equal if and only if they - have the same cpu, os, and ttl. - """ - # Vary the cpu - self._equalityTest( - dns.Record_HINFO('x86-64', 'plan9', 10), - dns.Record_HINFO('x86-64', 'plan9', 10), - dns.Record_HINFO('i386', 'plan9', 10)) - # Vary the os - self._equalityTest( - dns.Record_HINFO('x86-64', 'plan9', 10), - dns.Record_HINFO('x86-64', 'plan9', 10), - dns.Record_HINFO('x86-64', 'plan11', 10)) - # Vary the ttl - self._equalityTest( - dns.Record_HINFO('x86-64', 'plan9', 10), - dns.Record_HINFO('x86-64', 'plan9', 10), - dns.Record_HINFO('x86-64', 'plan9', 100)) - - - def test_minfo(self): - """ - Two L{dns.Record_MINFO} instances compare equal if and only if they - have the same rmailbx, emailbx, and ttl. - """ - # Vary the rmailbx - self._equalityTest( - dns.Record_MINFO(b'rmailbox', b'emailbox', 10), - dns.Record_MINFO(b'rmailbox', b'emailbox', 10), - dns.Record_MINFO(b'someplace', b'emailbox', 10)) - # Vary the emailbx - self._equalityTest( - dns.Record_MINFO(b'rmailbox', b'emailbox', 10), - dns.Record_MINFO(b'rmailbox', b'emailbox', 10), - dns.Record_MINFO(b'rmailbox', b'something', 10)) - # Vary the ttl - self._equalityTest( - dns.Record_MINFO(b'rmailbox', b'emailbox', 10), - dns.Record_MINFO(b'rmailbox', b'emailbox', 10), - dns.Record_MINFO(b'rmailbox', b'emailbox', 100)) - - - def test_mx(self): - """ - Two L{dns.Record_MX} instances compare equal if and only if they have - the same preference, name, and ttl. - """ - # Vary the preference - self._equalityTest( - dns.Record_MX(10, b'example.org', 20), - dns.Record_MX(10, b'example.org', 20), - dns.Record_MX(100, b'example.org', 20)) - # Vary the name - self._equalityTest( - dns.Record_MX(10, b'example.org', 20), - dns.Record_MX(10, b'example.org', 20), - dns.Record_MX(10, b'example.net', 20)) - # Vary the ttl - self._equalityTest( - dns.Record_MX(10, b'example.org', 20), - dns.Record_MX(10, b'example.org', 20), - dns.Record_MX(10, b'example.org', 200)) - - - def test_txt(self): - """ - Two L{dns.Record_TXT} instances compare equal if and only if they have - the same data and ttl. - """ - # Vary the length of the data - self._equalityTest( - dns.Record_TXT('foo', 'bar', ttl=10), - dns.Record_TXT('foo', 'bar', ttl=10), - dns.Record_TXT('foo', 'bar', 'baz', ttl=10)) - # Vary the value of the data - self._equalityTest( - dns.Record_TXT('foo', 'bar', ttl=10), - dns.Record_TXT('foo', 'bar', ttl=10), - dns.Record_TXT('bar', 'foo', ttl=10)) - # Vary the ttl - self._equalityTest( - dns.Record_TXT('foo', 'bar', ttl=10), - dns.Record_TXT('foo', 'bar', ttl=10), - dns.Record_TXT('foo', 'bar', ttl=100)) - - - def test_spf(self): - """ - L{dns.Record_SPF} instances compare equal if and only if they have the - same data and ttl. - """ - # Vary the length of the data - self._equalityTest( - dns.Record_SPF('foo', 'bar', ttl=10), - dns.Record_SPF('foo', 'bar', ttl=10), - dns.Record_SPF('foo', 'bar', 'baz', ttl=10)) - # Vary the value of the data - self._equalityTest( - dns.Record_SPF('foo', 'bar', ttl=10), - dns.Record_SPF('foo', 'bar', ttl=10), - dns.Record_SPF('bar', 'foo', ttl=10)) - # Vary the ttl - self._equalityTest( - dns.Record_SPF('foo', 'bar', ttl=10), - dns.Record_SPF('foo', 'bar', ttl=10), - dns.Record_SPF('foo', 'bar', ttl=100)) - - - def test_unknown(self): - """ - L{dns.UnknownRecord} instances compare equal if and only if they have - the same data and ttl. - """ - # Vary the length of the data - self._equalityTest( - dns.UnknownRecord('foo', ttl=10), - dns.UnknownRecord('foo', ttl=10), - dns.UnknownRecord('foobar', ttl=10)) - # Vary the value of the data - self._equalityTest( - dns.UnknownRecord('foo', ttl=10), - dns.UnknownRecord('foo', ttl=10), - dns.UnknownRecord('bar', ttl=10)) - # Vary the ttl - self._equalityTest( - dns.UnknownRecord('foo', ttl=10), - dns.UnknownRecord('foo', ttl=10), - dns.UnknownRecord('foo', ttl=100)) - - - -class RRHeaderTests(unittest.TestCase): - """ - Tests for L{twisted.names.dns.RRHeader}. - """ - - def test_negativeTTL(self): - """ - Attempting to create a L{dns.RRHeader} instance with a negative TTL - causes L{ValueError} to be raised. - """ - self.assertRaises( - ValueError, dns.RRHeader, "example.com", dns.A, - dns.IN, -1, dns.Record_A("127.0.0.1")) - - - -class NameToLabelsTests(unittest.SynchronousTestCase): - """ - Tests for L{twisted.names.dns._nameToLabels}. - """ - - def test_empty(self): - """ - L{dns._nameToLabels} returns a list containing a single - empty label for an empty name. - """ - self.assertEqual(dns._nameToLabels(b''), [b'']) - - - def test_onlyDot(self): - """ - L{dns._nameToLabels} returns a list containing a single - empty label for a name containing only a dot. - """ - self.assertEqual(dns._nameToLabels(b'.'), [b'']) - - - def test_withoutTrailingDot(self): - """ - L{dns._nameToLabels} returns a list ending with an empty - label for a name without a trailing dot. - """ - self.assertEqual(dns._nameToLabels(b'com'), [b'com', b'']) - - - def test_withTrailingDot(self): - """ - L{dns._nameToLabels} returns a list ending with an empty - label for a name with a trailing dot. - """ - self.assertEqual(dns._nameToLabels(b'com.'), [b'com', b'']) - - - def test_subdomain(self): - """ - L{dns._nameToLabels} returns a list containing entries - for all labels in a subdomain name. - """ - self.assertEqual( - dns._nameToLabels(b'foo.bar.baz.example.com.'), - [b'foo', b'bar', b'baz', b'example', b'com', b'']) - - - def test_casePreservation(self): - """ - L{dns._nameToLabels} preserves the case of ascii - characters in labels. - """ - self.assertEqual( - dns._nameToLabels(b'EXAMPLE.COM'), - [b'EXAMPLE', b'COM', b'']) - - - -def assertIsSubdomainOf(testCase, descendant, ancestor): - """ - Assert that C{descendant} *is* a subdomain of C{ancestor}. - - @type testCase: L{unittest.SynchronousTestCase} - @param testCase: The test case on which to run the assertions. - - @type descendant: C{str} - @param descendant: The subdomain name to test. - - @type ancestor: C{str} - @param ancestor: The superdomain name to test. - """ - testCase.assertTrue( - dns._isSubdomainOf(descendant, ancestor), - '%r is not a subdomain of %r' % (descendant, ancestor)) - - - -def assertIsNotSubdomainOf(testCase, descendant, ancestor): - """ - Assert that C{descendant} *is not* a subdomain of C{ancestor}. - - @type testCase: L{unittest.SynchronousTestCase} - @param testCase: The test case on which to run the assertions. - - @type descendant: C{str} - @param descendant: The subdomain name to test. - - @type ancestor: C{str} - @param ancestor: The superdomain name to test. - """ - testCase.assertFalse( - dns._isSubdomainOf(descendant, ancestor), - '%r is a subdomain of %r' % (descendant, ancestor)) - - - -class IsSubdomainOfTests(unittest.SynchronousTestCase): - """ - Tests for L{twisted.names.dns._isSubdomainOf}. - """ - - def test_identical(self): - """ - L{dns._isSubdomainOf} returns C{True} for identical - domain names. - """ - assertIsSubdomainOf(self, b'example.com', b'example.com') - - - def test_parent(self): - """ - L{dns._isSubdomainOf} returns C{True} when the first - name is an immediate descendant of the second name. - """ - assertIsSubdomainOf(self, b'foo.example.com', b'example.com') - - - def test_distantAncestor(self): - """ - L{dns._isSubdomainOf} returns C{True} when the first - name is a distant descendant of the second name. - """ - assertIsSubdomainOf(self, b'foo.bar.baz.example.com', b'com') - - - def test_superdomain(self): - """ - L{dns._isSubdomainOf} returns C{False} when the first - name is an ancestor of the second name. - """ - assertIsNotSubdomainOf(self, b'example.com', b'foo.example.com') - - - def test_sibling(self): - """ - L{dns._isSubdomainOf} returns C{False} if the first name - is a sibling of the second name. - """ - assertIsNotSubdomainOf(self, b'foo.example.com', b'bar.example.com') - - - def test_unrelatedCommonSuffix(self): - """ - L{dns._isSubdomainOf} returns C{False} even when domain - names happen to share a common suffix. - """ - assertIsNotSubdomainOf(self, b'foo.myexample.com', b'example.com') - - - def test_subdomainWithTrailingDot(self): - """ - L{dns._isSubdomainOf} returns C{True} if the first name - is a subdomain of the second name but the first name has a - trailing ".". - """ - assertIsSubdomainOf(self, b'foo.example.com.', b'example.com') - - - def test_superdomainWithTrailingDot(self): - """ - L{dns._isSubdomainOf} returns C{True} if the first name - is a subdomain of the second name but the second name has a - trailing ".". - """ - assertIsSubdomainOf(self, b'foo.example.com', b'example.com.') - - - def test_bothWithTrailingDot(self): - """ - L{dns._isSubdomainOf} returns C{True} if the first name - is a subdomain of the second name and both names have a - trailing ".". - """ - assertIsSubdomainOf(self, b'foo.example.com.', b'example.com.') - - - def test_emptySubdomain(self): - """ - L{dns._isSubdomainOf} returns C{False} if the first name - is empty and the second name is not. - """ - assertIsNotSubdomainOf(self, b'', b'example.com') - - - def test_emptySuperdomain(self): - """ - L{dns._isSubdomainOf} returns C{True} if the second name - is empty and the first name is not. - """ - assertIsSubdomainOf(self, b'foo.example.com', b'') - - - def test_caseInsensitiveComparison(self): - """ - L{dns._isSubdomainOf} does case-insensitive comparison - of name labels. - """ - assertIsSubdomainOf(self, b'foo.example.com', b'EXAMPLE.COM') - - assertIsSubdomainOf(self, b'FOO.EXAMPLE.COM', b'example.com') - - - -class OPTNonStandardAttributes(object): - """ - Generate byte and instance representations of an L{dns._OPTHeader} - where all attributes are set to non-default values. - - For testing whether attributes have really been read from the byte - string during decoding. - """ - @classmethod - def bytes(cls, excludeName=False, excludeOptions=False): - """ - Return L{bytes} representing an encoded OPT record. - - @param excludeName: A flag that controls whether to exclude - the name field. This allows a non-standard name to be - prepended during the test. - @type excludeName: L{bool} - - @param excludeOptions: A flag that controls whether to exclude - the RDLEN field. This allows encoded variable options to be - appended during the test. - @type excludeOptions: L{bool} - - @return: L{bytes} representing the encoded OPT record returned - by L{object}. - """ - rdlen = b'\x00\x00' # RDLEN 0 - if excludeOptions: - rdlen = b'' - - return ( - b'\x00' # 0 root zone - b'\x00\x29' # type 41 - b'\x02\x00' # udpPayloadsize 512 - b'\x03' # extendedRCODE 3 - b'\x04' # version 4 - b'\x80\x00' # DNSSEC OK 1 + Z - ) + rdlen - - - @classmethod - def object(cls): - """ - Return a new L{dns._OPTHeader} instance. - - @return: A L{dns._OPTHeader} instance with attributes that - match the encoded record returned by L{bytes}. - """ - return dns._OPTHeader( - udpPayloadSize=512, - extendedRCODE=3, - version=4, - dnssecOK=True) - - - -class OPTHeaderTests(ComparisonTestsMixin, unittest.TestCase): - """ - Tests for L{twisted.names.dns._OPTHeader}. - """ - def test_interface(self): - """ - L{dns._OPTHeader} implements L{dns.IEncodable}. - """ - verifyClass(dns.IEncodable, dns._OPTHeader) - - - def test_name(self): - """ - L{dns._OPTHeader.name} is a instance attribute whose value is - fixed as the root domain - """ - self.assertEqual(dns._OPTHeader().name, dns.Name(b'')) - - - def test_nameReadonly(self): - """ - L{dns._OPTHeader.name} is readonly. - """ - h = dns._OPTHeader() - self.assertRaises( - AttributeError, setattr, h, 'name', dns.Name(b'example.com')) - - - def test_type(self): - """ - L{dns._OPTHeader.type} is an instance attribute with fixed value - 41. - """ - self.assertEqual(dns._OPTHeader().type, 41) - - - def test_typeReadonly(self): - """ - L{dns._OPTHeader.type} is readonly. - """ - h = dns._OPTHeader() - self.assertRaises( - AttributeError, setattr, h, 'type', dns.A) - - - def test_udpPayloadSize(self): - """ - L{dns._OPTHeader.udpPayloadSize} defaults to 4096 as - recommended in rfc6891 section-6.2.5. - """ - self.assertEqual(dns._OPTHeader().udpPayloadSize, 4096) - - - def test_udpPayloadSizeOverride(self): - """ - L{dns._OPTHeader.udpPayloadSize} can be overridden in the - constructor. - """ - self.assertEqual(dns._OPTHeader(udpPayloadSize=512).udpPayloadSize, 512) - - - def test_extendedRCODE(self): - """ - L{dns._OPTHeader.extendedRCODE} defaults to 0. - """ - self.assertEqual(dns._OPTHeader().extendedRCODE, 0) - - - def test_extendedRCODEOverride(self): - """ - L{dns._OPTHeader.extendedRCODE} can be overridden in the - constructor. - """ - self.assertEqual(dns._OPTHeader(extendedRCODE=1).extendedRCODE, 1) - - - def test_version(self): - """ - L{dns._OPTHeader.version} defaults to 0. - """ - self.assertEqual(dns._OPTHeader().version, 0) - - - def test_versionOverride(self): - """ - L{dns._OPTHeader.version} can be overridden in the - constructor. - """ - self.assertEqual(dns._OPTHeader(version=1).version, 1) - - - def test_dnssecOK(self): - """ - L{dns._OPTHeader.dnssecOK} defaults to False. - """ - self.assertEqual(dns._OPTHeader().dnssecOK, False) - - - def test_dnssecOKOverride(self): - """ - L{dns._OPTHeader.dnssecOK} can be overridden in the - constructor. - """ - self.assertEqual(dns._OPTHeader(dnssecOK=True).dnssecOK, True) - - - def test_options(self): - """ - L{dns._OPTHeader.options} defaults to empty list. - """ - self.assertEqual(dns._OPTHeader().options, []) - - - def test_optionsOverride(self): - """ - L{dns._OPTHeader.options} can be overridden in the - constructor. - """ - h = dns._OPTHeader(options=[(1, 1, b'\x00')]) - self.assertEqual(h.options, [(1, 1, b'\x00')]) - - - def test_encode(self): - """ - L{dns._OPTHeader.encode} packs the header fields and writes - them to a file like object passed in as an argument. - """ - b = BytesIO() - - OPTNonStandardAttributes.object().encode(b) - self.assertEqual( - b.getvalue(), - OPTNonStandardAttributes.bytes() - ) - - - def test_encodeWithOptions(self): - """ - L{dns._OPTHeader.options} is a list of L{dns._OPTVariableOption} - instances which are packed into the rdata area of the header. - """ - h = OPTNonStandardAttributes.object() - h.options = [ - dns._OPTVariableOption(1, b'foobarbaz'), - dns._OPTVariableOption(2, b'qux'), - ] - b = BytesIO() - - h.encode(b) - self.assertEqual( - b.getvalue(), - - OPTNonStandardAttributes.bytes(excludeOptions=True) + ( - b'\x00\x14' # RDLEN 20 - - b'\x00\x01' # OPTION-CODE - b'\x00\x09' # OPTION-LENGTH - b'foobarbaz' # OPTION-DATA - - b'\x00\x02' # OPTION-CODE - b'\x00\x03' # OPTION-LENGTH - b'qux' # OPTION-DATA - )) - - - def test_decode(self): - """ - L{dns._OPTHeader.decode} unpacks the header fields from a file - like object and populates the attributes of an existing - L{dns._OPTHeader} instance. - """ - decodedHeader = dns._OPTHeader() - decodedHeader.decode(BytesIO(OPTNonStandardAttributes.bytes())) - - self.assertEqual( - decodedHeader, - OPTNonStandardAttributes.object()) - - - def test_decodeAllExpectedBytes(self): - """ - L{dns._OPTHeader.decode} reads all the bytes of the record - that is being decoded. - """ - # Check that all the input data has been consumed. - b = BytesIO(OPTNonStandardAttributes.bytes()) - - decodedHeader = dns._OPTHeader() - decodedHeader.decode(b) - - self.assertEqual(b.tell(), len(b.getvalue())) - - - def test_decodeOnlyExpectedBytes(self): - """ - L{dns._OPTHeader.decode} reads only the bytes from the current - file position to the end of the record that is being - decoded. Trailing bytes are not consumed. - """ - b = BytesIO(OPTNonStandardAttributes.bytes() - + b'xxxx') # Trailing bytes - - decodedHeader = dns._OPTHeader() - decodedHeader.decode(b) - - self.assertEqual(b.tell(), len(b.getvalue())-len(b'xxxx')) - - - def test_decodeDiscardsName(self): - """ - L{dns._OPTHeader.decode} discards the name which is encoded in - the supplied bytes. The name attribute of the resulting - L{dns._OPTHeader} instance will always be L{dns.Name(b'')}. - """ - b = BytesIO(OPTNonStandardAttributes.bytes(excludeName=True) - + b'\x07example\x03com\x00') - - h = dns._OPTHeader() - h.decode(b) - self.assertEqual(h.name, dns.Name(b'')) - - - def test_decodeRdlengthTooShort(self): - """ - L{dns._OPTHeader.decode} raises an exception if the supplied - RDLEN is too short. - """ - b = BytesIO( - OPTNonStandardAttributes.bytes(excludeOptions=True) + ( - b'\x00\x05' # RDLEN 5 Too short - should be 6 - - b'\x00\x01' # OPTION-CODE - b'\x00\x02' # OPTION-LENGTH - b'\x00\x00' # OPTION-DATA - )) - h = dns._OPTHeader() - self.assertRaises(EOFError, h.decode, b) - - - def test_decodeRdlengthTooLong(self): - """ - L{dns._OPTHeader.decode} raises an exception if the supplied - RDLEN is too long. - """ - b = BytesIO( - OPTNonStandardAttributes.bytes(excludeOptions=True) + ( - - b'\x00\x07' # RDLEN 7 Too long - should be 6 - - b'\x00\x01' # OPTION-CODE - b'\x00\x02' # OPTION-LENGTH - b'\x00\x00' # OPTION-DATA - )) - h = dns._OPTHeader() - self.assertRaises(EOFError, h.decode, b) - - - def test_decodeWithOptions(self): - """ - If the OPT bytes contain variable options, - L{dns._OPTHeader.decode} will populate a list - L{dns._OPTHeader.options} with L{dns._OPTVariableOption} - instances. - """ - - b = BytesIO( - OPTNonStandardAttributes.bytes(excludeOptions=True) + ( - - b'\x00\x14' # RDLEN 20 - - b'\x00\x01' # OPTION-CODE - b'\x00\x09' # OPTION-LENGTH - b'foobarbaz' # OPTION-DATA - - b'\x00\x02' # OPTION-CODE - b'\x00\x03' # OPTION-LENGTH - b'qux' # OPTION-DATA - )) - - h = dns._OPTHeader() - h.decode(b) - self.assertEqual( - h.options, - [dns._OPTVariableOption(1, b'foobarbaz'), - dns._OPTVariableOption(2, b'qux'),] - ) - - - def test_fromRRHeader(self): - """ - L{_OPTHeader.fromRRHeader} accepts an L{RRHeader} instance and - returns an L{_OPTHeader} instance whose attribute values have - been derived from the C{cls}, C{ttl} and C{payload} attributes - of the original header. - """ - genericHeader = dns.RRHeader( - b'example.com', - type=dns.OPT, - cls=0xffff, - ttl=(0xfe << 24 - | 0xfd << 16 - | True << 15), - payload=dns.UnknownRecord(b'\xff\xff\x00\x03abc')) - - decodedOptHeader = dns._OPTHeader.fromRRHeader(genericHeader) - - expectedOptHeader = dns._OPTHeader( - udpPayloadSize=0xffff, - extendedRCODE=0xfe, - version=0xfd, - dnssecOK=True, - options=[dns._OPTVariableOption(code=0xffff, data=b'abc')]) - - self.assertEqual(decodedOptHeader, expectedOptHeader) - - - def test_repr(self): - """ - L{dns._OPTHeader.__repr__} displays the name and type and all - the fixed and extended header values of the OPT record. - """ - self.assertEqual( - repr(dns._OPTHeader()), - '<_OPTHeader ' - 'name= ' - 'type=41 ' - 'udpPayloadSize=4096 ' - 'extendedRCODE=0 ' - 'version=0 ' - 'dnssecOK=False ' - 'options=[]>') - - - def test_equalityUdpPayloadSize(self): - """ - Two L{OPTHeader} instances compare equal if they have the same - udpPayloadSize. - """ - self.assertNormalEqualityImplementation( - dns._OPTHeader(udpPayloadSize=512), - dns._OPTHeader(udpPayloadSize=512), - dns._OPTHeader(udpPayloadSize=4096)) - - - def test_equalityExtendedRCODE(self): - """ - Two L{OPTHeader} instances compare equal if they have the same - extendedRCODE. - """ - self.assertNormalEqualityImplementation( - dns._OPTHeader(extendedRCODE=1), - dns._OPTHeader(extendedRCODE=1), - dns._OPTHeader(extendedRCODE=2)) - - - def test_equalityVersion(self): - """ - Two L{OPTHeader} instances compare equal if they have the same - version. - """ - self.assertNormalEqualityImplementation( - dns._OPTHeader(version=1), - dns._OPTHeader(version=1), - dns._OPTHeader(version=2)) - - - def test_equalityDnssecOK(self): - """ - Two L{OPTHeader} instances compare equal if they have the same - dnssecOK flags. - """ - self.assertNormalEqualityImplementation( - dns._OPTHeader(dnssecOK=True), - dns._OPTHeader(dnssecOK=True), - dns._OPTHeader(dnssecOK=False)) - - - def test_equalityOptions(self): - """ - Two L{OPTHeader} instances compare equal if they have the same - options. - """ - self.assertNormalEqualityImplementation( - dns._OPTHeader(options=[dns._OPTVariableOption(1, b'x')]), - dns._OPTHeader(options=[dns._OPTVariableOption(1, b'x')]), - dns._OPTHeader(options=[dns._OPTVariableOption(2, b'y')])) - - - -class OPTVariableOptionTests(ComparisonTestsMixin, unittest.TestCase): - """ - Tests for L{dns._OPTVariableOption}. - """ - def test_interface(self): - """ - L{dns._OPTVariableOption} implements L{dns.IEncodable}. - """ - verifyClass(dns.IEncodable, dns._OPTVariableOption) - - - def test_constructorArguments(self): - """ - L{dns._OPTVariableOption.__init__} requires code and data - arguments which are saved as public instance attributes. - """ - h = dns._OPTVariableOption(1, b'x') - self.assertEqual(h.code, 1) - self.assertEqual(h.data, b'x') - - - def test_repr(self): - """ - L{dns._OPTVariableOption.__repr__} displays the code and data - of the option. - """ - self.assertEqual( - repr(dns._OPTVariableOption(1, b'x')), - '<_OPTVariableOption ' - 'code=1 ' - "data=x" - '>') - - - def test_equality(self): - """ - Two OPTVariableOption instances compare equal if they have the same - code and data values. - """ - self.assertNormalEqualityImplementation( - dns._OPTVariableOption(1, b'x'), - dns._OPTVariableOption(1, b'x'), - dns._OPTVariableOption(2, b'x')) - - self.assertNormalEqualityImplementation( - dns._OPTVariableOption(1, b'x'), - dns._OPTVariableOption(1, b'x'), - dns._OPTVariableOption(1, b'y')) - - - def test_encode(self): - """ - L{dns._OPTVariableOption.encode} encodes the code and data - instance attributes to a byte string which also includes the - data length. - """ - o = dns._OPTVariableOption(1, b'foobar') - b = BytesIO() - o.encode(b) - self.assertEqual( - b.getvalue(), - b'\x00\x01' # OPTION-CODE 1 - b'\x00\x06' # OPTION-LENGTH 6 - b'foobar' # OPTION-DATA - ) - - - def test_decode(self): - """ - L{dns._OPTVariableOption.decode} is a classmethod that decodes - a byte string and returns a L{dns._OPTVariableOption} instance. - """ - b = BytesIO( - b'\x00\x01' # OPTION-CODE 1 - b'\x00\x06' # OPTION-LENGTH 6 - b'foobar' # OPTION-DATA - ) - - o = dns._OPTVariableOption() - o.decode(b) - self.assertEqual(o.code, 1) - self.assertEqual(o.data, b'foobar') - - - -class RaisedArgs(Exception): - """ - An exception which can be raised by fakes to test that the fake is called - with expected arguments. - """ - def __init__(self, args, kwargs): - """ - Store the positional and keyword arguments as attributes. - - @param args: The positional args. - @param kwargs: The keyword args. - """ - self.args = args - self.kwargs = kwargs - - - -class MessageEmpty(object): - """ - Generate byte string and constructor arguments for an empty - L{dns._EDNSMessage}. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x01\x00' # id: 256 - b'\x97' # QR: 1, OPCODE: 2, AA: 0, TC: 0, RD: 1 - b'\x8f' # RA: 1, Z, RCODE: 15 - b'\x00\x00' # number of queries - b'\x00\x00' # number of answers - b'\x00\x00' # number of authorities - b'\x00\x00' # number of additionals - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=256, - answer=True, - opCode=dns.OP_STATUS, - auth=True, - trunc=True, - recDes=True, - recAv=True, - rCode=15, - ednsVersion=None, - ) - - - -class MessageTruncated(object): - """ - An empty response message whose TR bit is set to 1. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x01\x00' # ID: 256 - b'\x82' # QR: 1, OPCODE: 0, AA: 0, TC: 1, RD: 0 - b'\x00' # RA: 0, Z, RCODE: 0 - b'\x00\x00' # Number of queries - b'\x00\x00' # Number of answers - b'\x00\x00' # Number of authorities - b'\x00\x00' # Number of additionals - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=256, - answer=1, - opCode=0, - auth=0, - trunc=1, - recDes=0, - recAv=0, - rCode=0, - ednsVersion=None,) - - - -class MessageNonAuthoritative(object): - """ - A minimal non-authoritative message. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x01\x00' # ID 256 - b'\x00' # QR: 0, OPCODE: 0, AA: 0, TC: 0, RD: 0 - b'\x00' # RA: 0, Z, RCODE: 0 - b'\x00\x00' # Query count - b'\x00\x01' # Answer count - b'\x00\x00' # Authorities count - b'\x00\x00' # Additionals count - # Answer - b'\x00' # RR NAME (root) - b'\x00\x01' # RR TYPE 1 (A) - b'\x00\x01' # RR CLASS 1 (IN) - b'\x00\x00\x00\x00' # RR TTL - b'\x00\x04' # RDLENGTH 4 - b'\x01\x02\x03\x04' # IPv4 1.2.3.4 - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=256, - auth=0, - ednsVersion=None, - answers=[ - dns.RRHeader( - b'', - payload=dns.Record_A('1.2.3.4', ttl=0), - auth=False)]) - - - -class MessageAuthoritative(object): - """ - A minimal authoritative message. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x01\x00' # ID: 256 - b'\x04' # QR: 0, OPCODE: 0, AA: 1, TC: 0, RD: 0 - b'\x00' # RA: 0, Z, RCODE: 0 - b'\x00\x00' # Query count - b'\x00\x01' # Answer count - b'\x00\x00' # Authorities count - b'\x00\x00' # Additionals count - # Answer - b'\x00' # RR NAME (root) - b'\x00\x01' # RR TYPE 1 (A) - b'\x00\x01' # RR CLASS 1 (IN) - b'\x00\x00\x00\x00' # RR TTL - b'\x00\x04' # RDLENGTH 4 - b'\x01\x02\x03\x04' # IPv4 1.2.3.4 - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=256, - auth=1, - ednsVersion=None, - answers=[ - dns.RRHeader( - b'', - payload=dns.Record_A('1.2.3.4', ttl=0), - auth=True)]) - - - -class MessageComplete: - """ - An example of a fully populated non-edns response message. - - Contains name compression, answers, authority, and additional records. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x01\x00' # ID: 256 - b'\x95' # QR: 1, OPCODE: 2, AA: 1, TC: 0, RD: 1 - b'\x8f' # RA: 1, Z, RCODE: 15 - b'\x00\x01' # Query count - b'\x00\x01' # Answer count - b'\x00\x01' # Authorities count - b'\x00\x01' # Additionals count - - # Query begins at Byte 12 - b'\x07example\x03com\x00' # QNAME - b'\x00\x06' # QTYPE 6 (SOA) - b'\x00\x01' # QCLASS 1 (IN) - - # Answers - b'\xc0\x0c' # RR NAME (compression ref b12) - b'\x00\x06' # RR TYPE 6 (SOA) - b'\x00\x01' # RR CLASS 1 (IN) - b'\xff\xff\xff\xff' # RR TTL - b'\x00\x27' # RDLENGTH 39 - b'\x03ns1\xc0\x0c' # Mname (ns1.example.com (compression ref b15) - b'\x0ahostmaster\xc0\x0c' # rname (hostmaster.example.com) - b'\xff\xff\xff\xfe' # Serial - b'\x7f\xff\xff\xfd' # Refresh - b'\x7f\xff\xff\xfc' # Retry - b'\x7f\xff\xff\xfb' # Expire - b'\xff\xff\xff\xfa' # Minimum - - # Authority - b'\xc0\x0c' # RR NAME (example.com compression ref b12) - b'\x00\x02' # RR TYPE 2 (NS) - b'\x00\x01' # RR CLASS 1 (IN) - b'\xff\xff\xff\xff' # RR TTL - b'\x00\x02' # RDLENGTH - b'\xc0\x29' # RDATA (ns1.example.com (compression ref b41) - - # Additional - b'\xc0\x29' # RR NAME (ns1.example.com compression ref b41) - b'\x00\x01' # RR TYPE 1 (A) - b'\x00\x01' # RR CLASS 1 (IN) - b'\xff\xff\xff\xff' # RR TTL - b'\x00\x04' # RDLENGTH - b'\x05\x06\x07\x08' # RDATA 5.6.7.8 - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=256, - answer=1, - opCode=dns.OP_STATUS, - auth=1, - recDes=1, - recAv=1, - rCode=15, - ednsVersion=None, - queries=[dns.Query(b'example.com', dns.SOA)], - answers=[ - dns.RRHeader( - b'example.com', - type=dns.SOA, - ttl=0xffffffff, - auth=True, - payload=dns.Record_SOA( - ttl=0xffffffff, - mname=b'ns1.example.com', - rname=b'hostmaster.example.com', - serial=0xfffffffe, - refresh=0x7ffffffd, - retry=0x7ffffffc, - expire=0x7ffffffb, - minimum=0xfffffffa, - ))], - authority=[ - dns.RRHeader( - b'example.com', - type=dns.NS, - ttl=0xffffffff, - auth=True, - payload=dns.Record_NS( - 'ns1.example.com', ttl=0xffffffff))], - additional=[ - dns.RRHeader( - b'ns1.example.com', - type=dns.A, - ttl=0xffffffff, - auth=True, - payload=dns.Record_A( - '5.6.7.8', ttl=0xffffffff))]) - - - -class MessageEDNSQuery(object): - """ - A minimal EDNS query message. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x00\x00' # ID: 0 - b'\x00' # QR: 0, OPCODE: 0, AA: 0, TC: 0, RD: 0 - b'\x00' # RA: 0, Z, RCODE: 0 - b'\x00\x01' # Queries count - b'\x00\x00' # Anwers count - b'\x00\x00' # Authority count - b'\x00\x01' # Additionals count - - # Queries - b'\x03www\x07example\x03com\x00' # QNAME - b'\x00\x01' # QTYPE (A) - b'\x00\x01' # QCLASS (IN) - - # Additional OPT record - b'\x00' # NAME (.) - b'\x00\x29' # TYPE (OPT 41) - b'\x10\x00' # UDP Payload Size (4096) - b'\x00' # Extended RCODE - b'\x03' # EDNS version - b'\x00\x00' # DO: False + Z - b'\x00\x00' # RDLENGTH - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=0, - answer=0, - opCode=dns.OP_QUERY, - auth=0, - recDes=0, - recAv=0, - rCode=0, - ednsVersion=3, - dnssecOK=False, - queries=[dns.Query(b'www.example.com', dns.A)], - additional=[]) - - - -class MessageEDNSComplete(object): - """ - An example of a fully populated edns response message. - - Contains name compression, answers, authority, and additional records. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x01\x00' # ID: 256 - b'\x95' # QR: 1, OPCODE: 2, AA: 1, TC: 0, RD: 1 - b'\xbf' # RA: 1, AD: 1, RCODE: 15 - b'\x00\x01' # Query count - b'\x00\x01' # Answer count - b'\x00\x01' # Authorities count - b'\x00\x02' # Additionals count - - # Query begins at Byte 12 - b'\x07example\x03com\x00' # QNAME - b'\x00\x06' # QTYPE 6 (SOA) - b'\x00\x01' # QCLASS 1 (IN) - - # Answers - b'\xc0\x0c' # RR NAME (compression ref b12) - b'\x00\x06' # RR TYPE 6 (SOA) - b'\x00\x01' # RR CLASS 1 (IN) - b'\xff\xff\xff\xff' # RR TTL - b'\x00\x27' # RDLENGTH 39 - b'\x03ns1\xc0\x0c' # mname (ns1.example.com (compression ref b15) - b'\x0ahostmaster\xc0\x0c' # rname (hostmaster.example.com) - b'\xff\xff\xff\xfe' # Serial - b'\x7f\xff\xff\xfd' # Refresh - b'\x7f\xff\xff\xfc' # Retry - b'\x7f\xff\xff\xfb' # Expire - b'\xff\xff\xff\xfa' # Minimum - - # Authority - b'\xc0\x0c' # RR NAME (example.com compression ref b12) - b'\x00\x02' # RR TYPE 2 (NS) - b'\x00\x01' # RR CLASS 1 (IN) - b'\xff\xff\xff\xff' # RR TTL - b'\x00\x02' # RDLENGTH - b'\xc0\x29' # RDATA (ns1.example.com (compression ref b41) - - # Additional - b'\xc0\x29' # RR NAME (ns1.example.com compression ref b41) - b'\x00\x01' # RR TYPE 1 (A) - b'\x00\x01' # RR CLASS 1 (IN) - b'\xff\xff\xff\xff' # RR TTL - b'\x00\x04' # RDLENGTH - b'\x05\x06\x07\x08' # RDATA 5.6.7.8 - - # Additional OPT record - b'\x00' # NAME (.) - b'\x00\x29' # TYPE (OPT 41) - b'\x04\x00' # UDP Payload Size (1024) - b'\x00' # Extended RCODE - b'\x03' # EDNS version - b'\x80\x00' # DO: True + Z - b'\x00\x00' # RDLENGTH - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=256, - answer=1, - opCode=dns.OP_STATUS, - auth=1, - trunc=0, - recDes=1, - recAv=1, - rCode=15, - ednsVersion=3, - dnssecOK=True, - authenticData=True, - checkingDisabled=True, - maxSize=1024, - queries=[dns.Query(b'example.com', dns.SOA)], - answers=[ - dns.RRHeader( - b'example.com', - type=dns.SOA, - ttl=0xffffffff, - auth=True, - payload=dns.Record_SOA( - ttl=0xffffffff, - mname=b'ns1.example.com', - rname=b'hostmaster.example.com', - serial=0xfffffffe, - refresh=0x7ffffffd, - retry=0x7ffffffc, - expire=0x7ffffffb, - minimum=0xfffffffa, - ))], - authority=[ - dns.RRHeader( - b'example.com', - type=dns.NS, - ttl=0xffffffff, - auth=True, - payload=dns.Record_NS( - 'ns1.example.com', ttl=0xffffffff))], - additional=[ - dns.RRHeader( - b'ns1.example.com', - type=dns.A, - ttl=0xffffffff, - auth=True, - payload=dns.Record_A( - '5.6.7.8', ttl=0xffffffff))]) - - - -class MessageEDNSExtendedRCODE(object): - """ - An example of an EDNS message with an extended RCODE. - """ - @classmethod - def bytes(cls): - """ - Bytes which are expected when encoding an instance constructed using - C{kwargs} and which are expected to result in an identical instance when - decoded. - - @return: The L{bytes} of a wire encoded message. - """ - return ( - b'\x00\x00' - b'\x00' - b'\x0c' # RA: 0, Z, RCODE: 12 - b'\x00\x00' - b'\x00\x00' - b'\x00\x00' - b'\x00\x01' # 1 additionals - - # Additional OPT record - b'\x00' - b'\x00\x29' - b'\x10\x00' - b'\xab' # Extended RCODE: 171 - b'\x00' - b'\x00\x00' - b'\x00\x00' - ) - - - @classmethod - def kwargs(cls): - """ - Keyword constructor arguments which are expected to result in an - instance which returns C{bytes} when encoded. - - @return: A L{dict} of keyword arguments. - """ - return dict( - id=0, - answer=False, - opCode=dns.OP_QUERY, - auth=False, - trunc=False, - recDes=False, - recAv=False, - rCode=0xabc, # Combined OPT extended RCODE + Message RCODE - ednsVersion=0, - dnssecOK=False, - maxSize=4096, - queries=[], - answers=[], - authority=[], - additional=[], - ) - - - -class MessageComparable(FancyEqMixin, FancyStrMixin, object): - """ - A wrapper around L{dns.Message} which is comparable so that it can be tested - using some of the L{dns._EDNSMessage} tests. - """ - showAttributes = compareAttributes = ( - 'id', 'answer', 'opCode', 'auth', 'trunc', - 'recDes', 'recAv', 'rCode', - 'queries', 'answers', 'authority', 'additional') - - def __init__(self, original): - self.original = original - - - def __getattr__(self, key): - return getattr(self.original, key) - - - -def verifyConstructorArgument(testCase, cls, argName, defaultVal, altVal, - attrName=None): - """ - Verify that an attribute has the expected default value and that a - corresponding argument passed to a constructor is assigned to that - attribute. - - @param testCase: The L{TestCase} whose assert methods will be - called. - @type testCase: L{unittest.TestCase} - - @param cls: The constructor under test. - @type cls: L{type} - - @param argName: The name of the constructor argument under test. - @type argName: L{str} - - @param defaultVal: The expected default value of C{attrName} / - C{argName} - @type defaultVal: L{object} - - @param altVal: A value which is different from the default. Used to - test that supplied constructor arguments are actually assigned to the - correct attribute. - @type altVal: L{object} - - @param attrName: The name of the attribute under test if different - from C{argName}. Defaults to C{argName} - @type attrName: L{str} - """ - if attrName is None: - attrName = argName - - actual = {} - expected = {'defaultVal': defaultVal, 'altVal': altVal} - - o = cls() - actual['defaultVal'] = getattr(o, attrName) - - o = cls(**{argName: altVal}) - actual['altVal'] = getattr(o, attrName) - - testCase.assertEqual(expected, actual) - - - -class ConstructorTestsMixin(object): - """ - Helper methods for verifying default attribute values and corresponding - constructor arguments. - """ - def _verifyConstructorArgument(self, argName, defaultVal, altVal): - """ - Wrap L{verifyConstructorArgument} to provide simpler interface for - testing Message and _EDNSMessage constructor arguments. - - @param argName: The name of the constructor argument. - @param defaultVal: The expected default value. - @param altVal: An alternative value which is expected to be assigned to - a correspondingly named attribute. - """ - verifyConstructorArgument(testCase=self, cls=self.messageFactory, - argName=argName, defaultVal=defaultVal, - altVal=altVal) - - - def _verifyConstructorFlag(self, argName, defaultVal): - """ - Wrap L{verifyConstructorArgument} to provide simpler interface for - testing _EDNSMessage constructor flags. - - @param argName: The name of the constructor flag argument - @param defaultVal: The expected default value of the flag - """ - assert defaultVal in (True, False) - verifyConstructorArgument(testCase=self, cls=self.messageFactory, - argName=argName, defaultVal=defaultVal, - altVal=not defaultVal,) - - - -class CommonConstructorTestsMixin(object): - """ - Tests for constructor arguments and their associated attributes that are - common to both L{twisted.names.dns._EDNSMessage} and L{dns.Message}. - - TestCase classes that use this mixin must provide a C{messageFactory} method - which accepts any argment supported by L{dns.Message.__init__}. - - TestCases must also mixin ConstructorTestsMixin which provides some custom - assertions for testing constructor arguments. - """ - def test_id(self): - """ - L{dns._EDNSMessage.id} defaults to C{0} and can be overridden in - the constructor. - """ - self._verifyConstructorArgument('id', defaultVal=0, altVal=1) - - - def test_answer(self): - """ - L{dns._EDNSMessage.answer} defaults to C{False} and can be overridden in - the constructor. - """ - self._verifyConstructorFlag('answer', defaultVal=False) - - - def test_opCode(self): - """ - L{dns._EDNSMessage.opCode} defaults to L{dns.OP_QUERY} and can be - overridden in the constructor. - """ - self._verifyConstructorArgument( - 'opCode', defaultVal=dns.OP_QUERY, altVal=dns.OP_STATUS) - - - def test_auth(self): - """ - L{dns._EDNSMessage.auth} defaults to C{False} and can be overridden in - the constructor. - """ - self._verifyConstructorFlag('auth', defaultVal=False) - - - def test_trunc(self): - """ - L{dns._EDNSMessage.trunc} defaults to C{False} and can be overridden in - the constructor. - """ - self._verifyConstructorFlag('trunc', defaultVal=False) - - - def test_recDes(self): - """ - L{dns._EDNSMessage.recDes} defaults to C{False} and can be overridden in - the constructor. - """ - self._verifyConstructorFlag('recDes', defaultVal=False) - - - def test_recAv(self): - """ - L{dns._EDNSMessage.recAv} defaults to C{False} and can be overridden in - the constructor. - """ - self._verifyConstructorFlag('recAv', defaultVal=False) - - - def test_rCode(self): - """ - L{dns._EDNSMessage.rCode} defaults to C{0} and can be overridden in the - constructor. - """ - self._verifyConstructorArgument('rCode', defaultVal=0, altVal=123) - - - def test_maxSize(self): - """ - L{dns._EDNSMessage.maxSize} defaults to C{512} and can be overridden in - the constructor. - """ - self._verifyConstructorArgument('maxSize', defaultVal=512, altVal=1024) - - - def test_queries(self): - """ - L{dns._EDNSMessage.queries} defaults to C{[]}. - """ - self.assertEqual(self.messageFactory().queries, []) - - - def test_answers(self): - """ - L{dns._EDNSMessage.answers} defaults to C{[]}. - """ - self.assertEqual(self.messageFactory().answers, []) - - - def test_authority(self): - """ - L{dns._EDNSMessage.authority} defaults to C{[]}. - """ - self.assertEqual(self.messageFactory().authority, []) - - - def test_additional(self): - """ - L{dns._EDNSMessage.additional} defaults to C{[]}. - """ - self.assertEqual(self.messageFactory().additional, []) - - - -class EDNSMessageConstructorTests(ConstructorTestsMixin, - CommonConstructorTestsMixin, - unittest.SynchronousTestCase): - """ - Tests for L{twisted.names.dns._EDNSMessage} constructor arguments that are - shared with L{dns.Message}. - """ - messageFactory = dns._EDNSMessage - - - -class MessageConstructorTests(ConstructorTestsMixin, - CommonConstructorTestsMixin, - unittest.SynchronousTestCase): - """ - Tests for L{twisted.names.dns.Message} constructor arguments that are shared - with L{dns._EDNSMessage}. - """ - messageFactory = dns.Message - - - -class EDNSMessageSpecificsTests(ConstructorTestsMixin, - unittest.SynchronousTestCase): - """ - Tests for L{dns._EDNSMessage}. - - These tests are for L{dns._EDNSMessage} APIs which are not shared with - L{dns.Message}. - """ - messageFactory = dns._EDNSMessage - - def test_ednsVersion(self): - """ - L{dns._EDNSMessage.ednsVersion} defaults to C{0} and can be overridden - in the constructor. - """ - self._verifyConstructorArgument( - 'ednsVersion', defaultVal=0, altVal=None) - - - def test_dnssecOK(self): - """ - L{dns._EDNSMessage.dnssecOK} defaults to C{False} and can be overridden - in the constructor. - """ - self._verifyConstructorFlag('dnssecOK', defaultVal=False) - - - def test_authenticData(self): - """ - L{dns._EDNSMessage.authenticData} defaults to C{False} and can be - overridden in the constructor. - """ - self._verifyConstructorFlag('authenticData', defaultVal=False) - - - def test_checkingDisabled(self): - """ - L{dns._EDNSMessage.checkingDisabled} defaults to C{False} and can be - overridden in the constructor. - """ - self._verifyConstructorFlag('checkingDisabled', defaultVal=False) - - - def test_queriesOverride(self): - """ - L{dns._EDNSMessage.queries} can be overridden in the constructor. - """ - msg = self.messageFactory(queries=[dns.Query(b'example.com')]) - - self.assertEqual( - msg.queries, - [dns.Query(b'example.com')]) - - - def test_answersOverride(self): - """ - L{dns._EDNSMessage.answers} can be overridden in the constructor. - """ - msg = self.messageFactory( - answers=[ - dns.RRHeader( - b'example.com', - payload=dns.Record_A('1.2.3.4'))]) - - self.assertEqual( - msg.answers, - [dns.RRHeader(b'example.com', payload=dns.Record_A('1.2.3.4'))]) - - - def test_authorityOverride(self): - """ - L{dns._EDNSMessage.authority} can be overridden in the constructor. - """ - msg = self.messageFactory( - authority=[ - dns.RRHeader( - b'example.com', - type=dns.SOA, - payload=dns.Record_SOA())]) - - self.assertEqual( - msg.authority, - [dns.RRHeader(b'example.com', type=dns.SOA, - payload=dns.Record_SOA())]) - - - def test_additionalOverride(self): - """ - L{dns._EDNSMessage.authority} can be overridden in the constructor. - """ - msg = self.messageFactory( - additional=[ - dns.RRHeader( - b'example.com', - payload=dns.Record_A('1.2.3.4'))]) - - self.assertEqual( - msg.additional, - [dns.RRHeader(b'example.com', payload=dns.Record_A('1.2.3.4'))]) - - - def test_reprDefaults(self): - """ - L{dns._EDNSMessage.__repr__} omits field values and sections which are - identical to their defaults. The id field value is always shown. - """ - self.assertEqual( - '<_EDNSMessage id=0>', - repr(self.messageFactory()) - ) - - - def test_reprFlagsIfSet(self): - """ - L{dns._EDNSMessage.__repr__} displays flags if they are L{True}. - """ - m = self.messageFactory(answer=True, auth=True, trunc=True, recDes=True, - recAv=True, authenticData=True, - checkingDisabled=True, dnssecOK=True) - self.assertEqual( - '<_EDNSMessage ' - 'id=0 ' - 'flags=answer,auth,trunc,recDes,recAv,authenticData,' - 'checkingDisabled,dnssecOK' - '>', - repr(m), - ) - - - def test_reprNonDefautFields(self): - """ - L{dns._EDNSMessage.__repr__} displays field values if they differ from - their defaults. - """ - m = self.messageFactory(id=10, opCode=20, rCode=30, maxSize=40, - ednsVersion=50) - self.assertEqual( - '<_EDNSMessage ' - 'id=10 ' - 'opCode=20 ' - 'rCode=30 ' - 'maxSize=40 ' - 'ednsVersion=50' - '>', - repr(m), - ) - - - def test_reprNonDefaultSections(self): - """ - L{dns.Message.__repr__} displays sections which differ from their - defaults. - """ - m = self.messageFactory() - m.queries = [1, 2, 3] - m.answers = [4, 5, 6] - m.authority = [7, 8, 9] - m.additional = [10, 11, 12] - self.assertEqual( - '<_EDNSMessage ' - 'id=0 ' - 'queries=[1, 2, 3] ' - 'answers=[4, 5, 6] ' - 'authority=[7, 8, 9] ' - 'additional=[10, 11, 12]' - '>', - repr(m), - ) - - - def test_fromStrCallsMessageFactory(self): - """ - L{dns._EDNSMessage.fromString} calls L{dns._EDNSMessage._messageFactory} - to create a new L{dns.Message} instance which is used to decode the - supplied bytes. - """ - class FakeMessageFactory(object): - """ - Fake message factory. - """ - def fromStr(self, *args, **kwargs): - """ - Fake fromStr method which raises the arguments it was passed. - - @param args: positional arguments - @param kwargs: keyword arguments - """ - raise RaisedArgs(args, kwargs) - - m = dns._EDNSMessage() - m._messageFactory = FakeMessageFactory - dummyBytes = object() - e = self.assertRaises(RaisedArgs, m.fromStr, dummyBytes) - self.assertEqual( - ((dummyBytes,), {}), - (e.args, e.kwargs) - ) - - - def test_fromStrCallsFromMessage(self): - """ - L{dns._EDNSMessage.fromString} calls L{dns._EDNSMessage._fromMessage} - with a L{dns.Message} instance - """ - m = dns._EDNSMessage() - class FakeMessageFactory(): - """ - Fake message factory. - """ - def fromStr(self, bytes): - """ - A noop fake version of fromStr - - @param bytes: the bytes to be decoded - """ - - fakeMessage = FakeMessageFactory() - m._messageFactory = lambda: fakeMessage - - def fakeFromMessage(*args, **kwargs): - raise RaisedArgs(args, kwargs) - m._fromMessage = fakeFromMessage - e = self.assertRaises(RaisedArgs, m.fromStr, b'') - self.assertEqual( - ((fakeMessage,), {}), - (e.args, e.kwargs) - ) - - - def test_toStrCallsToMessage(self): - """ - L{dns._EDNSMessage.toStr} calls L{dns._EDNSMessage._toMessage} - """ - m = dns._EDNSMessage() - def fakeToMessage(*args, **kwargs): - raise RaisedArgs(args, kwargs) - m._toMessage = fakeToMessage - e = self.assertRaises(RaisedArgs, m.toStr) - self.assertEqual( - ((), {}), - (e.args, e.kwargs) - ) - - - def test_toStrCallsToMessageToStr(self): - """ - L{dns._EDNSMessage.toStr} calls C{toStr} on the message returned by - L{dns._EDNSMessage._toMessage}. - """ - m = dns._EDNSMessage() - dummyBytes = object() - class FakeMessage(object): - """ - Fake Message - """ - def toStr(self): - """ - Fake toStr which returns dummyBytes. - - @return: dummyBytes - """ - return dummyBytes - - def fakeToMessage(*args, **kwargs): - return FakeMessage() - m._toMessage = fakeToMessage - - self.assertEqual( - dummyBytes, - m.toStr() - ) - - - -class EDNSMessageEqualityTests(ComparisonTestsMixin, unittest.SynchronousTestCase): - """ - Tests for equality between L(dns._EDNSMessage} instances. - - These tests will not work with L{dns.Message} because it does not use - L{twisted.python.util.FancyEqMixin}. - """ - - messageFactory = dns._EDNSMessage - - def test_id(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - id. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(id=1), - self.messageFactory(id=1), - self.messageFactory(id=2), - ) - - - def test_answer(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - answer flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(answer=True), - self.messageFactory(answer=True), - self.messageFactory(answer=False), - ) - - - def test_opCode(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - opCode. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(opCode=dns.OP_STATUS), - self.messageFactory(opCode=dns.OP_STATUS), - self.messageFactory(opCode=dns.OP_INVERSE), - ) - - - def test_auth(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - auth flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(auth=True), - self.messageFactory(auth=True), - self.messageFactory(auth=False), - ) - - - def test_trunc(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - trunc flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(trunc=True), - self.messageFactory(trunc=True), - self.messageFactory(trunc=False), - ) - - - def test_recDes(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - recDes flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(recDes=True), - self.messageFactory(recDes=True), - self.messageFactory(recDes=False), - ) - - - def test_recAv(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - recAv flag. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(recAv=True), - self.messageFactory(recAv=True), - self.messageFactory(recAv=False), - ) - - - def test_rCode(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - rCode. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(rCode=16), - self.messageFactory(rCode=16), - self.messageFactory(rCode=15), - ) - - - def test_ednsVersion(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - ednsVersion. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(ednsVersion=1), - self.messageFactory(ednsVersion=1), - self.messageFactory(ednsVersion=None), - ) - - - def test_dnssecOK(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - dnssecOK. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(dnssecOK=True), - self.messageFactory(dnssecOK=True), - self.messageFactory(dnssecOK=False), - ) - - - def test_authenticData(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - authenticData flags. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(authenticData=True), - self.messageFactory(authenticData=True), - self.messageFactory(authenticData=False), - ) - - - def test_checkingDisabled(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - checkingDisabled flags. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(checkingDisabled=True), - self.messageFactory(checkingDisabled=True), - self.messageFactory(checkingDisabled=False), - ) - - - def test_maxSize(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - maxSize. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(maxSize=2048), - self.messageFactory(maxSize=2048), - self.messageFactory(maxSize=1024), - ) - - - def test_queries(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - queries. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(queries=[dns.Query(b'example.com')]), - self.messageFactory(queries=[dns.Query(b'example.com')]), - self.messageFactory(queries=[dns.Query(b'example.org')]), - ) - - - def test_answers(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - answers. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(answers=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(answers=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(answers=[dns.RRHeader( - b'example.org', payload=dns.Record_A('4.3.2.1'))]), - ) - - - def test_authority(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - authority records. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(authority=[dns.RRHeader( - b'example.com', - type=dns.SOA, payload=dns.Record_SOA())]), - self.messageFactory(authority=[dns.RRHeader( - b'example.com', - type=dns.SOA, payload=dns.Record_SOA())]), - self.messageFactory(authority=[dns.RRHeader( - b'example.org', - type=dns.SOA, payload=dns.Record_SOA())]), - ) - - - def test_additional(self): - """ - Two L{dns._EDNSMessage} instances compare equal if they have the same - additional records. - """ - self.assertNormalEqualityImplementation( - self.messageFactory(additional=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(additional=[dns.RRHeader( - b'example.com', payload=dns.Record_A('1.2.3.4'))]), - self.messageFactory(additional=[dns.RRHeader( - b'example.org', payload=dns.Record_A('1.2.3.4'))]), - ) - - - -class StandardEncodingTestsMixin(object): - """ - Tests for the encoding and decoding of various standard (not EDNS) messages. - - These tests should work with both L{dns._EDNSMessage} and L{dns.Message}. - - TestCase classes that use this mixin must provide a C{messageFactory} method - which accepts any argment supported by L{dns._EDNSMessage.__init__}. - - EDNS specific arguments may be discarded if not supported by the message - class under construction. - """ - def test_emptyMessageEncode(self): - """ - An empty message can be encoded. - """ - self.assertEqual( - self.messageFactory(**MessageEmpty.kwargs()).toStr(), - MessageEmpty.bytes()) - - - def test_emptyMessageDecode(self): - """ - An empty message byte sequence can be decoded. - """ - m = self.messageFactory() - m.fromStr(MessageEmpty.bytes()) - - self.assertEqual(m, self.messageFactory(**MessageEmpty.kwargs())) - - - def test_completeQueryEncode(self): - """ - A fully populated query message can be encoded. - """ - self.assertEqual( - self.messageFactory(**MessageComplete.kwargs()).toStr(), - MessageComplete.bytes()) - - - def test_completeQueryDecode(self): - """ - A fully populated message byte string can be decoded. - """ - m = self.messageFactory() - m.fromStr(MessageComplete.bytes()), - - self.assertEqual(m, self.messageFactory(**MessageComplete.kwargs())) - - - def test_NULL(self): - """ - A I{NULL} record with an arbitrary payload can be encoded and decoded as - part of a message. - """ - bytes = b''.join([dns._ord2bytes(i) for i in range(256)]) - rec = dns.Record_NULL(bytes) - rr = dns.RRHeader(b'testname', dns.NULL, payload=rec) - msg1 = self.messageFactory() - msg1.answers.append(rr) - s = msg1.toStr() - - msg2 = self.messageFactory() - msg2.fromStr(s) - - self.assertIsInstance(msg2.answers[0].payload, dns.Record_NULL) - self.assertEqual(msg2.answers[0].payload.payload, bytes) - - - def test_nonAuthoritativeMessageEncode(self): - """ - If the message C{authoritative} attribute is set to 0, the encoded bytes - will have AA bit 0. - """ - self.assertEqual( - self.messageFactory(**MessageNonAuthoritative.kwargs()).toStr(), - MessageNonAuthoritative.bytes()) - - - def test_nonAuthoritativeMessageDecode(self): - """ - The L{dns.RRHeader} instances created by a message from a - non-authoritative message byte string are marked as not authoritative. - """ - m = self.messageFactory() - m.fromStr(MessageNonAuthoritative.bytes()) - - self.assertEqual( - m, self.messageFactory(**MessageNonAuthoritative.kwargs())) - - - def test_authoritativeMessageEncode(self): - """ - If the message C{authoritative} attribute is set to 1, the encoded bytes - will have AA bit 1. - """ - self.assertEqual( - self.messageFactory(**MessageAuthoritative.kwargs()).toStr(), - MessageAuthoritative.bytes()) - - - def test_authoritativeMessageDecode(self): - """ - The message and its L{dns.RRHeader} instances created by C{decode} from - an authoritative message byte string, are marked as authoritative. - """ - m = self.messageFactory() - m.fromStr(MessageAuthoritative.bytes()) - - self.assertEqual( - m, self.messageFactory(**MessageAuthoritative.kwargs())) - - - def test_truncatedMessageEncode(self): - """ - If the message C{trunc} attribute is set to 1 the encoded bytes will - have TR bit 1. - """ - self.assertEqual( - self.messageFactory(**MessageTruncated.kwargs()).toStr(), - MessageTruncated.bytes()) - - - def test_truncatedMessageDecode(self): - """ - The message instance created by decoding a truncated message is marked - as truncated. - """ - m = self.messageFactory() - m.fromStr(MessageTruncated.bytes()) - - self.assertEqual(m, self.messageFactory(**MessageTruncated.kwargs())) - - - -class EDNSMessageStandardEncodingTests(StandardEncodingTestsMixin, - unittest.SynchronousTestCase): - """ - Tests for the encoding and decoding of various standard (non-EDNS) messages - by L{dns._EDNSMessage}. - """ - messageFactory = dns._EDNSMessage - - - -class MessageStandardEncodingTests(StandardEncodingTestsMixin, - unittest.SynchronousTestCase): - """ - Tests for the encoding and decoding of various standard (non-EDNS) messages - by L{dns.Message}. - """ - @staticmethod - def messageFactory(**kwargs): - """ - This function adapts constructor arguments expected by - _EDNSMessage.__init__ to arguments suitable for use with the - Message.__init__. - - Also handles the fact that unlike L{dns._EDNSMessage}, - L{dns.Message.__init__} does not accept queries, answers etc as - arguments. - - Also removes any L{dns._EDNSMessage} specific arguments. - - @param args: The positional arguments which will be passed to - L{dns.Message.__init__}. - - @param kwargs: The keyword arguments which will be stripped of EDNS - specific arguments before being passed to L{dns.Message.__init__}. - - @return: An L{dns.Message} instance. - """ - queries = kwargs.pop('queries', []) - answers = kwargs.pop('answers', []) - authority = kwargs.pop('authority', []) - additional = kwargs.pop('additional', []) - - kwargs.pop('ednsVersion', None) - - m = dns.Message(**kwargs) - m.queries = queries - m.answers = answers - m.authority = authority - m.additional = additional - return MessageComparable(m) - - - -class EDNSMessageEDNSEncodingTests(unittest.SynchronousTestCase): - """ - Tests for the encoding and decoding of various EDNS messages. - - These test will not work with L{dns.Message}. - """ - messageFactory = dns._EDNSMessage - - def test_ednsMessageDecodeStripsOptRecords(self): - """ - The L(_EDNSMessage} instance created by L{dns._EDNSMessage.decode} from - an EDNS query never includes OPT records in the additional section. - """ - m = self.messageFactory() - m.fromStr(MessageEDNSQuery.bytes()) - - self.assertEqual(m.additional, []) - - - def test_ednsMessageDecodeMultipleOptRecords(self): - """ - An L(_EDNSMessage} instance created from a byte string containing - multiple I{OPT} records will discard all the C{OPT} records. - - C{ednsVersion} will be set to C{None}. - - @see: U{https://tools.ietf.org/html/rfc6891#section-6.1.1} - """ - m = dns.Message() - m.additional = [ - dns._OPTHeader(version=2), - dns._OPTHeader(version=3)] - - ednsMessage = dns._EDNSMessage() - ednsMessage.fromStr(m.toStr()) - - self.assertEqual(ednsMessage.ednsVersion, None) - - - def test_fromMessageCopiesSections(self): - """ - L{dns._EDNSMessage._fromMessage} returns an L{_EDNSMessage} instance - whose queries, answers, authority and additional lists are copies (not - references to) the original message lists. - """ - standardMessage = dns.Message() - standardMessage.fromStr(MessageEDNSQuery.bytes()) - - ednsMessage = dns._EDNSMessage._fromMessage(standardMessage) - - duplicates = [] - for attrName in ('queries', 'answers', 'authority', 'additional'): - if (getattr(standardMessage, attrName) - is getattr(ednsMessage, attrName)): - duplicates.append(attrName) - - if duplicates: - self.fail( - 'Message and _EDNSMessage shared references to the following ' - 'section lists after decoding: %s' % (duplicates,)) - - - def test_toMessageCopiesSections(self): - """ - L{dns._EDNSMessage.toStr} makes no in place changes to the message - instance. - """ - ednsMessage = dns._EDNSMessage(ednsVersion=1) - ednsMessage.toStr() - self.assertEqual(ednsMessage.additional, []) - - - def test_optHeaderPosition(self): - """ - L{dns._EDNSMessage} can decode OPT records, regardless of their position - in the additional records section. - - "The OPT RR MAY be placed anywhere within the additional data section." - - @see: U{https://tools.ietf.org/html/rfc6891#section-6.1.1} - """ - # XXX: We need an _OPTHeader.toRRHeader method. See #6779. - b = BytesIO() - optRecord = dns._OPTHeader(version=1) - optRecord.encode(b) - optRRHeader = dns.RRHeader() - b.seek(0) - optRRHeader.decode(b) - m = dns.Message() - m.additional = [optRRHeader] - - actualMessages = [] - actualMessages.append(dns._EDNSMessage._fromMessage(m).ednsVersion) - - m.additional.append(dns.RRHeader(type=dns.A)) - actualMessages.append( - dns._EDNSMessage._fromMessage(m).ednsVersion) - - m.additional.insert(0, dns.RRHeader(type=dns.A)) - actualMessages.append( - dns._EDNSMessage._fromMessage(m).ednsVersion) - - self.assertEqual( - [1] * 3, - actualMessages - ) - - - def test_ednsDecode(self): - """ - The L(_EDNSMessage} instance created by L{dns._EDNSMessage.fromStr} - derives its edns specific values (C{ednsVersion}, etc) from the supplied - OPT record. - """ - m = self.messageFactory() - m.fromStr(MessageEDNSComplete.bytes()) - - self.assertEqual(m, self.messageFactory(**MessageEDNSComplete.kwargs())) - - - def test_ednsEncode(self): - """ - The L(_EDNSMessage} instance created by L{dns._EDNSMessage.toStr} - encodes its edns specific values (C{ednsVersion}, etc) into an OPT - record added to the additional section. - """ - self.assertEqual( - self.messageFactory(**MessageEDNSComplete.kwargs()).toStr(), - MessageEDNSComplete.bytes()) - - - def test_extendedRcodeEncode(self): - """ - The L(_EDNSMessage.toStr} encodes the extended I{RCODE} (>=16) by - assigning the lower 4bits to the message RCODE field and the upper 4bits - to the OPT pseudo record. - """ - self.assertEqual( - self.messageFactory(**MessageEDNSExtendedRCODE.kwargs()).toStr(), - MessageEDNSExtendedRCODE.bytes()) - - - def test_extendedRcodeDecode(self): - """ - The L(_EDNSMessage} instance created by L{dns._EDNSMessage.fromStr} - derives RCODE from the supplied OPT record. - """ - m = self.messageFactory() - m.fromStr(MessageEDNSExtendedRCODE.bytes()) - - self.assertEqual( - m, self.messageFactory(**MessageEDNSExtendedRCODE.kwargs())) - - - def test_extendedRcodeZero(self): - """ - Note that EXTENDED-RCODE value 0 indicates that an unextended RCODE is - in use (values 0 through 15). - - https://tools.ietf.org/html/rfc6891#section-6.1.3 - """ - ednsMessage = self.messageFactory(rCode=15, ednsVersion=0) - standardMessage = ednsMessage._toMessage() - - self.assertEqual( - (15, 0), - (standardMessage.rCode, standardMessage.additional[0].extendedRCODE) - ) - - - -class ResponseFromMessageTests(unittest.SynchronousTestCase): - """ - Tests for L{dns._responseFromMessage}. - """ - def test_responseFromMessageResponseType(self): - """ - L{dns.Message._responseFromMessage} is a constructor function which - generates a new I{answer} message from an existing L{dns.Message} like - instance. - """ - request = dns.Message() - response = dns._responseFromMessage(responseConstructor=dns.Message, - message=request) - self.assertIsNot(request, response) - - - def test_responseType(self): - """ - L{dns._responseFromMessage} returns a new instance of C{cls} - """ - class SuppliedClass(object): - id = 1 - queries = [] - - expectedClass = dns.Message - - self.assertIsInstance( - dns._responseFromMessage(responseConstructor=expectedClass, - message=SuppliedClass()), - expectedClass - ) - - - def test_responseId(self): - """ - L{dns._responseFromMessage} copies the C{id} attribute of the original - message. - """ - self.assertEqual( - 1234, - dns._responseFromMessage(responseConstructor=dns.Message, - message=dns.Message(id=1234)).id - ) - - - def test_responseAnswer(self): - """ - L{dns._responseFromMessage} sets the C{answer} flag to L{True} - """ - request = dns.Message() - response = dns._responseFromMessage(responseConstructor=dns.Message, - message=request) - self.assertEqual( - (False, True), - (request.answer, response.answer) - ) - - - def test_responseQueries(self): - """ - L{dns._responseFromMessage} copies the C{queries} attribute of the - original message. - """ - request = dns.Message() - expectedQueries = [object(), object(), object()] - request.queries = expectedQueries[:] - - self.assertEqual( - expectedQueries, - dns._responseFromMessage(responseConstructor=dns.Message, - message=request).queries - ) - - - def test_responseKwargs(self): - """ - L{dns._responseFromMessage} accepts other C{kwargs} which are assigned - to the new message before it is returned. - """ - self.assertEqual( - 123, - dns._responseFromMessage( - responseConstructor=dns.Message, message=dns.Message(), - rCode=123).rCode - ) - - - -class Foo(object): - """ - An example class for use in L{dns._compactRepr} tests. - It follows the pattern of initialiser settable flags, fields and sections - found in L{dns.Message} and L{dns._EDNSMessage}. - """ - def __init__(self, - field1=1, field2=2, alwaysShowField='AS', - flagTrue=True, flagFalse=False, section1=None): - """ - Set some flags, fields and sections as public attributes. - """ - self.field1 = field1 - self.field2 = field2 - self.alwaysShowField = alwaysShowField - self.flagTrue = flagTrue - self.flagFalse = flagFalse - - if section1 is None: - section1 = [] - self.section1 = section1 - - - def __repr__(self): - """ - Call L{dns._compactRepr} to generate a string representation. - """ - return dns._compactRepr( - self, - alwaysShow='alwaysShowField'.split(), - fieldNames='field1 field2 alwaysShowField'.split(), - flagNames='flagTrue flagFalse'.split(), - sectionNames='section1 section2'.split() - ) - - - -class CompactReprTests(unittest.SynchronousTestCase): - """ - Tests for L[dns._compactRepr}. - """ - messageFactory = Foo - def test_defaults(self): - """ - L{dns._compactRepr} omits field values and sections which have the - default value. Flags which are True are always shown. - """ - self.assertEqual( - "", - repr(self.messageFactory()) - ) - - - def test_flagsIfSet(self): - """ - L{dns._compactRepr} displays flags if they have a non-default value. - """ - m = self.messageFactory(flagTrue=True, flagFalse=True) - self.assertEqual( - '', - repr(m), - ) - - - def test_nonDefautFields(self): - """ - L{dns._compactRepr} displays field values if they differ from their - defaults. - """ - m = self.messageFactory(field1=10, field2=20) - self.assertEqual( - '', - repr(m), - ) - - - def test_nonDefaultSections(self): - """ - L{dns._compactRepr} displays sections which differ from their defaults. - """ - m = self.messageFactory() - m.section1 = [1, 1, 1] - m.section2 = [2, 2, 2] - self.assertEqual( - '', - repr(m), - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_examples.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_examples.py deleted file mode 100644 index 067eb70..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_examples.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.names} example scripts. -""" - -import sys -from StringIO import StringIO - -from twisted.python.filepath import FilePath -from twisted.trial.unittest import SkipTest, TestCase - - - -class ExampleTestBase(object): - """ - This is a mixin which adds an example to the path, tests it, and then - removes it from the path and unimports the modules which the test loaded. - Test cases which test example code and documentation listings should use - this. - - This is done this way so that examples can live in isolated path entries, - next to the documentation, replete with their own plugin packages and - whatever other metadata they need. Also, example code is a rare instance - of it being valid to have multiple versions of the same code in the - repository at once, rather than relying on version control, because - documentation will often show the progression of a single piece of code as - features are added to it, and we want to test each one. - """ - - def setUp(self): - """ - Add our example directory to the path and record which modules are - currently loaded. - """ - self.originalPath = sys.path[:] - self.originalModules = sys.modules.copy() - - self.fakeErr = StringIO() - self.patch(sys, 'stderr', self.fakeErr) - self.fakeOut = StringIO() - self.patch(sys, 'stdout', self.fakeOut) - - # Get documentation root - here = ( - FilePath(__file__) - .parent().parent().parent().parent() - .child('docs') - ) - - # Find the example script within this branch - for childName in self.exampleRelativePath.split('/'): - here = here.child(childName) - if not here.exists(): - raise SkipTest( - "Examples (%s) not found - cannot test" % (here.path,)) - self.examplePath = here - - # Add the example parent folder to the Python path - sys.path.append(self.examplePath.parent().path) - - # Import the example as a module - moduleName = self.examplePath.basename().split('.')[0] - self.example = __import__(moduleName) - - - def tearDown(self): - """ - Remove the example directory from the path and remove all - modules loaded by the test from sys.modules. - """ - sys.modules.clear() - sys.modules.update(self.originalModules) - sys.path[:] = self.originalPath - - - def test_shebang(self): - """ - The example scripts start with the standard shebang line. - """ - self.assertEqual( - self.examplePath.open().readline().rstrip(), - '#!/usr/bin/env python') - - - def test_usageConsistency(self): - """ - The example script prints a usage message to stdout if it is - passed a --help option and then exits. - - The first line should contain a USAGE summary, explaining the - accepted command arguments. - """ - # Pass None as first parameter - the reactor - it shouldn't - # get as far as calling it. - self.assertRaises( - SystemExit, self.example.main, None, '--help') - - out = self.fakeOut.getvalue().splitlines() - self.assertTrue( - out[0].startswith('Usage:'), - 'Usage message first line should start with "Usage:". ' - 'Actual: %r' % (out[0],)) - - - def test_usageConsistencyOnError(self): - """ - The example script prints a usage message to stderr if it is - passed unrecognized command line arguments. - - The first line should contain a USAGE summary, explaining the - accepted command arguments. - - The last line should contain an ERROR summary, explaining that - incorrect arguments were supplied. - """ - # Pass None as first parameter - the reactor - it shouldn't - # get as far as calling it. - self.assertRaises( - SystemExit, self.example.main, None, '--unexpected_argument') - - err = self.fakeErr.getvalue().splitlines() - self.assertTrue( - err[0].startswith('Usage:'), - 'Usage message first line should start with "Usage:". ' - 'Actual: %r' % (err[0],)) - self.assertTrue( - err[-1].startswith('ERROR:'), - 'Usage message last line should start with "ERROR:" ' - 'Actual: %r' % (err[-1],)) - - - -class TestDnsTests(ExampleTestBase, TestCase): - """ - Test the testdns.py example script. - """ - - exampleRelativePath = 'names/examples/testdns.py' - - - -class GetHostByNameTests(ExampleTestBase, TestCase): - """ - Test the gethostbyname.py example script. - """ - - exampleRelativePath = 'names/examples/gethostbyname.py' - - - -class DnsServiceTests(ExampleTestBase, TestCase): - """ - Test the dns-service.py example script. - """ - - exampleRelativePath = 'names/examples/dns-service.py' - - - -class MultiReverseLookupTests(ExampleTestBase, TestCase): - """ - Test the multi_reverse_lookup.py example script. - """ - - exampleRelativePath = 'names/examples/multi_reverse_lookup.py' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_hosts.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_hosts.py deleted file mode 100644 index daf7863..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_hosts.py +++ /dev/null @@ -1,257 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for the I{hosts(5)}-based resolver, L{twisted.names.hosts}. -""" - -from __future__ import division, absolute_import - -from twisted.trial.unittest import TestCase -from twisted.python.filepath import FilePath -from twisted.internet.defer import gatherResults - -from twisted.names.dns import ( - A, AAAA, IN, DomainError, RRHeader, Query, Record_A, Record_AAAA) -from twisted.names.hosts import Resolver, searchFileFor, searchFileForAll - - -class GoodTempPathMixin(object): - def path(self): - return FilePath(self.mktemp().encode('utf-8')) - - - -class SearchHostsFileTests(TestCase, GoodTempPathMixin): - """ - Tests for L{searchFileFor}, a helper which finds the first address for a - particular hostname in a I{hosts(5)}-style file. - """ - def test_findAddress(self): - """ - If there is an IPv4 address for the hostname passed to L{searchFileFor}, - it is returned. - """ - hosts = self.path() - hosts.setContent( - b"10.2.3.4 foo.example.com\n") - self.assertEqual( - "10.2.3.4", searchFileFor(hosts.path, b"foo.example.com")) - - - def test_notFoundAddress(self): - """ - If there is no address information for the hostname passed to - L{searchFileFor}, C{None} is returned. - """ - hosts = self.path() - hosts.setContent( - b"10.2.3.4 foo.example.com\n") - self.assertIs(None, searchFileFor(hosts.path, b"bar.example.com")) - - - def test_firstAddress(self): - """ - The first address associated with the given hostname is returned. - """ - hosts = self.path() - hosts.setContent( - b"::1 foo.example.com\n" - b"10.1.2.3 foo.example.com\n" - b"fe80::21b:fcff:feee:5a1d foo.example.com\n") - self.assertEqual("::1", searchFileFor(hosts.path, b"foo.example.com")) - - - def test_searchFileForAliases(self): - """ - For a host with a canonical name and one or more aliases, - L{searchFileFor} can find an address given any of the names. - """ - hosts = self.path() - hosts.setContent( - b"127.0.1.1\thelmut.example.org\thelmut\n" - b"# a comment\n" - b"::1 localhost ip6-localhost ip6-loopback\n") - self.assertEqual(searchFileFor(hosts.path, b'helmut'), '127.0.1.1') - self.assertEqual( - searchFileFor(hosts.path, b'helmut.example.org'), '127.0.1.1') - self.assertEqual(searchFileFor(hosts.path, b'ip6-localhost'), '::1') - self.assertEqual(searchFileFor(hosts.path, b'ip6-loopback'), '::1') - self.assertEqual(searchFileFor(hosts.path, b'localhost'), '::1') - - - -class SearchHostsFileForAllTests(TestCase, GoodTempPathMixin): - """ - Tests for L{searchFileForAll}, a helper which finds all addresses for a - particular hostname in a I{hosts(5)}-style file. - """ - def test_allAddresses(self): - """ - L{searchFileForAll} returns a list of all addresses associated with the - name passed to it. - """ - hosts = self.path() - hosts.setContent( - b"127.0.0.1 foobar.example.com\n" - b"127.0.0.2 foobar.example.com\n" - b"::1 foobar.example.com\n") - self.assertEqual( - ["127.0.0.1", "127.0.0.2", "::1"], - searchFileForAll(hosts, b"foobar.example.com")) - - - def test_caseInsensitively(self): - """ - L{searchFileForAll} searches for names case-insensitively. - """ - hosts = self.path() - hosts.setContent(b"127.0.0.1 foobar.EXAMPLE.com\n") - self.assertEqual( - ["127.0.0.1"], searchFileForAll(hosts, b"FOOBAR.example.com")) - - - def test_readError(self): - """ - If there is an error reading the contents of the hosts file, - L{searchFileForAll} returns an empty list. - """ - self.assertEqual( - [], searchFileForAll(self.path(), b"example.com")) - - - -class HostsTests(TestCase, GoodTempPathMixin): - """ - Tests for the I{hosts(5)}-based L{twisted.names.hosts.Resolver}. - """ - def setUp(self): - f = self.path() - f.setContent(b''' -1.1.1.1 EXAMPLE EXAMPLE.EXAMPLETHING -::2 mixed -1.1.1.2 MIXED -::1 ip6thingy -1.1.1.3 multiple -1.1.1.4 multiple -::3 ip6-multiple -::4 ip6-multiple -''') - self.ttl = 4200 - self.resolver = Resolver(f.path, self.ttl) - - - def test_defaultPath(self): - """ - The default hosts file used by L{Resolver} is I{/etc/hosts} if no value - is given for the C{file} initializer parameter. - """ - resolver = Resolver() - self.assertEqual(b"/etc/hosts", resolver.file) - - - def test_getHostByName(self): - """ - L{hosts.Resolver.getHostByName} returns a L{Deferred} which fires with a - string giving the address of the queried name as found in the resolver's - hosts file. - """ - data = [(b'EXAMPLE', '1.1.1.1'), - (b'EXAMPLE.EXAMPLETHING', '1.1.1.1'), - (b'MIXED', '1.1.1.2'), - ] - ds = [self.resolver.getHostByName(n).addCallback(self.assertEqual, ip) - for n, ip in data] - return gatherResults(ds) - - - def test_lookupAddress(self): - """ - L{hosts.Resolver.lookupAddress} returns a L{Deferred} which fires with A - records from the hosts file. - """ - d = self.resolver.lookupAddress(b'multiple') - def resolved(results): - answers, authority, additional = results - self.assertEqual( - (RRHeader(b"multiple", A, IN, self.ttl, - Record_A("1.1.1.3", self.ttl)), - RRHeader(b"multiple", A, IN, self.ttl, - Record_A("1.1.1.4", self.ttl))), - answers) - d.addCallback(resolved) - return d - - - def test_lookupIPV6Address(self): - """ - L{hosts.Resolver.lookupIPV6Address} returns a L{Deferred} which fires - with AAAA records from the hosts file. - """ - d = self.resolver.lookupIPV6Address(b'ip6-multiple') - def resolved(results): - answers, authority, additional = results - self.assertEqual( - (RRHeader(b"ip6-multiple", AAAA, IN, self.ttl, - Record_AAAA("::3", self.ttl)), - RRHeader(b"ip6-multiple", AAAA, IN, self.ttl, - Record_AAAA("::4", self.ttl))), - answers) - d.addCallback(resolved) - return d - - - def test_lookupAllRecords(self): - """ - L{hosts.Resolver.lookupAllRecords} returns a L{Deferred} which fires - with A records from the hosts file. - """ - d = self.resolver.lookupAllRecords(b'mixed') - def resolved(results): - answers, authority, additional = results - self.assertEqual( - (RRHeader(b"mixed", A, IN, self.ttl, - Record_A("1.1.1.2", self.ttl)),), - answers) - d.addCallback(resolved) - return d - - - def test_notImplemented(self): - return self.assertFailure(self.resolver.lookupMailExchange(b'EXAMPLE'), - NotImplementedError) - - - def test_query(self): - d = self.resolver.query(Query(b'EXAMPLE')) - d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(), - '1.1.1.1')) - return d - - - def test_lookupAddressNotFound(self): - """ - L{hosts.Resolver.lookupAddress} returns a L{Deferred} which fires with - L{dns.DomainError} if the name passed in has no addresses in the hosts - file. - """ - return self.assertFailure(self.resolver.lookupAddress(b'foueoa'), - DomainError) - - - def test_lookupIPV6AddressNotFound(self): - """ - Like L{test_lookupAddressNotFound}, but for - L{hosts.Resolver.lookupIPV6Address}. - """ - return self.assertFailure(self.resolver.lookupIPV6Address(b'foueoa'), - DomainError) - - - def test_lookupAllRecordsNotFound(self): - """ - Like L{test_lookupAddressNotFound}, but for - L{hosts.Resolver.lookupAllRecords}. - """ - return self.assertFailure(self.resolver.lookupAllRecords(b'foueoa'), - DomainError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_names.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_names.py deleted file mode 100644 index d0f2461..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_names.py +++ /dev/null @@ -1,1022 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.names. -""" - -import socket, operator, copy -from StringIO import StringIO -from functools import partial, reduce -from struct import pack - -from twisted.trial import unittest - -from twisted.internet import reactor, defer, error -from twisted.internet.defer import succeed -from twisted.names import client, server, common, authority, dns -from twisted.names.dns import SOA, Message, RRHeader, Record_A, Record_SOA -from twisted.names.error import DomainError -from twisted.names.client import Resolver -from twisted.names.secondary import ( - SecondaryAuthorityService, SecondaryAuthority) - -from twisted.test.proto_helpers import StringTransport, MemoryReactorClock - -def justPayload(results): - return [r.payload for r in results[0]] - -class NoFileAuthority(authority.FileAuthority): - def __init__(self, soa, records): - # Yes, skip FileAuthority - common.ResolverBase.__init__(self) - self.soa, self.records = soa, records - - -soa_record = dns.Record_SOA( - mname = 'test-domain.com', - rname = 'root.test-domain.com', - serial = 100, - refresh = 1234, - minimum = 7654, - expire = 19283784, - retry = 15, - ttl=1 - ) - -reverse_soa = dns.Record_SOA( - mname = '93.84.28.in-addr.arpa', - rname = '93.84.28.in-addr.arpa', - serial = 120, - refresh = 54321, - minimum = 382, - expire = 11193983, - retry = 30, - ttl=3 - ) - -my_soa = dns.Record_SOA( - mname = 'my-domain.com', - rname = 'postmaster.test-domain.com', - serial = 130, - refresh = 12345, - minimum = 1, - expire = 999999, - retry = 100, - ) - -test_domain_com = NoFileAuthority( - soa = ('test-domain.com', soa_record), - records = { - 'test-domain.com': [ - soa_record, - dns.Record_A('127.0.0.1'), - dns.Record_NS('39.28.189.39'), - dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all'), - dns.Record_SPF('v=spf1 +mx a:\0colo', '.example.com/28 -all not valid'), - dns.Record_MX(10, 'host.test-domain.com'), - dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know'), - dns.Record_CNAME('canonical.name.com'), - dns.Record_MB('mailbox.test-domain.com'), - dns.Record_MG('mail.group.someplace'), - dns.Record_TXT('A First piece of Text', 'a SecoNd piece'), - dns.Record_A6(0, 'ABCD::4321', ''), - dns.Record_A6(12, '0:0069::0', 'some.network.tld'), - dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net'), - dns.Record_TXT('Some more text, haha! Yes. \0 Still here?'), - dns.Record_MR('mail.redirect.or.whatever'), - dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box'), - dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com'), - dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text'), - dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, - '\x12\x01\x16\xfe\xc1\x00\x01'), - dns.Record_NAPTR(100, 10, "u", "sip+E2U", - "!^.*$!sip:information@domain.tld!"), - dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF')], - 'http.tcp.test-domain.com': [ - dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') - ], - 'host.test-domain.com': [ - dns.Record_A('123.242.1.5'), - dns.Record_A('0.255.0.255'), - ], - 'host-two.test-domain.com': [ -# -# Python bug -# dns.Record_A('255.255.255.255'), -# - dns.Record_A('255.255.255.254'), - dns.Record_A('0.0.0.0') - ], - 'cname.test-domain.com': [ - dns.Record_CNAME('test-domain.com') - ], - 'anothertest-domain.com': [ - dns.Record_A('1.2.3.4')], - } -) - -reverse_domain = NoFileAuthority( - soa = ('93.84.28.in-addr.arpa', reverse_soa), - records = { - '123.93.84.28.in-addr.arpa': [ - dns.Record_PTR('test.host-reverse.lookup.com'), - reverse_soa - ] - } -) - - -my_domain_com = NoFileAuthority( - soa = ('my-domain.com', my_soa), - records = { - 'my-domain.com': [ - my_soa, - dns.Record_A('1.2.3.4', ttl='1S'), - dns.Record_NS('ns1.domain', ttl='2M'), - dns.Record_NS('ns2.domain', ttl='3H'), - dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D') - ] - } - ) - - -class ServerDNSTests(unittest.TestCase): - """ - Test cases for DNS server and client. - """ - - def setUp(self): - self.factory = server.DNSServerFactory([ - test_domain_com, reverse_domain, my_domain_com - ], verbose=2) - - p = dns.DNSDatagramProtocol(self.factory) - - while 1: - listenerTCP = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - # It's simpler to do the stop listening with addCleanup, - # even though we might not end up using this TCP port in - # the test (if the listenUDP below fails). Cleaning up - # this TCP port sooner than "cleanup time" would mean - # adding more code to keep track of the Deferred returned - # by stopListening. - self.addCleanup(listenerTCP.stopListening) - port = listenerTCP.getHost().port - - try: - listenerUDP = reactor.listenUDP(port, p, interface="127.0.0.1") - except error.CannotListenError: - pass - else: - self.addCleanup(listenerUDP.stopListening) - break - - self.listenerTCP = listenerTCP - self.listenerUDP = listenerUDP - self.resolver = client.Resolver(servers=[('127.0.0.1', port)]) - - - def tearDown(self): - """ - Clean up any server connections associated with the - L{DNSServerFactory} created in L{setUp} - """ - # It'd be great if DNSServerFactory had a method that - # encapsulated this task. At least the necessary data is - # available, though. - for conn in self.factory.connections[:]: - conn.transport.loseConnection() - - - def namesTest(self, querying, expectedRecords): - """ - Assert that the DNS response C{querying} will eventually fire with - contains exactly a certain collection of records. - - @param querying: A L{Deferred} returned from one of the DNS client - I{lookup} methods. - - @param expectedRecords: A L{list} of L{IRecord} providers which must be - in the response or the test will be failed. - - @return: A L{Deferred} that fires when the assertion has been made. It - fires with a success result if the assertion succeeds and with a - L{Failure} if it fails. - """ - def checkResults(response): - receivedRecords = justPayload(response) - self.assertEqual(set(expectedRecords), set(receivedRecords)) - - querying.addCallback(checkResults) - return querying - - - def test_addressRecord1(self): - """Test simple DNS 'A' record queries""" - return self.namesTest( - self.resolver.lookupAddress('test-domain.com'), - [dns.Record_A('127.0.0.1', ttl=19283784)] - ) - - - def test_addressRecord2(self): - """Test DNS 'A' record queries with multiple answers""" - return self.namesTest( - self.resolver.lookupAddress('host.test-domain.com'), - [dns.Record_A('123.242.1.5', ttl=19283784), dns.Record_A('0.255.0.255', ttl=19283784)] - ) - - - def test_addressRecord3(self): - """Test DNS 'A' record queries with edge cases""" - return self.namesTest( - self.resolver.lookupAddress('host-two.test-domain.com'), - [dns.Record_A('255.255.255.254', ttl=19283784), dns.Record_A('0.0.0.0', ttl=19283784)] - ) - - - def test_authority(self): - """Test DNS 'SOA' record queries""" - return self.namesTest( - self.resolver.lookupAuthority('test-domain.com'), - [soa_record] - ) - - - def test_mailExchangeRecord(self): - """ - The DNS client can issue an MX query and receive a response including - an MX record as well as any A record hints. - """ - return self.namesTest( - self.resolver.lookupMailExchange(b"test-domain.com"), - [dns.Record_MX(10, b"host.test-domain.com", ttl=19283784), - dns.Record_A(b"123.242.1.5", ttl=19283784), - dns.Record_A(b"0.255.0.255", ttl=19283784)]) - - - def test_nameserver(self): - """Test DNS 'NS' record queries""" - return self.namesTest( - self.resolver.lookupNameservers('test-domain.com'), - [dns.Record_NS('39.28.189.39', ttl=19283784)] - ) - - - def test_HINFO(self): - """Test DNS 'HINFO' record queries""" - return self.namesTest( - self.resolver.lookupHostInfo('test-domain.com'), - [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', ttl=19283784)] - ) - - def test_PTR(self): - """Test DNS 'PTR' record queries""" - return self.namesTest( - self.resolver.lookupPointer('123.93.84.28.in-addr.arpa'), - [dns.Record_PTR('test.host-reverse.lookup.com', ttl=11193983)] - ) - - - def test_CNAME(self): - """Test DNS 'CNAME' record queries""" - return self.namesTest( - self.resolver.lookupCanonicalName('test-domain.com'), - [dns.Record_CNAME('canonical.name.com', ttl=19283784)] - ) - - def test_MB(self): - """Test DNS 'MB' record queries""" - return self.namesTest( - self.resolver.lookupMailBox('test-domain.com'), - [dns.Record_MB('mailbox.test-domain.com', ttl=19283784)] - ) - - - def test_MG(self): - """Test DNS 'MG' record queries""" - return self.namesTest( - self.resolver.lookupMailGroup('test-domain.com'), - [dns.Record_MG('mail.group.someplace', ttl=19283784)] - ) - - - def test_MR(self): - """Test DNS 'MR' record queries""" - return self.namesTest( - self.resolver.lookupMailRename('test-domain.com'), - [dns.Record_MR('mail.redirect.or.whatever', ttl=19283784)] - ) - - - def test_MINFO(self): - """Test DNS 'MINFO' record queries""" - return self.namesTest( - self.resolver.lookupMailboxInfo('test-domain.com'), - [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', ttl=19283784)] - ) - - - def test_SRV(self): - """Test DNS 'SRV' record queries""" - return self.namesTest( - self.resolver.lookupService('http.tcp.test-domain.com'), - [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl=19283784)] - ) - - def test_AFSDB(self): - """Test DNS 'AFSDB' record queries""" - return self.namesTest( - self.resolver.lookupAFSDatabase('test-domain.com'), - [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', ttl=19283784)] - ) - - - def test_RP(self): - """Test DNS 'RP' record queries""" - return self.namesTest( - self.resolver.lookupResponsibility('test-domain.com'), - [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', ttl=19283784)] - ) - - - def test_TXT(self): - """Test DNS 'TXT' record queries""" - return self.namesTest( - self.resolver.lookupText('test-domain.com'), - [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', ttl=19283784), - dns.Record_TXT('Some more text, haha! Yes. \0 Still here?', ttl=19283784)] - ) - - - def test_spf(self): - """ - L{DNSServerFactory} can serve I{SPF} resource records. - """ - return self.namesTest( - self.resolver.lookupSenderPolicy('test-domain.com'), - [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all', ttl=19283784), - dns.Record_SPF('v=spf1 +mx a:\0colo', '.example.com/28 -all not valid', ttl=19283784)] - ) - - - def test_WKS(self): - """Test DNS 'WKS' record queries""" - return self.namesTest( - self.resolver.lookupWellKnownServices('test-domain.com'), - [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] - ) - - - def test_someRecordsWithTTLs(self): - result_soa = copy.copy(my_soa) - result_soa.ttl = my_soa.expire - return self.namesTest( - self.resolver.lookupAllRecords('my-domain.com'), - [result_soa, - dns.Record_A('1.2.3.4', ttl='1S'), - dns.Record_NS('ns1.domain', ttl='2M'), - dns.Record_NS('ns2.domain', ttl='3H'), - dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D')] - ) - - - def test_AAAA(self): - """Test DNS 'AAAA' record queries (IPv6)""" - return self.namesTest( - self.resolver.lookupIPV6Address('test-domain.com'), - [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', ttl=19283784)] - ) - - def test_A6(self): - """Test DNS 'A6' record queries (IPv6)""" - return self.namesTest( - self.resolver.lookupAddress6('test-domain.com'), - [dns.Record_A6(0, 'ABCD::4321', '', ttl=19283784), - dns.Record_A6(12, '0:0069::0', 'some.network.tld', ttl=19283784), - dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net', ttl=19283784)] - ) - - - def test_zoneTransfer(self): - """ - Test DNS 'AXFR' queries (Zone transfer) - """ - default_ttl = soa_record.expire - results = [copy.copy(r) for r in reduce(operator.add, test_domain_com.records.values())] - for r in results: - if r.ttl is None: - r.ttl = default_ttl - return self.namesTest( - self.resolver.lookupZone('test-domain.com').addCallback(lambda r: (r[0][:-1],)), - results - ) - - - def test_similarZonesDontInterfere(self): - """Tests that unrelated zones don't mess with each other.""" - return self.namesTest( - self.resolver.lookupAddress("anothertest-domain.com"), - [dns.Record_A('1.2.3.4', ttl=19283784)] - ) - - - def test_NAPTR(self): - """ - Test DNS 'NAPTR' record queries. - """ - return self.namesTest( - self.resolver.lookupNamingAuthorityPointer('test-domain.com'), - [dns.Record_NAPTR(100, 10, "u", "sip+E2U", - "!^.*$!sip:information@domain.tld!", - ttl=19283784)]) - - - -class HelperTests(unittest.TestCase): - def test_serialGenerator(self): - f = self.mktemp() - a = authority.getSerial(f) - for i in range(20): - b = authority.getSerial(f) - self.assertTrue(a < b) - a = b - - -class AXFRTests(unittest.TestCase): - def setUp(self): - self.results = None - self.d = defer.Deferred() - self.d.addCallback(self._gotResults) - self.controller = client.AXFRController('fooby.com', self.d) - - self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, ttl=86400, auth=False, - payload=dns.Record_SOA(mname='fooby.com', - rname='hooj.fooby.com', - serial=100, - refresh=200, - retry=300, - expire=400, - minimum=500, - ttl=600)) - - self.records = [ - self.soa, - dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, - payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700)), - - dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, auth=False, - payload=dns.Record_MX(preference=10, exchange='mail.mv3d.com', ttl=700)), - - dns.RRHeader(name='fooby.com', type=dns.A, cls=dns.IN, ttl=700, auth=False, - payload=dns.Record_A(address='64.123.27.105', ttl=700)), - self.soa - ] - - def _makeMessage(self): - # hooray they all have the same message format - return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, auth=1, rCode=0, trunc=0, maxSize=0) - - def test_bindAndTNamesStyle(self): - # Bind style = One big single message - m = self._makeMessage() - m.queries = [dns.Query('fooby.com', dns.AXFR, dns.IN)] - m.answers = self.records - self.controller.messageReceived(m, None) - self.assertEqual(self.results, self.records) - - def _gotResults(self, result): - self.results = result - - def test_DJBStyle(self): - # DJB style = message per record - records = self.records[:] - while records: - m = self._makeMessage() - m.queries = [] # DJB *doesn't* specify any queries.. hmm.. - m.answers = [records.pop(0)] - self.controller.messageReceived(m, None) - self.assertEqual(self.results, self.records) - - - -class ResolvConfHandlingTests(unittest.TestCase): - def test_missing(self): - resolvConf = self.mktemp() - r = client.Resolver(resolv=resolvConf) - self.assertEqual(r.dynServers, [('127.0.0.1', 53)]) - r._parseCall.cancel() - - def test_empty(self): - resolvConf = self.mktemp() - fObj = file(resolvConf, 'w') - fObj.close() - r = client.Resolver(resolv=resolvConf) - self.assertEqual(r.dynServers, [('127.0.0.1', 53)]) - r._parseCall.cancel() - - - -class AuthorityTests(unittest.TestCase): - """ - Tests for the basic response record selection code in L{FileAuthority} - (independent of its fileness). - """ - - def test_domainErrorForNameWithCommonSuffix(self): - """ - L{FileAuthority} lookup methods errback with L{DomainError} if - the requested C{name} shares a common suffix with its zone but - is not actually a descendant of its zone, in terms of its - sequence of DNS name labels. eg www.the-example.com has - nothing to do with the zone example.com. - """ - testDomain = test_domain_com - testDomainName = 'nonexistent.prefix-' + testDomain.soa[0] - f = self.failureResultOf(testDomain.lookupAddress(testDomainName)) - self.assertIsInstance(f.value, DomainError) - - - def test_recordMissing(self): - """ - If a L{FileAuthority} has a zone which includes an I{NS} record for a - particular name and that authority is asked for another record for the - same name which does not exist, the I{NS} record is not included in the - authority section of the response. - """ - authority = NoFileAuthority( - soa=(str(soa_record.mname), soa_record), - records={ - str(soa_record.mname): [ - soa_record, - dns.Record_NS('1.2.3.4'), - ]}) - d = authority.lookupAddress(str(soa_record.mname)) - result = [] - d.addCallback(result.append) - answer, authority, additional = result[0] - self.assertEqual(answer, []) - self.assertEqual( - authority, [ - dns.RRHeader( - str(soa_record.mname), soa_record.TYPE, - ttl=soa_record.expire, payload=soa_record, - auth=True)]) - self.assertEqual(additional, []) - - - def _referralTest(self, method): - """ - Create an authority and make a request against it. Then verify that the - result is a referral, including no records in the answers or additional - sections, but with an I{NS} record in the authority section. - """ - subdomain = 'example.' + str(soa_record.mname) - nameserver = dns.Record_NS('1.2.3.4') - authority = NoFileAuthority( - soa=(str(soa_record.mname), soa_record), - records={ - subdomain: [ - nameserver, - ]}) - d = getattr(authority, method)(subdomain) - answer, authority, additional = self.successResultOf(d) - self.assertEqual(answer, []) - self.assertEqual( - authority, [dns.RRHeader( - subdomain, dns.NS, ttl=soa_record.expire, - payload=nameserver, auth=False)]) - self.assertEqual(additional, []) - - - def test_referral(self): - """ - When an I{NS} record is found for a child zone, it is included in the - authority section of the response. It is marked as non-authoritative if - the authority is not also authoritative for the child zone (RFC 2181, - section 6.1). - """ - self._referralTest('lookupAddress') - - - def test_allRecordsReferral(self): - """ - A referral is also generated for a request of type C{ALL_RECORDS}. - """ - self._referralTest('lookupAllRecords') - - - -class AdditionalProcessingTests(unittest.TestCase): - """ - Tests for L{FileAuthority}'s additional processing for those record types - which require it (MX, CNAME, etc). - """ - _A = dns.Record_A(b"10.0.0.1") - _AAAA = dns.Record_AAAA(b"f080::1") - - def _lookupSomeRecords(self, method, soa, makeRecord, target, addresses): - """ - Perform a DNS lookup against a L{FileAuthority} configured with records - as defined by C{makeRecord} and C{addresses}. - - @param method: The name of the lookup method to use; for example, - C{"lookupNameservers"}. - @type method: L{str} - - @param soa: A L{Record_SOA} for the zone for which the L{FileAuthority} - is authoritative. - - @param makeRecord: A one-argument callable which accepts a name and - returns an L{IRecord} provider. L{FileAuthority} is constructed - with this record. The L{FileAuthority} is queried for a record of - the resulting type with the given name. - - @param target: The extra name which the record returned by - C{makeRecord} will be pointed at; this is the name which might - require extra processing by the server so that all the available, - useful information is returned. For example, this is the target of - a CNAME record or the mail exchange host pointed to by an MX record. - @type target: L{bytes} - - @param addresses: A L{list} of records giving addresses of C{target}. - - @return: A L{Deferred} that fires with the result of the resolver - method give by C{method}. - """ - authority = NoFileAuthority( - soa=(soa.mname.name, soa), - records={ - soa.mname.name: [makeRecord(target)], - target: addresses, - }, - ) - return getattr(authority, method)(soa_record.mname.name) - - - def assertRecordsMatch(self, expected, computed): - """ - Assert that the L{RRHeader} instances given by C{expected} and - C{computed} carry all the same information but without requiring the - records appear in the same order. - - @param expected: A L{list} of L{RRHeader} instances giving the expected - records. - - @param computed: A L{list} of L{RRHeader} instances giving the records - computed by the scenario under test. - - @raise self.failureException: If the two collections of records disagree. - """ - # RRHeader instances aren't inherently ordered. Impose an ordering - # that's good enough for the purposes of these tests - in which we - # never have more than one record of a particular type. - key = lambda rr: rr.type - self.assertEqual(sorted(expected, key=key), sorted(computed, key=key)) - - - def _additionalTest(self, method, makeRecord, addresses): - """ - Verify that certain address records are included in the I{additional} - section of a response generated by L{FileAuthority}. - - @param method: See L{_lookupSomeRecords} - - @param makeRecord: See L{_lookupSomeRecords} - - @param addresses: A L{list} of L{IRecord} providers which the - I{additional} section of the response is required to match - (ignoring order). - - @raise self.failureException: If the I{additional} section of the - response consists of different records than those given by - C{addresses}. - """ - target = b"mail." + soa_record.mname.name - d = self._lookupSomeRecords( - method, soa_record, makeRecord, target, addresses) - answer, authority, additional = self.successResultOf(d) - - self.assertRecordsMatch( - [dns.RRHeader( - target, address.TYPE, ttl=soa_record.expire, payload=address, - auth=True) - for address in addresses], - additional) - - - def _additionalMXTest(self, addresses): - """ - Verify that a response to an MX query has certain records in the - I{additional} section. - - @param addresses: See C{_additionalTest} - """ - self._additionalTest( - "lookupMailExchange", partial(dns.Record_MX, 10), addresses) - - - def test_mailExchangeAdditionalA(self): - """ - If the name of the MX response has A records, they are included in the - additional section of the response. - """ - self._additionalMXTest([self._A]) - - - def test_mailExchangeAdditionalAAAA(self): - """ - If the name of the MX response has AAAA records, they are included in - the additional section of the response. - """ - self._additionalMXTest([self._AAAA]) - - - def test_mailExchangeAdditionalBoth(self): - """ - If the name of the MX response has both A and AAAA records, they are - all included in the additional section of the response. - """ - self._additionalMXTest([self._A, self._AAAA]) - - - def _additionalNSTest(self, addresses): - """ - Verify that a response to an NS query has certain records in the - I{additional} section. - - @param addresses: See C{_additionalTest} - """ - self._additionalTest( - "lookupNameservers", dns.Record_NS, addresses) - - - def test_nameserverAdditionalA(self): - """ - If the name of the NS response has A records, they are included in the - additional section of the response. - """ - self._additionalNSTest([self._A]) - - - def test_nameserverAdditionalAAAA(self): - """ - If the name of the NS response has AAAA records, they are included in - the additional section of the response. - """ - self._additionalNSTest([self._AAAA]) - - - def test_nameserverAdditionalBoth(self): - """ - If the name of the NS response has both A and AAAA records, they are - all included in the additional section of the response. - """ - self._additionalNSTest([self._A, self._AAAA]) - - - def _answerCNAMETest(self, addresses): - """ - Verify that a response to a CNAME query has certain records in the - I{answer} section. - - @param addresses: See C{_additionalTest} - """ - target = b"www." + soa_record.mname.name - d = self._lookupSomeRecords( - "lookupCanonicalName", soa_record, dns.Record_CNAME, target, - addresses) - answer, authority, additional = self.successResultOf(d) - - alias = dns.RRHeader( - soa_record.mname.name, dns.CNAME, ttl=soa_record.expire, - payload=dns.Record_CNAME(target), auth=True) - self.assertRecordsMatch( - [dns.RRHeader( - target, address.TYPE, ttl=soa_record.expire, payload=address, - auth=True) - for address in addresses] + [alias], - answer) - - - def test_canonicalNameAnswerA(self): - """ - If the name of the CNAME response has A records, they are included in - the answer section of the response. - """ - self._answerCNAMETest([self._A]) - - - def test_canonicalNameAnswerAAAA(self): - """ - If the name of the CNAME response has AAAA records, they are included - in the answer section of the response. - """ - self._answerCNAMETest([self._AAAA]) - - - def test_canonicalNameAnswerBoth(self): - """ - If the name of the CNAME response has both A and AAAA records, they are - all included in the answer section of the response. - """ - self._answerCNAMETest([self._A, self._AAAA]) - - - -class NoInitialResponseTests(unittest.TestCase): - - def test_noAnswer(self): - """ - If a request returns a L{dns.NS} response, but we can't connect to the - given server, the request fails with the error returned at connection. - """ - - def query(self, *args): - # Pop from the message list, so that it blows up if more queries - # are run than expected. - return succeed(messages.pop(0)) - - def queryProtocol(self, *args, **kwargs): - return defer.fail(socket.gaierror("Couldn't connect")) - - resolver = Resolver(servers=[('0.0.0.0', 0)]) - resolver._query = query - messages = [] - # Let's patch dns.DNSDatagramProtocol.query, as there is no easy way to - # customize it. - self.patch(dns.DNSDatagramProtocol, "query", queryProtocol) - - records = [ - dns.RRHeader(name='fooba.com', type=dns.NS, cls=dns.IN, ttl=700, - auth=False, - payload=dns.Record_NS(name='ns.twistedmatrix.com', - ttl=700))] - m = dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, auth=1, - rCode=0, trunc=0, maxSize=0) - m.answers = records - messages.append(m) - return self.assertFailure( - resolver.getHostByName("fooby.com"), socket.gaierror) - - - -class SecondaryAuthorityServiceTests(unittest.TestCase): - """ - Tests for L{SecondaryAuthorityService}, a service which keeps one or more - authorities up to date by doing zone transfers from a master. - """ - - def test_constructAuthorityFromHost(self): - """ - L{SecondaryAuthorityService} can be constructed with a C{str} giving a - master server address and several domains, causing the creation of a - secondary authority for each domain and that master server address and - the default DNS port. - """ - primary = '192.168.1.2' - service = SecondaryAuthorityService( - primary, ['example.com', 'example.org']) - self.assertEqual(service.primary, primary) - self.assertEqual(service._port, 53) - - self.assertEqual(service.domains[0].primary, primary) - self.assertEqual(service.domains[0]._port, 53) - self.assertEqual(service.domains[0].domain, 'example.com') - - self.assertEqual(service.domains[1].primary, primary) - self.assertEqual(service.domains[1]._port, 53) - self.assertEqual(service.domains[1].domain, 'example.org') - - - def test_constructAuthorityFromHostAndPort(self): - """ - L{SecondaryAuthorityService.fromServerAddressAndDomains} constructs a - new L{SecondaryAuthorityService} from a C{str} giving a master server - address and DNS port and several domains, causing the creation of a secondary - authority for each domain and that master server address and the given - DNS port. - """ - primary = '192.168.1.3' - port = 5335 - service = SecondaryAuthorityService.fromServerAddressAndDomains( - (primary, port), ['example.net', 'example.edu']) - self.assertEqual(service.primary, primary) - self.assertEqual(service._port, 5335) - - self.assertEqual(service.domains[0].primary, primary) - self.assertEqual(service.domains[0]._port, port) - self.assertEqual(service.domains[0].domain, 'example.net') - - self.assertEqual(service.domains[1].primary, primary) - self.assertEqual(service.domains[1]._port, port) - self.assertEqual(service.domains[1].domain, 'example.edu') - - - -class SecondaryAuthorityTests(unittest.TestCase): - """ - L{twisted.names.secondary.SecondaryAuthority} correctly constructs objects - with a specified IP address and optionally specified DNS port. - """ - - def test_defaultPort(self): - """ - When constructed using L{SecondaryAuthority.__init__}, the default port - of 53 is used. - """ - secondary = SecondaryAuthority('192.168.1.1', 'inside.com') - self.assertEqual(secondary.primary, '192.168.1.1') - self.assertEqual(secondary._port, 53) - self.assertEqual(secondary.domain, 'inside.com') - - - def test_explicitPort(self): - """ - When constructed using L{SecondaryAuthority.fromServerAddressAndDomain}, - the specified port is used. - """ - secondary = SecondaryAuthority.fromServerAddressAndDomain( - ('192.168.1.1', 5353), 'inside.com') - self.assertEqual(secondary.primary, '192.168.1.1') - self.assertEqual(secondary._port, 5353) - self.assertEqual(secondary.domain, 'inside.com') - - - def test_transfer(self): - """ - An attempt is made to transfer the zone for the domain the - L{SecondaryAuthority} was constructed with from the server address it - was constructed with when L{SecondaryAuthority.transfer} is called. - """ - secondary = SecondaryAuthority.fromServerAddressAndDomain( - ('192.168.1.2', 1234), 'example.com') - secondary._reactor = reactor = MemoryReactorClock() - - secondary.transfer() - - # Verify a connection attempt to the server address above - host, port, factory, timeout, bindAddress = reactor.tcpClients.pop(0) - self.assertEqual(host, '192.168.1.2') - self.assertEqual(port, 1234) - - # See if a zone transfer query is issued. - proto = factory.buildProtocol((host, port)) - transport = StringTransport() - proto.makeConnection(transport) - - msg = Message() - # DNSProtocol.writeMessage length encodes the message by prepending a - # 2 byte message length to the buffered value. - msg.decode(StringIO(transport.value()[2:])) - - self.assertEqual( - [dns.Query('example.com', dns.AXFR, dns.IN)], msg.queries) - - - def test_lookupAddress(self): - """ - L{SecondaryAuthority.lookupAddress} returns a L{Deferred} that fires - with the I{A} records the authority has cached from the primary. - """ - secondary = SecondaryAuthority.fromServerAddressAndDomain( - (b'192.168.1.2', 1234), b'example.com') - secondary._reactor = reactor = MemoryReactorClock() - - secondary.transfer() - - host, port, factory, timeout, bindAddress = reactor.tcpClients.pop(0) - - proto = factory.buildProtocol((host, port)) - transport = StringTransport() - proto.makeConnection(transport) - - query = Message(answer=1, auth=1) - query.decode(StringIO(transport.value()[2:])) - - # Generate a response with some data we can check. - soa = Record_SOA( - mname=b'ns1.example.com', - rname='admin.example.com', - serial=123456, - refresh=3600, - minimum=4800, - expire=7200, - retry=9600, - ttl=12000, - ) - a = Record_A(b'192.168.1.2', ttl=0) - answer = Message(id=query.id, answer=1, auth=1) - answer.answers.extend([ - RRHeader(b'example.com', type=SOA, payload=soa), - RRHeader(b'example.com', payload=a), - RRHeader(b'example.com', type=SOA, payload=soa), - ]) - - data = answer.toStr() - proto.dataReceived(pack('!H', len(data)) + data) - - result = self.successResultOf(secondary.lookupAddress('example.com')) - self.assertEqual(( - [RRHeader(b'example.com', payload=a, auth=True)], [], []), result) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_resolve.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_resolve.py deleted file mode 100644 index 21fe8c0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_resolve.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.names.resolve}. -""" - -from twisted.trial.unittest import TestCase -from twisted.names.error import DomainError -from twisted.names.resolve import ResolverChain - - - -class ResolverChainTests(TestCase): - """ - Tests for L{twisted.names.resolve.ResolverChain} - """ - - def test_emptyResolversList(self): - """ - L{ResolverChain._lookup} returns a L{DomainError} failure if - its C{resolvers} list is empty. - """ - r = ResolverChain([]) - d = r.lookupAddress('www.example.com') - f = self.failureResultOf(d) - self.assertIs(f.trap(DomainError), DomainError) - - - def test_emptyResolversListLookupAllRecords(self): - """ - L{ResolverChain.lookupAllRecords} returns a L{DomainError} - failure if its C{resolvers} list is empty. - """ - r = ResolverChain([]) - d = r.lookupAllRecords('www.example.com') - f = self.failureResultOf(d) - self.assertIs(f.trap(DomainError), DomainError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_rfc1982.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_rfc1982.py deleted file mode 100644 index 2d1ef9f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_rfc1982.py +++ /dev/null @@ -1,444 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.names.rfc1982}. -""" - -from __future__ import division, absolute_import - -import calendar -from datetime import datetime -from functools import partial - -from twisted.names._rfc1982 import SerialNumber -from twisted.trial import unittest - - - -class SerialNumberTests(unittest.TestCase): - """ - Tests for L{SerialNumber}. - """ - - def test_serialBitsDefault(self): - """ - L{SerialNumber.serialBits} has default value 32. - """ - self.assertEqual(SerialNumber(1)._serialBits, 32) - - - def test_serialBitsOverride(self): - """ - L{SerialNumber.__init__} accepts a C{serialBits} argument whose value is - assigned to L{SerialNumber.serialBits}. - """ - self.assertEqual(SerialNumber(1, serialBits=8)._serialBits, 8) - - - def test_repr(self): - """ - L{SerialNumber.__repr__} returns a string containing number and - serialBits. - """ - self.assertEqual( - '', - repr(SerialNumber(123, serialBits=32)) - ) - - - def test_str(self): - """ - L{SerialNumber.__str__} returns a string representation of the current - value. - """ - self.assertEqual(str(SerialNumber(123)), '123') - - - def test_int(self): - """ - L{SerialNumber.__int__} returns an integer representation of the current - value. - """ - self.assertEqual(int(SerialNumber(123)), 123) - - - def test_hash(self): - """ - L{SerialNumber.__hash__} allows L{SerialNumber} instances to be hashed - for use as dictionary keys. - """ - self.assertEqual(hash(SerialNumber(1)), hash(SerialNumber(1))) - self.assertNotEqual(hash(SerialNumber(1)), hash(SerialNumber(2))) - - - def test_convertOtherSerialBitsMismatch(self): - """ - L{SerialNumber._convertOther} raises L{TypeError} if the other - SerialNumber instance has a different C{serialBits} value. - """ - s1 = SerialNumber(0, serialBits=8) - s2 = SerialNumber(0, serialBits=16) - - self.assertRaises( - TypeError, - s1._convertOther, - s2 - ) - - - def test_eq(self): - """ - L{SerialNumber.__eq__} provides rich equality comparison. - """ - self.assertEqual(SerialNumber(1), SerialNumber(1)) - - - def test_eqForeignType(self): - """ - == comparison of L{SerialNumber} with a non-L{SerialNumber} instance - raises L{TypeError}. - """ - self.assertRaises(TypeError, lambda: SerialNumber(1) == object()) - - - def test_ne(self): - """ - L{SerialNumber.__ne__} provides rich equality comparison. - """ - self.assertFalse(SerialNumber(1) != SerialNumber(1)) - self.assertNotEqual(SerialNumber(1), SerialNumber(2)) - - - def test_neForeignType(self): - """ - != comparison of L{SerialNumber} with a non-L{SerialNumber} instance - raises L{TypeError}. - """ - self.assertRaises(TypeError, lambda: SerialNumber(1) != object()) - - - def test_le(self): - """ - L{SerialNumber.__le__} provides rich <= comparison. - """ - self.assertTrue(SerialNumber(1) <= SerialNumber(1)) - self.assertTrue(SerialNumber(1) <= SerialNumber(2)) - - - def test_leForeignType(self): - """ - <= comparison of L{SerialNumber} with a non-L{SerialNumber} instance - raises L{TypeError}. - """ - self.assertRaises(TypeError, lambda: SerialNumber(1) <= object()) - - - def test_ge(self): - """ - L{SerialNumber.__ge__} provides rich >= comparison. - """ - self.assertTrue(SerialNumber(1) >= SerialNumber(1)) - self.assertTrue(SerialNumber(2) >= SerialNumber(1)) - - - def test_geForeignType(self): - """ - >= comparison of L{SerialNumber} with a non-L{SerialNumber} instance - raises L{TypeError}. - """ - self.assertRaises(TypeError, lambda: SerialNumber(1) >= object()) - - - def test_lt(self): - """ - L{SerialNumber.__lt__} provides rich < comparison. - """ - self.assertTrue(SerialNumber(1) < SerialNumber(2)) - - - def test_ltForeignType(self): - """ - < comparison of L{SerialNumber} with a non-L{SerialNumber} instance - raises L{TypeError}. - """ - self.assertRaises(TypeError, lambda: SerialNumber(1) < object()) - - - def test_gt(self): - """ - L{SerialNumber.__gt__} provides rich > comparison. - """ - self.assertTrue(SerialNumber(2) > SerialNumber(1)) - - - def test_gtForeignType(self): - """ - > comparison of L{SerialNumber} with a non-L{SerialNumber} instance - raises L{TypeError}. - """ - self.assertRaises(TypeError, lambda: SerialNumber(2) > object()) - - - def test_add(self): - """ - L{SerialNumber.__add__} allows L{SerialNumber} instances to be summed. - """ - self.assertEqual(SerialNumber(1) + SerialNumber(1), SerialNumber(2)) - - - def test_addForeignType(self): - """ - Addition of L{SerialNumber} with a non-L{SerialNumber} instance raises - L{TypeError}. - """ - self.assertRaises(TypeError, lambda: SerialNumber(1) + object()) - - - def test_addOutOfRangeHigh(self): - """ - L{SerialNumber} cannot be added with other SerialNumber values larger - than C{_maxAdd}. - """ - maxAdd = SerialNumber(1)._maxAdd - self.assertRaises( - ArithmeticError, - lambda: SerialNumber(1) + SerialNumber(maxAdd + 1)) - - - def test_maxVal(self): - """ - L{SerialNumber.__add__} returns a wrapped value when s1 plus the s2 - would result in a value greater than the C{maxVal}. - """ - s = SerialNumber(1) - maxVal = s._halfRing + s._halfRing - 1 - maxValPlus1 = maxVal + 1 - self.assertTrue(SerialNumber(maxValPlus1) > SerialNumber(maxVal)) - self.assertEqual(SerialNumber(maxValPlus1), SerialNumber(0)) - - - def test_fromRFC4034DateString(self): - """ - L{SerialNumber.fromRFC4034DateString} accepts a datetime string argument - of the form 'YYYYMMDDhhmmss' and returns an L{SerialNumber} instance - whose value is the unix timestamp corresponding to that UTC date. - """ - self.assertEqual( - SerialNumber(1325376000), - SerialNumber.fromRFC4034DateString('20120101000000') - ) - - - def test_toRFC4034DateString(self): - """ - L{DateSerialNumber.toRFC4034DateString} interprets the current value as - a unix timestamp and returns a date string representation of that date. - """ - self.assertEqual( - '20120101000000', - SerialNumber(1325376000).toRFC4034DateString() - ) - - - def test_unixEpoch(self): - """ - L{SerialNumber.toRFC4034DateString} stores 32bit timestamps relative to - the UNIX epoch. - """ - self.assertEqual( - SerialNumber(0).toRFC4034DateString(), - '19700101000000' - ) - - - def test_Y2106Problem(self): - """ - L{SerialNumber} wraps unix timestamps in the year 2106. - """ - self.assertEqual( - SerialNumber(-1).toRFC4034DateString(), - '21060207062815' - ) - - - def test_Y2038Problem(self): - """ - L{SerialNumber} raises ArithmeticError when used to add dates more than - 68 years in the future. - """ - maxAddTime = calendar.timegm( - datetime(2038, 1, 19, 3, 14, 7).utctimetuple()) - - self.assertEqual( - maxAddTime, - SerialNumber(0)._maxAdd, - ) - - self.assertRaises( - ArithmeticError, - lambda: SerialNumber(0) + SerialNumber(maxAddTime + 1)) - - - -def assertUndefinedComparison(testCase, s1, s2): - """ - A custom assertion for L{SerialNumber} values that cannot be meaningfully - compared. - - "Note that there are some pairs of values s1 and s2 for which s1 is not - equal to s2, but for which s1 is neither greater than, nor less than, s2. - An attempt to use these ordering operators on such pairs of values produces - an undefined result." - - @see: U{https://tools.ietf.org/html/rfc1982#section-3.2} - - @param testCase: The L{unittest.TestCase} on which to call assertion - methods. - @type testCase: L{unittest.TestCase} - - @param s1: The first value to compare. - @type s1: L{SerialNumber} - - @param s2: The second value to compare. - @type s2: L{SerialNumber} - """ - testCase.assertFalse(s1 == s2) - testCase.assertFalse(s1 <= s2) - testCase.assertFalse(s1 < s2) - testCase.assertFalse(s1 > s2) - testCase.assertFalse(s1 >= s2) - - - -serialNumber2 = partial(SerialNumber, serialBits=2) - - - -class SerialNumber2BitTests(unittest.TestCase): - """ - Tests for correct answers to example calculations in RFC1982 5.1. - - The simplest meaningful serial number space has SERIAL_BITS == 2. In this - space, the integers that make up the serial number space are 0, 1, 2, and 3. - That is, 3 == 2^SERIAL_BITS - 1. - - https://tools.ietf.org/html/rfc1982#section-5.1 - """ - def test_maxadd(self): - """ - In this space, the largest integer that it is meaningful to add to a - sequence number is 2^(SERIAL_BITS - 1) - 1, or 1. - """ - self.assertEqual(SerialNumber(0, serialBits=2)._maxAdd, 1) - - - def test_add(self): - """ - Then, as defined 0+1 == 1, 1+1 == 2, 2+1 == 3, and 3+1 == 0. - """ - self.assertEqual(serialNumber2(0) + serialNumber2(1), serialNumber2(1)) - self.assertEqual(serialNumber2(1) + serialNumber2(1), serialNumber2(2)) - self.assertEqual(serialNumber2(2) + serialNumber2(1), serialNumber2(3)) - self.assertEqual(serialNumber2(3) + serialNumber2(1), serialNumber2(0)) - - - def test_gt(self): - """ - Further, 1 > 0, 2 > 1, 3 > 2, and 0 > 3. - """ - self.assertTrue(serialNumber2(1) > serialNumber2(0)) - self.assertTrue(serialNumber2(2) > serialNumber2(1)) - self.assertTrue(serialNumber2(3) > serialNumber2(2)) - self.assertTrue(serialNumber2(0) > serialNumber2(3)) - - - def test_undefined(self): - """ - It is undefined whether 2 > 0 or 0 > 2, and whether 1 > 3 or 3 > 1. - """ - assertUndefinedComparison(self, serialNumber2(2), serialNumber2(0)) - assertUndefinedComparison(self, serialNumber2(0), serialNumber2(2)) - assertUndefinedComparison(self, serialNumber2(1), serialNumber2(3)) - assertUndefinedComparison(self, serialNumber2(3), serialNumber2(1)) - - - -serialNumber8 = partial(SerialNumber, serialBits=8) - - - -class SerialNumber8BitTests(unittest.TestCase): - """ - Tests for correct answers to example calculations in RFC1982 5.2. - - Consider the case where SERIAL_BITS == 8. In this space the integers that - make up the serial number space are 0, 1, 2, ... 254, 255. 255 == - 2^SERIAL_BITS - 1. - - https://tools.ietf.org/html/rfc1982#section-5.2 - """ - - def test_maxadd(self): - """ - In this space, the largest integer that it is meaningful to add to a - sequence number is 2^(SERIAL_BITS - 1) - 1, or 127. - """ - self.assertEqual(SerialNumber(0, serialBits=8)._maxAdd, 127) - - - def test_add(self): - """ - Addition is as expected in this space, for example: 255+1 == 0, - 100+100 == 200, and 200+100 == 44. - """ - self.assertEqual( - serialNumber8(255) + serialNumber8(1), serialNumber8(0)) - self.assertEqual( - serialNumber8(100) + serialNumber8(100), serialNumber8(200)) - self.assertEqual( - serialNumber8(200) + serialNumber8(100), serialNumber8(44)) - - - def test_gt(self): - """ - Comparison is more interesting, 1 > 0, 44 > 0, 100 > 0, 100 > 44, - 200 > 100, 255 > 200, 0 > 255, 100 > 255, 0 > 200, and 44 > 200. - """ - self.assertTrue(serialNumber8(1) > serialNumber8(0)) - self.assertTrue(serialNumber8(44) > serialNumber8(0)) - self.assertTrue(serialNumber8(100) > serialNumber8(0)) - self.assertTrue(serialNumber8(100) > serialNumber8(44)) - self.assertTrue(serialNumber8(200) > serialNumber8(100)) - self.assertTrue(serialNumber8(255) > serialNumber8(200)) - self.assertTrue(serialNumber8(100) > serialNumber8(255)) - self.assertTrue(serialNumber8(0) > serialNumber8(200)) - self.assertTrue(serialNumber8(44) > serialNumber8(200)) - - - def test_surprisingAddition(self): - """ - Note that 100+100 > 100, but that (100+100)+100 < 100. Incrementing a - serial number can cause it to become "smaller". Of course, incrementing - by a smaller number will allow many more increments to be made before - this occurs. However this is always something to be aware of, it can - cause surprising errors, or be useful as it is the only defined way to - actually cause a serial number to decrease. - """ - self.assertTrue( - serialNumber8(100) + serialNumber8(100) > serialNumber8(100)) - self.assertTrue( - serialNumber8(100) + serialNumber8(100) + serialNumber8(100) - < serialNumber8(100)) - - - def test_undefined(self): - """ - The pairs of values 0 and 128, 1 and 129, 2 and 130, etc, to 127 and 255 - are not equal, but in each pair, neither number is defined as being - greater than, or less than, the other. - """ - assertUndefinedComparison(self, serialNumber8(0), serialNumber8(128)) - assertUndefinedComparison(self, serialNumber8(1), serialNumber8(129)) - assertUndefinedComparison(self, serialNumber8(2), serialNumber8(130)) - assertUndefinedComparison(self, serialNumber8(127), serialNumber8(255)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_rootresolve.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_rootresolve.py deleted file mode 100644 index 181b876..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_rootresolve.py +++ /dev/null @@ -1,734 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for Twisted.names' root resolver. -""" - -from zope.interface import implementer -from zope.interface.verify import verifyClass - -from twisted.python.log import msg -from twisted.trial import util -from twisted.trial.unittest import SynchronousTestCase, TestCase -from twisted.internet.defer import Deferred, succeed, gatherResults, TimeoutError -from twisted.internet.interfaces import IResolverSimple -from twisted.names import client, root -from twisted.names.root import Resolver -from twisted.names.dns import ( - IN, HS, A, NS, CNAME, OK, ENAME, Record_CNAME, - Name, Query, Message, RRHeader, Record_A, Record_NS) -from twisted.names.error import DNSNameError, ResolverError -from twisted.names.test.test_util import MemoryReactor - - - -def getOnePayload(results): - """ - From the result of a L{Deferred} returned by L{IResolver.lookupAddress}, - return the payload of the first record in the answer section. - """ - ans, auth, add = results - return ans[0].payload - - -def getOneAddress(results): - """ - From the result of a L{Deferred} returned by L{IResolver.lookupAddress}, - return the first IPv4 address from the answer section. - """ - return getOnePayload(results).dottedQuad() - - - -class RootResolverTests(TestCase): - """ - Tests for L{twisted.names.root.Resolver}. - """ - def _queryTest(self, filter): - """ - Invoke L{Resolver._query} and verify that it sends the correct DNS - query. Deliver a canned response to the query and return whatever the - L{Deferred} returned by L{Resolver._query} fires with. - - @param filter: The value to pass for the C{filter} parameter to - L{Resolver._query}. - """ - reactor = MemoryReactor() - resolver = Resolver([], reactor=reactor) - d = resolver._query( - Query(b'foo.example.com', A, IN), [('1.1.2.3', 1053)], (30,), - filter) - - # A UDP port should have been started. - portNumber, transport = reactor.udpPorts.popitem() - - # And a DNS packet sent. - [(packet, address)] = transport._sentPackets - - message = Message() - message.fromStr(packet) - - # It should be a query with the parameters used above. - self.assertEqual(message.queries, [Query(b'foo.example.com', A, IN)]) - self.assertEqual(message.answers, []) - self.assertEqual(message.authority, []) - self.assertEqual(message.additional, []) - - response = [] - d.addCallback(response.append) - self.assertEqual(response, []) - - # Once a reply is received, the Deferred should fire. - del message.queries[:] - message.answer = 1 - message.answers.append(RRHeader( - b'foo.example.com', payload=Record_A('5.8.13.21'))) - transport._protocol.datagramReceived( - message.toStr(), ('1.1.2.3', 1053)) - return response[0] - - - def test_filteredQuery(self): - """ - L{Resolver._query} accepts a L{Query} instance and an address, issues - the query, and returns a L{Deferred} which fires with the response to - the query. If a true value is passed for the C{filter} parameter, the - result is a three-tuple of lists of records. - """ - answer, authority, additional = self._queryTest(True) - self.assertEqual( - answer, - [RRHeader(b'foo.example.com', payload=Record_A('5.8.13.21', ttl=0))]) - self.assertEqual(authority, []) - self.assertEqual(additional, []) - - - def test_unfilteredQuery(self): - """ - Similar to L{test_filteredQuery}, but for the case where a false value - is passed for the C{filter} parameter. In this case, the result is a - L{Message} instance. - """ - message = self._queryTest(False) - self.assertIsInstance(message, Message) - self.assertEqual(message.queries, []) - self.assertEqual( - message.answers, - [RRHeader(b'foo.example.com', payload=Record_A('5.8.13.21', ttl=0))]) - self.assertEqual(message.authority, []) - self.assertEqual(message.additional, []) - - - def _respond(self, answers=[], authority=[], additional=[], rCode=OK): - """ - Create a L{Message} suitable for use as a response to a query. - - @param answers: A C{list} of two-tuples giving data for the answers - section of the message. The first element of each tuple is a name - for the L{RRHeader}. The second element is the payload. - @param authority: A C{list} like C{answers}, but for the authority - section of the response. - @param additional: A C{list} like C{answers}, but for the - additional section of the response. - @param rCode: The response code the message will be created with. - - @return: A new L{Message} initialized with the given values. - """ - response = Message(rCode=rCode) - for (section, data) in [(response.answers, answers), - (response.authority, authority), - (response.additional, additional)]: - section.extend([ - RRHeader(name, record.TYPE, getattr(record, 'CLASS', IN), - payload=record) - for (name, record) in data]) - return response - - - def _getResolver(self, serverResponses, maximumQueries=10): - """ - Create and return a new L{root.Resolver} modified to resolve queries - against the record data represented by C{servers}. - - @param serverResponses: A mapping from dns server addresses to - mappings. The inner mappings are from query two-tuples (name, - type) to dictionaries suitable for use as **arguments to - L{_respond}. See that method for details. - """ - roots = ['1.1.2.3'] - resolver = Resolver(roots, maximumQueries) - - def query(query, serverAddresses, timeout, filter): - msg("Query for QNAME %s at %r" % (query.name, serverAddresses)) - for addr in serverAddresses: - try: - server = serverResponses[addr] - except KeyError: - continue - records = server[query.name.name, query.type] - return succeed(self._respond(**records)) - resolver._query = query - return resolver - - - def test_lookupAddress(self): - """ - L{root.Resolver.lookupAddress} looks up the I{A} records for the - specified hostname by first querying one of the root servers the - resolver was created with and then following the authority delegations - until a result is received. - """ - servers = { - ('1.1.2.3', 53): { - (b'foo.example.com', A): { - 'authority': [(b'foo.example.com', Record_NS(b'ns1.example.com'))], - 'additional': [(b'ns1.example.com', Record_A('34.55.89.144'))], - }, - }, - ('34.55.89.144', 53): { - (b'foo.example.com', A): { - 'answers': [(b'foo.example.com', Record_A('10.0.0.1'))], - } - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress(b'foo.example.com') - d.addCallback(getOneAddress) - d.addCallback(self.assertEqual, '10.0.0.1') - return d - - - def test_lookupChecksClass(self): - """ - If a response includes a record with a class different from the one - in the query, it is ignored and lookup continues until a record with - the right class is found. - """ - badClass = Record_A('10.0.0.1') - badClass.CLASS = HS - servers = { - ('1.1.2.3', 53): { - ('foo.example.com', A): { - 'answers': [('foo.example.com', badClass)], - 'authority': [('foo.example.com', Record_NS('ns1.example.com'))], - 'additional': [('ns1.example.com', Record_A('10.0.0.2'))], - }, - }, - ('10.0.0.2', 53): { - ('foo.example.com', A): { - 'answers': [('foo.example.com', Record_A('10.0.0.3'))], - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress('foo.example.com') - d.addCallback(getOnePayload) - d.addCallback(self.assertEqual, Record_A('10.0.0.3')) - return d - - - def test_missingGlue(self): - """ - If an intermediate response includes no glue records for the - authorities, separate queries are made to find those addresses. - """ - servers = { - ('1.1.2.3', 53): { - (b'foo.example.com', A): { - 'authority': [(b'foo.example.com', Record_NS(b'ns1.example.org'))], - # Conspicuous lack of an additional section naming ns1.example.com - }, - (b'ns1.example.org', A): { - 'answers': [(b'ns1.example.org', Record_A('10.0.0.1'))], - }, - }, - ('10.0.0.1', 53): { - (b'foo.example.com', A): { - 'answers': [(b'foo.example.com', Record_A('10.0.0.2'))], - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress(b'foo.example.com') - d.addCallback(getOneAddress) - d.addCallback(self.assertEqual, '10.0.0.2') - return d - - - def test_missingName(self): - """ - If a name is missing, L{Resolver.lookupAddress} returns a L{Deferred} - which fails with L{DNSNameError}. - """ - servers = { - ('1.1.2.3', 53): { - (b'foo.example.com', A): { - 'rCode': ENAME, - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress(b'foo.example.com') - return self.assertFailure(d, DNSNameError) - - - def test_answerless(self): - """ - If a query is responded to with no answers or nameserver records, the - L{Deferred} returned by L{Resolver.lookupAddress} fires with - L{ResolverError}. - """ - servers = { - ('1.1.2.3', 53): { - ('example.com', A): { - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress('example.com') - return self.assertFailure(d, ResolverError) - - - def test_delegationLookupError(self): - """ - If there is an error resolving the nameserver in a delegation response, - the L{Deferred} returned by L{Resolver.lookupAddress} fires with that - error. - """ - servers = { - ('1.1.2.3', 53): { - ('example.com', A): { - 'authority': [('example.com', Record_NS('ns1.example.com'))], - }, - ('ns1.example.com', A): { - 'rCode': ENAME, - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress('example.com') - return self.assertFailure(d, DNSNameError) - - - def test_delegationLookupEmpty(self): - """ - If there are no records in the response to a lookup of a delegation - nameserver, the L{Deferred} returned by L{Resolver.lookupAddress} fires - with L{ResolverError}. - """ - servers = { - ('1.1.2.3', 53): { - ('example.com', A): { - 'authority': [('example.com', Record_NS('ns1.example.com'))], - }, - ('ns1.example.com', A): { - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress('example.com') - return self.assertFailure(d, ResolverError) - - - def test_lookupNameservers(self): - """ - L{Resolver.lookupNameservers} is like L{Resolver.lookupAddress}, except - it queries for I{NS} records instead of I{A} records. - """ - servers = { - ('1.1.2.3', 53): { - (b'example.com', A): { - 'rCode': ENAME, - }, - (b'example.com', NS): { - 'answers': [(b'example.com', Record_NS(b'ns1.example.com'))], - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupNameservers(b'example.com') - def getOneName(results): - ans, auth, add = results - return ans[0].payload.name - d.addCallback(getOneName) - d.addCallback(self.assertEqual, Name(b'ns1.example.com')) - return d - - - def test_returnCanonicalName(self): - """ - If a I{CNAME} record is encountered as the answer to a query for - another record type, that record is returned as the answer. - """ - servers = { - ('1.1.2.3', 53): { - (b'example.com', A): { - 'answers': [(b'example.com', Record_CNAME(b'example.net')), - (b'example.net', Record_A('10.0.0.7'))], - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress(b'example.com') - d.addCallback(lambda results: results[0]) # Get the answer section - d.addCallback( - self.assertEqual, - [RRHeader(b'example.com', CNAME, payload=Record_CNAME(b'example.net')), - RRHeader(b'example.net', A, payload=Record_A('10.0.0.7'))]) - return d - - - def test_followCanonicalName(self): - """ - If no record of the requested type is included in a response, but a - I{CNAME} record for the query name is included, queries are made to - resolve the value of the I{CNAME}. - """ - servers = { - ('1.1.2.3', 53): { - ('example.com', A): { - 'answers': [('example.com', Record_CNAME('example.net'))], - }, - ('example.net', A): { - 'answers': [('example.net', Record_A('10.0.0.5'))], - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress('example.com') - d.addCallback(lambda results: results[0]) # Get the answer section - d.addCallback( - self.assertEqual, - [RRHeader('example.com', CNAME, payload=Record_CNAME('example.net')), - RRHeader('example.net', A, payload=Record_A('10.0.0.5'))]) - return d - - - def test_detectCanonicalNameLoop(self): - """ - If there is a cycle between I{CNAME} records in a response, this is - detected and the L{Deferred} returned by the lookup method fails - with L{ResolverError}. - """ - servers = { - ('1.1.2.3', 53): { - ('example.com', A): { - 'answers': [('example.com', Record_CNAME('example.net')), - ('example.net', Record_CNAME('example.com'))], - }, - }, - } - resolver = self._getResolver(servers) - d = resolver.lookupAddress('example.com') - return self.assertFailure(d, ResolverError) - - - def test_boundedQueries(self): - """ - L{Resolver.lookupAddress} won't issue more queries following - delegations than the limit passed to its initializer. - """ - servers = { - ('1.1.2.3', 53): { - # First query - force it to start over with a name lookup of - # ns1.example.com - ('example.com', A): { - 'authority': [('example.com', Record_NS('ns1.example.com'))], - }, - # Second query - let it resume the original lookup with the - # address of the nameserver handling the delegation. - ('ns1.example.com', A): { - 'answers': [('ns1.example.com', Record_A('10.0.0.2'))], - }, - }, - ('10.0.0.2', 53): { - # Third query - let it jump straight to asking the - # delegation server by including its address here (different - # case from the first query). - ('example.com', A): { - 'authority': [('example.com', Record_NS('ns2.example.com'))], - 'additional': [('ns2.example.com', Record_A('10.0.0.3'))], - }, - }, - ('10.0.0.3', 53): { - # Fourth query - give it the answer, we're done. - ('example.com', A): { - 'answers': [('example.com', Record_A('10.0.0.4'))], - }, - }, - } - - # Make two resolvers. One which is allowed to make 3 queries - # maximum, and so will fail, and on which may make 4, and so should - # succeed. - failer = self._getResolver(servers, 3) - failD = self.assertFailure( - failer.lookupAddress('example.com'), ResolverError) - - succeeder = self._getResolver(servers, 4) - succeedD = succeeder.lookupAddress('example.com') - succeedD.addCallback(getOnePayload) - succeedD.addCallback(self.assertEqual, Record_A('10.0.0.4')) - - return gatherResults([failD, succeedD]) - - - -class ResolverFactoryArguments(Exception): - """ - Raised by L{raisingResolverFactory} with the *args and **kwargs passed to - that function. - """ - def __init__(self, args, kwargs): - """ - Store the supplied args and kwargs as attributes. - - @param args: Positional arguments. - @param kwargs: Keyword arguments. - """ - self.args = args - self.kwargs = kwargs - - - -def raisingResolverFactory(*args, **kwargs): - """ - Raise a L{ResolverFactoryArguments} exception containing the - positional and keyword arguments passed to resolverFactory. - - @param args: A L{list} of all the positional arguments supplied by - the caller. - - @param kwargs: A L{list} of all the keyword arguments supplied by - the caller. - """ - raise ResolverFactoryArguments(args, kwargs) - - - -class RootResolverResolverFactoryTests(TestCase): - """ - Tests for L{root.Resolver._resolverFactory}. - """ - def test_resolverFactoryArgumentPresent(self): - """ - L{root.Resolver.__init__} accepts a C{resolverFactory} - argument and assigns it to C{self._resolverFactory}. - """ - r = Resolver(hints=[None], resolverFactory=raisingResolverFactory) - self.assertIdentical(r._resolverFactory, raisingResolverFactory) - - - def test_resolverFactoryArgumentAbsent(self): - """ - L{root.Resolver.__init__} sets L{client.Resolver} as the - C{_resolverFactory} if a C{resolverFactory} argument is not - supplied. - """ - r = Resolver(hints=[None]) - self.assertIdentical(r._resolverFactory, client.Resolver) - - - def test_resolverFactoryOnlyExpectedArguments(self): - """ - L{root.Resolver._resolverFactory} is supplied with C{reactor} and - C{servers} keyword arguments. - """ - dummyReactor = object() - r = Resolver(hints=['192.0.2.101'], - resolverFactory=raisingResolverFactory, - reactor=dummyReactor) - - e = self.assertRaises(ResolverFactoryArguments, - r.lookupAddress, 'example.com') - - self.assertEqual( - ((), {'reactor': dummyReactor, 'servers': [('192.0.2.101', 53)]}), - (e.args, e.kwargs) - ) - - - -ROOT_SERVERS = [ - 'a.root-servers.net', - 'b.root-servers.net', - 'c.root-servers.net', - 'd.root-servers.net', - 'e.root-servers.net', - 'f.root-servers.net', - 'g.root-servers.net', - 'h.root-servers.net', - 'i.root-servers.net', - 'j.root-servers.net', - 'k.root-servers.net', - 'l.root-servers.net', - 'm.root-servers.net'] - - - -@implementer(IResolverSimple) -class StubResolver(object): - """ - An L{IResolverSimple} implementer which traces all getHostByName - calls and their deferred results. The deferred results can be - accessed and fired synchronously. - """ - def __init__(self): - """ - @type calls: L{list} of L{tuple} containing C{args} and - C{kwargs} supplied to C{getHostByName} calls. - @type pendingResults: L{list} of L{Deferred} returned by - C{getHostByName}. - """ - self.calls = [] - self.pendingResults = [] - - - def getHostByName(self, *args, **kwargs): - """ - A fake implementation of L{IResolverSimple.getHostByName} - - @param args: A L{list} of all the positional arguments supplied by - the caller. - - @param kwargs: A L{list} of all the keyword arguments supplied by - the caller. - - @return: A L{Deferred} which may be fired later from the test - fixture. - """ - self.calls.append((args, kwargs)) - d = Deferred() - self.pendingResults.append(d) - return d - - - -verifyClass(IResolverSimple, StubResolver) - - - -class BootstrapTests(SynchronousTestCase): - """ - Tests for L{root.bootstrap} - """ - def test_returnsDeferredResolver(self): - """ - L{root.bootstrap} returns an object which is initially a - L{root.DeferredResolver}. - """ - deferredResolver = root.bootstrap(StubResolver()) - self.assertIsInstance(deferredResolver, root.DeferredResolver) - - - def test_resolves13RootServers(self): - """ - The L{IResolverSimple} supplied to L{root.bootstrap} is used to lookup - the IP addresses of the 13 root name servers. - """ - stubResolver = StubResolver() - root.bootstrap(stubResolver) - self.assertEqual( - stubResolver.calls, - [((s,), {}) for s in ROOT_SERVERS]) - - - def test_becomesResolver(self): - """ - The L{root.DeferredResolver} initially returned by L{root.bootstrap} - becomes a L{root.Resolver} when the supplied resolver has successfully - looked up all root hints. - """ - stubResolver = StubResolver() - deferredResolver = root.bootstrap(stubResolver) - for d in stubResolver.pendingResults: - d.callback('192.0.2.101') - self.assertIsInstance(deferredResolver, Resolver) - - - def test_resolverReceivesRootHints(self): - """ - The L{root.Resolver} which eventually replaces L{root.DeferredResolver} - is supplied with the IP addresses of the 13 root servers. - """ - stubResolver = StubResolver() - deferredResolver = root.bootstrap(stubResolver) - for d in stubResolver.pendingResults: - d.callback('192.0.2.101') - self.assertEqual(deferredResolver.hints, ['192.0.2.101'] * 13) - - - def test_continuesWhenSomeRootHintsFail(self): - """ - The L{root.Resolver} is eventually created, even if some of the root - hint lookups fail. Only the working root hint IP addresses are supplied - to the L{root.Resolver}. - """ - stubResolver = StubResolver() - deferredResolver = root.bootstrap(stubResolver) - results = iter(stubResolver.pendingResults) - d1 = next(results) - for d in results: - d.callback('192.0.2.101') - d1.errback(TimeoutError()) - - def checkHints(res): - self.assertEqual(deferredResolver.hints, ['192.0.2.101'] * 12) - d1.addBoth(checkHints) - - - def test_continuesWhenAllRootHintsFail(self): - """ - The L{root.Resolver} is eventually created, even if all of the root hint - lookups fail. Pending and new lookups will then fail with - AttributeError. - """ - stubResolver = StubResolver() - deferredResolver = root.bootstrap(stubResolver) - results = iter(stubResolver.pendingResults) - d1 = next(results) - for d in results: - d.errback(TimeoutError()) - d1.errback(TimeoutError()) - - def checkHints(res): - self.assertEqual(deferredResolver.hints, []) - d1.addBoth(checkHints) - - self.addCleanup(self.flushLoggedErrors, TimeoutError) - - - def test_passesResolverFactory(self): - """ - L{root.bootstrap} accepts a C{resolverFactory} argument which is passed - as an argument to L{root.Resolver} when it has successfully looked up - root hints. - """ - stubResolver = StubResolver() - deferredResolver = root.bootstrap( - stubResolver, resolverFactory=raisingResolverFactory) - - for d in stubResolver.pendingResults: - d.callback('192.0.2.101') - - self.assertIdentical( - deferredResolver._resolverFactory, raisingResolverFactory) - - - -class StubDNSDatagramProtocol: - """ - A do-nothing stand-in for L{DNSDatagramProtocol} which can be used to avoid - network traffic in tests where that kind of thing doesn't matter. - """ - def query(self, *a, **kw): - return Deferred() - - - -_retrySuppression = util.suppress( - category=DeprecationWarning, - message=( - 'twisted.names.root.retry is deprecated since Twisted 10.0. Use a ' - 'Resolver object for retry logic.')) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_server.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_server.py deleted file mode 100644 index 1be6d1e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_server.py +++ /dev/null @@ -1,1265 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.names.server}. -""" - -from zope.interface.verify import verifyClass - -from twisted.internet import defer -from twisted.internet.interfaces import IProtocolFactory -from twisted.names import dns, error, resolve, server -from twisted.python import failure, log -from twisted.trial import unittest - - - -class RaisedArguments(Exception): - """ - An exception containing the arguments raised by L{raiser}. - """ - def __init__(self, args, kwargs): - self.args = args - self.kwargs = kwargs - - - -def raiser(*args, **kwargs): - """ - Raise a L{RaisedArguments} exception containing the supplied arguments. - - Used as a fake when testing the call signatures of methods and functions. - """ - raise RaisedArguments(args, kwargs) - - - -class NoResponseDNSServerFactory(server.DNSServerFactory): - """ - A L{server.DNSServerFactory} subclass which does not attempt to reply to any - received messages. - - Used for testing logged messages in C{messageReceived} without having to - fake or patch the preceding code which attempts to deliver a response - message. - """ - def allowQuery(self, message, protocol, address): - """ - Deny all queries. - - @param message: See L{server.DNSServerFactory.allowQuery} - @param protocol: See L{server.DNSServerFactory.allowQuery} - @param address: See L{server.DNSServerFactory.allowQuery} - - @return: L{False} - @rtype: L{bool} - """ - return False - - - def sendReply(self, protocol, message, address): - """ - A noop send reply. - - @param protocol: See L{server.DNSServerFactory.sendReply} - @param message: See L{server.DNSServerFactory.sendReply} - @param address: See L{server.DNSServerFactory.sendReply} - """ - - - -class RaisingDNSServerFactory(server.DNSServerFactory): - """ - A L{server.DNSServerFactory} subclass whose methods raise an exception - containing the supplied arguments. - - Used for stopping L{messageReceived} and testing the arguments supplied to - L{allowQuery}. - """ - - class AllowQueryArguments(Exception): - """ - Contains positional and keyword arguments in C{args}. - """ - - def allowQuery(self, *args, **kwargs): - """ - Raise the arguments supplied to L{allowQuery}. - - @param args: Positional arguments which will be recorded in the raised - exception. - @type args: L{tuple} - - @param kwargs: Keyword args which will be recorded in the raised - exception. - @type kwargs: L{dict} - """ - raise self.AllowQueryArguments(args, kwargs) - - - -class RaisingProtocol(object): - """ - A partial fake L{IProtocol} whose methods raise an exception containing the - supplied arguments. - """ - class WriteMessageArguments(Exception): - """ - Contains positional and keyword arguments in C{args}. - """ - - def writeMessage(self, *args, **kwargs): - """ - Raises the supplied arguments. - - @param args: Positional arguments - @type args: L{tuple} - - @param kwargs: Keyword args - @type kwargs: L{dict} - """ - raise self.WriteMessageArguments(args, kwargs) - - - -class NoopProtocol(object): - """ - A partial fake L{dns.DNSProtocolMixin} with a noop L{writeMessage} method. - """ - def writeMessage(self, *args, **kwargs): - """ - A noop version of L{dns.DNSProtocolMixin.writeMessage}. - - @param args: Positional arguments - @type args: L{tuple} - - @param kwargs: Keyword args - @type kwargs: L{dict} - """ - - - -class RaisingResolver(object): - """ - A partial fake L{IResolver} whose methods raise an exception containing the - supplied arguments. - """ - class QueryArguments(Exception): - """ - Contains positional and keyword arguments in C{args}. - """ - - - def query(self, *args, **kwargs): - """ - Raises the supplied arguments. - - @param args: Positional arguments - @type args: L{tuple} - - @param kwargs: Keyword args - @type kwargs: L{dict} - """ - raise self.QueryArguments(args, kwargs) - - - -class RaisingCache(object): - """ - A partial fake L{twisted.names.cache.Cache} whose methods raise an exception - containing the supplied arguments. - """ - class CacheResultArguments(Exception): - """ - Contains positional and keyword arguments in C{args}. - """ - - - def cacheResult(self, *args, **kwargs): - """ - Raises the supplied arguments. - - @param args: Positional arguments - @type args: L{tuple} - - @param kwargs: Keyword args - @type kwargs: L{dict} - """ - raise self.CacheResultArguments(args, kwargs) - - - -def assertLogMessage(testCase, expectedMessages, callable, *args, **kwargs): - """ - Assert that the callable logs the expected messages when called. - - XXX: Put this somewhere where it can be re-used elsewhere. See #6677. - - @param testCase: The test case controlling the test which triggers the - logged messages and on which assertions will be called. - @type testCase: L{unittest.SynchronousTestCase} - - @param expectedMessages: A L{list} of the expected log messages - @type expectedMessages: L{list} - - @param callable: The function which is expected to produce the - C{expectedMessages} when called. - @type callable: L{callable} - - @param args: Positional arguments to be passed to C{callable}. - @type args: L{list} - - @param kwargs: Keyword arguments to be passed to C{callable}. - @type kwargs: L{dict} - """ - loggedMessages = [] - log.addObserver(loggedMessages.append) - testCase.addCleanup(log.removeObserver, loggedMessages.append) - - callable(*args, **kwargs) - - testCase.assertEqual( - [m['message'][0] for m in loggedMessages], - expectedMessages) - - - -class DNSServerFactoryTests(unittest.TestCase): - """ - Tests for L{server.DNSServerFactory}. - """ - def test_resolverType(self): - """ - L{server.DNSServerFactory.resolver} is a L{resolve.ResolverChain} - instance - """ - self.assertIsInstance( - server.DNSServerFactory().resolver, - resolve.ResolverChain) - - - def test_resolverDefaultEmpty(self): - """ - L{server.DNSServerFactory.resolver} is an empty L{resolve.ResolverChain} - by default. - """ - self.assertEqual( - server.DNSServerFactory().resolver.resolvers, - []) - - - def test_authorities(self): - """ - L{server.DNSServerFactory.__init__} accepts an C{authorities} - argument. The value of this argument is a list and is used to extend the - C{resolver} L{resolve.ResolverChain}. - """ - dummyResolver = object() - self.assertEqual( - server.DNSServerFactory( - authorities=[dummyResolver]).resolver.resolvers, - [dummyResolver]) - - - def test_caches(self): - """ - L{server.DNSServerFactory.__init__} accepts a C{caches} argument. The - value of this argument is a list and is used to extend the C{resolver} - L{resolve.ResolverChain}. - """ - dummyResolver = object() - self.assertEqual( - server.DNSServerFactory( - caches=[dummyResolver]).resolver.resolvers, - [dummyResolver]) - - - def test_clients(self): - """ - L{server.DNSServerFactory.__init__} accepts a C{clients} argument. The - value of this argument is a list and is used to extend the C{resolver} - L{resolve.ResolverChain}. - """ - dummyResolver = object() - self.assertEqual( - server.DNSServerFactory( - clients=[dummyResolver]).resolver.resolvers, - [dummyResolver]) - - - def test_resolverOrder(self): - """ - L{server.DNSServerFactory.resolver} contains an ordered list of - authorities, caches and clients. - """ - # Use classes here so that we can see meaningful names in test results - class DummyAuthority(object): - pass - - class DummyCache(object): - pass - - class DummyClient(object): - pass - - self.assertEqual( - server.DNSServerFactory( - authorities=[DummyAuthority], - caches=[DummyCache], - clients=[DummyClient]).resolver.resolvers, - [DummyAuthority, DummyCache, DummyClient]) - - - def test_cacheDefault(self): - """ - L{server.DNSServerFactory.cache} is L{None} by default. - """ - self.assertIs(server.DNSServerFactory().cache, None) - - - def test_cacheOverride(self): - """ - L{server.DNSServerFactory.__init__} assigns the last object in the - C{caches} list to L{server.DNSServerFactory.cache}. - """ - dummyResolver = object() - self.assertEqual( - server.DNSServerFactory(caches=[object(), dummyResolver]).cache, - dummyResolver) - - - def test_canRecurseDefault(self): - """ - L{server.DNSServerFactory.canRecurse} is a flag indicating that this - server is capable of performing recursive DNS lookups. It defaults to - L{False}. - """ - self.assertEqual(server.DNSServerFactory().canRecurse, False) - - - def test_canRecurseOverride(self): - """ - L{server.DNSServerFactory.__init__} sets C{canRecurse} to L{True} if it - is supplied with C{clients}. - """ - self.assertEqual( - server.DNSServerFactory(clients=[None]).canRecurse, True) - - - def test_verboseDefault(self): - """ - L{server.DNSServerFactory.verbose} defaults to L{False}. - """ - self.assertEqual(server.DNSServerFactory().verbose, False) - - - def test_verboseOverride(self): - """ - L{server.DNSServerFactory.__init__} accepts a C{verbose} argument which - overrides L{server.DNSServerFactory.verbose}. - """ - self.assertEqual(server.DNSServerFactory(verbose=True).verbose, True) - - - def test_interface(self): - """ - L{server.DNSServerFactory} implements L{IProtocolFactory}. - """ - self.assertTrue(verifyClass(IProtocolFactory, server.DNSServerFactory)) - - - def test_defaultProtocol(self): - """ - L{server.DNSServerFactory.protocol} defaults to L{dns.DNSProtocol}. - """ - self.assertIs(server.DNSServerFactory.protocol, dns.DNSProtocol) - - - def test_buildProtocolProtocolOverride(self): - """ - L{server.DNSServerFactory.buildProtocol} builds a protocol by calling - L{server.DNSServerFactory.protocol} with its self as a positional - argument. - """ - class FakeProtocol(object): - factory = None - args = None - kwargs = None - - stubProtocol = FakeProtocol() - - def fakeProtocolFactory(*args, **kwargs): - stubProtocol.args = args - stubProtocol.kwargs = kwargs - return stubProtocol - - f = server.DNSServerFactory() - f.protocol = fakeProtocolFactory - p = f.buildProtocol(addr=None) - - self.assertEqual( - (stubProtocol, (f,), {}), - (p, p.args, p.kwargs) - ) - - - def test_verboseLogQuiet(self): - """ - L{server.DNSServerFactory._verboseLog} does not log messages unless - C{verbose > 0}. - """ - f = server.DNSServerFactory() - assertLogMessage( - self, - [], - f._verboseLog, - 'Foo Bar' - ) - - - def test_verboseLogVerbose(self): - """ - L{server.DNSServerFactory._verboseLog} logs a message if C{verbose > 0}. - """ - f = server.DNSServerFactory(verbose=1) - assertLogMessage( - self, - ['Foo Bar'], - f._verboseLog, - 'Foo Bar' - ) - - - def test_messageReceivedLoggingNoQuery(self): - """ - L{server.DNSServerFactory.messageReceived} logs about an empty query if - the message had no queries and C{verbose} is C{>0}. - """ - m = dns.Message() - f = NoResponseDNSServerFactory(verbose=1) - - assertLogMessage( - self, - ["Empty query from ('192.0.2.100', 53)"], - f.messageReceived, - message=m, proto=None, address=('192.0.2.100', 53)) - - - def test_messageReceivedLogging1(self): - """ - L{server.DNSServerFactory.messageReceived} logs the query types of all - queries in the message if C{verbose} is set to C{1}. - """ - m = dns.Message() - m.addQuery(name='example.com', type=dns.MX) - m.addQuery(name='example.com', type=dns.AAAA) - f = NoResponseDNSServerFactory(verbose=1) - - assertLogMessage( - self, - ["MX AAAA query from ('192.0.2.100', 53)"], - f.messageReceived, - message=m, proto=None, address=('192.0.2.100', 53)) - - - def test_messageReceivedLogging2(self): - """ - L{server.DNSServerFactory.messageReceived} logs the repr of all queries - in the message if C{verbose} is set to C{2}. - """ - m = dns.Message() - m.addQuery(name='example.com', type=dns.MX) - m.addQuery(name='example.com', type=dns.AAAA) - f = NoResponseDNSServerFactory(verbose=2) - - assertLogMessage( - self, - [" " - " query from ('192.0.2.100', 53)"], - f.messageReceived, - message=m, proto=None, address=('192.0.2.100', 53)) - - - def test_messageReceivedTimestamp(self): - """ - L{server.DNSServerFactory.messageReceived} assigns a unix timestamp to - the received message. - """ - m = dns.Message() - f = NoResponseDNSServerFactory() - t = object() - self.patch(server.time, 'time', lambda: t) - f.messageReceived(message=m, proto=None, address=None) - - self.assertEqual(m.timeReceived, t) - - - def test_messageReceivedAllowQuery(self): - """ - L{server.DNSServerFactory.messageReceived} passes all messages to - L{server.DNSServerFactory.allowQuery} along with the receiving protocol - and origin address. - """ - message = dns.Message() - dummyProtocol = object() - dummyAddress = object() - - f = RaisingDNSServerFactory() - e = self.assertRaises( - RaisingDNSServerFactory.AllowQueryArguments, - f.messageReceived, - message=message, proto=dummyProtocol, address=dummyAddress) - args, kwargs = e.args - self.assertEqual(args, (message, dummyProtocol, dummyAddress)) - self.assertEqual(kwargs, {}) - - - def test_allowQueryFalse(self): - """ - If C{allowQuery} returns C{False}, - L{server.DNSServerFactory.messageReceived} calls L{server.sendReply} - with a message whose C{rCode} is L{dns.EREFUSED}. - """ - class SendReplyException(Exception): - pass - - class RaisingDNSServerFactory(server.DNSServerFactory): - def allowQuery(self, *args, **kwargs): - return False - - def sendReply(self, *args, **kwargs): - raise SendReplyException(args, kwargs) - - f = RaisingDNSServerFactory() - e = self.assertRaises( - SendReplyException, - f.messageReceived, - message=dns.Message(), proto=None, address=None) - (proto, message, address), kwargs = e.args - - self.assertEqual(message.rCode, dns.EREFUSED) - - - def _messageReceivedTest(self, methodName, message): - """ - Assert that the named method is called with the given message when it is - passed to L{DNSServerFactory.messageReceived}. - - @param methodName: The name of the method which is expected to be - called. - @type methodName: L{str} - - @param message: The message which is expected to be passed to the - C{methodName} method. - @type message: L{dns.Message} - """ - # Make it appear to have some queries so that - # DNSServerFactory.allowQuery allows it. - message.queries = [None] - - receivedMessages = [] - def fakeHandler(message, protocol, address): - receivedMessages.append((message, protocol, address)) - - protocol = NoopProtocol() - factory = server.DNSServerFactory(None) - setattr(factory, methodName, fakeHandler) - factory.messageReceived(message, protocol) - self.assertEqual(receivedMessages, [(message, protocol, None)]) - - - def test_queryMessageReceived(self): - """ - L{DNSServerFactory.messageReceived} passes messages with an opcode of - C{OP_QUERY} on to L{DNSServerFactory.handleQuery}. - """ - self._messageReceivedTest( - 'handleQuery', dns.Message(opCode=dns.OP_QUERY)) - - - def test_inverseQueryMessageReceived(self): - """ - L{DNSServerFactory.messageReceived} passes messages with an opcode of - C{OP_INVERSE} on to L{DNSServerFactory.handleInverseQuery}. - """ - self._messageReceivedTest( - 'handleInverseQuery', dns.Message(opCode=dns.OP_INVERSE)) - - - def test_statusMessageReceived(self): - """ - L{DNSServerFactory.messageReceived} passes messages with an opcode of - C{OP_STATUS} on to L{DNSServerFactory.handleStatus}. - """ - self._messageReceivedTest( - 'handleStatus', dns.Message(opCode=dns.OP_STATUS)) - - - def test_notifyMessageReceived(self): - """ - L{DNSServerFactory.messageReceived} passes messages with an opcode of - C{OP_NOTIFY} on to L{DNSServerFactory.handleNotify}. - """ - self._messageReceivedTest( - 'handleNotify', dns.Message(opCode=dns.OP_NOTIFY)) - - - def test_updateMessageReceived(self): - """ - L{DNSServerFactory.messageReceived} passes messages with an opcode of - C{OP_UPDATE} on to L{DNSServerFactory.handleOther}. - - This may change if the implementation ever covers update messages. - """ - self._messageReceivedTest( - 'handleOther', dns.Message(opCode=dns.OP_UPDATE)) - - - def test_connectionTracking(self): - """ - The C{connectionMade} and C{connectionLost} methods of - L{DNSServerFactory} cooperate to keep track of all L{DNSProtocol} - objects created by a factory which are connected. - """ - protoA, protoB = object(), object() - factory = server.DNSServerFactory() - factory.connectionMade(protoA) - self.assertEqual(factory.connections, [protoA]) - factory.connectionMade(protoB) - self.assertEqual(factory.connections, [protoA, protoB]) - factory.connectionLost(protoA) - self.assertEqual(factory.connections, [protoB]) - factory.connectionLost(protoB) - self.assertEqual(factory.connections, []) - - - def test_handleQuery(self): - """ - L{server.DNSServerFactory.handleQuery} takes the first query from the - supplied message and dispatches it to - L{server.DNSServerFactory.resolver.query}. - """ - m = dns.Message() - m.addQuery(b'one.example.com') - m.addQuery(b'two.example.com') - f = server.DNSServerFactory() - f.resolver = RaisingResolver() - - e = self.assertRaises( - RaisingResolver.QueryArguments, - f.handleQuery, - message=m, protocol=NoopProtocol(), address=None) - (query,), kwargs = e.args - self.assertEqual(query, m.queries[0]) - - - def test_handleQueryCallback(self): - """ - L{server.DNSServerFactory.handleQuery} adds - L{server.DNSServerFactory.resolver.gotResolverResponse} as a callback to - the deferred returned by L{server.DNSServerFactory.resolver.query}. It - is called with the query response, the original protocol, message and - origin address. - """ - f = server.DNSServerFactory() - - d = defer.Deferred() - class FakeResolver(object): - def query(self, *args, **kwargs): - return d - f.resolver = FakeResolver() - - gotResolverResponseArgs = [] - def fakeGotResolverResponse(*args, **kwargs): - gotResolverResponseArgs.append((args, kwargs)) - f.gotResolverResponse = fakeGotResolverResponse - - m = dns.Message() - m.addQuery(b'one.example.com') - stubProtocol = NoopProtocol() - dummyAddress = object() - - f.handleQuery(message=m, protocol=stubProtocol, address=dummyAddress) - - dummyResponse = object() - d.callback(dummyResponse) - - self.assertEqual( - gotResolverResponseArgs, - [((dummyResponse, stubProtocol, m, dummyAddress), {})]) - - - def test_handleQueryErrback(self): - """ - L{server.DNSServerFactory.handleQuery} adds - L{server.DNSServerFactory.resolver.gotResolverError} as an errback to - the deferred returned by L{server.DNSServerFactory.resolver.query}. It - is called with the query failure, the original protocol, message and - origin address. - """ - f = server.DNSServerFactory() - - d = defer.Deferred() - class FakeResolver(object): - def query(self, *args, **kwargs): - return d - f.resolver = FakeResolver() - - gotResolverErrorArgs = [] - def fakeGotResolverError(*args, **kwargs): - gotResolverErrorArgs.append((args, kwargs)) - f.gotResolverError = fakeGotResolverError - - m = dns.Message() - m.addQuery(b'one.example.com') - stubProtocol = NoopProtocol() - dummyAddress = object() - - f.handleQuery(message=m, protocol=stubProtocol, address=dummyAddress) - - stubFailure = failure.Failure(Exception()) - d.errback(stubFailure) - - self.assertEqual( - gotResolverErrorArgs, - [((stubFailure, stubProtocol, m, dummyAddress), {})]) - - - def test_gotResolverResponse(self): - """ - L{server.DNSServerFactory.gotResolverResponse} accepts a tuple of - resource record lists and triggers a response message containing those - resource record lists. - """ - f = server.DNSServerFactory() - answers = [] - authority = [] - additional = [] - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.gotResolverResponse, - (answers, authority, additional), - protocol=RaisingProtocol(), message=dns.Message(), address=None) - (message,), kwargs = e.args - - self.assertIs(message.answers, answers) - self.assertIs(message.authority, authority) - self.assertIs(message.additional, additional) - - - def test_gotResolverResponseCallsResponseFromMessage(self): - """ - L{server.DNSServerFactory.gotResolverResponse} calls - L{server.DNSServerFactory._responseFromMessage} to generate a response. - """ - factory = NoResponseDNSServerFactory() - factory._responseFromMessage = raiser - - request = dns.Message() - request.timeReceived = 1 - - e = self.assertRaises( - RaisedArguments, - factory.gotResolverResponse, - ([], [], []), - protocol=None, message=request, address=None - ) - self.assertEqual( - ((), dict(message=request, rCode=dns.OK, - answers=[], authority=[], additional=[])), - (e.args, e.kwargs) - ) - - - def test_responseFromMessageNewMessage(self): - """ - L{server.DNSServerFactory._responseFromMessage} generates a response - message which is a copy of the request message. - """ - factory = server.DNSServerFactory() - request = dns.Message(answer=False, recAv=False) - response = factory._responseFromMessage(message=request), - - self.assertIsNot(request, response) - - - def test_responseFromMessageRecursionAvailable(self): - """ - L{server.DNSServerFactory._responseFromMessage} generates a response - message whose C{recAV} attribute is L{True} if - L{server.DNSServerFactory.canRecurse} is L{True}. - """ - factory = server.DNSServerFactory() - factory.canRecurse = True - response1 = factory._responseFromMessage( - message=dns.Message(recAv=False)) - factory.canRecurse = False - response2 = factory._responseFromMessage( - message=dns.Message(recAv=True)) - self.assertEqual( - (True, False), - (response1.recAv, response2.recAv)) - - - def test_responseFromMessageTimeReceived(self): - """ - L{server.DNSServerFactory._responseFromMessage} generates a response - message whose C{timeReceived} attribute has the same value as that found - on the request. - """ - factory = server.DNSServerFactory() - request = dns.Message() - request.timeReceived = 1234 - response = factory._responseFromMessage(message=request) - - self.assertEqual(request.timeReceived, response.timeReceived) - - - def test_responseFromMessageMaxSize(self): - """ - L{server.DNSServerFactory._responseFromMessage} generates a response - message whose C{maxSize} attribute has the same value as that found - on the request. - """ - factory = server.DNSServerFactory() - request = dns.Message() - request.maxSize = 0 - response = factory._responseFromMessage(message=request) - - self.assertEqual(request.maxSize, response.maxSize) - - - def test_messageFactory(self): - """ - L{server.DNSServerFactory} has a C{_messageFactory} attribute which is - L{dns.Message} by default. - """ - self.assertIs(dns.Message, server.DNSServerFactory._messageFactory) - - - def test_responseFromMessageCallsMessageFactory(self): - """ - L{server.DNSServerFactory._responseFromMessage} calls - C{dns._responseFromMessage} to generate a response - message from the request message. It supplies the request message and - other keyword arguments which should be passed to the response message - initialiser. - """ - factory = server.DNSServerFactory() - self.patch(dns, '_responseFromMessage', raiser) - - request = dns.Message() - e = self.assertRaises( - RaisedArguments, - factory._responseFromMessage, - message=request, rCode=dns.OK - ) - self.assertEqual( - ((), dict(responseConstructor=factory._messageFactory, - message=request, rCode=dns.OK, recAv=factory.canRecurse, - auth=False)), - (e.args, e.kwargs) - ) - - - def test_responseFromMessageAuthoritativeMessage(self): - """ - L{server.DNSServerFactory._responseFromMessage} marks the response - message as authoritative if any of the answer records are authoritative. - """ - factory = server.DNSServerFactory() - response1 = factory._responseFromMessage( - message=dns.Message(), answers=[dns.RRHeader(auth=True)]) - response2 = factory._responseFromMessage( - message=dns.Message(), answers=[dns.RRHeader(auth=False)]) - self.assertEqual( - (True, False), - (response1.auth, response2.auth), - ) - - - def test_gotResolverResponseLogging(self): - """ - L{server.DNSServerFactory.gotResolverResponse} logs the total number of - records in the response if C{verbose > 0}. - """ - f = NoResponseDNSServerFactory(verbose=1) - answers = [dns.RRHeader()] - authority = [dns.RRHeader()] - additional = [dns.RRHeader()] - - assertLogMessage( - self, - ["Lookup found 3 records"], - f.gotResolverResponse, - (answers, authority, additional), - protocol=NoopProtocol(), message=dns.Message(), address=None) - - - def test_gotResolverResponseCaching(self): - """ - L{server.DNSServerFactory.gotResolverResponse} caches the response if at - least one cache was provided in the constructor. - """ - f = NoResponseDNSServerFactory(caches=[RaisingCache()]) - - m = dns.Message() - m.addQuery(b'example.com') - expectedAnswers = [dns.RRHeader()] - expectedAuthority = [] - expectedAdditional = [] - - e = self.assertRaises( - RaisingCache.CacheResultArguments, - f.gotResolverResponse, - (expectedAnswers, expectedAuthority, expectedAdditional), - protocol=NoopProtocol(), message=m, address=None) - (query, (answers, authority, additional)), kwargs = e.args - - self.assertEqual(query.name.name, b'example.com') - self.assertIs(answers, expectedAnswers) - self.assertIs(authority, expectedAuthority) - self.assertIs(additional, expectedAdditional) - - - def test_gotResolverErrorCallsResponseFromMessage(self): - """ - L{server.DNSServerFactory.gotResolverError} calls - L{server.DNSServerFactory._responseFromMessage} to generate a response. - """ - factory = NoResponseDNSServerFactory() - factory._responseFromMessage = raiser - - request = dns.Message() - request.timeReceived = 1 - - e = self.assertRaises( - RaisedArguments, - factory.gotResolverError, - failure.Failure(error.DomainError()), - protocol=None, message=request, address=None - ) - self.assertEqual( - ((), dict(message=request, rCode=dns.ENAME)), - (e.args, e.kwargs) - ) - - - def _assertMessageRcodeForError(self, responseError, expectedMessageCode): - """ - L{server.DNSServerFactory.gotResolver} accepts a L{failure.Failure} and - triggers a response message whose rCode corresponds to the DNS error - contained in the C{Failure}. - - @param responseError: The L{Exception} instance which is expected to - trigger C{expectedMessageCode} when it is supplied to - C{gotResolverError} - @type responseError: L{Exception} - - @param expectedMessageCode: The C{rCode} which is expected in the - message returned by C{gotResolverError} in response to - C{responseError}. - @type expectedMessageCode: L{int} - """ - f = server.DNSServerFactory() - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.gotResolverError, - failure.Failure(responseError), - protocol=RaisingProtocol(), message=dns.Message(), address=None) - (message,), kwargs = e.args - - self.assertEqual(message.rCode, expectedMessageCode) - - - def test_gotResolverErrorDomainError(self): - """ - L{server.DNSServerFactory.gotResolver} triggers a response message with - an C{rCode} of L{dns.ENAME} if supplied with a L{error.DomainError}. - """ - self._assertMessageRcodeForError(error.DomainError(), dns.ENAME) - - - def test_gotResolverErrorAuthoritativeDomainError(self): - """ - L{server.DNSServerFactory.gotResolver} triggers a response message with - an C{rCode} of L{dns.ENAME} if supplied with a - L{error.AuthoritativeDomainError}. - """ - self._assertMessageRcodeForError( - error.AuthoritativeDomainError(), dns.ENAME) - - - def test_gotResolverErrorOtherError(self): - """ - L{server.DNSServerFactory.gotResolver} triggers a response message with - an C{rCode} of L{dns.ESERVER} if supplied with another type of error and - logs the error. - """ - self._assertMessageRcodeForError(KeyError(), dns.ESERVER) - e = self.flushLoggedErrors(KeyError) - self.assertEqual(len(e), 1) - - - def test_gotResolverErrorLogging(self): - """ - L{server.DNSServerFactory.gotResolver} logs a message if C{verbose > 0}. - """ - f = NoResponseDNSServerFactory(verbose=1) - assertLogMessage( - self, - ["Lookup failed"], - f.gotResolverError, - failure.Failure(error.DomainError()), - protocol=NoopProtocol(), message=dns.Message(), address=None) - - - def test_gotResolverErrorResetsResponseAttributes(self): - """ - L{server.DNSServerFactory.gotResolverError} does not allow request - attributes to leak into the response ie it sends a response with AD, CD - set to 0 and empty response record sections. - """ - factory = server.DNSServerFactory() - responses = [] - factory.sendReply = ( - lambda protocol, response, address: responses.append(response) - ) - request = dns.Message(authenticData=True, checkingDisabled=True) - request.answers = [object(), object()] - request.authority = [object(), object()] - request.additional = [object(), object()] - factory.gotResolverError( - failure.Failure(error.DomainError()), - protocol=None, message=request, address=None - ) - - self.assertEqual([dns.Message(rCode=3, answer=True)], responses) - - - def test_gotResolverResponseResetsResponseAttributes(self): - """ - L{server.DNSServerFactory.gotResolverResponse} does not allow request - attributes to leak into the response ie it sends a response with AD, CD - set to 0 and none of the records in the request answer sections are - copied to the response. - """ - factory = server.DNSServerFactory() - responses = [] - factory.sendReply = ( - lambda protocol, response, address: responses.append(response) - ) - request = dns.Message(authenticData=True, checkingDisabled=True) - request.answers = [object(), object()] - request.authority = [object(), object()] - request.additional = [object(), object()] - - factory.gotResolverResponse( - ([], [], []), - protocol=None, message=request, address=None - ) - - self.assertEqual([dns.Message(rCode=0, answer=True)], responses) - - - def test_sendReplyWithAddress(self): - """ - If L{server.DNSServerFactory.sendReply} is supplied with a protocol - *and* an address tuple it will supply that address to - C{protocol.writeMessage}. - """ - m = dns.Message() - dummyAddress = object() - f = server.DNSServerFactory() - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.sendReply, - protocol=RaisingProtocol(), - message=m, - address=dummyAddress) - args, kwargs = e.args - self.assertEqual(args, (m, dummyAddress)) - self.assertEqual(kwargs, {}) - - - def test_sendReplyWithoutAddress(self): - """ - If L{server.DNSServerFactory.sendReply} is supplied with a protocol but - no address tuple it will supply only a message to - C{protocol.writeMessage}. - """ - m = dns.Message() - f = server.DNSServerFactory() - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.sendReply, - protocol=RaisingProtocol(), - message=m, - address=None) - args, kwargs = e.args - self.assertEqual(args, (m,)) - self.assertEqual(kwargs, {}) - - - def test_sendReplyLoggingNoAnswers(self): - """ - If L{server.DNSServerFactory.sendReply} logs a "no answers" message if - the supplied message has no answers. - """ - self.patch(server.time, 'time', lambda: 2) - m = dns.Message() - m.timeReceived = 1 - f = server.DNSServerFactory(verbose=2) - assertLogMessage( - self, - ["Replying with no answers", "Processed query in 1.000 seconds"], - f.sendReply, - protocol=NoopProtocol(), - message=m, - address=None) - - - def test_sendReplyLoggingWithAnswers(self): - """ - If L{server.DNSServerFactory.sendReply} logs a message for answers, - authority, additional if the supplied a message has records in any of - those sections. - """ - self.patch(server.time, 'time', lambda: 2) - m = dns.Message() - m.answers.append(dns.RRHeader(payload=dns.Record_A('127.0.0.1'))) - m.authority.append(dns.RRHeader(payload=dns.Record_A('127.0.0.1'))) - m.additional.append(dns.RRHeader(payload=dns.Record_A('127.0.0.1'))) - m.timeReceived = 1 - f = server.DNSServerFactory(verbose=2) - assertLogMessage( - self, - ['Answers are ', - 'Authority is ', - 'Additional is ', - 'Processed query in 1.000 seconds'], - f.sendReply, - protocol=NoopProtocol(), - message=m, - address=None) - - - def test_handleInverseQuery(self): - """ - L{server.DNSServerFactory.handleInverseQuery} triggers the sending of a - response message with C{rCode} set to L{dns.ENOTIMP}. - """ - f = server.DNSServerFactory() - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.handleInverseQuery, - message=dns.Message(), protocol=RaisingProtocol(), address=None) - (message,), kwargs = e.args - - self.assertEqual(message.rCode, dns.ENOTIMP) - - - def test_handleInverseQueryLogging(self): - """ - L{server.DNSServerFactory.handleInverseQuery} logs the message origin - address if C{verbose > 0}. - """ - f = NoResponseDNSServerFactory(verbose=1) - assertLogMessage( - self, - ["Inverse query from ('::1', 53)"], - f.handleInverseQuery, - message=dns.Message(), - protocol=NoopProtocol(), - address=('::1', 53)) - - - def test_handleStatus(self): - """ - L{server.DNSServerFactory.handleStatus} triggers the sending of a - response message with C{rCode} set to L{dns.ENOTIMP}. - """ - f = server.DNSServerFactory() - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.handleStatus, - message=dns.Message(), protocol=RaisingProtocol(), address=None) - (message,), kwargs = e.args - - self.assertEqual(message.rCode, dns.ENOTIMP) - - - def test_handleStatusLogging(self): - """ - L{server.DNSServerFactory.handleStatus} logs the message origin address - if C{verbose > 0}. - """ - f = NoResponseDNSServerFactory(verbose=1) - assertLogMessage( - self, - ["Status request from ('::1', 53)"], - f.handleStatus, - message=dns.Message(), - protocol=NoopProtocol(), - address=('::1', 53)) - - - def test_handleNotify(self): - """ - L{server.DNSServerFactory.handleNotify} triggers the sending of a - response message with C{rCode} set to L{dns.ENOTIMP}. - """ - f = server.DNSServerFactory() - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.handleNotify, - message=dns.Message(), protocol=RaisingProtocol(), address=None) - (message,), kwargs = e.args - - self.assertEqual(message.rCode, dns.ENOTIMP) - - - def test_handleNotifyLogging(self): - """ - L{server.DNSServerFactory.handleNotify} logs the message origin address - if C{verbose > 0}. - """ - f = NoResponseDNSServerFactory(verbose=1) - assertLogMessage( - self, - ["Notify message from ('::1', 53)"], - f.handleNotify, - message=dns.Message(), - protocol=NoopProtocol(), - address=('::1', 53)) - - - def test_handleOther(self): - """ - L{server.DNSServerFactory.handleOther} triggers the sending of a - response message with C{rCode} set to L{dns.ENOTIMP}. - """ - f = server.DNSServerFactory() - e = self.assertRaises( - RaisingProtocol.WriteMessageArguments, - f.handleOther, - message=dns.Message(), protocol=RaisingProtocol(), address=None) - (message,), kwargs = e.args - - self.assertEqual(message.rCode, dns.ENOTIMP) - - - def test_handleOtherLogging(self): - """ - L{server.DNSServerFactory.handleOther} logs the message origin address - if C{verbose > 0}. - """ - f = NoResponseDNSServerFactory(verbose=1) - assertLogMessage( - self, - ["Unknown op code (0) from ('::1', 53)"], - f.handleOther, - message=dns.Message(), - protocol=NoopProtocol(), - address=('::1', 53)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_srvconnect.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_srvconnect.py deleted file mode 100644 index 2997a9a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_srvconnect.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.names.srvconnect}. -""" - -from twisted.internet import defer, protocol -from twisted.names import client, dns, srvconnect -from twisted.names.common import ResolverBase -from twisted.names.error import DNSNameError -from twisted.internet.error import DNSLookupError, ServiceNameUnknownError -from twisted.trial import unittest -from twisted.test.proto_helpers import MemoryReactor - - -class FakeResolver(ResolverBase): - """ - Resolver that only gives out one given result. - - Either L{results} or L{failure} must be set and will be used for - the return value of L{_lookup} - - @ivar results: List of L{dns.RRHeader} for the desired result. - @type results: C{list} - @ivar failure: Failure with an exception from L{twisted.names.error}. - @type failure: L{Failure} - """ - - def __init__(self, results=None, failure=None): - self.results = results - self.failure = failure - - def _lookup(self, name, cls, qtype, timeout): - """ - Return the result or failure on lookup. - """ - if self.results is not None: - return defer.succeed((self.results, [], [])) - else: - return defer.fail(self.failure) - - - -class DummyFactory(protocol.ClientFactory): - """ - Dummy client factory that stores the reason of connection failure. - """ - def __init__(self): - self.reason = None - - def clientConnectionFailed(self, connector, reason): - self.reason = reason - - - -class SRVConnectorTests(unittest.TestCase): - """ - Tests for L{srvconnect.SRVConnector}. - """ - - def setUp(self): - self.patch(client, 'theResolver', FakeResolver()) - self.reactor = MemoryReactor() - self.factory = DummyFactory() - self.connector = srvconnect.SRVConnector(self.reactor, 'xmpp-server', - 'example.org', self.factory) - - - def test_SRVPresent(self): - """ - Test connectTCP gets called with the address from the SRV record. - """ - payload = dns.Record_SRV(port=6269, target='host.example.org', ttl=60) - client.theResolver.results = [dns.RRHeader(name='example.org', - type=dns.SRV, - cls=dns.IN, ttl=60, - payload=payload)] - self.connector.connect() - - self.assertIs(None, self.factory.reason) - self.assertEqual( - self.reactor.tcpClients.pop()[:2], ('host.example.org', 6269)) - - - def test_SRVNotPresent(self): - """ - Test connectTCP gets called with fallback parameters on NXDOMAIN. - """ - client.theResolver.failure = DNSNameError('example.org') - self.connector.connect() - - self.assertIs(None, self.factory.reason) - self.assertEqual( - self.reactor.tcpClients.pop()[:2], ('example.org', 'xmpp-server')) - - - def test_SRVNoResult(self): - """ - Test connectTCP gets called with fallback parameters on empty result. - """ - client.theResolver.results = [] - self.connector.connect() - - self.assertIs(None, self.factory.reason) - self.assertEqual( - self.reactor.tcpClients.pop()[:2], ('example.org', 'xmpp-server')) - - - def test_SRVNoResultUnknownServiceDefaultPort(self): - """ - connectTCP gets called with default port if the service is not defined. - """ - self.connector = srvconnect.SRVConnector(self.reactor, - 'thisbetternotexist', - 'example.org', self.factory, - defaultPort=5222) - - client.theResolver.failure = ServiceNameUnknownError() - self.connector.connect() - - self.assertIs(None, self.factory.reason) - self.assertEqual( - self.reactor.tcpClients.pop()[:2], ('example.org', 5222)) - - - def test_SRVNoResultUnknownServiceNoDefaultPort(self): - """ - Connect fails on no result, unknown service and no default port. - """ - self.connector = srvconnect.SRVConnector(self.reactor, - 'thisbetternotexist', - 'example.org', self.factory) - - client.theResolver.failure = ServiceNameUnknownError() - self.connector.connect() - - self.assertTrue(self.factory.reason.check(ServiceNameUnknownError)) - - - def test_SRVBadResult(self): - """ - Test connectTCP gets called with fallback parameters on bad result. - """ - client.theResolver.results = [dns.RRHeader(name='example.org', - type=dns.CNAME, - cls=dns.IN, ttl=60, - payload=None)] - self.connector.connect() - - self.assertIs(None, self.factory.reason) - self.assertEqual( - self.reactor.tcpClients.pop()[:2], ('example.org', 'xmpp-server')) - - - def test_SRVNoService(self): - """ - Test that connecting fails when no service is present. - """ - payload = dns.Record_SRV(port=5269, target='.', ttl=60) - client.theResolver.results = [dns.RRHeader(name='example.org', - type=dns.SRV, - cls=dns.IN, ttl=60, - payload=payload)] - self.connector.connect() - - self.assertIsNot(None, self.factory.reason) - self.factory.reason.trap(DNSLookupError) - self.assertEqual(self.reactor.tcpClients, []) - - - def test_unicodeDomain(self): - """ - L{srvconnect.SRVConnector} automatically encodes unicode domain using - C{idna} encoding. - """ - self.connector = srvconnect.SRVConnector( - self.reactor, 'xmpp-client', u'\u00e9chec.example.org', - self.factory) - self.assertIsInstance(self.connector.domain, bytes) - self.assertEqual(b'xn--chec-9oa.example.org', self.connector.domain) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_tap.py deleted file mode 100644 index 0c9fe01..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_tap.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.names.tap}. -""" - -from twisted.trial.unittest import TestCase -from twisted.python.usage import UsageError -from twisted.names.tap import Options, _buildResolvers -from twisted.names.dns import PORT -from twisted.names.secondary import SecondaryAuthorityService -from twisted.names.resolve import ResolverChain -from twisted.names.client import Resolver - -class OptionsTests(TestCase): - """ - Tests for L{Options}, defining how command line arguments for the DNS server - are parsed. - """ - def test_malformedSecondary(self): - """ - If the value supplied for an I{--secondary} option does not provide a - server IP address, optional port number, and domain name, - L{Options.parseOptions} raises L{UsageError}. - """ - options = Options() - self.assertRaises( - UsageError, options.parseOptions, ['--secondary', '']) - self.assertRaises( - UsageError, options.parseOptions, ['--secondary', '1.2.3.4']) - self.assertRaises( - UsageError, options.parseOptions, ['--secondary', '1.2.3.4:hello']) - self.assertRaises( - UsageError, options.parseOptions, - ['--secondary', '1.2.3.4:hello/example.com']) - - - def test_secondary(self): - """ - An argument of the form C{"ip/domain"} is parsed by L{Options} for the - I{--secondary} option and added to its list of secondaries, using the - default DNS port number. - """ - options = Options() - options.parseOptions(['--secondary', '1.2.3.4/example.com']) - self.assertEqual( - [(('1.2.3.4', PORT), ['example.com'])], options.secondaries) - - - def test_secondaryExplicitPort(self): - """ - An argument of the form C{"ip:port/domain"} can be used to specify an - alternate port number for which to act as a secondary. - """ - options = Options() - options.parseOptions(['--secondary', '1.2.3.4:5353/example.com']) - self.assertEqual( - [(('1.2.3.4', 5353), ['example.com'])], options.secondaries) - - - def test_secondaryAuthorityServices(self): - """ - After parsing I{--secondary} options, L{Options} constructs a - L{SecondaryAuthorityService} instance for each configured secondary. - """ - options = Options() - options.parseOptions(['--secondary', '1.2.3.4:5353/example.com', - '--secondary', '1.2.3.5:5354/example.com']) - self.assertEqual(len(options.svcs), 2) - secondary = options.svcs[0] - self.assertIsInstance(options.svcs[0], SecondaryAuthorityService) - self.assertEqual(secondary.primary, '1.2.3.4') - self.assertEqual(secondary._port, 5353) - secondary = options.svcs[1] - self.assertIsInstance(options.svcs[1], SecondaryAuthorityService) - self.assertEqual(secondary.primary, '1.2.3.5') - self.assertEqual(secondary._port, 5354) - - - def test_recursiveConfiguration(self): - """ - Recursive DNS lookups, if enabled, should be a last-resort option. - Any other lookup method (cache, local lookup, etc.) should take - precedence over recursive lookups - """ - options = Options() - options.parseOptions(['--hosts-file', 'hosts.txt', '--recursive']) - ca, cl = _buildResolvers(options) - - # Extra cleanup, necessary on POSIX because client.Resolver doesn't know - # when to stop parsing resolv.conf. See #NNN for improving this. - for x in cl: - if isinstance(x, ResolverChain): - recurser = x.resolvers[-1] - if isinstance(recurser, Resolver): - recurser._parseCall.cancel() - - self.assertIsInstance(cl[-1], ResolverChain) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_util.py deleted file mode 100644 index d40743d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/test/test_util.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Utilities for Twisted.names tests. -""" - -from __future__ import division, absolute_import - -from random import randrange - -from zope.interface import implementer -from zope.interface.verify import verifyClass - -from twisted.internet.address import IPv4Address -from twisted.internet.defer import succeed -from twisted.internet.task import Clock -from twisted.internet.interfaces import IReactorUDP, IUDPTransport - - - -@implementer(IUDPTransport) -class MemoryDatagramTransport(object): - """ - This L{IUDPTransport} implementation enforces the usual connection rules - and captures sent traffic in a list for later inspection. - - @ivar _host: The host address to which this transport is bound. - @ivar _protocol: The protocol connected to this transport. - @ivar _sentPackets: A C{list} of two-tuples of the datagrams passed to - C{write} and the addresses to which they are destined. - - @ivar _connectedTo: C{None} if this transport is unconnected, otherwise an - address to which all traffic is supposedly sent. - - @ivar _maxPacketSize: An C{int} giving the maximum length of a datagram - which will be successfully handled by C{write}. - """ - def __init__(self, host, protocol, maxPacketSize): - self._host = host - self._protocol = protocol - self._sentPackets = [] - self._connectedTo = None - self._maxPacketSize = maxPacketSize - - - def getHost(self): - """ - Return the address which this transport is pretending to be bound - to. - """ - return IPv4Address('UDP', *self._host) - - - def connect(self, host, port): - """ - Connect this transport to the given address. - """ - if self._connectedTo is not None: - raise ValueError("Already connected") - self._connectedTo = (host, port) - - - def write(self, datagram, addr=None): - """ - Send the given datagram. - """ - if addr is None: - addr = self._connectedTo - if addr is None: - raise ValueError("Need an address") - if len(datagram) > self._maxPacketSize: - raise ValueError("Packet too big") - self._sentPackets.append((datagram, addr)) - - - def stopListening(self): - """ - Shut down this transport. - """ - self._protocol.stopProtocol() - return succeed(None) - - - def setBroadcastAllowed(self, enabled): - """ - Dummy implementation to satisfy L{IUDPTransport}. - """ - pass - - - def getBroadcastAllowed(self): - """ - Dummy implementation to satisfy L{IUDPTransport}. - """ - pass - - -verifyClass(IUDPTransport, MemoryDatagramTransport) - - - -@implementer(IReactorUDP) -class MemoryReactor(Clock): - """ - An L{IReactorTime} and L{IReactorUDP} provider. - - Time is controlled deterministically via the base class, L{Clock}. UDP is - handled in-memory by connecting protocols to instances of - L{MemoryDatagramTransport}. - - @ivar udpPorts: A C{dict} mapping port numbers to instances of - L{MemoryDatagramTransport}. - """ - def __init__(self): - Clock.__init__(self) - self.udpPorts = {} - - - def listenUDP(self, port, protocol, interface='', maxPacketSize=8192): - """ - Pretend to bind a UDP port and connect the given protocol to it. - """ - if port == 0: - while True: - port = randrange(1, 2 ** 16) - if port not in self.udpPorts: - break - if port in self.udpPorts: - raise ValueError("Address in use") - transport = MemoryDatagramTransport( - (interface, port), protocol, maxPacketSize) - self.udpPorts[port] = transport - protocol.makeConnection(transport) - return transport - -verifyClass(IReactorUDP, MemoryReactor) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/NEWS deleted file mode 100644 index 3343918..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/NEWS +++ /dev/null @@ -1,412 +0,0 @@ -Ticket numbers in this file can be looked up by visiting -http://twistedmatrix.com/trac/ticket/ - -Twisted Names 15.2.1 (2015-05-23) -================================= - -No significant changes have been made for this release. - - -Twisted Names 15.2.0 (2015-05-18) -================================= - -No significant changes have been made for this release. - - -Twisted Names 15.1.0 (2015-04-02) -================================= - -No significant changes have been made for this release. - -Other ------ - - #7728 - - -Twisted Names 15.0.0 (2015-01-24) -================================= - -Bugfixes --------- - - twisted.names.secondary.SecondaryAuthority can now answer queries - again (broken since 13.2.0). (#7408) - -Other ------ - - #7352 - - -Twisted Names 14.0.2 (2014-09-18) -================================= - -No significant changes have been made for this release. - - -Twisted Names 14.0.1 (2014-09-17) -================================= - -No significant changes have been made for this release. - - -Twisted Names 14.0.0 (2014-05-08) -================================= - -Features --------- - - twisted.names.root.Resolver now accepts a resolverFactory argument, - which makes it possible to control how root.Resolver performs - iterative queries to authoritative nameservers. (#6095) - - twisted.names.dns.Message now has a repr method which shows only - those instance flags, fields and sections which are set to non- - default values. (#6847) - - twisted.names.dns.Message now support rich comparison. (#6848) - -Bugfixes --------- - - twisted.names.server.DNSServerFactory now responds with messages - whose flags and fields are reset to their default values instead of - copying these from the request. This means that AD and CD flags, - and EDNS OPT records in the request are no longer mirrored back to - the client. (#6645) - -Improved Documentation ----------------------- - - twisted.names now has narrative documentation showing how to create - a custom DNS server. (#6864) - - twisted.names.server now has full API documentation. (#6886) - - twisted.names now has narrative documentation explaining how to use - its client APIs. (#6925) - - twisted.names now has narrative documentation and examples showing - how to perform reverse DNS lookups. (#6969) - -Other ------ - - #5675, #6222, #6672, #6696, #6887, #6940, #6975, #6990 - - -Twisted Names 13.2.0 (2013-10-29) -================================= - -Features --------- - - twisted.names.authority.FileAuthority now considers any AAAA it - knows about for inclusion in the additional section of a response - (following the same logic previously used for including A records - there). (#6642) - - twisted.names.dns.Message now allows encoding and decoding of the - Authentic Data (AD) and Checking Disabled (CD) flags described in - RFC2535. (#6680) - -Bugfixes --------- - - twisted.names.resolve.ResolverChain now returns a - twisted.names.error.DomainError failure if its resolvers list is - empty. (#5992) - - twisted.names.authority.FileAuthority now only returns - AuthoritativeDomainError (NXDOMAIN) for names which are subdomains. - (#6475) - - The Deferred returned by twisted.names.client.Resolver.queryTCP now - fires with an error if the TCP connection attempt fails. (#6658) - -Improved Documentation ----------------------- - - Use zope.interface.moduleProvides to allow pydoctor to properly - document the twisted.names.client.lookup* functions. (#6328) - -Other ------ - - #5387, #5668, #6563, #6655 - - -Twisted Names 13.1.0 (2013-06-23) -================================= - -No significant changes have been made for this release. - -Other ------ - - #3908, #6381 - - -Twisted Names 13.0.0 (2013-03-19) -================================= - -Features --------- - - twisted.names.dns.Name and twisted.names.srvconnect.SRVConnector - now support unicode domain names, automatically converting using - the idna encoding. (#6245) - -Improved Documentation ----------------------- - - The API documentation for IResolver and its implementations has - been updated and consolidated in - twisted.internet.interfaces.IResolver. (#4685) - -Deprecations and Removals -------------------------- - - The retry, Resolver.discoveredAuthority, lookupNameservers, - lookupAddress, extractAuthority, and discoverAuthority APIs in - twisted.names.root have been deprecated since 10.0 and have been - removed. (#5564) - -Other ------ - - #5596, #6246, #6297 - - -Twisted Names 12.3.0 (2012-12-20) -================================= - -Deprecations and Removals -------------------------- - - The `protocol` attribute of twisted.names.client.Resolver, - deprecated since Twisted 8.2, has been removed. (#6045) - - twisted.names.hosts.Resolver is no longer a - `twisted.persisted.styles.Versioned` subclass. (#6092) - -Other ------ - - #5594, #6056, #6057, #6058, #6059, #6093 - - -Twisted Names 12.2.0 (2012-08-26) -================================= - -Features --------- - - twisted.names.srvconnect.SRVConnector now takes a default port to - use when SRV lookup fails. (#3456) - -Other ------ - - #5647 - - -Twisted Names 12.1.0 (2012-06-02) -================================= - -Features --------- - - "twistd dns" secondary server functionality and - twisted.names.secondary now support retrieving zone information - from a master running on a non-standard DNS port. (#5468) - -Bugfixes --------- - - twisted.names.dns.DNSProtocol instances no longer throw an - exception when disconnecting. (#5471) - - twisted.names.tap.makeService (thus also "twistd dns") now makes a - DNS server which gives precedence to the hosts file from its - configuration over the remote DNS servers from its configuration. - (#5524) - - twisted.name.cache.CacheResolver now makes sure TTLs on returned - results are never negative. (#5579) - - twisted.names.cache.CacheResolver entries added via the initializer - are now timed out correctly. (#5638) - -Improved Documentation ----------------------- - - The examples now contain instructions on how to run them and - descriptions in the examples index. (#5588) - -Deprecations and Removals -------------------------- - - The deprecated twisted.names.dns.Record_mx.exchange attribute was - removed. (#4549) - - -Twisted Names 12.0.0 (2012-02-10) -================================= - -Bugfixes --------- - - twisted.names.dns.Message now sets the `auth` flag on RRHeader - instances it creates to reflect the authority of the message - itself. (#5421) - - -Twisted Names 11.1.0 (2011-11-15) -================================= - -Features --------- - - twisted.names.dns.Message now parses records of unknown type into - instances of a new `UnknownType` class. (#4603) - -Bugfixes --------- - - twisted.names.dns.Name now detects loops in names it is decoding - and raises an exception. Previously it would follow the loop - forever, allowing a remote denial of service attack against any - twisted.names client or server. (#5064) - - twisted.names.hosts.Resolver now supports IPv6 addresses; its - lookupAddress method now filters them out and its lookupIPV6Address - method is now implemented. (#5098) - - -Twisted Names 11.0.0 (2011-04-01) -================================= - -No significant changes have been made for this release. - - -Twisted Names 10.2.0 (2010-11-29) -================================= - -Features --------- - - twisted.names.server can now serve SPF resource records using - twisted.names.dns.Record_SPF. twisted.names.client can query for - them using lookupSenderPolicy. (#3928) - -Bugfixes --------- - - twisted.names.common.extractRecords doesn't try to close the - transport anymore in case of recursion, as it's done by the - Resolver itself now. (#3998) - -Improved Documentation ----------------------- - - Tidied up the Twisted Names documentation for easier conversion. - (#4573) - - -Twisted Names 10.1.0 (2010-06-27) -================================= - -Features --------- - - twisted.names.dns.Message now uses a specially constructed - dictionary for looking up record types. This yields a significant - performance improvement on PyPy. (#4283) - - -Twisted Names 10.0.0 (2010-03-01) -================================= - -Bugfixes --------- - - twisted.names.root.Resolver no longer leaks UDP sockets while - resolving names. (#970) - -Deprecations and Removals -------------------------- - - Several top-level functions in twisted.names.root are now - deprecated. (#970) - -Other ------ - - #4066 - - -Twisted Names 9.0.0 (2009-11-24) -================================ - -Deprecations and Removals -------------------------- - - client.ThreadedResolver is deprecated in favor of - twisted.internet.base.ThreadedResolver (#3710) - -Other ------ - - #3540, #3560, #3712, #3750, #3990 - - -Names 8.2.0 (2008-12-16) -======================== - -Features --------- - - The NAPTR record type is now supported (#2276) - -Fixes ------ - - Make client.Resolver less vulnerable to the Birthday Paradox attack by - avoiding sending duplicate queries when it's not necessary (#3347) - - client.Resolver now uses a random source port for each DNS request (#3342) - - client.Resolver now uses a full 16 bits of randomness for message IDs, - instead of 10 which it previously used (#3342) - - All record types now have value-based equality and a string representation - (#2935) - -Other ------ - - #1622, #3424 - - -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Fixes ------ - - - Refactor DNSDatagramProtocol and DNSProtocol to use same base class (#2414) - - Change Resolver to query specified nameservers in specified order, instead - of reverse order. (#2290) - - Make SRVConnector work with bad results and NXDOMAIN responses. - (#1908, #2777) - - Handle write errors happening in dns queries, to have correct deferred - failures. (#2492) - - Fix the value of OP_NOTIFY and add a definition for OP_UPDATE. (#2945) - -Misc ----- - - #2685, #2936, #2581, #2847 - - -0.4.0 (2007-01-06) -================== - -Features --------- - - - In the twisted.names client, DNS responses which represent errors - are now translated to informative exception objects, rather than - empty lists. This means that client requests which fail will now - errback their Deferreds (#2248) - -Fixes ------ - - A major DoS vulnerability in the UDP DNS server was fixed (#1708) - -Misc ----- - - #1799, #1636, #2149, #2181 - - -0.3.0 (2006-05-21) -================== - -Features --------- - - Some docstring improvements - -Fixes ------ - - Fix a problem where the response for the first query with a - newly-created Resolver object would be dropped.(#1447) - - Misc: #1581, #1583 - - -0.2.0 -===== - - Fix occassional TCP connection leak in gethostbyname() - - Fix TCP connection leak in recursive lookups - - Remove deprecated use of Deferred.setTimeout - - Improved test coverage for zone transfers - -0.1.0 -===== - - Fix TCP connection leak in zone transfers - - Handle empty or missing resolv.conf as if 127.0.0.1 was specified - - Don't use blocking kernel entropy sources - - Retry logic now properly tries all specified servers. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/README deleted file mode 100644 index c2235e7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/README +++ /dev/null @@ -1,3 +0,0 @@ -Twisted Names 15.2.1 - -Twisted Names depends on Twisted Core. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/setup.py deleted file mode 100644 index f543e44..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/names/topfiles/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - extraMeta = dict( - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Internet :: Name Service (DNS)", - "Topic :: Software Development :: Libraries :: Python Modules", - ]) - - dist.setup( - twisted_subproject="names", - # metadata - name="Twisted Names", - description="A Twisted DNS implementation.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - url="http://twistedmatrix.com/trac/wiki/TwistedNames", - license="MIT", - long_description="""\ -Twisted Names is both a domain name server as well as a client -resolver library. Twisted Names comes with an "out of the box" -nameserver which can read most BIND-syntax zone files as well as a -simple Python-based configuration format. Twisted Names can act as an -authoritative server, perform zone transfers from a master to act as a -secondary, act as a caching nameserver, or any combination of -these. Twisted Names' client resolver library provides functions to -query for all commonly used record types as well as a replacement for -the blocking gethostbyname() function provided by the Python stdlib -socket module. -""", - **extraMeta) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/__init__.py deleted file mode 100644 index 98d6c03..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted News: A NNTP-based news service. -""" - -from twisted.news._version import version -__version__ = version.short() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/_version.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/_version.py deleted file mode 100644 index f6629e5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/_version.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This is an auto-generated file. Do not edit it. - -""" -Provides Twisted version information. -""" - -from twisted.python import versions -version = versions.Version('twisted.news', 15, 2, 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/database.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/database.py deleted file mode 100644 index dda5fbe..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/database.py +++ /dev/null @@ -1,1051 +0,0 @@ -# -*- test-case-name: twisted.news.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -News server backend implementations. -""" - -import getpass, pickle, time, socket -import os -import StringIO -from hashlib import md5 -from email.Message import Message -from email.Generator import Generator -from zope.interface import implements, Interface - -from twisted.news.nntp import NNTPError -from twisted.mail import smtp -from twisted.internet import defer -from twisted.enterprise import adbapi -from twisted.persisted import dirdbm - - - -ERR_NOGROUP, ERR_NOARTICLE = range(2, 4) # XXX - put NNTP values here (I guess?) - -OVERVIEW_FMT = [ - 'Subject', 'From', 'Date', 'Message-ID', 'References', - 'Bytes', 'Lines', 'Xref' -] - -def hexdigest(md5): #XXX: argh. 1.5.2 doesn't have this. - return ''.join(map(lambda x: hex(ord(x))[2:], md5.digest())) - -class Article: - def __init__(self, head, body): - self.body = body - self.headers = {} - header = None - for line in head.split('\r\n'): - if line[0] in ' \t': - i = list(self.headers[header]) - i[1] += '\r\n' + line - else: - i = line.split(': ', 1) - header = i[0].lower() - self.headers[header] = tuple(i) - - if not self.getHeader('Message-ID'): - s = str(time.time()) + self.body - id = hexdigest(md5(s)) + '@' + socket.gethostname() - self.putHeader('Message-ID', '<%s>' % id) - - if not self.getHeader('Bytes'): - self.putHeader('Bytes', str(len(self.body))) - - if not self.getHeader('Lines'): - self.putHeader('Lines', str(self.body.count('\n'))) - - if not self.getHeader('Date'): - self.putHeader('Date', time.ctime(time.time())) - - - def getHeader(self, header): - h = header.lower() - if h in self.headers: - return self.headers[h][1] - else: - return '' - - - def putHeader(self, header, value): - self.headers[header.lower()] = (header, value) - - - def textHeaders(self): - headers = [] - for i in self.headers.values(): - headers.append('%s: %s' % i) - return '\r\n'.join(headers) + '\r\n' - - def overview(self): - xover = [] - for i in OVERVIEW_FMT: - xover.append(self.getHeader(i)) - return xover - - -class NewsServerError(Exception): - pass - - -class INewsStorage(Interface): - """ - An interface for storing and requesting news articles - """ - - def listRequest(): - """ - Returns a deferred whose callback will be passed a list of 4-tuples - containing (name, max index, min index, flags) for each news group - """ - - - def subscriptionRequest(): - """ - Returns a deferred whose callback will be passed the list of - recommended subscription groups for new server users - """ - - - def postRequest(message): - """ - Returns a deferred whose callback will be invoked if 'message' - is successfully posted to one or more specified groups and - whose errback will be invoked otherwise. - """ - - - def overviewRequest(): - """ - Returns a deferred whose callback will be passed the a list of - headers describing this server's overview format. - """ - - - def xoverRequest(group, low, high): - """ - Returns a deferred whose callback will be passed a list of xover - headers for the given group over the given range. If low is None, - the range starts at the first article. If high is None, the range - ends at the last article. - """ - - - def xhdrRequest(group, low, high, header): - """ - Returns a deferred whose callback will be passed a list of XHDR data - for the given group over the given range. If low is None, - the range starts at the first article. If high is None, the range - ends at the last article. - """ - - - def listGroupRequest(group): - """ - Returns a deferred whose callback will be passed a two-tuple of - (group name, [article indices]) - """ - - - def groupRequest(group): - """ - Returns a deferred whose callback will be passed a five-tuple of - (group name, article count, highest index, lowest index, group flags) - """ - - - def articleExistsRequest(id): - """ - Returns a deferred whose callback will be passed with a true value - if a message with the specified Message-ID exists in the database - and with a false value otherwise. - """ - - - def articleRequest(group, index, id = None): - """ - Returns a deferred whose callback will be passed a file-like object - containing the full article text (headers and body) for the article - of the specified index in the specified group, and whose errback - will be invoked if the article or group does not exist. If id is - not None, index is ignored and the article with the given Message-ID - will be returned instead, along with its index in the specified - group. - """ - - - def headRequest(group, index): - """ - Returns a deferred whose callback will be passed the header for - the article of the specified index in the specified group, and - whose errback will be invoked if the article or group does not - exist. - """ - - - def bodyRequest(group, index): - """ - Returns a deferred whose callback will be passed the body for - the article of the specified index in the specified group, and - whose errback will be invoked if the article or group does not - exist. - """ - -class NewsStorage: - """ - Backwards compatibility class -- There is no reason to inherit from this, - just implement INewsStorage instead. - """ - def listRequest(self): - raise NotImplementedError() - def subscriptionRequest(self): - raise NotImplementedError() - def postRequest(self, message): - raise NotImplementedError() - def overviewRequest(self): - return defer.succeed(OVERVIEW_FMT) - def xoverRequest(self, group, low, high): - raise NotImplementedError() - def xhdrRequest(self, group, low, high, header): - raise NotImplementedError() - def listGroupRequest(self, group): - raise NotImplementedError() - def groupRequest(self, group): - raise NotImplementedError() - def articleExistsRequest(self, id): - raise NotImplementedError() - def articleRequest(self, group, index, id = None): - raise NotImplementedError() - def headRequest(self, group, index): - raise NotImplementedError() - def bodyRequest(self, group, index): - raise NotImplementedError() - - - -class _ModerationMixin: - """ - Storage implementations can inherit from this class to get the easy-to-use - C{notifyModerators} method which will take care of sending messages which - require moderation to a list of moderators. - """ - sendmail = staticmethod(smtp.sendmail) - - def notifyModerators(self, moderators, article): - """ - Send an article to a list of group moderators to be moderated. - - @param moderators: A C{list} of C{str} giving RFC 2821 addresses of - group moderators to notify. - - @param article: The article requiring moderation. - @type article: L{Article} - - @return: A L{Deferred} which fires with the result of sending the email. - """ - # Moderated postings go through as long as they have an Approved - # header, regardless of what the value is - group = article.getHeader('Newsgroups') - subject = article.getHeader('Subject') - - if self._sender is None: - # This case should really go away. This isn't a good default. - sender = 'twisted-news@' + socket.gethostname() - else: - sender = self._sender - - msg = Message() - msg['Message-ID'] = smtp.messageid() - msg['From'] = sender - msg['To'] = ', '.join(moderators) - msg['Subject'] = 'Moderate new %s message: %s' % (group, subject) - msg['Content-Type'] = 'message/rfc822' - - payload = Message() - for header, value in article.headers.values(): - payload.add_header(header, value) - payload.set_payload(article.body) - - msg.attach(payload) - - out = StringIO.StringIO() - gen = Generator(out, False) - gen.flatten(msg) - msg = out.getvalue() - - return self.sendmail(self._mailhost, sender, moderators, msg) - - - -class PickleStorage(_ModerationMixin): - """ - A trivial NewsStorage implementation using pickles - - Contains numerous flaws and is generally unsuitable for any - real applications. Consider yourself warned! - """ - - implements(INewsStorage) - - sharedDBs = {} - - def __init__(self, filename, groups=None, moderators=(), - mailhost=None, sender=None): - """ - @param mailhost: A C{str} giving the mail exchange host which will - accept moderation emails from this server. Must accept emails - destined for any address specified as a moderator. - - @param sender: A C{str} giving the address which will be used as the - sender of any moderation email generated by this server. - """ - self.datafile = filename - self.load(filename, groups, moderators) - self._mailhost = mailhost - self._sender = sender - - - def getModerators(self, groups): - # first see if any groups are moderated. if so, nothing gets posted, - # but the whole messages gets forwarded to the moderator address - moderators = [] - for group in groups: - moderators.extend(self.db['moderators'].get(group, None)) - return filter(None, moderators) - - - def listRequest(self): - "Returns a list of 4-tuples: (name, max index, min index, flags)" - l = self.db['groups'] - r = [] - for i in l: - if len(self.db[i].keys()): - low = min(self.db[i].keys()) - high = max(self.db[i].keys()) + 1 - else: - low = high = 0 - if self.db['moderators'].has_key(i): - flags = 'm' - else: - flags = 'y' - r.append((i, high, low, flags)) - return defer.succeed(r) - - def subscriptionRequest(self): - return defer.succeed(['alt.test']) - - def postRequest(self, message): - cleave = message.find('\r\n\r\n') - headers, article = message[:cleave], message[cleave + 4:] - - a = Article(headers, article) - groups = a.getHeader('Newsgroups').split() - xref = [] - - # Check moderated status - moderators = self.getModerators(groups) - if moderators and not a.getHeader('Approved'): - return self.notifyModerators(moderators, a) - - for group in groups: - if group in self.db: - if len(self.db[group].keys()): - index = max(self.db[group].keys()) + 1 - else: - index = 1 - xref.append((group, str(index))) - self.db[group][index] = a - - if len(xref) == 0: - return defer.fail(None) - - a.putHeader('Xref', '%s %s' % ( - socket.gethostname().split()[0], - ''.join(map(lambda x: ':'.join(x), xref)) - )) - - self.flush() - return defer.succeed(None) - - - def overviewRequest(self): - return defer.succeed(OVERVIEW_FMT) - - - def xoverRequest(self, group, low, high): - if not self.db.has_key(group): - return defer.succeed([]) - r = [] - for i in self.db[group].keys(): - if (low is None or i >= low) and (high is None or i <= high): - r.append([str(i)] + self.db[group][i].overview()) - return defer.succeed(r) - - - def xhdrRequest(self, group, low, high, header): - if not self.db.has_key(group): - return defer.succeed([]) - r = [] - for i in self.db[group].keys(): - if low is None or i >= low and high is None or i <= high: - r.append((i, self.db[group][i].getHeader(header))) - return defer.succeed(r) - - - def listGroupRequest(self, group): - if self.db.has_key(group): - return defer.succeed((group, self.db[group].keys())) - else: - return defer.fail(None) - - def groupRequest(self, group): - if self.db.has_key(group): - if len(self.db[group].keys()): - num = len(self.db[group].keys()) - low = min(self.db[group].keys()) - high = max(self.db[group].keys()) - else: - num = low = high = 0 - flags = 'y' - return defer.succeed((group, num, high, low, flags)) - else: - return defer.fail(ERR_NOGROUP) - - - def articleExistsRequest(self, id): - for group in self.db['groups']: - for a in self.db[group].values(): - if a.getHeader('Message-ID') == id: - return defer.succeed(1) - return defer.succeed(0) - - - def articleRequest(self, group, index, id = None): - if id is not None: - raise NotImplementedError - - if self.db.has_key(group): - if self.db[group].has_key(index): - a = self.db[group][index] - return defer.succeed(( - index, - a.getHeader('Message-ID'), - StringIO.StringIO(a.textHeaders() + '\r\n' + a.body) - )) - else: - return defer.fail(ERR_NOARTICLE) - else: - return defer.fail(ERR_NOGROUP) - - - def headRequest(self, group, index): - if self.db.has_key(group): - if self.db[group].has_key(index): - a = self.db[group][index] - return defer.succeed((index, a.getHeader('Message-ID'), a.textHeaders())) - else: - return defer.fail(ERR_NOARTICLE) - else: - return defer.fail(ERR_NOGROUP) - - - def bodyRequest(self, group, index): - if self.db.has_key(group): - if self.db[group].has_key(index): - a = self.db[group][index] - return defer.succeed((index, a.getHeader('Message-ID'), StringIO.StringIO(a.body))) - else: - return defer.fail(ERR_NOARTICLE) - else: - return defer.fail(ERR_NOGROUP) - - - def flush(self): - f = open(self.datafile, 'w') - pickle.dump(self.db, f) - f.close() - - - def load(self, filename, groups = None, moderators = ()): - if filename in PickleStorage.sharedDBs: - self.db = PickleStorage.sharedDBs[filename] - else: - try: - self.db = pickle.load(open(filename)) - PickleStorage.sharedDBs[filename] = self.db - except IOError: - self.db = PickleStorage.sharedDBs[filename] = {} - self.db['groups'] = groups - if groups is not None: - for i in groups: - self.db[i] = {} - self.db['moderators'] = dict(moderators) - self.flush() - - -class Group: - name = None - flags = '' - minArticle = 1 - maxArticle = 0 - articles = None - - def __init__(self, name, flags = 'y'): - self.name = name - self.flags = flags - self.articles = {} - - -class NewsShelf(_ModerationMixin): - """ - A NewStorage implementation using Twisted's dirdbm persistence module. - """ - - implements(INewsStorage) - - def __init__(self, mailhost, path, sender=None): - """ - @param mailhost: A C{str} giving the mail exchange host which will - accept moderation emails from this server. Must accept emails - destined for any address specified as a moderator. - - @param sender: A C{str} giving the address which will be used as the - sender of any moderation email generated by this server. - """ - self.path = path - self._mailhost = self.mailhost = mailhost - self._sender = sender - - if not os.path.exists(path): - os.mkdir(path) - - self.dbm = dirdbm.Shelf(os.path.join(path, "newsshelf")) - if not len(self.dbm.keys()): - self.initialize() - - - def initialize(self): - # A dictionary of group name/Group instance items - self.dbm['groups'] = dirdbm.Shelf(os.path.join(self.path, 'groups')) - - # A dictionary of group name/email address - self.dbm['moderators'] = dirdbm.Shelf(os.path.join(self.path, 'moderators')) - - # A list of group names - self.dbm['subscriptions'] = [] - - # A dictionary of MessageID strings/xref lists - self.dbm['Message-IDs'] = dirdbm.Shelf(os.path.join(self.path, 'Message-IDs')) - - - def addGroup(self, name, flags): - self.dbm['groups'][name] = Group(name, flags) - - - def addSubscription(self, name): - self.dbm['subscriptions'] = self.dbm['subscriptions'] + [name] - - - def addModerator(self, group, email): - self.dbm['moderators'][group] = email - - - def listRequest(self): - result = [] - for g in self.dbm['groups'].values(): - result.append((g.name, g.maxArticle, g.minArticle, g.flags)) - return defer.succeed(result) - - - def subscriptionRequest(self): - return defer.succeed(self.dbm['subscriptions']) - - - def getModerator(self, groups): - # first see if any groups are moderated. if so, nothing gets posted, - # but the whole messages gets forwarded to the moderator address - for group in groups: - try: - return self.dbm['moderators'][group] - except KeyError: - pass - return None - - - def notifyModerator(self, moderator, article): - """ - Notify a single moderator about an article requiring moderation. - - C{notifyModerators} should be preferred. - """ - return self.notifyModerators([moderator], article) - - - def postRequest(self, message): - cleave = message.find('\r\n\r\n') - headers, article = message[:cleave], message[cleave + 4:] - - article = Article(headers, article) - groups = article.getHeader('Newsgroups').split() - xref = [] - - # Check for moderated status - moderator = self.getModerator(groups) - if moderator and not article.getHeader('Approved'): - return self.notifyModerators([moderator], article) - - - for group in groups: - try: - g = self.dbm['groups'][group] - except KeyError: - pass - else: - index = g.maxArticle + 1 - g.maxArticle += 1 - g.articles[index] = article - xref.append((group, str(index))) - self.dbm['groups'][group] = g - - if not xref: - return defer.fail(NewsServerError("No groups carried: " + ' '.join(groups))) - - article.putHeader('Xref', '%s %s' % (socket.gethostname().split()[0], ' '.join(map(lambda x: ':'.join(x), xref)))) - self.dbm['Message-IDs'][article.getHeader('Message-ID')] = xref - return defer.succeed(None) - - - def overviewRequest(self): - return defer.succeed(OVERVIEW_FMT) - - - def xoverRequest(self, group, low, high): - if not self.dbm['groups'].has_key(group): - return defer.succeed([]) - - if low is None: - low = 0 - if high is None: - high = self.dbm['groups'][group].maxArticle - r = [] - for i in range(low, high + 1): - if self.dbm['groups'][group].articles.has_key(i): - r.append([str(i)] + self.dbm['groups'][group].articles[i].overview()) - return defer.succeed(r) - - - def xhdrRequest(self, group, low, high, header): - if group not in self.dbm['groups']: - return defer.succeed([]) - - if low is None: - low = 0 - if high is None: - high = self.dbm['groups'][group].maxArticle - r = [] - for i in range(low, high + 1): - if i in self.dbm['groups'][group].articles: - r.append((i, self.dbm['groups'][group].articles[i].getHeader(header))) - return defer.succeed(r) - - - def listGroupRequest(self, group): - if self.dbm['groups'].has_key(group): - return defer.succeed((group, self.dbm['groups'][group].articles.keys())) - return defer.fail(NewsServerError("No such group: " + group)) - - - def groupRequest(self, group): - try: - g = self.dbm['groups'][group] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - flags = g.flags - low = g.minArticle - high = g.maxArticle - num = high - low + 1 - return defer.succeed((group, num, high, low, flags)) - - - def articleExistsRequest(self, id): - return defer.succeed(id in self.dbm['Message-IDs']) - - - def articleRequest(self, group, index, id = None): - if id is not None: - try: - xref = self.dbm['Message-IDs'][id] - except KeyError: - return defer.fail(NewsServerError("No such article: " + id)) - else: - group, index = xref[0] - index = int(index) - - try: - a = self.dbm['groups'][group].articles[index] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - return defer.succeed(( - index, - a.getHeader('Message-ID'), - StringIO.StringIO(a.textHeaders() + '\r\n' + a.body) - )) - - - def headRequest(self, group, index, id = None): - if id is not None: - try: - xref = self.dbm['Message-IDs'][id] - except KeyError: - return defer.fail(NewsServerError("No such article: " + id)) - else: - group, index = xref[0] - index = int(index) - - try: - a = self.dbm['groups'][group].articles[index] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - return defer.succeed((index, a.getHeader('Message-ID'), a.textHeaders())) - - - def bodyRequest(self, group, index, id = None): - if id is not None: - try: - xref = self.dbm['Message-IDs'][id] - except KeyError: - return defer.fail(NewsServerError("No such article: " + id)) - else: - group, index = xref[0] - index = int(index) - - try: - a = self.dbm['groups'][group].articles[index] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - return defer.succeed((index, a.getHeader('Message-ID'), StringIO.StringIO(a.body))) - - -class NewsStorageAugmentation: - """ - A NewsStorage implementation using Twisted's asynchronous DB-API - """ - - implements(INewsStorage) - - schema = """ - - CREATE TABLE groups ( - group_id SERIAL, - name VARCHAR(80) NOT NULL, - - flags INTEGER DEFAULT 0 NOT NULL - ); - - CREATE UNIQUE INDEX group_id_index ON groups (group_id); - CREATE UNIQUE INDEX name_id_index ON groups (name); - - CREATE TABLE articles ( - article_id SERIAL, - message_id TEXT, - - header TEXT, - body TEXT - ); - - CREATE UNIQUE INDEX article_id_index ON articles (article_id); - CREATE UNIQUE INDEX article_message_index ON articles (message_id); - - CREATE TABLE postings ( - group_id INTEGER, - article_id INTEGER, - article_index INTEGER NOT NULL - ); - - CREATE UNIQUE INDEX posting_article_index ON postings (article_id); - - CREATE TABLE subscriptions ( - group_id INTEGER - ); - - CREATE TABLE overview ( - header TEXT - ); - """ - - def __init__(self, info): - self.info = info - self.dbpool = adbapi.ConnectionPool(**self.info) - - - def __setstate__(self, state): - self.__dict__ = state - self.info['password'] = getpass.getpass('Database password for %s: ' % (self.info['user'],)) - self.dbpool = adbapi.ConnectionPool(**self.info) - del self.info['password'] - - - def listRequest(self): - # COALESCE may not be totally portable - # it is shorthand for - # CASE WHEN (first parameter) IS NOT NULL then (first parameter) ELSE (second parameter) END - sql = """ - SELECT groups.name, - COALESCE(MAX(postings.article_index), 0), - COALESCE(MIN(postings.article_index), 0), - groups.flags - FROM groups LEFT OUTER JOIN postings - ON postings.group_id = groups.group_id - GROUP BY groups.name, groups.flags - ORDER BY groups.name - """ - return self.dbpool.runQuery(sql) - - - def subscriptionRequest(self): - sql = """ - SELECT groups.name FROM groups,subscriptions WHERE groups.group_id = subscriptions.group_id - """ - return self.dbpool.runQuery(sql) - - - def postRequest(self, message): - cleave = message.find('\r\n\r\n') - headers, article = message[:cleave], message[cleave + 4:] - article = Article(headers, article) - return self.dbpool.runInteraction(self._doPost, article) - - - def _doPost(self, transaction, article): - # Get the group ids - groups = article.getHeader('Newsgroups').split() - if not len(groups): - raise NNTPError('Missing Newsgroups header') - - sql = """ - SELECT name, group_id FROM groups - WHERE name IN (%s) - """ % (', '.join([("'%s'" % (adbapi.safe(group),)) for group in groups]),) - - transaction.execute(sql) - result = transaction.fetchall() - - # No relevant groups, bye bye! - if not len(result): - raise NNTPError('None of groups in Newsgroup header carried') - - # Got some groups, now find the indices this article will have in each - sql = """ - SELECT groups.group_id, COALESCE(MAX(postings.article_index), 0) + 1 - FROM groups LEFT OUTER JOIN postings - ON postings.group_id = groups.group_id - WHERE groups.group_id IN (%s) - GROUP BY groups.group_id - """ % (', '.join([("%d" % (id,)) for (group, id) in result]),) - - transaction.execute(sql) - indices = transaction.fetchall() - - if not len(indices): - raise NNTPError('Internal server error - no indices found') - - # Associate indices with group names - gidToName = dict([(b, a) for (a, b) in result]) - gidToIndex = dict(indices) - - nameIndex = [] - for i in gidToName: - nameIndex.append((gidToName[i], gidToIndex[i])) - - # Build xrefs - xrefs = socket.gethostname().split()[0] - xrefs = xrefs + ' ' + ' '.join([('%s:%d' % (group, id)) for (group, id) in nameIndex]) - article.putHeader('Xref', xrefs) - - # Hey! The article is ready to be posted! God damn f'in finally. - sql = """ - INSERT INTO articles (message_id, header, body) - VALUES ('%s', '%s', '%s') - """ % ( - adbapi.safe(article.getHeader('Message-ID')), - adbapi.safe(article.textHeaders()), - adbapi.safe(article.body) - ) - - transaction.execute(sql) - - # Now update the posting to reflect the groups to which this belongs - for gid in gidToName: - sql = """ - INSERT INTO postings (group_id, article_id, article_index) - VALUES (%d, (SELECT last_value FROM articles_article_id_seq), %d) - """ % (gid, gidToIndex[gid]) - transaction.execute(sql) - - return len(nameIndex) - - - def overviewRequest(self): - sql = """ - SELECT header FROM overview - """ - return self.dbpool.runQuery(sql).addCallback(lambda result: [header[0] for header in result]) - - - def xoverRequest(self, group, low, high): - sql = """ - SELECT postings.article_index, articles.header - FROM articles,postings,groups - WHERE postings.group_id = groups.group_id - AND groups.name = '%s' - AND postings.article_id = articles.article_id - %s - %s - """ % ( - adbapi.safe(group), - low is not None and "AND postings.article_index >= %d" % (low,) or "", - high is not None and "AND postings.article_index <= %d" % (high,) or "" - ) - - return self.dbpool.runQuery(sql).addCallback( - lambda results: [ - [id] + Article(header, None).overview() for (id, header) in results - ] - ) - - - def xhdrRequest(self, group, low, high, header): - sql = """ - SELECT articles.header - FROM groups,postings,articles - WHERE groups.name = '%s' AND postings.group_id = groups.group_id - AND postings.article_index >= %d - AND postings.article_index <= %d - """ % (adbapi.safe(group), low, high) - - return self.dbpool.runQuery(sql).addCallback( - lambda results: [ - (i, Article(h, None).getHeader(h)) for (i, h) in results - ] - ) - - - def listGroupRequest(self, group): - sql = """ - SELECT postings.article_index FROM postings,groups - WHERE postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (adbapi.safe(group),) - - return self.dbpool.runQuery(sql).addCallback( - lambda results, group = group: (group, [res[0] for res in results]) - ) - - - def groupRequest(self, group): - sql = """ - SELECT groups.name, - COUNT(postings.article_index), - COALESCE(MAX(postings.article_index), 0), - COALESCE(MIN(postings.article_index), 0), - groups.flags - FROM groups LEFT OUTER JOIN postings - ON postings.group_id = groups.group_id - WHERE groups.name = '%s' - GROUP BY groups.name, groups.flags - """ % (adbapi.safe(group),) - - return self.dbpool.runQuery(sql).addCallback( - lambda results: tuple(results[0]) - ) - - - def articleExistsRequest(self, id): - sql = """ - SELECT COUNT(message_id) FROM articles - WHERE message_id = '%s' - """ % (adbapi.safe(id),) - - return self.dbpool.runQuery(sql).addCallback( - lambda result: bool(result[0][0]) - ) - - - def articleRequest(self, group, index, id = None): - if id is not None: - sql = """ - SELECT postings.article_index, articles.message_id, articles.header, articles.body - FROM groups,postings LEFT OUTER JOIN articles - ON articles.message_id = '%s' - WHERE groups.name = '%s' - AND groups.group_id = postings.group_id - """ % (adbapi.safe(id), adbapi.safe(group)) - else: - sql = """ - SELECT postings.article_index, articles.message_id, articles.header, articles.body - FROM groups,articles LEFT OUTER JOIN postings - ON postings.article_id = articles.article_id - WHERE postings.article_index = %d - AND postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (index, adbapi.safe(group)) - - return self.dbpool.runQuery(sql).addCallback( - lambda result: ( - result[0][0], - result[0][1], - StringIO.StringIO(result[0][2] + '\r\n' + result[0][3]) - ) - ) - - - def headRequest(self, group, index): - sql = """ - SELECT postings.article_index, articles.message_id, articles.header - FROM groups,articles LEFT OUTER JOIN postings - ON postings.article_id = articles.article_id - WHERE postings.article_index = %d - AND postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (index, adbapi.safe(group)) - - return self.dbpool.runQuery(sql).addCallback(lambda result: result[0]) - - - def bodyRequest(self, group, index): - sql = """ - SELECT postings.article_index, articles.message_id, articles.body - FROM groups,articles LEFT OUTER JOIN postings - ON postings.article_id = articles.article_id - WHERE postings.article_index = %d - AND postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (index, adbapi.safe(group)) - - return self.dbpool.runQuery(sql).addCallback( - lambda result: result[0] - ).addCallback( - lambda (index, id, body): (index, id, StringIO.StringIO(body)) - ) - -#### -#### XXX - make these static methods some day -#### -def makeGroupSQL(groups): - res = '' - for g in groups: - res = res + """\n INSERT INTO groups (name) VALUES ('%s');\n""" % (adbapi.safe(g),) - return res - - -def makeOverviewSQL(): - res = '' - for o in OVERVIEW_FMT: - res = res + """\n INSERT INTO overview (header) VALUES ('%s');\n""" % (adbapi.safe(o),) - return res diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/news.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/news.py deleted file mode 100644 index 3eae700..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/news.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Maintainer: Jp Calderone -""" - -from twisted.news import nntp -from twisted.internet import protocol, reactor - -import time - -class NNTPFactory(protocol.ServerFactory): - """A factory for NNTP server protocols.""" - - protocol = nntp.NNTPServer - - def __init__(self, backend): - self.backend = backend - - def buildProtocol(self, connection): - p = self.protocol() - p.factory = self - return p - - -class UsenetClientFactory(protocol.ClientFactory): - def __init__(self, groups, storage): - self.lastChecks = {} - self.groups = groups - self.storage = storage - - - def clientConnectionLost(self, connector, reason): - pass - - - def clientConnectionFailed(self, connector, reason): - print 'Connection failed: ', reason - - - def updateChecks(self, addr): - self.lastChecks[addr] = time.mktime(time.gmtime()) - - - def buildProtocol(self, addr): - last = self.lastChecks.setdefault(addr, time.mktime(time.gmtime()) - (60 * 60 * 24 * 7)) - p = nntp.UsenetClientProtocol(self.groups, last, self.storage) - p.factory = self - return p - - -# XXX - Maybe this inheritance doesn't make so much sense? -class UsenetServerFactory(NNTPFactory): - """A factory for NNTP Usenet server protocols.""" - - protocol = nntp.NNTPServer - - def __init__(self, backend, remoteHosts = None, updatePeriod = 60): - NNTPFactory.__init__(self, backend) - self.updatePeriod = updatePeriod - self.remoteHosts = remoteHosts or [] - self.clientFactory = UsenetClientFactory(self.remoteHosts, self.backend) - - - def startFactory(self): - self._updateCall = reactor.callLater(0, self.syncWithRemotes) - - - def stopFactory(self): - if self._updateCall: - self._updateCall.cancel() - self._updateCall = None - - - def buildProtocol(self, connection): - p = self.protocol() - p.factory = self - return p - - - def syncWithRemotes(self): - for remote in self.remoteHosts: - reactor.connectTCP(remote, 119, self.clientFactory) - self._updateCall = reactor.callLater(self.updatePeriod, self.syncWithRemotes) - - -# backwards compatibility -Factory = UsenetServerFactory diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/nntp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/nntp.py deleted file mode 100644 index c083f2d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/nntp.py +++ /dev/null @@ -1,1037 +0,0 @@ -# -*- test-case-name: twisted.news.test.test_nntp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -NNTP protocol support. - -The following protocol commands are currently understood:: - - LIST LISTGROUP XOVER XHDR - POST GROUP ARTICLE STAT HEAD - BODY NEXT MODE STREAM MODE READER SLAVE - LAST QUIT HELP IHAVE XPATH - XINDEX XROVER TAKETHIS CHECK - -The following protocol commands require implementation:: - - NEWNEWS - XGTITLE XPAT - XTHREAD AUTHINFO NEWGROUPS - - -Other desired features: - - - A real backend - - More robust client input handling - - A control protocol -""" - -import time - -from twisted.protocols import basic -from twisted.python import log - -def parseRange(text): - articles = text.split('-') - if len(articles) == 1: - try: - a = int(articles[0]) - return a, a - except ValueError: - return None, None - elif len(articles) == 2: - try: - if len(articles[0]): - l = int(articles[0]) - else: - l = None - if len(articles[1]): - h = int(articles[1]) - else: - h = None - except ValueError: - return None, None - return l, h - - -def extractCode(line): - line = line.split(' ', 1) - if len(line) != 2: - return None - try: - return int(line[0]), line[1] - except ValueError: - return None - - -class NNTPError(Exception): - def __init__(self, string): - self.string = string - - def __str__(self): - return 'NNTPError: %s' % self.string - - -class NNTPClient(basic.LineReceiver): - MAX_COMMAND_LENGTH = 510 - - def __init__(self): - self.currentGroup = None - - self._state = [] - self._error = [] - self._inputBuffers = [] - self._responseCodes = [] - self._responseHandlers = [] - - self._postText = [] - - self._newState(self._statePassive, None, self._headerInitial) - - - def gotAllGroups(self, groups): - "Override for notification when fetchGroups() action is completed" - - - def getAllGroupsFailed(self, error): - "Override for notification when fetchGroups() action fails" - - - def gotOverview(self, overview): - "Override for notification when fetchOverview() action is completed" - - - def getOverviewFailed(self, error): - "Override for notification when fetchOverview() action fails" - - - def gotSubscriptions(self, subscriptions): - "Override for notification when fetchSubscriptions() action is completed" - - - def getSubscriptionsFailed(self, error): - "Override for notification when fetchSubscriptions() action fails" - - - def gotGroup(self, group): - "Override for notification when fetchGroup() action is completed" - - - def getGroupFailed(self, error): - "Override for notification when fetchGroup() action fails" - - - def gotArticle(self, article): - "Override for notification when fetchArticle() action is completed" - - - def getArticleFailed(self, error): - "Override for notification when fetchArticle() action fails" - - - def gotHead(self, head): - "Override for notification when fetchHead() action is completed" - - - def getHeadFailed(self, error): - "Override for notification when fetchHead() action fails" - - - def gotBody(self, info): - "Override for notification when fetchBody() action is completed" - - - def getBodyFailed(self, body): - "Override for notification when fetchBody() action fails" - - - def postedOk(self): - "Override for notification when postArticle() action is successful" - - - def postFailed(self, error): - "Override for notification when postArticle() action fails" - - - def gotXHeader(self, headers): - "Override for notification when getXHeader() action is successful" - - - def getXHeaderFailed(self, error): - "Override for notification when getXHeader() action fails" - - - def gotNewNews(self, news): - "Override for notification when getNewNews() action is successful" - - - def getNewNewsFailed(self, error): - "Override for notification when getNewNews() action fails" - - - def gotNewGroups(self, groups): - "Override for notification when getNewGroups() action is successful" - - - def getNewGroupsFailed(self, error): - "Override for notification when getNewGroups() action fails" - - - def setStreamSuccess(self): - "Override for notification when setStream() action is successful" - - - def setStreamFailed(self, error): - "Override for notification when setStream() action fails" - - - def fetchGroups(self): - """ - Request a list of all news groups from the server. gotAllGroups() - is called on success, getGroupsFailed() on failure - """ - self.sendLine('LIST') - self._newState(self._stateList, self.getAllGroupsFailed) - - - def fetchOverview(self): - """ - Request the overview format from the server. gotOverview() is called - on success, getOverviewFailed() on failure - """ - self.sendLine('LIST OVERVIEW.FMT') - self._newState(self._stateOverview, self.getOverviewFailed) - - - def fetchSubscriptions(self): - """ - Request a list of the groups it is recommended a new user subscribe to. - gotSubscriptions() is called on success, getSubscriptionsFailed() on - failure - """ - self.sendLine('LIST SUBSCRIPTIONS') - self._newState(self._stateSubscriptions, self.getSubscriptionsFailed) - - - def fetchGroup(self, group): - """ - Get group information for the specified group from the server. gotGroup() - is called on success, getGroupFailed() on failure. - """ - self.sendLine('GROUP %s' % (group,)) - self._newState(None, self.getGroupFailed, self._headerGroup) - - - def fetchHead(self, index = ''): - """ - Get the header for the specified article (or the currently selected - article if index is '') from the server. gotHead() is called on - success, getHeadFailed() on failure - """ - self.sendLine('HEAD %s' % (index,)) - self._newState(self._stateHead, self.getHeadFailed) - - - def fetchBody(self, index = ''): - """ - Get the body for the specified article (or the currently selected - article if index is '') from the server. gotBody() is called on - success, getBodyFailed() on failure - """ - self.sendLine('BODY %s' % (index,)) - self._newState(self._stateBody, self.getBodyFailed) - - - def fetchArticle(self, index = ''): - """ - Get the complete article with the specified index (or the currently - selected article if index is '') or Message-ID from the server. - gotArticle() is called on success, getArticleFailed() on failure. - """ - self.sendLine('ARTICLE %s' % (index,)) - self._newState(self._stateArticle, self.getArticleFailed) - - - def postArticle(self, text): - """ - Attempt to post an article with the specified text to the server. 'text' - must consist of both head and body data, as specified by RFC 850. If the - article is posted successfully, postedOk() is called, otherwise postFailed() - is called. - """ - self.sendLine('POST') - self._newState(None, self.postFailed, self._headerPost) - self._postText.append(text) - - - def fetchNewNews(self, groups, date, distributions = ''): - """ - Get the Message-IDs for all new news posted to any of the given - groups since the specified date - in seconds since the epoch, GMT - - optionally restricted to the given distributions. gotNewNews() is - called on success, getNewNewsFailed() on failure. - - One invocation of this function may result in multiple invocations - of gotNewNews()/getNewNewsFailed(). - """ - date, timeStr = time.strftime('%y%m%d %H%M%S', time.gmtime(date)).split() - line = 'NEWNEWS %%s %s %s %s' % (date, timeStr, distributions) - groupPart = '' - while len(groups) and len(line) + len(groupPart) + len(groups[-1]) + 1 < NNTPClient.MAX_COMMAND_LENGTH: - group = groups.pop() - groupPart = groupPart + ',' + group - - self.sendLine(line % (groupPart,)) - self._newState(self._stateNewNews, self.getNewNewsFailed) - - if len(groups): - self.fetchNewNews(groups, date, distributions) - - - def fetchNewGroups(self, date, distributions): - """ - Get the names of all new groups created/added to the server since - the specified date - in seconds since the ecpoh, GMT - optionally - restricted to the given distributions. gotNewGroups() is called - on success, getNewGroupsFailed() on failure. - """ - date, timeStr = time.strftime('%y%m%d %H%M%S', time.gmtime(date)).split() - self.sendLine('NEWGROUPS %s %s %s' % (date, timeStr, distributions)) - self._newState(self._stateNewGroups, self.getNewGroupsFailed) - - - def fetchXHeader(self, header, low = None, high = None, id = None): - """ - Request a specific header from the server for an article or range - of articles. If 'id' is not None, a header for only the article - with that Message-ID will be requested. If both low and high are - None, a header for the currently selected article will be selected; - If both low and high are zero-length strings, headers for all articles - in the currently selected group will be requested; Otherwise, high - and low will be used as bounds - if one is None the first or last - article index will be substituted, as appropriate. - """ - if id is not None: - r = header + ' <%s>' % (id,) - elif low is high is None: - r = header - elif high is None: - r = header + ' %d-' % (low,) - elif low is None: - r = header + ' -%d' % (high,) - else: - r = header + ' %d-%d' % (low, high) - self.sendLine('XHDR ' + r) - self._newState(self._stateXHDR, self.getXHeaderFailed) - - - def setStream(self): - """ - Set the mode to STREAM, suspending the normal "lock-step" mode of - communications. setStreamSuccess() is called on success, - setStreamFailed() on failure. - """ - self.sendLine('MODE STREAM') - self._newState(None, self.setStreamFailed, self._headerMode) - - - def quit(self): - self.sendLine('QUIT') - self.transport.loseConnection() - - - def _newState(self, method, error, responseHandler = None): - self._inputBuffers.append([]) - self._responseCodes.append(None) - self._state.append(method) - self._error.append(error) - self._responseHandlers.append(responseHandler) - - - def _endState(self): - buf = self._inputBuffers[0] - del self._responseCodes[0] - del self._inputBuffers[0] - del self._state[0] - del self._error[0] - del self._responseHandlers[0] - return buf - - - def _newLine(self, line, check = 1): - if check and line and line[0] == '.': - line = line[1:] - self._inputBuffers[0].append(line) - - - def _setResponseCode(self, code): - self._responseCodes[0] = code - - - def _getResponseCode(self): - return self._responseCodes[0] - - - def lineReceived(self, line): - if not len(self._state): - self._statePassive(line) - elif self._getResponseCode() is None: - code = extractCode(line) - if code is None or not (200 <= code[0] < 400): # An error! - self._error[0](line) - self._endState() - else: - self._setResponseCode(code) - if self._responseHandlers[0]: - self._responseHandlers[0](code) - else: - self._state[0](line) - - - def _statePassive(self, line): - log.msg('Server said: %s' % line) - - - def _passiveError(self, error): - log.err('Passive Error: %s' % (error,)) - - - def _headerInitial(self, (code, message)): - if code == 200: - self.canPost = 1 - else: - self.canPost = 0 - self._endState() - - - def _stateList(self, line): - if line != '.': - data = filter(None, line.strip().split()) - self._newLine((data[0], int(data[1]), int(data[2]), data[3]), 0) - else: - self.gotAllGroups(self._endState()) - - - def _stateOverview(self, line): - if line != '.': - self._newLine(filter(None, line.strip().split()), 0) - else: - self.gotOverview(self._endState()) - - - def _stateSubscriptions(self, line): - if line != '.': - self._newLine(line.strip(), 0) - else: - self.gotSubscriptions(self._endState()) - - - def _headerGroup(self, (code, line)): - self.gotGroup(tuple(line.split())) - self._endState() - - - def _stateArticle(self, line): - if line != '.': - if line.startswith('.'): - line = line[1:] - self._newLine(line, 0) - else: - self.gotArticle('\n'.join(self._endState())+'\n') - - - def _stateHead(self, line): - if line != '.': - self._newLine(line, 0) - else: - self.gotHead('\n'.join(self._endState())) - - - def _stateBody(self, line): - if line != '.': - if line.startswith('.'): - line = line[1:] - self._newLine(line, 0) - else: - self.gotBody('\n'.join(self._endState())+'\n') - - - def _headerPost(self, (code, message)): - if code == 340: - self.transport.write(self._postText[0].replace('\n', '\r\n').replace('\r\n.', '\r\n..')) - if self._postText[0][-1:] != '\n': - self.sendLine('') - self.sendLine('.') - del self._postText[0] - self._newState(None, self.postFailed, self._headerPosted) - else: - self.postFailed('%d %s' % (code, message)) - self._endState() - - - def _headerPosted(self, (code, message)): - if code == 240: - self.postedOk() - else: - self.postFailed('%d %s' % (code, message)) - self._endState() - - - def _stateXHDR(self, line): - if line != '.': - self._newLine(line.split(), 0) - else: - self._gotXHeader(self._endState()) - - - def _stateNewNews(self, line): - if line != '.': - self._newLine(line, 0) - else: - self.gotNewNews(self._endState()) - - - def _stateNewGroups(self, line): - if line != '.': - self._newLine(line, 0) - else: - self.gotNewGroups(self._endState()) - - - def _headerMode(self, (code, message)): - if code == 203: - self.setStreamSuccess() - else: - self.setStreamFailed((code, message)) - self._endState() - - -class NNTPServer(basic.LineReceiver): - COMMANDS = [ - 'LIST', 'GROUP', 'ARTICLE', 'STAT', 'MODE', 'LISTGROUP', 'XOVER', - 'XHDR', 'HEAD', 'BODY', 'NEXT', 'LAST', 'POST', 'QUIT', 'IHAVE', - 'HELP', 'SLAVE', 'XPATH', 'XINDEX', 'XROVER', 'TAKETHIS', 'CHECK' - ] - - def __init__(self): - self.servingSlave = 0 - - - def connectionMade(self): - self.inputHandler = None - self.currentGroup = None - self.currentIndex = None - self.sendLine('200 server ready - posting allowed') - - def lineReceived(self, line): - if self.inputHandler is not None: - self.inputHandler(line) - else: - parts = line.strip().split() - if len(parts): - cmd, parts = parts[0].upper(), parts[1:] - if cmd in NNTPServer.COMMANDS: - func = getattr(self, 'do_%s' % cmd) - try: - func(*parts) - except TypeError: - self.sendLine('501 command syntax error') - log.msg("501 command syntax error") - log.msg("command was", line) - log.deferr() - except: - self.sendLine('503 program fault - command not performed') - log.msg("503 program fault") - log.msg("command was", line) - log.deferr() - else: - self.sendLine('500 command not recognized') - - - def do_LIST(self, subcmd = '', *dummy): - subcmd = subcmd.strip().lower() - if subcmd == 'newsgroups': - # XXX - this could use a real implementation, eh? - self.sendLine('215 Descriptions in form "group description"') - self.sendLine('.') - elif subcmd == 'overview.fmt': - defer = self.factory.backend.overviewRequest() - defer.addCallbacks(self._gotOverview, self._errOverview) - log.msg('overview') - elif subcmd == 'subscriptions': - defer = self.factory.backend.subscriptionRequest() - defer.addCallbacks(self._gotSubscription, self._errSubscription) - log.msg('subscriptions') - elif subcmd == '': - defer = self.factory.backend.listRequest() - defer.addCallbacks(self._gotList, self._errList) - else: - self.sendLine('500 command not recognized') - - - def _gotList(self, list): - self.sendLine('215 newsgroups in form "group high low flags"') - for i in list: - self.sendLine('%s %d %d %s' % tuple(i)) - self.sendLine('.') - - - def _errList(self, failure): - print 'LIST failed: ', failure - self.sendLine('503 program fault - command not performed') - - - def _gotSubscription(self, parts): - self.sendLine('215 information follows') - for i in parts: - self.sendLine(i) - self.sendLine('.') - - - def _errSubscription(self, failure): - print 'SUBSCRIPTIONS failed: ', failure - self.sendLine('503 program fault - comand not performed') - - - def _gotOverview(self, parts): - self.sendLine('215 Order of fields in overview database.') - for i in parts: - self.sendLine(i + ':') - self.sendLine('.') - - - def _errOverview(self, failure): - print 'LIST OVERVIEW.FMT failed: ', failure - self.sendLine('503 program fault - command not performed') - - - def do_LISTGROUP(self, group = None): - group = group or self.currentGroup - if group is None: - self.sendLine('412 Not currently in newsgroup') - else: - defer = self.factory.backend.listGroupRequest(group) - defer.addCallbacks(self._gotListGroup, self._errListGroup) - - - def _gotListGroup(self, (group, articles)): - self.currentGroup = group - if len(articles): - self.currentIndex = int(articles[0]) - else: - self.currentIndex = None - - self.sendLine('211 list of article numbers follow') - for i in articles: - self.sendLine(str(i)) - self.sendLine('.') - - - def _errListGroup(self, failure): - print 'LISTGROUP failed: ', failure - self.sendLine('502 no permission') - - - def do_XOVER(self, range): - if self.currentGroup is None: - self.sendLine('412 No news group currently selected') - else: - l, h = parseRange(range) - defer = self.factory.backend.xoverRequest(self.currentGroup, l, h) - defer.addCallbacks(self._gotXOver, self._errXOver) - - - def _gotXOver(self, parts): - self.sendLine('224 Overview information follows') - for i in parts: - self.sendLine('\t'.join(map(str, i))) - self.sendLine('.') - - - def _errXOver(self, failure): - print 'XOVER failed: ', failure - self.sendLine('420 No article(s) selected') - - - def xhdrWork(self, header, range): - if self.currentGroup is None: - self.sendLine('412 No news group currently selected') - else: - if range is None: - if self.currentIndex is None: - self.sendLine('420 No current article selected') - return - else: - l = h = self.currentIndex - else: - # FIXME: articles may be a message-id - l, h = parseRange(range) - - if l is h is None: - self.sendLine('430 no such article') - else: - return self.factory.backend.xhdrRequest(self.currentGroup, l, h, header) - - - def do_XHDR(self, header, range = None): - d = self.xhdrWork(header, range) - if d: - d.addCallbacks(self._gotXHDR, self._errXHDR) - - - def _gotXHDR(self, parts): - self.sendLine('221 Header follows') - for i in parts: - self.sendLine('%d %s' % i) - self.sendLine('.') - - def _errXHDR(self, failure): - print 'XHDR failed: ', failure - self.sendLine('502 no permission') - - - def do_POST(self): - self.inputHandler = self._doingPost - self.message = '' - self.sendLine('340 send article to be posted. End with .') - - - def _doingPost(self, line): - if line == '.': - self.inputHandler = None - group, article = self.currentGroup, self.message - self.message = '' - - defer = self.factory.backend.postRequest(article) - defer.addCallbacks(self._gotPost, self._errPost) - else: - self.message = self.message + line + '\r\n' - - - def _gotPost(self, parts): - self.sendLine('240 article posted ok') - - - def _errPost(self, failure): - print 'POST failed: ', failure - self.sendLine('441 posting failed') - - - def do_CHECK(self, id): - d = self.factory.backend.articleExistsRequest(id) - d.addCallbacks(self._gotCheck, self._errCheck) - - - def _gotCheck(self, result): - if result: - self.sendLine("438 already have it, please don't send it to me") - else: - self.sendLine('238 no such article found, please send it to me') - - - def _errCheck(self, failure): - print 'CHECK failed: ', failure - self.sendLine('431 try sending it again later') - - - def do_TAKETHIS(self, id): - self.inputHandler = self._doingTakeThis - self.message = '' - - - def _doingTakeThis(self, line): - if line == '.': - self.inputHandler = None - article = self.message - self.message = '' - d = self.factory.backend.postRequest(article) - d.addCallbacks(self._didTakeThis, self._errTakeThis) - else: - self.message = self.message + line + '\r\n' - - - def _didTakeThis(self, result): - self.sendLine('239 article transferred ok') - - - def _errTakeThis(self, failure): - print 'TAKETHIS failed: ', failure - self.sendLine('439 article transfer failed') - - - def do_GROUP(self, group): - defer = self.factory.backend.groupRequest(group) - defer.addCallbacks(self._gotGroup, self._errGroup) - - - def _gotGroup(self, (name, num, high, low, flags)): - self.currentGroup = name - self.currentIndex = low - self.sendLine('211 %d %d %d %s group selected' % (num, low, high, name)) - - - def _errGroup(self, failure): - print 'GROUP failed: ', failure - self.sendLine('411 no such group') - - - def articleWork(self, article, cmd, func): - if self.currentGroup is None: - self.sendLine('412 no newsgroup has been selected') - else: - if not article: - if self.currentIndex is None: - self.sendLine('420 no current article has been selected') - else: - article = self.currentIndex - else: - if article[0] == '<': - return func(self.currentGroup, index = None, id = article) - else: - try: - article = int(article) - return func(self.currentGroup, article) - except ValueError: - self.sendLine('501 command syntax error') - - - def do_ARTICLE(self, article = None): - defer = self.articleWork(article, 'ARTICLE', self.factory.backend.articleRequest) - if defer: - defer.addCallbacks(self._gotArticle, self._errArticle) - - - def _gotArticle(self, (index, id, article)): - self.currentIndex = index - self.sendLine('220 %d %s article' % (index, id)) - s = basic.FileSender() - d = s.beginFileTransfer(article, self.transport) - d.addCallback(self.finishedFileTransfer) - - ## - ## Helper for FileSender - ## - def finishedFileTransfer(self, lastsent): - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - ## - - def _errArticle(self, failure): - print 'ARTICLE failed: ', failure - self.sendLine('423 bad article number') - - - def do_STAT(self, article = None): - defer = self.articleWork(article, 'STAT', self.factory.backend.articleRequest) - if defer: - defer.addCallbacks(self._gotStat, self._errStat) - - - def _gotStat(self, (index, id, article)): - self.currentIndex = index - self.sendLine('223 %d %s article retreived - request text separately' % (index, id)) - - - def _errStat(self, failure): - print 'STAT failed: ', failure - self.sendLine('423 bad article number') - - - def do_HEAD(self, article = None): - defer = self.articleWork(article, 'HEAD', self.factory.backend.headRequest) - if defer: - defer.addCallbacks(self._gotHead, self._errHead) - - - def _gotHead(self, (index, id, head)): - self.currentIndex = index - self.sendLine('221 %d %s article retrieved' % (index, id)) - self.transport.write(head + '\r\n') - self.sendLine('.') - - - def _errHead(self, failure): - print 'HEAD failed: ', failure - self.sendLine('423 no such article number in this group') - - - def do_BODY(self, article): - defer = self.articleWork(article, 'BODY', self.factory.backend.bodyRequest) - if defer: - defer.addCallbacks(self._gotBody, self._errBody) - - - def _gotBody(self, (index, id, body)): - self.currentIndex = index - self.sendLine('221 %d %s article retrieved' % (index, id)) - self.lastsent = '' - s = basic.FileSender() - d = s.beginFileTransfer(body, self.transport) - d.addCallback(self.finishedFileTransfer) - - def _errBody(self, failure): - print 'BODY failed: ', failure - self.sendLine('423 no such article number in this group') - - - # NEXT and LAST are just STATs that increment currentIndex first. - # Accordingly, use the STAT callbacks. - def do_NEXT(self): - i = self.currentIndex + 1 - defer = self.factory.backend.articleRequest(self.currentGroup, i) - defer.addCallbacks(self._gotStat, self._errStat) - - - def do_LAST(self): - i = self.currentIndex - 1 - defer = self.factory.backend.articleRequest(self.currentGroup, i) - defer.addCallbacks(self._gotStat, self._errStat) - - - def do_MODE(self, cmd): - cmd = cmd.strip().upper() - if cmd == 'READER': - self.servingSlave = 0 - self.sendLine('200 Hello, you can post') - elif cmd == 'STREAM': - self.sendLine('500 Command not understood') - else: - # This is not a mistake - self.sendLine('500 Command not understood') - - - def do_QUIT(self): - self.sendLine('205 goodbye') - self.transport.loseConnection() - - - def do_HELP(self): - self.sendLine('100 help text follows') - self.sendLine('Read the RFC.') - self.sendLine('.') - - - def do_SLAVE(self): - self.sendLine('202 slave status noted') - self.servingeSlave = 1 - - - def do_XPATH(self, article): - # XPATH is a silly thing to have. No client has the right to ask - # for this piece of information from me, and so that is what I'll - # tell them. - self.sendLine('502 access restriction or permission denied') - - - def do_XINDEX(self, article): - # XINDEX is another silly command. The RFC suggests it be relegated - # to the history books, and who am I to disagree? - self.sendLine('502 access restriction or permission denied') - - - def do_XROVER(self, range=None): - """ - Handle a request for references of all messages in the currently - selected group. - - This generates the same response a I{XHDR References} request would - generate. - """ - self.do_XHDR('References', range) - - - def do_IHAVE(self, id): - self.factory.backend.articleExistsRequest(id).addCallback(self._foundArticle) - - - def _foundArticle(self, result): - if result: - self.sendLine('437 article rejected - do not try again') - else: - self.sendLine('335 send article to be transferred. End with .') - self.inputHandler = self._handleIHAVE - self.message = '' - - - def _handleIHAVE(self, line): - if line == '.': - self.inputHandler = None - self.factory.backend.postRequest( - self.message - ).addCallbacks(self._gotIHAVE, self._errIHAVE) - - self.message = '' - else: - self.message = self.message + line + '\r\n' - - - def _gotIHAVE(self, result): - self.sendLine('235 article transferred ok') - - - def _errIHAVE(self, failure): - print 'IHAVE failed: ', failure - self.sendLine('436 transfer failed - try again later') - - -class UsenetClientProtocol(NNTPClient): - """ - A client that connects to an NNTP server and asks for articles new - since a certain time. - """ - - def __init__(self, groups, date, storage): - """ - Fetch all new articles from the given groups since the - given date and dump them into the given storage. groups - is a list of group names. date is an integer or floating - point representing seconds since the epoch (GMT). storage is - any object that implements the NewsStorage interface. - """ - NNTPClient.__init__(self) - self.groups, self.date, self.storage = groups, date, storage - - - def connectionMade(self): - NNTPClient.connectionMade(self) - log.msg("Initiating update with remote host: " + str(self.transport.getPeer())) - self.setStream() - self.fetchNewNews(self.groups, self.date, '') - - - def articleExists(self, exists, article): - if exists: - self.fetchArticle(article) - else: - self.count = self.count - 1 - self.disregard = self.disregard + 1 - - - def gotNewNews(self, news): - self.disregard = 0 - self.count = len(news) - log.msg("Transferring " + str(self.count) + - " articles from remote host: " + str(self.transport.getPeer())) - for i in news: - self.storage.articleExistsRequest(i).addCallback(self.articleExists, i) - - - def getNewNewsFailed(self, reason): - log.msg("Updated failed (" + reason + ") with remote host: " + str(self.transport.getPeer())) - self.quit() - - - def gotArticle(self, article): - self.storage.postRequest(article) - self.count = self.count - 1 - if not self.count: - log.msg("Completed update with remote host: " + str(self.transport.getPeer())) - if self.disregard: - log.msg("Disregarded %d articles." % (self.disregard,)) - self.factory.updateChecks(self.transport.getPeer()) - self.quit() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/tap.py deleted file mode 100644 index a4cf542..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/tap.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.news import news, database -from twisted.application import strports -from twisted.python import usage, log - -class DBOptions(usage.Options): - optParameters = [ - ['module', None, 'pyPgSQL.PgSQL', "DB-API 2.0 module to use"], - ['dbhost', None, 'localhost', "Host where database manager is listening"], - ['dbuser', None, 'news', "Username with which to connect to database"], - ['database', None, 'news', "Database name to use"], - ['schema', None, 'schema.sql', "File to which to write SQL schema initialisation"], - - # XXX - Hrm. - ["groups", "g", "groups.list", "File containing group list"], - ["servers", "s", "servers.list", "File containing server list"] - ] - - def postOptions(self): - # XXX - Hmmm. - self['groups'] = [g.strip() for g in open(self['groups']).readlines() if not g.startswith('#')] - self['servers'] = [s.strip() for s in open(self['servers']).readlines() if not s.startswith('#')] - - try: - __import__(self['module']) - except ImportError: - log.msg("Warning: Cannot import %s" % (self['module'],)) - - f = open(self['schema'], 'w') - f.write( - database.NewsStorageAugmentation.schema + '\n' + - database.makeGroupSQL(self['groups']) + '\n' + - database.makeOverviewSQL() - ) - f.close() - - info = { - 'host': self['dbhost'], 'user': self['dbuser'], - 'database': self['database'], 'dbapiName': self['module'] - } - self.db = database.NewsStorageAugmentation(info) - - -class PickleOptions(usage.Options): - optParameters = [ - ['file', None, 'news.pickle', "File to which to save pickle"], - - # XXX - Hrm. - ["groups", "g", "groups.list", "File containing group list"], - ["servers", "s", "servers.list", "File containing server list"], - ["moderators", "m", "moderators.list", - "File containing moderators list"], - ] - - subCommands = None - - def postOptions(self): - # XXX - Hmmm. - filename = self['file'] - self['groups'] = [g.strip() for g in open(self['groups']).readlines() - if not g.startswith('#')] - self['servers'] = [s.strip() for s in open(self['servers']).readlines() - if not s.startswith('#')] - self['moderators'] = [s.split() - for s in open(self['moderators']).readlines() - if not s.startswith('#')] - self.db = database.PickleStorage(filename, self['groups'], - self['moderators']) - - -class Options(usage.Options): - synopsis = "[options]" - - groups = None - servers = None - subscriptions = None - - optParameters = [ - ["port", "p", "119", "Listen port"], - ["interface", "i", "", "Interface to which to bind"], - ["datadir", "d", "news.db", "Root data storage path"], - ["mailhost", "m", "localhost", "Host of SMTP server to use"] - ] - compData = usage.Completions( - optActions={"datadir" : usage.CompleteDirs(), - "mailhost" : usage.CompleteHostnames(), - "interface" : usage.CompleteNetInterfaces()} - ) - - def __init__(self): - usage.Options.__init__(self) - self.groups = [] - self.servers = [] - self.subscriptions = [] - - - def opt_group(self, group): - """The name of a newsgroup to carry.""" - self.groups.append([group, None]) - - - def opt_moderator(self, moderator): - """The email of the moderator for the most recently passed group.""" - self.groups[-1][1] = moderator - - - def opt_subscription(self, group): - """A newsgroup to list as a recommended subscription.""" - self.subscriptions.append(group) - - - def opt_server(self, server): - """The address of a Usenet server to pass messages to and receive messages from.""" - self.servers.append(server) - - -def makeService(config): - if not len(config.groups): - raise usage.UsageError("No newsgroups specified") - - db = database.NewsShelf(config['mailhost'], config['datadir']) - for (g, m) in config.groups: - if m: - db.addGroup(g, 'm') - db.addModerator(g, m) - else: - db.addGroup(g, 'y') - for s in config.subscriptions: - print s - db.addSubscription(s) - s = config['port'] - if config['interface']: - # Add a warning here - s += ':interface='+config['interface'] - return strports.service(s, news.UsenetServerFactory(db, config.servers)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/__init__.py deleted file mode 100644 index 677518d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""News Tests""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_database.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_database.py deleted file mode 100644 index 42900a2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_database.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.news.database}. -""" - -__metaclass__ = type - -from email.Parser import Parser -from socket import gethostname - -from twisted.trial.unittest import TestCase -from twisted.internet.defer import succeed -from twisted.mail.smtp import messageid -from twisted.news.database import Article, PickleStorage, NewsShelf - - - -class ModerationTestsMixin: - """ - Tests for the moderation features of L{INewsStorage} implementations. - """ - def setUp(self): - self._email = [] - - - def sendmail(self, smtphost, from_addr, to_addrs, msg, - senderDomainName=None, port=25): - """ - Fake of L{twisted.mail.smtp.sendmail} which records attempts to send - email and immediately pretends success. - - Subclasses should arrange for their storage implementation to call this - instead of the real C{sendmail} function. - """ - self._email.append(( - smtphost, from_addr, to_addrs, msg, senderDomainName, port)) - return succeed(None) - - - _messageTemplate = """\ -From: some dude -To: another person -Subject: activities etc -Message-ID: %(articleID)s -Newsgroups: %(newsgroup)s -%(approved)s -Body of the message is such. -""".replace('\n', '\r\n') - - - def getApprovedMessage(self, articleID, group): - """ - Return a C{str} containing an RFC 2822 formatted message including an - I{Approved} header indicating it has passed through moderation. - """ - return self._messageTemplate % { - 'articleID': articleID, - 'newsgroup': group, - 'approved': 'Approved: yup\r\n'} - - - def getUnapprovedMessage(self, articleID, group): - """ - Return a C{str} containing an RFC 2822 formatted message with no - I{Approved} header indicating it may require moderation. - """ - return self._messageTemplate % { - 'articleID': articleID, - 'newsgroup': group, - 'approved': '\r\n'} - - - def getStorage(self, groups, moderators, mailhost, sender): - """ - Override in a subclass to return a L{INewsStorage} provider to test for - correct moderation behavior. - - @param groups: A C{list} of C{str} naming the groups which should exist - in the resulting storage object. - - @param moderators: A C{dict} mapping C{str} each group name to a C{list} - of C{str} giving moderator email (RFC 2821) addresses. - """ - raise NotImplementedError() - - - def test_postApproved(self): - """ - L{INewsStorage.postRequest} posts the message if it includes an - I{Approved} header. - """ - group = "example.group" - moderator = "alice@example.com" - mailhost = "127.0.0.1" - sender = "bob@example.org" - articleID = messageid() - storage = self.getStorage( - [group], {group: [moderator]}, mailhost, sender) - message = self.getApprovedMessage(articleID, group) - result = storage.postRequest(message) - - def cbPosted(ignored): - self.assertEqual(self._email, []) - exists = storage.articleExistsRequest(articleID) - exists.addCallback(self.assertTrue) - return exists - result.addCallback(cbPosted) - return result - - - def test_postModerated(self): - """ - L{INewsStorage.postRequest} forwards a message to the moderator if it - does not include an I{Approved} header. - """ - group = "example.group" - moderator = "alice@example.com" - mailhost = "127.0.0.1" - sender = "bob@example.org" - articleID = messageid() - storage = self.getStorage( - [group], {group: [moderator]}, mailhost, sender) - message = self.getUnapprovedMessage(articleID, group) - result = storage.postRequest(message) - - def cbModerated(ignored): - self.assertEqual(len(self._email), 1) - self.assertEqual(self._email[0][0], mailhost) - self.assertEqual(self._email[0][1], sender) - self.assertEqual(self._email[0][2], [moderator]) - self._checkModeratorMessage( - self._email[0][3], sender, moderator, group, message) - self.assertEqual(self._email[0][4], None) - self.assertEqual(self._email[0][5], 25) - exists = storage.articleExistsRequest(articleID) - exists.addCallback(self.assertFalse) - return exists - result.addCallback(cbModerated) - return result - - - def _checkModeratorMessage(self, messageText, sender, moderator, group, postingText): - p = Parser() - msg = p.parsestr(messageText) - headers = dict(msg.items()) - del headers['Message-ID'] - self.assertEqual( - headers, - {'From': sender, - 'To': moderator, - 'Subject': 'Moderate new %s message: activities etc' % (group,), - 'Content-Type': 'message/rfc822'}) - - posting = p.parsestr(postingText) - attachment = msg.get_payload()[0] - - for header in ['from', 'to', 'subject', 'message-id', 'newsgroups']: - self.assertEqual(posting[header], attachment[header]) - - self.assertEqual(posting.get_payload(), attachment.get_payload()) - - - -class PickleStorageTests(ModerationTestsMixin, TestCase): - """ - Tests for L{PickleStorage}. - """ - def getStorage(self, groups, moderators, mailhost, sender): - """ - Create and return a L{PickleStorage} instance configured to require - moderation. - """ - storageFilename = self.mktemp() - storage = PickleStorage( - storageFilename, groups, moderators, mailhost, sender) - storage.sendmail = self.sendmail - self.addCleanup(PickleStorage.sharedDBs.pop, storageFilename) - return storage - - - -class NewsShelfTests(ModerationTestsMixin, TestCase): - """ - Tests for L{NewsShelf}. - """ - def getStorage(self, groups, moderators, mailhost, sender): - """ - Create and return a L{NewsShelf} instance configured to require - moderation. - """ - storageFilename = self.mktemp() - shelf = NewsShelf(mailhost, storageFilename, sender) - for name in groups: - shelf.addGroup(name, 'm') # Dial 'm' for moderator - for address in moderators.get(name, []): - shelf.addModerator(name, address) - shelf.sendmail = self.sendmail - return shelf - - - def test_notifyModerator(self): - """ - L{NewsShelf.notifyModerator} sends a moderation email to a single - moderator. - """ - shelf = NewsShelf('example.com', self.mktemp(), 'alice@example.com') - shelf.sendmail = self.sendmail - shelf.notifyModerator('bob@example.org', Article('Foo: bar', 'Some text')) - self.assertEqual(len(self._email), 1) - - - def test_defaultSender(self): - """ - If no sender is specified to L{NewsShelf.notifyModerators}, a default - address based on the system hostname is used for both the envelope and - RFC 2822 sender addresses. - """ - shelf = NewsShelf('example.com', self.mktemp()) - shelf.sendmail = self.sendmail - shelf.notifyModerators(['bob@example.org'], Article('Foo: bar', 'Some text')) - self.assertEqual(self._email[0][1], 'twisted-news@' + gethostname()) - self.assertIn('From: twisted-news@' + gethostname(), self._email[0][3]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_news.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_news.py deleted file mode 100644 index 6d383ac..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_news.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from pprint import pformat - -from twisted.trial import unittest -from twisted.news import database - -MESSAGE_ID = "f83ba57450ed0fd8ac9a472b847e830e" - -POST_STRING = """Path: not-for-mail -From: -Subject: a test -Newsgroups: alt.test.nntp -Organization: -Summary: -Keywords: -Message-Id: %s -User-Agent: tin/1.4.5-20010409 ("One More Nightmare") (UNIX) (Linux/2.4.17 (i686)) - -this is a test -... -lala -moo --- -"One World, one Web, one Program." - Microsoft(R) promotional ad -"Ein Volk, ein Reich, ein Fuhrer." - Adolf Hitler --- - 10:56pm up 4 days, 4:42, 1 user, load average: 0.08, 0.08, 0.12 -""" % (MESSAGE_ID) - -class NewsTests(unittest.TestCase): - def setUp(self): - self.backend = database.NewsShelf(None, 'news2.db') - self.backend.addGroup('alt.test.nntp', 'y') - self.backend.postRequest(POST_STRING.replace('\n', '\r\n')) - - - def testArticleExists(self): - d = self.backend.articleExistsRequest(MESSAGE_ID) - d.addCallback(self.failUnless) - return d - - - def testArticleRequest(self): - d = self.backend.articleRequest(None, None, MESSAGE_ID) - - def cbArticle(result): - self.failUnless(isinstance(result, tuple), - 'callback result is wrong type: ' + str(result)) - self.assertEqual(len(result), 3, - 'callback result list should have three entries: ' + - str(result)) - self.assertEqual(result[1], MESSAGE_ID, - "callback result Message-Id doesn't match: %s vs %s" % - (MESSAGE_ID, result[1])) - body = result[2].read() - self.failIfEqual(body.find('\r\n\r\n'), -1, - "Can't find \\r\\n\\r\\n between header and body") - return result - - d.addCallback(cbArticle) - return d - - - def testHeadRequest(self): - d = self.testArticleRequest() - - def cbArticle(result): - index = result[0] - - d = self.backend.headRequest("alt.test.nntp", index) - d.addCallback(cbHead) - return d - - def cbHead(result): - self.assertEqual(result[1], MESSAGE_ID, - "callback result Message-Id doesn't match: %s vs %s" % - (MESSAGE_ID, result[1])) - - self.assertEqual(result[2][-2:], '\r\n', - "headers must be \\r\\n terminated.") - - d.addCallback(cbArticle) - return d - - - def testBodyRequest(self): - d = self.testArticleRequest() - - def cbArticle(result): - index = result[0] - - d = self.backend.bodyRequest("alt.test.nntp", index) - d.addCallback(cbBody) - return d - - def cbBody(result): - body = result[2].read() - self.assertEqual(body[0:4], 'this', - "message body has been altered: " + - pformat(body[0:4])) - - d.addCallback(cbArticle) - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_nntp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_nntp.py deleted file mode 100644 index d4c143f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/test/test_nntp.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.news import database -from twisted.news import nntp -from twisted.protocols import loopback -from twisted.test import proto_helpers - -ALL_GROUPS = ('alt.test.nntp', 0, 1, 'y'), -GROUP = ('0', '1', '0', 'alt.test.nntp', 'group', 'selected') -SUBSCRIPTIONS = ['alt.test.nntp', 'news.testgroup'] - -POST_STRING = """Path: not-for-mail -From: -Subject: a test -Newsgroups: alt.test.nntp -Organization: -Summary: -Keywords: -User-Agent: tin/1.4.5-20010409 ("One More Nightmare") (UNIX) (Linux/2.4.17 (i686)) - -this is a test -. -.. -... -lala -moo --- -"One World, one Web, one Program." - Microsoft(R) promotional ad -"Ein Volk, ein Reich, ein Fuhrer." - Adolf Hitler --- - 10:56pm up 4 days, 4:42, 1 user, load average: 0.08, 0.08, 0.12 -""" - -class TestNNTPClient(nntp.NNTPClient): - def __init__(self): - nntp.NNTPClient.__init__(self) - - def assertEqual(self, foo, bar): - if foo != bar: raise AssertionError("%r != %r!" % (foo, bar)) - - def connectionMade(self): - nntp.NNTPClient.connectionMade(self) - self.fetchSubscriptions() - - - def gotSubscriptions(self, subscriptions): - self.assertEqual(len(subscriptions), len(SUBSCRIPTIONS)) - for s in subscriptions: - assert s in SUBSCRIPTIONS - - self.fetchGroups() - - def gotAllGroups(self, info): - self.assertEqual(len(info), len(ALL_GROUPS)) - self.assertEqual(info[0], ALL_GROUPS[0]) - - self.fetchGroup('alt.test.nntp') - - - def getAllGroupsFailed(self, error): - raise AssertionError("fetchGroups() failed: %s" % (error,)) - - - def gotGroup(self, info): - self.assertEqual(len(info), 6) - self.assertEqual(info, GROUP) - - self.postArticle(POST_STRING) - - - def getSubscriptionsFailed(self, error): - raise AssertionError("fetchSubscriptions() failed: %s" % (error,)) - - - def getGroupFailed(self, error): - raise AssertionError("fetchGroup() failed: %s" % (error,)) - - - def postFailed(self, error): - raise AssertionError("postArticle() failed: %s" % (error,)) - - - def postedOk(self): - self.fetchArticle(1) - - - def gotArticle(self, info): - origBody = POST_STRING.split('\n\n')[1] - newBody = info.split('\n\n', 1)[1] - - self.assertEqual(origBody, newBody) - - # We're done - self.transport.loseConnection() - - - def getArticleFailed(self, error): - raise AssertionError("fetchArticle() failed: %s" % (error,)) - - -class NNTPTests(unittest.TestCase): - def setUp(self): - self.server = nntp.NNTPServer() - self.server.factory = self - self.backend = database.NewsShelf(None, 'news.db') - self.backend.addGroup('alt.test.nntp', 'y') - - for s in SUBSCRIPTIONS: - self.backend.addSubscription(s) - - self.transport = proto_helpers.StringTransport() - self.server.makeConnection(self.transport) - self.client = TestNNTPClient() - - def testLoopback(self): - return loopback.loopbackAsync(self.server, self.client) - - # XXX This test is woefully incomplete. It tests the single - # most common code path and nothing else. Expand it and the - # test fairy will leave you a surprise. - - # reactor.iterate(1) # fetchGroups() - # reactor.iterate(1) # fetchGroup() - # reactor.iterate(1) # postArticle() - - - def test_connectionMade(self): - """ - When L{NNTPServer} is connected, it sends a server greeting to the - client. - """ - self.assertEqual( - self.transport.value().split('\r\n'), [ - '200 server ready - posting allowed', - '']) - - - def test_LIST(self): - """ - When L{NTTPServer} receives a I{LIST} command, it sends a list of news - groups to the client (RFC 3977, section 7.6.1.1). - """ - self.transport.clear() - self.server.do_LIST() - self.assertEqual( - self.transport.value().split('\r\n'), [ - '215 newsgroups in form "group high low flags"', - 'alt.test.nntp 0 1 y', - '.', - '']) - - - def test_GROUP(self): - """ - When L{NNTPServer} receives a I{GROUP} command, it sends a line of - information about that group to the client (RFC 3977, section 6.1.1.1). - """ - self.transport.clear() - self.server.do_GROUP('alt.test.nntp') - self.assertEqual( - self.transport.value().split('\r\n'), [ - '211 0 1 0 alt.test.nntp group selected', - '']) - - - def test_LISTGROUP(self): - """ - When L{NNTPServer} receives a I{LISTGROUP} command, it sends a list of - message numbers for the messages in a particular group (RFC 3977, - section 6.1.2.1). - """ - self.transport.clear() - self.server.do_LISTGROUP('alt.test.nntp') - self.assertEqual( - self.transport.value().split('\r\n'), [ - '211 list of article numbers follow', - '.', - '']) - - - def test_XROVER(self): - """ - When L{NTTPServer} receives a I{XROVER} command, it sends a list of - I{References} header values for the messages in a particular group (RFC - 2980, section 2.11). - """ - self.server.do_GROUP('alt.test.nntp') - self.transport.clear() - - self.server.do_XROVER() - self.assertEqual( - self.transport.value().split('\r\n'), [ - '221 Header follows', - '.', - '']) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/NEWS deleted file mode 100644 index da2e8f5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/NEWS +++ /dev/null @@ -1,189 +0,0 @@ -Ticket numbers in this file can be looked up by visiting -http://twistedmatrix.com/trac/ticket/ - -Twisted News 15.2.1 (2015-05-23) -================================ - -No significant changes have been made for this release. - - -Twisted News 15.2.0 (2015-05-18) -================================ - -No significant changes have been made for this release. - - -Twisted News 15.1.0 (2015-04-02) -================================ - -No significant changes have been made for this release. - - -Twisted News 15.0.0 (2015-01-24) -================================ - -No significant changes have been made for this release. - -Other ------ - - #7703 - - -Twisted News 14.0.2 (2014-09-18) -================================ - -No significant changes have been made for this release. - - -Twisted News 14.0.1 (2014-09-17) -================================ - -No significant changes have been made for this release. - - -Twisted News 14.0.0 (2014-05-08) -================================ - -No significant changes have been made for this release. - -Other ------ - - #6991 - - -Twisted News 13.2.0 (2013-10-29) -================================ - -No significant changes have been made for this release. - - -Twisted News 13.1.0 (2013-06-23) -================================ - -No significant changes have been made for this release. - -Other ------ - - #6342 - - -Twisted News 13.0.0 (2013-03-19) -================================ - -No significant changes have been made for this release. - - -Twisted News 12.3.0 (2012-12-20) -================================ - -No significant changes have been made for this release. - - -Twisted News 12.2.0 (2012-08-26) -================================ - -No significant changes have been made for this release. - - -Twisted News 12.1.0 (2012-06-02) -================================ - -Bugfixes --------- - - twisted.news.nntp.NNTPServer now has additional test coverage and - less redundant implementation code. (#5537) - -Deprecations and Removals -------------------------- - - The ability to pass a string article to NNTPServer._gotBody and - NNTPServer._gotArticle in t.news.nntp has been deprecated for years - and is now removed. (#4548) - - -Twisted News 12.0.0 (2012-02-10) -================================ - -No significant changes have been made for this release. - - -Twisted News 11.1.0 (2011-11-15) -================================ - -No significant changes have been made for this release. - - -Twisted News 11.0.0 (2011-04-01) -================================ - -No significant changes have been made for this release. - -Other ------ - - #4580 - - -Twisted News 10.2.0 (2010-11-29) -================================ - -Bugfixes --------- - - twisted.news.database.PickleStorage now invokes the email APIs - correctly, allowing it to actually send moderation emails. (#4528) - - -Twisted News 10.1.0 (2010-06-27) -================================ - -No significant changes have been made for this release. - - -Twisted News 10.0.0 (2010-03-01) -================================ - -No interesting changes since Twisted 9.0. - - -Twisted News 9.0.0 (2009-11-24) -=============================== - -Other ------ - - #2763, #3540 - - -News 8.2.0 (2008-12-16) -======================= - -No interesting changes since Twisted 8.0. - - -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Misc ----- - - Remove all "API Stability" markers (#2847) - - -0.3.0 (2007-01-06) -================== -Fixes ------ - - News was updated to work with the latest twisted.components changes - to Twisted (#1636) - - The 'ip' attribute is no longer available on NNTP protocols (#1936) - - -0.2.0 (2006-05-24) -================== - -Fixes: - - Fixed a critical bug in moderation support. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/README deleted file mode 100644 index abedd1f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/README +++ /dev/null @@ -1,4 +0,0 @@ -Twisted News 15.2.1 - -News depends on Twisted, and, if you want to use the moderation -features, Twisted Mail. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/setup.py deleted file mode 100644 index d776f30..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/news/topfiles/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="news", - # metadata - name="Twisted News", - description="Twisted News is an NNTP server and programming library.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - url="http://twistedmatrix.com/trac/wiki/TwistedNews", - license="MIT", - long_description="""\ -Twisted News is an NNTP protocol (Usenet) programming library. The -library contains server and client protocol implementations. A simple -NNTP server is also provided. -""", - ) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/__init__.py deleted file mode 100644 index 6d3f5aa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Pair: The framework of your ethernet. - -Low-level networking transports and utilities. - -See also twisted.protocols.ethernet, twisted.protocols.ip, -twisted.protocols.raw and twisted.protocols.rawudp. - -Maintainer: Tommi Virtanen - -""" - -from twisted.pair._version import version -__version__ = version.short() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/_version.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/_version.py deleted file mode 100644 index c46a792..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/_version.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This is an auto-generated file. Do not edit it. - -""" -Provides Twisted version information. -""" - -from twisted.python import versions -version = versions.Version('twisted.pair', 15, 2, 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/ethernet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/ethernet.py deleted file mode 100644 index b432c6f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/ethernet.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- test-case-name: twisted.pair.test.test_ethernet -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -"""Support for working directly with ethernet frames""" - -import struct - - -from twisted.internet import protocol -from twisted.pair import raw -from zope.interface import implements, Interface - - -class IEthernetProtocol(Interface): - """An interface for protocols that handle Ethernet frames""" - def addProto(): - """Add an IRawPacketProtocol protocol""" - - def datagramReceived(): - """An Ethernet frame has been received""" - -class EthernetHeader: - def __init__(self, data): - - (self.dest, self.source, self.proto) \ - = struct.unpack("!6s6sH", data[:6+6+2]) - -class EthernetProtocol(protocol.AbstractDatagramProtocol): - - implements(IEthernetProtocol) - - def __init__(self): - self.etherProtos = {} - - def addProto(self, num, proto): - proto = raw.IRawPacketProtocol(proto) - if num < 0: - raise TypeError, 'Added protocol must be positive or zero' - if num >= 2**16: - raise TypeError, 'Added protocol must fit in 16 bits' - if num not in self.etherProtos: - self.etherProtos[num] = [] - self.etherProtos[num].append(proto) - - def datagramReceived(self, data, partial=0): - header = EthernetHeader(data[:14]) - for proto in self.etherProtos.get(header.proto, ()): - proto.datagramReceived(data=data[14:], - partial=partial, - dest=header.dest, - source=header.source, - protocol=header.proto) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/ip.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/ip.py deleted file mode 100644 index de03bd4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/ip.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- test-case-name: twisted.pair.test.test_ip -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -"""Support for working directly with IP packets""" - -import struct -import socket - -from twisted.internet import protocol -from twisted.pair import raw -from zope.interface import implements - - -class IPHeader: - def __init__(self, data): - - (ihlversion, self.tos, self.tot_len, self.fragment_id, frag_off, - self.ttl, self.protocol, self.check, saddr, daddr) \ - = struct.unpack("!BBHHHBBH4s4s", data[:20]) - self.saddr = socket.inet_ntoa(saddr) - self.daddr = socket.inet_ntoa(daddr) - self.version = ihlversion & 0x0F - self.ihl = ((ihlversion & 0xF0) >> 4) << 2 - self.fragment_offset = frag_off & 0x1FFF - self.dont_fragment = (frag_off & 0x4000 != 0) - self.more_fragments = (frag_off & 0x2000 != 0) - -MAX_SIZE = 2L**32 - -class IPProtocol(protocol.AbstractDatagramProtocol): - implements(raw.IRawPacketProtocol) - - def __init__(self): - self.ipProtos = {} - - def addProto(self, num, proto): - proto = raw.IRawDatagramProtocol(proto) - if num < 0: - raise TypeError, 'Added protocol must be positive or zero' - if num >= MAX_SIZE: - raise TypeError, 'Added protocol must fit in 32 bits' - if num not in self.ipProtos: - self.ipProtos[num] = [] - self.ipProtos[num].append(proto) - - def datagramReceived(self, - data, - partial, - dest, - source, - protocol): - header = IPHeader(data) - for proto in self.ipProtos.get(header.protocol, ()): - proto.datagramReceived(data=data[20:], - partial=partial, - source=header.saddr, - dest=header.daddr, - protocol=header.protocol, - version=header.version, - ihl=header.ihl, - tos=header.tos, - tot_len=header.tot_len, - fragment_id=header.fragment_id, - fragment_offset=header.fragment_offset, - dont_fragment=header.dont_fragment, - more_fragments=header.more_fragments, - ttl=header.ttl, - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/raw.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/raw.py deleted file mode 100644 index f205f66..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/raw.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -"""Interface definitions for working with raw packets""" - -from zope.interface import Interface - - -class IRawDatagramProtocol(Interface): - """An interface for protocols such as UDP, ICMP and TCP.""" - - def addProto(): - """ - Add a protocol on top of this one. - """ - - def datagramReceived(): - """ - An IP datagram has been received. Parse and process it. - """ - - -class IRawPacketProtocol(Interface): - """An interface for low-level protocols such as IP and ARP.""" - - def addProto(): - """ - Add a protocol on top of this one. - """ - - def datagramReceived(): - """ - An IP datagram has been received. Parse and process it. - """ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/rawudp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/rawudp.py deleted file mode 100644 index 1425e6b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/rawudp.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- test-case-name: twisted.pair.test.test_rawudp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Implementation of raw packet interfaces for UDP""" - -import struct - -from twisted.internet import protocol -from twisted.pair import raw -from zope.interface import implements - -class UDPHeader: - def __init__(self, data): - - (self.source, self.dest, self.len, self.check) \ - = struct.unpack("!HHHH", data[:8]) - -class RawUDPProtocol(protocol.AbstractDatagramProtocol): - implements(raw.IRawDatagramProtocol) - def __init__(self): - self.udpProtos = {} - - def addProto(self, num, proto): - if not isinstance(proto, protocol.DatagramProtocol): - raise TypeError, 'Added protocol must be an instance of DatagramProtocol' - if num < 0: - raise TypeError, 'Added protocol must be positive or zero' - if num >= 2**16: - raise TypeError, 'Added protocol must fit in 16 bits' - if num not in self.udpProtos: - self.udpProtos[num] = [] - self.udpProtos[num].append(proto) - - def datagramReceived(self, - data, - partial, - source, - dest, - protocol, - version, - ihl, - tos, - tot_len, - fragment_id, - fragment_offset, - dont_fragment, - more_fragments, - ttl): - header = UDPHeader(data) - for proto in self.udpProtos.get(header.dest, ()): - proto.datagramReceived(data[8:], - (source, header.source)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/__init__.py deleted file mode 100644 index 5aa286e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -'pair tests' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_ethernet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_ethernet.py deleted file mode 100644 index 7554d06..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_ethernet.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -from twisted.trial import unittest - -from twisted.python import components -from twisted.pair import ethernet, raw -from zope.interface import implements - - -class MyProtocol: - implements(raw.IRawPacketProtocol) - - def __init__(self, expecting): - self.expecting = list(expecting) - - def datagramReceived(self, data, **kw): - assert self.expecting, 'Got a packet when not expecting anymore.' - expect = self.expecting.pop(0) - assert expect == (data, kw), \ - "Expected %r, got %r" % ( - expect, (data, kw), - ) - -class EthernetTests(unittest.TestCase): - def testPacketParsing(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ]) - proto.addProto(0x0800, p1) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultiplePackets(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ('quux', { - 'partial': 1, - 'dest': "012345", - 'source': "abcdef", - 'protocol': 0x0800, - }), - - ]) - proto.addProto(0x0800, p1) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x00quux", - partial=1) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultipleSameProtos(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ]) - - p2 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ]) - - proto.addProto(0x0800, p1) - proto.addProto(0x0800, p2) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testWrongProtoNotSeen(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([]) - proto.addProto(0x0801, p1) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x00quux", - partial=1) - - def testDemuxing(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ('quux', { - 'partial': 1, - 'dest': "012345", - 'source': "abcdef", - 'protocol': 0x0800, - }), - - ]) - proto.addProto(0x0800, p1) - - p2 = MyProtocol([ - - ('quux', { - 'partial': 1, - 'dest': "012345", - 'source': "abcdef", - 'protocol': 0x0806, - }), - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0806, - }), - - ]) - proto.addProto(0x0806, p2) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x06quux", - partial=1) - proto.datagramReceived("123456987654\x08\x06foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x00quux", - partial=1) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testAddingBadProtos_WrongLevel(self): - """Adding a wrong level protocol raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(42, "silliness") - except components.CannotAdapt: - pass - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooSmall(self): - """Adding a protocol with a negative number raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(-1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must be positive or zero',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooBig(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(2**16, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - def testAddingBadProtos_TooBig2(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(2**16+1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_ip.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_ip.py deleted file mode 100644 index e7cc444..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_ip.py +++ /dev/null @@ -1,415 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -from twisted.trial import unittest - -from twisted.python import components -from twisted.pair import ip, raw -from zope import interface - - -class MyProtocol: - interface.implements(raw.IRawDatagramProtocol) - - def __init__(self, expecting): - self.expecting = list(expecting) - - def datagramReceived(self, data, **kw): - assert self.expecting, 'Got a packet when not expecting anymore.' - expectData, expectKw = self.expecting.pop(0) - - expectKwKeys = expectKw.keys(); expectKwKeys.sort() - kwKeys = kw.keys(); kwKeys.sort() - assert expectKwKeys == kwKeys, "Expected %r, got %r" % (expectKwKeys, kwKeys) - - for k in expectKwKeys: - assert expectKw[k] == kw[k], "Expected %s=%r, got %r" % (k, expectKw[k], kw[k]) - assert expectKw == kw, "Expected %r, got %r" % (expectKw, kw) - assert expectData == data, "Expected %r, got %r" % (expectData, data) - -class IPTests(unittest.TestCase): - def testPacketParsing(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - proto.addProto(0x0F, p1) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - def testMultiplePackets(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ('quux', { - 'partial': 1, - 'dest': '5.4.3.2', - 'source': '6.7.8.9', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - proto.addProto(0x0F, p1) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x06\x07\x08\x09" + "\x05\x04\x03\x02" + "quux", - partial=1, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultipleSameProtos(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - - p2 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - - proto.addProto(0x0F, p1) - proto.addProto(0x0F, p2) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testWrongProtoNotSeen(self): - proto = ip.IPProtocol() - p1 = MyProtocol([]) - proto.addProto(1, p1) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - def testDemuxing(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ('quux', { - 'partial': 1, - 'dest': '5.4.3.2', - 'source': '6.7.8.9', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - proto.addProto(0x0F, p1) - - p2 = MyProtocol([ - - ('quux', { - 'partial': 1, - 'dest': '5.4.3.2', - 'source': '6.7.8.9', - 'protocol': 0x0A, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0A, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - - ]) - proto.addProto(0x0A, p2) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0A" #protocol - + "FE" #checksum - + "\x06\x07\x08\x09" + "\x05\x04\x03\x02" + "quux", - partial=1, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x06\x07\x08\x09" + "\x05\x04\x03\x02" + "quux", - partial=1, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0A" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testAddingBadProtos_WrongLevel(self): - """Adding a wrong level protocol raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(42, "silliness") - except components.CannotAdapt: - pass - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooSmall(self): - """Adding a protocol with a negative number raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(-1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must be positive or zero',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooBig(self): - """Adding a protocol with a number >=2**32 raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(2L**32, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 32 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - def testAddingBadProtos_TooBig2(self): - """Adding a protocol with a number >=2**32 raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(2L**32+1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 32 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_rawudp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_rawudp.py deleted file mode 100644 index 29e445c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_rawudp.py +++ /dev/null @@ -1,326 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.trial import unittest - -from twisted.internet import protocol -from twisted.pair import rawudp - -class MyProtocol(protocol.DatagramProtocol): - def __init__(self, expecting): - self.expecting = list(expecting) - - def datagramReceived(self, data, (host, port)): - assert self.expecting, 'Got a packet when not expecting anymore.' - expectData, expectHost, expectPort = self.expecting.pop(0) - - assert expectData == data, "Expected data %r, got %r" % (expectData, data) - assert expectHost == host, "Expected host %r, got %r" % (expectHost, host) - assert expectPort == port, "Expected port %d=0x%04x, got %d=0x%04x" % (expectPort, expectPort, port, port) - -class RawUDPTests(unittest.TestCase): - def testPacketParsing(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - - ]) - proto.addProto(0xF00F, p1) - - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - def testMultiplePackets(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - ('quux', 'otherHost', 0x33FE), - - ]) - proto.addProto(0xF00F, p1) - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\x33\xFE" #source - + "\xf0\x0f" #dest - + "\x00\x05" #len - + "\xDE\xAD" #check - + "quux", - partial=0, - dest='dummy', - source='otherHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultipleSameProtos(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - - ]) - - p2 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - - ]) - - proto.addProto(0xF00F, p1) - proto.addProto(0xF00F, p2) - - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testWrongProtoNotSeen(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([]) - proto.addProto(1, p1) - - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - def testDemuxing(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - ('quux', 'otherHost', 0x33FE), - - ]) - proto.addProto(0xF00F, p1) - - p2 = MyProtocol([ - - ('quux', 'otherHost', 0xA401), - ('foobar', 'testHost', 0xA302), - - ]) - proto.addProto(0xB050, p2) - - proto.datagramReceived("\xA4\x01" #source - + "\xB0\x50" #dest - + "\x00\x05" #len - + "\xDE\xAD" #check - + "quux", - partial=0, - dest='dummy', - source='otherHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\x33\xFE" #source - + "\xf0\x0f" #dest - + "\x00\x05" #len - + "\xDE\xAD" #check - + "quux", - partial=0, - dest='dummy', - source='otherHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\xA3\x02" #source - + "\xB0\x50" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testAddingBadProtos_WrongLevel(self): - """Adding a wrong level protocol raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(42, "silliness") - except TypeError, e: - if e.args == ('Added protocol must be an instance of DatagramProtocol',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooSmall(self): - """Adding a protocol with a negative number raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(-1, protocol.DatagramProtocol()) - except TypeError, e: - if e.args == ('Added protocol must be positive or zero',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooBig(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(2**16, protocol.DatagramProtocol()) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - def testAddingBadProtos_TooBig2(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(2**16+1, protocol.DatagramProtocol()) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_tuntap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_tuntap.py deleted file mode 100644 index 0333c73..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/test/test_tuntap.py +++ /dev/null @@ -1,1397 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.pair.tuntap}. -""" - -from __future__ import division, absolute_import - -import os -import struct -import socket -from errno import EPERM, EBADF, EINVAL, EAGAIN, EWOULDBLOCK, ENOENT, ENODEV -from random import randrange -from collections import deque -from itertools import cycle -from signal import SIGINT - -from twisted.python.reflect import ObjectNotFound, namedAny - -try: - namedAny("fcntl.ioctl") -except (ObjectNotFound, AttributeError): - platformSkip = "Platform is missing fcntl/ioctl support" -else: - platformSkip = None - -from zope.interface import Interface, implementer -from zope.interface.verify import verifyObject - -from twisted.internet.interfaces import IListeningPort -from twisted.internet.protocol import DatagramProtocol -from twisted.pair.rawudp import RawUDPProtocol -from twisted.pair.ip import IPProtocol -from twisted.pair.ethernet import EthernetProtocol - -from twisted.python.reflect import fullyQualifiedName -from twisted.python.compat import iterbytes -from twisted.python.log import addObserver, removeObserver, textFromEventDict -from twisted.internet.interfaces import IAddress, IReactorFDSet -from twisted.internet.protocol import AbstractDatagramProtocol, Factory -from twisted.internet.task import Clock -from twisted.trial.unittest import SkipTest, SynchronousTestCase -from twisted.internet.error import CannotListenError -from twisted.pair.raw import IRawPacketProtocol - -# Let the module-scope testing subclass of this still be defined (and then not -# used) in case we can't import from twisted.pair.testing due to platform -# limitations. -_RealSystem = object - -# Same rationale as for _RealSystem. -_IInputOutputSystem = Interface - - -if platformSkip is None: - from twisted.pair.testing import ( - _PI_SIZE, Tunnel, MemoryIOSystem, _IPv4, _H, _ethernet, _ip, _udp) - - from twisted.pair.tuntap import ( - _TUNSETIFF, _IFNAMSIZ, _RealSystem, - _IInputOutputSystem, TunnelFlags, TunnelAddress, TuntapPort) -else: - skip = platformSkip - - - -@implementer(IReactorFDSet) -class ReactorFDSet(object): - """ - An implementation of L{IReactorFDSet} which only keeps track of which - descriptors have been registered for reading and writing. - - This implementation isn't actually capable of determining readability or - writeability and generates no events for the descriptors registered with - it. - - @ivar _readers: A L{set} of L{IReadDescriptor} providers which the reactor - is supposedly monitoring for read events. - - @ivar _writers: A L{set} of L{IWriteDescriptor} providers which the reactor - is supposedly monitoring for write events. - """ - def __init__(self): - self._readers = set() - self._writers = set() - self.addReader = self._readers.add - self.addWriter = self._writers.add - - - def removeReader(self, reader): - self._readers.discard(reader) - - - def removeWriter(self, writer): - self._writers.discard(writer) - - - def getReaders(self): - return iter(self._readers) - - - def getWriters(self): - return iter(self._writers) - - - def removeAll(self): - try: - return list(self._readers | self._writers) - finally: - self._readers = set() - self._writers = set() -verifyObject(IReactorFDSet, ReactorFDSet()) - - - -class FSSetClock(Clock, ReactorFDSet): - """ - An L{FSSetClock} is a L{IReactorFDSet} and an L{IReactorClock}. - """ - def __init__(self): - Clock.__init__(self) - ReactorFDSet.__init__(self) - - - -class TunHelper(object): - """ - A helper for tests of tun-related functionality (ip-level tunnels). - """ - @property - def TUNNEL_TYPE(self): - # Hide this in a property because TunnelFlags is not always imported. - return TunnelFlags.IFF_TUN | TunnelFlags.IFF_NO_PI - - - def __init__(self, tunnelRemote, tunnelLocal): - """ - @param tunnelRemote: The source address for UDP datagrams originated - from this helper. This is an IPv4 dotted-quad string. - @type tunnelRemote: L{bytes} - - @param tunnelLocal: The destination address for UDP datagrams - originated from this helper. This is an IPv4 dotted-quad string. - @type tunnelLocal: L{bytes} - """ - self.tunnelRemote = tunnelRemote - self.tunnelLocal = tunnelLocal - - - def encapsulate(self, source, destination, payload): - """ - Construct an ip datagram containing a udp datagram containing the given - application-level payload. - - @param source: The source port for the UDP datagram being encapsulated. - @type source: L{int} - - @param destination: The destination port for the UDP datagram being - encapsulated. - @type destination: L{int} - - @param payload: The application data to include in the udp datagram. - @type payload: L{bytes} - - @return: An ethernet frame. - @rtype: L{bytes} - """ - return _ip( - src=self.tunnelRemote, dst=self.tunnelLocal, - payload=_udp( - src=source, dst=destination, payload=payload)) - - - def parser(self): - """ - Get a function for parsing a datagram read from a I{tun} device. - - @return: A function which accepts a datagram exactly as might be read - from a I{tun} device. The datagram is expected to ultimately carry - a UDP datagram. When called, it returns a L{list} of L{tuple}s. - Each tuple has the UDP application data as the first element and - the sender address as the second element. - """ - datagrams = [] - receiver = DatagramProtocol() - - def capture(*args): - datagrams.append(args) - - receiver.datagramReceived = capture - - udp = RawUDPProtocol() - udp.addProto(12345, receiver) - - ip = IPProtocol() - ip.addProto(17, udp) - - def parse(data): - # TUN devices omit the ethernet framing so we can start parsing - # right at the IP layer. - ip.datagramReceived(data, False, None, None, None) - return datagrams - - return parse - - - -class TapHelper(object): - """ - A helper for tests of tap-related functionality (ethernet-level tunnels). - """ - @property - def TUNNEL_TYPE(self): - flag = TunnelFlags.IFF_TAP - if not self.pi: - flag |= TunnelFlags.IFF_NO_PI - return flag - - - def __init__(self, tunnelRemote, tunnelLocal, pi): - """ - @param tunnelRemote: The source address for UDP datagrams originated - from this helper. This is an IPv4 dotted-quad string. - @type tunnelRemote: L{bytes} - - @param tunnelLocal: The destination address for UDP datagrams - originated from this helper. This is an IPv4 dotted-quad string. - @type tunnelLocal: L{bytes} - - @param pi: A flag indicating whether this helper will generate and - consume a protocol information (PI) header. - @type pi: L{bool} - """ - self.tunnelRemote = tunnelRemote - self.tunnelLocal = tunnelLocal - self.pi = pi - - - def encapsulate(self, source, destination, payload): - """ - Construct an ethernet frame containing an ip datagram containing a udp - datagram containing the given application-level payload. - - @param source: The source port for the UDP datagram being encapsulated. - @type source: L{int} - - @param destination: The destination port for the UDP datagram being - encapsulated. - @type destination: L{int} - - @param payload: The application data to include in the udp datagram. - @type payload: L{bytes} - - @return: An ethernet frame. - @rtype: L{bytes} - """ - tun = TunHelper(self.tunnelRemote, self.tunnelLocal) - ip = tun.encapsulate(source, destination, payload) - frame = _ethernet( - src='\x00\x00\x00\x00\x00\x00', dst='\xff\xff\xff\xff\xff\xff', - protocol=_IPv4, payload=ip) - if self.pi: - # Going to send a datagram using IPv4 addressing - protocol = _IPv4 - # There are no flags though - flags = 0 - frame = _H(flags) + _H(protocol) + frame - return frame - - - def parser(self): - """ - Get a function for parsing a datagram read from a I{tap} device. - - @return: A function which accepts a datagram exactly as might be read - from a I{tap} device. The datagram is expected to ultimately carry - a UDP datagram. When called, it returns a L{list} of L{tuple}s. - Each tuple has the UDP application data as the first element and - the sender address as the second element. - """ - datagrams = [] - receiver = DatagramProtocol() - - def capture(*args): - datagrams.append(args) - - receiver.datagramReceived = capture - - udp = RawUDPProtocol() - udp.addProto(12345, receiver) - - ip = IPProtocol() - ip.addProto(17, udp) - - ether = EthernetProtocol() - ether.addProto(0x800, ip) - - def parser(datagram): - # TAP devices might include a PI header. Strip that off if we - # expect it to be there. - if self.pi: - datagram = datagram[_PI_SIZE:] - - # TAP devices include ethernet framing so start parsing at the - # ethernet layer. - ether.datagramReceived(datagram) - return datagrams - - return parser - - - -class TunnelTests(SynchronousTestCase): - """ - L{Tunnel} is mostly tested by other test cases but some tests don't fit - there. Those tests are here. - """ - def test_blockingRead(self): - """ - Blocking reads are not implemented by L{Tunnel.read}. Attempting one - results in L{NotImplementedError} being raised. - """ - tunnel = Tunnel(MemoryIOSystem(), os.O_RDONLY, None) - self.assertRaises( - NotImplementedError, tunnel.read, 1024) - - - -class TunnelDeviceTestsMixin(object): - """ - A mixin defining tests that apply to L{_IInputOutputSystem} - implementations. - """ - def setUp(self): - """ - Create the L{_IInputOutputSystem} provider under test and open a tunnel - using it. - """ - self.system = self.createSystem() - self.fileno = self.system.open(b"/dev/net/tun", - os.O_RDWR | os.O_NONBLOCK) - self.addCleanup(self.system.close, self.fileno) - - mode = self.helper.TUNNEL_TYPE - config = struct.pack( - "%dsH" % (_IFNAMSIZ,), self._TUNNEL_DEVICE, mode.value) - self.system.ioctl(self.fileno, _TUNSETIFF, config) - - - def test_interface(self): - """ - The object under test provides L{_IInputOutputSystem}. - """ - self.assertTrue(verifyObject(_IInputOutputSystem, self.system)) - - - def _invalidFileDescriptor(self): - """ - Get an invalid file descriptor. - - @return: An integer which is not a valid file descriptor at the time of - this call. After any future system call which allocates a new file - descriptor, there is no guarantee the returned file descriptor will - still be invalid. - """ - fd = self.system.open(b"/dev/net/tun", os.O_RDWR) - self.system.close(fd) - return fd - - - def test_readEBADF(self): - """ - The device's C{read} implementation raises L{OSError} with an errno of - C{EBADF} when called on a file descriptor which is not valid (ie, which - has no associated file description). - """ - fd = self._invalidFileDescriptor() - exc = self.assertRaises(OSError, self.system.read, fd, 1024) - self.assertEqual(EBADF, exc.errno) - - - def test_writeEBADF(self): - """ - The device's C{write} implementation raises L{OSError} with an errno of - C{EBADF} when called on a file descriptor which is not valid (ie, which - has no associated file description). - """ - fd = self._invalidFileDescriptor() - exc = self.assertRaises(OSError, self.system.write, fd, b"bytes") - self.assertEqual(EBADF, exc.errno) - - - def test_closeEBADF(self): - """ - The device's C{close} implementation raises L{OSError} with an errno of - C{EBADF} when called on a file descriptor which is not valid (ie, which - has no associated file description). - """ - fd = self._invalidFileDescriptor() - exc = self.assertRaises(OSError, self.system.close, fd) - self.assertEqual(EBADF, exc.errno) - - - def test_ioctlEBADF(self): - """ - The device's C{ioctl} implementation raises L{OSError} with an errno of - C{EBADF} when called on a file descriptor which is not valid (ie, which - has no associated file description). - """ - fd = self._invalidFileDescriptor() - exc = self.assertRaises( - IOError, self.system.ioctl, fd, _TUNSETIFF, b"tap0") - self.assertEqual(EBADF, exc.errno) - - - def test_ioctlEINVAL(self): - """ - The device's C{ioctl} implementation raises L{IOError} with an errno of - C{EINVAL} when called with a request (second argument) which is not a - supported operation. - """ - # Try to invent an unsupported request. Hopefully this isn't a real - # request on any system. - request = 0xDEADBEEF - exc = self.assertRaises( - IOError, self.system.ioctl, self.fileno, request, b"garbage") - self.assertEqual(EINVAL, exc.errno) - - - def test_receive(self): - """ - If a UDP datagram is sent to an address reachable by the tunnel device - then it can be read out of the tunnel device. - """ - parse = self.helper.parser() - - found = False - - # Try sending the datagram a lot of times. There are no delivery - # guarantees for UDP - not even over localhost. - for i in range(100): - key = randrange(2 ** 64) - message = "hello world:%d" % (key,) - source = self.system.sendUDP(message, (self._TUNNEL_REMOTE, 12345)) - - # Likewise try receiving each of those datagrams a lot of times. - # Timing might cause us to miss it the first few dozen times - # through the loop. - for j in range(100): - try: - packet = self.system.read(self.fileno, 1024) - except EnvironmentError as e: - if e.errno in (EAGAIN, EWOULDBLOCK): - break - raise - else: - datagrams = parse(packet) - if (message, source) in datagrams: - found = True - break - del datagrams[:] - if found: - break - - if not found: - self.fail("Never saw probe UDP packet on tunnel") - - - def test_send(self): - """ - If a UDP datagram is written the tunnel device then it is received by - the network to which it is addressed. - """ - # Construct a unique application payload so the receiving side can - # unambiguously identify the datagram we sent. - key = randrange(2 ** 64) - message = "hello world:%d" % (key,) - - # To avoid really inconvenient test failures where the test just hangs - # forever, set up a timeout for blocking socket operations. This - # shouldn't ever be triggered when the test is passing. It only serves - # to make sure the test runs eventually completes if something is - # broken in a way that prevents real traffic from flowing. The value - # chosen is totally arbitrary (but it might coincidentally exactly - # match trial's builtin timeout for asynchronous tests). - self.addCleanup(socket.setdefaulttimeout, socket.getdefaulttimeout()) - socket.setdefaulttimeout(120) - - # Start listening for the test datagram first. The resulting port - # object can be used to receive datagrams sent to _TUNNEL_LOCAL:12345 - - # in other words, an application using the tunnel device will be able - # to cause datagrams to arrive at this port as though they actually - # traversed a network to arrive at this host. - port = self.system.receiveUDP(self.fileno, self._TUNNEL_LOCAL, 12345) - - # Construct a packet with the appropriate wrappers and headings so that - # it will arrive at the port created above. - packet = self.helper.encapsulate(50000, 12345, message) - - # Write the packet to the tunnel device. - self.system.write(self.fileno, packet) - - # Try to receive that datagram and verify it has the correct payload. - packet = port.recv(1024) - self.assertEqual(message, packet) - - - -class FakeDeviceTestsMixin(object): - """ - Define a mixin for use with test cases that require an - L{_IInputOutputSystem} provider. This mixin hands out L{MemoryIOSystem} - instances as the provider of that interface. - """ - _TUNNEL_DEVICE = "tap-twistedtest" - _TUNNEL_LOCAL = "172.16.2.1" - _TUNNEL_REMOTE = "172.16.2.2" - - def createSystem(self): - """ - Create and return a brand new L{MemoryIOSystem}. - - The L{MemoryIOSystem} knows how to open new tunnel devices. - - @return: The newly created I/O system object. - @rtype: L{MemoryIOSystem} - """ - system = MemoryIOSystem() - system.registerSpecialDevice(Tunnel._DEVICE_NAME, Tunnel) - return system - - - -class FakeTapDeviceTests(FakeDeviceTestsMixin, - TunnelDeviceTestsMixin, SynchronousTestCase): - """ - Run various tap-type tunnel unit tests against an in-memory I/O system. - """ -FakeTapDeviceTests.helper = TapHelper( - FakeTapDeviceTests._TUNNEL_REMOTE, FakeTapDeviceTests._TUNNEL_LOCAL, - pi=False) - - - -class FakeTapDeviceWithPITests(FakeDeviceTestsMixin, - TunnelDeviceTestsMixin, SynchronousTestCase): - """ - Run various tap-type tunnel unit tests against an in-memory I/O system with - the PI header enabled. - """ -FakeTapDeviceWithPITests.helper = TapHelper( - FakeTapDeviceTests._TUNNEL_REMOTE, FakeTapDeviceTests._TUNNEL_LOCAL, - pi=True) - - - -class FakeTunDeviceTests(FakeDeviceTestsMixin, - TunnelDeviceTestsMixin, SynchronousTestCase): - """ - Run various tun-type tunnel unit tests against an in-memory I/O system. - """ -FakeTunDeviceTests.helper = TunHelper( - FakeTunDeviceTests._TUNNEL_REMOTE, FakeTunDeviceTests._TUNNEL_LOCAL) - - - -@implementer(_IInputOutputSystem) -class TestRealSystem(_RealSystem): - """ - Add extra skipping logic so tests that try to create real tunnel devices on - platforms where those are not supported automatically get skipped. - """ - def open(self, filename, *args, **kwargs): - """ - Attempt an open, but if the file is /dev/net/tun and it does not exist, - translate the error into L{SkipTest} so that tests that require - platform support for tuntap devices are skipped instead of failed. - """ - try: - return super(TestRealSystem, self).open(filename, *args, **kwargs) - except OSError as e: - # The device file may simply be missing. The device file may also - # exist but be unsupported by the kernel. - if e.errno in (ENOENT, ENODEV) and filename == b"/dev/net/tun": - raise SkipTest("Platform lacks /dev/net/tun") - raise - - - def ioctl(self, *args, **kwargs): - """ - Attempt an ioctl, but translate permission denied errors into - L{SkipTest} so that tests that require elevated system privileges and - do not have them are skipped instead of failed. - """ - try: - return super(TestRealSystem, self).ioctl(*args, **kwargs) - except IOError as e: - if EPERM == e.errno: - raise SkipTest("Permission to configure device denied") - raise - - - def sendUDP(self, datagram, address): - """ - Use the platform network stack to send a datagram to the given address. - - @param datagram: A UDP datagram payload to send. - @type datagram: L{bytes} - - @param address: The destination to which to send the datagram. - @type address: L{tuple} of (L{bytes}, L{int}) - - @return: The address from which the UDP datagram was sent. - @rtype: L{tuple} of (L{bytes}, L{int}) - """ - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.bind(('172.16.0.1', 0)) - s.sendto(datagram, address) - return s.getsockname() - - - def receiveUDP(self, fileno, host, port): - """ - Use the platform network stack to receive a datagram sent to the given - address. - - @param fileno: The file descriptor of the tunnel used to send the - datagram. This is ignored because a real socket is used to receive - the datagram. - @type fileno: L{int} - - @param host: The IPv4 address at which the datagram will be received. - @type host: L{bytes} - - @param port: The UDP port number at which the datagram will be - received. - @type port: L{int} - - @return: A L{socket.socket} which can be used to receive the specified - datagram. - """ - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.bind((host, port)) - return s - - - -class RealDeviceTestsMixin(object): - """ - Define a mixin for use with test cases that require an - L{_IInputOutputSystem} provider. This mixin hands out L{TestRealSystem} - instances as the provider of that interface. - """ - if platformSkip: - skip = platformSkip - - - def createSystem(self): - """ - Create a real I/O system that can be used to open real tunnel device - provided by the underlying system and previously configured. - - @return: The newly created I/O system object. - @rtype: L{TestRealSystem} - """ - return TestRealSystem() - - - -class RealDeviceWithProtocolInformationTests(RealDeviceTestsMixin, - TunnelDeviceTestsMixin, - SynchronousTestCase): - """ - Run various tap-type tunnel unit tests, with "protocol information" (PI) - turned on, against a real I/O system. - """ - _TUNNEL_DEVICE = "tap-twtest-pi" - _TUNNEL_LOCAL = "172.16.1.1" - _TUNNEL_REMOTE = "172.16.1.2" - - # The PI flag is not an inherent part of the tunnel. It must be specified - # by each user of the tunnel. Thus, we must also have an indication of - # whether we want PI so the tests can properly initialize the tunnel - # device. - helper = TapHelper(_TUNNEL_REMOTE, _TUNNEL_LOCAL, pi=True) - - - -class RealDeviceWithoutProtocolInformationTests(RealDeviceTestsMixin, - TunnelDeviceTestsMixin, - SynchronousTestCase): - - """ - Run various tap-type tunnel unit tests, with "protocol information" (PI) - turned off, against a real I/O system. - """ - _TUNNEL_DEVICE = "tap-twtest" - _TUNNEL_LOCAL = "172.16.0.1" - _TUNNEL_REMOTE = "172.16.0.2" - - helper = TapHelper(_TUNNEL_REMOTE, _TUNNEL_LOCAL, pi=False) - - - -class TuntapPortTests(SynchronousTestCase): - """ - Tests for L{TuntapPort} behavior that is independent of the tunnel type. - """ - def test_interface(self): - """ - A L{TuntapPort} instance provides L{IListeningPort}. - """ - port = TuntapPort(b"device", EthernetProtocol()) - self.assertTrue(verifyObject(IListeningPort, port)) - - - def test_realSystem(self): - """ - When not initialized with an I/O system, L{TuntapPort} uses a - L{_RealSystem}. - """ - port = TuntapPort(b"device", EthernetProtocol()) - self.assertIsInstance(port._system, _RealSystem) - - - -class TunnelTestsMixin(object): - """ - A mixin defining tests for L{TuntapPort}. - - These tests run against L{MemoryIOSystem} (proven equivalent to the real - thing by the tests above) to avoid performing any real I/O. - """ - def setUp(self): - """ - Create an in-memory I/O system and set up a L{TuntapPort} against it. - """ - self.name = b"tun0" - self.system = MemoryIOSystem() - self.system.registerSpecialDevice(Tunnel._DEVICE_NAME, Tunnel) - self.protocol = self.factory.buildProtocol( - TunnelAddress(self.helper.TUNNEL_TYPE, self.name)) - self.reactor = FSSetClock() - self.port = TuntapPort( - self.name, self.protocol, reactor=self.reactor, system=self.system) - - - def _tunnelTypeOnly(self, flags): - """ - Mask off any flags except for L{TunnelType.IFF_TUN} and - L{TunnelType.IFF_TAP}. - - @param flags: Flags from L{TunnelType} to mask. - @type flags: L{FlagConstant} - - @return: The flags given by C{flags} except the two type flags. - @rtype: L{FlagConstant} - """ - return flags & (TunnelFlags.IFF_TUN | TunnelFlags.IFF_TAP) - - - def test_startListeningOpensDevice(self): - """ - L{TuntapPort.startListening} opens the tunnel factory character special - device C{"/dev/net/tun"} and configures it as a I{tun} tunnel. - """ - system = self.system - self.port.startListening() - tunnel = self.system.getTunnel(self.port) - - expected = ( - system.O_RDWR | system.O_CLOEXEC | system.O_NONBLOCK, - b"tun0" + "\x00" * (_IFNAMSIZ - len(b"tun0")), - self.port.interface, False, True) - actual = ( - tunnel.openFlags, - tunnel.requestedName, - tunnel.name, tunnel.blocking, tunnel.closeOnExec) - self.assertEqual(expected, actual) - - - def test_startListeningSetsConnected(self): - """ - L{TuntapPort.startListening} sets C{connected} on the port object to - C{True}. - """ - self.port.startListening() - self.assertTrue(self.port.connected) - - - def test_startListeningConnectsProtocol(self): - """ - L{TuntapPort.startListening} calls C{makeConnection} on the protocol - the port was initialized with, passing the port as an argument. - """ - self.port.startListening() - self.assertIs(self.port, self.protocol.transport) - - - def test_startListeningStartsReading(self): - """ - L{TuntapPort.startListening} passes the port instance to the reactor's - C{addReader} method to begin watching the port's file descriptor for - data to read. - """ - self.port.startListening() - self.assertIn(self.port, self.reactor.getReaders()) - - - def test_startListeningHandlesOpenFailure(self): - """ - L{TuntapPort.startListening} raises L{CannotListenError} if opening the - tunnel factory character special device fails. - """ - self.system.permissions.remove('open') - self.assertRaises(CannotListenError, self.port.startListening) - - - def test_startListeningHandlesConfigureFailure(self): - """ - L{TuntapPort.startListening} raises L{CannotListenError} if the - C{ioctl} call to configure the tunnel device fails. - """ - self.system.permissions.remove('ioctl') - self.assertRaises(CannotListenError, self.port.startListening) - - - def _stopPort(self, port): - """ - Verify that the C{stopListening} method of an L{IListeningPort} removes - that port from the reactor's "readers" set and also that the - L{Deferred} returned by that method fires with C{None}. - - @param port: The port object to stop. - @type port: L{IListeningPort} provider - """ - stopped = port.stopListening() - self.assertNotIn(port, self.reactor.getReaders()) - # An unfortunate implementation detail - self.reactor.advance(0) - self.assertIs(None, self.successResultOf(stopped)) - - - def test_stopListeningStopsReading(self): - """ - L{TuntapPort.stopListening} returns a L{Deferred} which fires after the - port has been removed from the reactor's reader list by passing it to - the reactor's C{removeReader} method. - """ - self.port.startListening() - fileno = self.port.fileno() - self._stopPort(self.port) - - self.assertNotIn(fileno, self.system._openFiles) - - - def test_stopListeningUnsetsConnected(self): - """ - After the L{Deferred} returned by L{TuntapPort.stopListening} fires, - the C{connected} attribute of the port object is set to C{False}. - """ - self.port.startListening() - self._stopPort(self.port) - self.assertFalse(self.port.connected) - - - def test_stopListeningStopsProtocol(self): - """ - L{TuntapPort.stopListening} calls C{doStop} on the protocol the port - was initialized with. - """ - self.port.startListening() - self._stopPort(self.port) - self.assertIs(None, self.protocol.transport) - - - def test_stopListeningWhenStopped(self): - """ - L{TuntapPort.stopListening} returns a L{Deferred} which succeeds - immediately if it is called when the port is not listening. - """ - stopped = self.port.stopListening() - self.assertIs(None, self.successResultOf(stopped)) - - - def test_multipleStopListening(self): - """ - It is safe and a no-op to call L{TuntapPort.stopListening} more than - once with no intervening L{TuntapPort.startListening} call. - """ - self.port.startListening() - self.port.stopListening() - second = self.port.stopListening() - self.reactor.advance(0) - self.assertIs(None, self.successResultOf(second)) - - - def test_loseConnection(self): - """ - L{TuntapPort.loseConnection} stops the port and is deprecated. - """ - self.port.startListening() - - self.port.loseConnection() - # An unfortunate implementation detail - self.reactor.advance(0) - - self.assertFalse(self.port.connected) - warnings = self.flushWarnings([self.test_loseConnection]) - self.assertEqual(DeprecationWarning, warnings[0]['category']) - self.assertEqual( - "twisted.pair.tuntap.TuntapPort.loseConnection was deprecated " - "in Twisted 14.0.0; please use twisted.pair.tuntap.TuntapPort." - "stopListening instead", - warnings[0]['message']) - self.assertEqual(1, len(warnings)) - - - def _stopsReadingTest(self, style): - """ - Test that L{TuntapPort.doRead} has no side-effects under a certain - exception condition. - - @param style: An exception instance to arrange for the (python wrapper - around the) underlying platform I{read} call to fail with. - - @raise C{self.failureException}: If there are any observable - side-effects. - """ - self.port.startListening() - tunnel = self.system.getTunnel(self.port) - tunnel.nonBlockingExceptionStyle = style - self.port.doRead() - self.assertEqual([], self.protocol.received) - - - def test_eagainStopsReading(self): - """ - Once L{TuntapPort.doRead} encounters an I{EAGAIN} errno from a C{read} - call, it returns. - """ - self._stopsReadingTest(Tunnel.EAGAIN_STYLE) - - - def test_ewouldblockStopsReading(self): - """ - Once L{TuntapPort.doRead} encounters an I{EWOULDBLOCK} errno from a - C{read} call, it returns. - """ - self._stopsReadingTest(Tunnel.EWOULDBLOCK_STYLE) - - - def test_eintrblockStopsReading(self): - """ - Once L{TuntapPort.doRead} encounters an I{EINTR} errno from a C{read} - call, it returns. - """ - self._stopsReadingTest(Tunnel.EINTR_STYLE) - - - def test_unhandledReadError(self): - """ - If L{Tuntap.doRead} encounters any exception other than one explicitly - handled by the code, the exception propagates to the caller. - """ - class UnexpectedException(Exception): - pass - - self.assertRaises( - UnexpectedException, - self._stopsReadingTest, UnexpectedException()) - - - def test_unhandledEnvironmentReadError(self): - """ - Just like C{test_unhandledReadError}, but for the case where the - exception that is not explicitly handled happens to be of type - C{EnvironmentError} (C{OSError} or C{IOError}). - """ - self.assertRaises( - IOError, - self._stopsReadingTest, IOError(EPERM, "Operation not permitted")) - - - def test_doReadSmallDatagram(self): - """ - L{TuntapPort.doRead} reads a datagram of fewer than - C{TuntapPort.maxPacketSize} from the port's file descriptor and passes - it to its protocol's C{datagramReceived} method. - """ - datagram = b'x' * (self.port.maxPacketSize - 1) - self.port.startListening() - tunnel = self.system.getTunnel(self.port) - tunnel.readBuffer.append(datagram) - self.port.doRead() - self.assertEqual([datagram], self.protocol.received) - - - def test_doReadLargeDatagram(self): - """ - L{TuntapPort.doRead} reads the first part of a datagram of more than - C{TuntapPort.maxPacketSize} from the port's file descriptor and passes - the truncated data to its protocol's C{datagramReceived} method. - """ - datagram = b'x' * self.port.maxPacketSize - self.port.startListening() - tunnel = self.system.getTunnel(self.port) - tunnel.readBuffer.append(datagram + b'y') - self.port.doRead() - self.assertEqual([datagram], self.protocol.received) - - - def test_doReadSeveralDatagrams(self): - """ - L{TuntapPort.doRead} reads several datagrams, of up to - C{TuntapPort.maxThroughput} bytes total, before returning. - """ - values = cycle(iterbytes(b'abcdefghijklmnopqrstuvwxyz')) - total = 0 - datagrams = [] - while total < self.port.maxThroughput: - datagrams.append(next(values) * self.port.maxPacketSize) - total += self.port.maxPacketSize - - self.port.startListening() - tunnel = self.system.getTunnel(self.port) - tunnel.readBuffer.extend(datagrams) - tunnel.readBuffer.append(b'excessive datagram, not to be read') - - self.port.doRead() - self.assertEqual(datagrams, self.protocol.received) - - - def _datagramReceivedException(self): - """ - Deliver some data to a L{TuntapPort} hooked up to an application - protocol that raises an exception from its C{datagramReceived} method. - - @return: Whatever L{AttributeError} exceptions are logged. - """ - self.port.startListening() - self.system.getTunnel(self.port).readBuffer.append(b"ping") - - # Break the application logic - self.protocol.received = None - - self.port.doRead() - return self.flushLoggedErrors(AttributeError) - - - def test_datagramReceivedException(self): - """ - If the protocol's C{datagramReceived} method raises an exception, the - exception is logged. - """ - errors = self._datagramReceivedException() - self.assertEqual(1, len(errors)) - - - def test_datagramReceivedExceptionIdentifiesProtocol(self): - """ - The exception raised by C{datagramReceived} is logged with a message - identifying the offending protocol. - """ - messages = [] - addObserver(messages.append) - self.addCleanup(removeObserver, messages.append) - self._datagramReceivedException() - error = next(m for m in messages if m['isError']) - message = textFromEventDict(error) - self.assertEqual( - "Unhandled exception from %s.datagramReceived" % ( - fullyQualifiedName(self.protocol.__class__),), - message.splitlines()[0]) - - - def test_write(self): - """ - L{TuntapPort.write} sends a datagram into the tunnel. - """ - datagram = b"a b c d e f g" - self.port.startListening() - self.port.write(datagram) - self.assertEqual( - self.system.getTunnel(self.port).writeBuffer, - deque([datagram])) - - - def test_interruptedWrite(self): - """ - If the platform write call is interrupted (causing the Python wrapper - to raise C{IOError} with errno set to C{EINTR}), the write is re-tried. - """ - self.port.startListening() - tunnel = self.system.getTunnel(self.port) - tunnel.pendingSignals.append(SIGINT) - self.port.write(b"hello, world") - self.assertEqual(deque([b"hello, world"]), tunnel.writeBuffer) - - - def test_unhandledWriteError(self): - """ - Any exception raised by the underlying write call, except for EINTR, is - propagated to the caller. - """ - self.port.startListening() - tunnel = self.system.getTunnel(self.port) - self.assertRaises( - IOError, - self.port.write, b"x" * tunnel.SEND_BUFFER_SIZE + b"y") - - - def test_writeSequence(self): - """ - L{TuntapPort.writeSequence} sends a datagram into the tunnel by - concatenating the byte strings in the list passed to it. - """ - datagram = [b"a", b"b", b"c", b"d"] - self.port.startListening() - self.port.writeSequence(datagram) - self.assertEqual( - self.system.getTunnel(self.port).writeBuffer, - deque([b"".join(datagram)])) - - - def test_getHost(self): - """ - L{TuntapPort.getHost} returns a L{TunnelAddress} including the tunnel's - type and name. - """ - self.port.startListening() - address = self.port.getHost() - self.assertEqual( - TunnelAddress( - self._tunnelTypeOnly(self.helper.TUNNEL_TYPE), - self.system.getTunnel(self.port).name), - address) - - - def test_listeningString(self): - """ - The string representation of a L{TuntapPort} instance includes the - tunnel type and interface and the protocol associated with the port. - """ - self.port.startListening() - expected = "<%s listening on %s/%s>" % ( - fullyQualifiedName(self.protocol.__class__), - self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name, - self.system.getTunnel(self.port).name) - - self.assertEqual(expected, str(self.port)) - - - def test_unlisteningString(self): - """ - The string representation of a L{TuntapPort} instance includes the - tunnel type and interface and the protocol associated with the port. - """ - expected = "<%s not listening on %s/%s>" % ( - fullyQualifiedName(self.protocol.__class__), - self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name, self.name) - - self.assertEqual(expected, str(self.port)) - - - def test_logPrefix(self): - """ - L{TuntapPort.logPrefix} returns a string identifying the application - protocol and the type of tunnel. - """ - self.assertEqual( - "%s (%s)" % ( - self.protocol.__class__.__name__, - self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name), - self.port.logPrefix()) - - - -class TunnelAddressTests(SynchronousTestCase): - """ - Tests for L{TunnelAddress}. - """ - def test_interfaces(self): - """ - A L{TunnelAddress} instances provides L{IAddress}. - """ - self.assertTrue( - verifyObject(IAddress, TunnelAddress(TunnelFlags.IFF_TAP, "tap0"))) - - - def test_indexing(self): - """ - A L{TunnelAddress} instance can be indexed to retrieve either the byte - string C{"TUNTAP"} or the name of the tunnel interface, while - triggering a deprecation warning. - """ - address = TunnelAddress(TunnelFlags.IFF_TAP, "tap0") - self.assertEqual("TUNTAP", address[0]) - self.assertEqual("tap0", address[1]) - warnings = self.flushWarnings([self.test_indexing]) - message = ( - "TunnelAddress.__getitem__ is deprecated since Twisted 14.0.0 " - "Use attributes instead.") - self.assertEqual(DeprecationWarning, warnings[0]['category']) - self.assertEqual(message, warnings[0]['message']) - self.assertEqual(DeprecationWarning, warnings[1]['category']) - self.assertEqual(message, warnings[1]['message']) - self.assertEqual(2, len(warnings)) - - - def test_repr(self): - """ - The string representation of a L{TunnelAddress} instance includes the - class name and the values of the C{type} and C{name} attributes. - """ - self.assertEqual( - "", - repr(TunnelAddress(TunnelFlags.IFF_TUN, name=b"device"))) - - - -class TunnelAddressEqualityTests(SynchronousTestCase): - """ - Tests for the implementation of equality (C{==} and C{!=}) for - L{TunnelAddress}. - """ - def setUp(self): - self.first = TunnelAddress(TunnelFlags.IFF_TUN, b"device") - - # Construct a different object representing IFF_TUN to make this a little - # trickier. Two FlagConstants from the same container and with the same - # value do not compare equal to each other. - # - # The implementation will have to compare their values directly until - # https://twistedmatrix.com/trac/ticket/6878 is resolved. - self.second = TunnelAddress( - TunnelFlags.IFF_TUN | TunnelFlags.IFF_TUN, b"device") - - self.variedType = TunnelAddress(TunnelFlags.IFF_TAP, b"tap1") - self.variedName = TunnelAddress(TunnelFlags.IFF_TUN, b"tun1") - - - def test_selfComparesEqual(self): - """ - A L{TunnelAddress} compares equal to itself. - """ - self.assertTrue(self.first == self.first) - - - def test_selfNotComparesNotEqual(self): - """ - A L{TunnelAddress} doesn't compare not equal to itself. - """ - self.assertFalse(self.first != self.first) - - - def test_sameAttributesComparesEqual(self): - """ - Two L{TunnelAddress} instances with the same value for the C{type} and - C{name} attributes compare equal to each other. - """ - self.assertTrue(self.first == self.second) - - - def test_sameAttributesNotComparesNotEqual(self): - """ - Two L{TunnelAddress} instances with the same value for the C{type} and - C{name} attributes don't compare not equal to each other. - """ - self.assertFalse(self.first != self.second) - - - def test_differentTypeComparesNotEqual(self): - """ - Two L{TunnelAddress} instances that differ only by the value of their - type don't compare equal to each other. - """ - self.assertFalse(self.first == self.variedType) - - - def test_differentTypeNotComparesEqual(self): - """ - Two L{TunnelAddress} instances that differ only by the value of their - type compare not equal to each other. - """ - self.assertTrue(self.first != self.variedType) - - - def test_differentNameComparesNotEqual(self): - """ - Two L{TunnelAddress} instances that differ only by the value of their - name don't compare equal to each other. - """ - self.assertFalse(self.first == self.variedName) - - - def test_differentNameNotComparesEqual(self): - """ - Two L{TunnelAddress} instances that differ only by the value of their - name compare not equal to each other. - """ - self.assertTrue(self.first != self.variedName) - - - def test_differentClassNotComparesEqual(self): - """ - A L{TunnelAddress} doesn't compare equal to an instance of another - class. - """ - self.assertFalse(self.first == self) - - - def test_differentClassComparesNotEqual(self): - """ - A L{TunnelAddress} compares not equal to an instance of another class. - """ - self.assertTrue(self.first != self) - - - -@implementer(IRawPacketProtocol) -class IPRecordingProtocol(AbstractDatagramProtocol): - """ - A protocol which merely records the datagrams delivered to it. - """ - def startProtocol(self): - self.received = [] - - - def datagramReceived(self, datagram, partial=False): - self.received.append(datagram) - - - -class TunTests(TunnelTestsMixin, SynchronousTestCase): - """ - Tests for L{TuntapPort} when used to open a Linux I{tun} tunnel. - """ - factory = Factory() - factory.protocol = IPRecordingProtocol - helper = TunHelper(None, None) - - - -class EthernetRecordingProtocol(EthernetProtocol): - """ - A protocol which merely records the datagrams delivered to it. - """ - def startProtocol(self): - self.received = [] - - - def datagramReceived(self, datagram, partial=False): - self.received.append(datagram) - - - -class TapTests(TunnelTestsMixin, SynchronousTestCase): - """ - Tests for L{TuntapPort} when used to open a Linux I{tap} tunnel. - """ - factory = Factory() - factory.protocol = EthernetRecordingProtocol - helper = TapHelper(None, None, pi=False) - - - -class IOSystemTestsMixin(object): - """ - Tests that apply to any L{_IInputOutputSystem} implementation. - """ - def test_noSuchDevice(self): - """ - L{_IInputOutputSystem.open} raises L{OSError} when called with a - non-existent device path. - """ - system = self.createSystem() - self.assertRaises( - OSError, - system.open, b"/dev/there-is-no-such-device-ever", os.O_RDWR) - - - -class MemoryIOSystemTests(IOSystemTestsMixin, SynchronousTestCase, - FakeDeviceTestsMixin): - """ - General L{_IInputOutputSystem} tests applied to L{MemoryIOSystem}. - """ - - - -class RealIOSystemTests(IOSystemTestsMixin, SynchronousTestCase, - RealDeviceTestsMixin): - """ - General L{_IInputOutputSystem} tests applied to L{_RealSystem}. - """ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/testing.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/testing.py deleted file mode 100644 index 4f4bf2f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/testing.py +++ /dev/null @@ -1,570 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tools for automated testing of L{twisted.pair}-based applications. -""" - -import struct -import socket -from errno import ( - EPERM, EAGAIN, EWOULDBLOCK, ENOSYS, EBADF, EINVAL, EINTR, ENOBUFS) -from collections import deque -from functools import wraps - -from zope.interface import implementer - -from twisted.internet.protocol import DatagramProtocol -from twisted.pair.ethernet import EthernetProtocol -from twisted.pair.rawudp import RawUDPProtocol -from twisted.pair.ip import IPProtocol -from twisted.pair.tuntap import ( - _IFNAMSIZ, _TUNSETIFF, _IInputOutputSystem, TunnelFlags) - - -# The number of bytes in the "protocol information" header that may be present -# on datagrams read from a tunnel device. This is two bytes of flags followed -# by two bytes of protocol identification. All this code does with this -# information is use it to discard the header. -_PI_SIZE = 4 - - -def _H(n): - """ - Pack an integer into a network-order two-byte string. - - @param n: The integer to pack. Only values that fit into 16 bits are - supported. - - @return: The packed representation of the integer. - @rtype: L{bytes} - """ - return struct.pack('>H', n) - - -_IPv4 = 0x0800 - - -def _ethernet(src, dst, protocol, payload): - """ - Construct an ethernet frame. - - @param src: The source ethernet address, encoded. - @type src: L{bytes} - - @param dst: The destination ethernet address, encoded. - @type dst: L{bytes} - - @param protocol: The protocol number of the payload of this datagram. - @type protocol: L{int} - - @param payload: The content of the ethernet frame (such as an IP datagram). - @type payload: L{bytes} - - @return: The full ethernet frame. - @rtype: L{bytes} - """ - return dst + src + _H(protocol) + payload - - - -def _ip(src, dst, payload): - """ - Construct an IP datagram with the given source, destination, and - application payload. - - @param src: The source IPv4 address as a dotted-quad string. - @type src: L{bytes} - - @param dst: The destination IPv4 address as a dotted-quad string. - @type dst: L{bytes} - - @param payload: The content of the IP datagram (such as a UDP datagram). - @type payload: L{bytes} - - @return: An IP datagram header and payload. - @rtype: L{bytes} - """ - ipHeader = ( - # Version and header length, 4 bits each - '\x45' - # Differentiated services field - '\x00' - # Total length - + _H(20 + len(payload)) - + '\x00\x01\x00\x00\x40\x11' - # Checksum - + _H(0) - # Source address - + socket.inet_pton(socket.AF_INET, src) - # Destination address - + socket.inet_pton(socket.AF_INET, dst)) - - # Total all of the 16-bit integers in the header - checksumStep1 = sum(struct.unpack('!10H', ipHeader)) - # Pull off the carry - carry = checksumStep1 >> 16 - # And add it to what was left over - checksumStep2 = (checksumStep1 & 0xFFFF) + carry - # Compute the one's complement sum - checksumStep3 = checksumStep2 ^ 0xFFFF - - # Reconstruct the IP header including the correct checksum so the platform - # IP stack, if there is one involved in this test, doesn't drop it on the - # floor as garbage. - ipHeader = ( - ipHeader[:10] + - struct.pack('!H', checksumStep3) + - ipHeader[12:]) - - return ipHeader + payload - - - -def _udp(src, dst, payload): - """ - Construct a UDP datagram with the given source, destination, and - application payload. - - @param src: The source port number. - @type src: L{int} - - @param dst: The destination port number. - @type dst: L{int} - - @param payload: The content of the UDP datagram. - @type payload: L{bytes} - - @return: A UDP datagram header and payload. - @rtype: L{bytes} - """ - udpHeader = ( - # Source port - _H(src) - # Destination port - + _H(dst) - # Length - + _H(len(payload) + 8) - # Checksum - + _H(0)) - return udpHeader + payload - - - -class Tunnel(object): - """ - An in-memory implementation of a tun or tap device. - - @cvar _DEVICE_NAME: A string representing the conventional filesystem entry - for the tunnel factory character special device. - @type _DEVICE_NAME: C{bytes} - """ - _DEVICE_NAME = b"/dev/net/tun" - - # Between POSIX and Python, there are 4 combinations. Here are two, at - # least. - EAGAIN_STYLE = IOError(EAGAIN, "Resource temporarily unavailable") - EWOULDBLOCK_STYLE = OSError(EWOULDBLOCK, "Operation would block") - - # Oh yea, and then there's the case where maybe we would've read, but - # someone sent us a signal instead. - EINTR_STYLE = IOError(EINTR, "Interrupted function call") - - nonBlockingExceptionStyle = EAGAIN_STYLE - - SEND_BUFFER_SIZE = 1024 - - def __init__(self, system, openFlags, fileMode): - """ - @param system: An L{_IInputOutputSystem} provider to use to perform I/O. - - @param openFlags: Any flags to apply when opening the tunnel device. - See C{os.O_*}. - - @type openFlags: L{int} - - @param fileMode: ignored - """ - self.system = system - - # Drop fileMode on the floor - evidence and logic suggest it is - # irrelevant with respect to /dev/net/tun - self.openFlags = openFlags - self.tunnelMode = None - self.requestedName = None - self.name = None - self.readBuffer = deque() - self.writeBuffer = deque() - self.pendingSignals = deque() - - - @property - def blocking(self): - """ - If the file descriptor for this tunnel is open in blocking mode, - C{True}. C{False} otherwise. - """ - return not (self.openFlags & self.system.O_NONBLOCK) - - - @property - def closeOnExec(self): - """ - If the file descriptor for this tunnel is marked as close-on-exec, - C{True}. C{False} otherwise. - """ - return bool(self.openFlags & self.system.O_CLOEXEC) - - - def addToReadBuffer(self, datagram): - """ - Deliver a datagram to this tunnel's read buffer. This makes it - available to be read later using the C{read} method. - - @param datagram: The IPv4 datagram to deliver. If the mode of this - tunnel is TAP then ethernet framing will be added automatically. - @type datagram: L{bytes} - """ - # TAP devices also include ethernet framing. - if self.tunnelMode & TunnelFlags.IFF_TAP.value: - datagram = _ethernet( - src='\x00' * 6, dst='\xff' * 6, protocol=_IPv4, - payload=datagram) - - self.readBuffer.append(datagram) - - - def read(self, limit): - """ - Read a datagram out of this tunnel. - - @param limit: The maximum number of bytes from the datagram to return. - If the next datagram is larger than this, extra bytes are dropped - and lost forever. - @type limit: L{int} - - @raise OSError: Any of the usual I/O problems can result in this - exception being raised with some particular error number set. - - @raise IOError: Any of the usual I/O problems can result in this - exception being raised with some particular error number set. - - @return: The datagram which was read from the tunnel. If the tunnel - mode does not include L{TunnelFlags.IFF_NO_PI} then the datagram is - prefixed with a 4 byte PI header. - @rtype: L{bytes} - """ - if self.readBuffer: - if self.tunnelMode & TunnelFlags.IFF_NO_PI.value: - header = b"" - else: - # Synthesize a PI header to include in the result. Nothing in - # twisted.pair uses the PI information yet so we can synthesize - # something incredibly boring (ie 32 bits of 0). - header = b"\x00" * _PI_SIZE - limit -= 4 - return header + self.readBuffer.popleft()[:limit] - elif self.blocking: - raise NotImplementedError() - else: - raise self.nonBlockingExceptionStyle - - - def write(self, datagram): - """ - Write a datagram into this tunnel. - - @param datagram: The datagram to write. - @type datagram: L{bytes} - - @raise IOError: Any of the usual I/O problems can result in this - exception being raised with some particular error number set. - - @return: The number of bytes of the datagram which were written. - @rtype: L{int} - """ - if self.pendingSignals: - self.pendingSignals.popleft() - raise IOError(EINTR, "Interrupted system call") - - if len(datagram) > self.SEND_BUFFER_SIZE: - raise IOError(ENOBUFS, "No buffer space available") - - self.writeBuffer.append(datagram) - return len(datagram) - - - -def _privileged(original): - """ - Wrap a L{MemoryIOSystem} method with permission-checking logic. The - returned function will check C{self.permissions} and raise L{IOError} with - L{errno.EPERM} if the function name is not listed as an available - permission. - - @param original: The L{MemoryIOSystem} instance to wrap. - - @return: A wrapper around C{original} that applies permission checks. - """ - @wraps(original) - def permissionChecker(self, *args, **kwargs): - if original.func_name not in self.permissions: - raise IOError(EPERM, "Operation not permitted") - return original(self, *args, **kwargs) - return permissionChecker - - - -@implementer(_IInputOutputSystem) -class MemoryIOSystem(object): - """ - An in-memory implementation of basic I/O primitives, useful in the context - of unit testing as a drop-in replacement for parts of the C{os} module. - - @ivar _devices: - @ivar _openFiles: - @ivar permissions: - - @ivar _counter: - """ - _counter = 8192 - - O_RDWR = 1 << 0 - O_NONBLOCK = 1 << 1 - O_CLOEXEC = 1 << 2 - - def __init__(self): - self._devices = {} - self._openFiles = {} - self.permissions = set(['open', 'ioctl']) - - - def getTunnel(self, port): - """ - Get the L{Tunnel} object associated with the given L{TuntapPort}. - - @param port: A L{TuntapPort} previously initialized using this - L{MemoryIOSystem}. - - @return: The tunnel object created by a prior use of C{open} on this - object on the tunnel special device file. - @rtype: L{Tunnel} - """ - return self._openFiles[port.fileno()] - - - def registerSpecialDevice(self, name, cls): - """ - Specify a class which will be used to handle I/O to a device of a - particular name. - - @param name: The filesystem path name of the device. - @type name: L{bytes} - - @param cls: A class (like L{Tunnel}) to instantiated whenever this - device is opened. - """ - self._devices[name] = cls - - - @_privileged - def open(self, name, flags, mode=None): - """ - A replacement for C{os.open}. This initializes state in this - L{MemoryIOSystem} which will be reflected in the behavior of the other - file descriptor-related methods (eg L{MemoryIOSystem.read}, - L{MemoryIOSystem.write}, etc). - - @param name: A string giving the name of the file to open. - @type name: C{bytes} - - @param flags: The flags with which to open the file. - @type flags: C{int} - - @param mode: The mode with which to open the file. - @type mode: C{int} - - @raise OSError: With C{ENOSYS} if the file is not a recognized special - device file. - - @return: A file descriptor associated with the newly opened file - description. - @rtype: L{int} - """ - if name in self._devices: - fd = self._counter - self._counter += 1 - self._openFiles[fd] = self._devices[name](self, flags, mode) - return fd - raise OSError(ENOSYS, "Function not implemented") - - - def read(self, fd, limit): - """ - Try to read some bytes out of one of the in-memory buffers which may - previously have been populated by C{write}. - - @see: L{os.read} - """ - try: - return self._openFiles[fd].read(limit) - except KeyError: - raise OSError(EBADF, "Bad file descriptor") - - - def write(self, fd, data): - """ - Try to add some bytes to one of the in-memory buffers to be accessed by - a later C{read} call. - - @see: L{os.write} - """ - try: - return self._openFiles[fd].write(data) - except KeyError: - raise OSError(EBADF, "Bad file descriptor") - - - def close(self, fd): - """ - Discard the in-memory buffer and other in-memory state for the given - file descriptor. - - @see: L{os.close} - """ - try: - del self._openFiles[fd] - except KeyError: - raise OSError(EBADF, "Bad file descriptor") - - - @_privileged - def ioctl(self, fd, request, args): - """ - Perform some configuration change to the in-memory state for the given - file descriptor. - - @see: L{fcntl.ioctl} - """ - try: - tunnel = self._openFiles[fd] - except KeyError: - raise IOError(EBADF, "Bad file descriptor") - - if request != _TUNSETIFF: - raise IOError(EINVAL, "Request or args is not valid.") - - name, mode = struct.unpack('%dsH' % (_IFNAMSIZ,), args) - tunnel.tunnelMode = mode - tunnel.requestedName = name - tunnel.name = name[:_IFNAMSIZ - 3] + "123" - - return struct.pack('%dsH' % (_IFNAMSIZ,), tunnel.name, mode) - - - def sendUDP(self, datagram, address): - """ - Write an ethernet frame containing an ip datagram containing a udp - datagram containing the given payload, addressed to the given address, - to a tunnel device previously opened on this I/O system. - - @param datagram: A UDP datagram payload to send. - @type datagram: L{bytes} - - @param address: The destination to which to send the datagram. - @type address: L{tuple} of (L{bytes}, L{int}) - - @return: A two-tuple giving the address from which gives the address - from which the datagram was sent. - @rtype: L{tuple} of (L{bytes}, L{int}) - """ - # Just make up some random thing - srcIP = '10.1.2.3' - srcPort = 21345 - - serialized = _ip( - src=srcIP, dst=address[0], payload=_udp( - src=srcPort, dst=address[1], payload=datagram)) - - self._openFiles.values()[0].addToReadBuffer(serialized) - - return (srcIP, srcPort) - - - def receiveUDP(self, fileno, host, port): - """ - Get a socket-like object which can be used to receive a datagram sent - from the given address. - - @param fileno: A file descriptor representing a tunnel device which the - datagram will be received via. - @type fileno: L{int} - - @param host: The IPv4 address to which the datagram was sent. - @type host: L{bytes} - - @param port: The UDP port number to which the datagram was sent. - received. - @type port: L{int} - - @return: A L{socket.socket}-like object which can be used to receive - the specified datagram. - """ - return _FakePort(self, fileno) - - - -class _FakePort(object): - """ - A socket-like object which can be used to read UDP datagrams from - tunnel-like file descriptors managed by a L{MemoryIOSystem}. - """ - def __init__(self, system, fileno): - self._system = system - self._fileno = fileno - - - def recv(self, nbytes): - """ - Receive a datagram sent to this port using the L{MemoryIOSystem} which - created this object. - - This behaves like L{socket.socket.recv} but the data being I{sent} and - I{received} only passes through various memory buffers managed by this - object and L{MemoryIOSystem}. - - @see: L{socket.socket.recv} - """ - data = self._system._openFiles[self._fileno].writeBuffer.popleft() - - datagrams = [] - receiver = DatagramProtocol() - - def capture(datagram, address): - datagrams.append(datagram) - - receiver.datagramReceived = capture - - udp = RawUDPProtocol() - udp.addProto(12345, receiver) - - ip = IPProtocol() - ip.addProto(17, udp) - - mode = self._system._openFiles[self._fileno].tunnelMode - if (mode & TunnelFlags.IFF_TAP.value): - ether = EthernetProtocol() - ether.addProto(0x800, ip) - datagramReceived = ether.datagramReceived - else: - datagramReceived = lambda data: ip.datagramReceived( - data, None, None, None, None) - - dataHasPI = not (mode & TunnelFlags.IFF_NO_PI.value) - - if dataHasPI: - # datagramReceived can't handle the PI, get rid of it. - data = data[_PI_SIZE:] - - datagramReceived(data) - return datagrams[0][:nbytes] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/NEWS deleted file mode 100644 index 1906d42..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/NEWS +++ /dev/null @@ -1,140 +0,0 @@ -Twisted Pair 15.2.1 (2015-05-23) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 15.2.0 (2015-05-18) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 15.1.0 (2015-04-02) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 15.0.0 (2015-01-24) -================================ - -No significant changes have been made for this release. - -Other ------ - - #7722 - - -Twisted Pair 14.0.2 (2014-09-18) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 14.0.1 (2014-09-17) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 14.0.0 (2014-05-08) -================================ - -Features --------- - - twisted.pair.tuntap now has complete test coverage, basic - documentation, and works without the difficult-to-find system - bindings it used to require. (#6169) - -Other ------ - - #6898, #6931, #6993 - - -Twisted Pair 13.2.0 (2013-10-29) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 13.1.0 (2013-06-23) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 13.0.0 (2013-03-19) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 12.3.0 (2012-12-20) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 12.2.0 (2012-08-26) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 12.1.0 (2012-06-02) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 12.0.0 (2012-02-10) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 11.1.0 (2011-11-15) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 11.0.0 (2011-04-01) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 10.2.0 (2010-11-29) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 10.1.0 (2010-06-27) -================================ - -No significant changes have been made for this release. - - -Twisted Pair 10.0.0 (2010-03-01) -================================ - -Other ------ - - #4170 - - -Twisted Pair 9.0.0 (2009-11-24) -=============================== - -Other ------ - - #3540, #4050 - - -Pair 8.2.0 (2008-12-16) -======================= - -No interesting changes since Twisted 8.0. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/README deleted file mode 100644 index 8f6ce79..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/README +++ /dev/null @@ -1,12 +0,0 @@ -Twisted Pair 15.2.1: Very low-level networking functionality - -Twisted Pair includes parsers for several datagram formats, including ethernet, -IP, and UDP. It also offers low-level networking integration on Linux via tun -and tap devices. - -Twisted Pair depends on Twisted Core. - -To be able to run the Twisted Pair test suite as an unprivileged user, you need -to create a tunnel device owned by that user. Likewise, to use Twisted Pair's -tuntap support as an unprivileged user, you must do the same. See the -configuration howto for details. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/setup.py deleted file mode 100644 index e9eb5e6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/topfiles/setup.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="pair", - # metadata - name="Twisted Pair", - description="Twisted Pair contains low-level networking support.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Tommi Virtanen", - url="http://twistedmatrix.com/trac/wiki/TwistedPair", - license="MIT", - long_description=""" -Raw network packet parsing routines, including ethernet, IP and UDP -packets, and tuntap support. -""", - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/tuntap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/tuntap.py deleted file mode 100644 index afbddca..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/pair/tuntap.py +++ /dev/null @@ -1,434 +0,0 @@ -# -*- test-case-name: twisted.pair.test.test_tuntap -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for Linux ethernet and IP tunnel devices. - -@see: U{https://en.wikipedia.org/wiki/TUN/TAP} -""" - -import os -import fcntl -import errno -import struct -import warnings -from collections import namedtuple - -from zope.interface import Attribute, Interface, implementer - -from twisted.python.util import FancyEqMixin, FancyStrMixin -from twisted.python.versions import Version -from twisted.python.reflect import fullyQualifiedName -from twisted.python.deprecate import deprecated -from twisted.python.constants import Flags, FlagConstant -from twisted.python import log -from twisted.internet import abstract, error, task, interfaces, defer -from twisted.pair import ethernet, raw - -__all__ = [ - "TunnelFlags", "TunnelAddress", "TuntapPort", - ] - - -_IFNAMSIZ = 16 -_TUNSETIFF = 0x400454ca -_TUNGETIFF = 0x800454d2 -_TUN_KO_PATH = b"/dev/net/tun" - - -class TunnelFlags(Flags): - """ - L{TunnelFlags} defines more flags which are used to configure the behavior - of a tunnel device. - - @cvar IFF_TUN: This indicates a I{tun}-type device. This type of tunnel - carries IP datagrams. This flag is mutually exclusive with C{IFF_TAP}. - - @cvar IFF_TAP: This indicates a I{tap}-type device. This type of tunnel - carries ethernet frames. This flag is mutually exclusive with C{IFF_TUN}. - - @cvar IFF_NO_PI: This indicates the I{protocol information} header will - B{not} be included in data read from the tunnel. - - @see: U{https://www.kernel.org/doc/Documentation/networking/tuntap.txt} - """ - IFF_TUN = FlagConstant(0x0001) - IFF_TAP = FlagConstant(0x0002) - - TUN_FASYNC = FlagConstant(0x0010) - TUN_NOCHECKSUM = FlagConstant(0x0020) - TUN_NO_PI = FlagConstant(0x0040) - TUN_ONE_QUEUE = FlagConstant(0x0080) - TUN_PERSIST = FlagConstant(0x0100) - TUN_VNET_HDR = FlagConstant(0x0200) - - IFF_NO_PI = FlagConstant(0x1000) - IFF_ONE_QUEUE = FlagConstant(0x2000) - IFF_VNET_HDR = FlagConstant(0x4000) - IFF_TUN_EXCL = FlagConstant(0x8000) - - - -@implementer(interfaces.IAddress) -class TunnelAddress(FancyStrMixin, object, FancyEqMixin): - """ - A L{TunnelAddress} represents the tunnel to which a L{TuntapPort} is bound. - """ - compareAttributes = ("_typeValue", "name") - showAttributes = (("type", lambda flag: flag.name), "name") - - @property - def _typeValue(self): - """ - Return the integer value of the C{type} attribute. Used to produce - correct results in the equality implementation. - """ - # Work-around for https://twistedmatrix.com/trac/ticket/6878 - return self.type.value - - - def __init__(self, type, name): - """ - @param type: Either L{TunnelFlags.IFF_TUN} or L{TunnelFlags.IFF_TAP}, - representing the type of this tunnel. - - @param name: The system name of the tunnel. - @type name: L{bytes} - """ - self.type = type - self.name = name - - - def __getitem__(self, index): - """ - Deprecated accessor for the tunnel name. Use attributes instead. - """ - warnings.warn( - "TunnelAddress.__getitem__ is deprecated since Twisted 14.0.0 " - "Use attributes instead.", category=DeprecationWarning, - stacklevel=2) - return ('TUNTAP', self.name)[index] - - - -class _TunnelDescription(namedtuple("_TunnelDescription", "fileno name")): - """ - Describe an existing tunnel. - - @ivar fileno: the file descriptor associated with the tunnel - @type fileno: L{int} - - @ivar name: the name of the tunnel - @type name: L{bytes} - """ - - - -class _IInputOutputSystem(Interface): - """ - An interface for performing some basic kinds of I/O (particularly that I/O - which might be useful for L{twisted.pair.tuntap}-using code). - """ - O_RDWR = Attribute("@see: L{os.O_RDWR}") - O_NONBLOCK = Attribute("@see: L{os.O_NONBLOCK}") - O_CLOEXEC = Attribute("@see: L{os.O_CLOEXEC}") - - def open(filename, flag, mode=0o777): - """ - @see: L{os.open} - """ - - - def ioctl(fd, opt, arg=None, mutate_flag=None): - """ - @see: L{fcntl.ioctl} - """ - - - def read(fd, limit): - """ - @see: L{os.read} - """ - - - def write(fd, data): - """ - @see: L{os.write} - """ - - - def close(fd): - """ - @see: L{os.close} - """ - - - def sendUDP(datagram, address): - """ - Send a datagram to a certain address. - - @param datagram: The payload of a UDP datagram to send. - @type datagram: L{bytes} - - @param address: The destination to which to send the datagram. - @type address: L{tuple} of (L{bytes}, L{int}) - - @return: The local address from which the datagram was sent. - @rtype: L{tuple} of (L{bytes}, L{int}) - """ - - - def receiveUDP(fileno, host, port): - """ - Return a socket which can be used to receive datagrams sent to the - given address. - - @param fileno: A file descriptor representing a tunnel device which the - datagram was either sent via or will be received via. - @type fileno: L{int} - - @param host: The IPv4 address at which the datagram will be received. - @type host: L{bytes} - - @param port: The UDP port number at which the datagram will be - received. - @type port: L{int} - - @return: A L{socket.socket} which can be used to receive the specified - datagram. - """ - - - -class _RealSystem(object): - """ - An interface to the parts of the operating system which L{TuntapPort} - relies on. This is most of an implementation of L{_IInputOutputSystem}. - """ - open = staticmethod(os.open) - read = staticmethod(os.read) - write = staticmethod(os.write) - close = staticmethod(os.close) - ioctl = staticmethod(fcntl.ioctl) - - O_RDWR = os.O_RDWR - O_NONBLOCK = os.O_NONBLOCK - # Introduced in Python 3.x - # Ubuntu 12.04, /usr/include/x86_64-linux-gnu/bits/fcntl.h - O_CLOEXEC = getattr(os, "O_CLOEXEC", 0o2000000) - - - -@implementer(interfaces.IListeningPort) -class TuntapPort(abstract.FileDescriptor): - """ - A Port that reads and writes packets from/to a TUN/TAP-device. - """ - maxThroughput = 256 * 1024 # Max bytes we read in one eventloop iteration - - def __init__(self, interface, proto, maxPacketSize=8192, reactor=None, - system=None): - if ethernet.IEthernetProtocol.providedBy(proto): - self.ethernet = 1 - self._mode = TunnelFlags.IFF_TAP - else: - self.ethernet = 0 - self._mode = TunnelFlags.IFF_TUN - assert raw.IRawPacketProtocol.providedBy(proto) - - if system is None: - system = _RealSystem() - self._system = system - - abstract.FileDescriptor.__init__(self, reactor) - self.interface = interface - self.protocol = proto - self.maxPacketSize = maxPacketSize - - logPrefix = self._getLogPrefix(self.protocol) - self.logstr = "%s (%s)" % (logPrefix, self._mode.name) - - - def __repr__(self): - args = (self.protocol.__class__,) - if self.connected: - args = args + ("",) - else: - args = args + ("not ",) - args = args + (self._mode.name, self.interface) - return "<%s %slistening on %s/%s>" % args - - - def startListening(self): - """ - Create and bind my socket, and begin listening on it. - - This must be called after creating a server to begin listening on the - specified tunnel. - """ - self._bindSocket() - self.protocol.makeConnection(self) - self.startReading() - - - def _openTunnel(self, name, mode): - """ - Open the named tunnel using the given mode. - - @param name: The name of the tunnel to open. - @type name: L{bytes} - - @param mode: Flags from L{TunnelFlags} with exactly one of - L{TunnelFlags.IFF_TUN} or L{TunnelFlags.IFF_TAP} set. - - @return: A L{_TunnelDescription} representing the newly opened tunnel. - """ - flags = ( - self._system.O_RDWR | self._system.O_CLOEXEC | - self._system.O_NONBLOCK) - config = struct.pack("%dsH" % (_IFNAMSIZ,), name, mode.value) - fileno = self._system.open(_TUN_KO_PATH, flags) - result = self._system.ioctl(fileno, _TUNSETIFF, config) - return _TunnelDescription(fileno, result[:_IFNAMSIZ].strip('\x00')) - - - def _bindSocket(self): - """ - Open the tunnel. - """ - log.msg( - format="%(protocol)s starting on %(interface)s", - protocol=self.protocol.__class__, - interface=self.interface) - try: - fileno, interface = self._openTunnel( - self.interface, self._mode | TunnelFlags.IFF_NO_PI) - except (IOError, OSError) as e: - raise error.CannotListenError(None, self.interface, e) - - self.interface = interface - self._fileno = fileno - - self.connected = 1 - - - def fileno(self): - return self._fileno - - - def doRead(self): - """ - Called when my socket is ready for reading. - """ - read = 0 - while read < self.maxThroughput: - try: - data = self._system.read(self._fileno, self.maxPacketSize) - except EnvironmentError as e: - if e.errno in (errno.EWOULDBLOCK, errno.EAGAIN, errno.EINTR): - return - else: - raise - except: - raise - read += len(data) - # TODO pkt.isPartial()? - try: - self.protocol.datagramReceived(data, partial=0) - except: - cls = fullyQualifiedName(self.protocol.__class__) - log.err( - None, - "Unhandled exception from %s.datagramReceived" % (cls,)) - - - def write(self, datagram): - """ - Write the given data as a single datagram. - - @param datagram: The data that will make up the complete datagram to be - written. - @type datagram: L{bytes} - """ - try: - return self._system.write(self._fileno, datagram) - except IOError as e: - if e.errno == errno.EINTR: - return self.write(datagram) - raise - - - def writeSequence(self, seq): - """ - Write a datagram constructed from a L{list} of L{bytes}. - - @param datagram: The data that will make up the complete datagram to be - written. - @type seq: L{list} of L{bytes} - """ - self.write(b"".join(seq)) - - - def stopListening(self): - """ - Stop accepting connections on this port. - - This will shut down my socket and call self.connectionLost(). - - @return: A L{Deferred} that fires when this port has stopped. - """ - self.stopReading() - if self.disconnecting: - return self._stoppedDeferred - elif self.connected: - self._stoppedDeferred = task.deferLater( - self.reactor, 0, self.connectionLost) - self.disconnecting = True - return self._stoppedDeferred - else: - return defer.succeed(None) - - - def loseConnection(self): - """ - Close this tunnel. Use L{TuntapPort.stopListening} instead. - """ - self.stopListening().addErrback(log.err) - - - def connectionLost(self, reason=None): - """ - Cleans up my socket. - - @param reason: Ignored. Do not use this. - """ - log.msg('(Tuntap %s Closed)' % self.interface) - abstract.FileDescriptor.connectionLost(self, reason) - self.protocol.doStop() - self.connected = 0 - self._system.close(self._fileno) - self._fileno = -1 - - - def logPrefix(self): - """ - Returns the name of my class, to prefix log entries with. - """ - return self.logstr - - - def getHost(self): - """ - Get the local address of this L{TuntapPort}. - - @return: A L{TunnelAddress} which describes the tunnel device to which - this object is bound. - @rtype: L{TunnelAddress} - """ - return TunnelAddress(self._mode, self.interface) - -TuntapPort.loseConnection = deprecated( - Version("Twisted", 14, 0, 0), - TuntapPort.stopListening)(TuntapPort.loseConnection) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/__init__.py deleted file mode 100644 index 55893b8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Persisted: Utilities for managing persistence. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/aot.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/aot.py deleted file mode 100644 index c0e0282..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/aot.py +++ /dev/null @@ -1,560 +0,0 @@ -# -*- test-case-name: twisted.test.test_persisted -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -AOT: Abstract Object Trees -The source-code-marshallin'est abstract-object-serializin'est persister -this side of Marmalade! -""" - -import types, copy_reg, tokenize, re - -from twisted.python import reflect, log -from twisted.persisted import crefutil - -########################### -# Abstract Object Classes # -########################### - -#"\0" in a getSource means "insert variable-width indention here". -#see `indentify'. - -class Named: - def __init__(self, name): - self.name = name - -class Class(Named): - def getSource(self): - return "Class(%r)" % self.name - -class Function(Named): - def getSource(self): - return "Function(%r)" % self.name - -class Module(Named): - def getSource(self): - return "Module(%r)" % self.name - - -class InstanceMethod: - def __init__(self, name, klass, inst): - if not (isinstance(inst, Ref) or isinstance(inst, Instance) or isinstance(inst, Deref)): - raise TypeError("%s isn't an Instance, Ref, or Deref!" % inst) - self.name = name - self.klass = klass - self.instance = inst - - def getSource(self): - return "InstanceMethod(%r, %r, \n\0%s)" % (self.name, self.klass, prettify(self.instance)) - - -class _NoStateObj: - pass -NoStateObj = _NoStateObj() - -_SIMPLE_BUILTINS = [ - types.StringType, types.UnicodeType, types.IntType, types.FloatType, - types.ComplexType, types.LongType, types.NoneType, types.SliceType, - types.EllipsisType] - -try: - _SIMPLE_BUILTINS.append(types.BooleanType) -except AttributeError: - pass - -class Instance: - def __init__(self, className, __stateObj__=NoStateObj, **state): - if not isinstance(className, types.StringType): - raise TypeError("%s isn't a string!" % className) - self.klass = className - if __stateObj__ is not NoStateObj: - self.state = __stateObj__ - self.stateIsDict = 0 - else: - self.state = state - self.stateIsDict = 1 - - def getSource(self): - #XXX make state be foo=bar instead of a dict. - if self.stateIsDict: - stateDict = self.state - elif isinstance(self.state, Ref) and isinstance(self.state.obj, types.DictType): - stateDict = self.state.obj - else: - stateDict = None - if stateDict is not None: - try: - return "Instance(%r, %s)" % (self.klass, dictToKW(stateDict)) - except NonFormattableDict: - return "Instance(%r, %s)" % (self.klass, prettify(stateDict)) - return "Instance(%r, %s)" % (self.klass, prettify(self.state)) - -class Ref: - - def __init__(self, *args): - #blargh, lame. - if len(args) == 2: - self.refnum = args[0] - self.obj = args[1] - elif not args: - self.refnum = None - self.obj = None - - def setRef(self, num): - if self.refnum: - raise ValueError("Error setting id %s, I already have %s" % (num, self.refnum)) - self.refnum = num - - def setObj(self, obj): - if self.obj: - raise ValueError("Error setting obj %s, I already have %s" % (obj, self.obj)) - self.obj = obj - - def getSource(self): - if self.obj is None: - raise RuntimeError("Don't try to display me before setting an object on me!") - if self.refnum: - return "Ref(%d, \n\0%s)" % (self.refnum, prettify(self.obj)) - return prettify(self.obj) - - -class Deref: - def __init__(self, num): - self.refnum = num - - def getSource(self): - return "Deref(%d)" % self.refnum - - __repr__ = getSource - - -class Copyreg: - def __init__(self, loadfunc, state): - self.loadfunc = loadfunc - self.state = state - - def getSource(self): - return "Copyreg(%r, %s)" % (self.loadfunc, prettify(self.state)) - - - -############### -# Marshalling # -############### - - -def getSource(ao): - """Pass me an AO, I'll return a nicely-formatted source representation.""" - return indentify("app = " + prettify(ao)) - - -class NonFormattableDict(Exception): - """A dictionary was not formattable. - """ - -r = re.compile('[a-zA-Z_][a-zA-Z0-9_]*$') - -def dictToKW(d): - out = [] - items = d.items() - items.sort() - for k,v in items: - if not isinstance(k, types.StringType): - raise NonFormattableDict("%r ain't a string" % k) - if not r.match(k): - raise NonFormattableDict("%r ain't an identifier" % k) - out.append( - "\n\0%s=%s," % (k, prettify(v)) - ) - return ''.join(out) - - -def prettify(obj): - if hasattr(obj, 'getSource'): - return obj.getSource() - else: - #basic type - t = type(obj) - - if t in _SIMPLE_BUILTINS: - return repr(obj) - - elif t is types.DictType: - out = ['{'] - for k,v in obj.items(): - out.append('\n\0%s: %s,' % (prettify(k), prettify(v))) - out.append(len(obj) and '\n\0}' or '}') - return ''.join(out) - - elif t is types.ListType: - out = ["["] - for x in obj: - out.append('\n\0%s,' % prettify(x)) - out.append(len(obj) and '\n\0]' or ']') - return ''.join(out) - - elif t is types.TupleType: - out = ["("] - for x in obj: - out.append('\n\0%s,' % prettify(x)) - out.append(len(obj) and '\n\0)' or ')') - return ''.join(out) - else: - raise TypeError("Unsupported type %s when trying to prettify %s." % (t, obj)) - -def indentify(s): - out = [] - stack = [] - def eater(type, val, r, c, l, out=out, stack=stack): - #import sys - #sys.stdout.write(val) - if val in ['[', '(', '{']: - stack.append(val) - elif val in [']', ')', '}']: - stack.pop() - if val == '\0': - out.append(' '*len(stack)) - else: - out.append(val) - l = ['', s] - tokenize.tokenize(l.pop, eater) - return ''.join(out) - - - - - -########### -# Unjelly # -########### - -def unjellyFromAOT(aot): - """ - Pass me an Abstract Object Tree, and I'll unjelly it for you. - """ - return AOTUnjellier().unjelly(aot) - -def unjellyFromSource(stringOrFile): - """ - Pass me a string of code or a filename that defines an 'app' variable (in - terms of Abstract Objects!), and I'll execute it and unjelly the resulting - AOT for you, returning a newly unpersisted Application object! - """ - - ns = {"Instance": Instance, - "InstanceMethod": InstanceMethod, - "Class": Class, - "Function": Function, - "Module": Module, - "Ref": Ref, - "Deref": Deref, - "Copyreg": Copyreg, - } - - if hasattr(stringOrFile, "read"): - exec stringOrFile.read() in ns - else: - exec stringOrFile in ns - - if 'app' in ns: - return unjellyFromAOT(ns['app']) - else: - raise ValueError("%s needs to define an 'app', it didn't!" % stringOrFile) - - -class AOTUnjellier: - """I handle the unjellying of an Abstract Object Tree. - See AOTUnjellier.unjellyAO - """ - def __init__(self): - self.references = {} - self.stack = [] - self.afterUnjelly = [] - - ## - # unjelly helpers (copied pretty much directly from (now deleted) marmalade) - ## - def unjellyLater(self, node): - """Unjelly a node, later. - """ - d = crefutil._Defer() - self.unjellyInto(d, 0, node) - return d - - def unjellyInto(self, obj, loc, ao): - """Utility method for unjellying one object into another. - This automates the handling of backreferences. - """ - o = self.unjellyAO(ao) - obj[loc] = o - if isinstance(o, crefutil.NotKnown): - o.addDependant(obj, loc) - return o - - def callAfter(self, callable, result): - if isinstance(result, crefutil.NotKnown): - l = [None] - result.addDependant(l, 1) - else: - l = [result] - self.afterUnjelly.append((callable, l)) - - def unjellyAttribute(self, instance, attrName, ao): - #XXX this is unused???? - """Utility method for unjellying into instances of attributes. - - Use this rather than unjellyAO unless you like surprising bugs! - Alternatively, you can use unjellyInto on your instance's __dict__. - """ - self.unjellyInto(instance.__dict__, attrName, ao) - - def unjellyAO(self, ao): - """Unjelly an Abstract Object and everything it contains. - I return the real object. - """ - self.stack.append(ao) - t = type(ao) - if t is types.InstanceType: - #Abstract Objects - c = ao.__class__ - if c is Module: - return reflect.namedModule(ao.name) - - elif c in [Class, Function] or issubclass(c, type): - return reflect.namedObject(ao.name) - - elif c is InstanceMethod: - im_name = ao.name - im_class = reflect.namedObject(ao.klass) - im_self = self.unjellyAO(ao.instance) - if im_name in im_class.__dict__: - if im_self is None: - return getattr(im_class, im_name) - elif isinstance(im_self, crefutil.NotKnown): - return crefutil._InstanceMethod(im_name, im_self, im_class) - else: - return types.MethodType(im_class.__dict__[im_name], - im_self, - im_class) - else: - raise TypeError("instance method changed") - - elif c is Instance: - klass = reflect.namedObject(ao.klass) - state = self.unjellyAO(ao.state) - if hasattr(klass, "__setstate__"): - inst = types.InstanceType(klass, {}) - self.callAfter(inst.__setstate__, state) - else: - inst = types.InstanceType(klass, state) - return inst - - elif c is Ref: - o = self.unjellyAO(ao.obj) #THIS IS CHANGING THE REF OMG - refkey = ao.refnum - ref = self.references.get(refkey) - if ref is None: - self.references[refkey] = o - elif isinstance(ref, crefutil.NotKnown): - ref.resolveDependants(o) - self.references[refkey] = o - elif refkey is None: - # This happens when you're unjellying from an AOT not read from source - pass - else: - raise ValueError("Multiple references with the same ID: %s, %s, %s!" % (ref, refkey, ao)) - return o - - elif c is Deref: - num = ao.refnum - ref = self.references.get(num) - if ref is None: - der = crefutil._Dereference(num) - self.references[num] = der - return der - return ref - - elif c is Copyreg: - loadfunc = reflect.namedObject(ao.loadfunc) - d = self.unjellyLater(ao.state).addCallback( - lambda result, _l: _l(*result), loadfunc) - return d - - #Types - - elif t in _SIMPLE_BUILTINS: - return ao - - elif t is types.ListType: - l = [] - for x in ao: - l.append(None) - self.unjellyInto(l, len(l)-1, x) - return l - - elif t is types.TupleType: - l = [] - tuple_ = tuple - for x in ao: - l.append(None) - if isinstance(self.unjellyInto(l, len(l)-1, x), crefutil.NotKnown): - tuple_ = crefutil._Tuple - return tuple_(l) - - elif t is types.DictType: - d = {} - for k,v in ao.items(): - kvd = crefutil._DictKeyAndValue(d) - self.unjellyInto(kvd, 0, k) - self.unjellyInto(kvd, 1, v) - return d - - else: - raise TypeError("Unsupported AOT type: %s" % t) - - del self.stack[-1] - - - def unjelly(self, ao): - try: - l = [None] - self.unjellyInto(l, 0, ao) - for func, v in self.afterUnjelly: - func(v[0]) - return l[0] - except: - log.msg("Error jellying object! Stacktrace follows::") - log.msg("\n".join(map(repr, self.stack))) - raise -######### -# Jelly # -######### - - -def jellyToAOT(obj): - """Convert an object to an Abstract Object Tree.""" - return AOTJellier().jelly(obj) - -def jellyToSource(obj, file=None): - """ - Pass me an object and, optionally, a file object. - I'll convert the object to an AOT either return it (if no file was - specified) or write it to the file. - """ - - aot = jellyToAOT(obj) - if file: - file.write(getSource(aot)) - else: - return getSource(aot) - - -class AOTJellier: - def __init__(self): - # dict of {id(obj): (obj, node)} - self.prepared = {} - self._ref_id = 0 - self.stack = [] - - def prepareForRef(self, aoref, object): - """I prepare an object for later referencing, by storing its id() - and its _AORef in a cache.""" - self.prepared[id(object)] = aoref - - def jellyToAO(self, obj): - """I turn an object into an AOT and return it.""" - objType = type(obj) - self.stack.append(repr(obj)) - - #immutable: We don't care if these have multiple refs! - if objType in _SIMPLE_BUILTINS: - retval = obj - - elif objType is types.MethodType: - # TODO: make methods 'prefer' not to jelly the object internally, - # so that the object will show up where it's referenced first NOT - # by a method. - retval = InstanceMethod(obj.im_func.__name__, reflect.qual(obj.im_class), - self.jellyToAO(obj.im_self)) - - elif objType is types.ModuleType: - retval = Module(obj.__name__) - - elif objType is types.ClassType: - retval = Class(reflect.qual(obj)) - - elif issubclass(objType, type): - retval = Class(reflect.qual(obj)) - - elif objType is types.FunctionType: - retval = Function(reflect.fullFuncName(obj)) - - else: #mutable! gotta watch for refs. - -#Marmalade had the nicety of being able to just stick a 'reference' attribute -#on any Node object that was referenced, but in AOT, the referenced object -#is *inside* of a Ref call (Ref(num, obj) instead of -#). The problem is, especially for built-in types, -#I can't just assign some attribute to them to give them a refnum. So, I have -#to "wrap" a Ref(..) around them later -- that's why I put *everything* that's -#mutable inside one. The Ref() class will only print the "Ref(..)" around an -#object if it has a Reference explicitly attached. - - if id(obj) in self.prepared: - oldRef = self.prepared[id(obj)] - if oldRef.refnum: - # it's been referenced already - key = oldRef.refnum - else: - # it hasn't been referenced yet - self._ref_id = self._ref_id + 1 - key = self._ref_id - oldRef.setRef(key) - return Deref(key) - - retval = Ref() - self.prepareForRef(retval, obj) - - if objType is types.ListType: - retval.setObj(map(self.jellyToAO, obj)) #hah! - - elif objType is types.TupleType: - retval.setObj(tuple(map(self.jellyToAO, obj))) - - elif objType is types.DictionaryType: - d = {} - for k,v in obj.items(): - d[self.jellyToAO(k)] = self.jellyToAO(v) - retval.setObj(d) - - elif objType is types.InstanceType: - if hasattr(obj, "__getstate__"): - state = self.jellyToAO(obj.__getstate__()) - else: - state = self.jellyToAO(obj.__dict__) - retval.setObj(Instance(reflect.qual(obj.__class__), state)) - - elif objType in copy_reg.dispatch_table: - unpickleFunc, state = copy_reg.dispatch_table[objType](obj) - - retval.setObj(Copyreg( reflect.fullFuncName(unpickleFunc), - self.jellyToAO(state))) - - else: - raise TypeError("Unsupported type: %s" % objType.__name__) - - del self.stack[-1] - return retval - - def jelly(self, obj): - try: - ao = self.jellyToAO(obj) - return ao - except: - log.msg("Error jellying object! Stacktrace follows::") - log.msg('\n'.join(self.stack)) - raise diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/crefutil.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/crefutil.py deleted file mode 100644 index 39d7eb9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/crefutil.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- test-case-name: twisted.test.test_persisted -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Utility classes for dealing with circular references. -""" - -import types - -from twisted.python import log, reflect - - -class NotKnown: - def __init__(self): - self.dependants = [] - self.resolved = 0 - - def addDependant(self, mutableObject, key): - assert not self.resolved - self.dependants.append( (mutableObject, key) ) - - resolvedObject = None - - def resolveDependants(self, newObject): - self.resolved = 1 - self.resolvedObject = newObject - for mut, key in self.dependants: - mut[key] = newObject - if isinstance(newObject, NotKnown): - newObject.addDependant(mut, key) - - def __hash__(self): - assert 0, "I am not to be used as a dictionary key." - - - -class _Container(NotKnown): - """ - Helper class to resolve circular references on container objects. - """ - - def __init__(self, l, containerType): - """ - @param l: The list of object which may contain some not yet referenced - objects. - - @param containerType: A type of container objects (e.g., C{tuple} or - C{set}). - """ - NotKnown.__init__(self) - self.containerType = containerType - self.l = l - self.locs = range(len(l)) - for idx in xrange(len(l)): - if not isinstance(l[idx], NotKnown): - self.locs.remove(idx) - else: - l[idx].addDependant(self, idx) - if not self.locs: - self.resolveDependants(self.containerType(self.l)) - - - def __setitem__(self, n, obj): - """ - Change the value of one contained objects, and resolve references if - all objects have been referenced. - """ - self.l[n] = obj - if not isinstance(obj, NotKnown): - self.locs.remove(n) - if not self.locs: - self.resolveDependants(self.containerType(self.l)) - - - -class _Tuple(_Container): - """ - Manage tuple containing circular references. Deprecated: use C{_Container} - instead. - """ - - def __init__(self, l): - """ - @param l: The list of object which may contain some not yet referenced - objects. - """ - _Container.__init__(self, l, tuple) - - - -class _InstanceMethod(NotKnown): - def __init__(self, im_name, im_self, im_class): - NotKnown.__init__(self) - self.my_class = im_class - self.name = im_name - # im_self _must_ be a - im_self.addDependant(self, 0) - - def __call__(self, *args, **kw): - import traceback - log.msg('instance method %s.%s' % (reflect.qual(self.my_class), self.name)) - log.msg('being called with %r %r' % (args, kw)) - traceback.print_stack(file=log.logfile) - assert 0 - - def __setitem__(self, n, obj): - assert n == 0, "only zero index allowed" - if not isinstance(obj, NotKnown): - method = types.MethodType(self.my_class.__dict__[self.name], - obj, self.my_class) - self.resolveDependants(method) - -class _DictKeyAndValue: - def __init__(self, dict): - self.dict = dict - def __setitem__(self, n, obj): - if n not in (1, 0): - raise RuntimeError("DictKeyAndValue should only ever be called with 0 or 1") - if n: # value - self.value = obj - else: - self.key = obj - if hasattr(self, "key") and hasattr(self, "value"): - self.dict[self.key] = self.value - - -class _Dereference(NotKnown): - def __init__(self, id): - NotKnown.__init__(self) - self.id = id - - -from twisted.internet.defer import Deferred - -class _Catcher: - def catch(self, value): - self.value = value - -class _Defer(Deferred, NotKnown): - def __init__(self): - Deferred.__init__(self) - NotKnown.__init__(self) - self.pause() - - wasset = 0 - - def __setitem__(self, n, obj): - if self.wasset: - raise RuntimeError('setitem should only be called once, setting %r to %r' % (n, obj)) - else: - self.wasset = 1 - self.callback(obj) - - def addDependant(self, dep, key): - # by the time I'm adding a dependant, I'm *not* adding any more - # callbacks - NotKnown.addDependant(self, dep, key) - self.unpause() - resovd = self.result - self.resolveDependants(resovd) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/dirdbm.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/dirdbm.py deleted file mode 100644 index 26bbc1b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/dirdbm.py +++ /dev/null @@ -1,358 +0,0 @@ -# -*- test-case-name: twisted.test.test_dirdbm -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -DBM-style interface to a directory. - -Each key is stored as a single file. This is not expected to be very fast or -efficient, but it's good for easy debugging. - -DirDBMs are *not* thread-safe, they should only be accessed by one thread at -a time. - -No files should be placed in the working directory of a DirDBM save those -created by the DirDBM itself! - -Maintainer: Itamar Shtull-Trauring -""" - - -import os -import types -import base64 -import glob - -try: - import cPickle as pickle -except ImportError: - import pickle - -try: - _open -except NameError: - _open = open - - -class DirDBM: - """A directory with a DBM interface. - - This class presents a hash-like interface to a directory of small, - flat files. It can only use strings as keys or values. - """ - - def __init__(self, name): - """ - @type name: str - @param name: Base path to use for the directory storage. - """ - self.dname = os.path.abspath(name) - if not os.path.isdir(self.dname): - os.mkdir(self.dname) - else: - # Run recovery, in case we crashed. we delete all files ending - # with ".new". Then we find all files who end with ".rpl". If a - # corresponding file exists without ".rpl", we assume the write - # failed and delete the ".rpl" file. If only a ".rpl" exist we - # assume the program crashed right after deleting the old entry - # but before renaming the replacement entry. - # - # NOTE: '.' is NOT in the base64 alphabet! - for f in glob.glob(os.path.join(self.dname, "*.new")): - os.remove(f) - replacements = glob.glob(os.path.join(self.dname, "*.rpl")) - for f in replacements: - old = f[:-4] - if os.path.exists(old): - os.remove(f) - else: - os.rename(f, old) - - def _encode(self, k): - """Encode a key so it can be used as a filename. - """ - # NOTE: '_' is NOT in the base64 alphabet! - return base64.encodestring(k).replace('\n', '_').replace("/", "-") - - def _decode(self, k): - """Decode a filename to get the key. - """ - return base64.decodestring(k.replace('_', '\n').replace("-", "/")) - - def _readFile(self, path): - """Read in the contents of a file. - - Override in subclasses to e.g. provide transparently encrypted dirdbm. - """ - f = _open(path, "rb") - s = f.read() - f.close() - return s - - def _writeFile(self, path, data): - """Write data to a file. - - Override in subclasses to e.g. provide transparently encrypted dirdbm. - """ - f = _open(path, "wb") - f.write(data) - f.flush() - f.close() - - def __len__(self): - """ - @return: The number of key/value pairs in this Shelf - """ - return len(os.listdir(self.dname)) - - def __setitem__(self, k, v): - """ - C{dirdbm[k] = v} - Create or modify a textfile in this directory - - @type k: str - @param k: key to set - - @type v: str - @param v: value to associate with C{k} - """ - assert type(k) == types.StringType, "DirDBM key must be a string" - assert type(v) == types.StringType, "DirDBM value must be a string" - k = self._encode(k) - - # we create a new file with extension .new, write the data to it, and - # if the write succeeds delete the old file and rename the new one. - old = os.path.join(self.dname, k) - if os.path.exists(old): - new = old + ".rpl" # replacement entry - else: - new = old + ".new" # new entry - try: - self._writeFile(new, v) - except: - os.remove(new) - raise - else: - if os.path.exists(old): os.remove(old) - os.rename(new, old) - - def __getitem__(self, k): - """ - C{dirdbm[k]} - Get the contents of a file in this directory as a string. - - @type k: str - @param k: key to lookup - - @return: The value associated with C{k} - @raise KeyError: Raised when there is no such key - """ - assert type(k) == types.StringType, "DirDBM key must be a string" - path = os.path.join(self.dname, self._encode(k)) - try: - return self._readFile(path) - except: - raise KeyError, k - - def __delitem__(self, k): - """ - C{del dirdbm[foo]} - Delete a file in this directory. - - @type k: str - @param k: key to delete - - @raise KeyError: Raised when there is no such key - """ - assert type(k) == types.StringType, "DirDBM key must be a string" - k = self._encode(k) - try: os.remove(os.path.join(self.dname, k)) - except (OSError, IOError): raise KeyError(self._decode(k)) - - def keys(self): - """ - @return: a C{list} of filenames (keys). - """ - return map(self._decode, os.listdir(self.dname)) - - def values(self): - """ - @return: a C{list} of file-contents (values). - """ - vals = [] - keys = self.keys() - for key in keys: - vals.append(self[key]) - return vals - - def items(self): - """ - @return: a C{list} of 2-tuples containing key/value pairs. - """ - items = [] - keys = self.keys() - for key in keys: - items.append((key, self[key])) - return items - - def has_key(self, key): - """ - @type key: str - @param key: The key to test - - @return: A true value if this dirdbm has the specified key, a faluse - value otherwise. - """ - assert type(key) == types.StringType, "DirDBM key must be a string" - key = self._encode(key) - return os.path.isfile(os.path.join(self.dname, key)) - - def setdefault(self, key, value): - """ - @type key: str - @param key: The key to lookup - - @param value: The value to associate with key if key is not already - associated with a value. - """ - if not self.has_key(key): - self[key] = value - return value - return self[key] - - def get(self, key, default = None): - """ - @type key: str - @param key: The key to lookup - - @param default: The value to return if the given key does not exist - - @return: The value associated with C{key} or C{default} if not - C{self.has_key(key)} - """ - if self.has_key(key): - return self[key] - else: - return default - - def __contains__(self, key): - """ - C{key in dirdbm} - - @type key: str - @param key: The key to test - - @return: A true value if C{self.has_key(key)}, a false value otherwise. - """ - assert type(key) == types.StringType, "DirDBM key must be a string" - key = self._encode(key) - return os.path.isfile(os.path.join(self.dname, key)) - - def update(self, dict): - """ - Add all the key/value pairs in C{dict} to this dirdbm. Any conflicting - keys will be overwritten with the values from C{dict}. - - @type dict: mapping - @param dict: A mapping of key/value pairs to add to this dirdbm. - """ - for key, val in dict.items(): - self[key]=val - - def copyTo(self, path): - """ - Copy the contents of this dirdbm to the dirdbm at C{path}. - - @type path: C{str} - @param path: The path of the dirdbm to copy to. If a dirdbm - exists at the destination path, it is cleared first. - - @rtype: C{DirDBM} - @return: The dirdbm this dirdbm was copied to. - """ - path = os.path.abspath(path) - assert path != self.dname - - d = self.__class__(path) - d.clear() - for k in self.keys(): - d[k] = self[k] - return d - - def clear(self): - """ - Delete all key/value pairs in this dirdbm. - """ - for k in self.keys(): - del self[k] - - def close(self): - """ - Close this dbm: no-op, for dbm-style interface compliance. - """ - - def getModificationTime(self, key): - """ - Returns modification time of an entry. - - @return: Last modification date (seconds since epoch) of entry C{key} - @raise KeyError: Raised when there is no such key - """ - assert type(key) == types.StringType, "DirDBM key must be a string" - path = os.path.join(self.dname, self._encode(key)) - if os.path.isfile(path): - return os.path.getmtime(path) - else: - raise KeyError, key - - -class Shelf(DirDBM): - """A directory with a DBM shelf interface. - - This class presents a hash-like interface to a directory of small, - flat files. Keys must be strings, but values can be any given object. - """ - - def __setitem__(self, k, v): - """ - C{shelf[foo] = bar} - Create or modify a textfile in this directory. - - @type k: str - @param k: The key to set - - @param v: The value to associate with C{key} - """ - v = pickle.dumps(v) - DirDBM.__setitem__(self, k, v) - - def __getitem__(self, k): - """ - C{dirdbm[foo]} - Get and unpickle the contents of a file in this directory. - - @type k: str - @param k: The key to lookup - - @return: The value associated with the given key - @raise KeyError: Raised if the given key does not exist - """ - return pickle.loads(DirDBM.__getitem__(self, k)) - - -def open(file, flag = None, mode = None): - """ - This is for 'anydbm' compatibility. - - @param file: The parameter to pass to the DirDBM constructor. - - @param flag: ignored - @param mode: ignored - """ - return DirDBM(file) - - -__all__ = ["open", "DirDBM", "Shelf"] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/sob.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/sob.py deleted file mode 100644 index 89d9caa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/sob.py +++ /dev/null @@ -1,227 +0,0 @@ -# -*- test-case-name: twisted.test.test_sob -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Save and load Small OBjects to and from files, using various formats. - -Maintainer: Moshe Zadka -""" - -import os, sys -try: - import cPickle as pickle -except ImportError: - import pickle -try: - import cStringIO as StringIO -except ImportError: - import StringIO -from hashlib import md5 -from twisted.python import log, runtime -from twisted.persisted import styles -from zope.interface import implements, Interface - -# Note: -# These encrypt/decrypt functions only work for data formats -# which are immune to having spaces tucked at the end. -# All data formats which persist saves hold that condition. -def _encrypt(passphrase, data): - from Crypto.Cipher import AES as cipher - leftover = len(data) % cipher.block_size - if leftover: - data += ' '*(cipher.block_size - leftover) - return cipher.new(md5(passphrase).digest()[:16]).encrypt(data) - -def _decrypt(passphrase, data): - from Crypto.Cipher import AES - return AES.new(md5(passphrase).digest()[:16]).decrypt(data) - - -class IPersistable(Interface): - - """An object which can be saved in several formats to a file""" - - def setStyle(style): - """Set desired format. - - @type style: string (one of 'pickle' or 'source') - """ - - def save(tag=None, filename=None, passphrase=None): - """Save object to file. - - @type tag: string - @type filename: string - @type passphrase: string - """ - - -class Persistent: - - implements(IPersistable) - - style = "pickle" - - def __init__(self, original, name): - self.original = original - self.name = name - - def setStyle(self, style): - """Set desired format. - - @type style: string (one of 'pickle' or 'source') - """ - self.style = style - - def _getFilename(self, filename, ext, tag): - if filename: - finalname = filename - filename = finalname + "-2" - elif tag: - filename = "%s-%s-2.%s" % (self.name, tag, ext) - finalname = "%s-%s.%s" % (self.name, tag, ext) - else: - filename = "%s-2.%s" % (self.name, ext) - finalname = "%s.%s" % (self.name, ext) - return finalname, filename - - def _saveTemp(self, filename, passphrase, dumpFunc): - f = open(filename, 'wb') - if passphrase is None: - dumpFunc(self.original, f) - else: - s = StringIO.StringIO() - dumpFunc(self.original, s) - f.write(_encrypt(passphrase, s.getvalue())) - f.close() - - def _getStyle(self): - if self.style == "source": - from twisted.persisted.aot import jellyToSource as dumpFunc - ext = "tas" - else: - def dumpFunc(obj, file): - pickle.dump(obj, file, 2) - ext = "tap" - return ext, dumpFunc - - def save(self, tag=None, filename=None, passphrase=None): - """Save object to file. - - @type tag: string - @type filename: string - @type passphrase: string - """ - ext, dumpFunc = self._getStyle() - if passphrase: - ext = 'e' + ext - finalname, filename = self._getFilename(filename, ext, tag) - log.msg("Saving "+self.name+" application to "+finalname+"...") - self._saveTemp(filename, passphrase, dumpFunc) - if runtime.platformType == "win32" and os.path.isfile(finalname): - os.remove(finalname) - os.rename(filename, finalname) - log.msg("Saved.") - -# "Persistant" has been present since 1.0.7, so retain it for compatibility -Persistant = Persistent - -class _EverythingEphemeral(styles.Ephemeral): - - initRun = 0 - - def __init__(self, mainMod): - """ - @param mainMod: The '__main__' module that this class will proxy. - """ - self.mainMod = mainMod - - def __getattr__(self, key): - try: - return getattr(self.mainMod, key) - except AttributeError: - if self.initRun: - raise - else: - log.msg("Warning! Loading from __main__: %s" % key) - return styles.Ephemeral() - - -def load(filename, style, passphrase=None): - """Load an object from a file. - - Deserialize an object from a file. The file can be encrypted. - - @param filename: string - @param style: string (one of 'pickle' or 'source') - @param passphrase: string - """ - mode = 'r' - if style=='source': - from twisted.persisted.aot import unjellyFromSource as _load - else: - _load, mode = pickle.load, 'rb' - if passphrase: - fp = StringIO.StringIO(_decrypt(passphrase, - open(filename, 'rb').read())) - else: - fp = open(filename, mode) - ee = _EverythingEphemeral(sys.modules['__main__']) - sys.modules['__main__'] = ee - ee.initRun = 1 - try: - value = _load(fp) - finally: - # restore __main__ if an exception is raised. - sys.modules['__main__'] = ee.mainMod - - styles.doUpgrade() - ee.initRun = 0 - persistable = IPersistable(value, None) - if persistable is not None: - persistable.setStyle(style) - return value - - -def loadValueFromFile(filename, variable, passphrase=None): - """Load the value of a variable in a Python file. - - Run the contents of the file, after decrypting if C{passphrase} is - given, in a namespace and return the result of the variable - named C{variable}. - - @param filename: string - @param variable: string - @param passphrase: string - """ - if passphrase: - mode = 'rb' - else: - mode = 'r' - fileObj = open(filename, mode) - d = {'__file__': filename} - if passphrase: - data = fileObj.read() - data = _decrypt(passphrase, data) - exec data in d, d - else: - exec fileObj in d, d - value = d[variable] - return value - -def guessType(filename): - ext = os.path.splitext(filename)[1] - return { - '.tac': 'python', - '.etac': 'python', - '.py': 'python', - '.tap': 'pickle', - '.etap': 'pickle', - '.tas': 'source', - '.etas': 'source', - }[ext] - -__all__ = ['loadValueFromFile', 'load', 'Persistent', 'Persistant', - 'IPersistable', 'guessType'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/styles.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/styles.py deleted file mode 100644 index e3ca39b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/styles.py +++ /dev/null @@ -1,262 +0,0 @@ -# -*- test-case-name: twisted.test.test_persisted -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -Different styles of persisted objects. -""" - -# System Imports -import types -import copy_reg -import copy -import inspect -import sys - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -# Twisted Imports -from twisted.python import log -from twisted.python import reflect - -oldModules = {} - -## First, let's register support for some stuff that really ought to -## be registerable... - -def pickleMethod(method): - 'support function for copy_reg to pickle method refs' - return unpickleMethod, (method.im_func.__name__, - method.im_self, - method.im_class) - -def unpickleMethod(im_name, - im_self, - im_class): - 'support function for copy_reg to unpickle method refs' - try: - unbound = getattr(im_class,im_name) - if im_self is None: - return unbound - bound = types.MethodType(unbound.im_func, im_self, im_class) - return bound - except AttributeError: - log.msg("Method",im_name,"not on class",im_class) - assert im_self is not None,"No recourse: no instance to guess from." - # Attempt a common fix before bailing -- if classes have - # changed around since we pickled this method, we may still be - # able to get it by looking on the instance's current class. - unbound = getattr(im_self.__class__,im_name) - log.msg("Attempting fixup with",unbound) - if im_self is None: - return unbound - bound = types.MethodType(unbound.im_func, im_self, im_self.__class__) - return bound - -copy_reg.pickle(types.MethodType, - pickleMethod, - unpickleMethod) - -def pickleModule(module): - 'support function for copy_reg to pickle module refs' - return unpickleModule, (module.__name__,) - -def unpickleModule(name): - 'support function for copy_reg to unpickle module refs' - if name in oldModules: - log.msg("Module has moved: %s" % name) - name = oldModules[name] - log.msg(name) - return __import__(name,{},{},'x') - - -copy_reg.pickle(types.ModuleType, - pickleModule, - unpickleModule) - -def pickleStringO(stringo): - 'support function for copy_reg to pickle StringIO.OutputTypes' - return unpickleStringO, (stringo.getvalue(), stringo.tell()) - -def unpickleStringO(val, sek): - x = StringIO.StringIO() - x.write(val) - x.seek(sek) - return x - -if hasattr(StringIO, 'OutputType'): - copy_reg.pickle(StringIO.OutputType, - pickleStringO, - unpickleStringO) - -def pickleStringI(stringi): - return unpickleStringI, (stringi.getvalue(), stringi.tell()) - -def unpickleStringI(val, sek): - x = StringIO.StringIO(val) - x.seek(sek) - return x - - -if hasattr(StringIO, 'InputType'): - copy_reg.pickle(StringIO.InputType, - pickleStringI, - unpickleStringI) - -class Ephemeral: - """ - This type of object is never persisted; if possible, even references to it - are eliminated. - """ - - def __getstate__(self): - log.msg( "WARNING: serializing ephemeral %s" % self ) - import gc - if '__pypy__' not in sys.builtin_module_names: - if getattr(gc, 'get_referrers', None): - for r in gc.get_referrers(self): - log.msg( " referred to by %s" % (r,)) - return None - - def __setstate__(self, state): - log.msg( "WARNING: unserializing ephemeral %s" % self.__class__ ) - self.__class__ = Ephemeral - - -versionedsToUpgrade = {} -upgraded = {} - -def doUpgrade(): - global versionedsToUpgrade, upgraded - for versioned in versionedsToUpgrade.values(): - requireUpgrade(versioned) - versionedsToUpgrade = {} - upgraded = {} - -def requireUpgrade(obj): - """Require that a Versioned instance be upgraded completely first. - """ - objID = id(obj) - if objID in versionedsToUpgrade and objID not in upgraded: - upgraded[objID] = 1 - obj.versionUpgrade() - return obj - -def _aybabtu(c): - """ - Get all of the parent classes of C{c}, not including C{c} itself, which are - strict subclasses of L{Versioned}. - - The name comes from "all your base are belong to us", from the deprecated - L{twisted.python.reflect.allYourBase} function. - - @param c: a class - @returns: list of classes - """ - # begin with two classes that should *not* be included in the - # final result - l = [c, Versioned] - for b in inspect.getmro(c): - if b not in l and issubclass(b, Versioned): - l.append(b) - # return all except the unwanted classes - return l[2:] - -class Versioned: - """ - This type of object is persisted with versioning information. - - I have a single class attribute, the int persistenceVersion. After I am - unserialized (and styles.doUpgrade() is called), self.upgradeToVersionX() - will be called for each version upgrade I must undergo. - - For example, if I serialize an instance of a Foo(Versioned) at version 4 - and then unserialize it when the code is at version 9, the calls:: - - self.upgradeToVersion5() - self.upgradeToVersion6() - self.upgradeToVersion7() - self.upgradeToVersion8() - self.upgradeToVersion9() - - will be made. If any of these methods are undefined, a warning message - will be printed. - """ - persistenceVersion = 0 - persistenceForgets = () - - def __setstate__(self, state): - versionedsToUpgrade[id(self)] = self - self.__dict__ = state - - def __getstate__(self, dict=None): - """Get state, adding a version number to it on its way out. - """ - dct = copy.copy(dict or self.__dict__) - bases = _aybabtu(self.__class__) - bases.reverse() - bases.append(self.__class__) # don't forget me!! - for base in bases: - if 'persistenceForgets' in base.__dict__: - for slot in base.persistenceForgets: - if slot in dct: - del dct[slot] - if 'persistenceVersion' in base.__dict__: - dct['%s.persistenceVersion' % reflect.qual(base)] = base.persistenceVersion - return dct - - def versionUpgrade(self): - """(internal) Do a version upgrade. - """ - bases = _aybabtu(self.__class__) - # put the bases in order so superclasses' persistenceVersion methods - # will be called first. - bases.reverse() - bases.append(self.__class__) # don't forget me!! - # first let's look for old-skool versioned's - if "persistenceVersion" in self.__dict__: - - # Hacky heuristic: if more than one class subclasses Versioned, - # we'll assume that the higher version number wins for the older - # class, so we'll consider the attribute the version of the older - # class. There are obviously possibly times when this will - # eventually be an incorrect assumption, but hopefully old-school - # persistenceVersion stuff won't make it that far into multiple - # classes inheriting from Versioned. - - pver = self.__dict__['persistenceVersion'] - del self.__dict__['persistenceVersion'] - highestVersion = 0 - highestBase = None - for base in bases: - if not base.__dict__.has_key('persistenceVersion'): - continue - if base.persistenceVersion > highestVersion: - highestBase = base - highestVersion = base.persistenceVersion - if highestBase: - self.__dict__['%s.persistenceVersion' % reflect.qual(highestBase)] = pver - for base in bases: - # ugly hack, but it's what the user expects, really - if (Versioned not in base.__bases__ and - 'persistenceVersion' not in base.__dict__): - continue - currentVers = base.persistenceVersion - pverName = '%s.persistenceVersion' % reflect.qual(base) - persistVers = (self.__dict__.get(pverName) or 0) - if persistVers: - del self.__dict__[pverName] - assert persistVers <= currentVers, "Sorry, can't go backwards in time." - while persistVers < currentVers: - persistVers = persistVers + 1 - method = base.__dict__.get('upgradeToVersion%s' % persistVers, None) - if method: - log.msg( "Upgrading %s (of %s @ %s) to version %s" % (reflect.qual(base), reflect.qual(self.__class__), id(self), persistVers) ) - method(self) - else: - log.msg( 'Warning: cannot upgrade %s to version %s' % (base, persistVers) ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/test/__init__.py deleted file mode 100644 index 01ae065..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.persisted}. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/test/test_styles.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/test/test_styles.py deleted file mode 100644 index 9fcada7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/persisted/test/test_styles.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.persisted.styles}. -""" - -from twisted.trial import unittest -from twisted.persisted.styles import unpickleMethod - - -class Foo: - """ - Helper class. - """ - def method(self): - """ - Helper method. - """ - - - -class Bar: - """ - Helper class. - """ - - - -class UnpickleMethodTests(unittest.TestCase): - """ - Tests for the unpickleMethod function. - """ - - def test_instanceBuildingNamePresent(self): - """ - L{unpickleMethod} returns an instance method bound to the - instance passed to it. - """ - foo = Foo() - m = unpickleMethod('method', foo, Foo) - self.assertEqual(m, foo.method) - self.assertNotIdentical(m, foo.method) - - - def test_instanceBuildingNameNotPresent(self): - """ - If the named method is not present in the class, - L{unpickleMethod} finds a method on the class of the instance - and returns a bound method from there. - """ - foo = Foo() - m = unpickleMethod('method', foo, Bar) - self.assertEqual(m, foo.method) - self.assertNotIdentical(m, foo.method) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugin.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugin.py deleted file mode 100644 index 4ef2de5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugin.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- test-case-name: twisted.test.test_plugin -*- -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Plugin system for Twisted. - -@author: Jp Calderone -@author: Glyph Lefkowitz -""" - -import os -import sys - -from zope.interface import Interface, providedBy - -def _determinePickleModule(): - """ - Determine which 'pickle' API module to use. - """ - try: - import cPickle - return cPickle - except ImportError: - import pickle - return pickle - -pickle = _determinePickleModule() - -from twisted.python.components import getAdapterFactory -from twisted.python.reflect import namedAny -from twisted.python import log -from twisted.python.modules import getModule - - - -class IPlugin(Interface): - """ - Interface that must be implemented by all plugins. - - Only objects which implement this interface will be considered for return - by C{getPlugins}. To be useful, plugins should also implement some other - application-specific interface. - """ - - - -class CachedPlugin(object): - def __init__(self, dropin, name, description, provided): - self.dropin = dropin - self.name = name - self.description = description - self.provided = provided - self.dropin.plugins.append(self) - - def __repr__(self): - return '' % ( - self.name, self.dropin.moduleName, - ', '.join([i.__name__ for i in self.provided])) - - def load(self): - return namedAny(self.dropin.moduleName + '.' + self.name) - - def __conform__(self, interface, registry=None, default=None): - for providedInterface in self.provided: - if providedInterface.isOrExtends(interface): - return self.load() - if getAdapterFactory(providedInterface, interface, None) is not None: - return interface(self.load(), default) - return default - - # backwards compat HOORJ - getComponent = __conform__ - - - -class CachedDropin(object): - """ - A collection of L{CachedPlugin} instances from a particular module in a - plugin package. - - @type moduleName: C{str} - @ivar moduleName: The fully qualified name of the plugin module this - represents. - - @type description: C{str} or C{NoneType} - @ivar description: A brief explanation of this collection of plugins - (probably the plugin module's docstring). - - @type plugins: C{list} - @ivar plugins: The L{CachedPlugin} instances which were loaded from this - dropin. - """ - def __init__(self, moduleName, description): - self.moduleName = moduleName - self.description = description - self.plugins = [] - - - -def _generateCacheEntry(provider): - dropin = CachedDropin(provider.__name__, - provider.__doc__) - for k, v in provider.__dict__.iteritems(): - plugin = IPlugin(v, None) - if plugin is not None: - # Instantiated for its side-effects. - CachedPlugin(dropin, k, v.__doc__, list(providedBy(plugin))) - return dropin - -try: - fromkeys = dict.fromkeys -except AttributeError: - def fromkeys(keys, value=None): - d = {} - for k in keys: - d[k] = value - return d - - - -def getCache(module): - """ - Compute all the possible loadable plugins, while loading as few as - possible and hitting the filesystem as little as possible. - - @param module: a Python module object. This represents a package to search - for plugins. - - @return: a dictionary mapping module names to L{CachedDropin} instances. - """ - allCachesCombined = {} - mod = getModule(module.__name__) - # don't want to walk deep, only immediate children. - buckets = {} - # Fill buckets with modules by related entry on the given package's - # __path__. There's an abstraction inversion going on here, because this - # information is already represented internally in twisted.python.modules, - # but it's simple enough that I'm willing to live with it. If anyone else - # wants to fix up this iteration so that it's one path segment at a time, - # be my guest. --glyph - for plugmod in mod.iterModules(): - fpp = plugmod.filePath.parent() - if fpp not in buckets: - buckets[fpp] = [] - bucket = buckets[fpp] - bucket.append(plugmod) - for pseudoPackagePath, bucket in buckets.iteritems(): - dropinPath = pseudoPackagePath.child('dropin.cache') - try: - lastCached = dropinPath.getModificationTime() - dropinDotCache = pickle.load(dropinPath.open('r')) - except: - dropinDotCache = {} - lastCached = 0 - - needsWrite = False - existingKeys = {} - for pluginModule in bucket: - pluginKey = pluginModule.name.split('.')[-1] - existingKeys[pluginKey] = True - if ((pluginKey not in dropinDotCache) or - (pluginModule.filePath.getModificationTime() >= lastCached)): - needsWrite = True - try: - provider = pluginModule.load() - except: - # dropinDotCache.pop(pluginKey, None) - log.err() - else: - entry = _generateCacheEntry(provider) - dropinDotCache[pluginKey] = entry - # Make sure that the cache doesn't contain any stale plugins. - for pluginKey in dropinDotCache.keys(): - if pluginKey not in existingKeys: - del dropinDotCache[pluginKey] - needsWrite = True - if needsWrite: - try: - dropinPath.setContent(pickle.dumps(dropinDotCache)) - except OSError as e: - log.msg( - format=( - "Unable to write to plugin cache %(path)s: error " - "number %(errno)d"), - path=dropinPath.path, errno=e.errno) - except: - log.err(None, "Unexpected error while writing cache file") - allCachesCombined.update(dropinDotCache) - return allCachesCombined - - - -def getPlugins(interface, package=None): - """ - Retrieve all plugins implementing the given interface beneath the given module. - - @param interface: An interface class. Only plugins which implement this - interface will be returned. - - @param package: A package beneath which plugins are installed. For - most uses, the default value is correct. - - @return: An iterator of plugins. - """ - if package is None: - import twisted.plugins as package - allDropins = getCache(package) - for dropin in allDropins.itervalues(): - for plugin in dropin.plugins: - try: - adapted = interface(plugin, None) - except: - log.err() - else: - if adapted is not None: - yield adapted - - -# Old, backwards compatible name. Don't use this. -getPlugIns = getPlugins - - -def pluginPackagePaths(name): - """ - Return a list of additional directories which should be searched for - modules to be included as part of the named plugin package. - - @type name: C{str} - @param name: The fully-qualified Python name of a plugin package, eg - C{'twisted.plugins'}. - - @rtype: C{list} of C{str} - @return: The absolute paths to other directories which may contain plugin - modules for the named plugin package. - """ - package = name.split('.') - # Note that this may include directories which do not exist. It may be - # preferable to remove such directories at this point, rather than allow - # them to be searched later on. - # - # Note as well that only '__init__.py' will be considered to make a - # directory a package (and thus exclude it from this list). This means - # that if you create a master plugin package which has some other kind of - # __init__ (eg, __init__.pyc) it will be incorrectly treated as a - # supplementary plugin directory. - return [ - os.path.abspath(os.path.join(x, *package)) - for x - in sys.path - if - not os.path.exists(os.path.join(x, *package + ['__init__.py']))] - -__all__ = ['getPlugins', 'pluginPackagePaths'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/__init__.py deleted file mode 100644 index dd2d6aa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- test-case-name: twisted.test.test_plugin -*- -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Plugins for services implemented in Twisted. - -Plugins go in directories on your PYTHONPATH named twisted/plugins: -this is the only place where an __init__.py is necessary, thanks to -the __path__ variable. - -@author: Jp Calderone -@author: Glyph Lefkowitz -""" - -from twisted.plugin import pluginPackagePaths -__path__.extend(pluginPackagePaths(__name__)) -__all__ = [] # nothing to see here, move along, move along diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_anonymous.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_anonymous.py deleted file mode 100644 index ad0ea9e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_anonymous.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for anonymous logins. -""" - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.checkers import AllowAnonymousAccess -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.credentials import IAnonymous - - -anonymousCheckerFactoryHelp = """ -This allows anonymous authentication for servers that support it. -""" - - -class AnonymousCheckerFactory(object): - """ - Generates checkers that will authenticate an anonymous request. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'anonymous' - authHelp = anonymousCheckerFactoryHelp - argStringFormat = 'No argstring required.' - credentialInterfaces = (IAnonymous,) - - - def generateChecker(self, argstring=''): - return AllowAnonymousAccess() - - - -theAnonymousCheckerFactory = AnonymousCheckerFactory() - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_file.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_file.py deleted file mode 100644 index 3ff9b37..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_file.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for a file of the format 'username:password'. -""" - -import sys - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.checkers import FilePasswordDB -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword - - - -fileCheckerFactoryHelp = """ -This checker expects to receive the location of a file that -conforms to the FilePasswordDB format. Each line in the file -should be of the format 'username:password', in plain text. -""" - -invalidFileWarning = 'Warning: not a valid file' - - - -class FileCheckerFactory(object): - """ - A factory for instances of L{FilePasswordDB}. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'file' - authHelp = fileCheckerFactoryHelp - argStringFormat = 'Location of a FilePasswordDB-formatted file.' - # Explicitly defined here because FilePasswordDB doesn't do it for us - credentialInterfaces = (IUsernamePassword, IUsernameHashedPassword) - - errorOutput = sys.stderr - - def generateChecker(self, argstring): - """ - This checker factory expects to get the location of a file. - The file should conform to the format required by - L{FilePasswordDB} (using defaults for all - initialization parameters). - """ - from twisted.python.filepath import FilePath - if not argstring.strip(): - raise ValueError, '%r requires a filename' % self.authType - elif not FilePath(argstring).isfile(): - self.errorOutput.write('%s: %s\n' % (invalidFileWarning, argstring)) - return FilePasswordDB(argstring) - - - -theFileCheckerFactory = FileCheckerFactory() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_memory.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_memory.py deleted file mode 100644 index 0ed9083..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_memory.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for an in-memory user database. -""" - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse -from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword - - - -inMemoryCheckerFactoryHelp = """ -A checker that uses an in-memory user database. - -This is only of use in one-off test programs or examples which -don't want to focus too much on how credentials are verified. You -really don't want to use this for anything else. It is a toy. -""" - - - -class InMemoryCheckerFactory(object): - """ - A factory for in-memory credentials checkers. - - This is only of use in one-off test programs or examples which don't - want to focus too much on how credentials are verified. - - You really don't want to use this for anything else. It is, at best, a - toy. If you need a simple credentials checker for a real application, - see L{cred_passwd.PasswdCheckerFactory}. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'memory' - authHelp = inMemoryCheckerFactoryHelp - argStringFormat = 'A colon-separated list (name:password:...)' - credentialInterfaces = (IUsernamePassword, - IUsernameHashedPassword) - - def generateChecker(self, argstring): - """ - This checker factory expects to get a list of - username:password pairs, with each pair also separated by a - colon. For example, the string 'alice:f:bob:g' would generate - two users, one named 'alice' and one named 'bob'. - """ - checker = InMemoryUsernamePasswordDatabaseDontUse() - if argstring: - pieces = argstring.split(':') - if len(pieces) % 2: - from twisted.cred.strcred import InvalidAuthArgumentString - raise InvalidAuthArgumentString( - "argstring must be in format U:P:...") - for i in range(0, len(pieces), 2): - username, password = pieces[i], pieces[i+1] - checker.addUser(username, password) - return checker - - - -theInMemoryCheckerFactory = InMemoryCheckerFactory() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_sshkeys.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_sshkeys.py deleted file mode 100644 index e415146..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_sshkeys.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for ssh key login -""" - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.strcred import ICheckerFactory - - -sshKeyCheckerFactoryHelp = """ -This allows SSH public key authentication, based on public keys listed in -authorized_keys and authorized_keys2 files in user .ssh/ directories. -""" - - -try: - from twisted.conch.checkers import ( - SSHPublicKeyChecker, UNIXAuthorizedKeysFiles) - - class SSHKeyCheckerFactory(object): - """ - Generates checkers that will authenticate a SSH public key - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'sshkey' - authHelp = sshKeyCheckerFactoryHelp - argStringFormat = 'No argstring required.' - credentialInterfaces = SSHPublicKeyChecker.credentialInterfaces - - - def generateChecker(self, argstring=''): - """ - This checker factory ignores the argument string. Everything - needed to authenticate users is pulled out of the public keys - listed in user .ssh/ directories. - """ - return SSHPublicKeyChecker(UNIXAuthorizedKeysFiles()) - - - - theSSHKeyCheckerFactory = SSHKeyCheckerFactory() - -except ImportError: - # if checkers can't be imported, then there should be no SSH cred plugin - pass diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_unix.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_unix.py deleted file mode 100644 index a636497..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/cred_unix.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for UNIX user accounts. -""" - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.checkers import ICredentialsChecker -from twisted.cred.credentials import IUsernamePassword -from twisted.cred.error import UnauthorizedLogin -from twisted.internet import defer - - - -def verifyCryptedPassword(crypted, pw): - if crypted[0] == '$': # md5_crypt encrypted - salt = '$1$' + crypted.split('$')[2] - else: - salt = crypted[:2] - try: - import crypt - except ImportError: - crypt = None - - if crypt is None: - raise NotImplementedError("cred_unix not supported on this platform") - return crypt.crypt(pw, salt) == crypted - - - -class UNIXChecker(object): - """ - A credentials checker for a UNIX server. This will check that - an authenticating username/password is a valid user on the system. - - Does not work on Windows. - - Right now this supports Python's pwd and spwd modules, if they are - installed. It does not support PAM. - """ - implements(ICredentialsChecker) - credentialInterfaces = (IUsernamePassword,) - - - def checkPwd(self, pwd, username, password): - try: - cryptedPass = pwd.getpwnam(username)[1] - except KeyError: - return defer.fail(UnauthorizedLogin()) - else: - if cryptedPass in ('*', 'x'): - # Allow checkSpwd to take over - return None - elif verifyCryptedPassword(cryptedPass, password): - return defer.succeed(username) - - - def checkSpwd(self, spwd, username, password): - try: - cryptedPass = spwd.getspnam(username)[1] - except KeyError: - return defer.fail(UnauthorizedLogin()) - else: - if verifyCryptedPassword(cryptedPass, password): - return defer.succeed(username) - - - def requestAvatarId(self, credentials): - username, password = credentials.username, credentials.password - - try: - import pwd - except ImportError: - pwd = None - - if pwd is not None: - checked = self.checkPwd(pwd, username, password) - if checked is not None: - return checked - - try: - import spwd - except ImportError: - spwd = None - - if spwd is not None: - checked = self.checkSpwd(spwd, username, password) - if checked is not None: - return checked - # TODO: check_pam? - # TODO: check_shadow? - return defer.fail(UnauthorizedLogin()) - - - -unixCheckerFactoryHelp = """ -This checker will attempt to use every resource available to -authenticate against the list of users on the local UNIX system. -(This does not support Windows servers for very obvious reasons.) - -Right now, this includes support for: - - * Python's pwd module (which checks /etc/passwd) - * Python's spwd module (which checks /etc/shadow) - -Future versions may include support for PAM authentication. -""" - - - -class UNIXCheckerFactory(object): - """ - A factory for L{UNIXChecker}. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'unix' - authHelp = unixCheckerFactoryHelp - argStringFormat = 'No argstring required.' - credentialInterfaces = UNIXChecker.credentialInterfaces - - def generateChecker(self, argstring): - """ - This checker factory ignores the argument string. Everything - needed to generate a user database is pulled out of the local - UNIX environment. - """ - return UNIXChecker() - - - -theUnixCheckerFactory = UNIXCheckerFactory() - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_conch.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_conch.py deleted file mode 100644 index 4b37e0b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_conch.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedSSH = ServiceMaker( - "Twisted Conch Server", - "twisted.conch.tap", - "A Conch SSH service.", - "conch") - -TwistedManhole = ServiceMaker( - "Twisted Manhole (new)", - "twisted.conch.manhole_tap", - ("An interactive remote debugger service accessible via telnet " - "and ssh and providing syntax coloring and basic line editing " - "functionality."), - "manhole") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_core.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_core.py deleted file mode 100644 index 3907d42..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_core.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.internet.endpoints import _SystemdParser, _TCP6ServerParser, _StandardIOParser - -systemdEndpointParser = _SystemdParser() -tcp6ServerEndpointParser = _TCP6ServerParser() -stdioEndpointParser = _StandardIOParser() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_ftp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_ftp.py deleted file mode 100644 index 474a9c7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_ftp.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedFTP = ServiceMaker( - "Twisted FTP", - "twisted.tap.ftp", - "An FTP server.", - "ftp") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_inet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_inet.py deleted file mode 100644 index 1196343..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_inet.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedINETD = ServiceMaker( - "Twisted INETD Server", - "twisted.runner.inetdtap", - "An inetd(8) replacement.", - "inetd") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_lore.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_lore.py deleted file mode 100644 index 1ab57a5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_lore.py +++ /dev/null @@ -1,38 +0,0 @@ - -from zope.interface import implements - -from twisted.lore.scripts.lore import IProcessor -from twisted.plugin import IPlugin - -class _LorePlugin(object): - implements(IPlugin, IProcessor) - - def __init__(self, name, moduleName, description): - self.name = name - self.moduleName = moduleName - self.description = description - -DefaultProcessor = _LorePlugin( - "lore", - "twisted.lore.default", - "Lore format") - -MathProcessor = _LorePlugin( - "mlore", - "twisted.lore.lmath", - "Lore format with LaTeX formula") - -SlideProcessor = _LorePlugin( - "lore-slides", - "twisted.lore.slides", - "Lore for slides") - -ManProcessor = _LorePlugin( - "man", - "twisted.lore.man2lore", - "UNIX Man pages") - -NevowProcessor = _LorePlugin( - "nevow", - "twisted.lore.nevowlore", - "Nevow for Lore") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_mail.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_mail.py deleted file mode 100644 index 7e9a5bd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_mail.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedMail = ServiceMaker( - "Twisted Mail", - "twisted.mail.tap", - "An email service", - "mail") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_manhole.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_manhole.py deleted file mode 100644 index 2481890..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_manhole.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedManhole = ServiceMaker( - "Twisted Manhole (old)", - "twisted.tap.manhole", - "An interactive remote debugger service.", - "manhole-old") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_names.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_names.py deleted file mode 100644 index 7123bf0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_names.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedNames = ServiceMaker( - "Twisted DNS Server", - "twisted.names.tap", - "A domain name server.", - "dns") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_news.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_news.py deleted file mode 100644 index 0fc88d8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_news.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedNews = ServiceMaker( - "Twisted News", - "twisted.news.tap", - "A news server.", - "news") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_portforward.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_portforward.py deleted file mode 100644 index 1969434..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_portforward.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedPortForward = ServiceMaker( - "Twisted Port-Forwarding", - "twisted.tap.portforward", - "A simple port-forwarder.", - "portforward") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_qtstub.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_qtstub.py deleted file mode 100644 index ddf8843..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_qtstub.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Backwards-compatibility plugin for the Qt reactor. - -This provides a Qt reactor plugin named C{qt} which emits a deprecation -warning and a pointer to the separately distributed Qt reactor plugins. -""" - -import warnings - -from twisted.application.reactors import Reactor, NoSuchReactor - -wikiURL = 'http://twistedmatrix.com/trac/wiki/QTReactor' -errorMessage = ('qtreactor is no longer a part of Twisted due to licensing ' - 'issues. Please see %s for details.' % (wikiURL,)) - -class QTStub(Reactor): - """ - Reactor plugin which emits a deprecation warning on the successful - installation of its reactor or a pointer to further information if an - ImportError occurs while attempting to install it. - """ - def __init__(self): - super(QTStub, self).__init__( - 'qt', 'qtreactor', 'QT integration reactor') - - - def install(self): - """ - Install the Qt reactor with a deprecation warning or try to point - the user to further information if it cannot be installed. - """ - try: - super(QTStub, self).install() - except (ValueError, ImportError): - raise NoSuchReactor(errorMessage) - else: - warnings.warn( - "Please use -r qt3 to import qtreactor", - category=DeprecationWarning) - - -qt = QTStub() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_reactors.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_reactors.py deleted file mode 100644 index 8562aa9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_reactors.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.reactors import Reactor - -default = Reactor( - 'default', 'twisted.internet.default', - 'A reasonable default: poll(2) if available, otherwise select(2).') - -select = Reactor( - 'select', 'twisted.internet.selectreactor', 'select(2)-based reactor.') -wx = Reactor( - 'wx', 'twisted.internet.wxreactor', 'wxPython integration reactor.') -gi = Reactor( - 'gi', 'twisted.internet.gireactor', 'GObject Introspection integration reactor.') -gtk3 = Reactor( - 'gtk3', 'twisted.internet.gtk3reactor', 'Gtk3 integration reactor.') -gtk = Reactor( - 'gtk', 'twisted.internet.gtkreactor', 'Gtk1 integration reactor.') -gtk2 = Reactor( - 'gtk2', 'twisted.internet.gtk2reactor', 'Gtk2 integration reactor.') -glib2 = Reactor( - 'glib2', 'twisted.internet.glib2reactor', - 'GLib2 event-loop integration reactor.') -glade = Reactor( - 'debug-gui', 'twisted.manhole.gladereactor', - 'Semi-functional debugging/introspection reactor.') -win32er = Reactor( - 'win32', 'twisted.internet.win32eventreactor', - 'Win32 WaitForMultipleObjects-based reactor.') -poll = Reactor( - 'poll', 'twisted.internet.pollreactor', 'poll(2)-based reactor.') -epoll = Reactor( - 'epoll', 'twisted.internet.epollreactor', 'epoll(4)-based reactor.') -cf = Reactor( - 'cf' , 'twisted.internet.cfreactor', - 'CoreFoundation integration reactor.') -kqueue = Reactor( - 'kqueue', 'twisted.internet.kqreactor', 'kqueue(2)-based reactor.') -iocp = Reactor( - 'iocp', 'twisted.internet.iocpreactor', - 'Win32 IO Completion Ports-based reactor.') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_runner.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_runner.py deleted file mode 100644 index dc63028..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_runner.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedProcmon = ServiceMaker( - "Twisted Process Monitor", - "twisted.runner.procmontap", - ("A process watchdog / supervisor"), - "procmon") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_socks.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_socks.py deleted file mode 100644 index 5a94f87..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_socks.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedSOCKS = ServiceMaker( - "Twisted SOCKS", - "twisted.tap.socks", - "A SOCKSv4 proxy service.", - "socks") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_telnet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_telnet.py deleted file mode 100644 index 4cb1f98..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_telnet.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedTelnet = ServiceMaker( - "Twisted Telnet Shell Server", - "twisted.tap.telnet", - "A simple, telnet-based remote debugging service.", - "telnet") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_trial.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_trial.py deleted file mode 100644 index debc8af..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_trial.py +++ /dev/null @@ -1,59 +0,0 @@ - -from zope.interface import implements - -from twisted.trial.itrial import IReporter -from twisted.plugin import IPlugin - -class _Reporter(object): - implements(IPlugin, IReporter) - - def __init__(self, name, module, description, longOpt, shortOpt, klass): - self.name = name - self.module = module - self.description = description - self.longOpt = longOpt - self.shortOpt = shortOpt - self.klass = klass - - -Tree = _Reporter("Tree Reporter", - "twisted.trial.reporter", - description="verbose color output (default reporter)", - longOpt="verbose", - shortOpt="v", - klass="TreeReporter") - -BlackAndWhite = _Reporter("Black-And-White Reporter", - "twisted.trial.reporter", - description="Colorless verbose output", - longOpt="bwverbose", - shortOpt="o", - klass="VerboseTextReporter") - -Minimal = _Reporter("Minimal Reporter", - "twisted.trial.reporter", - description="minimal summary output", - longOpt="summary", - shortOpt="s", - klass="MinimalReporter") - -Classic = _Reporter("Classic Reporter", - "twisted.trial.reporter", - description="terse text output", - longOpt="text", - shortOpt="t", - klass="TextReporter") - -Timing = _Reporter("Timing Reporter", - "twisted.trial.reporter", - description="Timing output", - longOpt="timing", - shortOpt=None, - klass="TimingTextReporter") - -Subunit = _Reporter("Subunit Reporter", - "twisted.trial.reporter", - description="subunit output", - longOpt="subunit", - shortOpt=None, - klass="SubunitReporter") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_web.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_web.py deleted file mode 100644 index c7655a6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_web.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedWeb = ServiceMaker( - "Twisted Web", - "twisted.web.tap", - ("A general-purpose web server which can serve from a " - "filesystem or application resource."), - "web") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_words.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_words.py deleted file mode 100644 index 6f14aef..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/plugins/twisted_words.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from zope.interface import classProvides - -from twisted.plugin import IPlugin - -from twisted.application.service import ServiceMaker -from twisted.words import iwords - - -NewTwistedWords = ServiceMaker( - "New Twisted Words", - "twisted.words.tap", - "A modern words server", - "words") - -TwistedXMPPRouter = ServiceMaker( - "XMPP Router", - "twisted.words.xmpproutertap", - "An XMPP Router server", - "xmpp-router") - -class RelayChatInterface(object): - classProvides(IPlugin, iwords.IProtocolPlugin) - - name = 'irc' - - def getFactory(cls, realm, portal): - from twisted.words import service - return service.IRCFactory(realm, portal) - getFactory = classmethod(getFactory) - -class PBChatInterface(object): - classProvides(IPlugin, iwords.IProtocolPlugin) - - name = 'pb' - - def getFactory(cls, realm, portal): - from twisted.spread import pb - return pb.PBServerFactory(portal, True) - getFactory = classmethod(getFactory) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/__init__.py deleted file mode 100644 index a855f41..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- test-case-name: twisted.positioning.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Twisted Positioning: Framework for applications that make use of positioning. - -@since: 14.0 -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/_sentence.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/_sentence.py deleted file mode 100644 index 03563c8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/_sentence.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Generic sentence handling tools: hopefully reusable. -""" -class _BaseSentence(object): - """ - A base sentence class for a particular protocol. - - Using this base class, specific sentence classes can almost automatically - be created for a particular protocol (except for the documentation of - course) if that protocol implements the L{IPositioningSentenceProducer} - interface. To do this, fill the ALLOWED_ATTRIBUTES class attribute using - the C{getSentenceAttributes} class method of the producer:: - - class FooSentence(BaseSentence): - \"\"\" - A sentence for integalactic transmodulator sentences. - - @ivar transmogrificationConstant: The value used in the - transmogrifier while producing this sentence, corrected for - gravitational fields. - @type transmogrificationConstant: C{Tummy} - \"\"\" - ALLOWED_ATTRIBUTES = FooProtocol.getSentenceAttributes() - - @ivar presentAttribues: An iterable containing the names of the - attributes that are present in this sentence. - @type presentAttributes: iterable of C{str} - - @cvar ALLOWED_ATTRIBUTES: A set of attributes that are allowed in this - sentence. - @type ALLOWED_ATTRIBUTES: C{set} of C{str} - """ - ALLOWED_ATTRIBUTES = set() - - - def __init__(self, sentenceData): - """ - Initializes a sentence with parsed sentence data. - - @param sentenceData: The parsed sentence data. - @type sentenceData: C{dict} (C{str} -> C{str} or C{NoneType}) - """ - self._sentenceData = sentenceData - - - @property - def presentAttributes(self): - """ - An iterable containing the names of the attributes that are present in - this sentence. - - @return: The iterable of names of present attributes. - @rtype: iterable of C{str} - """ - return iter(self._sentenceData) - - - def __getattr__(self, name): - """ - Gets an attribute of this sentence. - """ - if name in self.ALLOWED_ATTRIBUTES: - return self._sentenceData.get(name, None) - else: - className = self.__class__.__name__ - msg = "%s sentences have no %s attributes" % (className, name) - raise AttributeError(msg) - - - def __repr__(self): - """ - Returns a textual representation of this sentence. - - @return: A textual representation of this sentence. - @rtype: C{str} - """ - items = self._sentenceData.items() - data = ["%s: %s" % (k, v) for k, v in sorted(items) if k != "type"] - dataRepr = ", ".join(data) - - typeRepr = self._sentenceData.get("type") or "unknown type" - className = self.__class__.__name__ - - return "<%s (%s) {%s}>" % (className, typeRepr, dataRepr) - - - -class _PositioningSentenceProducerMixin(object): - """ - A mixin for certain protocols that produce positioning sentences. - - This mixin helps protocols that store the layout of sentences that they - consume in a C{_SENTENCE_CONTENTS} class variable provide all sentence - attributes that can ever occur. It does this by providing a class method, - C{getSentenceAttributes}, which iterates over all sentence types and - collects the possible sentence attributes. - """ - @classmethod - def getSentenceAttributes(cls): - """ - Returns a set of all attributes that might be found in the sentences - produced by this protocol. - - This is basically a set of all the attributes of all the sentences that - this protocol can produce. - - @return: The set of all possible sentence attribute names. - @rtype: C{set} of C{str} - """ - attributes = set(["type"]) - for attributeList in cls._SENTENCE_CONTENTS.values(): - for attribute in attributeList: - if attribute is None: - continue - attributes.add(attribute) - - return attributes diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/base.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/base.py deleted file mode 100644 index 62e8781..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/base.py +++ /dev/null @@ -1,929 +0,0 @@ -# -*- test-case-name: twisted.positioning.test.test_base,twisted.positioning.test.test_sentence -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Generic positioning base classes. - -@since: 14.0 -""" -from functools import partial -from operator import attrgetter -from zope.interface import implementer -from twisted.python.constants import Names, NamedConstant -from twisted.python.util import FancyEqMixin -from twisted.positioning import ipositioning - - -MPS_PER_KNOT = 0.5144444444444444 -MPS_PER_KPH = 0.27777777777777777 -METERS_PER_FOOT = 0.3048 - - - -class Angles(Names): - """ - The types of angles. - """ - LATITUDE = NamedConstant() - LONGITUDE = NamedConstant() - HEADING = NamedConstant() - VARIATION = NamedConstant() - - - -class Directions(Names): - """ - The four cardinal directions (north, east, south, west). - """ - NORTH = NamedConstant() - EAST = NamedConstant() - SOUTH = NamedConstant() - WEST = NamedConstant() - - - -@implementer(ipositioning.IPositioningReceiver) -class BasePositioningReceiver(object): - """ - A base positioning receiver. - - This class would be a good base class for building positioning - receivers. It implements the interface (so you don't have to) with stub - methods. - - People who want to implement positioning receivers should subclass this - class and override the specific callbacks they want to handle. - """ - def timeReceived(self, time): - """ - Implements L{IPositioningReceiver.timeReceived} stub. - """ - - - def headingReceived(self, heading): - """ - Implements L{IPositioningReceiver.headingReceived} stub. - """ - - - def speedReceived(self, speed): - """ - Implements L{IPositioningReceiver.speedReceived} stub. - """ - - - def climbReceived(self, climb): - """ - Implements L{IPositioningReceiver.climbReceived} stub. - """ - - - def positionReceived(self, latitude, longitude): - """ - Implements L{IPositioningReceiver.positionReceived} stub. - """ - - - def positionErrorReceived(self, positionError): - """ - Implements L{IPositioningReceiver.positioningErrorReceived} stub. - """ - - - def altitudeReceived(self, altitude): - """ - Implements L{IPositioningReceiver.altitudeReceived} stub. - """ - - - def beaconInformationReceived(self, beaconInformation): - """ - Implements L{IPositioningReceiver.beaconInformationReceived} stub. - """ - - - -class InvalidSentence(Exception): - """ - An exception raised when a sentence is invalid. - """ - - - -class InvalidChecksum(Exception): - """ - An exception raised when the checksum of a sentence is invalid. - """ - - - -class Angle(object, FancyEqMixin): - """ - An object representing an angle. - - @cvar _RANGE_EXPRESSIONS: A collection of expressions for the allowable - range for the angular value of a particular coordinate value. - @type _RANGE_EXPRESSIONS: C{dict} of L{Angles} constants to callables - @cvar _ANGLE_TYPE_NAMES: English names for angle types. - @type _ANGLE_TYPE_NAMES: C{dict} of L{Angles} constants to C{str} - """ - _RANGE_EXPRESSIONS = { - Angles.LATITUDE: lambda latitude: -90.0 < latitude < 90.0, - Angles.LONGITUDE: lambda longitude: -180.0 < longitude < 180.0, - Angles.HEADING: lambda heading: 0 <= heading < 360, - Angles.VARIATION: lambda variation: -180 < variation <= 180, - } - - - _ANGLE_TYPE_NAMES = { - Angles.LATITUDE: "Latitude", - Angles.LONGITUDE: "Longitude", - Angles.VARIATION: "Variation", - Angles.HEADING: "Heading", - } - - - compareAttributes = 'angleType', 'inDecimalDegrees' - - - def __init__(self, angle=None, angleType=None): - """ - Initializes an angle. - - @param angle: The value of the angle in decimal degrees. (C{None} if - unknown). - @type angle: C{float} or C{NoneType} - @param angleType: A symbolic constant describing the angle type. Should - be one of L{AngleTypes} or {None} if unknown. - - @raises ValueError: If the angle type is not the default argument, - but it is an unknown type (not in C{Angle._RANGE_EXPRESSIONS}), - or it is a known type but the supplied value was out of the - allowable range for said type. - """ - if angleType is not None and angleType not in self._RANGE_EXPRESSIONS: - raise ValueError("Unknown angle type") - - if angle is not None and angleType is not None: - rangeExpression = self._RANGE_EXPRESSIONS[angleType] - if not rangeExpression(angle): - template = "Angle {0} not in allowed range for type {1}" - raise ValueError(template.format(angle, angleType)) - - self.angleType = angleType - self._angle = angle - - - @property - def inDecimalDegrees(self): - """ - The value of this angle in decimal degrees. This value is immutable. - - @return: This angle expressed in decimal degrees, or C{None} if the - angle is unknown. - @rtype: C{float} (or C{NoneType}) - """ - return self._angle - - - @property - def inDegreesMinutesSeconds(self): - """ - The value of this angle as a degrees, minutes, seconds tuple. This - value is immutable. - - @return: This angle expressed in degrees, minutes, seconds. C{None} if - the angle is unknown. - @rtype: 3-C{tuple} of C{int} (or C{NoneType}) - """ - if self._angle is None: - return None - - degrees = abs(int(self._angle)) - fractionalDegrees = abs(self._angle - int(self._angle)) - decimalMinutes = 60 * fractionalDegrees - - minutes = int(decimalMinutes) - fractionalMinutes = decimalMinutes - int(decimalMinutes) - decimalSeconds = 60 * fractionalMinutes - - return degrees, minutes, int(decimalSeconds) - - - def setSign(self, sign): - """ - Sets the sign of this angle. - - @param sign: The new sign. C{1} for positive and C{-1} for negative - signs, respectively. - @type sign: C{int} - - @raise ValueError: If the C{sign} parameter is not C{-1} or C{1}. - """ - if sign not in (-1, 1): - raise ValueError("bad sign (got %s, expected -1 or 1)" % sign) - - self._angle = sign * abs(self._angle) - - - def __float__(self): - """ - Returns this angle as a float. - - @return: The float value of this angle, expressed in degrees. - @rtype: C{float} - """ - return self._angle - - - def __repr__(self): - """ - Returns a string representation of this angle. - - @return: The string representation. - @rtype: C{str} - """ - return "<{s._angleTypeNameRepr} ({s._angleValueRepr})>".format(s=self) - - - @property - def _angleValueRepr(self): - """ - Returns a string representation of the angular value of this angle. - - This is a helper function for the actual C{__repr__}. - - @return: The string representation. - @rtype: C{str} - """ - if self.inDecimalDegrees is not None: - return "%s degrees" % round(self.inDecimalDegrees, 2) - else: - return "unknown value" - - - @property - def _angleTypeNameRepr(self): - """ - Returns a string representation of the type of this angle. - - This is a helper function for the actual C{__repr__}. - - @return: The string representation. - @rtype: C{str} - """ - try: - return self._ANGLE_TYPE_NAMES[self.angleType] - except KeyError: - return "Angle of unknown type" - - - -class Heading(Angle): - """ - The heading of a mobile object. - - @ivar variation: The (optional) magnetic variation. - The sign of the variation is positive for variations towards the east - (clockwise from north), and negative for variations towards the west - (counterclockwise from north). - If the variation is unknown or not applicable, this is C{None}. - @type variation: C{Angle} or C{NoneType}. - @ivar correctedHeading: The heading, corrected for variation. If the - variation is unknown (C{None}), is None. This attribute is read-only - (its value is determined by the angle and variation attributes). The - value is coerced to being between 0 (inclusive) and 360 (exclusive). - """ - def __init__(self, angle=None, variation=None): - """ - Initializes a angle with an optional variation. - """ - Angle.__init__(self, angle, Angles.HEADING) - self.variation = variation - - - @classmethod - def fromFloats(cls, angleValue=None, variationValue=None): - """ - Constructs a Heading from the float values of the angle and variation. - - @param angleValue: The angle value of this heading. - @type angleValue: C{float} - @param variationValue: The value of the variation of this heading. - @type variationValue: C{float} - @return A C{Heading } with the given values. - """ - variation = Angle(variationValue, Angles.VARIATION) - return cls(angleValue, variation) - - - @property - def correctedHeading(self): - """ - Corrects the heading by the given variation. This is sometimes known as - the true heading. - - @return: The heading, corrected by the variation. If the variation or - the angle are unknown, returns C{None}. - @rtype: C{float} or C{NoneType} - """ - if self._angle is None or self.variation is None: - return None - - angle = (self.inDecimalDegrees - self.variation.inDecimalDegrees) % 360 - return Angle(angle, Angles.HEADING) - - - def setSign(self, sign): - """ - Sets the sign of the variation of this heading. - - @param sign: The new sign. C{1} for positive and C{-1} for negative - signs, respectively. - @type sign: C{int} - - @raise ValueError: If the C{sign} parameter is not C{-1} or C{1}. - """ - if self.variation.inDecimalDegrees is None: - raise ValueError("can't set the sign of an unknown variation") - - self.variation.setSign(sign) - - - compareAttributes = list(Angle.compareAttributes) + ["variation"] - - - def __repr__(self): - """ - Returns a string representation of this angle. - - @return: The string representation. - @rtype: C{str} - """ - if self.variation is None: - variationRepr = "unknown variation" - else: - variationRepr = repr(self.variation) - - return "<%s (%s, %s)>" % ( - self._angleTypeNameRepr, self._angleValueRepr, variationRepr) - - - -class Coordinate(Angle): - """ - A coordinate. - - @ivar angle: The value of the coordinate in decimal degrees, with the usual - rules for sign (northern and eastern hemispheres are positive, southern - and western hemispheres are negative). - @type angle: C{float} - """ - def __init__(self, angle, coordinateType=None): - """ - Initializes a coordinate. - - @param angle: The angle of this coordinate in decimal degrees. The - hemisphere is determined by the sign (north and east are positive). - If this coordinate describes a latitude, this value must be within - -90.0 and +90.0 (exclusive). If this value describes a longitude, - this value must be within -180.0 and +180.0 (exclusive). - @type angle: C{float} - @param coordinateType: The coordinate type. One of L{Angles.LATITUDE}, - L{Angles.LONGITUDE} or C{None} if unknown. - """ - if coordinateType not in [Angles.LATITUDE, Angles.LONGITUDE, None]: - raise ValueError("coordinateType must be one of Angles.LATITUDE, " - "Angles.LONGITUDE or None, was {!r}" - .format(coordinateType)) - - Angle.__init__(self, angle, coordinateType) - - - @property - def hemisphere(self): - """ - Gets the hemisphere of this coordinate. - - @return: A symbolic constant representing a hemisphere (one of - L{Angles}) - """ - - if self.angleType is Angles.LATITUDE: - if self.inDecimalDegrees < 0: - return Directions.SOUTH - else: - return Directions.NORTH - elif self.angleType is Angles.LONGITUDE: - if self.inDecimalDegrees < 0: - return Directions.WEST - else: - return Directions.EAST - else: - raise ValueError("unknown coordinate type (cant find hemisphere)") - - - -class Altitude(object, FancyEqMixin): - """ - An altitude. - - @ivar inMeters: The altitude represented by this object, in meters. This - attribute is read-only. - @type inMeters: C{float} - - @ivar inFeet: As above, but expressed in feet. - @type inFeet: C{float} - """ - compareAttributes = 'inMeters', - - def __init__(self, altitude): - """ - Initializes an altitude. - - @param altitude: The altitude in meters. - @type altitude: C{float} - """ - self._altitude = altitude - - - @property - def inFeet(self): - """ - Gets the altitude this object represents, in feet. - - @return: The altitude, expressed in feet. - @rtype: C{float} - """ - return self._altitude / METERS_PER_FOOT - - - @property - def inMeters(self): - """ - Returns the altitude this object represents, in meters. - - @return: The altitude, expressed in feet. - @rtype: C{float} - """ - return self._altitude - - - def __float__(self): - """ - Returns the altitude represented by this object expressed in meters. - - @return: The altitude represented by this object, expressed in meters. - @rtype: C{float} - """ - return self._altitude - - - def __repr__(self): - """ - Returns a string representation of this altitude. - - @return: The string representation. - @rtype: C{str} - """ - return "" % (self._altitude,) - - - -class _BaseSpeed(object, FancyEqMixin): - """ - An object representing the abstract concept of the speed (rate of - movement) of a mobile object. - - This primarily has behavior for converting between units and comparison. - """ - compareAttributes = 'inMetersPerSecond', - - def __init__(self, speed): - """ - Initializes a speed. - - @param speed: The speed that this object represents, expressed in - meters per second. - @type speed: C{float} - - @raises ValueError: Raised if value was invalid for this particular - kind of speed. Only happens in subclasses. - """ - self._speed = speed - - - @property - def inMetersPerSecond(self): - """ - The speed that this object represents, expressed in meters per second. - This attribute is immutable. - - @return: The speed this object represents, in meters per second. - @rtype: C{float} - """ - return self._speed - - - @property - def inKnots(self): - """ - Returns the speed represented by this object, expressed in knots. This - attribute is immutable. - - @return: The speed this object represents, in knots. - @rtype: C{float} - """ - return self._speed / MPS_PER_KNOT - - - def __float__(self): - """ - Returns the speed represented by this object expressed in meters per - second. - - @return: The speed represented by this object, expressed in meters per - second. - @rtype: C{float} - """ - return self._speed - - - def __repr__(self): - """ - Returns a string representation of this speed object. - - @return: The string representation. - @rtype: C{str} - """ - speedValue = round(self.inMetersPerSecond, 2) - return "<%s (%s m/s)>" % (self.__class__.__name__, speedValue) - - - -class Speed(_BaseSpeed): - """ - The speed (rate of movement) of a mobile object. - """ - def __init__(self, speed): - """ - Initializes a L{Speed} object. - - @param speed: The speed that this object represents, expressed in - meters per second. - @type speed: C{float} - - @raises ValueError: Raised if C{speed} is negative. - """ - if speed < 0: - raise ValueError("negative speed: %r" % (speed,)) - - _BaseSpeed.__init__(self, speed) - - - -class Climb(_BaseSpeed): - """ - The climb ("vertical speed") of an object. - """ - def __init__(self, climb): - """ - Initializes a L{Climb} object. - - @param climb: The climb that this object represents, expressed in - meters per second. - @type climb: C{float} - """ - _BaseSpeed.__init__(self, climb) - - - -class PositionError(object, FancyEqMixin): - """ - Position error information. - - @cvar _ALLOWABLE_THRESHOLD: The maximum allowable difference between PDOP - and the geometric mean of VDOP and HDOP. That difference is supposed - to be zero, but can be non-zero because of rounding error and limited - reporting precision. You should never have to change this value. - @type _ALLOWABLE_THRESHOLD: C{float} - @cvar _DOP_EXPRESSIONS: A mapping of DOP types (C[hvp]dop) to a list of - callables that take self and return that DOP type, or raise - C{TypeError}. This allows a DOP value to either be returned directly - if it's know, or computed from other DOP types if it isn't. - @type _DOP_EXPRESSIONS: C{dict} of C{str} to callables - @ivar pdop: The position dilution of precision. C{None} if unknown. - @type pdop: C{float} or C{NoneType} - @ivar hdop: The horizontal dilution of precision. C{None} if unknown. - @type hdop: C{float} or C{NoneType} - @ivar vdop: The vertical dilution of precision. C{None} if unknown. - @type vdop: C{float} or C{NoneType} - """ - compareAttributes = 'pdop', 'hdop', 'vdop' - - def __init__(self, pdop=None, hdop=None, vdop=None, testInvariant=False): - """ - Initializes a positioning error object. - - @param pdop: The position dilution of precision. C{None} if unknown. - @type pdop: C{float} or C{NoneType} - @param hdop: The horizontal dilution of precision. C{None} if unknown. - @type hdop: C{float} or C{NoneType} - @param vdop: The vertical dilution of precision. C{None} if unknown. - @type vdop: C{float} or C{NoneType} - @param testInvariant: Flag to test if the DOP invariant is valid or - not. If C{True}, the invariant (PDOP = (HDOP**2 + VDOP**2)*.5) is - checked at every mutation. By default, this is false, because the - vast majority of DOP-providing devices ignore this invariant. - @type testInvariant: c{bool} - """ - self._pdop = pdop - self._hdop = hdop - self._vdop = vdop - - self._testInvariant = testInvariant - self._testDilutionOfPositionInvariant() - - - _ALLOWABLE_TRESHOLD = 0.01 - - - def _testDilutionOfPositionInvariant(self): - """ - Tests if this positioning error object satisfies the dilution of - position invariant (PDOP = (HDOP**2 + VDOP**2)*.5), unless the - C{self._testInvariant} instance variable is C{False}. - - @return: C{None} if the invariant was not satisfied or not tested. - @raises ValueError: Raised if the invariant was tested but not - satisfied. - """ - if not self._testInvariant: - return - - for x in (self.pdop, self.hdop, self.vdop): - if x is None: - return - - delta = abs(self.pdop - (self.hdop**2 + self.vdop**2)**.5) - if delta > self._ALLOWABLE_TRESHOLD: - raise ValueError("invalid combination of dilutions of precision: " - "position: %s, horizontal: %s, vertical: %s" - % (self.pdop, self.hdop, self.vdop)) - - - _DOP_EXPRESSIONS = { - 'pdop': [ - lambda self: float(self._pdop), - lambda self: (self._hdop**2 + self._vdop**2)**.5, - ], - - 'hdop': [ - lambda self: float(self._hdop), - lambda self: (self._pdop**2 - self._vdop**2)**.5, - ], - - 'vdop': [ - lambda self: float(self._vdop), - lambda self: (self._pdop**2 - self._hdop**2)**.5, - ], - } - - - def _getDOP(self, dopType): - """ - Gets a particular dilution of position value. - - @param dopType: The type of dilution of position to get. One of - ('pdop', 'hdop', 'vdop'). - @type dopType: C{str} - @return: The DOP if it is known, C{None} otherwise. - @rtype: C{float} or C{NoneType} - """ - for dopExpression in self._DOP_EXPRESSIONS[dopType]: - try: - return dopExpression(self) - except TypeError: - continue - - - def _setDOP(self, dopType, value): - """ - Sets a particular dilution of position value. - - @param dopType: The type of dilution of position to set. One of - ('pdop', 'hdop', 'vdop'). - @type dopType: C{str} - - @param value: The value to set the dilution of position type to. - @type value: C{float} - - If this position error tests dilution of precision invariants, - it will be checked. If the invariant is not satisfied, the - assignment will be undone and C{ValueError} is raised. - """ - attributeName = "_" + dopType - - oldValue = getattr(self, attributeName) - setattr(self, attributeName, float(value)) - - try: - self._testDilutionOfPositionInvariant() - except ValueError: - setattr(self, attributeName, oldValue) - raise - - - pdop = property(fget=lambda self: self._getDOP('pdop'), - fset=lambda self, value: self._setDOP('pdop', value)) - - - hdop = property(fget=lambda self: self._getDOP('hdop'), - fset=lambda self, value: self._setDOP('hdop', value)) - - - vdop = property(fget=lambda self: self._getDOP('vdop'), - fset=lambda self, value: self._setDOP('vdop', value)) - - - _REPR_TEMPLATE = "" - - - def __repr__(self): - """ - Returns a string representation of positioning information object. - - @return: The string representation. - @rtype: C{str} - """ - return self._REPR_TEMPLATE % (self.pdop, self.hdop, self.vdop) - - - -class BeaconInformation(object): - """ - Information about positioning beacons (a generalized term for the reference - objects that help you determine your position, such as satellites or cell - towers). - - @ivar seenBeacons: A set of visible beacons. Note that visible beacons are not - necessarily used in acquiring a positioning fix. - @type seenBeacons: C{set} of L{IPositioningBeacon} - @ivar usedBeacons: An set of the beacons that were used in obtaining a - positioning fix. This only contains beacons that are actually used, not - beacons for which it is unknown if they are used or not. - @type usedBeacons: C{set} of L{IPositioningBeacon} - """ - def __init__(self, seenBeacons=()): - """ - Initializes a beacon information object. - - @param seenBeacons: A collection of beacons that are currently seen. - @type seenBeacons: iterable of L{IPositioningBeacon}s - """ - self.seenBeacons = set(seenBeacons) - self.usedBeacons = set() - - - def __repr__(self): - """ - Returns a string representation of this beacon information object. - - The beacons are sorted by their identifier. - - @return: The string representation. - @rtype: C{str} - """ - sortedBeacons = partial(sorted, key=attrgetter("identifier")) - - usedBeacons = sortedBeacons(self.usedBeacons) - unusedBeacons = sortedBeacons(self.seenBeacons - self.usedBeacons) - - template = ("") - - formatted = template.format(numUsed=len(self.usedBeacons), - usedBeacons=usedBeacons, - unusedBeacons=unusedBeacons) - - return formatted - - - -@implementer(ipositioning.IPositioningBeacon) -class PositioningBeacon(object): - """ - A positioning beacon. - - @ivar identifier: The unique identifier for this beacon. This is usually - an integer. For GPS, this is also known as the PRN. - @type identifier: Pretty much anything that can be used as a unique - identifier. Depends on the implementation. - """ - def __init__(self, identifier): - """ - Initializes a positioning beacon. - - @param identifier: The identifier for this beacon. - @type identifier: Can be pretty much anything (see ivar documentation). - """ - self.identifier = identifier - - - def __hash__(self): - """ - Returns the hash of the identifier for this beacon. - - @return: The hash of the identifier. (C{hash(self.identifier)}) - @rtype: C{int} - """ - return hash(self.identifier) - - - def __repr__(self): - """ - Returns a string representation of this beacon. - - @return: The string representation. - @rtype: C{str} - """ - return "".format(s=self) - - - -class Satellite(PositioningBeacon): - """ - A satellite. - - @ivar azimuth: The azimuth of the satellite. This is the heading (positive - angle relative to true north) where the satellite appears to be to the - device. - @ivar elevation: The (positive) angle above the horizon where this - satellite appears to be to the device. - @ivar signalToNoiseRatio: The signal to noise ratio of the signal coming - from this satellite. - """ - def __init__(self, - identifier, - azimuth=None, - elevation=None, - signalToNoiseRatio=None): - """ - Initializes a satellite object. - - @param identifier: The PRN (unique identifier) of this satellite. - @type identifier: C{int} - @param azimuth: The azimuth of the satellite (see instance variable - documentation). - @type azimuth: C{float} - @param elevation: The elevation of the satellite (see instance variable - documentation). - @type elevation: C{float} - @param signalToNoiseRatio: The signal to noise ratio of the connection - to this satellite (see instance variable documentation). - @type signalToNoiseRatio: C{float} - """ - PositioningBeacon.__init__(self, int(identifier)) - - self.azimuth = azimuth - self.elevation = elevation - self.signalToNoiseRatio = signalToNoiseRatio - - - def __repr__(self): - """ - Returns a string representation of this Satellite. - - @return: The string representation. - @rtype: C{str} - """ - template = ("") - - return template.format(s=self) - - - -__all__ = [ - 'Altitude', - 'Angle', - 'Angles', - 'BasePositioningReceiver', - 'BeaconInformation', - 'Climb', - 'Coordinate', - 'Directions', - 'Heading', - 'InvalidChecksum', - 'InvalidSentence', - 'METERS_PER_FOOT', - 'MPS_PER_KNOT', - 'MPS_PER_KPH', - 'PositionError', - 'PositioningBeacon', - 'Satellite', - 'Speed' -] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/ipositioning.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/ipositioning.py deleted file mode 100644 index 2c4e661..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/ipositioning.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Positioning interfaces. - -@since: 14.0 -""" -from zope.interface import Attribute, Interface - - -class IPositioningReceiver(Interface): - """ - An interface for positioning providers. - """ - def positionReceived(latitude, longitude): - """ - Method called when a position is received. - - @param latitude: The latitude of the received position. - @type latitude: L{twisted.positioning.base.Coordinate} - @param longitude: The longitude of the received position. - @type longitude: L{twisted.positioning.base.Coordinate} - """ - - - def positionErrorReceived(positionError): - """ - Method called when position error is received. - - @param positioningError: The position error. - @type positioningError: L{twisted.positioning.base.PositionError} - """ - - def timeReceived(time): - """ - Method called when time and date information arrives. - - @param time: The date and time (expressed in UTC unless otherwise - specified). - @type time: L{datetime.datetime} - """ - - - def headingReceived(heading): - """ - Method called when a true heading is received. - - @param heading: The heading. - @type heading: L{twisted.positioning.base.Heading} - """ - - - def altitudeReceived(altitude): - """ - Method called when an altitude is received. - - @param altitude: The altitude. - @type altitude: L{twisted.positioning.base.Altitude} - """ - - - def speedReceived(speed): - """ - Method called when the speed is received. - - @param speed: The speed of a mobile object. - @type speed: L{twisted.positioning.base.Speed} - """ - - - def climbReceived(climb): - """ - Method called when the climb is received. - - @param climb: The climb of the mobile object. - @type climb: L{twisted.positioning.base.Climb} - """ - - def beaconInformationReceived(beaconInformation): - """ - Method called when positioning beacon information is received. - - @param beaconInformation: The beacon information. - @type beaconInformation: L{twisted.positioning.base.BeaconInformation} - """ - - - -class IPositioningBeacon(Interface): - """ - A positioning beacon. - """ - identifier = Attribute( - """ - A unique identifier for this beacon. The type is dependant on the - implementation, but must be immutable. - """) - - - -class INMEAReceiver(Interface): - """ - An object that can receive NMEA data. - """ - def sentenceReceived(sentence): - """ - Method called when a sentence is received. - - @param sentence: The received NMEA sentence. - @type L{twisted.positioning.nmea.NMEASentence} - """ - - - -__all__ = [ - "IPositioningReceiver", - "IPositioningBeacon", - "INMEAReceiver" -] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/nmea.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/nmea.py deleted file mode 100644 index cc3406f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/nmea.py +++ /dev/null @@ -1,980 +0,0 @@ -# -*- test-case-name: twisted.positioning.test.test_nmea -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Classes for working with NMEA 0183 sentence producing devices. -This standard is generally just called "NMEA", which is actually the -name of the body that produces the standard, not the standard itself.. - -For more information, read the blog post on NMEA by ESR (the gpsd -maintainer) at U{http://esr.ibiblio.org/?p=801}. Unfortunately, -official specifications on NMEA 0183 are only available at a cost. - -More information can be found on the Wikipedia page: -U{https://en.wikipedia.org/wiki/NMEA_0183}. - -The official standard may be obtained through the NMEA's website: -U{http://www.nmea.org/content/nmea_standards/nmea_0183_v_410.asp}. - -@since: 14.0 -""" -import itertools -import operator -import datetime -from zope.interface import implementer - -from twisted.positioning import base, ipositioning, _sentence -from twisted.positioning.base import Angles -from twisted.protocols.basic import LineReceiver -from twisted.python.constants import Values, ValueConstant -from twisted.python.compat import reduce - - -class GPGGAFixQualities(Values): - """ - The possible fix quality indications for GPGGA sentences. - - @cvar INVALID_FIX: The fix is invalid. - @cvar GPS_FIX: There is a fix, acquired using GPS. - @cvar DGPS_FIX: There is a fix, acquired using differential GPS (DGPS). - @cvar PPS_FIX: There is a fix, acquired using the precise positioning - service (PPS). - @cvar RTK_FIX: There is a fix, acquired using fixed real-time - kinematics. This means that there was a sufficient number of shared - satellites with the base station, usually yielding a resolution in - the centimeter range. This was added in NMEA 0183 version 3.0. This - is also called Carrier-Phase Enhancement or CPGPS, particularly when - used in combination with GPS. - @cvar FLOAT_RTK_FIX: There is a fix, acquired using floating real-time - kinematics. The same comments apply as for a fixed real-time - kinematics fix, except that there were insufficient shared satellites - to acquire it, so instead you got a slightly less good floating fix. - Typical resolution in the decimeter range. - @cvar DEAD_RECKONING: There is currently no more fix, but this data was - computed using a previous fix and some information about motion - (either from that fix or from other sources) using simple dead - reckoning. Not particularly reliable, but better-than-nonsense data. - @cvar MANUAL: There is no real fix from this device, but the location has - been manually entered, presumably with data obtained from some other - positioning method. - @cvar SIMULATED: There is no real fix, but instead it is being simulated. - """ - INVALID_FIX = "0" - GPS_FIX = "1" - DGPS_FIX = "2" - PPS_FIX = "3" - RTK_FIX = "4" - FLOAT_RTK_FIX = "5" - DEAD_RECKONING = "6" - MANUAL = "7" - SIMULATED = "8" - - - -class GPGLLGPRMCFixQualities(Values): - """ - The possible fix quality indications in GPGLL and GPRMC sentences. - - Unfortunately, these sentences only indicate whether data is good or void. - They provide no other information, such as what went wrong if the data is - void, or how good the data is if the data is not void. - - @cvar ACTIVE: The data is okay. - @cvar VOID: The data is void, and should not be used. - """ - ACTIVE = ValueConstant("A") - VOID = ValueConstant("V") - - - -class GPGSAFixTypes(Values): - """ - The possible fix types of a GPGSA sentence. - - @cvar GSA_NO_FIX: The sentence reports no fix at all. - @cvar GSA_2D_FIX: The sentence reports a 2D fix: position but no altitude. - @cvar GSA_3D_FIX: The sentence reports a 3D fix: position with altitude. - """ - GSA_NO_FIX = ValueConstant("1") - GSA_2D_FIX = ValueConstant("2") - GSA_3D_FIX = ValueConstant("3") - - - -def _split(sentence): - """ - Returns the split version of an NMEA sentence, minus header - and checksum. - - @param sentence: The NMEA sentence to split. - @type sentence: C{str} - - >>> _split("$GPGGA,spam,eggs*00") - ['GPGGA', 'spam', 'eggs'] - """ - if sentence[-3] == "*": # Sentence with checksum - return sentence[1:-3].split(',') - elif sentence[-1] == "*": # Sentence without checksum - return sentence[1:-1].split(',') - else: - raise base.InvalidSentence("malformed sentence %s" % (sentence,)) - - - -def _validateChecksum(sentence): - """ - Validates the checksum of an NMEA sentence. - - @param sentence: The NMEA sentence to check the checksum of. - @type sentence: C{str} - - @raise ValueError: If the sentence has an invalid checksum. - - Simply returns on sentences that either don't have a checksum, - or have a valid checksum. - """ - if sentence[-3] == '*': # Sentence has a checksum - reference, source = int(sentence[-2:], 16), sentence[1:-3] - computed = reduce(operator.xor, (ord(x) for x in source)) - if computed != reference: - raise base.InvalidChecksum("%02x != %02x" % (computed, reference)) - - - -class NMEAProtocol(LineReceiver, _sentence._PositioningSentenceProducerMixin): - """ - A protocol that parses and verifies the checksum of an NMEA sentence (in - string form, not L{NMEASentence}), and delegates to a receiver. - - It receives lines and verifies these lines are NMEA sentences. If - they are, verifies their checksum and unpacks them into their - components. It then wraps them in L{NMEASentence} objects and - calls the appropriate receiver method with them. - - @cvar _SENTENCE_CONTENTS: Has the field names in an NMEA sentence for each - sentence type (in order, obviously). - @type _SENTENCE_CONTENTS: C{dict} of bytestrings to C{list}s of C{str} - @param _receiver: A receiver for NMEAProtocol sentence objects. - @type _receiver: L{INMEAReceiver} - @param _sentenceCallback: A function that will be called with a new - L{NMEASentence} when it is created. Useful for massaging data from - particularly misbehaving NMEA receivers. - @type _sentenceCallback: unary callable - """ - def __init__(self, receiver, sentenceCallback=None): - """ - Initializes an NMEAProtocol. - - @param receiver: A receiver for NMEAProtocol sentence objects. - @type receiver: L{INMEAReceiver} - @param sentenceCallback: A function that will be called with a new - L{NMEASentence} when it is created. Useful for massaging data from - particularly misbehaving NMEA receivers. - @type sentenceCallback: unary callable - """ - self._receiver = receiver - self._sentenceCallback = sentenceCallback - - - def lineReceived(self, rawSentence): - """ - Parses the data from the sentence and validates the checksum. - - @param rawSentence: The NMEA positioning sentence. - @type rawSentence: C{str} - """ - sentence = rawSentence.strip() - - _validateChecksum(sentence) - splitSentence = _split(sentence) - - sentenceType, contents = splitSentence[0], splitSentence[1:] - - try: - keys = self._SENTENCE_CONTENTS[sentenceType] - except KeyError: - raise ValueError("unknown sentence type %s" % sentenceType) - - sentenceData = {"type": sentenceType} - for key, value in itertools.izip(keys, contents): - if key is not None and value != "": - sentenceData[key] = value - - sentence = NMEASentence(sentenceData) - - if self._sentenceCallback is not None: - self._sentenceCallback(sentence) - - self._receiver.sentenceReceived(sentence) - - - _SENTENCE_CONTENTS = { - 'GPGGA': [ - 'timestamp', - - 'latitudeFloat', - 'latitudeHemisphere', - 'longitudeFloat', - 'longitudeHemisphere', - - 'fixQuality', - 'numberOfSatellitesSeen', - 'horizontalDilutionOfPrecision', - - 'altitude', - 'altitudeUnits', - 'heightOfGeoidAboveWGS84', - 'heightOfGeoidAboveWGS84Units', - - # The next parts are DGPS information, currently unused. - None, # Time since last DGPS update - None, # DGPS reference source id - ], - - 'GPRMC': [ - 'timestamp', - - 'dataMode', - - 'latitudeFloat', - 'latitudeHemisphere', - 'longitudeFloat', - 'longitudeHemisphere', - - 'speedInKnots', - - 'trueHeading', - - 'datestamp', - - 'magneticVariation', - 'magneticVariationDirection', - ], - - 'GPGSV': [ - 'numberOfGSVSentences', - 'GSVSentenceIndex', - - 'numberOfSatellitesSeen', - - 'satellitePRN_0', - 'elevation_0', - 'azimuth_0', - 'signalToNoiseRatio_0', - - 'satellitePRN_1', - 'elevation_1', - 'azimuth_1', - 'signalToNoiseRatio_1', - - 'satellitePRN_2', - 'elevation_2', - 'azimuth_2', - 'signalToNoiseRatio_2', - - 'satellitePRN_3', - 'elevation_3', - 'azimuth_3', - 'signalToNoiseRatio_3', - ], - - 'GPGLL': [ - 'latitudeFloat', - 'latitudeHemisphere', - 'longitudeFloat', - 'longitudeHemisphere', - 'timestamp', - 'dataMode', - ], - - 'GPHDT': [ - 'trueHeading', - ], - - 'GPTRF': [ - 'datestamp', - 'timestamp', - - 'latitudeFloat', - 'latitudeHemisphere', - 'longitudeFloat', - 'longitudeHemisphere', - - 'elevation', - 'numberOfIterations', # Unused - 'numberOfDopplerIntervals', # Unused - 'updateDistanceInNauticalMiles', # Unused - 'satellitePRN', - ], - - 'GPGSA': [ - 'dataMode', - 'fixType', - - 'usedSatellitePRN_0', - 'usedSatellitePRN_1', - 'usedSatellitePRN_2', - 'usedSatellitePRN_3', - 'usedSatellitePRN_4', - 'usedSatellitePRN_5', - 'usedSatellitePRN_6', - 'usedSatellitePRN_7', - 'usedSatellitePRN_8', - 'usedSatellitePRN_9', - 'usedSatellitePRN_10', - 'usedSatellitePRN_11', - - 'positionDilutionOfPrecision', - 'horizontalDilutionOfPrecision', - 'verticalDilutionOfPrecision', - ] - } - - - -class NMEASentence(_sentence._BaseSentence): - """ - An object representing an NMEA sentence. - - The attributes of this objects are raw NMEA protocol data, which - are all ASCII bytestrings. - - This object contains all the raw NMEA protocol data in a single - sentence. Not all of these necessarily have to be present in the - sentence. Missing attributes are C{None} when accessed. - - @ivar type: The sentence type (C{"GPGGA"}, C{"GPGSV"}...). - @ivar numberOfGSVSentences: The total number of GSV sentences in a - sequence. - @ivar GSVSentenceIndex: The index of this GSV sentence in the GSV - sequence. - @ivar timestamp: A timestamp. (C{"123456"} -> 12:34:56Z) - @ivar datestamp: A datestamp. (C{"230394"} -> 23 Mar 1994) - @ivar latitudeFloat: Latitude value. (for example: C{"1234.567"} -> - 12 degrees, 34.567 minutes). - @ivar latitudeHemisphere: Latitudinal hemisphere (C{"N"} or C{"S"}). - @ivar longitudeFloat: Longitude value. See C{latitudeFloat} for an - example. - @ivar longitudeHemisphere: Longitudinal hemisphere (C{"E"} or C{"W"}). - @ivar altitude: The altitude above mean sea level. - @ivar altitudeUnits: Units in which altitude is expressed. (Always - C{"M"} for meters.) - @ivar heightOfGeoidAboveWGS84: The local height of the geoid above - the WGS84 ellipsoid model. - @ivar heightOfGeoidAboveWGS84Units: The units in which the height - above the geoid is expressed. (Always C{"M"} for meters.) - @ivar trueHeading: The true heading. - @ivar magneticVariation: The magnetic variation. - @ivar magneticVariationDirection: The direction of the magnetic - variation. One of C{"E"} or C{"W"}. - @ivar speedInKnots: The ground speed, expressed in knots. - @ivar fixQuality: The quality of the fix. - @type fixQuality: One of L{GPGGAFixQualities}. - @ivar dataMode: Signals if the data is usable or not. - @type dataMode: One of L{GPGLLGPRMCFixQualities}. - @ivar numberOfSatellitesSeen: The number of satellites seen by the - receiver. - @ivar numberOfSatellitesUsed: The number of satellites used in - computing the fix. - @ivar horizontalDilutionOfPrecision: The dilution of the precision of the - position on a plane tangential to the geoid. (HDOP) - @ivar verticalDilutionOfPrecision: As C{horizontalDilutionOfPrecision}, - but for a position on a plane perpendicular to the geoid. (VDOP) - @ivar positionDilutionOfPrecision: Euclidian norm of HDOP and VDOP. - @ivar satellitePRN: The unique identifcation number of a particular - satellite. Optionally suffixed with C{_N} if multiple satellites are - referenced in a sentence, where C{N in range(4)}. - @ivar elevation: The elevation of a satellite in decimal degrees. - Optionally suffixed with C{_N}, as with C{satellitePRN}. - @ivar azimuth: The azimuth of a satellite in decimal degrees. - Optionally suffixed with C{_N}, as with C{satellitePRN}. - @ivar signalToNoiseRatio: The SNR of a satellite signal, in decibels. - Optionally suffixed with C{_N}, as with C{satellitePRN}. - @ivar usedSatellitePRN_N: Where C{int(N) in range(12)}. The PRN - of a satellite used in computing the fix. - """ - ALLOWED_ATTRIBUTES = NMEAProtocol.getSentenceAttributes() - - def _isFirstGSVSentence(self): - """ - Tests if this current GSV sentence is the first one in a sequence. - - @return: C{True} if this is the first GSV sentence. - @rtype: C{bool} - """ - return self.GSVSentenceIndex == "1" - - - def _isLastGSVSentence(self): - """ - Tests if this current GSV sentence is the final one in a sequence. - - @return: C{True} if this is the last GSV sentence. - @rtype: C{bool} - """ - return self.GSVSentenceIndex == self.numberOfGSVSentences - - - -@implementer(ipositioning.INMEAReceiver) -class NMEAAdapter(object): - """ - An adapter from NMEAProtocol receivers to positioning receivers. - - @cvar _STATEFUL_UPDATE: Information on how to update partial information - in the sentence data or internal adapter state. For more information, - see C{_statefulUpdate}'s docstring. - @type _STATEFUL_UPDATE: See C{_statefulUpdate}'s docstring - @cvar _ACCEPTABLE_UNITS: A set of NMEA notations of units that are - already acceptable (metric), and therefore don't need to be converted. - @type _ACCEPTABLE_UNITS: C{frozenset} of bytestrings - @cvar _UNIT_CONVERTERS: Mapping of NMEA notations of units that are not - acceptable (not metric) to converters that take a quantity in that - unit and produce a metric quantity. - @type _UNIT_CONVERTERS: C{dict} of bytestrings to unary callables - @cvar _SPECIFIC_SENTENCE_FIXES: A mapping of sentece types to specific - fixes that are required to extract useful information from data from - those sentences. - @type _SPECIFIC_SENTENCE_FIXES: C{dict} of sentence types to callables - that take self and modify it in-place - @cvar _FIXERS: Set of unary callables that take an NMEAAdapter instance - and extract useful data from the sentence data, usually modifying the - adapter's sentence data in-place. - @type _FIXERS: C{dict} of native strings to unary callables - @ivar yearThreshold: The earliest possible year that data will be - interpreted as. For example, if this value is C{1990}, an NMEA - 0183 two-digit year of "96" will be interpreted as 1996, and - a two-digit year of "13" will be interpreted as 2013. - @type yearThreshold: L{int} - @ivar _state: The current internal state of the receiver. - @type _state: C{dict} - @ivar _sentenceData: The data present in the sentence currently being - processed. Starts empty, is filled as the sentence is parsed. - @type _sentenceData: C{dict} - @ivar _receiver: The positioning receiver that will receive parsed data. - @type _receiver: L{ipositioning.IPositioningReceiver} - """ - def __init__(self, receiver): - """ - Initializes a new NMEA adapter. - - @param receiver: The receiver for positioning sentences. - @type receiver: L{ipositioning.IPositioningReceiver} - """ - self._state = {} - self._sentenceData = {} - self._receiver = receiver - - - def _fixTimestamp(self): - """ - Turns the NMEAProtocol timestamp notation into a datetime.time object. - The time in this object is expressed as Zulu time. - """ - timestamp = self.currentSentence.timestamp.split('.')[0] - timeObject = datetime.datetime.strptime(timestamp, '%H%M%S').time() - self._sentenceData['_time'] = timeObject - - - yearThreshold = 1980 - - - def _fixDatestamp(self): - """ - Turns an NMEA datestamp format into a C{datetime.date} object. - - @raise ValueError: When the day or month value was invalid, e.g. 32nd - day, or 13th month, or 0th day or month. - """ - date = self.currentSentence.datestamp - day, month, year = map(int, [date[0:2], date[2:4], date[4:6]]) - - year += self.yearThreshold - (self.yearThreshold % 100) - if year < self.yearThreshold: - year += 100 - - self._sentenceData['_date'] = datetime.date(year, month, day) - - - def _fixCoordinateFloat(self, coordinateType): - """ - Turns the NMEAProtocol coordinate format into Python float. - - @param coordinateType: The coordinate type. - @type coordinateType: One of L{Angles.LATITUDE} or L{Angles.LONGITUDE}. - """ - if coordinateType is Angles.LATITUDE: - coordinateName = "latitude" - else: # coordinateType is Angles.LONGITUDE - coordinateName = "longitude" - nmeaCoordinate = getattr(self.currentSentence, coordinateName + "Float") - - left, right = nmeaCoordinate.split('.') - - degrees, minutes = int(left[:-2]), float("%s.%s" % (left[-2:], right)) - angle = degrees + minutes/60 - coordinate = base.Coordinate(angle, coordinateType) - self._sentenceData[coordinateName] = coordinate - - - def _fixHemisphereSign(self, coordinateType, sentenceDataKey=None): - """ - Fixes the sign for a hemisphere. - - This method must be called after the magnitude for the thing it - determines the sign of has been set. This is done by the following - functions: - - - C{self.FIXERS['magneticVariation']} - - C{self.FIXERS['latitudeFloat']} - - C{self.FIXERS['longitudeFloat']} - - @param coordinateType: Coordinate type. One of L{Angles.LATITUDE}, - L{Angles.LONGITUDE} or L{Angles.VARIATION}. - @param sentenceDataKey: The key name of the hemisphere sign being - fixed in the sentence data. If unspecified, C{coordinateType} is - used. - @type sentenceDataKey: C{str} (unless C{None}) - """ - sentenceDataKey = sentenceDataKey or coordinateType - sign = self._getHemisphereSign(coordinateType) - self._sentenceData[sentenceDataKey].setSign(sign) - - - def _getHemisphereSign(self, coordinateType): - """ - Returns the hemisphere sign for a given coordinate type. - - @param coordinateType: The coordinate type to find the hemisphere for. - @type coordinateType: L{Angles.LATITUDE}, L{Angles.LONGITUDE} or - L{Angles.VARIATION}. - @return: The sign of that hemisphere (-1 or 1). - @rtype: C{int} - """ - if coordinateType is Angles.LATITUDE: - hemisphereKey = "latitudeHemisphere" - elif coordinateType is Angles.LONGITUDE: - hemisphereKey = "longitudeHemisphere" - elif coordinateType is Angles.VARIATION: - hemisphereKey = 'magneticVariationDirection' - else: - raise ValueError("unknown coordinate type %s" % (coordinateType,)) - - hemisphere = getattr(self.currentSentence, hemisphereKey).upper() - - if hemisphere in "NE": - return 1 - elif hemisphere in "SW": - return -1 - else: - raise ValueError("bad hemisphere/direction: %s" % (hemisphere,)) - - - def _convert(self, key, converter): - """ - A simple conversion fix. - - @param key: The attribute name of the value to fix. - @type key: native string (Python identifier) - - @param converter: The function that converts the value. - @type converter: unary callable - """ - currentValue = getattr(self.currentSentence, key) - self._sentenceData[key] = converter(currentValue) - - - _STATEFUL_UPDATE = { - # sentenceKey: (stateKey, factory, attributeName, converter), - 'trueHeading': ('heading', base.Heading, '_angle', float), - 'magneticVariation': - ('heading', base.Heading, 'variation', - lambda angle: base.Angle(float(angle), Angles.VARIATION)), - - 'horizontalDilutionOfPrecision': - ('positionError', base.PositionError, 'hdop', float), - 'verticalDilutionOfPrecision': - ('positionError', base.PositionError, 'vdop', float), - 'positionDilutionOfPrecision': - ('positionError', base.PositionError, 'pdop', float), - - } - - - def _statefulUpdate(self, sentenceKey): - """ - Does a stateful update of a particular positioning attribute. - Specifically, this will mutate an object in the current sentence data. - - Using the C{sentenceKey}, this will get a tuple containing, in order, - the key name in the current state and sentence data, a factory for - new values, the attribute to update, and a converter from sentence - data (in NMEA notation) to something useful. - - If the sentence data doesn't have this data yet, it is grabbed from - the state. If that doesn't have anything useful yet either, the - factory is called to produce a new, empty object. Either way, the - object ends up in the sentence data. - - @param sentenceKey: The name of the key in the sentence attributes, - C{NMEAAdapter._STATEFUL_UPDATE} dictionary and the adapter state. - @type sentenceKey: C{str} - """ - key, factory, attr, converter = self._STATEFUL_UPDATE[sentenceKey] - - if key not in self._sentenceData: - try: - self._sentenceData[key] = self._state[key] - except KeyError: # state does not have this partial data yet - self._sentenceData[key] = factory() - - newValue = converter(getattr(self.currentSentence, sentenceKey)) - setattr(self._sentenceData[key], attr, newValue) - - - _ACCEPTABLE_UNITS = frozenset(['M']) - _UNIT_CONVERTERS = { - 'N': lambda inKnots: base.Speed(float(inKnots) * base.MPS_PER_KNOT), - 'K': lambda inKPH: base.Speed(float(inKPH) * base.MPS_PER_KPH), - } - - - def _fixUnits(self, unitKey=None, valueKey=None, sourceKey=None, - unit=None): - """ - Fixes the units of a certain value. If the units are already - acceptable (metric), does nothing. - - None of the keys are allowed to be the empty string. - - @param unit: The unit that is being converted I{from}. If unspecified - or C{None}, asks the current sentence for the C{unitKey}. If that - also fails, raises C{AttributeError}. - @type unit: C{str} - @param unitKey: The name of the key/attribute under which the unit can - be found in the current sentence. If the C{unit} parameter is set, - this parameter is not used. - @type unitKey: C{str} - @param sourceKey: The name of the key/attribute that contains the - current value to be converted (expressed in units as defined - according to the C{unit} parameter). If unset, will use the - same key as the value key. - @type sourceKey: C{str} - @param valueKey: The key name in which the data will be stored in the - C{_sentenceData} instance attribute. If unset, attempts to remove - "Units" from the end of the C{unitKey} parameter. If that fails, - raises C{ValueError}. - @type valueKey: C{str} - """ - if unit is None: - unit = getattr(self.currentSentence, unitKey) - if valueKey is None: - if unitKey is not None and unitKey.endswith("Units"): - valueKey = unitKey[:-5] - else: - raise ValueError("valueKey unspecified and couldn't be guessed") - if sourceKey is None: - sourceKey = valueKey - - if unit not in self._ACCEPTABLE_UNITS: - converter = self._UNIT_CONVERTERS[unit] - currentValue = getattr(self.currentSentence, sourceKey) - self._sentenceData[valueKey] = converter(currentValue) - - - def _fixGSV(self): - """ - Parses partial visible satellite information from a GSV sentence. - """ - # To anyone who knows NMEA, this method's name should raise a chuckle's - # worth of schadenfreude. 'Fix' GSV? Hah! Ludicrous. - beaconInformation = base.BeaconInformation() - self._sentenceData['_partialBeaconInformation'] = beaconInformation - - keys = "satellitePRN", "azimuth", "elevation", "signalToNoiseRatio" - for index in range(4): - prn, azimuth, elevation, snr = [getattr(self.currentSentence, attr) - for attr in ("%s_%i" % (key, index) for key in keys)] - - if prn is None or snr is None: - # The peephole optimizer optimizes the jump away, meaning that - # coverage.py thinks it isn't covered. It is. Replace it with - # break, and watch the test case fail. - # ML thread about this issue: http://goo.gl/1KNUi - # Related CPython bug: http://bugs.python.org/issue2506 - continue - - satellite = base.Satellite(prn, azimuth, elevation, snr) - beaconInformation.seenBeacons.add(satellite) - - - def _fixGSA(self): - """ - Extracts the information regarding which satellites were used in - obtaining the GPS fix from a GSA sentence. - - Precondition: A GSA sentence was fired. Postcondition: The current - sentence data (C{self._sentenceData} will contain a set of the - currently used PRNs (under the key C{_usedPRNs}. - """ - self._sentenceData['_usedPRNs'] = set() - for key in ("usedSatellitePRN_%d" % (x,) for x in range(12)): - prn = getattr(self.currentSentence, key, None) - if prn is not None: - self._sentenceData['_usedPRNs'].add(int(prn)) - - - _SPECIFIC_SENTENCE_FIXES = { - 'GPGSV': _fixGSV, - 'GPGSA': _fixGSA, - } - - - def _sentenceSpecificFix(self): - """ - Executes a fix for a specific type of sentence. - """ - fixer = self._SPECIFIC_SENTENCE_FIXES.get(self.currentSentence.type) - if fixer is not None: - fixer(self) - - - _FIXERS = { - 'type': - lambda self: self._sentenceSpecificFix(), - - 'timestamp': - lambda self: self._fixTimestamp(), - 'datestamp': - lambda self: self._fixDatestamp(), - - 'latitudeFloat': - lambda self: self._fixCoordinateFloat(Angles.LATITUDE), - 'latitudeHemisphere': - lambda self: self._fixHemisphereSign(Angles.LATITUDE, 'latitude'), - 'longitudeFloat': - lambda self: self._fixCoordinateFloat(Angles.LONGITUDE), - 'longitudeHemisphere': - lambda self: self._fixHemisphereSign(Angles.LONGITUDE, 'longitude'), - - 'altitude': - lambda self: self._convert('altitude', - converter=lambda strRepr: base.Altitude(float(strRepr))), - 'altitudeUnits': - lambda self: self._fixUnits(unitKey='altitudeUnits'), - - 'heightOfGeoidAboveWGS84': - lambda self: self._convert('heightOfGeoidAboveWGS84', - converter=lambda strRepr: base.Altitude(float(strRepr))), - 'heightOfGeoidAboveWGS84Units': - lambda self: self._fixUnits( - unitKey='heightOfGeoidAboveWGS84Units'), - - 'trueHeading': - lambda self: self._statefulUpdate('trueHeading'), - 'magneticVariation': - lambda self: self._statefulUpdate('magneticVariation'), - - 'magneticVariationDirection': - lambda self: self._fixHemisphereSign(Angles.VARIATION, - 'heading'), - - 'speedInKnots': - lambda self: self._fixUnits(valueKey='speed', - sourceKey='speedInKnots', - unit='N'), - - 'positionDilutionOfPrecision': - lambda self: self._statefulUpdate('positionDilutionOfPrecision'), - 'horizontalDilutionOfPrecision': - lambda self: self._statefulUpdate('horizontalDilutionOfPrecision'), - 'verticalDilutionOfPrecision': - lambda self: self._statefulUpdate('verticalDilutionOfPrecision'), - } - - - def clear(self): - """ - Resets this adapter. - - This will empty the adapter state and the current sentence data. - """ - self._state = {} - self._sentenceData = {} - - - def sentenceReceived(self, sentence): - """ - Called when a sentence is received. - - Will clean the received NMEAProtocol sentence up, and then update the - adapter's state, followed by firing the callbacks. - - If the received sentence was invalid, the state will be cleared. - - @param sentence: The sentence that is received. - @type sentence: L{NMEASentence} - """ - self.currentSentence = sentence - self._sentenceData = {} - - try: - self._validateCurrentSentence() - self._cleanCurrentSentence() - except base.InvalidSentence: - self.clear() - - self._updateState() - self._fireSentenceCallbacks() - - - def _validateCurrentSentence(self): - """ - Tests if a sentence contains a valid fix. - """ - if (self.currentSentence.fixQuality is GPGGAFixQualities.INVALID_FIX - or self.currentSentence.dataMode is GPGLLGPRMCFixQualities.VOID - or self.currentSentence.fixType is GPGSAFixTypes.GSA_NO_FIX): - raise base.InvalidSentence("bad sentence") - - - def _cleanCurrentSentence(self): - """ - Cleans the current sentence. - """ - for key in sorted(self.currentSentence.presentAttributes): - fixer = self._FIXERS.get(key, None) - - if fixer is not None: - fixer(self) - - - def _updateState(self): - """ - Updates the current state with the new information from the sentence. - """ - self._updateBeaconInformation() - self._combineDateAndTime() - self._state.update(self._sentenceData) - - - def _updateBeaconInformation(self): - """ - Updates existing beacon information state with new data. - """ - new = self._sentenceData.get('_partialBeaconInformation') - if new is None: - return - - self._updateUsedBeacons(new) - self._mergeBeaconInformation(new) - - if self.currentSentence._isLastGSVSentence(): - if not self.currentSentence._isFirstGSVSentence(): - # not a 1-sentence sequence, get rid of partial information - del self._state['_partialBeaconInformation'] - bi = self._sentenceData.pop('_partialBeaconInformation') - self._sentenceData['beaconInformation'] = bi - - - def _updateUsedBeacons(self, beaconInformation): - """ - Searches the adapter state and sentence data for information about - which beacons where used, then adds it to the provided beacon - information object. - - If no new beacon usage information is available, does nothing. - - @param beaconInformation: The beacon information object that beacon - usage information will be added to (if necessary). - @type beaconInformation: L{twisted.positioning.base.BeaconInformation} - """ - for source in [self._state, self._sentenceData]: - usedPRNs = source.get("_usedPRNs") - if usedPRNs is not None: - break - else: # No used PRN info to update - return - - for beacon in beaconInformation.seenBeacons: - if beacon.identifier in usedPRNs: - beaconInformation.usedBeacons.add(beacon) - - - def _mergeBeaconInformation(self, newBeaconInformation): - """ - Merges beacon information in the adapter state (if it exists) into - the provided beacon information. Specifically, this merges used and - seen beacons. - - If the adapter state has no beacon information, does nothing. - - @param beaconInformation: The beacon information object that beacon - information will be merged into (if necessary). - @type beaconInformation: L{twisted.positioning.base.BeaconInformation} - """ - old = self._state.get('_partialBeaconInformation') - if old is None: - return - - for attr in ["seenBeacons", "usedBeacons"]: - getattr(newBeaconInformation, attr).update(getattr(old, attr)) - - - def _combineDateAndTime(self): - """ - Combines a C{datetime.date} object and a C{datetime.time} object, - collected from one or more NMEA sentences, into a single - C{datetime.datetime} object suitable for sending to the - L{IPositioningReceiver}. - """ - if not any(k in self._sentenceData for k in ["_date", "_time"]): - # If the sentence has neither date nor time, there's - # nothing new to combine here. - return - - date, time = [self._sentenceData.get(key) or self._state.get(key) - for key in ('_date', '_time')] - - if date is None or time is None: - return - - dt = datetime.datetime.combine(date, time) - self._sentenceData['time'] = dt - - - def _fireSentenceCallbacks(self): - """ - Fires sentence callbacks for the current sentence. - - A callback will only fire if all of the keys it requires are present - in the current state and at least one such field was altered in the - current sentence. - - The callbacks will only be fired with data from L{self._state}. - """ - iface = ipositioning.IPositioningReceiver - for name, method in iface.namesAndDescriptions(): - callback = getattr(self._receiver, name) - - kwargs = {} - atLeastOnePresentInSentence = False - - try: - for field in method.positional: - if field in self._sentenceData: - atLeastOnePresentInSentence = True - kwargs[field] = self._state[field] - except KeyError: - continue - - if atLeastOnePresentInSentence: - callback(**kwargs) - - - -__all__ = [ - "NMEAProtocol", - "NMEASentence", - "NMEAAdapter" -] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/__init__.py deleted file mode 100644 index 18f3d51..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Tests for the Twisted positioning framework. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/receiver.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/receiver.py deleted file mode 100644 index 9119944..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/receiver.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Receivers for use in tests. -""" -from twisted.positioning import base, ipositioning - - -class MockPositioningReceiver(base.BasePositioningReceiver): - """ - A mock positioning receiver. - - Mocks all the L{IPositioningReceiver} methods with stubs that don't do - anything but register that they were called. - - @ivar called: A mapping of names of callbacks that have been called to - C{True}. - @type called: C{dict} - """ - def __init__(self): - self.clear() - - for methodName in ipositioning.IPositioningReceiver: - self._addCallback(methodName) - - - def clear(self): - """ - Forget all the methods that have been called on this receiver, by - emptying C{self.called}. - """ - self.called = {} - - - def _addCallback(self, name): - """ - Adds a callback of the given name, setting C{self.called[name]} to - C{True} when called. - """ - def callback(*a, **kw): - self.called[name] = True - - setattr(self, name, callback) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_base.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_base.py deleted file mode 100644 index 6b2e25e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_base.py +++ /dev/null @@ -1,917 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Test cases for positioning primitives. -""" -from twisted.trial.unittest import TestCase -from twisted.positioning import base -from twisted.positioning.base import Angles, Directions -from twisted.positioning.ipositioning import IPositioningBeacon -from zope.interface import verify - - -class AngleTests(TestCase): - """ - Tests for the L{twisted.positioning.base.Angle} class. - """ - def test_empty(self): - """ - The repr of an empty angle says that is of unknown type and unknown - value. - """ - a = base.Angle() - self.assertEqual("", repr(a)) - - - def test_variation(self): - """ - The repr of an empty variation says that it is a variation of unknown - value. - """ - a = base.Angle(angleType=Angles.VARIATION) - self.assertEqual("", repr(a)) - - - def test_unknownType(self): - """ - The repr of an angle of unknown type but a given value displays that - type and value in its repr. - """ - a = base.Angle(1.0) - self.assertEqual("", repr(a)) - - - def test_bogusType(self): - """ - Trying to create an angle with a bogus type raises C{ValueError}. - """ - self.assertRaises(ValueError, base.Angle, angleType="BOGUS") - - - -class HeadingTests(TestCase): - """ - Tests for the L{twisted.positioning.base.Heading} class. - """ - def test_simple(self): - """ - Tests that a simple heading has a value in decimal degrees, which is - also its value when converted to a float. Its variation, and by - consequence its corrected heading, is C{None}. - """ - h = base.Heading(1.) - self.assertEqual(h.inDecimalDegrees, 1.) - self.assertEqual(float(h), 1.) - self.assertEqual(h.variation, None) - self.assertEqual(h.correctedHeading, None) - - - def test_headingWithoutVariationRepr(self): - """ - A repr of a heading with no variation reports its value and that the - variation is unknown. - """ - heading = base.Heading(1.) - expectedRepr = "" - self.assertEqual(repr(heading), expectedRepr) - - - def test_headingWithVariationRepr(self): - """ - A repr of a heading with known variation reports its value and the - value of that variation. - """ - angle, variation = 1.0, -10.0 - heading = base.Heading.fromFloats(angle, variationValue=variation) - reprTemplate = ')>' - self.assertEqual(repr(heading), reprTemplate.format(angle, variation)) - - - def test_valueEquality(self): - """ - Headings with the same values compare equal. - """ - self.assertEqual(base.Heading(1.), base.Heading(1.)) - - - def test_valueInequality(self): - """ - Headings with different values compare unequal. - """ - self.assertNotEquals(base.Heading(1.), base.Heading(2.)) - - - def test_zeroHeadingEdgeCase(self): - """ - Headings can be instantiated with a value of 0 and no variation. - """ - base.Heading(0) - - - def test_zeroHeading180DegreeVariationEdgeCase(self): - """ - Headings can be instantiated with a value of 0 and a variation of 180 - degrees. - """ - base.Heading(0, 180) - - - def _badValueTest(self, **kw): - """ - Helper function for verifying that bad values raise C{ValueError}. - - @param kw: The keyword arguments passed to L{base.Heading.fromFloats}. - """ - self.assertRaises(ValueError, base.Heading.fromFloats, **kw) - - - def test_badAngleValueEdgeCase(self): - """ - Headings can not be instantiated with a value of 360 degrees. - """ - self._badValueTest(angleValue=360.0) - - - def test_badVariationEdgeCase(self): - """ - Headings can not be instantiated with a variation of -180 degrees. - """ - self._badValueTest(variationValue=-180.0) - - - def test_negativeHeading(self): - """ - Negative heading values raise C{ValueError}. - """ - self._badValueTest(angleValue=-10.0) - - - def test_headingTooLarge(self): - """ - Heading values greater than C{360.0} raise C{ValueError}. - """ - self._badValueTest(angleValue=370.0) - - - def test_variationTooNegative(self): - """ - Variation values less than C{-180.0} raise C{ValueError}. - """ - self._badValueTest(variationValue=-190.0) - - - def test_variationTooPositive(self): - """ - Variation values greater than C{180.0} raise C{ValueError}. - """ - self._badValueTest(variationValue=190.0) - - - def test_correctedHeading(self): - """ - A heading with a value and a variation has a corrected heading. - """ - h = base.Heading.fromFloats(1., variationValue=-10.) - self.assertEqual(h.correctedHeading, base.Angle(11., Angles.HEADING)) - - - def test_correctedHeadingOverflow(self): - """ - A heading with a value and a variation has the appropriate corrected - heading value, even when the variation puts it across the 360 degree - boundary. - """ - h = base.Heading.fromFloats(359., variationValue=-2.) - self.assertEqual(h.correctedHeading, base.Angle(1., Angles.HEADING)) - - - def test_correctedHeadingOverflowEdgeCase(self): - """ - A heading with a value and a variation has the appropriate corrected - heading value, even when the variation puts it exactly at the 360 - degree boundary. - """ - h = base.Heading.fromFloats(359., variationValue=-1.) - self.assertEqual(h.correctedHeading, base.Angle(0., Angles.HEADING)) - - - def test_correctedHeadingUnderflow(self): - """ - A heading with a value and a variation has the appropriate corrected - heading value, even when the variation puts it under the 0 degree - boundary. - """ - h = base.Heading.fromFloats(1., variationValue=2.) - self.assertEqual(h.correctedHeading, base.Angle(359., Angles.HEADING)) - - - def test_correctedHeadingUnderflowEdgeCase(self): - """ - A heading with a value and a variation has the appropriate corrected - heading value, even when the variation puts it exactly at the 0 - degree boundary. - """ - h = base.Heading.fromFloats(1., variationValue=1.) - self.assertEqual(h.correctedHeading, base.Angle(0., Angles.HEADING)) - - - def test_setVariationSign(self): - """ - Setting the sign of a heading changes the variation sign. - """ - h = base.Heading.fromFloats(1., variationValue=1.) - h.setSign(1) - self.assertEqual(h.variation.inDecimalDegrees, 1.) - h.setSign(-1) - self.assertEqual(h.variation.inDecimalDegrees, -1.) - - - def test_setBadVariationSign(self): - """ - Setting the sign of a heading to values that aren't C{-1} or C{1} - raises C{ValueError} and does not affect the heading. - """ - h = base.Heading.fromFloats(1., variationValue=1.) - self.assertRaises(ValueError, h.setSign, -50) - self.assertEqual(h.variation.inDecimalDegrees, 1.) - - self.assertRaises(ValueError, h.setSign, 0) - self.assertEqual(h.variation.inDecimalDegrees, 1.) - - self.assertRaises(ValueError, h.setSign, 50) - self.assertEqual(h.variation.inDecimalDegrees, 1.) - - - def test_setUnknownVariationSign(self): - """ - Setting the sign on a heading with unknown variation raises - C{ValueError}. - """ - h = base.Heading.fromFloats(1.) - self.assertIdentical(None, h.variation.inDecimalDegrees) - self.assertRaises(ValueError, h.setSign, 1) - - - -class CoordinateTests(TestCase): - def test_float(self): - """ - Coordinates can be converted to floats. - """ - coordinate = base.Coordinate(10.0) - self.assertEqual(float(coordinate), 10.0) - - - def test_repr(self): - """ - Coordinates that aren't explicitly latitudes or longitudes have an - appropriate repr. - """ - coordinate = base.Coordinate(10.0) - expectedRepr = "".format(10.0) - self.assertEqual(repr(coordinate), expectedRepr) - - - def test_positiveLatitude(self): - """ - Positive latitudes have a repr that specifies their type and value. - """ - coordinate = base.Coordinate(10.0, Angles.LATITUDE) - expectedRepr = "".format(10.0) - self.assertEqual(repr(coordinate), expectedRepr) - - - def test_negativeLatitude(self): - """ - Negative latitudes have a repr that specifies their type and value. - """ - coordinate = base.Coordinate(-50.0, Angles.LATITUDE) - expectedRepr = "".format(-50.0) - self.assertEqual(repr(coordinate), expectedRepr) - - - def test_positiveLongitude(self): - """ - Positive longitudes have a repr that specifies their type and value. - """ - longitude = base.Coordinate(50.0, Angles.LONGITUDE) - expectedRepr = "".format(50.0) - self.assertEqual(repr(longitude), expectedRepr) - - - def test_negativeLongitude(self): - """ - Negative longitudes have a repr that specifies their type and value. - """ - longitude = base.Coordinate(-50.0, Angles.LONGITUDE) - expectedRepr = "".format(-50.0) - self.assertEqual(repr(longitude), expectedRepr) - - - def test_bogusCoordinateType(self): - """ - Creating coordinates with bogus types rasies C{ValueError}. - """ - self.assertRaises(ValueError, base.Coordinate, 150.0, "BOGUS") - - - def test_angleTypeNotCoordinate(self): - """ - Creating coordinates with angle types that aren't coordinates raises - C{ValueError}. - """ - self.assertRaises(ValueError, base.Coordinate, 150.0, Angles.HEADING) - - - def test_equality(self): - """ - Coordinates with the same value and type are equal. - """ - def makeCoordinate(): - return base.Coordinate(1.0, Angles.LONGITUDE) - self.assertEqual(makeCoordinate(), makeCoordinate()) - - - def test_differentAnglesInequality(self): - """ - Coordinates with different values aren't equal. - """ - c1 = base.Coordinate(1.0) - c2 = base.Coordinate(-1.0) - self.assertNotEqual(c1, c2) - - - def test_differentTypesInequality(self): - """ - Coordinates with the same values but different types aren't equal. - """ - c1 = base.Coordinate(1.0, Angles.LATITUDE) - c2 = base.Coordinate(1.0, Angles.LONGITUDE) - self.assertNotEqual(c1, c2) - - - def test_sign(self): - """ - Setting the sign on a coordinate sets the sign of the value of the - coordinate. - """ - c = base.Coordinate(50., Angles.LATITUDE) - c.setSign(1) - self.assertEqual(c.inDecimalDegrees, 50.) - c.setSign(-1) - self.assertEqual(c.inDecimalDegrees, -50.) - - - def test_badVariationSign(self): - """ - Setting a bogus sign value (not -1 or 1) on a coordinate raises - C{ValueError} and doesn't affect the coordinate. - """ - value = 50.0 - c = base.Coordinate(value, Angles.LATITUDE) - - self.assertRaises(ValueError, c.setSign, -50) - self.assertEqual(c.inDecimalDegrees, 50.) - - self.assertRaises(ValueError, c.setSign, 0) - self.assertEqual(c.inDecimalDegrees, 50.) - - self.assertRaises(ValueError, c.setSign, 50) - self.assertEqual(c.inDecimalDegrees, 50.) - - - def test_northernHemisphere(self): - """ - Positive latitudes are in the northern hemisphere. - """ - coordinate = base.Coordinate(1.0, Angles.LATITUDE) - self.assertEqual(coordinate.hemisphere, Directions.NORTH) - - - def test_easternHemisphere(self): - """ - Positive longitudes are in the eastern hemisphere. - """ - coordinate = base.Coordinate(1.0, Angles.LONGITUDE) - self.assertEqual(coordinate.hemisphere, Directions.EAST) - - - def test_southernHemisphere(self): - """ - Negative latitudes are in the southern hemisphere. - """ - coordinate = base.Coordinate(-1.0, Angles.LATITUDE) - self.assertEqual(coordinate.hemisphere, Directions.SOUTH) - - - def test_westernHemisphere(self): - """ - Negative longitudes are in the western hemisphere. - """ - coordinate = base.Coordinate(-1.0, Angles.LONGITUDE) - self.assertEqual(coordinate.hemisphere, Directions.WEST) - - - def test_badHemisphere(self): - """ - Accessing the hemisphere for a coordinate that can't compute it - raises C{ValueError}. - """ - coordinate = base.Coordinate(1.0, None) - self.assertRaises(ValueError, lambda: coordinate.hemisphere) - - - def test_latitudeTooLarge(self): - """ - Creating a latitude with a value greater than or equal to 90 degrees - raises C{ValueError}. - """ - self.assertRaises(ValueError, _makeLatitude, 150.0) - self.assertRaises(ValueError, _makeLatitude, 90.0) - - - def test_latitudeTooSmall(self): - """ - Creating a latitude with a value less than or equal to -90 degrees - raises C{ValueError}. - """ - self.assertRaises(ValueError, _makeLatitude, -150.0) - self.assertRaises(ValueError, _makeLatitude, -90.0) - - - def test_longitudeTooLarge(self): - """ - Creating a longitude with a value greater than or equal to 180 degrees - raises C{ValueError}. - """ - self.assertRaises(ValueError, _makeLongitude, 250.0) - self.assertRaises(ValueError, _makeLongitude, 180.0) - - - def test_longitudeTooSmall(self): - """ - Creating a longitude with a value less than or equal to -180 degrees - raises C{ValueError}. - """ - self.assertRaises(ValueError, _makeLongitude, -250.0) - self.assertRaises(ValueError, _makeLongitude, -180.0) - - - def test_inDegreesMinutesSeconds(self): - """ - Coordinate values can be accessed in degrees, minutes, seconds. - """ - c = base.Coordinate(50.5, Angles.LATITUDE) - self.assertEqual(c.inDegreesMinutesSeconds, (50, 30, 0)) - - c = base.Coordinate(50.213, Angles.LATITUDE) - self.assertEqual(c.inDegreesMinutesSeconds, (50, 12, 46)) - - - def test_unknownAngleInDegreesMinutesSeconds(self): - """ - If the vaue of a coordinate is C{None}, its values in degrees, - minutes, seconds is also C{None}. - """ - c = base.Coordinate(None, None) - self.assertEqual(c.inDegreesMinutesSeconds, None) - - - -def _makeLatitude(value): - """ - Builds and returns a latitude of given value. - """ - return base.Coordinate(value, Angles.LATITUDE) - - - -def _makeLongitude(value): - """ - Builds and returns a longitude of given value. - """ - return base.Coordinate(value, Angles.LONGITUDE) - - - -class AltitudeTests(TestCase): - """ - Tests for the L{twisted.positioning.base.Altitude} class. - """ - def test_value(self): - """ - Altitudes can be instantiated and reports the correct value in - meters and feet, as well as when converted to float. - """ - altitude = base.Altitude(1.) - self.assertEqual(float(altitude), 1.) - self.assertEqual(altitude.inMeters, 1.) - self.assertEqual(altitude.inFeet, 1./base.METERS_PER_FOOT) - - - def test_repr(self): - """ - Altitudes report their type and value in their repr. - """ - altitude = base.Altitude(1.) - self.assertEqual(repr(altitude), "") - - - def test_equality(self): - """ - Altitudes with equal values compare equal. - """ - firstAltitude = base.Altitude(1.) - secondAltitude = base.Altitude(1.) - self.assertEqual(firstAltitude, secondAltitude) - - - def test_inequality(self): - """ - Altitudes with different values don't compare equal. - """ - firstAltitude = base.Altitude(1.) - secondAltitude = base.Altitude(-1.) - self.assertNotEquals(firstAltitude, secondAltitude) - - - -class SpeedTests(TestCase): - """ - Tests for the L{twisted.positioning.base.Speed} class. - """ - def test_value(self): - """ - Speeds can be instantiated, and report their value in meters - per second, and can be converted to floats. - """ - speed = base.Speed(50.0) - self.assertEqual(speed.inMetersPerSecond, 50.0) - self.assertEqual(float(speed), 50.0) - - - def test_repr(self): - """ - Speeds report their type and value in their repr. - """ - speed = base.Speed(50.0) - self.assertEqual(repr(speed), "") - - - def test_negativeSpeeds(self): - """ - Creating a negative speed raises C{ValueError}. - """ - self.assertRaises(ValueError, base.Speed, -1.0) - - - def test_inKnots(self): - """ - A speed can be converted into its value in knots. - """ - speed = base.Speed(1.0) - self.assertEqual(1/base.MPS_PER_KNOT, speed.inKnots) - - - def test_asFloat(self): - """ - A speed can be converted into a C{float}. - """ - self.assertEqual(1.0, float(base.Speed(1.0))) - - - -class ClimbTests(TestCase): - """ - Tests for L{twisted.positioning.base.Climb}. - """ - def test_simple(self): - """ - Speeds can be instantiated, and report their value in meters - per second, and can be converted to floats. - """ - climb = base.Climb(42.) - self.assertEqual(climb.inMetersPerSecond, 42.) - self.assertEqual(float(climb), 42.) - - - def test_repr(self): - """ - Climbs report their type and value in their repr. - """ - climb = base.Climb(42.) - self.assertEqual(repr(climb), "") - - - def test_negativeClimbs(self): - """ - Climbs can have negative values, and still report that value - in meters per second and when converted to floats. - """ - climb = base.Climb(-42.) - self.assertEqual(climb.inMetersPerSecond, -42.) - self.assertEqual(float(climb), -42.) - - - def test_speedInKnots(self): - """ - A climb can be converted into its value in knots. - """ - climb = base.Climb(1.0) - self.assertEqual(1/base.MPS_PER_KNOT, climb.inKnots) - - - def test_asFloat(self): - """ - A climb can be converted into a C{float}. - """ - self.assertEqual(1.0, float(base.Climb(1.0))) - - - -class PositionErrorTests(TestCase): - """ - Tests for L{twisted.positioning.base.PositionError}. - """ - def test_allUnset(self): - """ - In an empty L{base.PositionError} with no invariant testing, all - dilutions of positions are C{None}. - """ - positionError = base.PositionError() - self.assertEqual(positionError.pdop, None) - self.assertEqual(positionError.hdop, None) - self.assertEqual(positionError.vdop, None) - - - def test_allUnsetWithInvariant(self): - """ - In an empty L{base.PositionError} with invariant testing, all - dilutions of positions are C{None}. - """ - positionError = base.PositionError(testInvariant=True) - self.assertEqual(positionError.pdop, None) - self.assertEqual(positionError.hdop, None) - self.assertEqual(positionError.vdop, None) - - - def test_withoutInvariant(self): - """ - L{base.PositionError}s can be instantiated with just a HDOP. - """ - positionError = base.PositionError(hdop=1.0) - self.assertEqual(positionError.hdop, 1.0) - - - def test_withInvariant(self): - """ - Creating a simple L{base.PositionError} with just a HDOP while - checking the invariant works. - """ - positionError = base.PositionError(hdop=1.0, testInvariant=True) - self.assertEqual(positionError.hdop, 1.0) - - - def test_invalidWithoutInvariant(self): - """ - Creating a L{base.PositionError} with values set to an impossible - combination works if the invariant is not checked. - """ - error = base.PositionError(pdop=1.0, vdop=1.0, hdop=1.0) - self.assertEqual(error.pdop, 1.0) - self.assertEqual(error.hdop, 1.0) - self.assertEqual(error.vdop, 1.0) - - - def test_invalidWithInvariant(self): - """ - Creating a L{base.PositionError} with values set to an impossible - combination raises C{ValueError} if the invariant is being tested. - """ - self.assertRaises(ValueError, base.PositionError, - pdop=1.0, vdop=1.0, hdop=1.0, testInvariant=True) - - - def test_setDOPWithoutInvariant(self): - """ - You can set the PDOP value to value inconsisted with HDOP and VDOP - when not checking the invariant. - """ - pe = base.PositionError(hdop=1.0, vdop=1.0) - pe.pdop = 100.0 - self.assertEqual(pe.pdop, 100.0) - - - def test_setDOPWithInvariant(self): - """ - Attempting to set the PDOP value to value inconsisted with HDOP and - VDOP when checking the invariant raises C{ValueError}. - """ - pe = base.PositionError(hdop=1.0, vdop=1.0, testInvariant=True) - pdop = pe.pdop - - def setPDOP(pe): - pe.pdop = 100.0 - - self.assertRaises(ValueError, setPDOP, pe) - self.assertEqual(pe.pdop, pdop) - - - REPR_TEMPLATE = "" - - - def _testDOP(self, pe, pdop, hdop, vdop): - """ - Tests the DOP values in a position error, and the repr of that - position error. - - @param pe: The position error under test. - @type pe: C{PositionError} - @param pdop: The expected position dilution of precision. - @type pdop: C{float} or C{NoneType} - @param hdop: The expected horizontal dilution of precision. - @type hdop: C{float} or C{NoneType} - @param vdop: The expected vertical dilution of precision. - @type vdop: C{float} or C{NoneType} - """ - self.assertEqual(pe.pdop, pdop) - self.assertEqual(pe.hdop, hdop) - self.assertEqual(pe.vdop, vdop) - self.assertEqual(repr(pe), self.REPR_TEMPLATE % (pdop, hdop, vdop)) - - - def test_positionAndHorizontalSet(self): - """ - The VDOP is correctly determined from PDOP and HDOP. - """ - pdop, hdop = 2.0, 1.0 - vdop = (pdop**2 - hdop**2)**.5 - pe = base.PositionError(pdop=pdop, hdop=hdop) - self._testDOP(pe, pdop, hdop, vdop) - - - def test_positionAndVerticalSet(self): - """ - The HDOP is correctly determined from PDOP and VDOP. - """ - pdop, vdop = 2.0, 1.0 - hdop = (pdop**2 - vdop**2)**.5 - pe = base.PositionError(pdop=pdop, vdop=vdop) - self._testDOP(pe, pdop, hdop, vdop) - - - def test_horizontalAndVerticalSet(self): - """ - The PDOP is correctly determined from HDOP and VDOP. - """ - hdop, vdop = 1.0, 1.0 - pdop = (hdop**2 + vdop**2)**.5 - pe = base.PositionError(hdop=hdop, vdop=vdop) - self._testDOP(pe, pdop, hdop, vdop) - - - -class BeaconInformationTests(TestCase): - """ - Tests for L{twisted.positioning.base.BeaconInformation}. - """ - def test_minimal(self): - """ - For an empty beacon information object, the number of used - beacons is zero, the number of seen beacons is zero, and the - repr of the object reflects that. - """ - bi = base.BeaconInformation() - self.assertEqual(len(bi.usedBeacons), 0) - expectedRepr = ("") - self.assertEqual(repr(bi), expectedRepr) - - - satelliteKwargs = {"azimuth": 1, "elevation": 1, "signalToNoiseRatio": 1.} - - - def test_simple(self): - """ - Tests a beacon information with a bunch of satellites, none of - which used in computing a fix. - """ - def _buildSatellite(**kw): - kwargs = dict(self.satelliteKwargs) - kwargs.update(kw) - return base.Satellite(**kwargs) - - beacons = set() - for prn in range(1, 10): - beacons.add(_buildSatellite(identifier=prn)) - - bi = base.BeaconInformation(beacons) - - self.assertEqual(len(bi.seenBeacons), 9) - self.assertEqual(len(bi.usedBeacons), 0) - self.assertEqual(repr(bi), - ", " - ", " - ", " - ", " - ", " - ", " - ", " - ", " - "" - "])>") - - - def test_someSatellitesUsed(self): - """ - Tests a beacon information with a bunch of satellites, some of - them used in computing a fix. - """ - bi = base.BeaconInformation() - - for prn in range(1, 10): - satellite = base.Satellite(identifier=prn, **self.satelliteKwargs) - bi.seenBeacons.add(satellite) - if prn % 2: - bi.usedBeacons.add(satellite) - - self.assertEqual(len(bi.seenBeacons), 9) - self.assertEqual(len(bi.usedBeacons), 5) - - self.assertEqual(repr(bi), - ", " - ", " - ", " - ", " - "], " - "unused beacons: [" - ", " - ", " - ", " - "])>") - - - -class PositioningBeaconTests(TestCase): - """ - Tests for L{base.PositioningBeacon}. - """ - def test_interface(self): - """ - Tests that L{base.PositioningBeacon} implements L{IPositioningBeacon}. - """ - implements = IPositioningBeacon.implementedBy(base.PositioningBeacon) - self.assertTrue(implements) - verify.verifyObject(IPositioningBeacon, base.PositioningBeacon(1)) - - - def test_repr(self): - """ - Tests the repr of a positioning beacon. - """ - self.assertEqual(repr(base.PositioningBeacon("A")), "") - - - -class SatelliteTests(TestCase): - """ - Tests for L{twisted.positioning.base.Satellite}. - """ - def test_minimal(self): - """ - Tests a minimal satellite that only has a known PRN. - - Tests that the azimuth, elevation and signal to noise ratios - are C{None} and verifies the repr. - """ - s = base.Satellite(1) - self.assertEqual(s.identifier, 1) - self.assertEqual(s.azimuth, None) - self.assertEqual(s.elevation, None) - self.assertEqual(s.signalToNoiseRatio, None) - self.assertEqual(repr(s), "") - - - def test_simple(self): - """ - Tests a minimal satellite that only has a known PRN. - - Tests that the azimuth, elevation and signal to noise ratios - are correct and verifies the repr. - """ - s = base.Satellite(identifier=1, - azimuth=270., - elevation=30., - signalToNoiseRatio=25.) - - self.assertEqual(s.identifier, 1) - self.assertEqual(s.azimuth, 270.) - self.assertEqual(s.elevation, 30.) - self.assertEqual(s.signalToNoiseRatio, 25.) - self.assertEqual(repr(s), "") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_nmea.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_nmea.py deleted file mode 100644 index e79a4b3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_nmea.py +++ /dev/null @@ -1,1252 +0,0 @@ -# Copyright (c) 2009-2011 Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Test cases for using NMEA sentences. -""" -import datetime -from operator import attrgetter -from zope.interface import implementer - -from twisted.positioning import base, nmea, ipositioning -from twisted.positioning.test.receiver import MockPositioningReceiver -from twisted.trial.unittest import TestCase - -from twisted.positioning.base import Angles - -# Sample sentences -GPGGA = '$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47' -GPRMC = '$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A' -GPGSA = '$GPGSA,A,3,19,28,14,18,27,22,31,39,,,,,1.7,1.0,1.3*34' -GPHDT = '$GPHDT,038.005,T*3B' -GPGLL = '$GPGLL,4916.45,N,12311.12,W,225444,A*31' -GPGLL_PARTIAL = '$GPGLL,3751.65,S,14507.36,E*77' - -GPGSV_SINGLE = '$GPGSV,1,1,11,03,03,111,00,04,15,270,00,06,01,010,00,,,,*4b' -GPGSV_EMPTY_MIDDLE = '$GPGSV,1,1,11,03,03,111,00,,,,,,,,,13,06,292,00*75' -GPGSV_SEQ = GPGSV_FIRST, GPGSV_MIDDLE, GPGSV_LAST = """ -$GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74 -$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74 -$GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D -""".split() - - - -@implementer(ipositioning.INMEAReceiver) -class NMEATestReceiver(object): - """ - An NMEA receiver for testing. - - Remembers the last sentence it has received. - """ - def __init__(self): - self.clear() - - - def clear(self): - """ - Forgets the received sentence (if any), by setting - C{self.receivedSentence} to C{None}. - """ - self.receivedSentence = None - - - def sentenceReceived(self, sentence): - self.receivedSentence = sentence - - - -class CallbackTests(TestCase): - """ - Tests if the NMEA protocol correctly calls its sentence callback. - - @ivar protocol: The NMEA protocol under test. - @type protocol: L{nmea.NMEAProtocol} - @ivar sentenceTypes: The set of sentence types of all sentences the test's - sentence callback function has been called with. - @type sentenceTypes: C{set} - """ - def setUp(self): - receiver = NMEATestReceiver() - self.protocol = nmea.NMEAProtocol(receiver, self._sentenceCallback) - self.sentenceTypes = set() - - - def _sentenceCallback(self, sentence): - """ - Remembers that a sentence of this type was fired. - """ - self.sentenceTypes.add(sentence.type) - - - def test_callbacksCalled(self): - """ - The correct callbacks fire, and that *only* those fire. - """ - sentencesByType = { - 'GPGGA': ['$GPGGA*56'], - 'GPGLL': ['$GPGLL*50'], - 'GPGSA': ['$GPGSA*42'], - 'GPGSV': ['$GPGSV*55'], - 'GPHDT': ['$GPHDT*4f'], - 'GPRMC': ['$GPRMC*4b'] - } - - for sentenceType, sentences in sentencesByType.iteritems(): - for sentence in sentences: - self.protocol.lineReceived(sentence) - self.assertEqual(self.sentenceTypes, set([sentenceType])) - self.sentenceTypes.clear() - - - -class BrokenSentenceCallbackTests(TestCase): - """ - Tests for broken NMEA sentence callbacks. - """ - def setUp(self): - receiver = NMEATestReceiver() - self.protocol = nmea.NMEAProtocol(receiver, self._sentenceCallback) - - - def _sentenceCallback(self, sentence): - """ - Raises C{AttributeError}. - """ - raise AttributeError("ERROR!!!") - - - def test_dontSwallowCallbackExceptions(self): - """ - An C{AttributeError} in the sentence callback of an C{NMEAProtocol} - doesn't get swallowed. - """ - lineReceived = self.protocol.lineReceived - self.assertRaises(AttributeError, lineReceived, '$GPGGA*56') - - - -class SplitTests(TestCase): - """ - Checks splitting of NMEA sentences. - """ - def test_withChecksum(self): - """ - An NMEA sentence with a checksum gets split correctly. - """ - splitSentence = nmea._split("$GPGGA,spam,eggs*00") - self.assertEqual(splitSentence, ['GPGGA', 'spam', 'eggs']) - - - def test_noCheckum(self): - """ - An NMEA sentence without a checksum gets split correctly. - """ - splitSentence = nmea._split("$GPGGA,spam,eggs*") - self.assertEqual(splitSentence, ['GPGGA', 'spam', 'eggs']) - - - -class ChecksumTests(TestCase): - """ - NMEA sentence checksum verification tests. - """ - def test_valid(self): - """ - Sentences with valid checksums get validated. - """ - nmea._validateChecksum(GPGGA) - - - def test_missing(self): - """ - Sentences with missing checksums get validated. - """ - nmea._validateChecksum(GPGGA[:-2]) - - - def test_invalid(self): - """ - Sentences with a bad checksum raise L{base.InvalidChecksum} when - attempting to validate them. - """ - validate = nmea._validateChecksum - - bareSentence, checksum = GPGGA.split("*") - badChecksum = "%x" % (int(checksum, 16) + 1) - sentences = ["%s*%s" % (bareSentence, badChecksum)] - - for s in sentences: - self.assertRaises(base.InvalidChecksum, validate, s) - - - -class NMEAReceiverSetup(object): - """ - A mixin for tests that need an NMEA receiver (and a protocol attached to - it). - - @ivar receiver: An NMEA receiver that remembers the last sentence. - @type receiver: L{NMEATestReceiver} - @ivar protocol: An NMEA protocol attached to the receiver. - @type protocol: L{twisted.positioning.nmea.NMEAProtocol} - """ - def setUp(self): - """ - Sets up an NMEA receiver. - """ - self.receiver = NMEATestReceiver() - self.protocol = nmea.NMEAProtocol(self.receiver) - - - -class GSVSequenceTests(NMEAReceiverSetup, TestCase): - """ - Tests for the interpretation of GSV sequences. - """ - def test_firstSentence(self): - """ - The first sentence in a GSV sequence is correctly identified. - """ - self.protocol.lineReceived(GPGSV_FIRST) - sentence = self.receiver.receivedSentence - - self.assertTrue(sentence._isFirstGSVSentence()) - self.assertFalse(sentence._isLastGSVSentence()) - - - def test_middleSentence(self): - """ - A sentence in the middle of a GSV sequence is correctly - identified (as being neither the last nor the first). - """ - self.protocol.lineReceived(GPGSV_MIDDLE) - sentence = self.receiver.receivedSentence - - self.assertFalse(sentence._isFirstGSVSentence()) - self.assertFalse(sentence._isLastGSVSentence()) - - - def test_lastSentence(self): - """ - The last sentence in a GSV sequence is correctly identified. - """ - self.protocol.lineReceived(GPGSV_LAST) - sentence = self.receiver.receivedSentence - - self.assertFalse(sentence._isFirstGSVSentence()) - self.assertTrue(sentence._isLastGSVSentence()) - - - -class BogusSentenceTests(NMEAReceiverSetup, TestCase): - """ - Tests for verifying predictable failure for bogus NMEA sentences. - """ - def assertRaisesOnSentence(self, exceptionClass, sentence): - """ - Asserts that the protocol raises C{exceptionClass} when it receives - C{sentence}. - - @param exceptionClass: The exception class expected to be raised. - @type exceptionClass: C{Exception} subclass - - @param sentence: The (bogus) NMEA sentence. - @type sentence: C{str} - """ - self.assertRaises(exceptionClass, self.protocol.lineReceived, sentence) - - - def test_raiseOnUnknownSentenceType(self): - """ - Receiving a well-formed sentence of unknown type raises - C{ValueError}. - """ - self.assertRaisesOnSentence(ValueError, "$GPBOGUS*5b") - - - def test_raiseOnMalformedSentences(self): - """ - Receiving a malformed sentence raises L{base.InvalidSentence}. - """ - self.assertRaisesOnSentence(base.InvalidSentence, "GPBOGUS") - - - -class NMEASentenceTests(NMEAReceiverSetup, TestCase): - """ - Tests for L{nmea.NMEASentence} objects. - """ - def test_repr(self): - """ - The C{repr} of L{nmea.NMEASentence} objects is correct. - """ - sentencesWithExpectedRepr = [ - (GPGSA, - ""), - ] - - for sentence, expectedRepr in sentencesWithExpectedRepr: - self.protocol.lineReceived(sentence) - received = self.receiver.receivedSentence - self.assertEqual(repr(received), expectedRepr) - - - -class ParsingTests(NMEAReceiverSetup, TestCase): - """ - Tests if raw NMEA sentences get parsed correctly. - - This doesn't really involve any interpretation, just turning ugly raw NMEA - representations into objects that are more pleasant to work with. - """ - def _parserTest(self, sentence, expected): - """ - Passes a sentence to the protocol and gets the parsed sentence from - the receiver. Then verifies that the parsed sentence contains the - expected data. - """ - self.protocol.lineReceived(sentence) - received = self.receiver.receivedSentence - self.assertEqual(expected, received._sentenceData) - - - def test_fullRMC(self): - """ - A full RMC sentence is correctly parsed. - """ - expected = { - 'type': 'GPRMC', - 'latitudeFloat': '4807.038', - 'latitudeHemisphere': 'N', - 'longitudeFloat': '01131.000', - 'longitudeHemisphere': 'E', - 'magneticVariation': '003.1', - 'magneticVariationDirection': 'W', - 'speedInKnots': '022.4', - 'timestamp': '123519', - 'datestamp': '230394', - 'trueHeading': '084.4', - 'dataMode': 'A', - } - self._parserTest(GPRMC, expected) - - - def test_fullGGA(self): - """ - A full GGA sentence is correctly parsed. - """ - expected = { - 'type': 'GPGGA', - - 'altitude': '545.4', - 'altitudeUnits': 'M', - 'heightOfGeoidAboveWGS84': '46.9', - 'heightOfGeoidAboveWGS84Units': 'M', - - 'horizontalDilutionOfPrecision': '0.9', - - 'latitudeFloat': '4807.038', - 'latitudeHemisphere': 'N', - 'longitudeFloat': '01131.000', - 'longitudeHemisphere': 'E', - - 'numberOfSatellitesSeen': '08', - 'timestamp': '123519', - 'fixQuality': '1', - } - self._parserTest(GPGGA, expected) - - - def test_fullGLL(self): - """ - A full GLL sentence is correctly parsed. - """ - expected = { - 'type': 'GPGLL', - - 'latitudeFloat': '4916.45', - 'latitudeHemisphere': 'N', - 'longitudeFloat': '12311.12', - 'longitudeHemisphere': 'W', - - 'timestamp': '225444', - 'dataMode': 'A', - } - self._parserTest(GPGLL, expected) - - - def test_partialGLL(self): - """ - A partial GLL sentence is correctly parsed. - """ - expected = { - 'type': 'GPGLL', - - 'latitudeFloat': '3751.65', - 'latitudeHemisphere': 'S', - 'longitudeFloat': '14507.36', - 'longitudeHemisphere': 'E', - } - self._parserTest(GPGLL_PARTIAL, expected) - - - def test_fullGSV(self): - """ - A full GSV sentence is correctly parsed. - """ - expected = { - 'type': 'GPGSV', - 'GSVSentenceIndex': '1', - 'numberOfGSVSentences': '3', - 'numberOfSatellitesSeen': '11', - - 'azimuth_0': '111', - 'azimuth_1': '270', - 'azimuth_2': '010', - 'azimuth_3': '292', - - 'elevation_0': '03', - 'elevation_1': '15', - 'elevation_2': '01', - 'elevation_3': '06', - - 'satellitePRN_0': '03', - 'satellitePRN_1': '04', - 'satellitePRN_2': '06', - 'satellitePRN_3': '13', - - 'signalToNoiseRatio_0': '00', - 'signalToNoiseRatio_1': '00', - 'signalToNoiseRatio_2': '00', - 'signalToNoiseRatio_3': '00', - } - self._parserTest(GPGSV_FIRST, expected) - - - def test_partialGSV(self): - """ - A partial GSV sentence is correctly parsed. - """ - expected = { - 'type': 'GPGSV', - 'GSVSentenceIndex': '3', - 'numberOfGSVSentences': '3', - 'numberOfSatellitesSeen': '11', - - 'azimuth_0': '067', - 'azimuth_1': '311', - 'azimuth_2': '244', - - 'elevation_0': '42', - 'elevation_1': '14', - 'elevation_2': '05', - - 'satellitePRN_0': '22', - 'satellitePRN_1': '24', - 'satellitePRN_2': '27', - - 'signalToNoiseRatio_0': '42', - 'signalToNoiseRatio_1': '43', - 'signalToNoiseRatio_2': '00', - } - self._parserTest(GPGSV_LAST, expected) - - - def test_fullHDT(self): - """ - A full HDT sentence is correctly parsed. - """ - expected = { - 'type': 'GPHDT', - 'trueHeading': '038.005', - } - self._parserTest(GPHDT, expected) - - - def test_typicalGSA(self): - """ - A typical GSA sentence is correctly parsed. - """ - expected = { - 'type': 'GPGSA', - - 'dataMode': 'A', - 'fixType': '3', - - 'usedSatellitePRN_0': '19', - 'usedSatellitePRN_1': '28', - 'usedSatellitePRN_2': '14', - 'usedSatellitePRN_3': '18', - 'usedSatellitePRN_4': '27', - 'usedSatellitePRN_5': '22', - 'usedSatellitePRN_6': '31', - 'usedSatellitePRN_7': '39', - - 'positionDilutionOfPrecision': '1.7', - 'horizontalDilutionOfPrecision': '1.0', - 'verticalDilutionOfPrecision': '1.3', - } - self._parserTest(GPGSA, expected) - - - -class FixUnitsTests(TestCase): - """ - Tests for the generic unit fixing method, L{nmea.NMEAAdapter._fixUnits}. - - @ivar adapter: The NMEA adapter. - @type adapter: L{nmea.NMEAAdapter} - """ - def setUp(self): - self.adapter = nmea.NMEAAdapter(base.BasePositioningReceiver()) - - - def test_noValueKey(self): - """ - Tests that when no C{valueKey} is provided, C{unitKey} is used, minus - C{"Units"} at the end. - """ - class FakeSentence(object): - """ - A fake sentence that just has a "foo" attribute. - """ - def __init__(self): - self.foo = 1 - - self.adapter.currentSentence = FakeSentence() - self.adapter._fixUnits(unitKey="fooUnits", unit="N") - self.assertNotEqual(self.adapter._sentenceData["foo"], 1) - - - def test_unitKeyButNoUnit(self): - """ - Tests that if a unit key is provided but the unit isn't, the unit is - automatically determined from the unit key. - """ - class FakeSentence(object): - """ - A fake sentence that just has "foo" and "fooUnits" attributes. - """ - def __init__(self): - self.foo = 1 - self.fooUnits = "N" - - self.adapter.currentSentence = FakeSentence() - self.adapter._fixUnits(unitKey="fooUnits") - self.assertNotEqual(self.adapter._sentenceData["foo"], 1) - - - def test_noValueKeyAndNoUnitKey(self): - """ - Tests that when a unit is specified but neither C{valueKey} nor - C{unitKey} is provided, C{ValueError} is raised. - """ - self.assertRaises(ValueError, self.adapter._fixUnits, unit="K") - - - -class FixerTestMixin: - """ - Mixin for tests for the fixers on L{nmea.NMEAAdapter} that adapt - from NMEA-specific notations to generic Python objects. - - @ivar adapter: The NMEA adapter. - @type adapter: L{nmea.NMEAAdapter} - """ - def setUp(self): - self.adapter = nmea.NMEAAdapter(base.BasePositioningReceiver()) - - - def _fixerTest(self, sentenceData, expected=None, exceptionClass=None): - """ - A generic adapter fixer test. - - Creates a sentence from the C{sentenceData} and sends that to the - adapter. If C{exceptionClass} is not passed, this is assumed to work, - and C{expected} is compared with the adapter's internal state. - Otherwise, passing the sentence to the adapter is checked to raise - C{exceptionClass}. - - @param sentenceData: Raw sentence content. - @type sentenceData: C{dict} mapping C{str} to C{str} - - @param expected: The expected state of the adapter. - @type expected: C{dict} or C{None} - - @param exceptionClass: The exception to be raised by the adapter. - @type exceptionClass: subclass of C{Exception} - """ - sentence = nmea.NMEASentence(sentenceData) - def receiveSentence(): - self.adapter.sentenceReceived(sentence) - - if exceptionClass is None: - receiveSentence() - self.assertEqual(self.adapter._state, expected) - else: - self.assertRaises(exceptionClass, receiveSentence) - - self.adapter.clear() - - - -class TimestampFixerTests(FixerTestMixin, TestCase): - """ - Tests conversion from NMEA timestamps to C{datetime.time} objects. - """ - def test_simple(self): - """ - A simple timestamp is converted correctly. - """ - data = {'timestamp': '123456'} # 12:34:56Z - expected = {'_time': datetime.time(12, 34, 56)} - self._fixerTest(data, expected) - - - def test_broken(self): - """ - A broken timestamp raises C{ValueError}. - """ - badTimestamps = '993456', '129956', '123499' - - for t in badTimestamps: - self._fixerTest({'timestamp': t}, exceptionClass=ValueError) - - - -class DatestampFixerTests(FixerTestMixin, TestCase): - def test_defaultYearThreshold(self): - """ - The default year threshold is 1980. - """ - self.assertEqual(self.adapter.yearThreshold, 1980) - - - def test_beforeThreshold(self): - """ - Dates before the threshold are interpreted as being in the century - after the threshold. (Since the threshold is the earliest possible - date.) - """ - datestring, date = '010115', datetime.date(2015, 1, 1) - self._fixerTest({'datestamp': datestring}, {'_date': date}) - - - def test_afterThreshold(self): - """ - Dates after the threshold are interpreted as being in the same century - as the threshold. - """ - datestring, date = '010195', datetime.date(1995, 1, 1) - self._fixerTest({'datestamp': datestring}, {'_date': date}) - - - def test_invalidMonth(self): - """ - A datestring with an invalid month (> 12) raises C{ValueError}. - """ - self._fixerTest({'datestamp': '011301'}, exceptionClass=ValueError) - - - def test_invalidDay(self): - """ - A datestring with an invalid day (more days than there are in that - month) raises C{ValueError}. - """ - self._fixerTest({'datestamp': '320101'}, exceptionClass=ValueError) - self._fixerTest({'datestamp': '300201'}, exceptionClass=ValueError) - - - -def _nmeaFloat(degrees, minutes): - """ - Builds an NMEA float representation for a given angle in degrees and - decimal minutes. - - @param degrees: The integer degrees for this angle. - @type degrees: C{int} - @param minutes: The decimal minutes value for this angle. - @type minutes: C{float} - @return: The NMEA float representation for this angle. - @rtype: C{str} - """ - return "%i%0.3f" % (degrees, minutes) - - -def _coordinateSign(hemisphere): - """ - Return the sign of a coordinate. - - This is C{1} if the coordinate is in the northern or eastern hemispheres, - C{-1} otherwise. - - @param hemisphere: NMEA shorthand for the hemisphere. One of "NESW". - @type hemisphere: C{str} - - @return: The sign of the coordinate value. - @rtype: C{int} - """ - return 1 if hemisphere in "NE" else -1 - - -def _coordinateType(hemisphere): - """ - Return the type of a coordinate. - - This is L{Angles.LATITUDE} if the coordinate is in the northern or - southern hemispheres, L{Angles.LONGITUDE} otherwise. - - @param hemisphere: NMEA shorthand for the hemisphere. One of "NESW". - @type hemisphere: C{str} - - @return: The type of the coordinate (L{Angles.LATITUDE} or - L{Angles.LONGITUDE}) - """ - return Angles.LATITUDE if hemisphere in "NS" else Angles.LONGITUDE - - - -class CoordinateFixerTests(FixerTestMixin, TestCase): - """ - Tests turning NMEA coordinate notations into something more pleasant. - """ - def test_north(self): - """ - NMEA coordinate representations in the northern hemisphere - convert correctly. - """ - sentenceData = {"latitudeFloat": "1030.000", "latitudeHemisphere": "N"} - state = {"latitude": base.Coordinate(10.5, Angles.LATITUDE)} - self._fixerTest(sentenceData, state) - - - def test_south(self): - """ - NMEA coordinate representations in the southern hemisphere - convert correctly. - """ - sentenceData = {"latitudeFloat": "1030.000", "latitudeHemisphere": "S"} - state = {"latitude": base.Coordinate(-10.5, Angles.LATITUDE)} - self._fixerTest(sentenceData, state) - - - def test_east(self): - """ - NMEA coordinate representations in the eastern hemisphere - convert correctly. - """ - sentenceData = {"longitudeFloat": "1030.000", "longitudeHemisphere": "E"} - state = {"longitude": base.Coordinate(10.5, Angles.LONGITUDE)} - self._fixerTest(sentenceData, state) - - - def test_west(self): - """ - NMEA coordinate representations in the western hemisphere - convert correctly. - """ - sentenceData = {"longitudeFloat": "1030.000", "longitudeHemisphere": "W"} - state = {"longitude": base.Coordinate(-10.5, Angles.LONGITUDE)} - self._fixerTest(sentenceData, state) - - - def test_badHemisphere(self): - """ - NMEA coordinate representations for nonexistent hemispheres - raise C{ValueError} when you attempt to parse them. - """ - sentenceData = {'longitudeHemisphere': 'Q'} - self._fixerTest(sentenceData, exceptionClass=ValueError) - - - def test_badHemisphereSign(self): - """ - NMEA coordinate repesentation parsing fails predictably - when you pass nonexistent coordinate types (not latitude or - longitude). - """ - getSign = lambda: self.adapter._getHemisphereSign("BOGUS_VALUE") - self.assertRaises(ValueError, getSign) - - - -class AltitudeFixerTests(FixerTestMixin, TestCase): - """ - Tests that NMEA representations of altitudes are correctly converted. - """ - def test_fixAltitude(self): - """ - The NMEA representation of an altitude (above mean sea level) - is correctly converted. - """ - key, value = 'altitude', '545.4' - altitude = base.Altitude(float(value)) - self._fixerTest({key: value}, {key: altitude}) - - - def test_heightOfGeoidAboveWGS84(self): - """ - The NMEA representation of an altitude of the geoid (above the - WGS84 reference level) is correctly converted. - """ - key, value = 'heightOfGeoidAboveWGS84', '46.9' - altitude = base.Altitude(float(value)) - self._fixerTest({key: value}, {key: altitude}) - - - -class SpeedFixerTests(FixerTestMixin, TestCase): - """ - Tests that NMEA representations of speeds are correctly converted. - """ - def test_speedInKnots(self): - """ - Speeds reported in knots correctly get converted to meters per - second. - """ - key, value, targetKey = "speedInKnots", "10", "speed" - speed = base.Speed(float(value) * base.MPS_PER_KNOT) - self._fixerTest({key: value}, {targetKey: speed}) - - - -class VariationFixerTests(FixerTestMixin, TestCase): - """ - Tests if the absolute values of magnetic variations on the heading - and their sign get combined correctly, and if that value gets - combined with a heading correctly. - """ - def test_west(self): - """ - Tests westward (negative) magnetic variation. - """ - variation, direction = "1.34", "W" - heading = base.Heading.fromFloats(variationValue=-1*float(variation)) - sentenceData = {'magneticVariation': variation, - 'magneticVariationDirection': direction} - - self._fixerTest(sentenceData, {'heading': heading}) - - - def test_east(self): - """ - Tests eastward (positive) magnetic variation. - """ - variation, direction = "1.34", "E" - heading = base.Heading.fromFloats(variationValue=float(variation)) - sentenceData = {'magneticVariation': variation, - 'magneticVariationDirection': direction} - - self._fixerTest(sentenceData, {'heading': heading}) - - - def test_withHeading(self): - """ - Variation values get combined with headings correctly. - """ - trueHeading, variation, direction = "123.12", "1.34", "E" - sentenceData = {'trueHeading': trueHeading, - 'magneticVariation': variation, - 'magneticVariationDirection': direction} - heading = base.Heading.fromFloats(float(trueHeading), - variationValue=float(variation)) - self._fixerTest(sentenceData, {'heading': heading}) - - - -class PositionErrorFixerTests(FixerTestMixin, TestCase): - """ - Position errors in NMEA are passed as dilutions of precision (DOP). This - is a measure relative to some specified value of the GPS device as its - "reference" precision. Unfortunately, there are very few ways of figuring - this out from just the device (sans manual). - - There are two basic DOP values: vertical and horizontal. HDOP tells you - how precise your location is on the face of the earth (pretending it's - flat, at least locally). VDOP tells you how precise your altitude is - known. PDOP (position DOP) is a dependent value defined as the Euclidean - norm of those two, and gives you a more generic "goodness of fix" value. - """ - def test_simple(self): - self._fixerTest( - {'horizontalDilutionOfPrecision': '11'}, - {'positionError': base.PositionError(hdop=11.)}) - - - def test_mixing(self): - pdop, hdop, vdop = "1", "1", "1" - positionError = base.PositionError(pdop=float(pdop), - hdop=float(hdop), - vdop=float(vdop)) - sentenceData = {'positionDilutionOfPrecision': pdop, - 'horizontalDilutionOfPrecision': hdop, - 'verticalDilutionOfPrecision': vdop} - self._fixerTest(sentenceData, {"positionError": positionError}) - - -class ValidFixTests(FixerTestMixin, TestCase): - """ - Tests that data reported from a valid fix is used. - """ - def test_GGA(self): - """ - GGA data with a valid fix is used. - """ - sentenceData = {'type': 'GPGGA', - 'altitude': '545.4', - 'fixQuality': nmea.GPGGAFixQualities.GPS_FIX} - expectedState = {'altitude': base.Altitude(545.4)} - - self._fixerTest(sentenceData, expectedState) - - - def test_GLL(self): - """ - GLL data with a valid data mode is used. - """ - sentenceData = {'type': 'GPGLL', - 'altitude': '545.4', - 'dataMode': nmea.GPGLLGPRMCFixQualities.ACTIVE} - expectedState = {'altitude': base.Altitude(545.4)} - - self._fixerTest(sentenceData, expectedState) - - - -class InvalidFixTests(FixerTestMixin, TestCase): - """ - Tests that data being reported from a bad or incomplete fix isn't - used. Although the specification dictates that GPSes shouldn't produce - NMEA sentences with real-looking values for altitude or position in them - unless they have at least some semblance of a GPS fix, this is widely - ignored. - """ - def _invalidFixTest(self, sentenceData): - """ - Sentences with an invalid fix or data mode result in empty - state (ie, the data isn't used). - """ - self._fixerTest(sentenceData, {}) - - - def test_GGA(self): - """ - GGA sentence data is unused when there is no fix. - """ - sentenceData = {'type': 'GPGGA', - 'altitude': '545.4', - 'fixQuality': nmea.GPGGAFixQualities.INVALID_FIX} - - self._invalidFixTest(sentenceData) - - - def test_GLL(self): - """ - GLL sentence data is unused when the data is flagged as void. - """ - sentenceData = {'type': 'GPGLL', - 'altitude': '545.4', - 'dataMode': nmea.GPGLLGPRMCFixQualities.VOID} - - self._invalidFixTest(sentenceData) - - - def test_badGSADataMode(self): - """ - GSA sentence data is not used when there is no GPS fix, but - the data mode claims the data is "active". Some GPSes do - this, unfortunately, and that means you shouldn't use the - data. - """ - sentenceData = {'type': 'GPGSA', - 'altitude': '545.4', - 'dataMode': nmea.GPGLLGPRMCFixQualities.ACTIVE, - 'fixType': nmea.GPGSAFixTypes.GSA_NO_FIX} - self._invalidFixTest(sentenceData) - - - - def test_badGSAFixType(self): - """ - GSA sentence data is not used when the fix claims to be valid - (albeit only 2D), but the data mode says the data is void. - Some GPSes do this, unfortunately, and that means you - shouldn't use the data. - """ - sentenceData = {'type': 'GPGSA', - 'altitude': '545.4', - 'dataMode': nmea.GPGLLGPRMCFixQualities.VOID, - 'fixType': nmea.GPGSAFixTypes.GSA_2D_FIX} - self._invalidFixTest(sentenceData) - - - - def test_badGSADataModeAndFixType(self): - """ - GSA sentence data is not use when neither the fix nor the data - mode is any good. - """ - sentenceData = {'type': 'GPGSA', - 'altitude': '545.4', - 'dataMode': nmea.GPGLLGPRMCFixQualities.VOID, - 'fixType': nmea.GPGSAFixTypes.GSA_NO_FIX} - self._invalidFixTest(sentenceData) - - - -class NMEAReceiverTests(TestCase): - """ - Tests for the NMEA receiver. - """ - def setUp(self): - self.receiver = MockPositioningReceiver() - self.adapter = nmea.NMEAAdapter(self.receiver) - self.protocol = nmea.NMEAProtocol(self.adapter) - - - def test_onlyFireWhenCurrentSentenceHasNewInformation(self): - """ - If the current sentence does not contain any new fields for a - particular callback, that callback is not called; even if all - necessary information is still in the state from one or more - previous messages. - """ - self.protocol.lineReceived(GPGGA) - - gpggaCallbacks = set(['positionReceived', - 'positionErrorReceived', - 'altitudeReceived']) - self.assertEqual(set(self.receiver.called.keys()), gpggaCallbacks) - - self.receiver.clear() - self.assertNotEqual(self.adapter._state, {}) - - # GPHDT contains heading information but not position, - # altitude or anything like that; but that information is - # still in the state. - self.protocol.lineReceived(GPHDT) - gphdtCallbacks = set(['headingReceived']) - self.assertEqual(set(self.receiver.called.keys()), gphdtCallbacks) - - - def _receiverTest(self, sentences, expectedFired=(), extraTest=None): - """ - A generic test for NMEA receiver behavior. - - @param sentences: The sequence of sentences to simulate receiving. - @type sentences: iterable of C{str} - @param expectedFired: The names of the callbacks expected to fire. - @type expectedFired: iterable of C{str} - @param extraTest: An optional extra test hook. - @type extraTest: nullary callable - """ - for sentence in sentences: - self.protocol.lineReceived(sentence) - - actuallyFired = self.receiver.called.keys() - self.assertEqual(set(actuallyFired), set(expectedFired)) - - if extraTest is not None: - extraTest() - - self.receiver.clear() - self.adapter.clear() - - - def test_positionErrorUpdateAcrossStates(self): - """ - The positioning error is updated across multiple states. - """ - sentences = [GPGSA] + GPGSV_SEQ - callbacksFired = ['positionErrorReceived', 'beaconInformationReceived'] - - def _getIdentifiers(beacons): - return sorted(map(attrgetter("identifier"), beacons)) - - def checkBeaconInformation(): - beaconInformation = self.adapter._state['beaconInformation'] - - seenIdentifiers = _getIdentifiers(beaconInformation.seenBeacons) - expected = [3, 4, 6, 13, 14, 16, 18, 19, 22, 24, 27] - self.assertEqual(seenIdentifiers, expected) - - usedIdentifiers = _getIdentifiers(beaconInformation.usedBeacons) - # These are not actually all the PRNs in the sample GPGSA: - # only the ones also reported by the GPGSV sequence. This - # is just because the sample data doesn't come from the - # same reporting cycle of a GPS device. - self.assertEqual(usedIdentifiers, [14, 18, 19, 22, 27]) - - self._receiverTest(sentences, callbacksFired, checkBeaconInformation) - - - def test_emptyMiddleGSV(self): - """ - A GSV sentence with empty entries in any position does not mean that - entries in subsequent positions of the same GSV sentence are ignored. - """ - sentences = [GPGSV_EMPTY_MIDDLE] - callbacksFired = ['beaconInformationReceived'] - - def checkBeaconInformation(): - beaconInformation = self.adapter._state['beaconInformation'] - seenBeacons = beaconInformation.seenBeacons - - self.assertEqual(len(seenBeacons), 2) - self.assertIn(13, [b.identifier for b in seenBeacons]) - - self._receiverTest(sentences, callbacksFired, checkBeaconInformation) - - - def test_GGASentences(self): - """ - A sequence of GGA sentences fires C{positionReceived}, - C{positionErrorReceived} and C{altitudeReceived}. - """ - sentences = [GPGGA] - callbacksFired = ['positionReceived', - 'positionErrorReceived', - 'altitudeReceived'] - - self._receiverTest(sentences, callbacksFired) - - - def test_GGAWithDateInState(self): - """ - When receiving a GPGGA sentence and a date was already in the - state, the new time (from the GPGGA sentence) is combined with - that date. - """ - self.adapter._state["_date"] = datetime.date(2014, 1, 1) - - sentences = [GPGGA] - callbacksFired = ['positionReceived', - 'positionErrorReceived', - 'altitudeReceived', - 'timeReceived'] - - self._receiverTest(sentences, callbacksFired) - - - def test_RMCSentences(self): - """ - A sequence of RMC sentences fires C{positionReceived}, - C{speedReceived}, C{headingReceived} and C{timeReceived}. - """ - sentences = [GPRMC] - callbacksFired = ['headingReceived', - 'speedReceived', - 'positionReceived', - 'timeReceived'] - - self._receiverTest(sentences, callbacksFired) - - - def test_GSVSentences(self): - """ - A complete sequence of GSV sentences fires - C{beaconInformationReceived}. - """ - sentences = [GPGSV_FIRST, GPGSV_MIDDLE, GPGSV_LAST] - callbacksFired = ['beaconInformationReceived'] - - def checkPartialInformation(): - self.assertNotIn('_partialBeaconInformation', self.adapter._state) - - self._receiverTest(sentences, callbacksFired, checkPartialInformation) - - - def test_emptyMiddleEntriesGSVSequence(self): - """ - A complete sequence of GSV sentences with empty entries in the - middle still fires C{beaconInformationReceived}. - """ - sentences = [GPGSV_EMPTY_MIDDLE] - self._receiverTest(sentences, ["beaconInformationReceived"]) - - - def test_incompleteGSVSequence(self): - """ - An incomplete sequence of GSV sentences does not fire any callbacks. - """ - sentences = [GPGSV_FIRST] - self._receiverTest(sentences) - - - def test_singleSentenceGSVSequence(self): - """ - The parser does not fail badly when the sequence consists of - only one sentence (but is otherwise complete). - """ - sentences = [GPGSV_SINGLE] - self._receiverTest(sentences, ["beaconInformationReceived"]) - - - def test_GLLSentences(self): - """ - GLL sentences fire C{positionReceived}. - """ - sentences = [GPGLL_PARTIAL, GPGLL] - self._receiverTest(sentences, ['positionReceived']) - - - def test_HDTSentences(self): - """ - HDT sentences fire C{headingReceived}. - """ - sentences = [GPHDT] - self._receiverTest(sentences, ['headingReceived']) - - - def test_mixedSentences(self): - """ - A mix of sentences fires the correct callbacks. - """ - sentences = [GPRMC, GPGGA] - callbacksFired = ['altitudeReceived', - 'speedReceived', - 'positionReceived', - 'positionErrorReceived', - 'timeReceived', - 'headingReceived'] - - def checkTime(): - expectedDateTime = datetime.datetime(1994, 3, 23, 12, 35, 19) - self.assertEqual(self.adapter._state['time'], expectedDateTime) - - self._receiverTest(sentences, callbacksFired, checkTime) - - - def test_lotsOfMixedSentences(self): - """ - Sends an entire gamut of sentences and verifies the - appropriate callbacks fire. These are more than you'd expect - from your average consumer GPS device. They have most of the - important information, including beacon information and - visibility. - """ - sentences = [GPGSA] + GPGSV_SEQ + [GPRMC, GPGGA, GPGLL] - - callbacksFired = ['headingReceived', - 'beaconInformationReceived', - 'speedReceived', - 'positionReceived', - 'timeReceived', - 'altitudeReceived', - 'positionErrorReceived'] - - self._receiverTest(sentences, callbacksFired) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_sentence.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_sentence.py deleted file mode 100644 index 8f6062b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/positioning/test/test_sentence.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Tests for positioning sentences. -""" -import itertools - -from twisted.positioning import _sentence -from twisted.trial.unittest import TestCase - - -sentinelValueOne = "someStringValue" -sentinelValueTwo = "someOtherStringValue" - - - -class DummyProtocol(object): - """ - A simple, fake protocol. - """ - @staticmethod - def getSentenceAttributes(): - return ["type", sentinelValueOne, sentinelValueTwo] - - - -class DummySentence(_sentence._BaseSentence): - """ - A sentence for L{DummyProtocol}. - """ - ALLOWED_ATTRIBUTES = DummyProtocol.getSentenceAttributes() - - - -class MixinProtocol(_sentence._PositioningSentenceProducerMixin): - """ - A simple, fake protocol that declaratively tells you the sentences - it produces using L{base.PositioningSentenceProducerMixin}. - """ - _SENTENCE_CONTENTS = { - None: [ - sentinelValueOne, - sentinelValueTwo, - None # See MixinTests.test_noNoneInSentenceAttributes - ], - } - - - -class MixinSentence(_sentence._BaseSentence): - """ - A sentence for L{MixinProtocol}. - """ - ALLOWED_ATTRIBUTES = MixinProtocol.getSentenceAttributes() - - - -class SentenceTestsMixin(object): - """ - Tests for positioning protocols and their respective sentences. - """ - def test_attributeAccess(self): - """ - A sentence attribute gets the correct value, and accessing an - unset attribute (which is specified as being a valid sentence - attribute) gets C{None}. - """ - thisSentinel = object() - sentence = self.sentenceClass({sentinelValueOne: thisSentinel}) - self.assertEqual(getattr(sentence, sentinelValueOne), thisSentinel) - self.assertEqual(getattr(sentence, sentinelValueTwo), None) - - - def test_raiseOnMissingAttributeAccess(self): - """ - Accessing a nonexistent attribute raises C{AttributeError}. - """ - sentence = self.sentenceClass({}) - self.assertRaises(AttributeError, getattr, sentence, "BOGUS") - - - def test_raiseOnBadAttributeAccess(self): - """ - Accessing bogus attributes raises C{AttributeError}, *even* - when that attribute actually is in the sentence data. - """ - sentence = self.sentenceClass({"BOGUS": None}) - self.assertRaises(AttributeError, getattr, sentence, "BOGUS") - - - sentenceType = "tummies" - reprTemplate = "<%s (%s) {%s}>" - - - def _expectedRepr(self, sentenceType="unknown type", dataRepr=""): - """ - Builds the expected repr for a sentence. - - @param sentenceType: The name of the sentence type (e.g "GPGGA"). - @type sentenceType: C{str} - @param dataRepr: The repr of the data in the sentence. - @type dataRepr: C{str} - @return: The expected repr of the sentence. - @rtype: C{str} - """ - clsName = self.sentenceClass.__name__ - return self.reprTemplate % (clsName, sentenceType, dataRepr) - - - def test_unknownTypeRepr(self): - """ - Test the repr of an empty sentence of unknown type. - """ - sentence = self.sentenceClass({}) - expectedRepr = self._expectedRepr() - self.assertEqual(repr(sentence), expectedRepr) - - - def test_knownTypeRepr(self): - """ - Test the repr of an empty sentence of known type. - """ - sentence = self.sentenceClass({"type": self.sentenceType}) - expectedRepr = self._expectedRepr(self.sentenceType) - self.assertEqual(repr(sentence), expectedRepr) - - - -class DummyTests(TestCase, SentenceTestsMixin): - """ - Tests for protocol classes that implement the appropriate interface - (L{ipositioning.IPositioningSentenceProducer}) manually. - """ - def setUp(self): - self.protocol = DummyProtocol() - self.sentenceClass = DummySentence - - - -class MixinTests(TestCase, SentenceTestsMixin): - """ - Tests for protocols deriving from L{base.PositioningSentenceProducerMixin} - and their sentences. - """ - def setUp(self): - self.protocol = MixinProtocol() - self.sentenceClass = MixinSentence - - - def test_noNoneInSentenceAttributes(self): - """ - C{None} does not appear in the sentence attributes of the - protocol, even though it's in the specification. - - This is because C{None} is a placeholder for parts of the sentence you - don't really need or want, but there are some bits later on in the - sentence that you do want. The alternative would be to have to specify - things like "_UNUSED0", "_UNUSED1"... which would end up cluttering - the sentence data and eventually adapter state. - """ - sentenceAttributes = self.protocol.getSentenceAttributes() - self.assertNotIn(None, sentenceAttributes) - - sentenceContents = self.protocol._SENTENCE_CONTENTS - sentenceSpecAttributes = itertools.chain(*sentenceContents.values()) - self.assertIn(None, sentenceSpecAttributes) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/__init__.py deleted file mode 100644 index 67dee3e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Protocols: A collection of internet protocol implementations. -""" - -# Deprecating twisted.protocols.gps. -from twisted.python.versions import Version -from twisted.python.deprecate import deprecatedModuleAttribute - -deprecatedModuleAttribute( - Version("Twisted", 15, 2, 0), - "Use twisted.positioning instead.", - "twisted.protocols", "gps") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/amp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/amp.py deleted file mode 100644 index a744882..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/amp.py +++ /dev/null @@ -1,2720 +0,0 @@ -# -*- test-case-name: twisted.test.test_amp -*- -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module implements AMP, the Asynchronous Messaging Protocol. - -AMP is a protocol for sending multiple asynchronous request/response pairs over -the same connection. Requests and responses are both collections of key/value -pairs. - -AMP is a very simple protocol which is not an application. This module is a -"protocol construction kit" of sorts; it attempts to be the simplest wire-level -implementation of Deferreds. AMP provides the following base-level features: - - - Asynchronous request/response handling (hence the name) - - - Requests and responses are both key/value pairs - - - Binary transfer of all data: all data is length-prefixed. Your - application will never need to worry about quoting. - - - Command dispatching (like HTTP Verbs): the protocol is extensible, and - multiple AMP sub-protocols can be grouped together easily. - -The protocol implementation also provides a few additional features which are -not part of the core wire protocol, but are nevertheless very useful: - - - Tight TLS integration, with an included StartTLS command. - - - Handshaking to other protocols: because AMP has well-defined message - boundaries and maintains all incoming and outgoing requests for you, you - can start a connection over AMP and then switch to another protocol. - This makes it ideal for firewall-traversal applications where you may - have only one forwarded port but multiple applications that want to use - it. - -Using AMP with Twisted is simple. Each message is a command, with a response. -You begin by defining a command type. Commands specify their input and output -in terms of the types that they expect to see in the request and response -key-value pairs. Here's an example of a command that adds two integers, 'a' -and 'b':: - - class Sum(amp.Command): - arguments = [('a', amp.Integer()), - ('b', amp.Integer())] - response = [('total', amp.Integer())] - -Once you have specified a command, you need to make it part of a protocol, and -define a responder for it. Here's a 'JustSum' protocol that includes a -responder for our 'Sum' command:: - - class JustSum(amp.AMP): - def sum(self, a, b): - total = a + b - print 'Did a sum: %d + %d = %d' % (a, b, total) - return {'total': total} - Sum.responder(sum) - -Later, when you want to actually do a sum, the following expression will return -a L{Deferred} which will fire with the result:: - - ClientCreator(reactor, amp.AMP).connectTCP(...).addCallback( - lambda p: p.callRemote(Sum, a=13, b=81)).addCallback( - lambda result: result['total']) - -Command responders may also return Deferreds, causing the response to be -sent only once the Deferred fires:: - - class DelayedSum(amp.AMP): - def slowSum(self, a, b): - total = a + b - result = defer.Deferred() - reactor.callLater(3, result.callback, {'total': total}) - return result - Sum.responder(slowSum) - -This is transparent to the caller. - -You can also define the propagation of specific errors in AMP. For example, -for the slightly more complicated case of division, we might have to deal with -division by zero:: - - class Divide(amp.Command): - arguments = [('numerator', amp.Integer()), - ('denominator', amp.Integer())] - response = [('result', amp.Float())] - errors = {ZeroDivisionError: 'ZERO_DIVISION'} - -The 'errors' mapping here tells AMP that if a responder to Divide emits a -L{ZeroDivisionError}, then the other side should be informed that an error of -the type 'ZERO_DIVISION' has occurred. Writing a responder which takes -advantage of this is very simple - just raise your exception normally:: - - class JustDivide(amp.AMP): - def divide(self, numerator, denominator): - result = numerator / denominator - print 'Divided: %d / %d = %d' % (numerator, denominator, total) - return {'result': result} - Divide.responder(divide) - -On the client side, the errors mapping will be used to determine what the -'ZERO_DIVISION' error means, and translated into an asynchronous exception, -which can be handled normally as any L{Deferred} would be:: - - def trapZero(result): - result.trap(ZeroDivisionError) - print "Divided by zero: returning INF" - return 1e1000 - ClientCreator(reactor, amp.AMP).connectTCP(...).addCallback( - lambda p: p.callRemote(Divide, numerator=1234, - denominator=0) - ).addErrback(trapZero) - -For a complete, runnable example of both of these commands, see the files in -the Twisted repository:: - - doc/core/examples/ampserver.py - doc/core/examples/ampclient.py - -On the wire, AMP is a protocol which uses 2-byte lengths to prefix keys and -values, and empty keys to separate messages:: - - <2-byte length><2-byte length> - <2-byte length><2-byte length> - ... - <2-byte length><2-byte length> - # Empty Key == End of Message - -And so on. Because it's tedious to refer to lengths and NULs constantly, the -documentation will refer to packets as if they were newline delimited, like -so:: - - C: _command: sum - C: _ask: ef639e5c892ccb54 - C: a: 13 - C: b: 81 - - S: _answer: ef639e5c892ccb54 - S: total: 94 - -Notes: - -In general, the order of keys is arbitrary. Specific uses of AMP may impose an -ordering requirement, but unless this is specified explicitly, any ordering may -be generated and any ordering must be accepted. This applies to the -command-related keys I{_command} and I{_ask} as well as any other keys. - -Values are limited to the maximum encodable size in a 16-bit length, 65535 -bytes. - -Keys are limited to the maximum encodable size in a 8-bit length, 255 bytes. -Note that we still use 2-byte lengths to encode keys. This small redundancy -has several features: - - - If an implementation becomes confused and starts emitting corrupt data, - or gets keys confused with values, many common errors will be signalled - immediately instead of delivering obviously corrupt packets. - - - A single NUL will separate every key, and a double NUL separates - messages. This provides some redundancy when debugging traffic dumps. - - - NULs will be present at regular intervals along the protocol, providing - some padding for otherwise braindead C implementations of the protocol, - so that string functions will see the NUL and stop. - - - This makes it possible to run an AMP server on a port also used by a - plain-text protocol, and easily distinguish between non-AMP clients (like - web browsers) which issue non-NUL as the first byte, and AMP clients, - which always issue NUL as the first byte. -""" - -__metaclass__ = type - -import types, warnings - -from cStringIO import StringIO -from struct import pack -import decimal, datetime -from itertools import count - -from zope.interface import Interface, implements - -from twisted.python.reflect import accumulateClassDict -from twisted.python.failure import Failure -from twisted.python._tzhelper import ( - FixedOffsetTimeZone as _FixedOffsetTZInfo, UTC as utc -) - -from twisted.python import log, filepath - -from twisted.internet.interfaces import IFileDescriptorReceiver -from twisted.internet.main import CONNECTION_LOST -from twisted.internet.error import PeerVerifyError, ConnectionLost -from twisted.internet.error import ConnectionClosed -from twisted.internet.defer import Deferred, maybeDeferred, fail -from twisted.protocols.basic import Int16StringReceiver, StatefulStringProtocol - -try: - from twisted.internet import ssl -except ImportError: - ssl = None - -if ssl and not ssl.supported: - ssl = None - -if ssl is not None: - from twisted.internet.ssl import (CertificateOptions, Certificate, DN, - KeyPair) - - - -__all__ = [ - 'AMP', - 'ANSWER', - 'ASK', - 'AmpBox', - 'AmpError', - 'AmpList', - 'Argument', - 'BadLocalReturn', - 'BinaryBoxProtocol', - 'Boolean', - 'Box', - 'BoxDispatcher', - 'COMMAND', - 'Command', - 'CommandLocator', - 'Decimal', - 'Descriptor', - 'ERROR', - 'ERROR_CODE', - 'ERROR_DESCRIPTION', - 'Float', - 'IArgumentType', - 'IBoxReceiver', - 'IBoxSender', - 'IResponderLocator', - 'IncompatibleVersions', - 'Integer', - 'InvalidSignature', - 'ListOf', - 'MAX_KEY_LENGTH', - 'MAX_VALUE_LENGTH', - 'MalformedAmpBox', - 'NoEmptyBoxes', - 'OnlyOneTLS', - 'PROTOCOL_ERRORS', - 'PYTHON_KEYWORDS', - 'Path', - 'ProtocolSwitchCommand', - 'ProtocolSwitched', - 'QuitBox', - 'RemoteAmpError', - 'SimpleStringLocator', - 'StartTLS', - 'String', - 'TooLong', - 'UNHANDLED_ERROR_CODE', - 'UNKNOWN_ERROR_CODE', - 'UnhandledCommand', - 'utc', - 'Unicode', - 'UnknownRemoteError', - 'parse', - 'parseString', -] - - - -ASK = '_ask' -ANSWER = '_answer' -COMMAND = '_command' -ERROR = '_error' -ERROR_CODE = '_error_code' -ERROR_DESCRIPTION = '_error_description' -UNKNOWN_ERROR_CODE = 'UNKNOWN' -UNHANDLED_ERROR_CODE = 'UNHANDLED' - -MAX_KEY_LENGTH = 0xff -MAX_VALUE_LENGTH = 0xffff - - -class IArgumentType(Interface): - """ - An L{IArgumentType} can serialize a Python object into an AMP box and - deserialize information from an AMP box back into a Python object. - - @since: 9.0 - """ - def fromBox(name, strings, objects, proto): - """ - Given an argument name and an AMP box containing serialized values, - extract one or more Python objects and add them to the C{objects} - dictionary. - - @param name: The name associated with this argument. Most commonly, - this is the key which can be used to find a serialized value in - C{strings} and which should be used as the key in C{objects} to - associate with a structured Python object. - @type name: C{str} - - @param strings: The AMP box from which to extract one or more - values. - @type strings: C{dict} - - @param objects: The output dictionary to populate with the value for - this argument. - @type objects: C{dict} - - @param proto: The protocol instance which received the AMP box being - interpreted. Most likely this is an instance of L{AMP}, but - this is not guaranteed. - - @return: C{None} - """ - - - def toBox(name, strings, objects, proto): - """ - Given an argument name and a dictionary containing structured Python - objects, serialize values into one or more strings and add them to - the C{strings} dictionary. - - @param name: The name associated with this argument. Most commonly, - this is the key which can be used to find an object in - C{objects} and which should be used as the key in C{strings} to - associate with a C{str} giving the serialized form of that - object. - @type name: C{str} - - @param strings: The AMP box into which to insert one or more - strings. - @type strings: C{dict} - - @param objects: The input dictionary from which to extract Python - objects to serialize. - @type objects: C{dict} - - @param proto: The protocol instance which will send the AMP box once - it is fully populated. Most likely this is an instance of - L{AMP}, but this is not guaranteed. - - @return: C{None} - """ - - - -class IBoxSender(Interface): - """ - A transport which can send L{AmpBox} objects. - """ - - def sendBox(box): - """ - Send an L{AmpBox}. - - @raise ProtocolSwitched: if the underlying protocol has been - switched. - - @raise ConnectionLost: if the underlying connection has already been - lost. - """ - - def unhandledError(failure): - """ - An unhandled error occurred in response to a box. Log it - appropriately. - - @param failure: a L{Failure} describing the error that occurred. - """ - - - -class IBoxReceiver(Interface): - """ - An application object which can receive L{AmpBox} objects and dispatch them - appropriately. - """ - - def startReceivingBoxes(boxSender): - """ - The L{ampBoxReceived} method will start being called; boxes may be - responded to by responding to the given L{IBoxSender}. - - @param boxSender: an L{IBoxSender} provider. - """ - - - def ampBoxReceived(box): - """ - A box was received from the transport; dispatch it appropriately. - """ - - - def stopReceivingBoxes(reason): - """ - No further boxes will be received on this connection. - - @type reason: L{Failure} - """ - - - -class IResponderLocator(Interface): - """ - An application object which can look up appropriate responder methods for - AMP commands. - """ - - def locateResponder(name): - """ - Locate a responder method appropriate for the named command. - - @param name: the wire-level name (commandName) of the AMP command to be - responded to. - - @return: a 1-argument callable that takes an L{AmpBox} with argument - values for the given command, and returns an L{AmpBox} containing - argument values for the named command, or a L{Deferred} that fires the - same. - """ - - - -class AmpError(Exception): - """ - Base class of all Amp-related exceptions. - """ - - - -class ProtocolSwitched(Exception): - """ - Connections which have been switched to other protocols can no longer - accept traffic at the AMP level. This is raised when you try to send it. - """ - - - -class OnlyOneTLS(AmpError): - """ - This is an implementation limitation; TLS may only be started once per - connection. - """ - - - -class NoEmptyBoxes(AmpError): - """ - You can't have empty boxes on the connection. This is raised when you - receive or attempt to send one. - """ - - - -class InvalidSignature(AmpError): - """ - You didn't pass all the required arguments. - """ - - - -class TooLong(AmpError): - """ - One of the protocol's length limitations was violated. - - @ivar isKey: true if the string being encoded in a key position, false if - it was in a value position. - - @ivar isLocal: Was the string encoded locally, or received too long from - the network? (It's only physically possible to encode "too long" values on - the network for keys.) - - @ivar value: The string that was too long. - - @ivar keyName: If the string being encoded was in a value position, what - key was it being encoded for? - """ - - def __init__(self, isKey, isLocal, value, keyName=None): - AmpError.__init__(self) - self.isKey = isKey - self.isLocal = isLocal - self.value = value - self.keyName = keyName - - - def __repr__(self): - hdr = self.isKey and "key" or "value" - if not self.isKey: - hdr += ' ' + repr(self.keyName) - lcl = self.isLocal and "local" or "remote" - return "%s %s too long: %d" % (lcl, hdr, len(self.value)) - - - -class BadLocalReturn(AmpError): - """ - A bad value was returned from a local command; we were unable to coerce it. - """ - def __init__(self, message, enclosed): - AmpError.__init__(self) - self.message = message - self.enclosed = enclosed - - - def __repr__(self): - return self.message + " " + self.enclosed.getBriefTraceback() - - __str__ = __repr__ - - - -class RemoteAmpError(AmpError): - """ - This error indicates that something went wrong on the remote end of the - connection, and the error was serialized and transmitted to you. - """ - def __init__(self, errorCode, description, fatal=False, local=None): - """Create a remote error with an error code and description. - - @param errorCode: the AMP error code of this error. - - @param description: some text to show to the user. - - @param fatal: a boolean, true if this error should terminate the - connection. - - @param local: a local Failure, if one exists. - """ - if local: - localwhat = ' (local)' - othertb = local.getBriefTraceback() - else: - localwhat = '' - othertb = '' - Exception.__init__(self, "Code<%s>%s: %s%s" % ( - errorCode, localwhat, - description, othertb)) - self.local = local - self.errorCode = errorCode - self.description = description - self.fatal = fatal - - - -class UnknownRemoteError(RemoteAmpError): - """ - This means that an error whose type we can't identify was raised from the - other side. - """ - def __init__(self, description): - errorCode = UNKNOWN_ERROR_CODE - RemoteAmpError.__init__(self, errorCode, description) - - - -class MalformedAmpBox(AmpError): - """ - This error indicates that the wire-level protocol was malformed. - """ - - - -class UnhandledCommand(AmpError): - """ - A command received via amp could not be dispatched. - """ - - - -class IncompatibleVersions(AmpError): - """ - It was impossible to negotiate a compatible version of the protocol with - the other end of the connection. - """ - - -PROTOCOL_ERRORS = {UNHANDLED_ERROR_CODE: UnhandledCommand} - -class AmpBox(dict): - """ - I am a packet in the AMP protocol, much like a regular str:str dictionary. - """ - __slots__ = [] # be like a regular dictionary, don't magically - # acquire a __dict__... - - - def copy(self): - """ - Return another AmpBox just like me. - """ - newBox = self.__class__() - newBox.update(self) - return newBox - - - def serialize(self): - """ - Convert me into a wire-encoded string. - - @return: a str encoded according to the rules described in the module - docstring. - """ - i = self.items() - i.sort() - L = [] - w = L.append - for k, v in i: - if type(k) == unicode: - raise TypeError("Unicode key not allowed: %r" % k) - if type(v) == unicode: - raise TypeError( - "Unicode value for key %r not allowed: %r" % (k, v)) - if len(k) > MAX_KEY_LENGTH: - raise TooLong(True, True, k, None) - if len(v) > MAX_VALUE_LENGTH: - raise TooLong(False, True, v, k) - for kv in k, v: - w(pack("!H", len(kv))) - w(kv) - w(pack("!H", 0)) - return ''.join(L) - - - def _sendTo(self, proto): - """ - Serialize and send this box to a Amp instance. By the time it is being - sent, several keys are required. I must have exactly ONE of:: - - _ask - _answer - _error - - If the '_ask' key is set, then the '_command' key must also be - set. - - @param proto: an AMP instance. - """ - proto.sendBox(self) - - def __repr__(self): - return 'AmpBox(%s)' % (dict.__repr__(self),) - -# amp.Box => AmpBox - -Box = AmpBox - -class QuitBox(AmpBox): - """ - I am an AmpBox that, upon being sent, terminates the connection. - """ - __slots__ = [] - - - def __repr__(self): - return 'QuitBox(**%s)' % (super(QuitBox, self).__repr__(),) - - - def _sendTo(self, proto): - """ - Immediately call loseConnection after sending. - """ - super(QuitBox, self)._sendTo(proto) - proto.transport.loseConnection() - - - -class _SwitchBox(AmpBox): - """ - Implementation detail of ProtocolSwitchCommand: I am a AmpBox which sets - up state for the protocol to switch. - """ - - # DON'T set __slots__ here; we do have an attribute. - - def __init__(self, innerProto, **kw): - """ - Create a _SwitchBox with the protocol to switch to after being sent. - - @param innerProto: the protocol instance to switch to. - @type innerProto: an IProtocol provider. - """ - super(_SwitchBox, self).__init__(**kw) - self.innerProto = innerProto - - - def __repr__(self): - return '_SwitchBox(%r, **%s)' % (self.innerProto, - dict.__repr__(self),) - - - def _sendTo(self, proto): - """ - Send me; I am the last box on the connection. All further traffic will be - over the new protocol. - """ - super(_SwitchBox, self)._sendTo(proto) - proto._lockForSwitch() - proto._switchTo(self.innerProto) - - - -class BoxDispatcher: - """ - A L{BoxDispatcher} dispatches '_ask', '_answer', and '_error' L{AmpBox}es, - both incoming and outgoing, to their appropriate destinations. - - Outgoing commands are converted into L{Deferred}s and outgoing boxes, and - associated tracking state to fire those L{Deferred} when '_answer' boxes - come back. Incoming '_answer' and '_error' boxes are converted into - callbacks and errbacks on those L{Deferred}s, respectively. - - Incoming '_ask' boxes are converted into method calls on a supplied method - locator. - - @ivar _outstandingRequests: a dictionary mapping request IDs to - L{Deferred}s which were returned for those requests. - - @ivar locator: an object with a L{locateResponder} method that locates a - responder function that takes a Box and returns a result (either a Box or a - Deferred which fires one). - - @ivar boxSender: an object which can send boxes, via the L{_sendBox} - method, such as an L{AMP} instance. - @type boxSender: L{IBoxSender} - """ - - implements(IBoxReceiver) - - _failAllReason = None - _outstandingRequests = None - _counter = 0L - boxSender = None - - def __init__(self, locator): - self._outstandingRequests = {} - self.locator = locator - - - def startReceivingBoxes(self, boxSender): - """ - The given boxSender is going to start calling boxReceived on this - L{BoxDispatcher}. - - @param boxSender: The L{IBoxSender} to send command responses to. - """ - self.boxSender = boxSender - - - def stopReceivingBoxes(self, reason): - """ - No further boxes will be received here. Terminate all currently - oustanding command deferreds with the given reason. - """ - self.failAllOutgoing(reason) - - - def failAllOutgoing(self, reason): - """ - Call the errback on all outstanding requests awaiting responses. - - @param reason: the Failure instance to pass to those errbacks. - """ - self._failAllReason = reason - OR = self._outstandingRequests.items() - self._outstandingRequests = None # we can never send another request - for key, value in OR: - value.errback(reason) - - - def _nextTag(self): - """ - Generate protocol-local serial numbers for _ask keys. - - @return: a string that has not yet been used on this connection. - """ - self._counter += 1 - return '%x' % (self._counter,) - - - def _sendBoxCommand(self, command, box, requiresAnswer=True): - """ - Send a command across the wire with the given C{amp.Box}. - - Mutate the given box to give it any additional keys (_command, _ask) - required for the command and request/response machinery, then send it. - - If requiresAnswer is True, returns a C{Deferred} which fires when a - response is received. The C{Deferred} is fired with an C{amp.Box} on - success, or with an C{amp.RemoteAmpError} if an error is received. - - If the Deferred fails and the error is not handled by the caller of - this method, the failure will be logged and the connection dropped. - - @param command: a str, the name of the command to issue. - - @param box: an AmpBox with the arguments for the command. - - @param requiresAnswer: a boolean. Defaults to True. If True, return a - Deferred which will fire when the other side responds to this command. - If False, return None and do not ask the other side for acknowledgement. - - @return: a Deferred which fires the AmpBox that holds the response to - this command, or None, as specified by requiresAnswer. - - @raise ProtocolSwitched: if the protocol has been switched. - """ - if self._failAllReason is not None: - return fail(self._failAllReason) - box[COMMAND] = command - tag = self._nextTag() - if requiresAnswer: - box[ASK] = tag - box._sendTo(self.boxSender) - if requiresAnswer: - result = self._outstandingRequests[tag] = Deferred() - else: - result = None - return result - - - def callRemoteString(self, command, requiresAnswer=True, **kw): - """ - This is a low-level API, designed only for optimizing simple messages - for which the overhead of parsing is too great. - - @param command: a str naming the command. - - @param kw: arguments to the amp box. - - @param requiresAnswer: a boolean. Defaults to True. If True, return a - Deferred which will fire when the other side responds to this command. - If False, return None and do not ask the other side for acknowledgement. - - @return: a Deferred which fires the AmpBox that holds the response to - this command, or None, as specified by requiresAnswer. - """ - box = Box(kw) - return self._sendBoxCommand(command, box, requiresAnswer) - - - def callRemote(self, commandType, *a, **kw): - """ - This is the primary high-level API for sending messages via AMP. Invoke it - with a command and appropriate arguments to send a message to this - connection's peer. - - @param commandType: a subclass of Command. - @type commandType: L{type} - - @param a: Positional (special) parameters taken by the command. - Positional parameters will typically not be sent over the wire. The - only command included with AMP which uses positional parameters is - L{ProtocolSwitchCommand}, which takes the protocol that will be - switched to as its first argument. - - @param kw: Keyword arguments taken by the command. These are the - arguments declared in the command's 'arguments' attribute. They will - be encoded and sent to the peer as arguments for the L{commandType}. - - @return: If L{commandType} has a C{requiresAnswer} attribute set to - L{False}, then return L{None}. Otherwise, return a L{Deferred} which - fires with a dictionary of objects representing the result of this - call. Additionally, this L{Deferred} may fail with an exception - representing a connection failure, with L{UnknownRemoteError} if the - other end of the connection fails for an unknown reason, or with any - error specified as a key in L{commandType}'s C{errors} dictionary. - """ - - # XXX this takes command subclasses and not command objects on purpose. - # There's really no reason to have all this back-and-forth between - # command objects and the protocol, and the extra object being created - # (the Command instance) is pointless. Command is kind of like - # Interface, and should be more like it. - - # In other words, the fact that commandType is instantiated here is an - # implementation detail. Don't rely on it. - - try: - co = commandType(*a, **kw) - except: - return fail() - return co._doCommand(self) - - - def unhandledError(self, failure): - """ - This is a terminal callback called after application code has had a - chance to quash any errors. - """ - return self.boxSender.unhandledError(failure) - - - def _answerReceived(self, box): - """ - An AMP box was received that answered a command previously sent with - L{callRemote}. - - @param box: an AmpBox with a value for its L{ANSWER} key. - """ - question = self._outstandingRequests.pop(box[ANSWER]) - question.addErrback(self.unhandledError) - question.callback(box) - - - def _errorReceived(self, box): - """ - An AMP box was received that answered a command previously sent with - L{callRemote}, with an error. - - @param box: an L{AmpBox} with a value for its L{ERROR}, L{ERROR_CODE}, - and L{ERROR_DESCRIPTION} keys. - """ - question = self._outstandingRequests.pop(box[ERROR]) - question.addErrback(self.unhandledError) - errorCode = box[ERROR_CODE] - description = box[ERROR_DESCRIPTION] - if errorCode in PROTOCOL_ERRORS: - exc = PROTOCOL_ERRORS[errorCode](errorCode, description) - else: - exc = RemoteAmpError(errorCode, description) - question.errback(Failure(exc)) - - - def _commandReceived(self, box): - """ - @param box: an L{AmpBox} with a value for its L{COMMAND} and L{ASK} - keys. - """ - def formatAnswer(answerBox): - answerBox[ANSWER] = box[ASK] - return answerBox - def formatError(error): - if error.check(RemoteAmpError): - code = error.value.errorCode - desc = error.value.description - if error.value.fatal: - errorBox = QuitBox() - else: - errorBox = AmpBox() - else: - errorBox = QuitBox() - log.err(error) # here is where server-side logging happens - # if the error isn't handled - code = UNKNOWN_ERROR_CODE - desc = "Unknown Error" - errorBox[ERROR] = box[ASK] - errorBox[ERROR_DESCRIPTION] = desc - errorBox[ERROR_CODE] = code - return errorBox - deferred = self.dispatchCommand(box) - if ASK in box: - deferred.addCallbacks(formatAnswer, formatError) - deferred.addCallback(self._safeEmit) - deferred.addErrback(self.unhandledError) - - - def ampBoxReceived(self, box): - """ - An AmpBox was received, representing a command, or an answer to a - previously issued command (either successful or erroneous). Respond to - it according to its contents. - - @param box: an AmpBox - - @raise NoEmptyBoxes: when a box is received that does not contain an - '_answer', '_command' / '_ask', or '_error' key; i.e. one which does not - fit into the command / response protocol defined by AMP. - """ - if ANSWER in box: - self._answerReceived(box) - elif ERROR in box: - self._errorReceived(box) - elif COMMAND in box: - self._commandReceived(box) - else: - raise NoEmptyBoxes(box) - - - def _safeEmit(self, aBox): - """ - Emit a box, ignoring L{ProtocolSwitched} and L{ConnectionLost} errors - which cannot be usefully handled. - """ - try: - aBox._sendTo(self.boxSender) - except (ProtocolSwitched, ConnectionLost): - pass - - - def dispatchCommand(self, box): - """ - A box with a _command key was received. - - Dispatch it to a local handler call it. - - @param proto: an AMP instance. - @param box: an AmpBox to be dispatched. - """ - cmd = box[COMMAND] - responder = self.locator.locateResponder(cmd) - if responder is None: - return fail(RemoteAmpError( - UNHANDLED_ERROR_CODE, - "Unhandled Command: %r" % (cmd,), - False, - local=Failure(UnhandledCommand()))) - return maybeDeferred(responder, box) - - - -class CommandLocator: - """ - A L{CommandLocator} is a collection of responders to AMP L{Command}s, with - the help of the L{Command.responder} decorator. - """ - - class __metaclass__(type): - """ - This metaclass keeps track of all of the Command.responder-decorated - methods defined since the last CommandLocator subclass was defined. It - assumes (usually correctly, but unfortunately not necessarily so) that - those commands responders were all declared as methods of the class - being defined. Note that this list can be incorrect if users use the - Command.responder decorator outside the context of a CommandLocator - class declaration. - - Command responders defined on subclasses are given precedence over - those inherited from a base class. - - The Command.responder decorator explicitly cooperates with this - metaclass. - """ - - _currentClassCommands = [] - def __new__(cls, name, bases, attrs): - commands = cls._currentClassCommands[:] - cls._currentClassCommands[:] = [] - cd = attrs['_commandDispatch'] = {} - subcls = type.__new__(cls, name, bases, attrs) - ancestors = list(subcls.__mro__[1:]) - ancestors.reverse() - for ancestor in ancestors: - cd.update(getattr(ancestor, '_commandDispatch', {})) - for commandClass, responderFunc in commands: - cd[commandClass.commandName] = (commandClass, responderFunc) - if (bases and ( - subcls.lookupFunction != CommandLocator.lookupFunction)): - def locateResponder(self, name): - warnings.warn( - "Override locateResponder, not lookupFunction.", - category=PendingDeprecationWarning, - stacklevel=2) - return self.lookupFunction(name) - subcls.locateResponder = locateResponder - return subcls - - - implements(IResponderLocator) - - - def _wrapWithSerialization(self, aCallable, command): - """ - Wrap aCallable with its command's argument de-serialization - and result serialization logic. - - @param aCallable: a callable with a 'command' attribute, designed to be - called with keyword arguments. - - @param command: the command class whose serialization to use. - - @return: a 1-arg callable which, when invoked with an AmpBox, will - deserialize the argument list and invoke appropriate user code for the - callable's command, returning a Deferred which fires with the result or - fails with an error. - """ - def doit(box): - kw = command.parseArguments(box, self) - def checkKnownErrors(error): - key = error.trap(*command.allErrors) - code = command.allErrors[key] - desc = str(error.value) - return Failure(RemoteAmpError( - code, desc, key in command.fatalErrors, local=error)) - def makeResponseFor(objects): - try: - return command.makeResponse(objects, self) - except: - # let's helpfully log this. - originalFailure = Failure() - raise BadLocalReturn( - "%r returned %r and %r could not serialize it" % ( - aCallable, - objects, - command), - originalFailure) - return maybeDeferred(aCallable, **kw).addCallback( - makeResponseFor).addErrback( - checkKnownErrors) - return doit - - - def lookupFunction(self, name): - """ - Deprecated synonym for L{locateResponder} - """ - if self.__class__.lookupFunction != CommandLocator.lookupFunction: - return CommandLocator.locateResponder(self, name) - else: - warnings.warn("Call locateResponder, not lookupFunction.", - category=PendingDeprecationWarning, - stacklevel=2) - return self.locateResponder(name) - - - def locateResponder(self, name): - """ - Locate a callable to invoke when executing the named command. - - @param name: the normalized name (from the wire) of the command. - - @return: a 1-argument function that takes a Box and returns a box or a - Deferred which fires a Box, for handling the command identified by the - given name, or None, if no appropriate responder can be found. - """ - # Try to find a high-level method to invoke, and if we can't find one, - # fall back to a low-level one. - cd = self._commandDispatch - if name in cd: - commandClass, responderFunc = cd[name] - responderMethod = types.MethodType( - responderFunc, self, self.__class__) - return self._wrapWithSerialization(responderMethod, commandClass) - - - -class SimpleStringLocator(object): - """ - Implement the L{locateResponder} method to do simple, string-based - dispatch. - """ - - implements(IResponderLocator) - - baseDispatchPrefix = 'amp_' - - def locateResponder(self, name): - """ - Locate a callable to invoke when executing the named command. - - @return: a function with the name C{"amp_" + name} on L{self}, or None - if no such function exists. This function will then be called with the - L{AmpBox} itself as an argument. - - @param name: the normalized name (from the wire) of the command. - """ - fName = self.baseDispatchPrefix + (name.upper()) - return getattr(self, fName, None) - - - -PYTHON_KEYWORDS = [ - 'and', 'del', 'for', 'is', 'raise', 'assert', 'elif', 'from', 'lambda', - 'return', 'break', 'else', 'global', 'not', 'try', 'class', 'except', - 'if', 'or', 'while', 'continue', 'exec', 'import', 'pass', 'yield', - 'def', 'finally', 'in', 'print'] - - - -def _wireNameToPythonIdentifier(key): - """ - (Private) Normalize an argument name from the wire for use with Python - code. If the return value is going to be a python keyword it will be - capitalized. If it contains any dashes they will be replaced with - underscores. - - The rationale behind this method is that AMP should be an inherently - multi-language protocol, so message keys may contain all manner of bizarre - bytes. This is not a complete solution; there are still forms of arguments - that this implementation will be unable to parse. However, Python - identifiers share a huge raft of properties with identifiers from many - other languages, so this is a 'good enough' effort for now. We deal - explicitly with dashes because that is the most likely departure: Lisps - commonly use dashes to separate method names, so protocols initially - implemented in a lisp amp dialect may use dashes in argument or command - names. - - @param key: a str, looking something like 'foo-bar-baz' or 'from' - - @return: a str which is a valid python identifier, looking something like - 'foo_bar_baz' or 'From'. - """ - lkey = key.replace("-", "_") - if lkey in PYTHON_KEYWORDS: - return lkey.title() - return lkey - - - -class Argument: - """ - Base-class of all objects that take values from Amp packets and convert - them into objects for Python functions. - - This implementation of L{IArgumentType} provides several higher-level - hooks for subclasses to override. See L{toString} and L{fromString} - which will be used to define the behavior of L{IArgumentType.toBox} and - L{IArgumentType.fromBox}, respectively. - """ - implements(IArgumentType) - - optional = False - - - def __init__(self, optional=False): - """ - Create an Argument. - - @param optional: a boolean indicating whether this argument can be - omitted in the protocol. - """ - self.optional = optional - - - def retrieve(self, d, name, proto): - """ - Retrieve the given key from the given dictionary, removing it if found. - - @param d: a dictionary. - - @param name: a key in L{d}. - - @param proto: an instance of an AMP. - - @raise KeyError: if I am not optional and no value was found. - - @return: d[name]. - """ - if self.optional: - value = d.get(name) - if value is not None: - del d[name] - else: - value = d.pop(name) - return value - - - def fromBox(self, name, strings, objects, proto): - """ - Populate an 'out' dictionary with mapping names to Python values - decoded from an 'in' AmpBox mapping strings to string values. - - @param name: the argument name to retrieve - @type name: str - - @param strings: The AmpBox to read string(s) from, a mapping of - argument names to string values. - @type strings: AmpBox - - @param objects: The dictionary to write object(s) to, a mapping of - names to Python objects. - @type objects: dict - - @param proto: an AMP instance. - """ - st = self.retrieve(strings, name, proto) - nk = _wireNameToPythonIdentifier(name) - if self.optional and st is None: - objects[nk] = None - else: - objects[nk] = self.fromStringProto(st, proto) - - - def toBox(self, name, strings, objects, proto): - """ - Populate an 'out' AmpBox with strings encoded from an 'in' dictionary - mapping names to Python values. - - @param name: the argument name to retrieve - @type name: str - - @param strings: The AmpBox to write string(s) to, a mapping of - argument names to string values. - @type strings: AmpBox - - @param objects: The dictionary to read object(s) from, a mapping of - names to Python objects. - - @type objects: dict - - @param proto: the protocol we are converting for. - @type proto: AMP - """ - obj = self.retrieve(objects, _wireNameToPythonIdentifier(name), proto) - if self.optional and obj is None: - # strings[name] = None - pass - else: - strings[name] = self.toStringProto(obj, proto) - - - def fromStringProto(self, inString, proto): - """ - Convert a string to a Python value. - - @param inString: the string to convert. - - @param proto: the protocol we are converting for. - @type proto: AMP - - @return: a Python object. - """ - return self.fromString(inString) - - - def toStringProto(self, inObject, proto): - """ - Convert a Python object to a string. - - @param inObject: the object to convert. - - @param proto: the protocol we are converting for. - @type proto: AMP - """ - return self.toString(inObject) - - - def fromString(self, inString): - """ - Convert a string to a Python object. Subclasses must implement this. - - @param inString: the string to convert. - @type inString: str - - @return: the decoded value from inString - """ - - - def toString(self, inObject): - """ - Convert a Python object into a string for passing over the network. - - @param inObject: an object of the type that this Argument is intended - to deal with. - - @return: the wire encoding of inObject - @rtype: str - """ - - - -class Integer(Argument): - """ - Encode any integer values of any size on the wire as the string - representation. - - Example: C{123} becomes C{"123"} - """ - fromString = int - def toString(self, inObject): - return str(int(inObject)) - - - -class String(Argument): - """ - Don't do any conversion at all; just pass through 'str'. - """ - def toString(self, inObject): - return inObject - - - def fromString(self, inString): - return inString - - - -class Float(Argument): - """ - Encode floating-point values on the wire as their repr. - """ - fromString = float - toString = repr - - - -class Boolean(Argument): - """ - Encode True or False as "True" or "False" on the wire. - """ - def fromString(self, inString): - if inString == 'True': - return True - elif inString == 'False': - return False - else: - raise TypeError("Bad boolean value: %r" % (inString,)) - - - def toString(self, inObject): - if inObject: - return 'True' - else: - return 'False' - - - -class Unicode(String): - """ - Encode a unicode string on the wire as UTF-8. - """ - - def toString(self, inObject): - # assert isinstance(inObject, unicode) - return String.toString(self, inObject.encode('utf-8')) - - - def fromString(self, inString): - # assert isinstance(inString, str) - return String.fromString(self, inString).decode('utf-8') - - - -class Path(Unicode): - """ - Encode and decode L{filepath.FilePath} instances as paths on the wire. - - This is really intended for use with subprocess communication tools: - exchanging pathnames on different machines over a network is not generally - meaningful, but neither is it disallowed; you can use this to communicate - about NFS paths, for example. - """ - def fromString(self, inString): - return filepath.FilePath(Unicode.fromString(self, inString)) - - - def toString(self, inObject): - return Unicode.toString(self, inObject.path) - - - -class ListOf(Argument): - """ - Encode and decode lists of instances of a single other argument type. - - For example, if you want to pass:: - - [3, 7, 9, 15] - - You can create an argument like this:: - - ListOf(Integer()) - - The serialized form of the entire list is subject to the limit imposed by - L{MAX_VALUE_LENGTH}. List elements are represented as 16-bit length - prefixed strings. The argument type passed to the L{ListOf} initializer is - responsible for producing the serialized form of each element. - - @ivar elementType: The L{Argument} instance used to encode and decode list - elements (note, not an arbitrary L{IArgument} implementation: - arguments must be implemented using only the C{fromString} and - C{toString} methods, not the C{fromBox} and C{toBox} methods). - - @param optional: a boolean indicating whether this argument can be - omitted in the protocol. - - @since: 10.0 - """ - def __init__(self, elementType, optional=False): - self.elementType = elementType - Argument.__init__(self, optional) - - - def fromString(self, inString): - """ - Convert the serialized form of a list of instances of some type back - into that list. - """ - strings = [] - parser = Int16StringReceiver() - parser.stringReceived = strings.append - parser.dataReceived(inString) - return map(self.elementType.fromString, strings) - - - def toString(self, inObject): - """ - Serialize the given list of objects to a single string. - """ - strings = [] - for obj in inObject: - serialized = self.elementType.toString(obj) - strings.append(pack('!H', len(serialized))) - strings.append(serialized) - return ''.join(strings) - - - -class AmpList(Argument): - """ - Convert a list of dictionaries into a list of AMP boxes on the wire. - - For example, if you want to pass:: - - [{'a': 7, 'b': u'hello'}, {'a': 9, 'b': u'goodbye'}] - - You might use an AmpList like this in your arguments or response list:: - - AmpList([('a', Integer()), - ('b', Unicode())]) - """ - def __init__(self, subargs, optional=False): - """ - Create an AmpList. - - @param subargs: a list of 2-tuples of ('name', argument) describing the - schema of the dictionaries in the sequence of amp boxes. - - @param optional: a boolean indicating whether this argument can be - omitted in the protocol. - """ - self.subargs = subargs - Argument.__init__(self, optional) - - - def fromStringProto(self, inString, proto): - boxes = parseString(inString) - values = [_stringsToObjects(box, self.subargs, proto) - for box in boxes] - return values - - - def toStringProto(self, inObject, proto): - return ''.join([_objectsToStrings( - objects, self.subargs, Box(), proto - ).serialize() for objects in inObject]) - - - -class Descriptor(Integer): - """ - Encode and decode file descriptors for exchange over a UNIX domain socket. - - This argument type requires an AMP connection set up over an - L{IUNIXTransport} provider (for - example, the kind of connection created by - L{IReactorUNIX.connectUNIX} - and L{UNIXClientEndpoint}). - - There is no correspondence between the integer value of the file descriptor - on the sending and receiving sides, therefore an alternate approach is taken - to matching up received descriptors with particular L{Descriptor} - parameters. The argument is encoded to an ordinal (unique per connection) - for inclusion in the AMP command or response box. The descriptor itself is - sent using - L{IUNIXTransport.sendFileDescriptor}. - The receiver uses the order in which file descriptors are received and the - ordinal value to come up with the received copy of the descriptor. - """ - def fromStringProto(self, inString, proto): - """ - Take a unique identifier associated with a file descriptor which must - have been received by now and use it to look up that descriptor in a - dictionary where they are kept. - - @param inString: The base representation (as a byte string) of an - ordinal indicating which file descriptor corresponds to this usage - of this argument. - @type inString: C{str} - - @param proto: The protocol used to receive this descriptor. This - protocol must be connected via a transport providing - L{IUNIXTransport}. - @type proto: L{BinaryBoxProtocol} - - @return: The file descriptor represented by C{inString}. - @rtype: C{int} - """ - return proto._getDescriptor(int(inString)) - - - def toStringProto(self, inObject, proto): - """ - Send C{inObject}, an integer file descriptor, over C{proto}'s connection - and return a unique identifier which will allow the receiver to - associate the file descriptor with this argument. - - @param inObject: A file descriptor to duplicate over an AMP connection - as the value for this argument. - @type inObject: C{int} - - @param proto: The protocol which will be used to send this descriptor. - This protocol must be connected via a transport providing - L{IUNIXTransport}. - - @return: A byte string which can be used by the receiver to reconstruct - the file descriptor. - @type: C{str} - """ - identifier = proto._sendFileDescriptor(inObject) - outString = Integer.toStringProto(self, identifier, proto) - return outString - - - -class Command: - """ - Subclass me to specify an AMP Command. - - @cvar arguments: A list of 2-tuples of (name, Argument-subclass-instance), - specifying the names and values of the parameters which are required for - this command. - - @cvar response: A list like L{arguments}, but instead used for the return - value. - - @cvar errors: A mapping of subclasses of L{Exception} to wire-protocol tags - for errors represented as L{str}s. Responders which raise keys from this - dictionary will have the error translated to the corresponding tag on the - wire. Invokers which receive Deferreds from invoking this command with - L{AMP.callRemote} will potentially receive Failures with keys from this - mapping as their value. This mapping is inherited; if you declare a - command which handles C{FooError} as 'FOO_ERROR', then subclass it and - specify C{BarError} as 'BAR_ERROR', responders to the subclass may raise - either C{FooError} or C{BarError}, and invokers must be able to deal with - either of those exceptions. - - @cvar fatalErrors: like 'errors', but errors in this list will always - terminate the connection, despite being of a recognizable error type. - - @cvar commandType: The type of Box used to issue commands; useful only for - protocol-modifying behavior like startTLS or protocol switching. Defaults - to a plain vanilla L{Box}. - - @cvar responseType: The type of Box used to respond to this command; only - useful for protocol-modifying behavior like startTLS or protocol switching. - Defaults to a plain vanilla L{Box}. - - @ivar requiresAnswer: a boolean; defaults to True. Set it to False on your - subclass if you want callRemote to return None. Note: this is a hint only - to the client side of the protocol. The return-type of a command responder - method must always be a dictionary adhering to the contract specified by - L{response}, because clients are always free to request a response if they - want one. - """ - - class __metaclass__(type): - """ - Metaclass hack to establish reverse-mappings for 'errors' and - 'fatalErrors' as class vars. - """ - def __new__(cls, name, bases, attrs): - reverseErrors = attrs['reverseErrors'] = {} - er = attrs['allErrors'] = {} - if 'commandName' not in attrs: - attrs['commandName'] = name - newtype = type.__new__(cls, name, bases, attrs) - errors = {} - fatalErrors = {} - accumulateClassDict(newtype, 'errors', errors) - accumulateClassDict(newtype, 'fatalErrors', fatalErrors) - for v, k in errors.iteritems(): - reverseErrors[k] = v - er[v] = k - for v, k in fatalErrors.iteritems(): - reverseErrors[k] = v - er[v] = k - return newtype - - arguments = [] - response = [] - extra = [] - errors = {} - fatalErrors = {} - - commandType = Box - responseType = Box - - requiresAnswer = True - - - def __init__(self, **kw): - """ - Create an instance of this command with specified values for its - parameters. - - @param kw: a dict containing an appropriate value for each name - specified in the L{arguments} attribute of my class. - - @raise InvalidSignature: if you forgot any required arguments. - """ - self.structured = kw - givenArgs = kw.keys() - forgotten = [] - for name, arg in self.arguments: - pythonName = _wireNameToPythonIdentifier(name) - if pythonName not in givenArgs and not arg.optional: - forgotten.append(pythonName) - if forgotten: - raise InvalidSignature("forgot %s for %s" % ( - ', '.join(forgotten), self.commandName)) - forgotten = [] - - - def makeResponse(cls, objects, proto): - """ - Serialize a mapping of arguments using this L{Command}'s - response schema. - - @param objects: a dict with keys matching the names specified in - self.response, having values of the types that the Argument objects in - self.response can format. - - @param proto: an L{AMP}. - - @return: an L{AmpBox}. - """ - try: - responseType = cls.responseType() - except: - return fail() - return _objectsToStrings(objects, cls.response, responseType, proto) - makeResponse = classmethod(makeResponse) - - - def makeArguments(cls, objects, proto): - """ - Serialize a mapping of arguments using this L{Command}'s - argument schema. - - @param objects: a dict with keys similar to the names specified in - self.arguments, having values of the types that the Argument objects in - self.arguments can parse. - - @param proto: an L{AMP}. - - @return: An instance of this L{Command}'s C{commandType}. - """ - allowedNames = set() - for (argName, ignored) in cls.arguments: - allowedNames.add(_wireNameToPythonIdentifier(argName)) - - for intendedArg in objects: - if intendedArg not in allowedNames: - raise InvalidSignature( - "%s is not a valid argument" % (intendedArg,)) - return _objectsToStrings(objects, cls.arguments, cls.commandType(), - proto) - makeArguments = classmethod(makeArguments) - - - def parseResponse(cls, box, protocol): - """ - Parse a mapping of serialized arguments using this - L{Command}'s response schema. - - @param box: A mapping of response-argument names to the - serialized forms of those arguments. - @param protocol: The L{AMP} protocol. - - @return: A mapping of response-argument names to the parsed - forms. - """ - return _stringsToObjects(box, cls.response, protocol) - parseResponse = classmethod(parseResponse) - - - def parseArguments(cls, box, protocol): - """ - Parse a mapping of serialized arguments using this - L{Command}'s argument schema. - - @param box: A mapping of argument names to the seralized forms - of those arguments. - @param protocol: The L{AMP} protocol. - - @return: A mapping of argument names to the parsed forms. - """ - return _stringsToObjects(box, cls.arguments, protocol) - parseArguments = classmethod(parseArguments) - - - def responder(cls, methodfunc): - """ - Declare a method to be a responder for a particular command. - - This is a decorator. - - Use like so:: - - class MyCommand(Command): - arguments = [('a', ...), ('b', ...)] - - class MyProto(AMP): - def myFunMethod(self, a, b): - ... - MyCommand.responder(myFunMethod) - - Notes: Although decorator syntax is not used within Twisted, this - function returns its argument and is therefore safe to use with - decorator syntax. - - This is not thread safe. Don't declare AMP subclasses in other - threads. Don't declare responders outside the scope of AMP subclasses; - the behavior is undefined. - - @param methodfunc: A function which will later become a method, which - has a keyword signature compatible with this command's L{argument} list - and returns a dictionary with a set of keys compatible with this - command's L{response} list. - - @return: the methodfunc parameter. - """ - CommandLocator._currentClassCommands.append((cls, methodfunc)) - return methodfunc - responder = classmethod(responder) - - - # Our only instance method - def _doCommand(self, proto): - """ - Encode and send this Command to the given protocol. - - @param proto: an AMP, representing the connection to send to. - - @return: a Deferred which will fire or error appropriately when the - other side responds to the command (or error if the connection is lost - before it is responded to). - """ - - def _massageError(error): - error.trap(RemoteAmpError) - rje = error.value - errorType = self.reverseErrors.get(rje.errorCode, - UnknownRemoteError) - return Failure(errorType(rje.description)) - - d = proto._sendBoxCommand(self.commandName, - self.makeArguments(self.structured, proto), - self.requiresAnswer) - - if self.requiresAnswer: - d.addCallback(self.parseResponse, proto) - d.addErrback(_massageError) - - return d - - - -class _NoCertificate: - """ - This is for peers which don't want to use a local certificate. Used by - AMP because AMP's internal language is all about certificates and this - duck-types in the appropriate place; this API isn't really stable though, - so it's not exposed anywhere public. - - For clients, it will use ephemeral DH keys, or whatever the default is for - certificate-less clients in OpenSSL. For servers, it will generate a - temporary self-signed certificate with garbage values in the DN and use - that. - """ - - def __init__(self, client): - """ - Create a _NoCertificate which either is or isn't for the client side of - the connection. - - @param client: True if we are a client and should truly have no - certificate and be anonymous, False if we are a server and actually - have to generate a temporary certificate. - - @type client: bool - """ - self.client = client - - - def options(self, *authorities): - """ - Behaves like L{twisted.internet.ssl.PrivateCertificate.options}(). - """ - if not self.client: - # do some crud with sslverify to generate a temporary self-signed - # certificate. This is SLOOOWWWWW so it is only in the absolute - # worst, most naive case. - - # We have to do this because OpenSSL will not let both the server - # and client be anonymous. - sharedDN = DN(CN='TEMPORARY CERTIFICATE') - key = KeyPair.generate() - cr = key.certificateRequest(sharedDN) - sscrd = key.signCertificateRequest(sharedDN, cr, lambda dn: True, 1) - cert = key.newCertificate(sscrd) - return cert.options(*authorities) - options = dict() - if authorities: - options.update(dict(verify=True, - requireCertificate=True, - caCerts=[auth.original for auth in authorities])) - occo = CertificateOptions(**options) - return occo - - - -class _TLSBox(AmpBox): - """ - I am an AmpBox that, upon being sent, initiates a TLS connection. - """ - __slots__ = [] - - def __init__(self): - if ssl is None: - raise RemoteAmpError("TLS_ERROR", "TLS not available") - AmpBox.__init__(self) - - - def _keyprop(k, default): - return property(lambda self: self.get(k, default)) - - - # These properties are described in startTLS - certificate = _keyprop('tls_localCertificate', _NoCertificate(False)) - verify = _keyprop('tls_verifyAuthorities', None) - - def _sendTo(self, proto): - """ - Send my encoded value to the protocol, then initiate TLS. - """ - ab = AmpBox(self) - for k in ['tls_localCertificate', - 'tls_verifyAuthorities']: - ab.pop(k, None) - ab._sendTo(proto) - proto._startTLS(self.certificate, self.verify) - - - -class _LocalArgument(String): - """ - Local arguments are never actually relayed across the wire. This is just a - shim so that StartTLS can pretend to have some arguments: if arguments - acquire documentation properties, replace this with something nicer later. - """ - - def fromBox(self, name, strings, objects, proto): - pass - - - -class StartTLS(Command): - """ - Use, or subclass, me to implement a command that starts TLS. - - Callers of StartTLS may pass several special arguments, which affect the - TLS negotiation: - - - tls_localCertificate: This is a - twisted.internet.ssl.PrivateCertificate which will be used to secure - the side of the connection it is returned on. - - - tls_verifyAuthorities: This is a list of - twisted.internet.ssl.Certificate objects that will be used as the - certificate authorities to verify our peer's certificate. - - Each of those special parameters may also be present as a key in the - response dictionary. - """ - - arguments = [("tls_localCertificate", _LocalArgument(optional=True)), - ("tls_verifyAuthorities", _LocalArgument(optional=True))] - - response = [("tls_localCertificate", _LocalArgument(optional=True)), - ("tls_verifyAuthorities", _LocalArgument(optional=True))] - - responseType = _TLSBox - - def __init__(self, **kw): - """ - Create a StartTLS command. (This is private. Use AMP.callRemote.) - - @param tls_localCertificate: the PrivateCertificate object to use to - secure the connection. If it's None, or unspecified, an ephemeral DH - key is used instead. - - @param tls_verifyAuthorities: a list of Certificate objects which - represent root certificates to verify our peer with. - """ - if ssl is None: - raise RuntimeError("TLS not available.") - self.certificate = kw.pop('tls_localCertificate', _NoCertificate(True)) - self.authorities = kw.pop('tls_verifyAuthorities', None) - Command.__init__(self, **kw) - - - def _doCommand(self, proto): - """ - When a StartTLS command is sent, prepare to start TLS, but don't actually - do it; wait for the acknowledgement, then initiate the TLS handshake. - """ - d = Command._doCommand(self, proto) - proto._prepareTLS(self.certificate, self.authorities) - # XXX before we get back to user code we are going to start TLS... - def actuallystart(response): - proto._startTLS(self.certificate, self.authorities) - return response - d.addCallback(actuallystart) - return d - - - -class ProtocolSwitchCommand(Command): - """ - Use this command to switch from something Amp-derived to a different - protocol mid-connection. This can be useful to use amp as the - connection-startup negotiation phase. Since TLS is a different layer - entirely, you can use Amp to negotiate the security parameters of your - connection, then switch to a different protocol, and the connection will - remain secured. - """ - - def __init__(self, _protoToSwitchToFactory, **kw): - """ - Create a ProtocolSwitchCommand. - - @param _protoToSwitchToFactory: a ProtocolFactory which will generate - the Protocol to switch to. - - @param kw: Keyword arguments, encoded and handled normally as - L{Command} would. - """ - - self.protoToSwitchToFactory = _protoToSwitchToFactory - super(ProtocolSwitchCommand, self).__init__(**kw) - - - def makeResponse(cls, innerProto, proto): - return _SwitchBox(innerProto) - makeResponse = classmethod(makeResponse) - - - def _doCommand(self, proto): - """ - When we emit a ProtocolSwitchCommand, lock the protocol, but don't actually - switch to the new protocol unless an acknowledgement is received. If - an error is received, switch back. - """ - d = super(ProtocolSwitchCommand, self)._doCommand(proto) - proto._lockForSwitch() - def switchNow(ign): - innerProto = self.protoToSwitchToFactory.buildProtocol( - proto.transport.getPeer()) - proto._switchTo(innerProto, self.protoToSwitchToFactory) - return ign - def handle(ign): - proto._unlockFromSwitch() - self.protoToSwitchToFactory.clientConnectionFailed( - None, Failure(CONNECTION_LOST)) - return ign - return d.addCallbacks(switchNow, handle) - - - -class _DescriptorExchanger(object): - """ - L{_DescriptorExchanger} is a mixin for L{BinaryBoxProtocol} which adds - support for receiving file descriptors, a feature offered by - L{IUNIXTransport}. - - @ivar _descriptors: Temporary storage for all file descriptors received. - Values in this dictionary are the file descriptors (as integers). Keys - in this dictionary are ordinals giving the order in which each - descriptor was received. The ordering information is used to allow - L{Descriptor} to determine which is the correct descriptor for any - particular usage of that argument type. - @type _descriptors: C{dict} - - @ivar _sendingDescriptorCounter: A no-argument callable which returns the - ordinals, starting from 0. This is used to construct values for - C{_sendFileDescriptor}. - - @ivar _receivingDescriptorCounter: A no-argument callable which returns the - ordinals, starting from 0. This is used to construct values for - C{fileDescriptorReceived}. - """ - implements(IFileDescriptorReceiver) - - def __init__(self): - self._descriptors = {} - self._getDescriptor = self._descriptors.pop - self._sendingDescriptorCounter = count().next - self._receivingDescriptorCounter = count().next - - - def _sendFileDescriptor(self, descriptor): - """ - Assign and return the next ordinal to the given descriptor after sending - the descriptor over this protocol's transport. - """ - self.transport.sendFileDescriptor(descriptor) - return self._sendingDescriptorCounter() - - - def fileDescriptorReceived(self, descriptor): - """ - Collect received file descriptors to be claimed later by L{Descriptor}. - - @param descriptor: The received file descriptor. - @type descriptor: C{int} - """ - self._descriptors[self._receivingDescriptorCounter()] = descriptor - - - -class BinaryBoxProtocol(StatefulStringProtocol, Int16StringReceiver, - _DescriptorExchanger): - """ - A protocol for receiving L{AmpBox}es - key/value pairs - via length-prefixed - strings. A box is composed of: - - - any number of key-value pairs, described by: - - a 2-byte network-endian packed key length (of which the first - byte must be null, and the second must be non-null: i.e. the - value of the length must be 1-255) - - a key, comprised of that many bytes - - a 2-byte network-endian unsigned value length (up to the maximum - of 65535) - - a value, comprised of that many bytes - - 2 null bytes - - In other words, an even number of strings prefixed with packed unsigned - 16-bit integers, and then a 0-length string to indicate the end of the box. - - This protocol also implements 2 extra private bits of functionality related - to the byte boundaries between messages; it can start TLS between two given - boxes or switch to an entirely different protocol. However, due to some - tricky elements of the implementation, the public interface to this - functionality is L{ProtocolSwitchCommand} and L{StartTLS}. - - @ivar _keyLengthLimitExceeded: A flag which is only true when the - connection is being closed because a key length prefix which was longer - than allowed by the protocol was received. - - @ivar boxReceiver: an L{IBoxReceiver} provider, whose L{ampBoxReceived} - method will be invoked for each L{AmpBox} that is received. - """ - - implements(IBoxSender) - - _justStartedTLS = False - _startingTLSBuffer = None - _locked = False - _currentKey = None - _currentBox = None - - _keyLengthLimitExceeded = False - - hostCertificate = None - noPeerCertificate = False # for tests - innerProtocol = None - innerProtocolClientFactory = None - - def __init__(self, boxReceiver): - _DescriptorExchanger.__init__(self) - self.boxReceiver = boxReceiver - - - def _switchTo(self, newProto, clientFactory=None): - """ - Switch this BinaryBoxProtocol's transport to a new protocol. You need - to do this 'simultaneously' on both ends of a connection; the easiest - way to do this is to use a subclass of ProtocolSwitchCommand. - - @param newProto: the new protocol instance to switch to. - - @param clientFactory: the ClientFactory to send the - L{clientConnectionLost} notification to. - """ - # All the data that Int16Receiver has not yet dealt with belongs to our - # new protocol: luckily it's keeping that in a handy (although - # ostensibly internal) variable for us: - newProtoData = self.recvd - # We're quite possibly in the middle of a 'dataReceived' loop in - # Int16StringReceiver: let's make sure that the next iteration, the - # loop will break and not attempt to look at something that isn't a - # length prefix. - self.recvd = '' - # Finally, do the actual work of setting up the protocol and delivering - # its first chunk of data, if one is available. - self.innerProtocol = newProto - self.innerProtocolClientFactory = clientFactory - newProto.makeConnection(self.transport) - if newProtoData: - newProto.dataReceived(newProtoData) - - - def sendBox(self, box): - """ - Send a amp.Box to my peer. - - Note: transport.write is never called outside of this method. - - @param box: an AmpBox. - - @raise ProtocolSwitched: if the protocol has previously been switched. - - @raise ConnectionLost: if the connection has previously been lost. - """ - if self._locked: - raise ProtocolSwitched( - "This connection has switched: no AMP traffic allowed.") - if self.transport is None: - raise ConnectionLost() - if self._startingTLSBuffer is not None: - self._startingTLSBuffer.append(box) - else: - self.transport.write(box.serialize()) - - - def makeConnection(self, transport): - """ - Notify L{boxReceiver} that it is about to receive boxes from this - protocol by invoking L{startReceivingBoxes}. - """ - self.transport = transport - self.boxReceiver.startReceivingBoxes(self) - self.connectionMade() - - - def dataReceived(self, data): - """ - Either parse incoming data as L{AmpBox}es or relay it to our nested - protocol. - """ - if self._justStartedTLS: - self._justStartedTLS = False - # If we already have an inner protocol, then we don't deliver data to - # the protocol parser any more; we just hand it off. - if self.innerProtocol is not None: - self.innerProtocol.dataReceived(data) - return - return Int16StringReceiver.dataReceived(self, data) - - - def connectionLost(self, reason): - """ - The connection was lost; notify any nested protocol. - """ - if self.innerProtocol is not None: - self.innerProtocol.connectionLost(reason) - if self.innerProtocolClientFactory is not None: - self.innerProtocolClientFactory.clientConnectionLost(None, reason) - if self._keyLengthLimitExceeded: - failReason = Failure(TooLong(True, False, None, None)) - elif reason.check(ConnectionClosed) and self._justStartedTLS: - # We just started TLS and haven't received any data. This means - # the other connection didn't like our cert (although they may not - # have told us why - later Twisted should make 'reason' into a TLS - # error.) - failReason = PeerVerifyError( - "Peer rejected our certificate for an unknown reason.") - else: - failReason = reason - self.boxReceiver.stopReceivingBoxes(failReason) - - - # The longest key allowed - _MAX_KEY_LENGTH = 255 - - # The longest value allowed (this is somewhat redundant, as longer values - # cannot be encoded - ah well). - _MAX_VALUE_LENGTH = 65535 - - # The first thing received is a key. - MAX_LENGTH = _MAX_KEY_LENGTH - - def proto_init(self, string): - """ - String received in the 'init' state. - """ - self._currentBox = AmpBox() - return self.proto_key(string) - - - def proto_key(self, string): - """ - String received in the 'key' state. If the key is empty, a complete - box has been received. - """ - if string: - self._currentKey = string - self.MAX_LENGTH = self._MAX_VALUE_LENGTH - return 'value' - else: - self.boxReceiver.ampBoxReceived(self._currentBox) - self._currentBox = None - return 'init' - - - def proto_value(self, string): - """ - String received in the 'value' state. - """ - self._currentBox[self._currentKey] = string - self._currentKey = None - self.MAX_LENGTH = self._MAX_KEY_LENGTH - return 'key' - - - def lengthLimitExceeded(self, length): - """ - The key length limit was exceeded. Disconnect the transport and make - sure a meaningful exception is reported. - """ - self._keyLengthLimitExceeded = True - self.transport.loseConnection() - - - def _lockForSwitch(self): - """ - Lock this binary protocol so that no further boxes may be sent. This - is used when sending a request to switch underlying protocols. You - probably want to subclass ProtocolSwitchCommand rather than calling - this directly. - """ - self._locked = True - - - def _unlockFromSwitch(self): - """ - Unlock this locked binary protocol so that further boxes may be sent - again. This is used after an attempt to switch protocols has failed - for some reason. - """ - if self.innerProtocol is not None: - raise ProtocolSwitched("Protocol already switched. Cannot unlock.") - self._locked = False - - - def _prepareTLS(self, certificate, verifyAuthorities): - """ - Used by StartTLSCommand to put us into the state where we don't - actually send things that get sent, instead we buffer them. see - L{_sendBox}. - """ - self._startingTLSBuffer = [] - if self.hostCertificate is not None: - raise OnlyOneTLS( - "Previously authenticated connection between %s and %s " - "is trying to re-establish as %s" % ( - self.hostCertificate, - self.peerCertificate, - (certificate, verifyAuthorities))) - - - def _startTLS(self, certificate, verifyAuthorities): - """ - Used by TLSBox to initiate the SSL handshake. - - @param certificate: a L{twisted.internet.ssl.PrivateCertificate} for - use locally. - - @param verifyAuthorities: L{twisted.internet.ssl.Certificate} instances - representing certificate authorities which will verify our peer. - """ - self.hostCertificate = certificate - self._justStartedTLS = True - if verifyAuthorities is None: - verifyAuthorities = () - self.transport.startTLS(certificate.options(*verifyAuthorities)) - stlsb = self._startingTLSBuffer - if stlsb is not None: - self._startingTLSBuffer = None - for box in stlsb: - self.sendBox(box) - - - def _getPeerCertificate(self): - if self.noPeerCertificate: - return None - return Certificate.peerFromTransport(self.transport) - peerCertificate = property(_getPeerCertificate) - - - def unhandledError(self, failure): - """ - The buck stops here. This error was completely unhandled, time to - terminate the connection. - """ - log.err( - failure, - "Amp server or network failure unhandled by client application. " - "Dropping connection! To avoid, add errbacks to ALL remote " - "commands!") - if self.transport is not None: - self.transport.loseConnection() - - - def _defaultStartTLSResponder(self): - """ - The default TLS responder doesn't specify any certificate or anything. - - From a security perspective, it's little better than a plain-text - connection - but it is still a *bit* better, so it's included for - convenience. - - You probably want to override this by providing your own StartTLS.responder. - """ - return {} - StartTLS.responder(_defaultStartTLSResponder) - - - -class AMP(BinaryBoxProtocol, BoxDispatcher, - CommandLocator, SimpleStringLocator): - """ - This protocol is an AMP connection. See the module docstring for protocol - details. - """ - - _ampInitialized = False - - def __init__(self, boxReceiver=None, locator=None): - # For backwards compatibility. When AMP did not separate parsing logic - # (L{BinaryBoxProtocol}), request-response logic (L{BoxDispatcher}) and - # command routing (L{CommandLocator}), it did not have a constructor. - # Now it does, so old subclasses might have defined their own that did - # not upcall. If this flag isn't set, we'll call the constructor in - # makeConnection before anything actually happens. - self._ampInitialized = True - if boxReceiver is None: - boxReceiver = self - if locator is None: - locator = self - BoxDispatcher.__init__(self, locator) - BinaryBoxProtocol.__init__(self, boxReceiver) - - - def locateResponder(self, name): - """ - Unify the implementations of L{CommandLocator} and - L{SimpleStringLocator} to perform both kinds of dispatch, preferring - L{CommandLocator}. - """ - firstResponder = CommandLocator.locateResponder(self, name) - if firstResponder is not None: - return firstResponder - secondResponder = SimpleStringLocator.locateResponder(self, name) - return secondResponder - - - def __repr__(self): - """ - A verbose string representation which gives us information about this - AMP connection. - """ - if self.innerProtocol is not None: - innerRepr = ' inner %r' % (self.innerProtocol,) - else: - innerRepr = '' - return '<%s%s at 0x%x>' % ( - self.__class__.__name__, innerRepr, id(self)) - - - def makeConnection(self, transport): - """ - Emit a helpful log message when the connection is made. - """ - if not self._ampInitialized: - # See comment in the constructor re: backward compatibility. I - # should probably emit a deprecation warning here. - AMP.__init__(self) - # Save these so we can emit a similar log message in L{connectionLost}. - self._transportPeer = transport.getPeer() - self._transportHost = transport.getHost() - log.msg("%s connection established (HOST:%s PEER:%s)" % ( - self.__class__.__name__, - self._transportHost, - self._transportPeer)) - BinaryBoxProtocol.makeConnection(self, transport) - - - def connectionLost(self, reason): - """ - Emit a helpful log message when the connection is lost. - """ - log.msg("%s connection lost (HOST:%s PEER:%s)" % - (self.__class__.__name__, - self._transportHost, - self._transportPeer)) - BinaryBoxProtocol.connectionLost(self, reason) - self.transport = None - - - -class _ParserHelper: - """ - A box receiver which records all boxes received. - """ - def __init__(self): - self.boxes = [] - - - def getPeer(self): - return 'string' - - - def getHost(self): - return 'string' - - disconnecting = False - - - def startReceivingBoxes(self, sender): - """ - No initialization is required. - """ - - - def ampBoxReceived(self, box): - self.boxes.append(box) - - - # Synchronous helpers - def parse(cls, fileObj): - """ - Parse some amp data stored in a file. - - @param fileObj: a file-like object. - - @return: a list of AmpBoxes encoded in the given file. - """ - parserHelper = cls() - bbp = BinaryBoxProtocol(boxReceiver=parserHelper) - bbp.makeConnection(parserHelper) - bbp.dataReceived(fileObj.read()) - return parserHelper.boxes - parse = classmethod(parse) - - - def parseString(cls, data): - """ - Parse some amp data stored in a string. - - @param data: a str holding some amp-encoded data. - - @return: a list of AmpBoxes encoded in the given string. - """ - return cls.parse(StringIO(data)) - parseString = classmethod(parseString) - - - -parse = _ParserHelper.parse -parseString = _ParserHelper.parseString - -def _stringsToObjects(strings, arglist, proto): - """ - Convert an AmpBox to a dictionary of python objects, converting through a - given arglist. - - @param strings: an AmpBox (or dict of strings) - - @param arglist: a list of 2-tuples of strings and Argument objects, as - described in L{Command.arguments}. - - @param proto: an L{AMP} instance. - - @return: the converted dictionary mapping names to argument objects. - """ - objects = {} - myStrings = strings.copy() - for argname, argparser in arglist: - argparser.fromBox(argname, myStrings, objects, proto) - return objects - - - -def _objectsToStrings(objects, arglist, strings, proto): - """ - Convert a dictionary of python objects to an AmpBox, converting through a - given arglist. - - @param objects: a dict mapping names to python objects - - @param arglist: a list of 2-tuples of strings and Argument objects, as - described in L{Command.arguments}. - - @param strings: [OUT PARAMETER] An object providing the L{dict} - interface which will be populated with serialized data. - - @param proto: an L{AMP} instance. - - @return: The converted dictionary mapping names to encoded argument - strings (identical to C{strings}). - """ - myObjects = objects.copy() - for argname, argparser in arglist: - argparser.toBox(argname, strings, myObjects, proto) - return strings - - - -class Decimal(Argument): - """ - Encodes C{decimal.Decimal} instances. - - There are several ways in which a decimal value might be encoded. - - Special values are encoded as special strings:: - - - Positive infinity is encoded as C{"Infinity"} - - Negative infinity is encoded as C{"-Infinity"} - - Quiet not-a-number is encoded as either C{"NaN"} or C{"-NaN"} - - Signalling not-a-number is encoded as either C{"sNaN"} or C{"-sNaN"} - - Normal values are encoded using the base ten string representation, using - engineering notation to indicate magnitude without precision, and "normal" - digits to indicate precision. For example:: - - - C{"1"} represents the value I{1} with precision to one place. - - C{"-1"} represents the value I{-1} with precision to one place. - - C{"1.0"} represents the value I{1} with precision to two places. - - C{"10"} represents the value I{10} with precision to two places. - - C{"1E+2"} represents the value I{10} with precision to one place. - - C{"1E-1"} represents the value I{0.1} with precision to one place. - - C{"1.5E+2"} represents the value I{15} with precision to two places. - - U{http://speleotrove.com/decimal/} should be considered the authoritative - specification for the format. - """ - fromString = decimal.Decimal - - def toString(self, inObject): - """ - Serialize a C{decimal.Decimal} instance to the specified wire format. - """ - if isinstance(inObject, decimal.Decimal): - # Hopefully decimal.Decimal.__str__ actually does what we want. - return str(inObject) - raise ValueError( - "amp.Decimal can only encode instances of decimal.Decimal") - - - -class DateTime(Argument): - """ - Encodes C{datetime.datetime} instances. - - Wire format: '%04i-%02i-%02iT%02i:%02i:%02i.%06i%s%02i:%02i'. Fields in - order are: year, month, day, hour, minute, second, microsecond, timezone - direction (+ or -), timezone hour, timezone minute. Encoded string is - always exactly 32 characters long. This format is compatible with ISO 8601, - but that does not mean all ISO 8601 dates can be accepted. - - Also, note that the datetime module's notion of a "timezone" can be - complex, but the wire format includes only a fixed offset, so the - conversion is not lossless. A lossless transmission of a C{datetime} instance - is not feasible since the receiving end would require a Python interpreter. - - @ivar _positions: A sequence of slices giving the positions of various - interesting parts of the wire format. - """ - - _positions = [ - slice(0, 4), slice(5, 7), slice(8, 10), # year, month, day - slice(11, 13), slice(14, 16), slice(17, 19), # hour, minute, second - slice(20, 26), # microsecond - # intentionally skip timezone direction, as it is not an integer - slice(27, 29), slice(30, 32) # timezone hour, timezone minute - ] - - def fromString(self, s): - """ - Parse a string containing a date and time in the wire format into a - C{datetime.datetime} instance. - """ - if len(s) != 32: - raise ValueError('invalid date format %r' % (s,)) - - values = [int(s[p]) for p in self._positions] - sign = s[26] - timezone = _FixedOffsetTZInfo.fromSignHoursMinutes(sign, *values[7:]) - values[7:] = [timezone] - return datetime.datetime(*values) - - - def toString(self, i): - """ - Serialize a C{datetime.datetime} instance to a string in the specified - wire format. - """ - offset = i.utcoffset() - if offset is None: - raise ValueError( - 'amp.DateTime cannot serialize naive datetime instances. ' - 'You may find amp.utc useful.') - - minutesOffset = (offset.days * 86400 + offset.seconds) // 60 - - if minutesOffset > 0: - sign = '+' - else: - sign = '-' - - # strftime has no way to format the microseconds, or put a ':' in the - # timezone. Surprise! - - return '%04i-%02i-%02iT%02i:%02i:%02i.%06i%s%02i:%02i' % ( - i.year, - i.month, - i.day, - i.hour, - i.minute, - i.second, - i.microsecond, - sign, - abs(minutesOffset) // 60, - abs(minutesOffset) % 60) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/basic.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/basic.py deleted file mode 100644 index 7ad7c48..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/basic.py +++ /dev/null @@ -1,952 +0,0 @@ -# -*- test-case-name: twisted.protocols.test.test_basic -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Basic protocols, such as line-oriented, netstring, and int prefixed strings. -""" - -from __future__ import absolute_import, division - -# System imports -import re -from struct import pack, unpack, calcsize -from io import BytesIO -import math - -from zope.interface import implementer - -# Twisted imports -from twisted.python.compat import _PY3 -from twisted.internet import protocol, defer, interfaces, error -from twisted.python import log - - -# Unfortunately we cannot use regular string formatting on Python 3; see -# http://bugs.python.org/issue3982 for details. -if _PY3: - def _formatNetstring(data): - return b''.join([str(len(data)).encode("ascii"), b':', data, b',']) -else: - def _formatNetstring(data): - return b'%d:%s,' % (len(data), data) -_formatNetstring.__doc__ = """ -Convert some C{bytes} into netstring format. - -@param data: C{bytes} that will be reformatted. -""" - - - -DEBUG = 0 - -class NetstringParseError(ValueError): - """ - The incoming data is not in valid Netstring format. - """ - - - -class IncompleteNetstring(Exception): - """ - Not enough data to complete a netstring. - """ - - -class NetstringReceiver(protocol.Protocol): - """ - A protocol that sends and receives netstrings. - - See U{http://cr.yp.to/proto/netstrings.txt} for the specification of - netstrings. Every netstring starts with digits that specify the length - of the data. This length specification is separated from the data by - a colon. The data is terminated with a comma. - - Override L{stringReceived} to handle received netstrings. This - method is called with the netstring payload as a single argument - whenever a complete netstring is received. - - Security features: - 1. Messages are limited in size, useful if you don't want - someone sending you a 500MB netstring (change C{self.MAX_LENGTH} - to the maximum length you wish to accept). - 2. The connection is lost if an illegal message is received. - - @ivar MAX_LENGTH: Defines the maximum length of netstrings that can be - received. - @type MAX_LENGTH: C{int} - - @ivar _LENGTH: A pattern describing all strings that contain a netstring - length specification. Examples for length specifications are C{b'0:'}, - C{b'12:'}, and C{b'179:'}. C{b'007:'} is not a valid length - specification, since leading zeros are not allowed. - @type _LENGTH: C{re.Match} - - @ivar _LENGTH_PREFIX: A pattern describing all strings that contain - the first part of a netstring length specification (without the - trailing comma). Examples are '0', '12', and '179'. '007' does not - start a netstring length specification, since leading zeros are - not allowed. - @type _LENGTH_PREFIX: C{re.Match} - - @ivar _PARSING_LENGTH: Indicates that the C{NetstringReceiver} is in - the state of parsing the length portion of a netstring. - @type _PARSING_LENGTH: C{int} - - @ivar _PARSING_PAYLOAD: Indicates that the C{NetstringReceiver} is in - the state of parsing the payload portion (data and trailing comma) - of a netstring. - @type _PARSING_PAYLOAD: C{int} - - @ivar brokenPeer: Indicates if the connection is still functional - @type brokenPeer: C{int} - - @ivar _state: Indicates if the protocol is consuming the length portion - (C{PARSING_LENGTH}) or the payload (C{PARSING_PAYLOAD}) of a netstring - @type _state: C{int} - - @ivar _remainingData: Holds the chunk of data that has not yet been consumed - @type _remainingData: C{string} - - @ivar _payload: Holds the payload portion of a netstring including the - trailing comma - @type _payload: C{BytesIO} - - @ivar _expectedPayloadSize: Holds the payload size plus one for the trailing - comma. - @type _expectedPayloadSize: C{int} - """ - MAX_LENGTH = 99999 - _LENGTH = re.compile(b'(0|[1-9]\d*)(:)') - - _LENGTH_PREFIX = re.compile(b'(0|[1-9]\d*)$') - - # Some error information for NetstringParseError instances. - _MISSING_LENGTH = ("The received netstring does not start with a " - "length specification.") - _OVERFLOW = ("The length specification of the received netstring " - "cannot be represented in Python - it causes an " - "OverflowError!") - _TOO_LONG = ("The received netstring is longer than the maximum %s " - "specified by self.MAX_LENGTH") - _MISSING_COMMA = "The received netstring is not terminated by a comma." - - # The following constants are used for determining if the NetstringReceiver - # is parsing the length portion of a netstring, or the payload. - _PARSING_LENGTH, _PARSING_PAYLOAD = range(2) - - def makeConnection(self, transport): - """ - Initializes the protocol. - """ - protocol.Protocol.makeConnection(self, transport) - self._remainingData = b"" - self._currentPayloadSize = 0 - self._payload = BytesIO() - self._state = self._PARSING_LENGTH - self._expectedPayloadSize = 0 - self.brokenPeer = 0 - - - def sendString(self, string): - """ - Sends a netstring. - - Wraps up C{string} by adding length information and a - trailing comma; writes the result to the transport. - - @param string: The string to send. The necessary framing (length - prefix, etc) will be added. - @type string: C{bytes} - """ - self.transport.write(_formatNetstring(string)) - - - def dataReceived(self, data): - """ - Receives some characters of a netstring. - - Whenever a complete netstring is received, this method extracts - its payload and calls L{stringReceived} to process it. - - @param data: A chunk of data representing a (possibly partial) - netstring - @type data: C{bytes} - """ - self._remainingData += data - while self._remainingData: - try: - self._consumeData() - except IncompleteNetstring: - break - except NetstringParseError: - self._handleParseError() - break - - - def stringReceived(self, string): - """ - Override this for notification when each complete string is received. - - @param string: The complete string which was received with all - framing (length prefix, etc) removed. - @type string: C{bytes} - - @raise NotImplementedError: because the method has to be implemented - by the child class. - """ - raise NotImplementedError() - - - def _maxLengthSize(self): - """ - Calculate and return the string size of C{self.MAX_LENGTH}. - - @return: The size of the string representation for C{self.MAX_LENGTH} - @rtype: C{float} - """ - return math.ceil(math.log10(self.MAX_LENGTH)) + 1 - - - def _consumeData(self): - """ - Consumes the content of C{self._remainingData}. - - @raise IncompleteNetstring: if C{self._remainingData} does not - contain enough data to complete the current netstring. - @raise NetstringParseError: if the received data do not - form a valid netstring. - """ - if self._state == self._PARSING_LENGTH: - self._consumeLength() - self._prepareForPayloadConsumption() - if self._state == self._PARSING_PAYLOAD: - self._consumePayload() - - - def _consumeLength(self): - """ - Consumes the length portion of C{self._remainingData}. - - @raise IncompleteNetstring: if C{self._remainingData} contains - a partial length specification (digits without trailing - comma). - @raise NetstringParseError: if the received data do not form a valid - netstring. - """ - lengthMatch = self._LENGTH.match(self._remainingData) - if not lengthMatch: - self._checkPartialLengthSpecification() - raise IncompleteNetstring() - self._processLength(lengthMatch) - - - def _checkPartialLengthSpecification(self): - """ - Makes sure that the received data represents a valid number. - - Checks if C{self._remainingData} represents a number smaller or - equal to C{self.MAX_LENGTH}. - - @raise NetstringParseError: if C{self._remainingData} is no - number or is too big (checked by L{extractLength}). - """ - partialLengthMatch = self._LENGTH_PREFIX.match(self._remainingData) - if not partialLengthMatch: - raise NetstringParseError(self._MISSING_LENGTH) - lengthSpecification = (partialLengthMatch.group(1)) - self._extractLength(lengthSpecification) - - - def _processLength(self, lengthMatch): - """ - Processes the length definition of a netstring. - - Extracts and stores in C{self._expectedPayloadSize} the number - representing the netstring size. Removes the prefix - representing the length specification from - C{self._remainingData}. - - @raise NetstringParseError: if the received netstring does not - start with a number or the number is bigger than - C{self.MAX_LENGTH}. - @param lengthMatch: A regular expression match object matching - a netstring length specification - @type lengthMatch: C{re.Match} - """ - endOfNumber = lengthMatch.end(1) - startOfData = lengthMatch.end(2) - lengthString = self._remainingData[:endOfNumber] - # Expect payload plus trailing comma: - self._expectedPayloadSize = self._extractLength(lengthString) + 1 - self._remainingData = self._remainingData[startOfData:] - - - def _extractLength(self, lengthAsString): - """ - Attempts to extract the length information of a netstring. - - @raise NetstringParseError: if the number is bigger than - C{self.MAX_LENGTH}. - @param lengthAsString: A chunk of data starting with a length - specification - @type lengthAsString: C{bytes} - @return: The length of the netstring - @rtype: C{int} - """ - self._checkStringSize(lengthAsString) - length = int(lengthAsString) - if length > self.MAX_LENGTH: - raise NetstringParseError(self._TOO_LONG % (self.MAX_LENGTH,)) - return length - - - def _checkStringSize(self, lengthAsString): - """ - Checks the sanity of lengthAsString. - - Checks if the size of the length specification exceeds the - size of the string representing self.MAX_LENGTH. If this is - not the case, the number represented by lengthAsString is - certainly bigger than self.MAX_LENGTH, and a - NetstringParseError can be raised. - - This method should make sure that netstrings with extremely - long length specifications are refused before even attempting - to convert them to an integer (which might trigger a - MemoryError). - """ - if len(lengthAsString) > self._maxLengthSize(): - raise NetstringParseError(self._TOO_LONG % (self.MAX_LENGTH,)) - - - def _prepareForPayloadConsumption(self): - """ - Sets up variables necessary for consuming the payload of a netstring. - """ - self._state = self._PARSING_PAYLOAD - self._currentPayloadSize = 0 - self._payload.seek(0) - self._payload.truncate() - - - def _consumePayload(self): - """ - Consumes the payload portion of C{self._remainingData}. - - If the payload is complete, checks for the trailing comma and - processes the payload. If not, raises an L{IncompleteNetstring} - exception. - - @raise IncompleteNetstring: if the payload received so far - contains fewer characters than expected. - @raise NetstringParseError: if the payload does not end with a - comma. - """ - self._extractPayload() - if self._currentPayloadSize < self._expectedPayloadSize: - raise IncompleteNetstring() - self._checkForTrailingComma() - self._state = self._PARSING_LENGTH - self._processPayload() - - - def _extractPayload(self): - """ - Extracts payload information from C{self._remainingData}. - - Splits C{self._remainingData} at the end of the netstring. The - first part becomes C{self._payload}, the second part is stored - in C{self._remainingData}. - - If the netstring is not yet complete, the whole content of - C{self._remainingData} is moved to C{self._payload}. - """ - if self._payloadComplete(): - remainingPayloadSize = (self._expectedPayloadSize - - self._currentPayloadSize) - self._payload.write(self._remainingData[:remainingPayloadSize]) - self._remainingData = self._remainingData[remainingPayloadSize:] - self._currentPayloadSize = self._expectedPayloadSize - else: - self._payload.write(self._remainingData) - self._currentPayloadSize += len(self._remainingData) - self._remainingData = b"" - - - def _payloadComplete(self): - """ - Checks if enough data have been received to complete the netstring. - - @return: C{True} iff the received data contain at least as many - characters as specified in the length section of the - netstring - @rtype: C{bool} - """ - return (len(self._remainingData) + self._currentPayloadSize >= - self._expectedPayloadSize) - - - def _processPayload(self): - """ - Processes the actual payload with L{stringReceived}. - - Strips C{self._payload} of the trailing comma and calls - L{stringReceived} with the result. - """ - self.stringReceived(self._payload.getvalue()[:-1]) - - - def _checkForTrailingComma(self): - """ - Checks if the netstring has a trailing comma at the expected position. - - @raise NetstringParseError: if the last payload character is - anything but a comma. - """ - if self._payload.getvalue()[-1:] != b",": - raise NetstringParseError(self._MISSING_COMMA) - - - def _handleParseError(self): - """ - Terminates the connection and sets the flag C{self.brokenPeer}. - """ - self.transport.loseConnection() - self.brokenPeer = 1 - - - -class LineOnlyReceiver(protocol.Protocol): - """ - A protocol that receives only lines. - - This is purely a speed optimisation over LineReceiver, for the - cases that raw mode is known to be unnecessary. - - @cvar delimiter: The line-ending delimiter to use. By default this is - C{b'\\r\\n'}. - @cvar MAX_LENGTH: The maximum length of a line to allow (If a - sent line is longer than this, the connection is dropped). - Default is 16384. - """ - _buffer = b'' - delimiter = b'\r\n' - MAX_LENGTH = 16384 - - def dataReceived(self, data): - """ - Translates bytes into lines, and calls lineReceived. - """ - lines = (self._buffer+data).split(self.delimiter) - self._buffer = lines.pop(-1) - for line in lines: - if self.transport.disconnecting: - # this is necessary because the transport may be told to lose - # the connection by a line within a larger packet, and it is - # important to disregard all the lines in that packet following - # the one that told it to close. - return - if len(line) > self.MAX_LENGTH: - return self.lineLengthExceeded(line) - else: - self.lineReceived(line) - if len(self._buffer) > self.MAX_LENGTH: - return self.lineLengthExceeded(self._buffer) - - - def lineReceived(self, line): - """ - Override this for when each line is received. - - @param line: The line which was received with the delimiter removed. - @type line: C{bytes} - """ - raise NotImplementedError - - - def sendLine(self, line): - """ - Sends a line to the other end of the connection. - - @param line: The line to send, not including the delimiter. - @type line: C{bytes} - """ - return self.transport.writeSequence((line, self.delimiter)) - - - def lineLengthExceeded(self, line): - """ - Called when the maximum line length has been reached. - Override if it needs to be dealt with in some special way. - """ - return error.ConnectionLost('Line length exceeded') - - - -class _PauseableMixin: - paused = False - - def pauseProducing(self): - self.paused = True - self.transport.pauseProducing() - - - def resumeProducing(self): - self.paused = False - self.transport.resumeProducing() - self.dataReceived(b'') - - - def stopProducing(self): - self.paused = True - self.transport.stopProducing() - - - -class LineReceiver(protocol.Protocol, _PauseableMixin): - """ - A protocol that receives lines and/or raw data, depending on mode. - - In line mode, each line that's received becomes a callback to - L{lineReceived}. In raw data mode, each chunk of raw data becomes a - callback to L{rawDataReceived}. The L{setLineMode} and L{setRawMode} - methods switch between the two modes. - - This is useful for line-oriented protocols such as IRC, HTTP, POP, etc. - - @cvar delimiter: The line-ending delimiter to use. By default this is - C{b'\\r\\n'}. - @cvar MAX_LENGTH: The maximum length of a line to allow (If a - sent line is longer than this, the connection is dropped). - Default is 16384. - """ - line_mode = 1 - _buffer = b'' - _busyReceiving = False - delimiter = b'\r\n' - MAX_LENGTH = 16384 - - def clearLineBuffer(self): - """ - Clear buffered data. - - @return: All of the cleared buffered data. - @rtype: C{bytes} - """ - b, self._buffer = self._buffer, b"" - return b - - - def dataReceived(self, data): - """ - Protocol.dataReceived. - Translates bytes into lines, and calls lineReceived (or - rawDataReceived, depending on mode.) - """ - if self._busyReceiving: - self._buffer += data - return - - try: - self._busyReceiving = True - self._buffer += data - while self._buffer and not self.paused: - if self.line_mode: - try: - line, self._buffer = self._buffer.split( - self.delimiter, 1) - except ValueError: - if len(self._buffer) > self.MAX_LENGTH: - line, self._buffer = self._buffer, b'' - return self.lineLengthExceeded(line) - return - else: - lineLength = len(line) - if lineLength > self.MAX_LENGTH: - exceeded = line + self.delimiter + self._buffer - self._buffer = b'' - return self.lineLengthExceeded(exceeded) - why = self.lineReceived(line) - if (why or self.transport and - self.transport.disconnecting): - return why - else: - data = self._buffer - self._buffer = b'' - why = self.rawDataReceived(data) - if why: - return why - finally: - self._busyReceiving = False - - - def setLineMode(self, extra=b''): - """ - Sets the line-mode of this receiver. - - If you are calling this from a rawDataReceived callback, - you can pass in extra unhandled data, and that data will - be parsed for lines. Further data received will be sent - to lineReceived rather than rawDataReceived. - - Do not pass extra data if calling this function from - within a lineReceived callback. - """ - self.line_mode = 1 - if extra: - return self.dataReceived(extra) - - - def setRawMode(self): - """ - Sets the raw mode of this receiver. - Further data received will be sent to rawDataReceived rather - than lineReceived. - """ - self.line_mode = 0 - - - def rawDataReceived(self, data): - """ - Override this for when raw data is received. - """ - raise NotImplementedError - - - def lineReceived(self, line): - """ - Override this for when each line is received. - - @param line: The line which was received with the delimiter removed. - @type line: C{bytes} - """ - raise NotImplementedError - - - def sendLine(self, line): - """ - Sends a line to the other end of the connection. - - @param line: The line to send, not including the delimiter. - @type line: C{bytes} - """ - return self.transport.write(line + self.delimiter) - - - def lineLengthExceeded(self, line): - """ - Called when the maximum line length has been reached. - Override if it needs to be dealt with in some special way. - - The argument 'line' contains the remainder of the buffer, starting - with (at least some part) of the line which is too long. This may - be more than one line, or may be only the initial portion of the - line. - """ - return self.transport.loseConnection() - - - -class StringTooLongError(AssertionError): - """ - Raised when trying to send a string too long for a length prefixed - protocol. - """ - - - -class _RecvdCompatHack(object): - """ - Emulates the to-be-deprecated C{IntNStringReceiver.recvd} attribute. - - The C{recvd} attribute was where the working buffer for buffering and - parsing netstrings was kept. It was updated each time new data arrived and - each time some of that data was parsed and delivered to application code. - The piecemeal updates to its string value were expensive and have been - removed from C{IntNStringReceiver} in the normal case. However, for - applications directly reading this attribute, this descriptor restores that - behavior. It only copies the working buffer when necessary (ie, when - accessed). This avoids the cost for applications not using the data. - - This is a custom descriptor rather than a property, because we still need - the default __set__ behavior in both new-style and old-style subclasses. - """ - def __get__(self, oself, type=None): - return oself._unprocessed[oself._compatibilityOffset:] - - - -class IntNStringReceiver(protocol.Protocol, _PauseableMixin): - """ - Generic class for length prefixed protocols. - - @ivar _unprocessed: bytes received, but not yet broken up into messages / - sent to stringReceived. _compatibilityOffset must be updated when this - value is updated so that the C{recvd} attribute can be generated - correctly. - @type _unprocessed: C{bytes} - - @ivar structFormat: format used for struct packing/unpacking. Define it in - subclass. - @type structFormat: C{str} - - @ivar prefixLength: length of the prefix, in bytes. Define it in subclass, - using C{struct.calcsize(structFormat)} - @type prefixLength: C{int} - - @ivar _compatibilityOffset: the offset within C{_unprocessed} to the next - message to be parsed. (used to generate the recvd attribute) - @type _compatibilityOffset: C{int} - """ - - MAX_LENGTH = 99999 - _unprocessed = b"" - _compatibilityOffset = 0 - - # Backwards compatibility support for applications which directly touch the - # "internal" parse buffer. - recvd = _RecvdCompatHack() - - def stringReceived(self, string): - """ - Override this for notification when each complete string is received. - - @param string: The complete string which was received with all - framing (length prefix, etc) removed. - @type string: C{bytes} - """ - raise NotImplementedError - - - def lengthLimitExceeded(self, length): - """ - Callback invoked when a length prefix greater than C{MAX_LENGTH} is - received. The default implementation disconnects the transport. - Override this. - - @param length: The length prefix which was received. - @type length: C{int} - """ - self.transport.loseConnection() - - - def dataReceived(self, data): - """ - Convert int prefixed strings into calls to stringReceived. - """ - # Try to minimize string copying (via slices) by keeping one buffer - # containing all the data we have so far and a separate offset into that - # buffer. - alldata = self._unprocessed + data - currentOffset = 0 - prefixLength = self.prefixLength - fmt = self.structFormat - self._unprocessed = alldata - - while len(alldata) >= (currentOffset + prefixLength) and not self.paused: - messageStart = currentOffset + prefixLength - length, = unpack(fmt, alldata[currentOffset:messageStart]) - if length > self.MAX_LENGTH: - self._unprocessed = alldata - self._compatibilityOffset = currentOffset - self.lengthLimitExceeded(length) - return - messageEnd = messageStart + length - if len(alldata) < messageEnd: - break - - # Here we have to slice the working buffer so we can send just the - # netstring into the stringReceived callback. - packet = alldata[messageStart:messageEnd] - currentOffset = messageEnd - self._compatibilityOffset = currentOffset - self.stringReceived(packet) - - # Check to see if the backwards compat "recvd" attribute got written - # to by application code. If so, drop the current data buffer and - # switch to the new buffer given by that attribute's value. - if 'recvd' in self.__dict__: - alldata = self.__dict__.pop('recvd') - self._unprocessed = alldata - self._compatibilityOffset = currentOffset = 0 - if alldata: - continue - return - - # Slice off all the data that has been processed, avoiding holding onto - # memory to store it, and update the compatibility attributes to reflect - # that change. - self._unprocessed = alldata[currentOffset:] - self._compatibilityOffset = 0 - - - def sendString(self, string): - """ - Send a prefixed string to the other end of the connection. - - @param string: The string to send. The necessary framing (length - prefix, etc) will be added. - @type string: C{bytes} - """ - if len(string) >= 2 ** (8 * self.prefixLength): - raise StringTooLongError( - "Try to send %s bytes whereas maximum is %s" % ( - len(string), 2 ** (8 * self.prefixLength))) - self.transport.write( - pack(self.structFormat, len(string)) + string) - - - -class Int32StringReceiver(IntNStringReceiver): - """ - A receiver for int32-prefixed strings. - - An int32 string is a string prefixed by 4 bytes, the 32-bit length of - the string encoded in network byte order. - - This class publishes the same interface as NetstringReceiver. - """ - structFormat = "!I" - prefixLength = calcsize(structFormat) - - - -class Int16StringReceiver(IntNStringReceiver): - """ - A receiver for int16-prefixed strings. - - An int16 string is a string prefixed by 2 bytes, the 16-bit length of - the string encoded in network byte order. - - This class publishes the same interface as NetstringReceiver. - """ - structFormat = "!H" - prefixLength = calcsize(structFormat) - - - -class Int8StringReceiver(IntNStringReceiver): - """ - A receiver for int8-prefixed strings. - - An int8 string is a string prefixed by 1 byte, the 8-bit length of - the string. - - This class publishes the same interface as NetstringReceiver. - """ - structFormat = "!B" - prefixLength = calcsize(structFormat) - - - -class StatefulStringProtocol: - """ - A stateful string protocol. - - This is a mixin for string protocols (L{Int32StringReceiver}, - L{NetstringReceiver}) which translates L{stringReceived} into a callback - (prefixed with C{'proto_'}) depending on state. - - The state C{'done'} is special; if a C{proto_*} method returns it, the - connection will be closed immediately. - - @ivar state: Current state of the protocol. Defaults to C{'init'}. - @type state: C{str} - """ - - state = 'init' - - def stringReceived(self, string): - """ - Choose a protocol phase function and call it. - - Call back to the appropriate protocol phase; this begins with - the function C{proto_init} and moves on to C{proto_*} depending on - what each C{proto_*} function returns. (For example, if - C{self.proto_init} returns 'foo', then C{self.proto_foo} will be the - next function called when a protocol message is received. - """ - try: - pto = 'proto_' + self.state - statehandler = getattr(self, pto) - except AttributeError: - log.msg('callback', self.state, 'not found') - else: - self.state = statehandler(string) - if self.state == 'done': - self.transport.loseConnection() - - - -@implementer(interfaces.IProducer) -class FileSender: - """ - A producer that sends the contents of a file to a consumer. - - This is a helper for protocols that, at some point, will take a - file-like object, read its contents, and write them out to the network, - optionally performing some transformation on the bytes in between. - """ - - CHUNK_SIZE = 2 ** 14 - - lastSent = '' - deferred = None - - def beginFileTransfer(self, file, consumer, transform=None): - """ - Begin transferring a file - - @type file: Any file-like object - @param file: The file object to read data from - - @type consumer: Any implementor of IConsumer - @param consumer: The object to write data to - - @param transform: A callable taking one string argument and returning - the same. All bytes read from the file are passed through this before - being written to the consumer. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked when the file has - been completely written to the consumer. The last byte written to the - consumer is passed to the callback. - """ - self.file = file - self.consumer = consumer - self.transform = transform - - self.deferred = deferred = defer.Deferred() - self.consumer.registerProducer(self, False) - return deferred - - - def resumeProducing(self): - chunk = '' - if self.file: - chunk = self.file.read(self.CHUNK_SIZE) - if not chunk: - self.file = None - self.consumer.unregisterProducer() - if self.deferred: - self.deferred.callback(self.lastSent) - self.deferred = None - return - - if self.transform: - chunk = self.transform(chunk) - self.consumer.write(chunk) - self.lastSent = chunk[-1:] - - - def pauseProducing(self): - pass - - - def stopProducing(self): - if self.deferred: - self.deferred.errback( - Exception("Consumer asked us to stop producing")) - self.deferred = None diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/dict.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/dict.py deleted file mode 100644 index 60d529a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/dict.py +++ /dev/null @@ -1,362 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Dict client protocol implementation. - -@author: Pavel Pergamenshchik -""" - -from twisted.protocols import basic -from twisted.internet import defer, protocol -from twisted.python import log -from StringIO import StringIO - -def parseParam(line): - """Chew one dqstring or atom from beginning of line and return (param, remaningline)""" - if line == '': - return (None, '') - elif line[0] != '"': # atom - mode = 1 - else: # dqstring - mode = 2 - res = "" - io = StringIO(line) - if mode == 2: # skip the opening quote - io.read(1) - while 1: - a = io.read(1) - if a == '"': - if mode == 2: - io.read(1) # skip the separating space - return (res, io.read()) - elif a == '\\': - a = io.read(1) - if a == '': - return (None, line) # unexpected end of string - elif a == '': - if mode == 1: - return (res, io.read()) - else: - return (None, line) # unexpected end of string - elif a == ' ': - if mode == 1: - return (res, io.read()) - res += a - -def makeAtom(line): - """Munch a string into an 'atom'""" - # FIXME: proper quoting - return filter(lambda x: not (x in map(chr, range(33)+[34, 39, 92])), line) - -def makeWord(s): - mustquote = range(33)+[34, 39, 92] - result = [] - for c in s: - if ord(c) in mustquote: - result.append("\\") - result.append(c) - s = "".join(result) - return s - -def parseText(line): - if len(line) == 1 and line == '.': - return None - else: - if len(line) > 1 and line[0:2] == '..': - line = line[1:] - return line - -class Definition: - """A word definition""" - def __init__(self, name, db, dbdesc, text): - self.name = name - self.db = db - self.dbdesc = dbdesc - self.text = text # list of strings not terminated by newline - -class DictClient(basic.LineReceiver): - """dict (RFC2229) client""" - - data = None # multiline data - MAX_LENGTH = 1024 - state = None - mode = None - result = None - factory = None - - def __init__(self): - self.data = None - self.result = None - - def connectionMade(self): - self.state = "conn" - self.mode = "command" - - def sendLine(self, line): - """Throw up if the line is longer than 1022 characters""" - if len(line) > self.MAX_LENGTH - 2: - raise ValueError("DictClient tried to send a too long line") - basic.LineReceiver.sendLine(self, line) - - def lineReceived(self, line): - try: - line = line.decode("UTF-8") - except UnicodeError: # garbage received, skip - return - if self.mode == "text": # we are receiving textual data - code = "text" - else: - if len(line) < 4: - log.msg("DictClient got invalid line from server -- %s" % line) - self.protocolError("Invalid line from server") - self.transport.LoseConnection() - return - code = int(line[:3]) - line = line[4:] - method = getattr(self, 'dictCode_%s_%s' % (code, self.state), self.dictCode_default) - method(line) - - def dictCode_default(self, line): - """Unknown message""" - log.msg("DictClient got unexpected message from server -- %s" % line) - self.protocolError("Unexpected server message") - self.transport.loseConnection() - - def dictCode_221_ready(self, line): - """We are about to get kicked off, do nothing""" - pass - - def dictCode_220_conn(self, line): - """Greeting message""" - self.state = "ready" - self.dictConnected() - - def dictCode_530_conn(self): - self.protocolError("Access denied") - self.transport.loseConnection() - - def dictCode_420_conn(self): - self.protocolError("Server temporarily unavailable") - self.transport.loseConnection() - - def dictCode_421_conn(self): - self.protocolError("Server shutting down at operator request") - self.transport.loseConnection() - - def sendDefine(self, database, word): - """Send a dict DEFINE command""" - assert self.state == "ready", "DictClient.sendDefine called when not in ready state" - self.result = None # these two are just in case. In "ready" state, result and data - self.data = None # should be None - self.state = "define" - command = "DEFINE %s %s" % (makeAtom(database.encode("UTF-8")), makeWord(word.encode("UTF-8"))) - self.sendLine(command) - - def sendMatch(self, database, strategy, word): - """Send a dict MATCH command""" - assert self.state == "ready", "DictClient.sendMatch called when not in ready state" - self.result = None - self.data = None - self.state = "match" - command = "MATCH %s %s %s" % (makeAtom(database), makeAtom(strategy), makeAtom(word)) - self.sendLine(command.encode("UTF-8")) - - def dictCode_550_define(self, line): - """Invalid database""" - self.mode = "ready" - self.defineFailed("Invalid database") - - def dictCode_550_match(self, line): - """Invalid database""" - self.mode = "ready" - self.matchFailed("Invalid database") - - def dictCode_551_match(self, line): - """Invalid strategy""" - self.mode = "ready" - self.matchFailed("Invalid strategy") - - def dictCode_552_define(self, line): - """No match""" - self.mode = "ready" - self.defineFailed("No match") - - def dictCode_552_match(self, line): - """No match""" - self.mode = "ready" - self.matchFailed("No match") - - def dictCode_150_define(self, line): - """n definitions retrieved""" - self.result = [] - - def dictCode_151_define(self, line): - """Definition text follows""" - self.mode = "text" - (word, line) = parseParam(line) - (db, line) = parseParam(line) - (dbdesc, line) = parseParam(line) - if not (word and db and dbdesc): - self.protocolError("Invalid server response") - self.transport.loseConnection() - else: - self.result.append(Definition(word, db, dbdesc, [])) - self.data = [] - - def dictCode_152_match(self, line): - """n matches found, text follows""" - self.mode = "text" - self.result = [] - self.data = [] - - def dictCode_text_define(self, line): - """A line of definition text received""" - res = parseText(line) - if res == None: - self.mode = "command" - self.result[-1].text = self.data - self.data = None - else: - self.data.append(line) - - def dictCode_text_match(self, line): - """One line of match text received""" - def l(s): - p1, t = parseParam(s) - p2, t = parseParam(t) - return (p1, p2) - res = parseText(line) - if res == None: - self.mode = "command" - self.result = map(l, self.data) - self.data = None - else: - self.data.append(line) - - def dictCode_250_define(self, line): - """ok""" - t = self.result - self.result = None - self.state = "ready" - self.defineDone(t) - - def dictCode_250_match(self, line): - """ok""" - t = self.result - self.result = None - self.state = "ready" - self.matchDone(t) - - def protocolError(self, reason): - """override to catch unexpected dict protocol conditions""" - pass - - def dictConnected(self): - """override to be notified when the server is ready to accept commands""" - pass - - def defineFailed(self, reason): - """override to catch reasonable failure responses to DEFINE""" - pass - - def defineDone(self, result): - """override to catch succesful DEFINE""" - pass - - def matchFailed(self, reason): - """override to catch resonable failure responses to MATCH""" - pass - - def matchDone(self, result): - """override to catch succesful MATCH""" - pass - - -class InvalidResponse(Exception): - pass - - -class DictLookup(DictClient): - """Utility class for a single dict transaction. To be used with DictLookupFactory""" - - def protocolError(self, reason): - if not self.factory.done: - self.factory.d.errback(InvalidResponse(reason)) - self.factory.clientDone() - - def dictConnected(self): - if self.factory.queryType == "define": - apply(self.sendDefine, self.factory.param) - elif self.factory.queryType == "match": - apply(self.sendMatch, self.factory.param) - - def defineFailed(self, reason): - self.factory.d.callback([]) - self.factory.clientDone() - self.transport.loseConnection() - - def defineDone(self, result): - self.factory.d.callback(result) - self.factory.clientDone() - self.transport.loseConnection() - - def matchFailed(self, reason): - self.factory.d.callback([]) - self.factory.clientDone() - self.transport.loseConnection() - - def matchDone(self, result): - self.factory.d.callback(result) - self.factory.clientDone() - self.transport.loseConnection() - - -class DictLookupFactory(protocol.ClientFactory): - """Utility factory for a single dict transaction""" - protocol = DictLookup - done = None - - def __init__(self, queryType, param, d): - self.queryType = queryType - self.param = param - self.d = d - self.done = 0 - - def clientDone(self): - """Called by client when done.""" - self.done = 1 - del self.d - - def clientConnectionFailed(self, connector, error): - self.d.errback(error) - - def clientConnectionLost(self, connector, error): - if not self.done: - self.d.errback(error) - - def buildProtocol(self, addr): - p = self.protocol() - p.factory = self - return p - - -def define(host, port, database, word): - """Look up a word using a dict server""" - d = defer.Deferred() - factory = DictLookupFactory("define", (database, word), d) - - from twisted.internet import reactor - reactor.connectTCP(host, port, factory) - return d - -def match(host, port, database, strategy, word): - """Match a word using a dict server""" - d = defer.Deferred() - factory = DictLookupFactory("match", (database, strategy, word), d) - - from twisted.internet import reactor - reactor.connectTCP(host, port, factory) - return d - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/finger.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/finger.py deleted file mode 100644 index fcb9396..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/finger.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""The Finger User Information Protocol (RFC 1288)""" - -from twisted.protocols import basic - -class Finger(basic.LineReceiver): - - def lineReceived(self, line): - parts = line.split() - if not parts: - parts = [''] - if len(parts) == 1: - slash_w = 0 - else: - slash_w = 1 - user = parts[-1] - if '@' in user: - host_place = user.rfind('@') - user = user[:host_place] - host = user[host_place+1:] - return self.forwardQuery(slash_w, user, host) - if user: - return self.getUser(slash_w, user) - else: - return self.getDomain(slash_w) - - def _refuseMessage(self, message): - self.transport.write(message+"\n") - self.transport.loseConnection() - - def forwardQuery(self, slash_w, user, host): - self._refuseMessage('Finger forwarding service denied') - - def getDomain(self, slash_w): - self._refuseMessage('Finger online list denied') - - def getUser(self, slash_w, user): - self.transport.write('Login: '+user+'\n') - self._refuseMessage('No such user') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/ftp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/ftp.py deleted file mode 100644 index d3eb36c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/ftp.py +++ /dev/null @@ -1,3218 +0,0 @@ -# -*- test-case-name: twisted.test.test_ftp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An FTP protocol implementation -""" - -# System Imports -import os -import time -import re -import stat -import errno -import fnmatch - -try: - import pwd, grp -except ImportError: - pwd = grp = None - -from zope.interface import Interface, implements - -# Twisted Imports -from twisted import copyright -from twisted.internet import reactor, interfaces, protocol, error, defer -from twisted.protocols import basic, policies - -from twisted.python import log, failure, filepath - -from twisted.cred import error as cred_error, portal, credentials, checkers - -# constants -# response codes - -RESTART_MARKER_REPLY = "100" -SERVICE_READY_IN_N_MINUTES = "120" -DATA_CNX_ALREADY_OPEN_START_XFR = "125" -FILE_STATUS_OK_OPEN_DATA_CNX = "150" - -CMD_OK = "200.1" -TYPE_SET_OK = "200.2" -ENTERING_PORT_MODE = "200.3" -CMD_NOT_IMPLMNTD_SUPERFLUOUS = "202" -SYS_STATUS_OR_HELP_REPLY = "211.1" -FEAT_OK = '211.2' -DIR_STATUS = "212" -FILE_STATUS = "213" -HELP_MSG = "214" -NAME_SYS_TYPE = "215" -SVC_READY_FOR_NEW_USER = "220.1" -WELCOME_MSG = "220.2" -SVC_CLOSING_CTRL_CNX = "221.1" -GOODBYE_MSG = "221.2" -DATA_CNX_OPEN_NO_XFR_IN_PROGRESS = "225" -CLOSING_DATA_CNX = "226.1" -TXFR_COMPLETE_OK = "226.2" -ENTERING_PASV_MODE = "227" -ENTERING_EPSV_MODE = "229" -USR_LOGGED_IN_PROCEED = "230.1" # v1 of code 230 -GUEST_LOGGED_IN_PROCEED = "230.2" # v2 of code 230 -REQ_FILE_ACTN_COMPLETED_OK = "250" -PWD_REPLY = "257.1" -MKD_REPLY = "257.2" - -USR_NAME_OK_NEED_PASS = "331.1" # v1 of Code 331 -GUEST_NAME_OK_NEED_EMAIL = "331.2" # v2 of code 331 -NEED_ACCT_FOR_LOGIN = "332" -REQ_FILE_ACTN_PENDING_FURTHER_INFO = "350" - -SVC_NOT_AVAIL_CLOSING_CTRL_CNX = "421.1" -TOO_MANY_CONNECTIONS = "421.2" -CANT_OPEN_DATA_CNX = "425" -CNX_CLOSED_TXFR_ABORTED = "426" -REQ_ACTN_ABRTD_FILE_UNAVAIL = "450" -REQ_ACTN_ABRTD_LOCAL_ERR = "451" -REQ_ACTN_ABRTD_INSUFF_STORAGE = "452" - -SYNTAX_ERR = "500" -SYNTAX_ERR_IN_ARGS = "501" -CMD_NOT_IMPLMNTD = "502.1" -OPTS_NOT_IMPLEMENTED = '502.2' -BAD_CMD_SEQ = "503" -CMD_NOT_IMPLMNTD_FOR_PARAM = "504" -NOT_LOGGED_IN = "530.1" # v1 of code 530 - please log in -AUTH_FAILURE = "530.2" # v2 of code 530 - authorization failure -NEED_ACCT_FOR_STOR = "532" -FILE_NOT_FOUND = "550.1" # no such file or directory -PERMISSION_DENIED = "550.2" # permission denied -ANON_USER_DENIED = "550.3" # anonymous users can't alter filesystem -IS_NOT_A_DIR = "550.4" # rmd called on a path that is not a directory -REQ_ACTN_NOT_TAKEN = "550.5" -FILE_EXISTS = "550.6" -IS_A_DIR = "550.7" -PAGE_TYPE_UNK = "551" -EXCEEDED_STORAGE_ALLOC = "552" -FILENAME_NOT_ALLOWED = "553" - - -RESPONSE = { - # -- 100's -- - RESTART_MARKER_REPLY: '110 MARK yyyy-mmmm', # TODO: this must be fixed - SERVICE_READY_IN_N_MINUTES: '120 service ready in %s minutes', - DATA_CNX_ALREADY_OPEN_START_XFR: '125 Data connection already open, starting transfer', - FILE_STATUS_OK_OPEN_DATA_CNX: '150 File status okay; about to open data connection.', - - # -- 200's -- - CMD_OK: '200 Command OK', - TYPE_SET_OK: '200 Type set to %s.', - ENTERING_PORT_MODE: '200 PORT OK', - CMD_NOT_IMPLMNTD_SUPERFLUOUS: '202 Command not implemented, superfluous at this site', - SYS_STATUS_OR_HELP_REPLY: '211 System status reply', - FEAT_OK: ['211-Features:','211 End'], - DIR_STATUS: '212 %s', - FILE_STATUS: '213 %s', - HELP_MSG: '214 help: %s', - NAME_SYS_TYPE: '215 UNIX Type: L8', - WELCOME_MSG: "220 %s", - SVC_READY_FOR_NEW_USER: '220 Service ready', - SVC_CLOSING_CTRL_CNX: '221 Service closing control connection', - GOODBYE_MSG: '221 Goodbye.', - DATA_CNX_OPEN_NO_XFR_IN_PROGRESS: '225 data connection open, no transfer in progress', - CLOSING_DATA_CNX: '226 Abort successful', - TXFR_COMPLETE_OK: '226 Transfer Complete.', - ENTERING_PASV_MODE: '227 Entering Passive Mode (%s).', - ENTERING_EPSV_MODE: '229 Entering Extended Passive Mode (|||%s|).', # where is epsv defined in the rfc's? - USR_LOGGED_IN_PROCEED: '230 User logged in, proceed', - GUEST_LOGGED_IN_PROCEED: '230 Anonymous login ok, access restrictions apply.', - REQ_FILE_ACTN_COMPLETED_OK: '250 Requested File Action Completed OK', #i.e. CWD completed ok - PWD_REPLY: '257 "%s"', - MKD_REPLY: '257 "%s" created', - - # -- 300's -- - USR_NAME_OK_NEED_PASS: '331 Password required for %s.', - GUEST_NAME_OK_NEED_EMAIL: '331 Guest login ok, type your email address as password.', - NEED_ACCT_FOR_LOGIN: '332 Need account for login.', - - REQ_FILE_ACTN_PENDING_FURTHER_INFO: '350 Requested file action pending further information.', - -# -- 400's -- - SVC_NOT_AVAIL_CLOSING_CTRL_CNX: '421 Service not available, closing control connection.', - TOO_MANY_CONNECTIONS: '421 Too many users right now, try again in a few minutes.', - CANT_OPEN_DATA_CNX: "425 Can't open data connection.", - CNX_CLOSED_TXFR_ABORTED: '426 Transfer aborted. Data connection closed.', - - REQ_ACTN_ABRTD_FILE_UNAVAIL: '450 Requested action aborted. File unavailable.', - REQ_ACTN_ABRTD_LOCAL_ERR: '451 Requested action aborted. Local error in processing.', - REQ_ACTN_ABRTD_INSUFF_STORAGE: '452 Requested action aborted. Insufficient storage.', - - # -- 500's -- - SYNTAX_ERR: "500 Syntax error: %s", - SYNTAX_ERR_IN_ARGS: '501 syntax error in argument(s) %s.', - CMD_NOT_IMPLMNTD: "502 Command '%s' not implemented", - OPTS_NOT_IMPLEMENTED: "502 Option '%s' not implemented.", - BAD_CMD_SEQ: '503 Incorrect sequence of commands: %s', - CMD_NOT_IMPLMNTD_FOR_PARAM: "504 Not implemented for parameter '%s'.", - NOT_LOGGED_IN: '530 Please login with USER and PASS.', - AUTH_FAILURE: '530 Sorry, Authentication failed.', - NEED_ACCT_FOR_STOR: '532 Need an account for storing files', - FILE_NOT_FOUND: '550 %s: No such file or directory.', - PERMISSION_DENIED: '550 %s: Permission denied.', - ANON_USER_DENIED: '550 Anonymous users are forbidden to change the filesystem', - IS_NOT_A_DIR: '550 Cannot rmd, %s is not a directory', - FILE_EXISTS: '550 %s: File exists', - IS_A_DIR: '550 %s: is a directory', - REQ_ACTN_NOT_TAKEN: '550 Requested action not taken: %s', - PAGE_TYPE_UNK: '551 Page type unknown', - EXCEEDED_STORAGE_ALLOC: '552 Requested file action aborted, exceeded file storage allocation', - FILENAME_NOT_ALLOWED: '553 Requested action not taken, file name not allowed' -} - - - -class InvalidPath(Exception): - """ - Internal exception used to signify an error during parsing a path. - """ - - - -def toSegments(cwd, path): - """ - Normalize a path, as represented by a list of strings each - representing one segment of the path. - """ - if path.startswith('/'): - segs = [] - else: - segs = cwd[:] - - for s in path.split('/'): - if s == '.' or s == '': - continue - elif s == '..': - if segs: - segs.pop() - else: - raise InvalidPath(cwd, path) - elif '\0' in s or '/' in s: - raise InvalidPath(cwd, path) - else: - segs.append(s) - return segs - - -def errnoToFailure(e, path): - """ - Map C{OSError} and C{IOError} to standard FTP errors. - """ - if e == errno.ENOENT: - return defer.fail(FileNotFoundError(path)) - elif e == errno.EACCES or e == errno.EPERM: - return defer.fail(PermissionDeniedError(path)) - elif e == errno.ENOTDIR: - return defer.fail(IsNotADirectoryError(path)) - elif e == errno.EEXIST: - return defer.fail(FileExistsError(path)) - elif e == errno.EISDIR: - return defer.fail(IsADirectoryError(path)) - else: - return defer.fail() - - -def _isGlobbingExpression(segments=None): - """ - Helper for checking if a FTPShell `segments` contains a wildcard Unix - expression. - - Only filename globbing is supported. - This means that wildcards can only be presents in the last element of - `segments`. - - @type segments: C{list} - @param segments: List of path elements as used by the FTP server protocol. - - @rtype: Boolean - @return: True if `segments` contains a globbing expression. - """ - if not segments: - return False - - # To check that something is a glob expression, we convert it to - # Regular Expression. If the result is the same as the original expression - # then it contains no globbing expression. - globCandidate = segments[-1] - # A set of default regex rules is added to all strings. - emtpyTranslations = fnmatch.translate('') - globTranslations = fnmatch.translate(globCandidate) - - if globCandidate + emtpyTranslations == globTranslations: - return False - else: - return True - - -class FTPCmdError(Exception): - """ - Generic exception for FTP commands. - """ - def __init__(self, *msg): - Exception.__init__(self, *msg) - self.errorMessage = msg - - - def response(self): - """ - Generate a FTP response message for this error. - """ - return RESPONSE[self.errorCode] % self.errorMessage - - - -class FileNotFoundError(FTPCmdError): - """ - Raised when trying to access a non existent file or directory. - """ - errorCode = FILE_NOT_FOUND - - - -class AnonUserDeniedError(FTPCmdError): - """ - Raised when an anonymous user issues a command that will alter the - filesystem - """ - - errorCode = ANON_USER_DENIED - - - -class PermissionDeniedError(FTPCmdError): - """ - Raised when access is attempted to a resource to which access is - not allowed. - """ - errorCode = PERMISSION_DENIED - - - -class IsNotADirectoryError(FTPCmdError): - """ - Raised when RMD is called on a path that isn't a directory. - """ - errorCode = IS_NOT_A_DIR - - - -class FileExistsError(FTPCmdError): - """ - Raised when attempted to override an existing resource. - """ - errorCode = FILE_EXISTS - - - -class IsADirectoryError(FTPCmdError): - """ - Raised when DELE is called on a path that is a directory. - """ - errorCode = IS_A_DIR - - - -class CmdSyntaxError(FTPCmdError): - """ - Raised when a command syntax is wrong. - """ - errorCode = SYNTAX_ERR - - - -class CmdArgSyntaxError(FTPCmdError): - """ - Raised when a command is called with wrong value or a wrong number of - arguments. - """ - errorCode = SYNTAX_ERR_IN_ARGS - - - -class CmdNotImplementedError(FTPCmdError): - """ - Raised when an unimplemented command is given to the server. - """ - errorCode = CMD_NOT_IMPLMNTD - - - -class CmdNotImplementedForArgError(FTPCmdError): - """ - Raised when the handling of a parameter for a command is not implemented by - the server. - """ - errorCode = CMD_NOT_IMPLMNTD_FOR_PARAM - - - -class FTPError(Exception): - pass - - - -class PortConnectionError(Exception): - pass - - - -class BadCmdSequenceError(FTPCmdError): - """ - Raised when a client sends a series of commands in an illogical sequence. - """ - errorCode = BAD_CMD_SEQ - - - -class AuthorizationError(FTPCmdError): - """ - Raised when client authentication fails. - """ - errorCode = AUTH_FAILURE - - - -def debugDeferred(self, *_): - log.msg('debugDeferred(): %s' % str(_), debug=True) - - -# -- DTP Protocol -- - - -_months = [ - None, - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - - -class DTP(object, protocol.Protocol): - implements(interfaces.IConsumer) - - isConnected = False - - _cons = None - _onConnLost = None - _buffer = None - - def connectionMade(self): - self.isConnected = True - self.factory.deferred.callback(None) - self._buffer = [] - - def connectionLost(self, reason): - self.isConnected = False - if self._onConnLost is not None: - self._onConnLost.callback(None) - - def sendLine(self, line): - """ - Send a line to data channel. - - @param line: The line to be sent. - @type line: L{bytes} - """ - self.transport.write(line + '\r\n') - - - def _formatOneListResponse(self, name, size, directory, permissions, hardlinks, modified, owner, group): - """ - Helper method to format one entry's info into a text entry like: - 'drwxrwxrwx 0 user group 0 Jan 01 1970 filename.txt' - - @param name: C{str} name of the entry (file or directory or link) - @param size: C{int} size of the entry - @param directory: evals to C{bool} - whether the entry is a directory - @param permissions: L{twisted.python.filepath.Permissions} object - representing that entry's permissions - @param hardlinks: C{int} number of hardlinks - @param modified: C{float} - entry's last modified time in seconds - since the epoch - @param owner: C{str} username of the owner - @param group: C{str} group name of the owner - - @return: C{str} in the requisite format - """ - def formatDate(mtime): - now = time.gmtime() - info = { - 'month': _months[mtime.tm_mon], - 'day': mtime.tm_mday, - 'year': mtime.tm_year, - 'hour': mtime.tm_hour, - 'minute': mtime.tm_min - } - if now.tm_year != mtime.tm_year: - return '%(month)s %(day)02d %(year)5d' % info - else: - return '%(month)s %(day)02d %(hour)02d:%(minute)02d' % info - - format = ('%(directory)s%(permissions)s%(hardlinks)4d ' - '%(owner)-9s %(group)-9s %(size)15d %(date)12s ' - '%(name)s') - - return format % { - 'directory': directory and 'd' or '-', - 'permissions': permissions.shorthand(), - 'hardlinks': hardlinks, - 'owner': owner[:8], - 'group': group[:8], - 'size': size, - 'date': formatDate(time.gmtime(modified)), - 'name': name} - - - def sendListResponse(self, name, response): - self.sendLine(self._formatOneListResponse(name, *response)) - - - # Proxy IConsumer to our transport - def registerProducer(self, producer, streaming): - return self.transport.registerProducer(producer, streaming) - - def unregisterProducer(self): - self.transport.unregisterProducer() - self.transport.loseConnection() - - def write(self, data): - if self.isConnected: - return self.transport.write(data) - raise Exception("Crap damn crap damn crap damn") - - - # Pretend to be a producer, too. - def _conswrite(self, bytes): - try: - self._cons.write(bytes) - except: - self._onConnLost.errback() - - def dataReceived(self, bytes): - if self._cons is not None: - self._conswrite(bytes) - else: - self._buffer.append(bytes) - - def _unregConsumer(self, ignored): - self._cons.unregisterProducer() - self._cons = None - del self._onConnLost - return ignored - - def registerConsumer(self, cons): - assert self._cons is None - self._cons = cons - self._cons.registerProducer(self, True) - for chunk in self._buffer: - self._conswrite(chunk) - self._buffer = None - if self.isConnected: - self._onConnLost = d = defer.Deferred() - d.addBoth(self._unregConsumer) - return d - else: - self._cons.unregisterProducer() - self._cons = None - return defer.succeed(None) - - def resumeProducing(self): - self.transport.resumeProducing() - - def pauseProducing(self): - self.transport.pauseProducing() - - def stopProducing(self): - self.transport.stopProducing() - -class DTPFactory(protocol.ClientFactory): - """ - Client factory for I{data transfer process} protocols. - - @ivar peerCheck: perform checks to make sure the ftp-pi's peer is the same - as the dtp's - @ivar pi: a reference to this factory's protocol interpreter - - @ivar _state: Indicates the current state of the DTPFactory. Initially, - this is L{_IN_PROGRESS}. If the connection fails or times out, it is - L{_FAILED}. If the connection succeeds before the timeout, it is - L{_FINISHED}. - """ - - _IN_PROGRESS = object() - _FAILED = object() - _FINISHED = object() - - _state = _IN_PROGRESS - - # -- configuration variables -- - peerCheck = False - - # -- class variables -- - def __init__(self, pi, peerHost=None, reactor=None): - """ - Constructor - - @param pi: this factory's protocol interpreter - @param peerHost: if peerCheck is True, this is the tuple that the - generated instance will use to perform security checks - """ - self.pi = pi # the protocol interpreter that is using this factory - self.peerHost = peerHost # the from FTP.transport.peerHost() - self.deferred = defer.Deferred() # deferred will fire when instance is connected - self.delayedCall = None - if reactor is None: - from twisted.internet import reactor - self._reactor = reactor - - - def buildProtocol(self, addr): - log.msg('DTPFactory.buildProtocol', debug=True) - - if self._state is not self._IN_PROGRESS: - return None - self._state = self._FINISHED - - self.cancelTimeout() - p = DTP() - p.factory = self - p.pi = self.pi - self.pi.dtpInstance = p - return p - - - def stopFactory(self): - log.msg('dtpFactory.stopFactory', debug=True) - self.cancelTimeout() - - - def timeoutFactory(self): - log.msg('timed out waiting for DTP connection') - if self._state is not self._IN_PROGRESS: - return - self._state = self._FAILED - - d = self.deferred - self.deferred = None - d.errback( - PortConnectionError(defer.TimeoutError("DTPFactory timeout"))) - - - def cancelTimeout(self): - if self.delayedCall is not None and self.delayedCall.active(): - log.msg('cancelling DTP timeout', debug=True) - self.delayedCall.cancel() - - - def setTimeout(self, seconds): - log.msg('DTPFactory.setTimeout set to %s seconds' % seconds) - self.delayedCall = self._reactor.callLater(seconds, self.timeoutFactory) - - - def clientConnectionFailed(self, connector, reason): - if self._state is not self._IN_PROGRESS: - return - self._state = self._FAILED - d = self.deferred - self.deferred = None - d.errback(PortConnectionError(reason)) - - -# -- FTP-PI (Protocol Interpreter) -- - -class ASCIIConsumerWrapper(object): - def __init__(self, cons): - self.cons = cons - self.registerProducer = cons.registerProducer - self.unregisterProducer = cons.unregisterProducer - - assert os.linesep == "\r\n" or len(os.linesep) == 1, "Unsupported platform (yea right like this even exists)" - - if os.linesep == "\r\n": - self.write = cons.write - - def write(self, bytes): - return self.cons.write(bytes.replace(os.linesep, "\r\n")) - - - -class FileConsumer(object): - """ - A consumer for FTP input that writes data to a file. - - @ivar fObj: a file object opened for writing, used to write data received. - @type fObj: C{file} - """ - - implements(interfaces.IConsumer) - - def __init__(self, fObj): - self.fObj = fObj - - - def registerProducer(self, producer, streaming): - self.producer = producer - assert streaming - - - def unregisterProducer(self): - self.producer = None - self.fObj.close() - - - def write(self, bytes): - self.fObj.write(bytes) - - - -class FTPOverflowProtocol(basic.LineReceiver): - """FTP mini-protocol for when there are too many connections.""" - def connectionMade(self): - self.sendLine(RESPONSE[TOO_MANY_CONNECTIONS]) - self.transport.loseConnection() - - -class FTP(object, basic.LineReceiver, policies.TimeoutMixin): - """ - Protocol Interpreter for the File Transfer Protocol - - @ivar state: The current server state. One of L{UNAUTH}, - L{INAUTH}, L{AUTHED}, L{RENAMING}. - - @ivar shell: The connected avatar - @ivar binary: The transfer mode. If false, ASCII. - @ivar dtpFactory: Generates a single DTP for this session - @ivar dtpPort: Port returned from listenTCP - @ivar listenFactory: A callable with the signature of - L{twisted.internet.interfaces.IReactorTCP.listenTCP} which will be used - to create Ports for passive connections (mainly for testing). - - @ivar passivePortRange: iterator used as source of passive port numbers. - @type passivePortRange: C{iterator} - """ - - disconnected = False - - # States an FTP can be in - UNAUTH, INAUTH, AUTHED, RENAMING = range(4) - - # how long the DTP waits for a connection - dtpTimeout = 10 - - portal = None - shell = None - dtpFactory = None - dtpPort = None - dtpInstance = None - binary = True - PUBLIC_COMMANDS = ['FEAT', 'QUIT'] - FEATURES = ['FEAT', 'MDTM', 'PASV', 'SIZE', 'TYPE A;I'] - - passivePortRange = xrange(0, 1) - - listenFactory = reactor.listenTCP - - def reply(self, key, *args): - msg = RESPONSE[key] % args - self.sendLine(msg) - - - def connectionMade(self): - self.state = self.UNAUTH - self.setTimeout(self.timeOut) - self.reply(WELCOME_MSG, self.factory.welcomeMessage) - - def connectionLost(self, reason): - # if we have a DTP protocol instance running and - # we lose connection to the client's PI, kill the - # DTP connection and close the port - if self.dtpFactory: - self.cleanupDTP() - self.setTimeout(None) - if hasattr(self.shell, 'logout') and self.shell.logout is not None: - self.shell.logout() - self.shell = None - self.transport = None - - def timeoutConnection(self): - self.transport.loseConnection() - - def lineReceived(self, line): - self.resetTimeout() - self.pauseProducing() - - def processFailed(err): - if err.check(FTPCmdError): - self.sendLine(err.value.response()) - elif (err.check(TypeError) and - err.value.args[0].find('takes exactly') != -1): - self.reply(SYNTAX_ERR, "%s requires an argument." % (cmd,)) - else: - log.msg("Unexpected FTP error") - log.err(err) - self.reply(REQ_ACTN_NOT_TAKEN, "internal server error") - - def processSucceeded(result): - if isinstance(result, tuple): - self.reply(*result) - elif result is not None: - self.reply(result) - - def allDone(ignored): - if not self.disconnected: - self.resumeProducing() - - spaceIndex = line.find(' ') - if spaceIndex != -1: - cmd = line[:spaceIndex] - args = (line[spaceIndex + 1:],) - else: - cmd = line - args = () - d = defer.maybeDeferred(self.processCommand, cmd, *args) - d.addCallbacks(processSucceeded, processFailed) - d.addErrback(log.err) - - # XXX It burnsss - # LineReceiver doesn't let you resumeProducing inside - # lineReceived atm - from twisted.internet import reactor - reactor.callLater(0, d.addBoth, allDone) - - - def processCommand(self, cmd, *params): - - def call_ftp_command(command): - method = getattr(self, "ftp_" + command, None) - if method is not None: - return method(*params) - return defer.fail(CmdNotImplementedError(command)) - - cmd = cmd.upper() - - if cmd in self.PUBLIC_COMMANDS: - return call_ftp_command(cmd) - - elif self.state == self.UNAUTH: - if cmd == 'USER': - return self.ftp_USER(*params) - elif cmd == 'PASS': - return BAD_CMD_SEQ, "USER required before PASS" - else: - return NOT_LOGGED_IN - - elif self.state == self.INAUTH: - if cmd == 'PASS': - return self.ftp_PASS(*params) - else: - return BAD_CMD_SEQ, "PASS required after USER" - - elif self.state == self.AUTHED: - return call_ftp_command(cmd) - - elif self.state == self.RENAMING: - if cmd == 'RNTO': - return self.ftp_RNTO(*params) - else: - return BAD_CMD_SEQ, "RNTO required after RNFR" - - - def getDTPPort(self, factory): - """ - Return a port for passive access, using C{self.passivePortRange} - attribute. - """ - for portn in self.passivePortRange: - try: - dtpPort = self.listenFactory(portn, factory) - except error.CannotListenError: - continue - else: - return dtpPort - raise error.CannotListenError('', portn, - "No port available in range %s" % - (self.passivePortRange,)) - - - def ftp_USER(self, username): - """ - First part of login. Get the username the peer wants to - authenticate as. - """ - if not username: - return defer.fail(CmdSyntaxError('USER requires an argument')) - - self._user = username - self.state = self.INAUTH - if self.factory.allowAnonymous and self._user == self.factory.userAnonymous: - return GUEST_NAME_OK_NEED_EMAIL - else: - return (USR_NAME_OK_NEED_PASS, username) - - # TODO: add max auth try before timeout from ip... - # TODO: need to implement minimal ABOR command - - def ftp_PASS(self, password): - """ - Second part of login. Get the password the peer wants to - authenticate with. - """ - if self.factory.allowAnonymous and self._user == self.factory.userAnonymous: - # anonymous login - creds = credentials.Anonymous() - reply = GUEST_LOGGED_IN_PROCEED - else: - # user login - creds = credentials.UsernamePassword(self._user, password) - reply = USR_LOGGED_IN_PROCEED - del self._user - - def _cbLogin((interface, avatar, logout)): - assert interface is IFTPShell, "The realm is busted, jerk." - self.shell = avatar - self.logout = logout - self.workingDirectory = [] - self.state = self.AUTHED - return reply - - def _ebLogin(failure): - failure.trap(cred_error.UnauthorizedLogin, cred_error.UnhandledCredentials) - self.state = self.UNAUTH - raise AuthorizationError - - d = self.portal.login(creds, None, IFTPShell) - d.addCallbacks(_cbLogin, _ebLogin) - return d - - - def ftp_PASV(self): - """ - Request for a passive connection - - from the rfc:: - - This command requests the server-DTP to \"listen\" on a data port - (which is not its default data port) and to wait for a connection - rather than initiate one upon receipt of a transfer command. The - response to this command includes the host and port address this - server is listening on. - """ - # if we have a DTP port set up, lose it. - if self.dtpFactory is not None: - # cleanupDTP sets dtpFactory to none. Later we'll do - # cleanup here or something. - self.cleanupDTP() - self.dtpFactory = DTPFactory(pi=self) - self.dtpFactory.setTimeout(self.dtpTimeout) - self.dtpPort = self.getDTPPort(self.dtpFactory) - - host = self.transport.getHost().host - port = self.dtpPort.getHost().port - self.reply(ENTERING_PASV_MODE, encodeHostPort(host, port)) - return self.dtpFactory.deferred.addCallback(lambda ign: None) - - - def ftp_PORT(self, address): - addr = map(int, address.split(',')) - ip = '%d.%d.%d.%d' % tuple(addr[:4]) - port = addr[4] << 8 | addr[5] - - # if we have a DTP port set up, lose it. - if self.dtpFactory is not None: - self.cleanupDTP() - - self.dtpFactory = DTPFactory(pi=self, peerHost=self.transport.getPeer().host) - self.dtpFactory.setTimeout(self.dtpTimeout) - self.dtpPort = reactor.connectTCP(ip, port, self.dtpFactory) - - def connected(ignored): - return ENTERING_PORT_MODE - def connFailed(err): - err.trap(PortConnectionError) - return CANT_OPEN_DATA_CNX - return self.dtpFactory.deferred.addCallbacks(connected, connFailed) - - - def _encodeName(self, name): - """ - Encode C{name} to be sent over the wire. - - This encodes L{unicode} objects as UTF-8 and leaves L{bytes} as-is. - - As described by U{RFC 3659 section - 2.2}:: - - Various FTP commands take pathnames as arguments, or return - pathnames in responses. When the MLST command is supported, as - indicated in the response to the FEAT command, pathnames are to be - transferred in one of the following two formats. - - pathname = utf-8-name / raw - utf-8-name = - raw = - - Which format is used is at the option of the user-PI or server-PI - sending the pathname. - - @param name: Name to be encoded. - @type name: L{bytes} or L{unicode} - - @return: Wire format of C{name}. - @rtype: L{bytes} - """ - if isinstance(name, unicode): - return name.encode('utf-8') - return name - - - def ftp_LIST(self, path=''): - """ This command causes a list to be sent from the server to the - passive DTP. If the pathname specifies a directory or other - group of files, the server should transfer a list of files - in the specified directory. If the pathname specifies a - file then the server should send current information on the - file. A null argument implies the user's current working or - default directory. - """ - # Uh, for now, do this retarded thing. - if self.dtpInstance is None or not self.dtpInstance.isConnected: - return defer.fail(BadCmdSequenceError('must send PORT or PASV before RETR')) - - # Various clients send flags like -L or -al etc. We just ignore them. - if path.lower() in ['-a', '-l', '-la', '-al']: - path = '' - - def gotListing(results): - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - for (name, attrs) in results: - name = self._encodeName(name) - self.dtpInstance.sendListResponse(name, attrs) - self.dtpInstance.transport.loseConnection() - return (TXFR_COMPLETE_OK,) - - try: - segments = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - d = self.shell.list( - segments, - ('size', 'directory', 'permissions', 'hardlinks', - 'modified', 'owner', 'group')) - d.addCallback(gotListing) - return d - - - def ftp_NLST(self, path): - """ - This command causes a directory listing to be sent from the server to - the client. The pathname should specify a directory or other - system-specific file group descriptor. An empty path implies the current - working directory. If the path is non-existent, send nothing. If the - path is to a file, send only the file name. - - @type path: C{str} - @param path: The path for which a directory listing should be returned. - - @rtype: L{Deferred} - @return: a L{Deferred} which will be fired when the listing request - is finished. - """ - # XXX: why is this check different from ftp_RETR/ftp_STOR? See #4180 - if self.dtpInstance is None or not self.dtpInstance.isConnected: - return defer.fail( - BadCmdSequenceError('must send PORT or PASV before RETR')) - - try: - segments = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - def cbList(results, glob): - """ - Send, line by line, each matching file in the directory listing, and - then close the connection. - - @type results: A C{list} of C{tuple}. The first element of each - C{tuple} is a C{str} and the second element is a C{list}. - @param results: The names of the files in the directory. - - @param glob: A shell-style glob through which to filter results (see - U{http://docs.python.org/2/library/fnmatch.html}), or C{None} - for no filtering. - @type glob: L{str} or L{NoneType} - - @return: A C{tuple} containing the status code for a successful - transfer. - @rtype: C{tuple} - """ - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - for (name, ignored) in results: - if not glob or (glob and fnmatch.fnmatch(name, glob)): - name = self._encodeName(name) - self.dtpInstance.sendLine(name) - self.dtpInstance.transport.loseConnection() - return (TXFR_COMPLETE_OK,) - - def listErr(results): - """ - RFC 959 specifies that an NLST request may only return directory - listings. Thus, send nothing and just close the connection. - - @type results: L{Failure} - @param results: The L{Failure} wrapping a L{FileNotFoundError} that - occurred while trying to list the contents of a nonexistent - directory. - - @returns: A C{tuple} containing the status code for a successful - transfer. - @rtype: C{tuple} - """ - self.dtpInstance.transport.loseConnection() - return (TXFR_COMPLETE_OK,) - - if _isGlobbingExpression(segments): - # Remove globbing expression from path - # and keep to be used for filtering. - glob = segments.pop() - else: - glob = None - - d = self.shell.list(segments) - d.addCallback(cbList, glob) - # self.shell.list will generate an error if the path is invalid - d.addErrback(listErr) - return d - - - def ftp_CWD(self, path): - try: - segments = toSegments(self.workingDirectory, path) - except InvalidPath: - # XXX Eh, what to fail with here? - return defer.fail(FileNotFoundError(path)) - - def accessGranted(result): - self.workingDirectory = segments - return (REQ_FILE_ACTN_COMPLETED_OK,) - - return self.shell.access(segments).addCallback(accessGranted) - - - def ftp_CDUP(self): - return self.ftp_CWD('..') - - - def ftp_PWD(self): - return (PWD_REPLY, '/' + '/'.join(self.workingDirectory)) - - - def ftp_RETR(self, path): - """ - This command causes the content of a file to be sent over the data - transfer channel. If the path is to a folder, an error will be raised. - - @type path: C{str} - @param path: The path to the file which should be transferred over the - data transfer channel. - - @rtype: L{Deferred} - @return: a L{Deferred} which will be fired when the transfer is done. - """ - if self.dtpInstance is None: - raise BadCmdSequenceError('PORT or PASV required before RETR') - - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - # XXX For now, just disable the timeout. Later we'll want to - # leave it active and have the DTP connection reset it - # periodically. - self.setTimeout(None) - - # Put it back later - def enableTimeout(result): - self.setTimeout(self.factory.timeOut) - return result - - # And away she goes - if not self.binary: - cons = ASCIIConsumerWrapper(self.dtpInstance) - else: - cons = self.dtpInstance - - def cbSent(result): - return (TXFR_COMPLETE_OK,) - - def ebSent(err): - log.msg("Unexpected error attempting to transmit file to client:") - log.err(err) - if err.check(FTPCmdError): - return err - return (CNX_CLOSED_TXFR_ABORTED,) - - def cbOpened(file): - # Tell them what to doooo - if self.dtpInstance.isConnected: - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - else: - self.reply(FILE_STATUS_OK_OPEN_DATA_CNX) - - d = file.send(cons) - d.addCallbacks(cbSent, ebSent) - return d - - def ebOpened(err): - if not err.check(PermissionDeniedError, FileNotFoundError, IsADirectoryError): - log.msg("Unexpected error attempting to open file for transmission:") - log.err(err) - if err.check(FTPCmdError): - return (err.value.errorCode, '/'.join(newsegs)) - return (FILE_NOT_FOUND, '/'.join(newsegs)) - - d = self.shell.openForReading(newsegs) - d.addCallbacks(cbOpened, ebOpened) - d.addBoth(enableTimeout) - - # Pass back Deferred that fires when the transfer is done - return d - - - def ftp_STOR(self, path): - """ - STORE (STOR) - - This command causes the server-DTP to accept the data - transferred via the data connection and to store the data as - a file at the server site. If the file specified in the - pathname exists at the server site, then its contents shall - be replaced by the data being transferred. A new file is - created at the server site if the file specified in the - pathname does not already exist. - """ - if self.dtpInstance is None: - raise BadCmdSequenceError('PORT or PASV required before STOR') - - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - # XXX For now, just disable the timeout. Later we'll want to - # leave it active and have the DTP connection reset it - # periodically. - self.setTimeout(None) - - # Put it back later - def enableTimeout(result): - self.setTimeout(self.factory.timeOut) - return result - - def cbOpened(file): - """ - File was open for reading. Launch the data transfer channel via - the file consumer. - """ - d = file.receive() - d.addCallback(cbConsumer) - d.addCallback(lambda ignored: file.close()) - d.addCallbacks(cbSent, ebSent) - return d - - def ebOpened(err): - """ - Called when failed to open the file for reading. - - For known errors, return the FTP error code. - For all other, return a file not found error. - """ - if isinstance(err.value, FTPCmdError): - return (err.value.errorCode, '/'.join(newsegs)) - log.err(err, "Unexpected error received while opening file:") - return (FILE_NOT_FOUND, '/'.join(newsegs)) - - def cbConsumer(cons): - """ - Called after the file was opended for reading. - - Prepare the data transfer channel and send the response - to the command channel. - """ - if not self.binary: - cons = ASCIIConsumerWrapper(cons) - - d = self.dtpInstance.registerConsumer(cons) - - # Tell them what to doooo - if self.dtpInstance.isConnected: - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - else: - self.reply(FILE_STATUS_OK_OPEN_DATA_CNX) - - return d - - def cbSent(result): - """ - Called from data transport when tranfer is done. - """ - return (TXFR_COMPLETE_OK,) - - def ebSent(err): - """ - Called from data transport when there are errors during the - transfer. - """ - log.err(err, "Unexpected error received during transfer:") - if err.check(FTPCmdError): - return err - return (CNX_CLOSED_TXFR_ABORTED,) - - d = self.shell.openForWriting(newsegs) - d.addCallbacks(cbOpened, ebOpened) - d.addBoth(enableTimeout) - - # Pass back Deferred that fires when the transfer is done - return d - - - def ftp_SIZE(self, path): - """ - File SIZE - - The FTP command, SIZE OF FILE (SIZE), is used to obtain the transfer - size of a file from the server-FTP process. This is the exact number - of octets (8 bit bytes) that would be transmitted over the data - connection should that file be transmitted. This value will change - depending on the current STRUcture, MODE, and TYPE of the data - connection or of a data connection that would be created were one - created now. Thus, the result of the SIZE command is dependent on - the currently established STRU, MODE, and TYPE parameters. - - The SIZE command returns how many octets would be transferred if the - file were to be transferred using the current transfer structure, - mode, and type. This command is normally used in conjunction with - the RESTART (REST) command when STORing a file to a remote server in - STREAM mode, to determine the restart point. The server-PI might - need to read the partially transferred file, do any appropriate - conversion, and count the number of octets that would be generated - when sending the file in order to correctly respond to this command. - Estimates of the file transfer size MUST NOT be returned; only - precise information is acceptable. - - http://tools.ietf.org/html/rfc3659 - """ - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - def cbStat((size,)): - return (FILE_STATUS, str(size)) - - return self.shell.stat(newsegs, ('size',)).addCallback(cbStat) - - - def ftp_MDTM(self, path): - """ - File Modification Time (MDTM) - - The FTP command, MODIFICATION TIME (MDTM), can be used to determine - when a file in the server NVFS was last modified. This command has - existed in many FTP servers for many years, as an adjunct to the REST - command for STREAM mode, thus is widely available. However, where - supported, the "modify" fact that can be provided in the result from - the new MLST command is recommended as a superior alternative. - - http://tools.ietf.org/html/rfc3659 - """ - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - def cbStat((modified,)): - return (FILE_STATUS, time.strftime('%Y%m%d%H%M%S', time.gmtime(modified))) - - return self.shell.stat(newsegs, ('modified',)).addCallback(cbStat) - - - def ftp_TYPE(self, type): - """ - REPRESENTATION TYPE (TYPE) - - The argument specifies the representation type as described - in the Section on Data Representation and Storage. Several - types take a second parameter. The first parameter is - denoted by a single Telnet character, as is the second - Format parameter for ASCII and EBCDIC; the second parameter - for local byte is a decimal integer to indicate Bytesize. - The parameters are separated by a (Space, ASCII code - 32). - """ - p = type.upper() - if p: - f = getattr(self, 'type_' + p[0], None) - if f is not None: - return f(p[1:]) - return self.type_UNKNOWN(p) - return (SYNTAX_ERR,) - - def type_A(self, code): - if code == '' or code == 'N': - self.binary = False - return (TYPE_SET_OK, 'A' + code) - else: - return defer.fail(CmdArgSyntaxError(code)) - - def type_I(self, code): - if code == '': - self.binary = True - return (TYPE_SET_OK, 'I') - else: - return defer.fail(CmdArgSyntaxError(code)) - - def type_UNKNOWN(self, code): - return defer.fail(CmdNotImplementedForArgError(code)) - - - - def ftp_SYST(self): - return NAME_SYS_TYPE - - - def ftp_STRU(self, structure): - p = structure.upper() - if p == 'F': - return (CMD_OK,) - return defer.fail(CmdNotImplementedForArgError(structure)) - - - def ftp_MODE(self, mode): - p = mode.upper() - if p == 'S': - return (CMD_OK,) - return defer.fail(CmdNotImplementedForArgError(mode)) - - - def ftp_MKD(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - return self.shell.makeDirectory(newsegs).addCallback(lambda ign: (MKD_REPLY, path)) - - - def ftp_RMD(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - return self.shell.removeDirectory(newsegs).addCallback(lambda ign: (REQ_FILE_ACTN_COMPLETED_OK,)) - - - def ftp_DELE(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - return self.shell.removeFile(newsegs).addCallback(lambda ign: (REQ_FILE_ACTN_COMPLETED_OK,)) - - - def ftp_NOOP(self): - return (CMD_OK,) - - - def ftp_RNFR(self, fromName): - self._fromName = fromName - self.state = self.RENAMING - return (REQ_FILE_ACTN_PENDING_FURTHER_INFO,) - - - def ftp_RNTO(self, toName): - fromName = self._fromName - del self._fromName - self.state = self.AUTHED - - try: - fromsegs = toSegments(self.workingDirectory, fromName) - tosegs = toSegments(self.workingDirectory, toName) - except InvalidPath: - return defer.fail(FileNotFoundError(fromName)) - return self.shell.rename(fromsegs, tosegs).addCallback(lambda ign: (REQ_FILE_ACTN_COMPLETED_OK,)) - - - def ftp_FEAT(self): - """ - Advertise the features supported by the server. - - http://tools.ietf.org/html/rfc2389 - """ - self.sendLine(RESPONSE[FEAT_OK][0]) - for feature in self.FEATURES: - self.sendLine(' ' + feature) - self.sendLine(RESPONSE[FEAT_OK][1]) - - def ftp_OPTS(self, option): - """ - Handle OPTS command. - - http://tools.ietf.org/html/draft-ietf-ftpext-utf-8-option-00 - """ - return self.reply(OPTS_NOT_IMPLEMENTED, option) - - def ftp_QUIT(self): - self.reply(GOODBYE_MSG) - self.transport.loseConnection() - self.disconnected = True - - def cleanupDTP(self): - """ - Call when DTP connection exits - """ - log.msg('cleanupDTP', debug=True) - - log.msg(self.dtpPort) - dtpPort, self.dtpPort = self.dtpPort, None - if interfaces.IListeningPort.providedBy(dtpPort): - dtpPort.stopListening() - elif interfaces.IConnector.providedBy(dtpPort): - dtpPort.disconnect() - else: - assert False, "dtpPort should be an IListeningPort or IConnector, instead is %r" % (dtpPort,) - - self.dtpFactory.stopFactory() - self.dtpFactory = None - - if self.dtpInstance is not None: - self.dtpInstance = None - - -class FTPFactory(policies.LimitTotalConnectionsFactory): - """ - A factory for producing ftp protocol instances - - @ivar timeOut: the protocol interpreter's idle timeout time in seconds, - default is 600 seconds. - - @ivar passivePortRange: value forwarded to C{protocol.passivePortRange}. - @type passivePortRange: C{iterator} - """ - protocol = FTP - overflowProtocol = FTPOverflowProtocol - allowAnonymous = True - userAnonymous = 'anonymous' - timeOut = 600 - - welcomeMessage = "Twisted %s FTP Server" % (copyright.version,) - - passivePortRange = xrange(0, 1) - - def __init__(self, portal=None, userAnonymous='anonymous'): - self.portal = portal - self.userAnonymous = userAnonymous - self.instances = [] - - def buildProtocol(self, addr): - p = policies.LimitTotalConnectionsFactory.buildProtocol(self, addr) - if p is not None: - p.wrappedProtocol.portal = self.portal - p.wrappedProtocol.timeOut = self.timeOut - p.wrappedProtocol.passivePortRange = self.passivePortRange - return p - - def stopFactory(self): - # make sure ftp instance's timeouts are set to None - # to avoid reactor complaints - [p.setTimeout(None) for p in self.instances if p.timeOut is not None] - policies.LimitTotalConnectionsFactory.stopFactory(self) - -# -- Cred Objects -- - - -class IFTPShell(Interface): - """ - An abstraction of the shell commands used by the FTP protocol for - a given user account. - - All path names must be absolute. - """ - - def makeDirectory(path): - """ - Create a directory. - - @param path: The path, as a list of segments, to create - @type path: C{list} of C{unicode} - - @return: A Deferred which fires when the directory has been - created, or which fails if the directory cannot be created. - """ - - - def removeDirectory(path): - """ - Remove a directory. - - @param path: The path, as a list of segments, to remove - @type path: C{list} of C{unicode} - - @return: A Deferred which fires when the directory has been - removed, or which fails if the directory cannot be removed. - """ - - - def removeFile(path): - """ - Remove a file. - - @param path: The path, as a list of segments, to remove - @type path: C{list} of C{unicode} - - @return: A Deferred which fires when the file has been - removed, or which fails if the file cannot be removed. - """ - - - def rename(fromPath, toPath): - """ - Rename a file or directory. - - @param fromPath: The current name of the path. - @type fromPath: C{list} of C{unicode} - - @param toPath: The desired new name of the path. - @type toPath: C{list} of C{unicode} - - @return: A Deferred which fires when the path has been - renamed, or which fails if the path cannot be renamed. - """ - - - def access(path): - """ - Determine whether access to the given path is allowed. - - @param path: The path, as a list of segments - - @return: A Deferred which fires with None if access is allowed - or which fails with a specific exception type if access is - denied. - """ - - - def stat(path, keys=()): - """ - Retrieve information about the given path. - - This is like list, except it will never return results about - child paths. - """ - - - def list(path, keys=()): - """ - Retrieve information about the given path. - - If the path represents a non-directory, the result list should - have only one entry with information about that non-directory. - Otherwise, the result list should have an element for each - child of the directory. - - @param path: The path, as a list of segments, to list - @type path: C{list} of C{unicode} or C{bytes} - - @param keys: A tuple of keys desired in the resulting - dictionaries. - - @return: A Deferred which fires with a list of (name, list), - where the name is the name of the entry as a unicode string or - bytes and each list contains values corresponding to the requested - keys. The following are possible elements of keys, and the - values which should be returned for them: - - - C{'size'}: size in bytes, as an integer (this is kinda required) - - - C{'directory'}: boolean indicating the type of this entry - - - C{'permissions'}: a bitvector (see os.stat(foo).st_mode) - - - C{'hardlinks'}: Number of hard links to this entry - - - C{'modified'}: number of seconds since the epoch since entry was - modified - - - C{'owner'}: string indicating the user owner of this entry - - - C{'group'}: string indicating the group owner of this entry - """ - - - def openForReading(path): - """ - @param path: The path, as a list of segments, to open - @type path: C{list} of C{unicode} - - @rtype: C{Deferred} which will fire with L{IReadFile} - """ - - - def openForWriting(path): - """ - @param path: The path, as a list of segments, to open - @type path: C{list} of C{unicode} - - @rtype: C{Deferred} which will fire with L{IWriteFile} - """ - - - -class IReadFile(Interface): - """ - A file out of which bytes may be read. - """ - - def send(consumer): - """ - Produce the contents of the given path to the given consumer. This - method may only be invoked once on each provider. - - @type consumer: C{IConsumer} - - @return: A Deferred which fires when the file has been - consumed completely. - """ - - - -class IWriteFile(Interface): - """ - A file into which bytes may be written. - """ - - def receive(): - """ - Create a consumer which will write to this file. This method may - only be invoked once on each provider. - - @rtype: C{Deferred} of C{IConsumer} - """ - - def close(): - """ - Perform any post-write work that needs to be done. This method may - only be invoked once on each provider, and will always be invoked - after receive(). - - @rtype: C{Deferred} of anything: the value is ignored. The FTP client - will not see their upload request complete until this Deferred has - been fired. - """ - -def _getgroups(uid): - """ - Return the primary and supplementary groups for the given UID. - - @type uid: C{int} - """ - result = [] - pwent = pwd.getpwuid(uid) - - result.append(pwent.pw_gid) - - for grent in grp.getgrall(): - if pwent.pw_name in grent.gr_mem: - result.append(grent.gr_gid) - - return result - - -def _testPermissions(uid, gid, spath, mode='r'): - """ - checks to see if uid has proper permissions to access path with mode - - @type uid: C{int} - @param uid: numeric user id - - @type gid: C{int} - @param gid: numeric group id - - @type spath: C{str} - @param spath: the path on the server to test - - @type mode: C{str} - @param mode: 'r' or 'w' (read or write) - - @rtype: C{bool} - @return: True if the given credentials have the specified form of - access to the given path - """ - if mode == 'r': - usr = stat.S_IRUSR - grp = stat.S_IRGRP - oth = stat.S_IROTH - amode = os.R_OK - elif mode == 'w': - usr = stat.S_IWUSR - grp = stat.S_IWGRP - oth = stat.S_IWOTH - amode = os.W_OK - else: - raise ValueError("Invalid mode %r: must specify 'r' or 'w'" % (mode,)) - - access = False - if os.path.exists(spath): - if uid == 0: - access = True - else: - s = os.stat(spath) - if usr & s.st_mode and uid == s.st_uid: - access = True - elif grp & s.st_mode and gid in _getgroups(uid): - access = True - elif oth & s.st_mode: - access = True - - if access: - if not os.access(spath, amode): - access = False - log.msg("Filesystem grants permission to UID %d but it is inaccessible to me running as UID %d" % ( - uid, os.getuid())) - return access - - - -class FTPAnonymousShell(object): - """ - An anonymous implementation of IFTPShell - - @type filesystemRoot: L{twisted.python.filepath.FilePath} - @ivar filesystemRoot: The path which is considered the root of - this shell. - """ - implements(IFTPShell) - - def __init__(self, filesystemRoot): - self.filesystemRoot = filesystemRoot - - - def _path(self, path): - return self.filesystemRoot.descendant(path) - - - def makeDirectory(self, path): - return defer.fail(AnonUserDeniedError()) - - - def removeDirectory(self, path): - return defer.fail(AnonUserDeniedError()) - - - def removeFile(self, path): - return defer.fail(AnonUserDeniedError()) - - - def rename(self, fromPath, toPath): - return defer.fail(AnonUserDeniedError()) - - - def receive(self, path): - path = self._path(path) - return defer.fail(AnonUserDeniedError()) - - - def openForReading(self, path): - """ - Open C{path} for reading. - - @param path: The path, as a list of segments, to open. - @type path: C{list} of C{unicode} - @return: A L{Deferred} is returned that will fire with an object - implementing L{IReadFile} if the file is successfully opened. If - C{path} is a directory, or if an exception is raised while trying - to open the file, the L{Deferred} will fire with an error. - """ - p = self._path(path) - if p.isdir(): - # Normally, we would only check for EISDIR in open, but win32 - # returns EACCES in this case, so we check before - return defer.fail(IsADirectoryError(path)) - try: - f = p.open('r') - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(_FileReader(f)) - - - def openForWriting(self, path): - """ - Reject write attempts by anonymous users with - L{PermissionDeniedError}. - """ - return defer.fail(PermissionDeniedError("STOR not allowed")) - - - def access(self, path): - p = self._path(path) - if not p.exists(): - # Again, win32 doesn't report a sane error after, so let's fail - # early if we can - return defer.fail(FileNotFoundError(path)) - # For now, just see if we can os.listdir() it - try: - p.listdir() - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def stat(self, path, keys=()): - p = self._path(path) - if p.isdir(): - try: - statResult = self._statNode(p, keys) - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(statResult) - else: - return self.list(path, keys).addCallback(lambda res: res[0][1]) - - - def list(self, path, keys=()): - """ - Return the list of files at given C{path}, adding C{keys} stat - informations if specified. - - @param path: the directory or file to check. - @type path: C{str} - - @param keys: the list of desired metadata - @type keys: C{list} of C{str} - """ - filePath = self._path(path) - if filePath.isdir(): - entries = filePath.listdir() - fileEntries = [filePath.child(p) for p in entries] - elif filePath.isfile(): - entries = [os.path.join(*filePath.segmentsFrom(self.filesystemRoot))] - fileEntries = [filePath] - else: - return defer.fail(FileNotFoundError(path)) - - results = [] - for fileName, filePath in zip(entries, fileEntries): - ent = [] - results.append((fileName, ent)) - if keys: - try: - ent.extend(self._statNode(filePath, keys)) - except (IOError, OSError), e: - return errnoToFailure(e.errno, fileName) - except: - return defer.fail() - - return defer.succeed(results) - - - def _statNode(self, filePath, keys): - """ - Shortcut method to get stat info on a node. - - @param filePath: the node to stat. - @type filePath: C{filepath.FilePath} - - @param keys: the stat keys to get. - @type keys: C{iterable} - """ - filePath.restat() - return [getattr(self, '_stat_' + k)(filePath) for k in keys] - - - def _stat_size(self, fp): - """ - Get the filepath's size as an int - - @param fp: L{twisted.python.filepath.FilePath} - @return: C{int} representing the size - """ - return fp.getsize() - - - def _stat_permissions(self, fp): - """ - Get the filepath's permissions object - - @param fp: L{twisted.python.filepath.FilePath} - @return: L{twisted.python.filepath.Permissions} of C{fp} - """ - return fp.getPermissions() - - - def _stat_hardlinks(self, fp): - """ - Get the number of hardlinks for the filepath - if the number of - hardlinks is not yet implemented (say in Windows), just return 0 since - stat-ing a file in Windows seems to return C{st_nlink=0}. - - (Reference: - U{http://stackoverflow.com/questions/5275731/os-stat-on-windows}) - - @param fp: L{twisted.python.filepath.FilePath} - @return: C{int} representing the number of hardlinks - """ - try: - return fp.getNumberOfHardLinks() - except NotImplementedError: - return 0 - - - def _stat_modified(self, fp): - """ - Get the filepath's last modified date - - @param fp: L{twisted.python.filepath.FilePath} - @return: C{int} as seconds since the epoch - """ - return fp.getModificationTime() - - - def _stat_owner(self, fp): - """ - Get the filepath's owner's username. If this is not implemented - (say in Windows) return the string "0" since stat-ing a file in - Windows seems to return C{st_uid=0}. - - (Reference: - U{http://stackoverflow.com/questions/5275731/os-stat-on-windows}) - - @param fp: L{twisted.python.filepath.FilePath} - @return: C{str} representing the owner's username - """ - try: - userID = fp.getUserID() - except NotImplementedError: - return "0" - else: - if pwd is not None: - try: - return pwd.getpwuid(userID)[0] - except KeyError: - pass - return str(userID) - - - def _stat_group(self, fp): - """ - Get the filepath's owner's group. If this is not implemented - (say in Windows) return the string "0" since stat-ing a file in - Windows seems to return C{st_gid=0}. - - (Reference: - U{http://stackoverflow.com/questions/5275731/os-stat-on-windows}) - - @param fp: L{twisted.python.filepath.FilePath} - @return: C{str} representing the owner's group - """ - try: - groupID = fp.getGroupID() - except NotImplementedError: - return "0" - else: - if grp is not None: - try: - return grp.getgrgid(groupID)[0] - except KeyError: - pass - return str(groupID) - - - def _stat_directory(self, fp): - """ - Get whether the filepath is a directory - - @param fp: L{twisted.python.filepath.FilePath} - @return: C{bool} - """ - return fp.isdir() - - - -class _FileReader(object): - implements(IReadFile) - - def __init__(self, fObj): - self.fObj = fObj - self._send = False - - def _close(self, passthrough): - self._send = True - self.fObj.close() - return passthrough - - def send(self, consumer): - assert not self._send, "Can only call IReadFile.send *once* per instance" - self._send = True - d = basic.FileSender().beginFileTransfer(self.fObj, consumer) - d.addBoth(self._close) - return d - - - -class FTPShell(FTPAnonymousShell): - """ - An authenticated implementation of L{IFTPShell}. - """ - - def makeDirectory(self, path): - p = self._path(path) - try: - p.makedirs() - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def removeDirectory(self, path): - p = self._path(path) - if p.isfile(): - # Win32 returns the wrong errno when rmdir is called on a file - # instead of a directory, so as we have the info here, let's fail - # early with a pertinent error - return defer.fail(IsNotADirectoryError(path)) - try: - os.rmdir(p.path) - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def removeFile(self, path): - p = self._path(path) - if p.isdir(): - # Win32 returns the wrong errno when remove is called on a - # directory instead of a file, so as we have the info here, - # let's fail early with a pertinent error - return defer.fail(IsADirectoryError(path)) - try: - p.remove() - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def rename(self, fromPath, toPath): - fp = self._path(fromPath) - tp = self._path(toPath) - try: - os.rename(fp.path, tp.path) - except (IOError, OSError), e: - return errnoToFailure(e.errno, fromPath) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def openForWriting(self, path): - """ - Open C{path} for writing. - - @param path: The path, as a list of segments, to open. - @type path: C{list} of C{unicode} - @return: A L{Deferred} is returned that will fire with an object - implementing L{IWriteFile} if the file is successfully opened. If - C{path} is a directory, or if an exception is raised while trying - to open the file, the L{Deferred} will fire with an error. - """ - p = self._path(path) - if p.isdir(): - # Normally, we would only check for EISDIR in open, but win32 - # returns EACCES in this case, so we check before - return defer.fail(IsADirectoryError(path)) - try: - fObj = p.open('w') - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - return defer.succeed(_FileWriter(fObj)) - - - -class _FileWriter(object): - implements(IWriteFile) - - def __init__(self, fObj): - self.fObj = fObj - self._receive = False - - def receive(self): - assert not self._receive, "Can only call IWriteFile.receive *once* per instance" - self._receive = True - # FileConsumer will close the file object - return defer.succeed(FileConsumer(self.fObj)) - - def close(self): - return defer.succeed(None) - - - -class BaseFTPRealm: - """ - Base class for simple FTP realms which provides an easy hook for specifying - the home directory for each user. - """ - implements(portal.IRealm) - - def __init__(self, anonymousRoot): - self.anonymousRoot = filepath.FilePath(anonymousRoot) - - - def getHomeDirectory(self, avatarId): - """ - Return a L{FilePath} representing the home directory of the given - avatar. Override this in a subclass. - - @param avatarId: A user identifier returned from a credentials checker. - @type avatarId: C{str} - - @rtype: L{FilePath} - """ - raise NotImplementedError( - "%r did not override getHomeDirectory" % (self.__class__,)) - - - def requestAvatar(self, avatarId, mind, *interfaces): - for iface in interfaces: - if iface is IFTPShell: - if avatarId is checkers.ANONYMOUS: - avatar = FTPAnonymousShell(self.anonymousRoot) - else: - avatar = FTPShell(self.getHomeDirectory(avatarId)) - return (IFTPShell, avatar, - getattr(avatar, 'logout', lambda: None)) - raise NotImplementedError( - "Only IFTPShell interface is supported by this realm") - - - -class FTPRealm(BaseFTPRealm): - """ - @type anonymousRoot: L{twisted.python.filepath.FilePath} - @ivar anonymousRoot: Root of the filesystem to which anonymous - users will be granted access. - - @type userHome: L{filepath.FilePath} - @ivar userHome: Root of the filesystem containing user home directories. - """ - def __init__(self, anonymousRoot, userHome='/home'): - BaseFTPRealm.__init__(self, anonymousRoot) - self.userHome = filepath.FilePath(userHome) - - - def getHomeDirectory(self, avatarId): - """ - Use C{avatarId} as a single path segment to construct a child of - C{self.userHome} and return that child. - """ - return self.userHome.child(avatarId) - - - -class SystemFTPRealm(BaseFTPRealm): - """ - L{SystemFTPRealm} uses system user account information to decide what the - home directory for a particular avatarId is. - - This works on POSIX but probably is not reliable on Windows. - """ - def getHomeDirectory(self, avatarId): - """ - Return the system-defined home directory of the system user account with - the name C{avatarId}. - """ - path = os.path.expanduser('~' + avatarId) - if path.startswith('~'): - raise cred_error.UnauthorizedLogin() - return filepath.FilePath(path) - - - -# --- FTP CLIENT ------------------------------------------------------------- - -#### -# And now for the client... - -# Notes: -# * Reference: http://cr.yp.to/ftp.html -# * FIXME: Does not support pipelining (which is not supported by all -# servers anyway). This isn't a functionality limitation, just a -# small performance issue. -# * Only has a rudimentary understanding of FTP response codes (although -# the full response is passed to the caller if they so choose). -# * Assumes that USER and PASS should always be sent -# * Always sets TYPE I (binary mode) -# * Doesn't understand any of the weird, obscure TELNET stuff (\377...) -# * FIXME: Doesn't share any code with the FTPServer - -class ConnectionLost(FTPError): - pass - -class CommandFailed(FTPError): - pass - -class BadResponse(FTPError): - pass - -class UnexpectedResponse(FTPError): - pass - -class UnexpectedData(FTPError): - pass - -class FTPCommand: - def __init__(self, text=None, public=0): - self.text = text - self.deferred = defer.Deferred() - self.ready = 1 - self.public = public - self.transferDeferred = None - - def fail(self, failure): - if self.public: - self.deferred.errback(failure) - - -class ProtocolWrapper(protocol.Protocol): - def __init__(self, original, deferred): - self.original = original - self.deferred = deferred - def makeConnection(self, transport): - self.original.makeConnection(transport) - def dataReceived(self, data): - self.original.dataReceived(data) - def connectionLost(self, reason): - self.original.connectionLost(reason) - # Signal that transfer has completed - self.deferred.callback(None) - - - -class IFinishableConsumer(interfaces.IConsumer): - """ - A Consumer for producers that finish. - - @since: 11.0 - """ - - def finish(): - """ - The producer has finished producing. - """ - - - -class SenderProtocol(protocol.Protocol): - implements(IFinishableConsumer) - - def __init__(self): - # Fired upon connection - self.connectedDeferred = defer.Deferred() - - # Fired upon disconnection - self.deferred = defer.Deferred() - - #Protocol stuff - def dataReceived(self, data): - raise UnexpectedData( - "Received data from the server on a " - "send-only data-connection" - ) - - def makeConnection(self, transport): - protocol.Protocol.makeConnection(self, transport) - self.connectedDeferred.callback(self) - - def connectionLost(self, reason): - if reason.check(error.ConnectionDone): - self.deferred.callback('connection done') - else: - self.deferred.errback(reason) - - #IFinishableConsumer stuff - def write(self, data): - self.transport.write(data) - - def registerProducer(self, producer, streaming): - """ - Register the given producer with our transport. - """ - self.transport.registerProducer(producer, streaming) - - def unregisterProducer(self): - """ - Unregister the previously registered producer. - """ - self.transport.unregisterProducer() - - def finish(self): - self.transport.loseConnection() - - -def decodeHostPort(line): - """ - Decode an FTP response specifying a host and port. - - @return: a 2-tuple of (host, port). - """ - abcdef = re.sub('[^0-9, ]', '', line) - parsed = [int(p.strip()) for p in abcdef.split(',')] - for x in parsed: - if x < 0 or x > 255: - raise ValueError("Out of range", line, x) - a, b, c, d, e, f = parsed - host = "%s.%s.%s.%s" % (a, b, c, d) - port = (int(e) << 8) + int(f) - return host, port - -def encodeHostPort(host, port): - numbers = host.split('.') + [str(port >> 8), str(port % 256)] - return ','.join(numbers) - -def _unwrapFirstError(failure): - failure.trap(defer.FirstError) - return failure.value.subFailure - -class FTPDataPortFactory(protocol.ServerFactory): - """ - Factory for data connections that use the PORT command - - (i.e. "active" transfers) - """ - noisy = 0 - def buildProtocol(self, addr): - # This is a bit hackish -- we already have a Protocol instance, - # so just return it instead of making a new one - # FIXME: Reject connections from the wrong address/port - # (potential security problem) - self.protocol.factory = self - self.port.loseConnection() - return self.protocol - - -class FTPClientBasic(basic.LineReceiver): - """ - Foundations of an FTP client. - """ - debug = False - - def __init__(self): - self.actionQueue = [] - self.greeting = None - self.nextDeferred = defer.Deferred().addCallback(self._cb_greeting) - self.nextDeferred.addErrback(self.fail) - self.response = [] - self._failed = 0 - - def fail(self, error): - """ - Give an error to any queued deferreds. - """ - self._fail(error) - - def _fail(self, error): - """ - Errback all queued deferreds. - """ - if self._failed: - # We're recursing; bail out here for simplicity - return error - self._failed = 1 - if self.nextDeferred: - try: - self.nextDeferred.errback(failure.Failure(ConnectionLost('FTP connection lost', error))) - except defer.AlreadyCalledError: - pass - for ftpCommand in self.actionQueue: - ftpCommand.fail(failure.Failure(ConnectionLost('FTP connection lost', error))) - return error - - def _cb_greeting(self, greeting): - self.greeting = greeting - - def sendLine(self, line): - """ - (Private) Sends a line, unless line is None. - """ - if line is None: - return - basic.LineReceiver.sendLine(self, line) - - def sendNextCommand(self): - """ - (Private) Processes the next command in the queue. - """ - ftpCommand = self.popCommandQueue() - if ftpCommand is None: - self.nextDeferred = None - return - if not ftpCommand.ready: - self.actionQueue.insert(0, ftpCommand) - reactor.callLater(1.0, self.sendNextCommand) - self.nextDeferred = None - return - - # FIXME: this if block doesn't belong in FTPClientBasic, it belongs in - # FTPClient. - if ftpCommand.text == 'PORT': - self.generatePortCommand(ftpCommand) - - if self.debug: - log.msg('<-- %s' % ftpCommand.text) - self.nextDeferred = ftpCommand.deferred - self.sendLine(ftpCommand.text) - - def queueCommand(self, ftpCommand): - """ - Add an FTPCommand object to the queue. - - If it's the only thing in the queue, and we are connected and we aren't - waiting for a response of an earlier command, the command will be sent - immediately. - - @param ftpCommand: an L{FTPCommand} - """ - self.actionQueue.append(ftpCommand) - if (len(self.actionQueue) == 1 and self.transport is not None and - self.nextDeferred is None): - self.sendNextCommand() - - def queueStringCommand(self, command, public=1): - """ - Queues a string to be issued as an FTP command - - @param command: string of an FTP command to queue - @param public: a flag intended for internal use by FTPClient. Don't - change it unless you know what you're doing. - - @return: a L{Deferred} that will be called when the response to the - command has been received. - """ - ftpCommand = FTPCommand(command, public) - self.queueCommand(ftpCommand) - return ftpCommand.deferred - - def popCommandQueue(self): - """ - Return the front element of the command queue, or None if empty. - """ - if self.actionQueue: - return self.actionQueue.pop(0) - else: - return None - - def queueLogin(self, username, password): - """ - Login: send the username, send the password. - - If the password is C{None}, the PASS command won't be sent. Also, if - the response to the USER command has a response code of 230 (User logged - in), then PASS won't be sent either. - """ - # Prepare the USER command - deferreds = [] - userDeferred = self.queueStringCommand('USER ' + username, public=0) - deferreds.append(userDeferred) - - # Prepare the PASS command (if a password is given) - if password is not None: - passwordCmd = FTPCommand('PASS ' + password, public=0) - self.queueCommand(passwordCmd) - deferreds.append(passwordCmd.deferred) - - # Avoid sending PASS if the response to USER is 230. - # (ref: http://cr.yp.to/ftp/user.html#user) - def cancelPasswordIfNotNeeded(response): - if response[0].startswith('230'): - # No password needed! - self.actionQueue.remove(passwordCmd) - return response - userDeferred.addCallback(cancelPasswordIfNotNeeded) - - # Error handling. - for deferred in deferreds: - # If something goes wrong, call fail - deferred.addErrback(self.fail) - # But also swallow the error, so we don't cause spurious errors - deferred.addErrback(lambda x: None) - - def lineReceived(self, line): - """ - (Private) Parses the response messages from the FTP server. - """ - # Add this line to the current response - if self.debug: - log.msg('--> %s' % line) - self.response.append(line) - - # Bail out if this isn't the last line of a response - # The last line of response starts with 3 digits followed by a space - codeIsValid = re.match(r'\d{3} ', line) - if not codeIsValid: - return - - code = line[0:3] - - # Ignore marks - if code[0] == '1': - return - - # Check that we were expecting a response - if self.nextDeferred is None: - self.fail(UnexpectedResponse(self.response)) - return - - # Reset the response - response = self.response - self.response = [] - - # Look for a success or error code, and call the appropriate callback - if code[0] in ('2', '3'): - # Success - self.nextDeferred.callback(response) - elif code[0] in ('4', '5'): - # Failure - self.nextDeferred.errback(failure.Failure(CommandFailed(response))) - else: - # This shouldn't happen unless something screwed up. - log.msg('Server sent invalid response code %s' % (code,)) - self.nextDeferred.errback(failure.Failure(BadResponse(response))) - - # Run the next command - self.sendNextCommand() - - def connectionLost(self, reason): - self._fail(reason) - - - -class _PassiveConnectionFactory(protocol.ClientFactory): - noisy = False - - def __init__(self, protoInstance): - self.protoInstance = protoInstance - - def buildProtocol(self, ignored): - self.protoInstance.factory = self - return self.protoInstance - - def clientConnectionFailed(self, connector, reason): - e = FTPError('Connection Failed', reason) - self.protoInstance.deferred.errback(e) - - - -class FTPClient(FTPClientBasic): - """ - L{FTPClient} is a client implementation of the FTP protocol which - exposes FTP commands as methods which return L{Deferred}s. - - Each command method returns a L{Deferred} which is called back when a - successful response code (2xx or 3xx) is received from the server or - which is error backed if an error response code (4xx or 5xx) is received - from the server or if a protocol violation occurs. If an error response - code is received, the L{Deferred} fires with a L{Failure} wrapping a - L{CommandFailed} instance. The L{CommandFailed} instance is created - with a list of the response lines received from the server. - - See U{RFC 959} for error code - definitions. - - Both active and passive transfers are supported. - - @ivar passive: See description in __init__. - """ - connectFactory = reactor.connectTCP - - def __init__(self, username='anonymous', - password='twisted@twistedmatrix.com', - passive=1): - """ - Constructor. - - I will login as soon as I receive the welcome message from the server. - - @param username: FTP username - @param password: FTP password - @param passive: flag that controls if I use active or passive data - connections. You can also change this after construction by - assigning to C{self.passive}. - """ - FTPClientBasic.__init__(self) - self.queueLogin(username, password) - - self.passive = passive - - def fail(self, error): - """ - Disconnect, and also give an error to any queued deferreds. - """ - self.transport.loseConnection() - self._fail(error) - - def receiveFromConnection(self, commands, protocol): - """ - Retrieves a file or listing generated by the given command, - feeding it to the given protocol. - - @param commands: list of strings of FTP commands to execute then receive - the results of (e.g. C{LIST}, C{RETR}) - @param protocol: A L{Protocol} B{instance} e.g. an - L{FTPFileListProtocol}, or something that can be adapted to one. - Typically this will be an L{IConsumer} implementation. - - @return: L{Deferred}. - """ - protocol = interfaces.IProtocol(protocol) - wrapper = ProtocolWrapper(protocol, defer.Deferred()) - return self._openDataConnection(commands, wrapper) - - def queueLogin(self, username, password): - """ - Login: send the username, send the password, and - set retrieval mode to binary - """ - FTPClientBasic.queueLogin(self, username, password) - d = self.queueStringCommand('TYPE I', public=0) - # If something goes wrong, call fail - d.addErrback(self.fail) - # But also swallow the error, so we don't cause spurious errors - d.addErrback(lambda x: None) - - def sendToConnection(self, commands): - """ - XXX - - @return: A tuple of two L{Deferred}s: - - L{Deferred} L{IFinishableConsumer}. You must call - the C{finish} method on the IFinishableConsumer when the file - is completely transferred. - - L{Deferred} list of control-connection responses. - """ - s = SenderProtocol() - r = self._openDataConnection(commands, s) - return (s.connectedDeferred, r) - - def _openDataConnection(self, commands, protocol): - """ - This method returns a DeferredList. - """ - cmds = [FTPCommand(command, public=1) for command in commands] - cmdsDeferred = defer.DeferredList([cmd.deferred for cmd in cmds], - fireOnOneErrback=True, consumeErrors=True) - cmdsDeferred.addErrback(_unwrapFirstError) - - if self.passive: - # Hack: use a mutable object to sneak a variable out of the - # scope of doPassive - _mutable = [None] - def doPassive(response): - """Connect to the port specified in the response to PASV""" - host, port = decodeHostPort(response[-1][4:]) - - f = _PassiveConnectionFactory(protocol) - _mutable[0] = self.connectFactory(host, port, f) - - pasvCmd = FTPCommand('PASV') - self.queueCommand(pasvCmd) - pasvCmd.deferred.addCallback(doPassive).addErrback(self.fail) - - results = [cmdsDeferred, pasvCmd.deferred, protocol.deferred] - d = defer.DeferredList(results, fireOnOneErrback=True, consumeErrors=True) - d.addErrback(_unwrapFirstError) - - # Ensure the connection is always closed - def close(x, m=_mutable): - m[0] and m[0].disconnect() - return x - d.addBoth(close) - - else: - # We just place a marker command in the queue, and will fill in - # the host and port numbers later (see generatePortCommand) - portCmd = FTPCommand('PORT') - - # Ok, now we jump through a few hoops here. - # This is the problem: a transfer is not to be trusted as complete - # until we get both the "226 Transfer complete" message on the - # control connection, and the data socket is closed. Thus, we use - # a DeferredList to make sure we only fire the callback at the - # right time. - - portCmd.transferDeferred = protocol.deferred - portCmd.protocol = protocol - portCmd.deferred.addErrback(portCmd.transferDeferred.errback) - self.queueCommand(portCmd) - - # Create dummy functions for the next callback to call. - # These will also be replaced with real functions in - # generatePortCommand. - portCmd.loseConnection = lambda result: result - portCmd.fail = lambda error: error - - # Ensure that the connection always gets closed - cmdsDeferred.addErrback(lambda e, pc=portCmd: pc.fail(e) or e) - - results = [cmdsDeferred, portCmd.deferred, portCmd.transferDeferred] - d = defer.DeferredList(results, fireOnOneErrback=True, consumeErrors=True) - d.addErrback(_unwrapFirstError) - - for cmd in cmds: - self.queueCommand(cmd) - return d - - def generatePortCommand(self, portCmd): - """ - (Private) Generates the text of a given PORT command. - """ - - # The problem is that we don't create the listening port until we need - # it for various reasons, and so we have to muck about to figure out - # what interface and port it's listening on, and then finally we can - # create the text of the PORT command to send to the FTP server. - - # FIXME: This method is far too ugly. - - # FIXME: The best solution is probably to only create the data port - # once per FTPClient, and just recycle it for each new download. - # This should be ok, because we don't pipeline commands. - - # Start listening on a port - factory = FTPDataPortFactory() - factory.protocol = portCmd.protocol - listener = reactor.listenTCP(0, factory) - factory.port = listener - - # Ensure we close the listening port if something goes wrong - def listenerFail(error, listener=listener): - if listener.connected: - listener.loseConnection() - return error - portCmd.fail = listenerFail - - # Construct crufty FTP magic numbers that represent host & port - host = self.transport.getHost().host - port = listener.getHost().port - portCmd.text = 'PORT ' + encodeHostPort(host, port) - - def escapePath(self, path): - """ - Returns a FTP escaped path (replace newlines with nulls). - """ - # Escape newline characters - return path.replace('\n', '\0') - - def retrieveFile(self, path, protocol, offset=0): - """ - Retrieve a file from the given path - - This method issues the 'RETR' FTP command. - - The file is fed into the given Protocol instance. The data connection - will be passive if self.passive is set. - - @param path: path to file that you wish to receive. - @param protocol: a L{Protocol} instance. - @param offset: offset to start downloading from - - @return: L{Deferred} - """ - cmds = ['RETR ' + self.escapePath(path)] - if offset: - cmds.insert(0, ('REST ' + str(offset))) - return self.receiveFromConnection(cmds, protocol) - - retr = retrieveFile - - def storeFile(self, path, offset=0): - """ - Store a file at the given path. - - This method issues the 'STOR' FTP command. - - @return: A tuple of two L{Deferred}s: - - L{Deferred} L{IFinishableConsumer}. You must call - the C{finish} method on the IFinishableConsumer when the file - is completely transferred. - - L{Deferred} list of control-connection responses. - """ - cmds = ['STOR ' + self.escapePath(path)] - if offset: - cmds.insert(0, ('REST ' + str(offset))) - return self.sendToConnection(cmds) - - stor = storeFile - - - def rename(self, pathFrom, pathTo): - """ - Rename a file. - - This method issues the I{RNFR}/I{RNTO} command sequence to rename - C{pathFrom} to C{pathTo}. - - @param: pathFrom: the absolute path to the file to be renamed - @type pathFrom: C{str} - - @param: pathTo: the absolute path to rename the file to. - @type pathTo: C{str} - - @return: A L{Deferred} which fires when the rename operation has - succeeded or failed. If it succeeds, the L{Deferred} is called - back with a two-tuple of lists. The first list contains the - responses to the I{RNFR} command. The second list contains the - responses to the I{RNTO} command. If either I{RNFR} or I{RNTO} - fails, the L{Deferred} is errbacked with L{CommandFailed} or - L{BadResponse}. - @rtype: L{Deferred} - - @since: 8.2 - """ - renameFrom = self.queueStringCommand('RNFR ' + self.escapePath(pathFrom)) - renameTo = self.queueStringCommand('RNTO ' + self.escapePath(pathTo)) - - fromResponse = [] - - # Use a separate Deferred for the ultimate result so that Deferred - # chaining can't interfere with its result. - result = defer.Deferred() - # Bundle up all the responses - result.addCallback(lambda toResponse: (fromResponse, toResponse)) - - def ebFrom(failure): - # Make sure the RNTO doesn't run if the RNFR failed. - self.popCommandQueue() - result.errback(failure) - - # Save the RNFR response to pass to the result Deferred later - renameFrom.addCallbacks(fromResponse.extend, ebFrom) - - # Hook up the RNTO to the result Deferred as well - renameTo.chainDeferred(result) - - return result - - - def list(self, path, protocol): - """ - Retrieve a file listing into the given protocol instance. - - This method issues the 'LIST' FTP command. - - @param path: path to get a file listing for. - @param protocol: a L{Protocol} instance, probably a - L{FTPFileListProtocol} instance. It can cope with most common file - listing formats. - - @return: L{Deferred} - """ - if path is None: - path = '' - return self.receiveFromConnection(['LIST ' + self.escapePath(path)], protocol) - - - def nlst(self, path, protocol): - """ - Retrieve a short file listing into the given protocol instance. - - This method issues the 'NLST' FTP command. - - NLST (should) return a list of filenames, one per line. - - @param path: path to get short file listing for. - @param protocol: a L{Protocol} instance. - """ - if path is None: - path = '' - return self.receiveFromConnection(['NLST ' + self.escapePath(path)], protocol) - - - def cwd(self, path): - """ - Issues the CWD (Change Working Directory) command. - - @return: a L{Deferred} that will be called when done. - """ - return self.queueStringCommand('CWD ' + self.escapePath(path)) - - - def makeDirectory(self, path): - """ - Make a directory - - This method issues the MKD command. - - @param path: The path to the directory to create. - @type path: C{str} - - @return: A L{Deferred} which fires when the server responds. If the - directory is created, the L{Deferred} is called back with the - server response. If the server response indicates the directory - was not created, the L{Deferred} is errbacked with a L{Failure} - wrapping L{CommandFailed} or L{BadResponse}. - @rtype: L{Deferred} - - @since: 8.2 - """ - return self.queueStringCommand('MKD ' + self.escapePath(path)) - - - def removeFile(self, path): - """ - Delete a file on the server. - - L{removeFile} issues a I{DELE} command to the server to remove the - indicated file. Note that this command cannot remove a directory. - - @param path: The path to the file to delete. May be relative to the - current dir. - @type path: C{str} - - @return: A L{Deferred} which fires when the server responds. On error, - it is errbacked with either L{CommandFailed} or L{BadResponse}. On - success, it is called back with a list of response lines. - @rtype: L{Deferred} - - @since: 8.2 - """ - return self.queueStringCommand('DELE ' + self.escapePath(path)) - - - def removeDirectory(self, path): - """ - Delete a directory on the server. - - L{removeDirectory} issues a I{RMD} command to the server to remove the - indicated directory. Described in RFC959. - - @param path: The path to the directory to delete. May be relative to - the current working directory. - @type path: C{str} - - @return: A L{Deferred} which fires when the server responds. On error, - it is errbacked with either L{CommandFailed} or L{BadResponse}. On - success, it is called back with a list of response lines. - @rtype: L{Deferred} - - @since: 11.1 - """ - return self.queueStringCommand('RMD ' + self.escapePath(path)) - - - def cdup(self): - """ - Issues the CDUP (Change Directory UP) command. - - @return: a L{Deferred} that will be called when done. - """ - return self.queueStringCommand('CDUP') - - - def pwd(self): - """ - Issues the PWD (Print Working Directory) command. - - The L{getDirectory} does the same job but automatically parses the - result. - - @return: a L{Deferred} that will be called when done. It is up to the - caller to interpret the response, but the L{parsePWDResponse} method - in this module should work. - """ - return self.queueStringCommand('PWD') - - - def getDirectory(self): - """ - Returns the current remote directory. - - @return: a L{Deferred} that will be called back with a C{str} giving - the remote directory or which will errback with L{CommandFailed} - if an error response is returned. - """ - def cbParse(result): - try: - # The only valid code is 257 - if int(result[0].split(' ', 1)[0]) != 257: - raise ValueError - except (IndexError, ValueError): - return failure.Failure(CommandFailed(result)) - path = parsePWDResponse(result[0]) - if path is None: - return failure.Failure(CommandFailed(result)) - return path - return self.pwd().addCallback(cbParse) - - - def quit(self): - """ - Issues the I{QUIT} command. - - @return: A L{Deferred} that fires when the server acknowledges the - I{QUIT} command. The transport should not be disconnected until - this L{Deferred} fires. - """ - return self.queueStringCommand('QUIT') - - - -class FTPFileListProtocol(basic.LineReceiver): - """ - Parser for standard FTP file listings - - This is the evil required to match:: - - -rw-r--r-- 1 root other 531 Jan 29 03:26 README - - If you need different evil for a wacky FTP server, you can - override either C{fileLinePattern} or C{parseDirectoryLine()}. - - It populates the instance attribute self.files, which is a list containing - dicts with the following keys (examples from the above line): - - filetype: e.g. 'd' for directories, or '-' for an ordinary file - - perms: e.g. 'rw-r--r--' - - nlinks: e.g. 1 - - owner: e.g. 'root' - - group: e.g. 'other' - - size: e.g. 531 - - date: e.g. 'Jan 29 03:26' - - filename: e.g. 'README' - - linktarget: e.g. 'some/file' - - Note that the 'date' value will be formatted differently depending on the - date. Check U{http://cr.yp.to/ftp.html} if you really want to try to parse - it. - - It also matches the following:: - -rw-r--r-- 1 root other 531 Jan 29 03:26 I HAVE\ SPACE - - filename: e.g. 'I HAVE SPACE' - - -rw-r--r-- 1 root other 531 Jan 29 03:26 LINK -> TARGET - - filename: e.g. 'LINK' - - linktarget: e.g. 'TARGET' - - -rw-r--r-- 1 root other 531 Jan 29 03:26 N S -> L S - - filename: e.g. 'N S' - - linktarget: e.g. 'L S' - - @ivar files: list of dicts describing the files in this listing - """ - fileLinePattern = re.compile( - r'^(?P.)(?P.{9})\s+(?P\d*)\s*' - r'(?P\S+)\s+(?P\S+)\s+(?P\d+)\s+' - r'(?P...\s+\d+\s+[\d:]+)\s+(?P.{1,}?)' - r'( -> (?P[^\r]*))?\r?$' - ) - delimiter = '\n' - - def __init__(self): - self.files = [] - - def lineReceived(self, line): - d = self.parseDirectoryLine(line) - if d is None: - self.unknownLine(line) - else: - self.addFile(d) - - def parseDirectoryLine(self, line): - """ - Return a dictionary of fields, or None if line cannot be parsed. - - @param line: line of text expected to contain a directory entry - @type line: str - - @return: dict - """ - match = self.fileLinePattern.match(line) - if match is None: - return None - else: - d = match.groupdict() - d['filename'] = d['filename'].replace(r'\ ', ' ') - d['nlinks'] = int(d['nlinks']) - d['size'] = int(d['size']) - if d['linktarget']: - d['linktarget'] = d['linktarget'].replace(r'\ ', ' ') - return d - - def addFile(self, info): - """ - Append file information dictionary to the list of known files. - - Subclasses can override or extend this method to handle file - information differently without affecting the parsing of data - from the server. - - @param info: dictionary containing the parsed representation - of the file information - @type info: dict - """ - self.files.append(info) - - def unknownLine(self, line): - """ - Deal with received lines which could not be parsed as file - information. - - Subclasses can override this to perform any special processing - needed. - - @param line: unparsable line as received - @type line: str - """ - pass - -def parsePWDResponse(response): - """ - Returns the path from a response to a PWD command. - - Responses typically look like:: - - 257 "/home/andrew" is current directory. - - For this example, I will return C{'/home/andrew'}. - - If I can't find the path, I return C{None}. - """ - match = re.search('"(.*)"', response) - if match: - return match.groups()[0] - else: - return None diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/__init__.py deleted file mode 100644 index 278648c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Global Positioning System protocols.""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/nmea.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/nmea.py deleted file mode 100644 index 7e0cae0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/nmea.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- test-case-name: twisted.test.test_nmea -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -NMEA 0183 implementation - -Maintainer: Bob Ippolito - -The following NMEA 0183 sentences are currently understood:: - GPGGA (fix) - GPGLL (position) - GPRMC (position and time) - GPGSA (active satellites) - -The following NMEA 0183 sentences require implementation:: - None really, the others aren't generally useful or implemented in most devices anyhow - -Other desired features:: - - A NMEA 0183 producer to emulate GPS devices (?) -""" - -import operator -from functools import reduce - -from twisted.protocols import basic - -POSFIX_INVALID, POSFIX_SPS, POSFIX_DGPS, POSFIX_PPS = 0, 1, 2, 3 -MODE_AUTO, MODE_FORCED = 'A', 'M' -MODE_NOFIX, MODE_2D, MODE_3D = 1, 2, 3 - -class InvalidSentence(Exception): - pass - -class InvalidChecksum(Exception): - pass - -class NMEAReceiver(basic.LineReceiver): - """ - This parses most common NMEA-0183 messages, presumably from a serial GPS - device at 4800 bps. - """ - delimiter = '\r\n' - dispatch = { - 'GPGGA': 'fix', - 'GPGLL': 'position', - 'GPGSA': 'activesatellites', - 'GPRMC': 'positiontime', - 'GPGSV': 'viewsatellites', # not implemented - 'GPVTG': 'course', # not implemented - 'GPALM': 'almanac', # not implemented - 'GPGRS': 'range', # not implemented - 'GPGST': 'noise', # not implemented - 'GPMSS': 'beacon', # not implemented - 'GPZDA': 'time', # not implemented - } - # generally you may miss the beginning of the first message - ignore_invalid_sentence = 1 - # checksums shouldn't be invalid - ignore_checksum_mismatch = 0 - # ignore unknown sentence types - ignore_unknown_sentencetypes = 0 - # do we want to even bother checking to see if it's from the 20th century? - convert_dates_before_y2k = 1 - - def lineReceived(self, line): - if not line.startswith('$'): - if self.ignore_invalid_sentence: - return - raise InvalidSentence("%r does not begin with $" % (line,)) - # message is everything between $ and *, checksum is xor of all ASCII - # values of the message - strmessage, checksum = line[1:].strip().split('*') - message = strmessage.split(',') - sentencetype, message = message[0], message[1:] - dispatch = self.dispatch.get(sentencetype, None) - if (not dispatch) and (not self.ignore_unknown_sentencetypes): - raise InvalidSentence("sentencetype %r" % (sentencetype,)) - if not self.ignore_checksum_mismatch: - checksum = int(checksum, 16) - calculated_checksum = reduce(operator.xor, map(ord, strmessage)) - if checksum != calculated_checksum: - raise InvalidChecksum("Given 0x%02X != 0x%02X" % (checksum, - calculated_checksum)) - handler = getattr(self, "handle_%s" % dispatch, None) - decoder = getattr(self, "decode_%s" % dispatch, None) - if not (dispatch and handler and decoder): - # missing dispatch, handler, or decoder - return - # return handler(*decoder(*message)) - try: - decoded = decoder(*message) - except Exception: - raise InvalidSentence("%r is not a valid %s (%s) sentence" % ( - line, sentencetype, dispatch)) - return handler(*decoded) - - def decode_position(self, latitude, ns, longitude, ew, utc, status): - latitude, longitude = self._decode_latlon(latitude, ns, longitude, ew) - utc = self._decode_utc(utc) - if status == 'A': - status = 1 - else: - status = 0 - return ( - latitude, - longitude, - utc, - status, - ) - - def decode_positiontime(self, utc, status, latitude, ns, longitude, ew, speed, course, utcdate, magvar, magdir): - utc = self._decode_utc(utc) - latitude, longitude = self._decode_latlon(latitude, ns, longitude, ew) - if speed != '': - speed = float(speed) - else: - speed = None - if course != '': - course = float(course) - else: - course = None - utcdate = 2000+int(utcdate[4:6]), int(utcdate[2:4]), int(utcdate[0:2]) - if self.convert_dates_before_y2k and utcdate[0] > 2073: - # GPS was invented by the US DoD in 1973, but NMEA uses 2 digit year. - # Highly unlikely that we'll be using NMEA or this twisted module in 70 years, - # but remotely possible that you'll be using it to play back data from the 20th century. - utcdate = (utcdate[0] - 100, utcdate[1], utcdate[2]) - if magvar != '': - magvar = float(magvar) - if magdir == 'W': - magvar = -magvar - else: - magvar = None - return ( - latitude, - longitude, - speed, - course, - # UTC seconds past utcdate - utc, - # UTC (year, month, day) - utcdate, - # None or magnetic variation in degrees (west is negative) - magvar, - ) - - def _decode_utc(self, utc): - utc_hh, utc_mm, utc_ss = map(float, (utc[:2], utc[2:4], utc[4:])) - return utc_hh * 3600.0 + utc_mm * 60.0 + utc_ss - - def _decode_latlon(self, latitude, ns, longitude, ew): - latitude = float(latitude[:2]) + float(latitude[2:])/60.0 - if ns == 'S': - latitude = -latitude - longitude = float(longitude[:3]) + float(longitude[3:])/60.0 - if ew == 'W': - longitude = -longitude - return (latitude, longitude) - - def decode_activesatellites(self, mode1, mode2, *args): - satellites, (pdop, hdop, vdop) = args[:12], map(float, args[12:]) - satlist = [] - for n in satellites: - if n: - satlist.append(int(n)) - else: - satlist.append(None) - mode = (mode1, int(mode2)) - return ( - # satellite list by channel - tuple(satlist), - # (MODE_AUTO/MODE_FORCED, MODE_NOFIX/MODE_2DFIX/MODE_3DFIX) - mode, - # position dilution of precision - pdop, - # horizontal dilution of precision - hdop, - # vertical dilution of precision - vdop, - ) - - def decode_fix(self, utc, latitude, ns, longitude, ew, posfix, satellites, hdop, altitude, altitude_units, geoid_separation, geoid_separation_units, dgps_age, dgps_station_id): - latitude, longitude = self._decode_latlon(latitude, ns, longitude, ew) - utc = self._decode_utc(utc) - posfix = int(posfix) - satellites = int(satellites) - hdop = float(hdop) - altitude = (float(altitude), altitude_units) - if geoid_separation != '': - geoid = (float(geoid_separation), geoid_separation_units) - else: - geoid = None - if dgps_age != '': - dgps = (float(dgps_age), dgps_station_id) - else: - dgps = None - return ( - # seconds since 00:00 UTC - utc, - # latitude (degrees) - latitude, - # longitude (degrees) - longitude, - # position fix status (POSFIX_INVALID, POSFIX_SPS, POSFIX_DGPS, POSFIX_PPS) - posfix, - # number of satellites used for fix 0 <= satellites <= 12 - satellites, - # horizontal dilution of precision - hdop, - # None or (altitude according to WGS-84 ellipsoid, units (typically 'M' for meters)) - altitude, - # None or (geoid separation according to WGS-84 ellipsoid, units (typically 'M' for meters)) - geoid, - # (age of dgps data in seconds, dgps station id) - dgps, - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/rockwell.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/rockwell.py deleted file mode 100644 index 1874a69..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/gps/rockwell.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Rockwell Semiconductor Zodiac Serial Protocol -Coded from official protocol specs (Order No. GPS-25, 09/24/1996, Revision 11) - -Maintainer: Bob Ippolito - -The following Rockwell Zodiac messages are currently understood:: - EARTHA\\r\\n (a hack to "turn on" a DeLorme Earthmate) - 1000 (Geodesic Position Status Output) - 1002 (Channel Summary) - 1003 (Visible Satellites) - 1011 (Receiver ID) - -The following Rockwell Zodiac messages require implementation:: - None really, the others aren't quite so useful and require bidirectional communication w/ the device - -Other desired features:: - - Compatibility with the DeLorme Tripmate and other devices with this chipset (?) -""" - -import math -import struct - -from twisted.internet import protocol -from twisted.python import log - -DEBUG = 1 - - -class ZodiacParseError(ValueError): - pass - - - -class Zodiac(protocol.Protocol): - dispatch = { - # Output Messages (* means they get sent by the receiver by default periodically) - 1000: 'fix', # *Geodesic Position Status Output - 1001: 'ecef', # ECEF Position Status Output - 1002: 'channels', # *Channel Summary - 1003: 'satellites', # *Visible Satellites - 1005: 'dgps', # Differential GPS Status - 1007: 'channelmeas', # Channel Measurement - 1011: 'id', # *Receiver ID - 1012: 'usersettings', # User-Settings Output - 1100: 'testresults', # Built-In Test Results - 1102: 'meastimemark', # Measurement Time Mark - 1108: 'utctimemark', # UTC Time Mark Pulse Output - 1130: 'serial', # Serial Port Communication Parameters In Use - 1135: 'eepromupdate', # EEPROM Update - 1136: 'eepromstatus', # EEPROM Status - } - # these aren't used for anything yet, just sitting here for reference - messages = { - # Input Messages - 'fix': 1200, # Geodesic Position and Velocity Initialization - 'udatum': 1210, # User-Defined Datum Definition - 'mdatum': 1211, # Map Datum Select - 'smask': 1212, # Satellite Elevation Mask Control - 'sselect': 1213, # Satellite Candidate Select - 'dgpsc': 1214, # Differential GPS Control - 'startc': 1216, # Cold Start Control - 'svalid': 1217, # Solution Validity Control - 'antenna': 1218, # Antenna Type Select - 'altinput': 1219, # User-Entered Altitude Input - 'appctl': 1220, # Application Platform Control - 'navcfg': 1221, # Nav Configuration - 'test': 1300, # Perform Built-In Test Command - 'restart': 1303, # Restart Command - 'serial': 1330, # Serial Port Communications Parameters - 'msgctl': 1331, # Message Protocol Control - 'dgpsd': 1351, # Raw DGPS RTCM SC-104 Data - } - MAX_LENGTH = 296 - allow_earthmate_hack = 1 - recvd = "" - - def dataReceived(self, recd): - self.recvd = self.recvd + recd - while len(self.recvd) >= 10: - - # hack for DeLorme EarthMate - if self.recvd[:8] == 'EARTHA\r\n': - if self.allow_earthmate_hack: - self.allow_earthmate_hack = 0 - self.transport.write('EARTHA\r\n') - self.recvd = self.recvd[8:] - continue - - if self.recvd[0:2] != '\xFF\x81': - if DEBUG: - raise ZodiacParseError('Invalid Sync %r' % self.recvd) - else: - raise ZodiacParseError - sync, msg_id, length, acknak, checksum = struct.unpack(' self.MAX_LENGTH: - raise ZodiacParseError("Invalid Header??") - - # empty messages pass empty strings - message = '' - - # does this message have data ? - if length: - message = self.recvd[10:10 + length], - checksum = struct.unpack(' 0 - minimize_ram = (options_list & 0x02) > 0 - # (version info), (options info) - return ((software_version, software_date), (minimize_rom, minimize_ram)) - - def decode_channels(self, message): - assert len(message) == 90, "Channel Summary Message should be 51 words total (90 byte message)" - ticks, msgseq, satseq, gpswk, gpsws, gpsns = struct.unpack('}. - -@seealso: U{HTB Linux queuing discipline manual - user guide - } -@seealso: U{Token Bucket Filter in Linux Advanced Routing & Traffic Control - HOWTO} -""" - - -# TODO: Investigate whether we should be using os.times()[-1] instead of -# time.time. time.time, it has been pointed out, can go backwards. Is -# the same true of os.times? -from time import time -from zope.interface import implements, Interface - -from twisted.protocols import pcp - - -class Bucket: - """ - Implementation of a Token bucket. - - A bucket can hold a certain number of tokens and it drains over time. - - @cvar maxburst: The maximum number of tokens that the bucket can - hold at any given time. If this is C{None}, the bucket has - an infinite size. - @type maxburst: C{int} - @cvar rate: The rate at which the bucket drains, in number - of tokens per second. If the rate is C{None}, the bucket - drains instantaneously. - @type rate: C{int} - """ - - maxburst = None - rate = None - - _refcount = 0 - - def __init__(self, parentBucket=None): - """ - Create a L{Bucket} that may have a parent L{Bucket}. - - @param parentBucket: If a parent Bucket is specified, - all L{add} and L{drip} operations on this L{Bucket} - will be applied on the parent L{Bucket} as well. - @type parentBucket: L{Bucket} - """ - self.content = 0 - self.parentBucket = parentBucket - self.lastDrip = time() - - - def add(self, amount): - """ - Adds tokens to the L{Bucket} and its C{parentBucket}. - - This will add as many of the C{amount} tokens as will fit into both - this L{Bucket} and its C{parentBucket}. - - @param amount: The number of tokens to try to add. - @type amount: C{int} - - @returns: The number of tokens that actually fit. - @returntype: C{int} - """ - self.drip() - if self.maxburst is None: - allowable = amount - else: - allowable = min(amount, self.maxburst - self.content) - - if self.parentBucket is not None: - allowable = self.parentBucket.add(allowable) - self.content += allowable - return allowable - - - def drip(self): - """ - Let some of the bucket drain. - - The L{Bucket} drains at the rate specified by the class - variable C{rate}. - - @returns: C{True} if the bucket is empty after this drip. - @returntype: C{bool} - """ - if self.parentBucket is not None: - self.parentBucket.drip() - - if self.rate is None: - self.content = 0 - else: - now = time() - deltaTime = now - self.lastDrip - deltaTokens = deltaTime * self.rate - self.content = max(0, self.content - deltaTokens) - self.lastDrip = now - return self.content == 0 - - -class IBucketFilter(Interface): - def getBucketFor(*somethings, **some_kw): - """ - Return a L{Bucket} corresponding to the provided parameters. - - @returntype: L{Bucket} - """ - -class HierarchicalBucketFilter: - """ - Filter things into buckets that can be nested. - - @cvar bucketFactory: Class of buckets to make. - @type bucketFactory: L{Bucket} - @cvar sweepInterval: Seconds between sweeping out the bucket cache. - @type sweepInterval: C{int} - """ - - implements(IBucketFilter) - - bucketFactory = Bucket - sweepInterval = None - - def __init__(self, parentFilter=None): - self.buckets = {} - self.parentFilter = parentFilter - self.lastSweep = time() - - def getBucketFor(self, *a, **kw): - """ - Find or create a L{Bucket} corresponding to the provided parameters. - - Any parameters are passed on to L{getBucketKey}, from them it - decides which bucket you get. - - @returntype: L{Bucket} - """ - if ((self.sweepInterval is not None) - and ((time() - self.lastSweep) > self.sweepInterval)): - self.sweep() - - if self.parentFilter: - parentBucket = self.parentFilter.getBucketFor(self, *a, **kw) - else: - parentBucket = None - - key = self.getBucketKey(*a, **kw) - bucket = self.buckets.get(key) - if bucket is None: - bucket = self.bucketFactory(parentBucket) - self.buckets[key] = bucket - return bucket - - def getBucketKey(self, *a, **kw): - """ - Construct a key based on the input parameters to choose a L{Bucket}. - - The default implementation returns the same key for all - arguments. Override this method to provide L{Bucket} selection. - - @returns: Something to be used as a key in the bucket cache. - """ - return None - - def sweep(self): - """ - Remove empty buckets. - """ - for key, bucket in self.buckets.items(): - bucket_is_empty = bucket.drip() - if (bucket._refcount == 0) and bucket_is_empty: - del self.buckets[key] - - self.lastSweep = time() - - -class FilterByHost(HierarchicalBucketFilter): - """ - A Hierarchical Bucket filter with a L{Bucket} for each host. - """ - sweepInterval = 60 * 20 - - def getBucketKey(self, transport): - return transport.getPeer()[1] - - -class FilterByServer(HierarchicalBucketFilter): - """ - A Hierarchical Bucket filter with a L{Bucket} for each service. - """ - sweepInterval = None - - def getBucketKey(self, transport): - return transport.getHost()[2] - - -class ShapedConsumer(pcp.ProducerConsumerProxy): - """ - Wraps a C{Consumer} and shapes the rate at which it receives data. - """ - # Providing a Pull interface means I don't have to try to schedule - # traffic with callLaters. - iAmStreaming = False - - def __init__(self, consumer, bucket): - pcp.ProducerConsumerProxy.__init__(self, consumer) - self.bucket = bucket - self.bucket._refcount += 1 - - def _writeSomeData(self, data): - # In practice, this actually results in obscene amounts of - # overhead, as a result of generating lots and lots of packets - # with twelve-byte payloads. We may need to do a version of - # this with scheduled writes after all. - amount = self.bucket.add(len(data)) - return pcp.ProducerConsumerProxy._writeSomeData(self, data[:amount]) - - def stopProducing(self): - pcp.ProducerConsumerProxy.stopProducing(self) - self.bucket._refcount -= 1 - - -class ShapedTransport(ShapedConsumer): - """ - Wraps a C{Transport} and shapes the rate at which it receives data. - - This is a L{ShapedConsumer} with a little bit of magic to provide for - the case where the consumer it wraps is also a C{Transport} and people - will be attempting to access attributes this does not proxy as a - C{Consumer} (e.g. C{loseConnection}). - """ - # Ugh. We only wanted to filter IConsumer, not ITransport. - - iAmStreaming = False - def __getattr__(self, name): - # Because people will be doing things like .getPeer and - # .loseConnection on me. - return getattr(self.consumer, name) - - -class ShapedProtocolFactory: - """ - Dispense C{Protocols} with traffic shaping on their transports. - - Usage:: - - myserver = SomeFactory() - myserver.protocol = ShapedProtocolFactory(myserver.protocol, - bucketFilter) - - Where C{SomeServerFactory} is a L{twisted.internet.protocol.Factory}, and - C{bucketFilter} is an instance of L{HierarchicalBucketFilter}. - """ - def __init__(self, protoClass, bucketFilter): - """ - Tell me what to wrap and where to get buckets. - - @param protoClass: The class of C{Protocol} this will generate - wrapped instances of. - @type protoClass: L{Protocol} - class - @param bucketFilter: The filter which will determine how - traffic is shaped. - @type bucketFilter: L{HierarchicalBucketFilter}. - """ - # More precisely, protoClass can be any callable that will return - # instances of something that implements IProtocol. - self.protocol = protoClass - self.bucketFilter = bucketFilter - - def __call__(self, *a, **kw): - """ - Make a C{Protocol} instance with a shaped transport. - - Any parameters will be passed on to the protocol's initializer. - - @returns: A C{Protocol} instance with a L{ShapedTransport}. - """ - proto = self.protocol(*a, **kw) - origMakeConnection = proto.makeConnection - def makeConnection(transport): - bucket = self.bucketFilter.getBucketFor(transport) - shapedTransport = ShapedTransport(transport, bucket) - return origMakeConnection(shapedTransport) - proto.makeConnection = makeConnection - return proto diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/ident.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/ident.py deleted file mode 100644 index 985322d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/ident.py +++ /dev/null @@ -1,231 +0,0 @@ -# -*- test-case-name: twisted.test.test_ident -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Ident protocol implementation. -""" - -import struct - -from twisted.internet import defer -from twisted.protocols import basic -from twisted.python import log, failure - -_MIN_PORT = 1 -_MAX_PORT = 2 ** 16 - 1 - -class IdentError(Exception): - """ - Can't determine connection owner; reason unknown. - """ - - identDescription = 'UNKNOWN-ERROR' - - def __str__(self): - return self.identDescription - - -class NoUser(IdentError): - """ - The connection specified by the port pair is not currently in use or - currently not owned by an identifiable entity. - """ - identDescription = 'NO-USER' - - -class InvalidPort(IdentError): - """ - Either the local or foreign port was improperly specified. This should - be returned if either or both of the port ids were out of range (TCP - port numbers are from 1-65535), negative integers, reals or in any - fashion not recognized as a non-negative integer. - """ - identDescription = 'INVALID-PORT' - - -class HiddenUser(IdentError): - """ - The server was able to identify the user of this port, but the - information was not returned at the request of the user. - """ - identDescription = 'HIDDEN-USER' - - -class IdentServer(basic.LineOnlyReceiver): - """ - The Identification Protocol (a.k.a., "ident", a.k.a., "the Ident - Protocol") provides a means to determine the identity of a user of a - particular TCP connection. Given a TCP port number pair, it returns a - character string which identifies the owner of that connection on the - server's system. - - Server authors should subclass this class and override the lookup method. - The default implementation returns an UNKNOWN-ERROR response for every - query. - """ - - def lineReceived(self, line): - parts = line.split(',') - if len(parts) != 2: - self.invalidQuery() - else: - try: - portOnServer, portOnClient = map(int, parts) - except ValueError: - self.invalidQuery() - else: - if _MIN_PORT <= portOnServer <= _MAX_PORT and _MIN_PORT <= portOnClient <= _MAX_PORT: - self.validQuery(portOnServer, portOnClient) - else: - self._ebLookup(failure.Failure(InvalidPort()), portOnServer, portOnClient) - - def invalidQuery(self): - self.transport.loseConnection() - - - def validQuery(self, portOnServer, portOnClient): - """ - Called when a valid query is received to look up and deliver the - response. - - @param portOnServer: The server port from the query. - @param portOnClient: The client port from the query. - """ - serverAddr = self.transport.getHost().host, portOnServer - clientAddr = self.transport.getPeer().host, portOnClient - defer.maybeDeferred(self.lookup, serverAddr, clientAddr - ).addCallback(self._cbLookup, portOnServer, portOnClient - ).addErrback(self._ebLookup, portOnServer, portOnClient - ) - - - def _cbLookup(self, (sysName, userId), sport, cport): - self.sendLine('%d, %d : USERID : %s : %s' % (sport, cport, sysName, userId)) - - def _ebLookup(self, failure, sport, cport): - if failure.check(IdentError): - self.sendLine('%d, %d : ERROR : %s' % (sport, cport, failure.value)) - else: - log.err(failure) - self.sendLine('%d, %d : ERROR : %s' % (sport, cport, IdentError(failure.value))) - - def lookup(self, serverAddress, clientAddress): - """Lookup user information about the specified address pair. - - Return value should be a two-tuple of system name and username. - Acceptable values for the system name may be found online at:: - - U{http://www.iana.org/assignments/operating-system-names} - - This method may also raise any IdentError subclass (or IdentError - itself) to indicate user information will not be provided for the - given query. - - A Deferred may also be returned. - - @param serverAddress: A two-tuple representing the server endpoint - of the address being queried. The first element is a string holding - a dotted-quad IP address. The second element is an integer - representing the port. - - @param clientAddress: Like L{serverAddress}, but represents the - client endpoint of the address being queried. - """ - raise IdentError() - -class ProcServerMixin: - """Implements lookup() to grab entries for responses from /proc/net/tcp - """ - - SYSTEM_NAME = 'LINUX' - - try: - from pwd import getpwuid - def getUsername(self, uid, getpwuid=getpwuid): - return getpwuid(uid)[0] - del getpwuid - except ImportError: - def getUsername(self, uid): - raise IdentError() - - def entries(self): - f = file('/proc/net/tcp') - f.readline() - for L in f: - yield L.strip() - - def dottedQuadFromHexString(self, hexstr): - return '.'.join(map(str, struct.unpack('4B', struct.pack('=L', int(hexstr, 16))))) - - def unpackAddress(self, packed): - addr, port = packed.split(':') - addr = self.dottedQuadFromHexString(addr) - port = int(port, 16) - return addr, port - - def parseLine(self, line): - parts = line.strip().split() - localAddr, localPort = self.unpackAddress(parts[1]) - remoteAddr, remotePort = self.unpackAddress(parts[2]) - uid = int(parts[7]) - return (localAddr, localPort), (remoteAddr, remotePort), uid - - def lookup(self, serverAddress, clientAddress): - for ent in self.entries(): - localAddr, remoteAddr, uid = self.parseLine(ent) - if remoteAddr == clientAddress and localAddr[1] == serverAddress[1]: - return (self.SYSTEM_NAME, self.getUsername(uid)) - - raise NoUser() - - -class IdentClient(basic.LineOnlyReceiver): - - errorTypes = (IdentError, NoUser, InvalidPort, HiddenUser) - - def __init__(self): - self.queries = [] - - def lookup(self, portOnServer, portOnClient): - """Lookup user information about the specified address pair. - """ - self.queries.append((defer.Deferred(), portOnServer, portOnClient)) - if len(self.queries) > 1: - return self.queries[-1][0] - - self.sendLine('%d, %d' % (portOnServer, portOnClient)) - return self.queries[-1][0] - - def lineReceived(self, line): - if not self.queries: - log.msg("Unexpected server response: %r" % (line,)) - else: - d, _, _ = self.queries.pop(0) - self.parseResponse(d, line) - if self.queries: - self.sendLine('%d, %d' % (self.queries[0][1], self.queries[0][2])) - - def connectionLost(self, reason): - for q in self.queries: - q[0].errback(IdentError(reason)) - self.queries = [] - - def parseResponse(self, deferred, line): - parts = line.split(':', 2) - if len(parts) != 3: - deferred.errback(IdentError(line)) - else: - ports, type, addInfo = map(str.strip, parts) - if type == 'ERROR': - for et in self.errorTypes: - if et.identDescription == addInfo: - deferred.errback(et(line)) - return - deferred.errback(IdentError(line)) - else: - deferred.callback((type, addInfo)) - -__all__ = ['IdentError', 'NoUser', 'InvalidPort', 'HiddenUser', - 'IdentServer', 'IdentClient', - 'ProcServerMixin'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/loopback.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/loopback.py deleted file mode 100644 index 0e0ba3b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/loopback.py +++ /dev/null @@ -1,377 +0,0 @@ -# -*- test-case-name: twisted.test.test_loopback -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Testing support for protocols -- loopback between client and server. -""" - -from __future__ import division, absolute_import - -# system imports -import tempfile - -from zope.interface import implementer - -# Twisted Imports -from twisted.protocols import policies -from twisted.internet import interfaces, protocol, main, defer -from twisted.internet.task import deferLater -from twisted.python import failure -from twisted.internet.interfaces import IAddress - - -class _LoopbackQueue(object): - """ - Trivial wrapper around a list to give it an interface like a queue, which - the addition of also sending notifications by way of a Deferred whenever - the list has something added to it. - """ - - _notificationDeferred = None - disconnect = False - - def __init__(self): - self._queue = [] - - - def put(self, v): - self._queue.append(v) - if self._notificationDeferred is not None: - d, self._notificationDeferred = self._notificationDeferred, None - d.callback(None) - - - def __nonzero__(self): - return bool(self._queue) - __bool__ = __nonzero__ - - - def get(self): - return self._queue.pop(0) - - - -@implementer(IAddress) -class _LoopbackAddress(object): - pass - - - -@implementer(interfaces.ITransport, interfaces.IConsumer) -class _LoopbackTransport(object): - disconnecting = False - producer = None - - # ITransport - def __init__(self, q): - self.q = q - - def write(self, data): - if not isinstance(data, bytes): - raise TypeError("Can only write bytes to ITransport") - self.q.put(data) - - def writeSequence(self, iovec): - self.q.put(b''.join(iovec)) - - def loseConnection(self): - self.q.disconnect = True - self.q.put(None) - - def getPeer(self): - return _LoopbackAddress() - - def getHost(self): - return _LoopbackAddress() - - # IConsumer - def registerProducer(self, producer, streaming): - assert self.producer is None - self.producer = producer - self.streamingProducer = streaming - self._pollProducer() - - def unregisterProducer(self): - assert self.producer is not None - self.producer = None - - def _pollProducer(self): - if self.producer is not None and not self.streamingProducer: - self.producer.resumeProducing() - - - -def identityPumpPolicy(queue, target): - """ - L{identityPumpPolicy} is a policy which delivers each chunk of data written - to the given queue as-is to the target. - - This isn't a particularly realistic policy. - - @see: L{loopbackAsync} - """ - while queue: - bytes = queue.get() - if bytes is None: - break - target.dataReceived(bytes) - - - -def collapsingPumpPolicy(queue, target): - """ - L{collapsingPumpPolicy} is a policy which collapses all outstanding chunks - into a single string and delivers it to the target. - - @see: L{loopbackAsync} - """ - bytes = [] - while queue: - chunk = queue.get() - if chunk is None: - break - bytes.append(chunk) - if bytes: - target.dataReceived(b''.join(bytes)) - - - -def loopbackAsync(server, client, pumpPolicy=identityPumpPolicy): - """ - Establish a connection between C{server} and C{client} then transfer data - between them until the connection is closed. This is often useful for - testing a protocol. - - @param server: The protocol instance representing the server-side of this - connection. - - @param client: The protocol instance representing the client-side of this - connection. - - @param pumpPolicy: When either C{server} or C{client} writes to its - transport, the string passed in is added to a queue of data for the - other protocol. Eventually, C{pumpPolicy} will be called with one such - queue and the corresponding protocol object. The pump policy callable - is responsible for emptying the queue and passing the strings it - contains to the given protocol's C{dataReceived} method. The signature - of C{pumpPolicy} is C{(queue, protocol)}. C{queue} is an object with a - C{get} method which will return the next string written to the - transport, or C{None} if the transport has been disconnected, and which - evaluates to C{True} if and only if there are more items to be - retrieved via C{get}. - - @return: A L{Deferred} which fires when the connection has been closed and - both sides have received notification of this. - """ - serverToClient = _LoopbackQueue() - clientToServer = _LoopbackQueue() - - server.makeConnection(_LoopbackTransport(serverToClient)) - client.makeConnection(_LoopbackTransport(clientToServer)) - - return _loopbackAsyncBody( - server, serverToClient, client, clientToServer, pumpPolicy) - - - -def _loopbackAsyncBody(server, serverToClient, client, clientToServer, - pumpPolicy): - """ - Transfer bytes from the output queue of each protocol to the input of the other. - - @param server: The protocol instance representing the server-side of this - connection. - - @param serverToClient: The L{_LoopbackQueue} holding the server's output. - - @param client: The protocol instance representing the client-side of this - connection. - - @param clientToServer: The L{_LoopbackQueue} holding the client's output. - - @param pumpPolicy: See L{loopbackAsync}. - - @return: A L{Deferred} which fires when the connection has been closed and - both sides have received notification of this. - """ - def pump(source, q, target): - sent = False - if q: - pumpPolicy(q, target) - sent = True - if sent and not q: - # A write buffer has now been emptied. Give any producer on that - # side an opportunity to produce more data. - source.transport._pollProducer() - - return sent - - while 1: - disconnect = clientSent = serverSent = False - - # Deliver the data which has been written. - serverSent = pump(server, serverToClient, client) - clientSent = pump(client, clientToServer, server) - - if not clientSent and not serverSent: - # Neither side wrote any data. Wait for some new data to be added - # before trying to do anything further. - d = defer.Deferred() - clientToServer._notificationDeferred = d - serverToClient._notificationDeferred = d - d.addCallback( - _loopbackAsyncContinue, - server, serverToClient, client, clientToServer, pumpPolicy) - return d - if serverToClient.disconnect: - # The server wants to drop the connection. Flush any remaining - # data it has. - disconnect = True - pump(server, serverToClient, client) - elif clientToServer.disconnect: - # The client wants to drop the connection. Flush any remaining - # data it has. - disconnect = True - pump(client, clientToServer, server) - if disconnect: - # Someone wanted to disconnect, so okay, the connection is gone. - server.connectionLost(failure.Failure(main.CONNECTION_DONE)) - client.connectionLost(failure.Failure(main.CONNECTION_DONE)) - return defer.succeed(None) - - - -def _loopbackAsyncContinue(ignored, server, serverToClient, client, - clientToServer, pumpPolicy): - # Clear the Deferred from each message queue, since it has already fired - # and cannot be used again. - clientToServer._notificationDeferred = None - serverToClient._notificationDeferred = None - - # Schedule some more byte-pushing to happen. This isn't done - # synchronously because no actual transport can re-enter dataReceived as - # a result of calling write, and doing this synchronously could result - # in that. - from twisted.internet import reactor - return deferLater( - reactor, 0, - _loopbackAsyncBody, - server, serverToClient, client, clientToServer, pumpPolicy) - - - -@implementer(interfaces.ITransport, interfaces.IConsumer) -class LoopbackRelay: - buffer = '' - shouldLose = 0 - disconnecting = 0 - producer = None - - def __init__(self, target, logFile=None): - self.target = target - self.logFile = logFile - - def write(self, data): - self.buffer = self.buffer + data - if self.logFile: - self.logFile.write("loopback writing %s\n" % repr(data)) - - def writeSequence(self, iovec): - self.write("".join(iovec)) - - def clearBuffer(self): - if self.shouldLose == -1: - return - - if self.producer: - self.producer.resumeProducing() - if self.buffer: - if self.logFile: - self.logFile.write("loopback receiving %s\n" % repr(self.buffer)) - buffer = self.buffer - self.buffer = '' - self.target.dataReceived(buffer) - if self.shouldLose == 1: - self.shouldLose = -1 - self.target.connectionLost(failure.Failure(main.CONNECTION_DONE)) - - def loseConnection(self): - if self.shouldLose != -1: - self.shouldLose = 1 - - def getHost(self): - return 'loopback' - - def getPeer(self): - return 'loopback' - - def registerProducer(self, producer, streaming): - self.producer = producer - - def unregisterProducer(self): - self.producer = None - - def logPrefix(self): - return 'Loopback(%r)' % (self.target.__class__.__name__,) - - - -class LoopbackClientFactory(protocol.ClientFactory): - - def __init__(self, protocol): - self.disconnected = 0 - self.deferred = defer.Deferred() - self.protocol = protocol - - def buildProtocol(self, addr): - return self.protocol - - def clientConnectionLost(self, connector, reason): - self.disconnected = 1 - self.deferred.callback(None) - - -class _FireOnClose(policies.ProtocolWrapper): - def __init__(self, protocol, factory): - policies.ProtocolWrapper.__init__(self, protocol, factory) - self.deferred = defer.Deferred() - - def connectionLost(self, reason): - policies.ProtocolWrapper.connectionLost(self, reason) - self.deferred.callback(None) - - -def loopbackTCP(server, client, port=0, noisy=True): - """Run session between server and client protocol instances over TCP.""" - from twisted.internet import reactor - f = policies.WrappingFactory(protocol.Factory()) - serverWrapper = _FireOnClose(f, server) - f.noisy = noisy - f.buildProtocol = lambda addr: serverWrapper - serverPort = reactor.listenTCP(port, f, interface='127.0.0.1') - clientF = LoopbackClientFactory(client) - clientF.noisy = noisy - reactor.connectTCP('127.0.0.1', serverPort.getHost().port, clientF) - d = clientF.deferred - d.addCallback(lambda x: serverWrapper.deferred) - d.addCallback(lambda x: serverPort.stopListening()) - return d - - -def loopbackUNIX(server, client, noisy=True): - """Run session between server and client protocol instances over UNIX socket.""" - path = tempfile.mktemp() - from twisted.internet import reactor - f = policies.WrappingFactory(protocol.Factory()) - serverWrapper = _FireOnClose(f, server) - f.noisy = noisy - f.buildProtocol = lambda addr: serverWrapper - serverPort = reactor.listenUNIX(path, f) - clientF = LoopbackClientFactory(client) - clientF.noisy = noisy - reactor.connectUNIX(path, clientF) - d = clientF.deferred - d.addCallback(lambda x: serverWrapper.deferred) - d.addCallback(lambda x: serverPort.stopListening()) - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/memcache.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/memcache.py deleted file mode 100644 index c18a3d3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/memcache.py +++ /dev/null @@ -1,752 +0,0 @@ -# -*- test-case-name: twisted.test.test_memcache -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Memcache client protocol. Memcached is a caching server, storing data in the -form of pairs key/value, and memcache is the protocol to talk with it. - -To connect to a server, create a factory for L{MemCacheProtocol}:: - - from twisted.internet import reactor, protocol - from twisted.protocols.memcache import MemCacheProtocol, DEFAULT_PORT - d = protocol.ClientCreator(reactor, MemCacheProtocol - ).connectTCP("localhost", DEFAULT_PORT) - def doSomething(proto): - # Here you call the memcache operations - return proto.set("mykey", "a lot of data") - d.addCallback(doSomething) - reactor.run() - -All the operations of the memcache protocol are present, but -L{MemCacheProtocol.set} and L{MemCacheProtocol.get} are the more important. - -See U{http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt} for -more information about the protocol. -""" - -from collections import deque - -from twisted.protocols.basic import LineReceiver -from twisted.protocols.policies import TimeoutMixin -from twisted.internet.defer import Deferred, fail, TimeoutError -from twisted.python import log - - - -DEFAULT_PORT = 11211 - - - -class NoSuchCommand(Exception): - """ - Exception raised when a non existent command is called. - """ - - - -class ClientError(Exception): - """ - Error caused by an invalid client call. - """ - - - -class ServerError(Exception): - """ - Problem happening on the server. - """ - - - -class Command(object): - """ - Wrap a client action into an object, that holds the values used in the - protocol. - - @ivar _deferred: the L{Deferred} object that will be fired when the result - arrives. - @type _deferred: L{Deferred} - - @ivar command: name of the command sent to the server. - @type command: C{str} - """ - - def __init__(self, command, **kwargs): - """ - Create a command. - - @param command: the name of the command. - @type command: C{str} - - @param kwargs: this values will be stored as attributes of the object - for future use - """ - self.command = command - self._deferred = Deferred() - for k, v in kwargs.items(): - setattr(self, k, v) - - - def success(self, value): - """ - Shortcut method to fire the underlying deferred. - """ - self._deferred.callback(value) - - - def fail(self, error): - """ - Make the underlying deferred fails. - """ - self._deferred.errback(error) - - - -class MemCacheProtocol(LineReceiver, TimeoutMixin): - """ - MemCache protocol: connect to a memcached server to store/retrieve values. - - @ivar persistentTimeOut: the timeout period used to wait for a response. - @type persistentTimeOut: C{int} - - @ivar _current: current list of requests waiting for an answer from the - server. - @type _current: C{deque} of L{Command} - - @ivar _lenExpected: amount of data expected in raw mode, when reading for - a value. - @type _lenExpected: C{int} - - @ivar _getBuffer: current buffer of data, used to store temporary data - when reading in raw mode. - @type _getBuffer: C{list} - - @ivar _bufferLength: the total amount of bytes in C{_getBuffer}. - @type _bufferLength: C{int} - - @ivar _disconnected: indicate if the connectionLost has been called or not. - @type _disconnected: C{bool} - """ - MAX_KEY_LENGTH = 250 - _disconnected = False - - def __init__(self, timeOut=60): - """ - Create the protocol. - - @param timeOut: the timeout to wait before detecting that the - connection is dead and close it. It's expressed in seconds. - @type timeOut: C{int} - """ - self._current = deque() - self._lenExpected = None - self._getBuffer = None - self._bufferLength = None - self.persistentTimeOut = self.timeOut = timeOut - - - def _cancelCommands(self, reason): - """ - Cancel all the outstanding commands, making them fail with C{reason}. - """ - while self._current: - cmd = self._current.popleft() - cmd.fail(reason) - - - def timeoutConnection(self): - """ - Close the connection in case of timeout. - """ - self._cancelCommands(TimeoutError("Connection timeout")) - self.transport.loseConnection() - - - def connectionLost(self, reason): - """ - Cause any outstanding commands to fail. - """ - self._disconnected = True - self._cancelCommands(reason) - LineReceiver.connectionLost(self, reason) - - - def sendLine(self, line): - """ - Override sendLine to add a timeout to response. - """ - if not self._current: - self.setTimeout(self.persistentTimeOut) - LineReceiver.sendLine(self, line) - - - def rawDataReceived(self, data): - """ - Collect data for a get. - """ - self.resetTimeout() - self._getBuffer.append(data) - self._bufferLength += len(data) - if self._bufferLength >= self._lenExpected + 2: - data = "".join(self._getBuffer) - buf = data[:self._lenExpected] - rem = data[self._lenExpected + 2:] - val = buf - self._lenExpected = None - self._getBuffer = None - self._bufferLength = None - cmd = self._current[0] - if cmd.multiple: - flags, cas = cmd.values[cmd.currentKey] - cmd.values[cmd.currentKey] = (flags, cas, val) - else: - cmd.value = val - self.setLineMode(rem) - - - def cmd_STORED(self): - """ - Manage a success response to a set operation. - """ - self._current.popleft().success(True) - - - def cmd_NOT_STORED(self): - """ - Manage a specific 'not stored' response to a set operation: this is not - an error, but some condition wasn't met. - """ - self._current.popleft().success(False) - - - def cmd_END(self): - """ - This the end token to a get or a stat operation. - """ - cmd = self._current.popleft() - if cmd.command == "get": - if cmd.multiple: - values = dict([(key, val[::2]) for key, val in - cmd.values.iteritems()]) - cmd.success(values) - else: - cmd.success((cmd.flags, cmd.value)) - elif cmd.command == "gets": - if cmd.multiple: - cmd.success(cmd.values) - else: - cmd.success((cmd.flags, cmd.cas, cmd.value)) - elif cmd.command == "stats": - cmd.success(cmd.values) - - - def cmd_NOT_FOUND(self): - """ - Manage error response for incr/decr/delete. - """ - self._current.popleft().success(False) - - - def cmd_VALUE(self, line): - """ - Prepare the reading a value after a get. - """ - cmd = self._current[0] - if cmd.command == "get": - key, flags, length = line.split() - cas = "" - else: - key, flags, length, cas = line.split() - self._lenExpected = int(length) - self._getBuffer = [] - self._bufferLength = 0 - if cmd.multiple: - if key not in cmd.keys: - raise RuntimeError("Unexpected commands answer.") - cmd.currentKey = key - cmd.values[key] = [int(flags), cas] - else: - if cmd.key != key: - raise RuntimeError("Unexpected commands answer.") - cmd.flags = int(flags) - cmd.cas = cas - self.setRawMode() - - - def cmd_STAT(self, line): - """ - Reception of one stat line. - """ - cmd = self._current[0] - key, val = line.split(" ", 1) - cmd.values[key] = val - - - def cmd_VERSION(self, versionData): - """ - Read version token. - """ - self._current.popleft().success(versionData) - - - def cmd_ERROR(self): - """ - An non-existent command has been sent. - """ - log.err("Non-existent command sent.") - cmd = self._current.popleft() - cmd.fail(NoSuchCommand()) - - - def cmd_CLIENT_ERROR(self, errText): - """ - An invalid input as been sent. - """ - log.err("Invalid input: %s" % (errText,)) - cmd = self._current.popleft() - cmd.fail(ClientError(errText)) - - - def cmd_SERVER_ERROR(self, errText): - """ - An error has happened server-side. - """ - log.err("Server error: %s" % (errText,)) - cmd = self._current.popleft() - cmd.fail(ServerError(errText)) - - - def cmd_DELETED(self): - """ - A delete command has completed successfully. - """ - self._current.popleft().success(True) - - - def cmd_OK(self): - """ - The last command has been completed. - """ - self._current.popleft().success(True) - - - def cmd_EXISTS(self): - """ - A C{checkAndSet} update has failed. - """ - self._current.popleft().success(False) - - - def lineReceived(self, line): - """ - Receive line commands from the server. - """ - self.resetTimeout() - token = line.split(" ", 1)[0] - # First manage standard commands without space - cmd = getattr(self, "cmd_%s" % (token,), None) - if cmd is not None: - args = line.split(" ", 1)[1:] - if args: - cmd(args[0]) - else: - cmd() - else: - # Then manage commands with space in it - line = line.replace(" ", "_") - cmd = getattr(self, "cmd_%s" % (line,), None) - if cmd is not None: - cmd() - else: - # Increment/Decrement response - cmd = self._current.popleft() - val = int(line) - cmd.success(val) - if not self._current: - # No pending request, remove timeout - self.setTimeout(None) - - - def increment(self, key, val=1): - """ - Increment the value of C{key} by given value (default to 1). - C{key} must be consistent with an int. Return the new value. - - @param key: the key to modify. - @type key: C{str} - - @param val: the value to increment. - @type val: C{int} - - @return: a deferred with will be called back with the new value - associated with the key (after the increment). - @rtype: L{Deferred} - """ - return self._incrdecr("incr", key, val) - - - def decrement(self, key, val=1): - """ - Decrement the value of C{key} by given value (default to 1). - C{key} must be consistent with an int. Return the new value, coerced to - 0 if negative. - - @param key: the key to modify. - @type key: C{str} - - @param val: the value to decrement. - @type val: C{int} - - @return: a deferred with will be called back with the new value - associated with the key (after the decrement). - @rtype: L{Deferred} - """ - return self._incrdecr("decr", key, val) - - - def _incrdecr(self, cmd, key, val): - """ - Internal wrapper for incr/decr. - """ - if self._disconnected: - return fail(RuntimeError("not connected")) - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - if len(key) > self.MAX_KEY_LENGTH: - return fail(ClientError("Key too long")) - fullcmd = "%s %s %d" % (cmd, key, int(val)) - self.sendLine(fullcmd) - cmdObj = Command(cmd, key=key) - self._current.append(cmdObj) - return cmdObj._deferred - - - def replace(self, key, val, flags=0, expireTime=0): - """ - Replace the given C{key}. It must already exist in the server. - - @param key: the key to replace. - @type key: C{str} - - @param val: the new value associated with the key. - @type val: C{str} - - @param flags: the flags to store with the key. - @type flags: C{int} - - @param expireTime: if different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: a deferred that will fire with C{True} if the operation has - succeeded, and C{False} with the key didn't previously exist. - @rtype: L{Deferred} - """ - return self._set("replace", key, val, flags, expireTime, "") - - - def add(self, key, val, flags=0, expireTime=0): - """ - Add the given C{key}. It must not exist in the server. - - @param key: the key to add. - @type key: C{str} - - @param val: the value associated with the key. - @type val: C{str} - - @param flags: the flags to store with the key. - @type flags: C{int} - - @param expireTime: if different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: a deferred that will fire with C{True} if the operation has - succeeded, and C{False} with the key already exists. - @rtype: L{Deferred} - """ - return self._set("add", key, val, flags, expireTime, "") - - - def set(self, key, val, flags=0, expireTime=0): - """ - Set the given C{key}. - - @param key: the key to set. - @type key: C{str} - - @param val: the value associated with the key. - @type val: C{str} - - @param flags: the flags to store with the key. - @type flags: C{int} - - @param expireTime: if different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: a deferred that will fire with C{True} if the operation has - succeeded. - @rtype: L{Deferred} - """ - return self._set("set", key, val, flags, expireTime, "") - - - def checkAndSet(self, key, val, cas, flags=0, expireTime=0): - """ - Change the content of C{key} only if the C{cas} value matches the - current one associated with the key. Use this to store a value which - hasn't been modified since last time you fetched it. - - @param key: The key to set. - @type key: C{str} - - @param val: The value associated with the key. - @type val: C{str} - - @param cas: Unique 64-bit value returned by previous call of C{get}. - @type cas: C{str} - - @param flags: The flags to store with the key. - @type flags: C{int} - - @param expireTime: If different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: A deferred that will fire with C{True} if the operation has - succeeded, C{False} otherwise. - @rtype: L{Deferred} - """ - return self._set("cas", key, val, flags, expireTime, cas) - - - def _set(self, cmd, key, val, flags, expireTime, cas): - """ - Internal wrapper for setting values. - """ - if self._disconnected: - return fail(RuntimeError("not connected")) - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - if len(key) > self.MAX_KEY_LENGTH: - return fail(ClientError("Key too long")) - if not isinstance(val, str): - return fail(ClientError( - "Invalid type for value: %s, expecting a string" % - (type(val),))) - if cas: - cas = " " + cas - length = len(val) - fullcmd = "%s %s %d %d %d%s" % ( - cmd, key, flags, expireTime, length, cas) - self.sendLine(fullcmd) - self.sendLine(val) - cmdObj = Command(cmd, key=key, flags=flags, length=length) - self._current.append(cmdObj) - return cmdObj._deferred - - - def append(self, key, val): - """ - Append given data to the value of an existing key. - - @param key: The key to modify. - @type key: C{str} - - @param val: The value to append to the current value associated with - the key. - @type val: C{str} - - @return: A deferred that will fire with C{True} if the operation has - succeeded, C{False} otherwise. - @rtype: L{Deferred} - """ - # Even if flags and expTime values are ignored, we have to pass them - return self._set("append", key, val, 0, 0, "") - - - def prepend(self, key, val): - """ - Prepend given data to the value of an existing key. - - @param key: The key to modify. - @type key: C{str} - - @param val: The value to prepend to the current value associated with - the key. - @type val: C{str} - - @return: A deferred that will fire with C{True} if the operation has - succeeded, C{False} otherwise. - @rtype: L{Deferred} - """ - # Even if flags and expTime values are ignored, we have to pass them - return self._set("prepend", key, val, 0, 0, "") - - - def get(self, key, withIdentifier=False): - """ - Get the given C{key}. It doesn't support multiple keys. If - C{withIdentifier} is set to C{True}, the command issued is a C{gets}, - that will return the current identifier associated with the value. This - identifier has to be used when issuing C{checkAndSet} update later, - using the corresponding method. - - @param key: The key to retrieve. - @type key: C{str} - - @param withIdentifier: If set to C{True}, retrieve the current - identifier along with the value and the flags. - @type withIdentifier: C{bool} - - @return: A deferred that will fire with the tuple (flags, value) if - C{withIdentifier} is C{False}, or (flags, cas identifier, value) - if C{True}. If the server indicates there is no value - associated with C{key}, the returned value will be C{None} and - the returned flags will be C{0}. - @rtype: L{Deferred} - """ - return self._get([key], withIdentifier, False) - - - def getMultiple(self, keys, withIdentifier=False): - """ - Get the given list of C{keys}. If C{withIdentifier} is set to C{True}, - the command issued is a C{gets}, that will return the identifiers - associated with each values. This identifier has to be used when - issuing C{checkAndSet} update later, using the corresponding method. - - @param keys: The keys to retrieve. - @type keys: C{list} of C{str} - - @param withIdentifier: If set to C{True}, retrieve the identifiers - along with the values and the flags. - @type withIdentifier: C{bool} - - @return: A deferred that will fire with a dictionary with the elements - of C{keys} as keys and the tuples (flags, value) as values if - C{withIdentifier} is C{False}, or (flags, cas identifier, value) if - C{True}. If the server indicates there is no value associated with - C{key}, the returned values will be C{None} and the returned flags - will be C{0}. - @rtype: L{Deferred} - - @since: 9.0 - """ - return self._get(keys, withIdentifier, True) - - def _get(self, keys, withIdentifier, multiple): - """ - Helper method for C{get} and C{getMultiple}. - """ - if self._disconnected: - return fail(RuntimeError("not connected")) - for key in keys: - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - if len(key) > self.MAX_KEY_LENGTH: - return fail(ClientError("Key too long")) - if withIdentifier: - cmd = "gets" - else: - cmd = "get" - fullcmd = "%s %s" % (cmd, " ".join(keys)) - self.sendLine(fullcmd) - if multiple: - values = dict([(key, (0, "", None)) for key in keys]) - cmdObj = Command(cmd, keys=keys, values=values, multiple=True) - else: - cmdObj = Command(cmd, key=keys[0], value=None, flags=0, cas="", - multiple=False) - self._current.append(cmdObj) - return cmdObj._deferred - - def stats(self, arg=None): - """ - Get some stats from the server. It will be available as a dict. - - @param arg: An optional additional string which will be sent along - with the I{stats} command. The interpretation of this value by - the server is left undefined by the memcache protocol - specification. - @type arg: L{NoneType} or L{str} - - @return: a deferred that will fire with a C{dict} of the available - statistics. - @rtype: L{Deferred} - """ - if arg: - cmd = "stats " + arg - else: - cmd = "stats" - if self._disconnected: - return fail(RuntimeError("not connected")) - self.sendLine(cmd) - cmdObj = Command("stats", values={}) - self._current.append(cmdObj) - return cmdObj._deferred - - - def version(self): - """ - Get the version of the server. - - @return: a deferred that will fire with the string value of the - version. - @rtype: L{Deferred} - """ - if self._disconnected: - return fail(RuntimeError("not connected")) - self.sendLine("version") - cmdObj = Command("version") - self._current.append(cmdObj) - return cmdObj._deferred - - - def delete(self, key): - """ - Delete an existing C{key}. - - @param key: the key to delete. - @type key: C{str} - - @return: a deferred that will be called back with C{True} if the key - was successfully deleted, or C{False} if not. - @rtype: L{Deferred} - """ - if self._disconnected: - return fail(RuntimeError("not connected")) - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - self.sendLine("delete %s" % key) - cmdObj = Command("delete", key=key) - self._current.append(cmdObj) - return cmdObj._deferred - - - def flushAll(self): - """ - Flush all cached values. - - @return: a deferred that will be called back with C{True} when the - operation has succeeded. - @rtype: L{Deferred} - """ - if self._disconnected: - return fail(RuntimeError("not connected")) - self.sendLine("flush_all") - cmdObj = Command("flush_all") - self._current.append(cmdObj) - return cmdObj._deferred - - - -__all__ = ["MemCacheProtocol", "DEFAULT_PORT", "NoSuchCommand", "ClientError", - "ServerError"] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/mice/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/mice/__init__.py deleted file mode 100644 index fda89c5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/mice/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Mice Protocols.""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/mice/mouseman.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/mice/mouseman.py deleted file mode 100644 index 4071b20..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/mice/mouseman.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# -"""Logictech MouseMan serial protocol. - -http://www.softnco.demon.co.uk/SerialMouse.txt -""" - -from twisted.internet import protocol - -class MouseMan(protocol.Protocol): - """ - - Parser for Logitech MouseMan serial mouse protocol (compatible - with Microsoft Serial Mouse). - - """ - - state = 'initial' - - leftbutton=None - rightbutton=None - middlebutton=None - - leftold=None - rightold=None - middleold=None - - horiz=None - vert=None - horizold=None - vertold=None - - def down_left(self): - pass - - def up_left(self): - pass - - def down_middle(self): - pass - - def up_middle(self): - pass - - def down_right(self): - pass - - def up_right(self): - pass - - def move(self, x, y): - pass - - horiz=None - vert=None - - def state_initial(self, byte): - if byte & 1<<6: - self.word1=byte - self.leftbutton = byte & 1<<5 - self.rightbutton = byte & 1<<4 - return 'horiz' - else: - return 'initial' - - def state_horiz(self, byte): - if byte & 1<<6: - return self.state_initial(byte) - else: - x=(self.word1 & 0x03)<<6 | (byte & 0x3f) - if x>=128: - x=-256+x - self.horiz = x - return 'vert' - - def state_vert(self, byte): - if byte & 1<<6: - # short packet - return self.state_initial(byte) - else: - x = (self.word1 & 0x0c)<<4 | (byte & 0x3f) - if x>=128: - x=-256+x - self.vert = x - self.snapshot() - return 'maybemiddle' - - def state_maybemiddle(self, byte): - if byte & 1<<6: - self.snapshot() - return self.state_initial(byte) - else: - self.middlebutton=byte & 1<<5 - self.snapshot() - return 'initial' - - def snapshot(self): - if self.leftbutton and not self.leftold: - self.down_left() - self.leftold=1 - if not self.leftbutton and self.leftold: - self.up_left() - self.leftold=0 - - if self.middlebutton and not self.middleold: - self.down_middle() - self.middleold=1 - if not self.middlebutton and self.middleold: - self.up_middle() - self.middleold=0 - - if self.rightbutton and not self.rightold: - self.down_right() - self.rightold=1 - if not self.rightbutton and self.rightold: - self.up_right() - self.rightold=0 - - if self.horiz or self.vert: - self.move(self.horiz, self.vert) - - def dataReceived(self, data): - for c in data: - byte = ord(c) - self.state = getattr(self, 'state_'+self.state)(byte) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/pcp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/pcp.py deleted file mode 100644 index 8970f90..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/pcp.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- test-case-name: twisted.test.test_pcp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Producer-Consumer Proxy. -""" - -from zope.interface import implements - -from twisted.internet import interfaces - - -class BasicProducerConsumerProxy: - """ - I can act as a man in the middle between any Producer and Consumer. - - @ivar producer: the Producer I subscribe to. - @type producer: L{IProducer} - @ivar consumer: the Consumer I publish to. - @type consumer: L{IConsumer} - @ivar paused: As a Producer, am I paused? - @type paused: bool - """ - implements(interfaces.IProducer, interfaces.IConsumer) - - consumer = None - producer = None - producerIsStreaming = None - iAmStreaming = True - outstandingPull = False - paused = False - stopped = False - - def __init__(self, consumer): - self._buffer = [] - if consumer is not None: - self.consumer = consumer - consumer.registerProducer(self, self.iAmStreaming) - - # Producer methods: - - def pauseProducing(self): - self.paused = True - if self.producer: - self.producer.pauseProducing() - - def resumeProducing(self): - self.paused = False - if self._buffer: - # TODO: Check to see if consumer supports writeSeq. - self.consumer.write(''.join(self._buffer)) - self._buffer[:] = [] - else: - if not self.iAmStreaming: - self.outstandingPull = True - - if self.producer is not None: - self.producer.resumeProducing() - - def stopProducing(self): - if self.producer is not None: - self.producer.stopProducing() - if self.consumer is not None: - del self.consumer - - # Consumer methods: - - def write(self, data): - if self.paused or (not self.iAmStreaming and not self.outstandingPull): - # We could use that fifo queue here. - self._buffer.append(data) - - elif self.consumer is not None: - self.consumer.write(data) - self.outstandingPull = False - - def finish(self): - if self.consumer is not None: - self.consumer.finish() - self.unregisterProducer() - - def registerProducer(self, producer, streaming): - self.producer = producer - self.producerIsStreaming = streaming - - def unregisterProducer(self): - if self.producer is not None: - del self.producer - del self.producerIsStreaming - if self.consumer: - self.consumer.unregisterProducer() - - def __repr__(self): - return '<%s@%x around %s>' % (self.__class__, id(self), self.consumer) - - -class ProducerConsumerProxy(BasicProducerConsumerProxy): - """ProducerConsumerProxy with a finite buffer. - - When my buffer fills up, I have my parent Producer pause until my buffer - has room in it again. - """ - # Copies much from abstract.FileDescriptor - bufferSize = 2**2**2**2 - - producerPaused = False - unregistered = False - - def pauseProducing(self): - # Does *not* call up to ProducerConsumerProxy to relay the pause - # message through to my parent Producer. - self.paused = True - - def resumeProducing(self): - self.paused = False - if self._buffer: - data = ''.join(self._buffer) - bytesSent = self._writeSomeData(data) - if bytesSent < len(data): - unsent = data[bytesSent:] - assert not self.iAmStreaming, ( - "Streaming producer did not write all its data.") - self._buffer[:] = [unsent] - else: - self._buffer[:] = [] - else: - bytesSent = 0 - - if (self.unregistered and bytesSent and not self._buffer and - self.consumer is not None): - self.consumer.unregisterProducer() - - if not self.iAmStreaming: - self.outstandingPull = not bytesSent - - if self.producer is not None: - bytesBuffered = sum([len(s) for s in self._buffer]) - # TODO: You can see here the potential for high and low - # watermarks, where bufferSize would be the high mark when we - # ask the upstream producer to pause, and we wouldn't have - # it resume again until it hit the low mark. Or if producer - # is Pull, maybe we'd like to pull from it as much as necessary - # to keep our buffer full to the low mark, so we're never caught - # without something to send. - if self.producerPaused and (bytesBuffered < self.bufferSize): - # Now that our buffer is empty, - self.producerPaused = False - self.producer.resumeProducing() - elif self.outstandingPull: - # I did not have any data to write in response to a pull, - # so I'd better pull some myself. - self.producer.resumeProducing() - - def write(self, data): - if self.paused or (not self.iAmStreaming and not self.outstandingPull): - # We could use that fifo queue here. - self._buffer.append(data) - - elif self.consumer is not None: - assert not self._buffer, ( - "Writing fresh data to consumer before my buffer is empty!") - # I'm going to use _writeSomeData here so that there is only one - # path to self.consumer.write. But it doesn't actually make sense, - # if I am streaming, for some data to not be all data. But maybe I - # am not streaming, but I am writing here anyway, because there was - # an earlier request for data which was not answered. - bytesSent = self._writeSomeData(data) - self.outstandingPull = False - if not bytesSent == len(data): - assert not self.iAmStreaming, ( - "Streaming producer did not write all its data.") - self._buffer.append(data[bytesSent:]) - - if (self.producer is not None) and self.producerIsStreaming: - bytesBuffered = sum([len(s) for s in self._buffer]) - if bytesBuffered >= self.bufferSize: - - self.producer.pauseProducing() - self.producerPaused = True - - def registerProducer(self, producer, streaming): - self.unregistered = False - BasicProducerConsumerProxy.registerProducer(self, producer, streaming) - if not streaming: - producer.resumeProducing() - - def unregisterProducer(self): - if self.producer is not None: - del self.producer - del self.producerIsStreaming - self.unregistered = True - if self.consumer and not self._buffer: - self.consumer.unregisterProducer() - - def _writeSomeData(self, data): - """Write as much of this data as possible. - - @returns: The number of bytes written. - """ - if self.consumer is None: - return 0 - self.consumer.write(data) - return len(data) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/policies.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/policies.py deleted file mode 100644 index 4db3040..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/policies.py +++ /dev/null @@ -1,737 +0,0 @@ -# -*- test-case-name: twisted.test.test_policies -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Resource limiting policies. - -@seealso: See also L{twisted.protocols.htb} for rate limiting. -""" - -from __future__ import division, absolute_import - -# system imports -import sys - -from zope.interface import directlyProvides, providedBy - -# twisted imports -from twisted.internet.protocol import ServerFactory, Protocol, ClientFactory -from twisted.internet import error -from twisted.internet.interfaces import ILoggingContext -from twisted.python import log - - -def _wrappedLogPrefix(wrapper, wrapped): - """ - Compute a log prefix for a wrapper and the object it wraps. - - @rtype: C{str} - """ - if ILoggingContext.providedBy(wrapped): - logPrefix = wrapped.logPrefix() - else: - logPrefix = wrapped.__class__.__name__ - return "%s (%s)" % (logPrefix, wrapper.__class__.__name__) - - - -class ProtocolWrapper(Protocol): - """ - Wraps protocol instances and acts as their transport as well. - - @ivar wrappedProtocol: An L{IProtocol} - provider to which L{IProtocol} - method calls onto this L{ProtocolWrapper} will be proxied. - - @ivar factory: The L{WrappingFactory} which created this - L{ProtocolWrapper}. - """ - - disconnecting = 0 - - def __init__(self, factory, wrappedProtocol): - self.wrappedProtocol = wrappedProtocol - self.factory = factory - - - def logPrefix(self): - """ - Use a customized log prefix mentioning both the wrapped protocol and - the current one. - """ - return _wrappedLogPrefix(self, self.wrappedProtocol) - - - def makeConnection(self, transport): - """ - When a connection is made, register this wrapper with its factory, - save the real transport, and connect the wrapped protocol to this - L{ProtocolWrapper} to intercept any transport calls it makes. - """ - directlyProvides(self, providedBy(transport)) - Protocol.makeConnection(self, transport) - self.factory.registerProtocol(self) - self.wrappedProtocol.makeConnection(self) - - - # Transport relaying - - def write(self, data): - self.transport.write(data) - - - def writeSequence(self, data): - self.transport.writeSequence(data) - - - def loseConnection(self): - self.disconnecting = 1 - self.transport.loseConnection() - - - def getPeer(self): - return self.transport.getPeer() - - - def getHost(self): - return self.transport.getHost() - - - def registerProducer(self, producer, streaming): - self.transport.registerProducer(producer, streaming) - - - def unregisterProducer(self): - self.transport.unregisterProducer() - - - def stopConsuming(self): - self.transport.stopConsuming() - - - def __getattr__(self, name): - return getattr(self.transport, name) - - - # Protocol relaying - - def dataReceived(self, data): - self.wrappedProtocol.dataReceived(data) - - - def connectionLost(self, reason): - self.factory.unregisterProtocol(self) - self.wrappedProtocol.connectionLost(reason) - - - -class WrappingFactory(ClientFactory): - """ - Wraps a factory and its protocols, and keeps track of them. - """ - - protocol = ProtocolWrapper - - def __init__(self, wrappedFactory): - self.wrappedFactory = wrappedFactory - self.protocols = {} - - - def logPrefix(self): - """ - Generate a log prefix mentioning both the wrapped factory and this one. - """ - return _wrappedLogPrefix(self, self.wrappedFactory) - - - def doStart(self): - self.wrappedFactory.doStart() - ClientFactory.doStart(self) - - - def doStop(self): - self.wrappedFactory.doStop() - ClientFactory.doStop(self) - - - def startedConnecting(self, connector): - self.wrappedFactory.startedConnecting(connector) - - - def clientConnectionFailed(self, connector, reason): - self.wrappedFactory.clientConnectionFailed(connector, reason) - - - def clientConnectionLost(self, connector, reason): - self.wrappedFactory.clientConnectionLost(connector, reason) - - - def buildProtocol(self, addr): - return self.protocol(self, self.wrappedFactory.buildProtocol(addr)) - - - def registerProtocol(self, p): - """ - Called by protocol to register itself. - """ - self.protocols[p] = 1 - - - def unregisterProtocol(self, p): - """ - Called by protocols when they go away. - """ - del self.protocols[p] - - - -class ThrottlingProtocol(ProtocolWrapper): - """ - Protocol for L{ThrottlingFactory}. - """ - - # wrap API for tracking bandwidth - - def write(self, data): - self.factory.registerWritten(len(data)) - ProtocolWrapper.write(self, data) - - - def writeSequence(self, seq): - self.factory.registerWritten(sum(map(len, seq))) - ProtocolWrapper.writeSequence(self, seq) - - - def dataReceived(self, data): - self.factory.registerRead(len(data)) - ProtocolWrapper.dataReceived(self, data) - - - def registerProducer(self, producer, streaming): - self.producer = producer - ProtocolWrapper.registerProducer(self, producer, streaming) - - - def unregisterProducer(self): - del self.producer - ProtocolWrapper.unregisterProducer(self) - - - def throttleReads(self): - self.transport.pauseProducing() - - - def unthrottleReads(self): - self.transport.resumeProducing() - - - def throttleWrites(self): - if hasattr(self, "producer"): - self.producer.pauseProducing() - - - def unthrottleWrites(self): - if hasattr(self, "producer"): - self.producer.resumeProducing() - - - -class ThrottlingFactory(WrappingFactory): - """ - Throttles bandwidth and number of connections. - - Write bandwidth will only be throttled if there is a producer - registered. - """ - - protocol = ThrottlingProtocol - - def __init__(self, wrappedFactory, maxConnectionCount=sys.maxsize, - readLimit=None, writeLimit=None): - WrappingFactory.__init__(self, wrappedFactory) - self.connectionCount = 0 - self.maxConnectionCount = maxConnectionCount - self.readLimit = readLimit # max bytes we should read per second - self.writeLimit = writeLimit # max bytes we should write per second - self.readThisSecond = 0 - self.writtenThisSecond = 0 - self.unthrottleReadsID = None - self.checkReadBandwidthID = None - self.unthrottleWritesID = None - self.checkWriteBandwidthID = None - - - def callLater(self, period, func): - """ - Wrapper around L{reactor.callLater} for test purpose. - """ - from twisted.internet import reactor - return reactor.callLater(period, func) - - - def registerWritten(self, length): - """ - Called by protocol to tell us more bytes were written. - """ - self.writtenThisSecond += length - - - def registerRead(self, length): - """ - Called by protocol to tell us more bytes were read. - """ - self.readThisSecond += length - - - def checkReadBandwidth(self): - """ - Checks if we've passed bandwidth limits. - """ - if self.readThisSecond > self.readLimit: - self.throttleReads() - throttleTime = (float(self.readThisSecond) / self.readLimit) - 1.0 - self.unthrottleReadsID = self.callLater(throttleTime, - self.unthrottleReads) - self.readThisSecond = 0 - self.checkReadBandwidthID = self.callLater(1, self.checkReadBandwidth) - - - def checkWriteBandwidth(self): - if self.writtenThisSecond > self.writeLimit: - self.throttleWrites() - throttleTime = (float(self.writtenThisSecond) / self.writeLimit) - 1.0 - self.unthrottleWritesID = self.callLater(throttleTime, - self.unthrottleWrites) - # reset for next round - self.writtenThisSecond = 0 - self.checkWriteBandwidthID = self.callLater(1, self.checkWriteBandwidth) - - - def throttleReads(self): - """ - Throttle reads on all protocols. - """ - log.msg("Throttling reads on %s" % self) - for p in self.protocols.keys(): - p.throttleReads() - - - def unthrottleReads(self): - """ - Stop throttling reads on all protocols. - """ - self.unthrottleReadsID = None - log.msg("Stopped throttling reads on %s" % self) - for p in self.protocols.keys(): - p.unthrottleReads() - - - def throttleWrites(self): - """ - Throttle writes on all protocols. - """ - log.msg("Throttling writes on %s" % self) - for p in self.protocols.keys(): - p.throttleWrites() - - - def unthrottleWrites(self): - """ - Stop throttling writes on all protocols. - """ - self.unthrottleWritesID = None - log.msg("Stopped throttling writes on %s" % self) - for p in self.protocols.keys(): - p.unthrottleWrites() - - - def buildProtocol(self, addr): - if self.connectionCount == 0: - if self.readLimit is not None: - self.checkReadBandwidth() - if self.writeLimit is not None: - self.checkWriteBandwidth() - - if self.connectionCount < self.maxConnectionCount: - self.connectionCount += 1 - return WrappingFactory.buildProtocol(self, addr) - else: - log.msg("Max connection count reached!") - return None - - - def unregisterProtocol(self, p): - WrappingFactory.unregisterProtocol(self, p) - self.connectionCount -= 1 - if self.connectionCount == 0: - if self.unthrottleReadsID is not None: - self.unthrottleReadsID.cancel() - if self.checkReadBandwidthID is not None: - self.checkReadBandwidthID.cancel() - if self.unthrottleWritesID is not None: - self.unthrottleWritesID.cancel() - if self.checkWriteBandwidthID is not None: - self.checkWriteBandwidthID.cancel() - - - -class SpewingProtocol(ProtocolWrapper): - def dataReceived(self, data): - log.msg("Received: %r" % data) - ProtocolWrapper.dataReceived(self,data) - - def write(self, data): - log.msg("Sending: %r" % data) - ProtocolWrapper.write(self,data) - - - -class SpewingFactory(WrappingFactory): - protocol = SpewingProtocol - - - -class LimitConnectionsByPeer(WrappingFactory): - - maxConnectionsPerPeer = 5 - - def startFactory(self): - self.peerConnections = {} - - def buildProtocol(self, addr): - peerHost = addr[0] - connectionCount = self.peerConnections.get(peerHost, 0) - if connectionCount >= self.maxConnectionsPerPeer: - return None - self.peerConnections[peerHost] = connectionCount + 1 - return WrappingFactory.buildProtocol(self, addr) - - def unregisterProtocol(self, p): - peerHost = p.getPeer()[1] - self.peerConnections[peerHost] -= 1 - if self.peerConnections[peerHost] == 0: - del self.peerConnections[peerHost] - - -class LimitTotalConnectionsFactory(ServerFactory): - """ - Factory that limits the number of simultaneous connections. - - @type connectionCount: C{int} - @ivar connectionCount: number of current connections. - @type connectionLimit: C{int} or C{None} - @cvar connectionLimit: maximum number of connections. - @type overflowProtocol: L{Protocol} or C{None} - @cvar overflowProtocol: Protocol to use for new connections when - connectionLimit is exceeded. If C{None} (the default value), excess - connections will be closed immediately. - """ - connectionCount = 0 - connectionLimit = None - overflowProtocol = None - - def buildProtocol(self, addr): - if (self.connectionLimit is None or - self.connectionCount < self.connectionLimit): - # Build the normal protocol - wrappedProtocol = self.protocol() - elif self.overflowProtocol is None: - # Just drop the connection - return None - else: - # Too many connections, so build the overflow protocol - wrappedProtocol = self.overflowProtocol() - - wrappedProtocol.factory = self - protocol = ProtocolWrapper(self, wrappedProtocol) - self.connectionCount += 1 - return protocol - - def registerProtocol(self, p): - pass - - def unregisterProtocol(self, p): - self.connectionCount -= 1 - - - -class TimeoutProtocol(ProtocolWrapper): - """ - Protocol that automatically disconnects when the connection is idle. - """ - - def __init__(self, factory, wrappedProtocol, timeoutPeriod): - """ - Constructor. - - @param factory: An L{IFactory}. - @param wrappedProtocol: A L{Protocol} to wrapp. - @param timeoutPeriod: Number of seconds to wait for activity before - timing out. - """ - ProtocolWrapper.__init__(self, factory, wrappedProtocol) - self.timeoutCall = None - self.setTimeout(timeoutPeriod) - - - def setTimeout(self, timeoutPeriod=None): - """ - Set a timeout. - - This will cancel any existing timeouts. - - @param timeoutPeriod: If not C{None}, change the timeout period. - Otherwise, use the existing value. - """ - self.cancelTimeout() - if timeoutPeriod is not None: - self.timeoutPeriod = timeoutPeriod - self.timeoutCall = self.factory.callLater(self.timeoutPeriod, self.timeoutFunc) - - - def cancelTimeout(self): - """ - Cancel the timeout. - - If the timeout was already cancelled, this does nothing. - """ - if self.timeoutCall: - try: - self.timeoutCall.cancel() - except error.AlreadyCalled: - pass - self.timeoutCall = None - - - def resetTimeout(self): - """ - Reset the timeout, usually because some activity just happened. - """ - if self.timeoutCall: - self.timeoutCall.reset(self.timeoutPeriod) - - - def write(self, data): - self.resetTimeout() - ProtocolWrapper.write(self, data) - - - def writeSequence(self, seq): - self.resetTimeout() - ProtocolWrapper.writeSequence(self, seq) - - - def dataReceived(self, data): - self.resetTimeout() - ProtocolWrapper.dataReceived(self, data) - - - def connectionLost(self, reason): - self.cancelTimeout() - ProtocolWrapper.connectionLost(self, reason) - - - def timeoutFunc(self): - """ - This method is called when the timeout is triggered. - - By default it calls L{loseConnection}. Override this if you want - something else to happen. - """ - self.loseConnection() - - - -class TimeoutFactory(WrappingFactory): - """ - Factory for TimeoutWrapper. - """ - protocol = TimeoutProtocol - - - def __init__(self, wrappedFactory, timeoutPeriod=30*60): - self.timeoutPeriod = timeoutPeriod - WrappingFactory.__init__(self, wrappedFactory) - - - def buildProtocol(self, addr): - return self.protocol(self, self.wrappedFactory.buildProtocol(addr), - timeoutPeriod=self.timeoutPeriod) - - - def callLater(self, period, func): - """ - Wrapper around L{reactor.callLater} for test purpose. - """ - from twisted.internet import reactor - return reactor.callLater(period, func) - - - -class TrafficLoggingProtocol(ProtocolWrapper): - - def __init__(self, factory, wrappedProtocol, logfile, lengthLimit=None, - number=0): - """ - @param factory: factory which created this protocol. - @type factory: C{protocol.Factory}. - @param wrappedProtocol: the underlying protocol. - @type wrappedProtocol: C{protocol.Protocol}. - @param logfile: file opened for writing used to write log messages. - @type logfile: C{file} - @param lengthLimit: maximum size of the datareceived logged. - @type lengthLimit: C{int} - @param number: identifier of the connection. - @type number: C{int}. - """ - ProtocolWrapper.__init__(self, factory, wrappedProtocol) - self.logfile = logfile - self.lengthLimit = lengthLimit - self._number = number - - - def _log(self, line): - self.logfile.write(line + '\n') - self.logfile.flush() - - - def _mungeData(self, data): - if self.lengthLimit and len(data) > self.lengthLimit: - data = data[:self.lengthLimit - 12] + '<... elided>' - return data - - - # IProtocol - def connectionMade(self): - self._log('*') - return ProtocolWrapper.connectionMade(self) - - - def dataReceived(self, data): - self._log('C %d: %r' % (self._number, self._mungeData(data))) - return ProtocolWrapper.dataReceived(self, data) - - - def connectionLost(self, reason): - self._log('C %d: %r' % (self._number, reason)) - return ProtocolWrapper.connectionLost(self, reason) - - - # ITransport - def write(self, data): - self._log('S %d: %r' % (self._number, self._mungeData(data))) - return ProtocolWrapper.write(self, data) - - - def writeSequence(self, iovec): - self._log('SV %d: %r' % (self._number, [self._mungeData(d) for d in iovec])) - return ProtocolWrapper.writeSequence(self, iovec) - - - def loseConnection(self): - self._log('S %d: *' % (self._number,)) - return ProtocolWrapper.loseConnection(self) - - - -class TrafficLoggingFactory(WrappingFactory): - protocol = TrafficLoggingProtocol - - _counter = 0 - - def __init__(self, wrappedFactory, logfilePrefix, lengthLimit=None): - self.logfilePrefix = logfilePrefix - self.lengthLimit = lengthLimit - WrappingFactory.__init__(self, wrappedFactory) - - - def open(self, name): - return file(name, 'w') - - - def buildProtocol(self, addr): - self._counter += 1 - logfile = self.open(self.logfilePrefix + '-' + str(self._counter)) - return self.protocol(self, self.wrappedFactory.buildProtocol(addr), - logfile, self.lengthLimit, self._counter) - - - def resetCounter(self): - """ - Reset the value of the counter used to identify connections. - """ - self._counter = 0 - - - -class TimeoutMixin: - """ - Mixin for protocols which wish to timeout connections. - - Protocols that mix this in have a single timeout, set using L{setTimeout}. - When the timeout is hit, L{timeoutConnection} is called, which, by - default, closes the connection. - - @cvar timeOut: The number of seconds after which to timeout the connection. - """ - timeOut = None - - __timeoutCall = None - - def callLater(self, period, func): - """ - Wrapper around L{reactor.callLater} for test purpose. - """ - from twisted.internet import reactor - return reactor.callLater(period, func) - - - def resetTimeout(self): - """ - Reset the timeout count down. - - If the connection has already timed out, then do nothing. If the - timeout has been cancelled (probably using C{setTimeout(None)}), also - do nothing. - - It's often a good idea to call this when the protocol has received - some meaningful input from the other end of the connection. "I've got - some data, they're still there, reset the timeout". - """ - if self.__timeoutCall is not None and self.timeOut is not None: - self.__timeoutCall.reset(self.timeOut) - - def setTimeout(self, period): - """ - Change the timeout period - - @type period: C{int} or C{NoneType} - @param period: The period, in seconds, to change the timeout to, or - C{None} to disable the timeout. - """ - prev = self.timeOut - self.timeOut = period - - if self.__timeoutCall is not None: - if period is None: - self.__timeoutCall.cancel() - self.__timeoutCall = None - else: - self.__timeoutCall.reset(period) - elif period is not None: - self.__timeoutCall = self.callLater(period, self.__timedOut) - - return prev - - def __timedOut(self): - self.__timeoutCall = None - self.timeoutConnection() - - def timeoutConnection(self): - """ - Called when the connection times out. - - Override to define behavior other than dropping the connection. - """ - self.transport.loseConnection() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/portforward.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/portforward.py deleted file mode 100644 index 626d5aa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/portforward.py +++ /dev/null @@ -1,87 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A simple port forwarder. -""" - -# Twisted imports -from twisted.internet import protocol -from twisted.python import log - -class Proxy(protocol.Protocol): - noisy = True - - peer = None - - def setPeer(self, peer): - self.peer = peer - - def connectionLost(self, reason): - if self.peer is not None: - self.peer.transport.loseConnection() - self.peer = None - elif self.noisy: - log.msg("Unable to connect to peer: %s" % (reason,)) - - def dataReceived(self, data): - self.peer.transport.write(data) - -class ProxyClient(Proxy): - def connectionMade(self): - self.peer.setPeer(self) - - # Wire this and the peer transport together to enable - # flow control (this stops connections from filling - # this proxy memory when one side produces data at a - # higher rate than the other can consume). - self.transport.registerProducer(self.peer.transport, True) - self.peer.transport.registerProducer(self.transport, True) - - # We're connected, everybody can read to their hearts content. - self.peer.transport.resumeProducing() - -class ProxyClientFactory(protocol.ClientFactory): - - protocol = ProxyClient - - def setServer(self, server): - self.server = server - - def buildProtocol(self, *args, **kw): - prot = protocol.ClientFactory.buildProtocol(self, *args, **kw) - prot.setPeer(self.server) - return prot - - def clientConnectionFailed(self, connector, reason): - self.server.transport.loseConnection() - - -class ProxyServer(Proxy): - - clientProtocolFactory = ProxyClientFactory - reactor = None - - def connectionMade(self): - # Don't read anything from the connecting client until we have - # somewhere to send it to. - self.transport.pauseProducing() - - client = self.clientProtocolFactory() - client.setServer(self) - - if self.reactor is None: - from twisted.internet import reactor - self.reactor = reactor - self.reactor.connectTCP(self.factory.host, self.factory.port, client) - - -class ProxyFactory(protocol.Factory): - """Factory for port forwarder.""" - - protocol = ProxyServer - - def __init__(self, host, port): - self.host = host - self.port = port diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/postfix.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/postfix.py deleted file mode 100644 index 7a2079d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/postfix.py +++ /dev/null @@ -1,112 +0,0 @@ -# -*- test-case-name: twisted.test.test_postfix -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Postfix mail transport agent related protocols. -""" - -import sys -import UserDict -import urllib - -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import protocol, defer -from twisted.python import log - -# urllib's quote functions just happen to match -# the postfix semantics. -def quote(s): - return urllib.quote(s) - -def unquote(s): - return urllib.unquote(s) - -class PostfixTCPMapServer(basic.LineReceiver, policies.TimeoutMixin): - """Postfix mail transport agent TCP map protocol implementation. - - Receive requests for data matching given key via lineReceived, - asks it's factory for the data with self.factory.get(key), and - returns the data to the requester. None means no entry found. - - You can use postfix's postmap to test the map service:: - - /usr/sbin/postmap -q KEY tcp:localhost:4242 - - """ - - timeout = 600 - delimiter = '\n' - - def connectionMade(self): - self.setTimeout(self.timeout) - - def sendCode(self, code, message=''): - "Send an SMTP-like code with a message." - self.sendLine('%3.3d %s' % (code, message or '')) - - def lineReceived(self, line): - self.resetTimeout() - try: - request, params = line.split(None, 1) - except ValueError: - request = line - params = None - try: - f = getattr(self, 'do_' + request) - except AttributeError: - self.sendCode(400, 'unknown command') - else: - try: - f(params) - except: - self.sendCode(400, 'Command %r failed: %s.' % (request, sys.exc_info()[1])) - - def do_get(self, key): - if key is None: - self.sendCode(400, 'Command %r takes 1 parameters.' % 'get') - else: - d = defer.maybeDeferred(self.factory.get, key) - d.addCallbacks(self._cbGot, self._cbNot) - d.addErrback(log.err) - - def _cbNot(self, fail): - self.sendCode(400, fail.getErrorMessage()) - - def _cbGot(self, value): - if value is None: - self.sendCode(500) - else: - self.sendCode(200, quote(value)) - - def do_put(self, keyAndValue): - if keyAndValue is None: - self.sendCode(400, 'Command %r takes 2 parameters.' % 'put') - else: - try: - key, value = keyAndValue.split(None, 1) - except ValueError: - self.sendCode(400, 'Command %r takes 2 parameters.' % 'put') - else: - self.sendCode(500, 'put is not implemented yet.') - - -class PostfixTCPMapDictServerFactory(protocol.ServerFactory, - UserDict.UserDict): - """An in-memory dictionary factory for PostfixTCPMapServer.""" - - protocol = PostfixTCPMapServer - -class PostfixTCPMapDeferringDictServerFactory(protocol.ServerFactory): - """An in-memory dictionary factory for PostfixTCPMapServer.""" - - protocol = PostfixTCPMapServer - - def __init__(self, data=None): - self.data = {} - if data is not None: - self.data.update(data) - - def get(self, key): - return defer.succeed(self.data.get(key)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/shoutcast.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/shoutcast.py deleted file mode 100644 index 317d5e8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/shoutcast.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Chop up shoutcast stream into MP3s and metadata, if available. -""" - -from twisted.web import http -from twisted import copyright - - -class ShoutcastClient(http.HTTPClient): - """ - Shoutcast HTTP stream. - - Modes can be 'length', 'meta' and 'mp3'. - - See U{http://www.smackfu.com/stuff/programming/shoutcast.html} - for details on the protocol. - """ - - userAgent = "Twisted Shoutcast client " + copyright.version - - def __init__(self, path="/"): - self.path = path - self.got_metadata = False - self.metaint = None - self.metamode = "mp3" - self.databuffer = "" - - def connectionMade(self): - self.sendCommand("GET", self.path) - self.sendHeader("User-Agent", self.userAgent) - self.sendHeader("Icy-MetaData", "1") - self.endHeaders() - - def lineReceived(self, line): - # fix shoutcast crappiness - if not self.firstLine and line: - if len(line.split(": ", 1)) == 1: - line = line.replace(":", ": ", 1) - http.HTTPClient.lineReceived(self, line) - - def handleHeader(self, key, value): - if key.lower() == 'icy-metaint': - self.metaint = int(value) - self.got_metadata = True - - def handleEndHeaders(self): - # Lets check if we got metadata, and set the - # appropriate handleResponsePart method. - if self.got_metadata: - # if we have metadata, then it has to be parsed out of the data stream - self.handleResponsePart = self.handleResponsePart_with_metadata - else: - # otherwise, all the data is MP3 data - self.handleResponsePart = self.gotMP3Data - - def handleResponsePart_with_metadata(self, data): - self.databuffer += data - while self.databuffer: - stop = getattr(self, "handle_%s" % self.metamode)() - if stop: - return - - def handle_length(self): - self.remaining = ord(self.databuffer[0]) * 16 - self.databuffer = self.databuffer[1:] - self.metamode = "meta" - - def handle_mp3(self): - if len(self.databuffer) > self.metaint: - self.gotMP3Data(self.databuffer[:self.metaint]) - self.databuffer = self.databuffer[self.metaint:] - self.metamode = "length" - else: - return 1 - - def handle_meta(self): - if len(self.databuffer) >= self.remaining: - if self.remaining: - data = self.databuffer[:self.remaining] - self.gotMetaData(self.parseMetadata(data)) - self.databuffer = self.databuffer[self.remaining:] - self.metamode = "mp3" - else: - return 1 - - def parseMetadata(self, data): - meta = [] - for chunk in data.split(';'): - chunk = chunk.strip().replace("\x00", "") - if not chunk: - continue - key, value = chunk.split('=', 1) - if value.startswith("'") and value.endswith("'"): - value = value[1:-1] - meta.append((key, value)) - return meta - - def gotMetaData(self, metadata): - """Called with a list of (key, value) pairs of metadata, - if metadata is available on the server. - - Will only be called on non-empty metadata. - """ - raise NotImplementedError, "implement in subclass" - - def gotMP3Data(self, data): - """Called with chunk of MP3 data.""" - raise NotImplementedError, "implement in subclass" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/sip.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/sip.py deleted file mode 100644 index b7774c1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/sip.py +++ /dev/null @@ -1,1346 +0,0 @@ -# -*- test-case-name: twisted.test.test_sip -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Session Initialization Protocol. - -Documented in RFC 2543. -[Superseded by 3261] - - -This module contains a deprecated implementation of HTTP Digest authentication. -See L{twisted.cred.credentials} and L{twisted.cred._digest} for its new home. -""" - -# system imports -import socket, time, sys, random, warnings -from hashlib import md5 -from zope.interface import implements, Interface - -# twisted imports -from twisted.python import log, util -from twisted.python.deprecate import deprecated -from twisted.python.versions import Version -from twisted.internet import protocol, defer, reactor - -from twisted import cred -from twisted.cred.credentials import UsernameHashedPassword, UsernamePassword - - -# sibling imports -from twisted.protocols import basic - -PORT = 5060 - -# SIP headers have short forms -shortHeaders = {"call-id": "i", - "contact": "m", - "content-encoding": "e", - "content-length": "l", - "content-type": "c", - "from": "f", - "subject": "s", - "to": "t", - "via": "v", - } - -longHeaders = {} -for k, v in shortHeaders.items(): - longHeaders[v] = k -del k, v - -statusCodes = { - 100: "Trying", - 180: "Ringing", - 181: "Call Is Being Forwarded", - 182: "Queued", - 183: "Session Progress", - - 200: "OK", - - 300: "Multiple Choices", - 301: "Moved Permanently", - 302: "Moved Temporarily", - 303: "See Other", - 305: "Use Proxy", - 380: "Alternative Service", - - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Timeout", - 409: "Conflict", # Not in RFC3261 - 410: "Gone", - 411: "Length Required", # Not in RFC3261 - 413: "Request Entity Too Large", - 414: "Request-URI Too Large", - 415: "Unsupported Media Type", - 416: "Unsupported URI Scheme", - 420: "Bad Extension", - 421: "Extension Required", - 423: "Interval Too Brief", - 480: "Temporarily Unavailable", - 481: "Call/Transaction Does Not Exist", - 482: "Loop Detected", - 483: "Too Many Hops", - 484: "Address Incomplete", - 485: "Ambiguous", - 486: "Busy Here", - 487: "Request Terminated", - 488: "Not Acceptable Here", - 491: "Request Pending", - 493: "Undecipherable", - - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", # no donut - 503: "Service Unavailable", - 504: "Server Time-out", - 505: "SIP Version not supported", - 513: "Message Too Large", - - 600: "Busy Everywhere", - 603: "Decline", - 604: "Does not exist anywhere", - 606: "Not Acceptable", -} - -specialCases = { - 'cseq': 'CSeq', - 'call-id': 'Call-ID', - 'www-authenticate': 'WWW-Authenticate', -} - - -def dashCapitalize(s): - ''' Capitalize a string, making sure to treat - as a word separator ''' - return '-'.join([ x.capitalize() for x in s.split('-')]) - -def unq(s): - if s[0] == s[-1] == '"': - return s[1:-1] - return s - -def DigestCalcHA1( - pszAlg, - pszUserName, - pszRealm, - pszPassword, - pszNonce, - pszCNonce, -): - m = md5() - m.update(pszUserName) - m.update(":") - m.update(pszRealm) - m.update(":") - m.update(pszPassword) - HA1 = m.digest() - if pszAlg == "md5-sess": - m = md5() - m.update(HA1) - m.update(":") - m.update(pszNonce) - m.update(":") - m.update(pszCNonce) - HA1 = m.digest() - return HA1.encode('hex') - - -DigestCalcHA1 = deprecated(Version("Twisted", 9, 0, 0))(DigestCalcHA1) - -def DigestCalcResponse( - HA1, - pszNonce, - pszNonceCount, - pszCNonce, - pszQop, - pszMethod, - pszDigestUri, - pszHEntity, -): - m = md5() - m.update(pszMethod) - m.update(":") - m.update(pszDigestUri) - if pszQop == "auth-int": - m.update(":") - m.update(pszHEntity) - HA2 = m.digest().encode('hex') - - m = md5() - m.update(HA1) - m.update(":") - m.update(pszNonce) - m.update(":") - if pszNonceCount and pszCNonce: # pszQop: - m.update(pszNonceCount) - m.update(":") - m.update(pszCNonce) - m.update(":") - m.update(pszQop) - m.update(":") - m.update(HA2) - hash = m.digest().encode('hex') - return hash - - -DigestCalcResponse = deprecated(Version("Twisted", 9, 0, 0))(DigestCalcResponse) - -_absent = object() - -class Via(object): - """ - A L{Via} is a SIP Via header, representing a segment of the path taken by - the request. - - See RFC 3261, sections 8.1.1.7, 18.2.2, and 20.42. - - @ivar transport: Network protocol used for this leg. (Probably either "TCP" - or "UDP".) - @type transport: C{str} - @ivar branch: Unique identifier for this request. - @type branch: C{str} - @ivar host: Hostname or IP for this leg. - @type host: C{str} - @ivar port: Port used for this leg. - @type port C{int}, or None. - @ivar rportRequested: Whether to request RFC 3581 client processing or not. - @type rportRequested: C{bool} - @ivar rportValue: Servers wishing to honor requests for RFC 3581 processing - should set this parameter to the source port the request was received - from. - @type rportValue: C{int}, or None. - - @ivar ttl: Time-to-live for requests on multicast paths. - @type ttl: C{int}, or None. - @ivar maddr: The destination multicast address, if any. - @type maddr: C{str}, or None. - @ivar hidden: Obsolete in SIP 2.0. - @type hidden: C{bool} - @ivar otherParams: Any other parameters in the header. - @type otherParams: C{dict} - """ - - def __init__(self, host, port=PORT, transport="UDP", ttl=None, - hidden=False, received=None, rport=_absent, branch=None, - maddr=None, **kw): - """ - Set parameters of this Via header. All arguments correspond to - attributes of the same name. - - To maintain compatibility with old SIP - code, the 'rport' argument is used to determine the values of - C{rportRequested} and C{rportValue}. If None, C{rportRequested} is set - to True. (The deprecated method for doing this is to pass True.) If an - integer, C{rportValue} is set to the given value. - - Any arguments not explicitly named here are collected into the - C{otherParams} dict. - """ - self.transport = transport - self.host = host - self.port = port - self.ttl = ttl - self.hidden = hidden - self.received = received - if rport is True: - warnings.warn( - "rport=True is deprecated since Twisted 9.0.", - DeprecationWarning, - stacklevel=2) - self.rportValue = None - self.rportRequested = True - elif rport is None: - self.rportValue = None - self.rportRequested = True - elif rport is _absent: - self.rportValue = None - self.rportRequested = False - else: - self.rportValue = rport - self.rportRequested = False - - self.branch = branch - self.maddr = maddr - self.otherParams = kw - - - def _getrport(self): - """ - Returns the rport value expected by the old SIP code. - """ - if self.rportRequested == True: - return True - elif self.rportValue is not None: - return self.rportValue - else: - return None - - - def _setrport(self, newRPort): - """ - L{Base._fixupNAT} sets C{rport} directly, so this method sets - C{rportValue} based on that. - - @param newRPort: The new rport value. - @type newRPort: C{int} - """ - self.rportValue = newRPort - self.rportRequested = False - - - rport = property(_getrport, _setrport) - - def toString(self): - """ - Serialize this header for use in a request or response. - """ - s = "SIP/2.0/%s %s:%s" % (self.transport, self.host, self.port) - if self.hidden: - s += ";hidden" - for n in "ttl", "branch", "maddr", "received": - value = getattr(self, n) - if value is not None: - s += ";%s=%s" % (n, value) - if self.rportRequested: - s += ";rport" - elif self.rportValue is not None: - s += ";rport=%s" % (self.rport,) - - etc = self.otherParams.items() - etc.sort() - for k, v in etc: - if v is None: - s += ";" + k - else: - s += ";%s=%s" % (k, v) - return s - - -def parseViaHeader(value): - """ - Parse a Via header. - - @return: The parsed version of this header. - @rtype: L{Via} - """ - parts = value.split(";") - sent, params = parts[0], parts[1:] - protocolinfo, by = sent.split(" ", 1) - by = by.strip() - result = {} - pname, pversion, transport = protocolinfo.split("/") - if pname != "SIP" or pversion != "2.0": - raise ValueError, "wrong protocol or version: %r" % value - result["transport"] = transport - if ":" in by: - host, port = by.split(":") - result["port"] = int(port) - result["host"] = host - else: - result["host"] = by - for p in params: - # it's the comment-striping dance! - p = p.strip().split(" ", 1) - if len(p) == 1: - p, comment = p[0], "" - else: - p, comment = p - if p == "hidden": - result["hidden"] = True - continue - parts = p.split("=", 1) - if len(parts) == 1: - name, value = parts[0], None - else: - name, value = parts - if name in ("rport", "ttl"): - value = int(value) - result[name] = value - return Via(**result) - - -class URL: - """A SIP URL.""" - - def __init__(self, host, username=None, password=None, port=None, - transport=None, usertype=None, method=None, - ttl=None, maddr=None, tag=None, other=None, headers=None): - self.username = username - self.host = host - self.password = password - self.port = port - self.transport = transport - self.usertype = usertype - self.method = method - self.tag = tag - self.ttl = ttl - self.maddr = maddr - if other == None: - self.other = [] - else: - self.other = other - if headers == None: - self.headers = {} - else: - self.headers = headers - - def toString(self): - l = []; w = l.append - w("sip:") - if self.username != None: - w(self.username) - if self.password != None: - w(":%s" % self.password) - w("@") - w(self.host) - if self.port != None: - w(":%d" % self.port) - if self.usertype != None: - w(";user=%s" % self.usertype) - for n in ("transport", "ttl", "maddr", "method", "tag"): - v = getattr(self, n) - if v != None: - w(";%s=%s" % (n, v)) - for v in self.other: - w(";%s" % v) - if self.headers: - w("?") - w("&".join([("%s=%s" % (specialCases.get(h) or dashCapitalize(h), v)) for (h, v) in self.headers.items()])) - return "".join(l) - - def __str__(self): - return self.toString() - - def __repr__(self): - return '' % (self.username, self.password, self.host, self.port, self.transport) - - -def parseURL(url, host=None, port=None): - """Return string into URL object. - - URIs are of form 'sip:user@example.com'. - """ - d = {} - if not url.startswith("sip:"): - raise ValueError("unsupported scheme: " + url[:4]) - parts = url[4:].split(";") - userdomain, params = parts[0], parts[1:] - udparts = userdomain.split("@", 1) - if len(udparts) == 2: - userpass, hostport = udparts - upparts = userpass.split(":", 1) - if len(upparts) == 1: - d["username"] = upparts[0] - else: - d["username"] = upparts[0] - d["password"] = upparts[1] - else: - hostport = udparts[0] - hpparts = hostport.split(":", 1) - if len(hpparts) == 1: - d["host"] = hpparts[0] - else: - d["host"] = hpparts[0] - d["port"] = int(hpparts[1]) - if host != None: - d["host"] = host - if port != None: - d["port"] = port - for p in params: - if p == params[-1] and "?" in p: - d["headers"] = h = {} - p, headers = p.split("?", 1) - for header in headers.split("&"): - k, v = header.split("=") - h[k] = v - nv = p.split("=", 1) - if len(nv) == 1: - d.setdefault("other", []).append(p) - continue - name, value = nv - if name == "user": - d["usertype"] = value - elif name in ("transport", "ttl", "maddr", "method", "tag"): - if name == "ttl": - value = int(value) - d[name] = value - else: - d.setdefault("other", []).append(p) - return URL(**d) - - -def cleanRequestURL(url): - """Clean a URL from a Request line.""" - url.transport = None - url.maddr = None - url.ttl = None - url.headers = {} - - -def parseAddress(address, host=None, port=None, clean=0): - """Return (name, uri, params) for From/To/Contact header. - - @param clean: remove unnecessary info, usually for From and To headers. - """ - address = address.strip() - # simple 'sip:foo' case - if address.startswith("sip:"): - return "", parseURL(address, host=host, port=port), {} - params = {} - name, url = address.split("<", 1) - name = name.strip() - if name.startswith('"'): - name = name[1:] - if name.endswith('"'): - name = name[:-1] - url, paramstring = url.split(">", 1) - url = parseURL(url, host=host, port=port) - paramstring = paramstring.strip() - if paramstring: - for l in paramstring.split(";"): - if not l: - continue - k, v = l.split("=") - params[k] = v - if clean: - # rfc 2543 6.21 - url.ttl = None - url.headers = {} - url.transport = None - url.maddr = None - return name, url, params - - -class SIPError(Exception): - def __init__(self, code, phrase=None): - if phrase is None: - phrase = statusCodes[code] - Exception.__init__(self, "SIP error (%d): %s" % (code, phrase)) - self.code = code - self.phrase = phrase - - -class RegistrationError(SIPError): - """Registration was not possible.""" - - -class Message: - """A SIP message.""" - - length = None - - def __init__(self): - self.headers = util.OrderedDict() # map name to list of values - self.body = "" - self.finished = 0 - - def addHeader(self, name, value): - name = name.lower() - name = longHeaders.get(name, name) - if name == "content-length": - self.length = int(value) - self.headers.setdefault(name,[]).append(value) - - def bodyDataReceived(self, data): - self.body += data - - def creationFinished(self): - if (self.length != None) and (self.length != len(self.body)): - raise ValueError, "wrong body length" - self.finished = 1 - - def toString(self): - s = "%s\r\n" % self._getHeaderLine() - for n, vs in self.headers.items(): - for v in vs: - s += "%s: %s\r\n" % (specialCases.get(n) or dashCapitalize(n), v) - s += "\r\n" - s += self.body - return s - - def _getHeaderLine(self): - raise NotImplementedError - - -class Request(Message): - """A Request for a URI""" - - - def __init__(self, method, uri, version="SIP/2.0"): - Message.__init__(self) - self.method = method - if isinstance(uri, URL): - self.uri = uri - else: - self.uri = parseURL(uri) - cleanRequestURL(self.uri) - - def __repr__(self): - return "" % (id(self), self.method, self.uri.toString()) - - def _getHeaderLine(self): - return "%s %s SIP/2.0" % (self.method, self.uri.toString()) - - -class Response(Message): - """A Response to a URI Request""" - - def __init__(self, code, phrase=None, version="SIP/2.0"): - Message.__init__(self) - self.code = code - if phrase == None: - phrase = statusCodes[code] - self.phrase = phrase - - def __repr__(self): - return "" % (id(self), self.code) - - def _getHeaderLine(self): - return "SIP/2.0 %s %s" % (self.code, self.phrase) - - -class MessagesParser(basic.LineReceiver): - """A SIP messages parser. - - Expects dataReceived, dataDone repeatedly, - in that order. Shouldn't be connected to actual transport. - """ - - version = "SIP/2.0" - acceptResponses = 1 - acceptRequests = 1 - state = "firstline" # or "headers", "body" or "invalid" - - debug = 0 - - def __init__(self, messageReceivedCallback): - self.messageReceived = messageReceivedCallback - self.reset() - - def reset(self, remainingData=""): - self.state = "firstline" - self.length = None # body length - self.bodyReceived = 0 # how much of the body we received - self.message = None - self.header = None - self.setLineMode(remainingData) - - def invalidMessage(self): - self.state = "invalid" - self.setRawMode() - - def dataDone(self): - # clear out any buffered data that may be hanging around - self.clearLineBuffer() - if self.state == "firstline": - return - if self.state != "body": - self.reset() - return - if self.length == None: - # no content-length header, so end of data signals message done - self.messageDone() - elif self.length < self.bodyReceived: - # aborted in the middle - self.reset() - else: - # we have enough data and message wasn't finished? something is wrong - raise RuntimeError, "this should never happen" - - def dataReceived(self, data): - try: - basic.LineReceiver.dataReceived(self, data) - except: - log.err() - self.invalidMessage() - - def handleFirstLine(self, line): - """Expected to create self.message.""" - raise NotImplementedError - - def lineLengthExceeded(self, line): - self.invalidMessage() - - def lineReceived(self, line): - if self.state == "firstline": - while line.startswith("\n") or line.startswith("\r"): - line = line[1:] - if not line: - return - try: - a, b, c = line.split(" ", 2) - except ValueError: - self.invalidMessage() - return - if a == "SIP/2.0" and self.acceptResponses: - # response - try: - code = int(b) - except ValueError: - self.invalidMessage() - return - self.message = Response(code, c) - elif c == "SIP/2.0" and self.acceptRequests: - self.message = Request(a, b) - else: - self.invalidMessage() - return - self.state = "headers" - return - else: - assert self.state == "headers" - if line: - # multiline header - if line.startswith(" ") or line.startswith("\t"): - name, value = self.header - self.header = name, (value + line.lstrip()) - else: - # new header - if self.header: - self.message.addHeader(*self.header) - self.header = None - try: - name, value = line.split(":", 1) - except ValueError: - self.invalidMessage() - return - self.header = name, value.lstrip() - # XXX we assume content-length won't be multiline - if name.lower() == "content-length": - try: - self.length = int(value.lstrip()) - except ValueError: - self.invalidMessage() - return - else: - # CRLF, we now have message body until self.length bytes, - # or if no length was given, until there is no more data - # from the connection sending us data. - self.state = "body" - if self.header: - self.message.addHeader(*self.header) - self.header = None - if self.length == 0: - self.messageDone() - return - self.setRawMode() - - def messageDone(self, remainingData=""): - assert self.state == "body" - self.message.creationFinished() - self.messageReceived(self.message) - self.reset(remainingData) - - def rawDataReceived(self, data): - assert self.state in ("body", "invalid") - if self.state == "invalid": - return - if self.length == None: - self.message.bodyDataReceived(data) - else: - dataLen = len(data) - expectedLen = self.length - self.bodyReceived - if dataLen > expectedLen: - self.message.bodyDataReceived(data[:expectedLen]) - self.messageDone(data[expectedLen:]) - return - else: - self.bodyReceived += dataLen - self.message.bodyDataReceived(data) - if self.bodyReceived == self.length: - self.messageDone() - - -class Base(protocol.DatagramProtocol): - """Base class for SIP clients and servers.""" - - PORT = PORT - debug = False - - def __init__(self): - self.messages = [] - self.parser = MessagesParser(self.addMessage) - - def addMessage(self, msg): - self.messages.append(msg) - - def datagramReceived(self, data, addr): - self.parser.dataReceived(data) - self.parser.dataDone() - for m in self.messages: - self._fixupNAT(m, addr) - if self.debug: - log.msg("Received %r from %r" % (m.toString(), addr)) - if isinstance(m, Request): - self.handle_request(m, addr) - else: - self.handle_response(m, addr) - self.messages[:] = [] - - def _fixupNAT(self, message, (srcHost, srcPort)): - # RFC 2543 6.40.2, - senderVia = parseViaHeader(message.headers["via"][0]) - if senderVia.host != srcHost: - senderVia.received = srcHost - if senderVia.port != srcPort: - senderVia.rport = srcPort - message.headers["via"][0] = senderVia.toString() - elif senderVia.rport == True: - senderVia.received = srcHost - senderVia.rport = srcPort - message.headers["via"][0] = senderVia.toString() - - def deliverResponse(self, responseMessage): - """Deliver response. - - Destination is based on topmost Via header.""" - destVia = parseViaHeader(responseMessage.headers["via"][0]) - # XXX we don't do multicast yet - host = destVia.received or destVia.host - port = destVia.rport or destVia.port or self.PORT - destAddr = URL(host=host, port=port) - self.sendMessage(destAddr, responseMessage) - - def responseFromRequest(self, code, request): - """Create a response to a request message.""" - response = Response(code) - for name in ("via", "to", "from", "call-id", "cseq"): - response.headers[name] = request.headers.get(name, [])[:] - - return response - - def sendMessage(self, destURL, message): - """Send a message. - - @param destURL: C{URL}. This should be a *physical* URL, not a logical one. - @param message: The message to send. - """ - if destURL.transport not in ("udp", None): - raise RuntimeError, "only UDP currently supported" - if self.debug: - log.msg("Sending %r to %r" % (message.toString(), destURL)) - self.transport.write(message.toString(), (destURL.host, destURL.port or self.PORT)) - - def handle_request(self, message, addr): - """Override to define behavior for requests received - - @type message: C{Message} - @type addr: C{tuple} - """ - raise NotImplementedError - - def handle_response(self, message, addr): - """Override to define behavior for responses received. - - @type message: C{Message} - @type addr: C{tuple} - """ - raise NotImplementedError - - -class IContact(Interface): - """A user of a registrar or proxy""" - - -class Registration: - def __init__(self, secondsToExpiry, contactURL): - self.secondsToExpiry = secondsToExpiry - self.contactURL = contactURL - -class IRegistry(Interface): - """Allows registration of logical->physical URL mapping.""" - - def registerAddress(domainURL, logicalURL, physicalURL): - """Register the physical address of a logical URL. - - @return: Deferred of C{Registration} or failure with RegistrationError. - """ - - def unregisterAddress(domainURL, logicalURL, physicalURL): - """Unregister the physical address of a logical URL. - - @return: Deferred of C{Registration} or failure with RegistrationError. - """ - - def getRegistrationInfo(logicalURL): - """Get registration info for logical URL. - - @return: Deferred of C{Registration} object or failure of LookupError. - """ - - -class ILocator(Interface): - """Allow looking up physical address for logical URL.""" - - def getAddress(logicalURL): - """Return physical URL of server for logical URL of user. - - @param logicalURL: a logical C{URL}. - @return: Deferred which becomes URL or fails with LookupError. - """ - - -class Proxy(Base): - """SIP proxy.""" - - PORT = PORT - - locator = None # object implementing ILocator - - def __init__(self, host=None, port=PORT): - """Create new instance. - - @param host: our hostname/IP as set in Via headers. - @param port: our port as set in Via headers. - """ - self.host = host or socket.getfqdn() - self.port = port - Base.__init__(self) - - def getVia(self): - """Return value of Via header for this proxy.""" - return Via(host=self.host, port=self.port) - - def handle_request(self, message, addr): - # send immediate 100/trying message before processing - #self.deliverResponse(self.responseFromRequest(100, message)) - f = getattr(self, "handle_%s_request" % message.method, None) - if f is None: - f = self.handle_request_default - try: - d = f(message, addr) - except SIPError, e: - self.deliverResponse(self.responseFromRequest(e.code, message)) - except: - log.err() - self.deliverResponse(self.responseFromRequest(500, message)) - else: - if d is not None: - d.addErrback(lambda e: - self.deliverResponse(self.responseFromRequest(e.code, message)) - ) - - def handle_request_default(self, message, (srcHost, srcPort)): - """Default request handler. - - Default behaviour for OPTIONS and unknown methods for proxies - is to forward message on to the client. - - Since at the moment we are stateless proxy, that's basically - everything. - """ - def _mungContactHeader(uri, message): - message.headers['contact'][0] = uri.toString() - return self.sendMessage(uri, message) - - viaHeader = self.getVia() - if viaHeader.toString() in message.headers["via"]: - # must be a loop, so drop message - log.msg("Dropping looped message.") - return - - message.headers["via"].insert(0, viaHeader.toString()) - name, uri, tags = parseAddress(message.headers["to"][0], clean=1) - - # this is broken and needs refactoring to use cred - d = self.locator.getAddress(uri) - d.addCallback(self.sendMessage, message) - d.addErrback(self._cantForwardRequest, message) - - def _cantForwardRequest(self, error, message): - error.trap(LookupError) - del message.headers["via"][0] # this'll be us - self.deliverResponse(self.responseFromRequest(404, message)) - - def deliverResponse(self, responseMessage): - """Deliver response. - - Destination is based on topmost Via header.""" - destVia = parseViaHeader(responseMessage.headers["via"][0]) - # XXX we don't do multicast yet - host = destVia.received or destVia.host - port = destVia.rport or destVia.port or self.PORT - - destAddr = URL(host=host, port=port) - self.sendMessage(destAddr, responseMessage) - - def responseFromRequest(self, code, request): - """Create a response to a request message.""" - response = Response(code) - for name in ("via", "to", "from", "call-id", "cseq"): - response.headers[name] = request.headers.get(name, [])[:] - return response - - def handle_response(self, message, addr): - """Default response handler.""" - v = parseViaHeader(message.headers["via"][0]) - if (v.host, v.port) != (self.host, self.port): - # we got a message not intended for us? - # XXX note this check breaks if we have multiple external IPs - # yay for suck protocols - log.msg("Dropping incorrectly addressed message") - return - del message.headers["via"][0] - if not message.headers["via"]: - # this message is addressed to us - self.gotResponse(message, addr) - return - self.deliverResponse(message) - - def gotResponse(self, message, addr): - """Called with responses that are addressed at this server.""" - pass - -class IAuthorizer(Interface): - def getChallenge(peer): - """Generate a challenge the client may respond to. - - @type peer: C{tuple} - @param peer: The client's address - - @rtype: C{str} - @return: The challenge string - """ - - def decode(response): - """Create a credentials object from the given response. - - @type response: C{str} - """ - -class BasicAuthorizer: - """Authorizer for insecure Basic (base64-encoded plaintext) authentication. - - This form of authentication is broken and insecure. Do not use it. - """ - - implements(IAuthorizer) - - def __init__(self): - """ - This method exists solely to issue a deprecation warning. - """ - warnings.warn( - "twisted.protocols.sip.BasicAuthorizer was deprecated " - "in Twisted 9.0.0", - category=DeprecationWarning, - stacklevel=2) - - - def getChallenge(self, peer): - return None - - def decode(self, response): - # At least one SIP client improperly pads its Base64 encoded messages - for i in range(3): - try: - creds = (response + ('=' * i)).decode('base64') - except: - pass - else: - break - else: - # Totally bogus - raise SIPError(400) - p = creds.split(':', 1) - if len(p) == 2: - return UsernamePassword(*p) - raise SIPError(400) - - - -class DigestedCredentials(UsernameHashedPassword): - """Yet Another Simple Digest-MD5 authentication scheme""" - - def __init__(self, username, fields, challenges): - warnings.warn( - "twisted.protocols.sip.DigestedCredentials was deprecated " - "in Twisted 9.0.0", - category=DeprecationWarning, - stacklevel=2) - self.username = username - self.fields = fields - self.challenges = challenges - - def checkPassword(self, password): - method = 'REGISTER' - response = self.fields.get('response') - uri = self.fields.get('uri') - nonce = self.fields.get('nonce') - cnonce = self.fields.get('cnonce') - nc = self.fields.get('nc') - algo = self.fields.get('algorithm', 'MD5') - qop = self.fields.get('qop-options', 'auth') - opaque = self.fields.get('opaque') - - if opaque not in self.challenges: - return False - del self.challenges[opaque] - - user, domain = self.username.split('@', 1) - if uri is None: - uri = 'sip:' + domain - - expected = DigestCalcResponse( - DigestCalcHA1(algo, user, domain, password, nonce, cnonce), - nonce, nc, cnonce, qop, method, uri, None, - ) - - return expected == response - -class DigestAuthorizer: - CHALLENGE_LIFETIME = 15 - - implements(IAuthorizer) - - def __init__(self): - warnings.warn( - "twisted.protocols.sip.DigestAuthorizer was deprecated " - "in Twisted 9.0.0", - category=DeprecationWarning, - stacklevel=2) - - self.outstanding = {} - - - - def generateNonce(self): - c = tuple([random.randrange(sys.maxint) for _ in range(3)]) - c = '%d%d%d' % c - return c - - def generateOpaque(self): - return str(random.randrange(sys.maxint)) - - def getChallenge(self, peer): - c = self.generateNonce() - o = self.generateOpaque() - self.outstanding[o] = c - return ','.join(( - 'nonce="%s"' % c, - 'opaque="%s"' % o, - 'qop-options="auth"', - 'algorithm="MD5"', - )) - - def decode(self, response): - response = ' '.join(response.splitlines()) - parts = response.split(',') - auth = dict([(k.strip(), unq(v.strip())) for (k, v) in [p.split('=', 1) for p in parts]]) - try: - username = auth['username'] - except KeyError: - raise SIPError(401) - try: - return DigestedCredentials(username, auth, self.outstanding) - except: - raise SIPError(400) - - -class RegisterProxy(Proxy): - """A proxy that allows registration for a specific domain. - - Unregistered users won't be handled. - """ - - portal = None - - registry = None # should implement IRegistry - - authorizers = {} - - def __init__(self, *args, **kw): - Proxy.__init__(self, *args, **kw) - self.liveChallenges = {} - if "digest" not in self.authorizers: - self.authorizers["digest"] = DigestAuthorizer() - - def handle_ACK_request(self, message, (host, port)): - # XXX - # ACKs are a client's way of indicating they got the last message - # Responding to them is not a good idea. - # However, we should keep track of terminal messages and re-transmit - # if no ACK is received. - pass - - def handle_REGISTER_request(self, message, (host, port)): - """Handle a registration request. - - Currently registration is not proxied. - """ - if self.portal is None: - # There is no portal. Let anyone in. - self.register(message, host, port) - else: - # There is a portal. Check for credentials. - if not message.headers.has_key("authorization"): - return self.unauthorized(message, host, port) - else: - return self.login(message, host, port) - - def unauthorized(self, message, host, port): - m = self.responseFromRequest(401, message) - for (scheme, auth) in self.authorizers.iteritems(): - chal = auth.getChallenge((host, port)) - if chal is None: - value = '%s realm="%s"' % (scheme.title(), self.host) - else: - value = '%s %s,realm="%s"' % (scheme.title(), chal, self.host) - m.headers.setdefault('www-authenticate', []).append(value) - self.deliverResponse(m) - - - def login(self, message, host, port): - parts = message.headers['authorization'][0].split(None, 1) - a = self.authorizers.get(parts[0].lower()) - if a: - try: - c = a.decode(parts[1]) - except SIPError: - raise - except: - log.err() - self.deliverResponse(self.responseFromRequest(500, message)) - else: - c.username += '@' + self.host - self.portal.login(c, None, IContact - ).addCallback(self._cbLogin, message, host, port - ).addErrback(self._ebLogin, message, host, port - ).addErrback(log.err - ) - else: - self.deliverResponse(self.responseFromRequest(501, message)) - - def _cbLogin(self, (i, a, l), message, host, port): - # It's stateless, matey. What a joke. - self.register(message, host, port) - - def _ebLogin(self, failure, message, host, port): - failure.trap(cred.error.UnauthorizedLogin) - self.unauthorized(message, host, port) - - def register(self, message, host, port): - """Allow all users to register""" - name, toURL, params = parseAddress(message.headers["to"][0], clean=1) - contact = None - if message.headers.has_key("contact"): - contact = message.headers["contact"][0] - - if message.headers.get("expires", [None])[0] == "0": - self.unregister(message, toURL, contact) - else: - # XXX Check expires on appropriate URL, and pass it to registry - # instead of having registry hardcode it. - if contact is not None: - name, contactURL, params = parseAddress(contact, host=host, port=port) - d = self.registry.registerAddress(message.uri, toURL, contactURL) - else: - d = self.registry.getRegistrationInfo(toURL) - d.addCallbacks(self._cbRegister, self._ebRegister, - callbackArgs=(message,), - errbackArgs=(message,) - ) - - def _cbRegister(self, registration, message): - response = self.responseFromRequest(200, message) - if registration.contactURL != None: - response.addHeader("contact", registration.contactURL.toString()) - response.addHeader("expires", "%d" % registration.secondsToExpiry) - response.addHeader("content-length", "0") - self.deliverResponse(response) - - def _ebRegister(self, error, message): - error.trap(RegistrationError, LookupError) - # XXX return error message, and alter tests to deal with - # this, currently tests assume no message sent on failure - - def unregister(self, message, toURL, contact): - try: - expires = int(message.headers["expires"][0]) - except ValueError: - self.deliverResponse(self.responseFromRequest(400, message)) - else: - if expires == 0: - if contact == "*": - contactURL = "*" - else: - name, contactURL, params = parseAddress(contact) - d = self.registry.unregisterAddress(message.uri, toURL, contactURL) - d.addCallback(self._cbUnregister, message - ).addErrback(self._ebUnregister, message - ) - - def _cbUnregister(self, registration, message): - msg = self.responseFromRequest(200, message) - msg.headers.setdefault('contact', []).append(registration.contactURL.toString()) - msg.addHeader("expires", "0") - self.deliverResponse(msg) - - def _ebUnregister(self, registration, message): - pass - - -class InMemoryRegistry: - """A simplistic registry for a specific domain.""" - - implements(IRegistry, ILocator) - - def __init__(self, domain): - self.domain = domain # the domain we handle registration for - self.users = {} # map username to (IDelayedCall for expiry, address URI) - - def getAddress(self, userURI): - if userURI.host != self.domain: - return defer.fail(LookupError("unknown domain")) - if userURI.username in self.users: - dc, url = self.users[userURI.username] - return defer.succeed(url) - else: - return defer.fail(LookupError("no such user")) - - def getRegistrationInfo(self, userURI): - if userURI.host != self.domain: - return defer.fail(LookupError("unknown domain")) - if self.users.has_key(userURI.username): - dc, url = self.users[userURI.username] - return defer.succeed(Registration(int(dc.getTime() - time.time()), url)) - else: - return defer.fail(LookupError("no such user")) - - def _expireRegistration(self, username): - try: - dc, url = self.users[username] - except KeyError: - return defer.fail(LookupError("no such user")) - else: - dc.cancel() - del self.users[username] - return defer.succeed(Registration(0, url)) - - def registerAddress(self, domainURL, logicalURL, physicalURL): - if domainURL.host != self.domain: - log.msg("Registration for domain we don't handle.") - return defer.fail(RegistrationError(404)) - if logicalURL.host != self.domain: - log.msg("Registration for domain we don't handle.") - return defer.fail(RegistrationError(404)) - if logicalURL.username in self.users: - dc, old = self.users[logicalURL.username] - dc.reset(3600) - else: - dc = reactor.callLater(3600, self._expireRegistration, logicalURL.username) - log.msg("Registered %s at %s" % (logicalURL.toString(), physicalURL.toString())) - self.users[logicalURL.username] = (dc, physicalURL) - return defer.succeed(Registration(int(dc.getTime() - time.time()), physicalURL)) - - def unregisterAddress(self, domainURL, logicalURL, physicalURL): - return self._expireRegistration(logicalURL.username) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/socks.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/socks.py deleted file mode 100644 index 445b9f3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/socks.py +++ /dev/null @@ -1,240 +0,0 @@ -# -*- test-case-name: twisted.test.test_socks -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Implementation of the SOCKSv4 protocol. -""" - -# python imports -import struct -import string -import socket -import time - -# twisted imports -from twisted.internet import reactor, protocol, defer -from twisted.python import log - - -class SOCKSv4Outgoing(protocol.Protocol): - - def __init__(self,socks): - self.socks=socks - - def connectionMade(self): - peer = self.transport.getPeer() - self.socks.makeReply(90, 0, port=peer.port, ip=peer.host) - self.socks.otherConn=self - - def connectionLost(self, reason): - self.socks.transport.loseConnection() - - def dataReceived(self,data): - self.socks.write(data) - - def write(self,data): - self.socks.log(self,data) - self.transport.write(data) - - - -class SOCKSv4Incoming(protocol.Protocol): - - def __init__(self,socks): - self.socks=socks - self.socks.otherConn=self - - def connectionLost(self, reason): - self.socks.transport.loseConnection() - - def dataReceived(self,data): - self.socks.write(data) - - def write(self,data): - self.socks.log(self,data) - self.transport.write(data) - - -class SOCKSv4(protocol.Protocol): - """ - An implementation of the SOCKSv4 protocol. - - @type logging: C{str} or C{None} - @ivar logging: If not C{None}, the name of the logfile to which connection - information will be written. - - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - @ivar reactor: The reactor used to create connections. - - @type buf: C{str} - @ivar buf: Part of a SOCKSv4 connection request. - - @type otherConn: C{SOCKSv4Incoming}, C{SOCKSv4Outgoing} or C{None} - @ivar otherConn: Until the connection has been established, C{otherConn} is - C{None}. After that, it is the proxy-to-destination protocol instance - along which the client's connection is being forwarded. - """ - def __init__(self, logging=None, reactor=reactor): - self.logging = logging - self.reactor = reactor - - def connectionMade(self): - self.buf = "" - self.otherConn = None - - def dataReceived(self, data): - """ - Called whenever data is received. - - @type data: C{str} - @param data: Part or all of a SOCKSv4 packet. - """ - if self.otherConn: - self.otherConn.write(data) - return - self.buf = self.buf + data - completeBuffer = self.buf - if "\000" in self.buf[8:]: - head, self.buf = self.buf[:8], self.buf[8:] - version, code, port = struct.unpack("!BBH", head[:4]) - user, self.buf = self.buf.split("\000", 1) - if head[4:7] == "\000\000\000" and head[7] != "\000": - # An IP address of the form 0.0.0.X, where X is non-zero, - # signifies that this is a SOCKSv4a packet. - # If the complete packet hasn't been received, restore the - # buffer and wait for it. - if "\000" not in self.buf: - self.buf = completeBuffer - return - server, self.buf = self.buf.split("\000", 1) - d = self.reactor.resolve(server) - d.addCallback(self._dataReceived2, user, - version, code, port) - d.addErrback(lambda result, self = self: self.makeReply(91)) - return - else: - server = socket.inet_ntoa(head[4:8]) - - self._dataReceived2(server, user, version, code, port) - - def _dataReceived2(self, server, user, version, code, port): - """ - The second half of the SOCKS connection setup. For a SOCKSv4 packet this - is after the server address has been extracted from the header. For a - SOCKSv4a packet this is after the host name has been resolved. - - @type server: C{str} - @param server: The IP address of the destination, represented as a - dotted quad. - - @type user: C{str} - @param user: The username associated with the connection. - - @type version: C{int} - @param version: The SOCKS protocol version number. - - @type code: C{int} - @param code: The comand code. 1 means establish a TCP/IP stream - connection, and 2 means establish a TCP/IP port binding. - - @type port: C{int} - @param port: The port number associated with the connection. - """ - assert version == 4, "Bad version code: %s" % version - if not self.authorize(code, server, port, user): - self.makeReply(91) - return - if code == 1: # CONNECT - d = self.connectClass(server, port, SOCKSv4Outgoing, self) - d.addErrback(lambda result, self = self: self.makeReply(91)) - elif code == 2: # BIND - d = self.listenClass(0, SOCKSv4IncomingFactory, self, server) - d.addCallback(lambda (h, p), - self = self: self.makeReply(90, 0, p, h)) - else: - raise RuntimeError, "Bad Connect Code: %s" % code - assert self.buf == "", "hmm, still stuff in buffer... %s" % repr( - self.buf) - - def connectionLost(self, reason): - if self.otherConn: - self.otherConn.transport.loseConnection() - - def authorize(self,code,server,port,user): - log.msg("code %s connection to %s:%s (user %s) authorized" % (code,server,port,user)) - return 1 - - def connectClass(self, host, port, klass, *args): - return protocol.ClientCreator(reactor, klass, *args).connectTCP(host,port) - - def listenClass(self, port, klass, *args): - serv = reactor.listenTCP(port, klass(*args)) - return defer.succeed(serv.getHost()[1:]) - - def makeReply(self,reply,version=0,port=0,ip="0.0.0.0"): - self.transport.write(struct.pack("!BBH",version,reply,port)+socket.inet_aton(ip)) - if reply!=90: self.transport.loseConnection() - - def write(self,data): - self.log(self,data) - self.transport.write(data) - - def log(self,proto,data): - if not self.logging: return - peer = self.transport.getPeer() - their_peer = self.otherConn.transport.getPeer() - f=open(self.logging,"a") - f.write("%s\t%s:%d %s %s:%d\n"%(time.ctime(), - peer.host,peer.port, - ((proto==self and '<') or '>'), - their_peer.host,their_peer.port)) - while data: - p,data=data[:16],data[16:] - f.write(string.join(map(lambda x:'%02X'%ord(x),p),' ')+' ') - f.write((16-len(p))*3*' ') - for c in p: - if len(repr(c))>3: f.write('.') - else: f.write(c) - f.write('\n') - f.write('\n') - f.close() - - - -class SOCKSv4Factory(protocol.Factory): - """ - A factory for a SOCKSv4 proxy. - - Constructor accepts one argument, a log file name. - """ - - def __init__(self, log): - self.logging = log - - def buildProtocol(self, addr): - return SOCKSv4(self.logging, reactor) - - - -class SOCKSv4IncomingFactory(protocol.Factory): - """ - A utility class for building protocols for incoming connections. - """ - - def __init__(self, socks, ip): - self.socks = socks - self.ip = ip - - - def buildProtocol(self, addr): - if addr[0] == self.ip: - self.ip = "" - self.socks.makeReply(90, 0) - return SOCKSv4Incoming(self.socks) - elif self.ip == "": - return None - else: - self.socks.makeReply(91, 0) - self.ip = "" - return None diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/stateful.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/stateful.py deleted file mode 100644 index 7b82ae3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/stateful.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- test-case-name: twisted.test.test_stateful -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.internet import protocol - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -class StatefulProtocol(protocol.Protocol): - """A Protocol that stores state for you. - - state is a pair (function, num_bytes). When num_bytes bytes of data arrives - from the network, function is called. It is expected to return the next - state or None to keep same state. Initial state is returned by - getInitialState (override it). - """ - _sful_data = None, None, 0 - - def makeConnection(self, transport): - protocol.Protocol.makeConnection(self, transport) - self._sful_data = self.getInitialState(), StringIO(), 0 - - def getInitialState(self): - raise NotImplementedError - - def dataReceived(self, data): - state, buffer, offset = self._sful_data - buffer.seek(0, 2) - buffer.write(data) - blen = buffer.tell() # how many bytes total is in the buffer - buffer.seek(offset) - while blen - offset >= state[1]: - d = buffer.read(state[1]) - offset += state[1] - next = state[0](d) - if self.transport.disconnecting: # XXX: argh stupid hack borrowed right from LineReceiver - return # dataReceived won't be called again, so who cares about consistent state - if next: - state = next - if offset != 0: - b = buffer.read() - buffer.seek(0) - buffer.truncate() - buffer.write(b) - offset = 0 - self._sful_data = state, buffer, offset - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/telnet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/telnet.py deleted file mode 100644 index ba1c826..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/telnet.py +++ /dev/null @@ -1,325 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""TELNET implementation, with line-oriented command handling. -""" - -import warnings -warnings.warn( - "As of Twisted 2.1, twisted.protocols.telnet is deprecated. " - "See twisted.conch.telnet for the current, supported API.", - DeprecationWarning, - stacklevel=2) - - -# System Imports -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -# Twisted Imports -from twisted import copyright -from twisted.internet import protocol - -# Some utility chars. -ESC = chr(27) # ESC for doing fanciness -BOLD_MODE_ON = ESC+"[1m" # turn bold on -BOLD_MODE_OFF= ESC+"[m" # no char attributes - - -# Characters gleaned from the various (and conflicting) RFCs. Not all of these are correct. - -NULL = chr(0) # No operation. -LF = chr(10) # Moves the printer to the - # next print line, keeping the - # same horizontal position. -CR = chr(13) # Moves the printer to the left - # margin of the current line. -BEL = chr(7) # Produces an audible or - # visible signal (which does - # NOT move the print head). -BS = chr(8) # Moves the print head one - # character position towards - # the left margin. -HT = chr(9) # Moves the printer to the - # next horizontal tab stop. - # It remains unspecified how - # either party determines or - # establishes where such tab - # stops are located. -VT = chr(11) # Moves the printer to the - # next vertical tab stop. It - # remains unspecified how - # either party determines or - # establishes where such tab - # stops are located. -FF = chr(12) # Moves the printer to the top - # of the next page, keeping - # the same horizontal position. -SE = chr(240) # End of subnegotiation parameters. -NOP= chr(241) # No operation. -DM = chr(242) # "Data Mark": The data stream portion - # of a Synch. This should always be - # accompanied by a TCP Urgent - # notification. -BRK= chr(243) # NVT character Break. -IP = chr(244) # The function Interrupt Process. -AO = chr(245) # The function Abort Output -AYT= chr(246) # The function Are You There. -EC = chr(247) # The function Erase Character. -EL = chr(248) # The function Erase Line -GA = chr(249) # The Go Ahead signal. -SB = chr(250) # Indicates that what follows is - # subnegotiation of the indicated - # option. -WILL = chr(251) # Indicates the desire to begin - # performing, or confirmation that - # you are now performing, the - # indicated option. -WONT = chr(252) # Indicates the refusal to perform, - # or continue performing, the - # indicated option. -DO = chr(253) # Indicates the request that the - # other party perform, or - # confirmation that you are expecting - # the other party to perform, the - # indicated option. -DONT = chr(254) # Indicates the demand that the - # other party stop performing, - # or confirmation that you are no - # longer expecting the other party - # to perform, the indicated option. -IAC = chr(255) # Data Byte 255. - -# features - -ECHO = chr(1) # User-to-Server: Asks the server to send - # Echos of the transmitted data. - - # Server-to User: States that the server is - # sending echos of the transmitted data. - # Sent only as a reply to ECHO or NO ECHO. - -SUPGA = chr(3) # Supress Go Ahead...? "Modern" telnet servers - # are supposed to do this. - -LINEMODE = chr(34) # I don't care that Jon Postel is dead. - -HIDE = chr(133) # The intention is that a server will send - # this signal to a user system which is - # echoing locally (to the user) when the user - # is about to type something secret (e.g. a - # password). In this case, the user system - # is to suppress local echoing or overprint - # the input (or something) until the server - # sends a NOECHO signal. In situations where - # the user system is not echoing locally, - # this signal must not be sent by the server. - - -NOECHO= chr(131) # User-to-Server: Asks the server not to - # return Echos of the transmitted data. - # - # Server-to-User: States that the server is - # not sending echos of the transmitted data. - # Sent only as a reply to ECHO or NO ECHO, - # or to end the hide your input. - - - -iacBytes = { - DO: 'DO', - DONT: 'DONT', - WILL: 'WILL', - WONT: 'WONT', - IP: 'IP' - } - -def multireplace(st, dct): - for k, v in dct.items(): - st = st.replace(k, v) - return st - -class Telnet(protocol.Protocol): - """I am a Protocol for handling Telnet connections. I have two - sets of special methods, telnet_* and iac_*. - - telnet_* methods get called on every line sent to me. The method - to call is decided by the current mode. The initial mode is 'User'; - this means that telnet_User is the first telnet_* method to be called. - All telnet_* methods should return a string which specifies the mode - to go into next; thus dictating which telnet_* method to call next. - For example, the default telnet_User method returns 'Password' to go - into Password mode, and the default telnet_Password method returns - 'Command' to go into Command mode. - - The iac_* methods are less-used; they are called when an IAC telnet - byte is received. You can define iac_DO, iac_DONT, iac_WILL, iac_WONT, - and iac_IP methods to do what you want when one of these bytes is - received.""" - - - gotIAC = 0 - iacByte = None - lastLine = None - buffer = '' - echo = 0 - delimiters = ['\r\n', '\r\000'] - mode = "User" - - def write(self, data): - """Send the given data over my transport.""" - self.transport.write(data) - - - def connectionMade(self): - """I will write a welcomeMessage and loginPrompt to the client.""" - self.write(self.welcomeMessage() + self.loginPrompt()) - - def welcomeMessage(self): - """Override me to return a string which will be sent to the client - before login.""" - x = self.factory.__class__ - return ("\r\n" + x.__module__ + '.' + x.__name__ + - '\r\nTwisted %s\r\n' % copyright.version - ) - - def loginPrompt(self): - """Override me to return a 'login:'-type prompt.""" - return "username: " - - def iacSBchunk(self, chunk): - pass - - def iac_DO(self, feature): - pass - - def iac_DONT(self, feature): - pass - - def iac_WILL(self, feature): - pass - - def iac_WONT(self, feature): - pass - - def iac_IP(self, feature): - pass - - def processLine(self, line): - """I call a method that looks like 'telnet_*' where '*' is filled - in by the current mode. telnet_* methods should return a string which - will become the new mode. If None is returned, the mode will not change. - """ - mode = getattr(self, "telnet_"+self.mode)(line) - if mode is not None: - self.mode = mode - - def telnet_User(self, user): - """I take a username, set it to the 'self.username' attribute, - print out a password prompt, and switch to 'Password' mode. If - you want to do something else when the username is received (ie, - create a new user if the user doesn't exist), override me.""" - self.username = user - self.write(IAC+WILL+ECHO+"password: ") - return "Password" - - def telnet_Password(self, paswd): - """I accept a password as an argument, and check it with the - checkUserAndPass method. If the login is successful, I call - loggedIn().""" - self.write(IAC+WONT+ECHO+"*****\r\n") - try: - checked = self.checkUserAndPass(self.username, paswd) - except: - return "Done" - if not checked: - return "Done" - self.loggedIn() - return "Command" - - def telnet_Command(self, cmd): - """The default 'command processing' mode. You probably want to - override me.""" - return "Command" - - def processChunk(self, chunk): - """I take a chunk of data and delegate out to telnet_* methods - by way of processLine. If the current mode is 'Done', I'll close - the connection. """ - self.buffer = self.buffer + chunk - - #yech. - for delim in self.delimiters: - idx = self.buffer.find(delim) - if idx != -1: - break - - while idx != -1: - buf, self.buffer = self.buffer[:idx], self.buffer[idx+2:] - self.processLine(buf) - if self.mode == 'Done': - self.transport.loseConnection() - - for delim in self.delimiters: - idx = self.buffer.find(delim) - if idx != -1: - break - - def dataReceived(self, data): - chunk = StringIO() - # silly little IAC state-machine - for char in data: - if self.gotIAC: - # working on an IAC request state - if self.iacByte: - # we're in SB mode, getting a chunk - if self.iacByte == SB: - if char == SE: - self.iacSBchunk(chunk.getvalue()) - chunk = StringIO() - del self.iacByte - del self.gotIAC - else: - chunk.write(char) - else: - # got all I need to know state - try: - getattr(self, 'iac_%s' % iacBytes[self.iacByte])(char) - except KeyError: - pass - del self.iacByte - del self.gotIAC - else: - # got IAC, this is my W/W/D/D (or perhaps sb) - self.iacByte = char - elif char == IAC: - # Process what I've got so far before going into - # the IAC state; don't want to process characters - # in an inconsistent state with what they were - # received in. - c = chunk.getvalue() - if c: - why = self.processChunk(c) - if why: - return why - chunk = StringIO() - self.gotIAC = 1 - else: - chunk.write(char) - # chunks are of a relatively indeterminate size. - c = chunk.getvalue() - if c: - why = self.processChunk(c) - if why: - return why - - def loggedIn(self): - """Called after the user succesfully logged in. - - Override in subclasses. - """ - pass diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/__init__.py deleted file mode 100644 index fd1e058..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Unit tests for L{twisted.protocols}. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/test_basic.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/test_basic.py deleted file mode 100644 index be9eda0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/test_basic.py +++ /dev/null @@ -1,1360 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.protocols.basic}. -""" - -from __future__ import division, absolute_import - -import sys -import struct -from io import BytesIO - -from zope.interface.verify import verifyObject - -from twisted.python.compat import _PY3, iterbytes -from twisted.trial import unittest -from twisted.protocols import basic -from twisted.python import reflect -from twisted.internet import protocol, error, task -from twisted.internet.interfaces import IProducer -from twisted.test import proto_helpers - -_PY3NEWSTYLESKIP = "All classes are new style on Python 3." - - - -class FlippingLineTester(basic.LineReceiver): - """ - A line receiver that flips between line and raw data modes after one byte. - """ - - delimiter = b'\n' - - def __init__(self): - self.lines = [] - - - def lineReceived(self, line): - """ - Set the mode to raw. - """ - self.lines.append(line) - self.setRawMode() - - - def rawDataReceived(self, data): - """ - Set the mode back to line. - """ - self.setLineMode(data[1:]) - - - -class LineTester(basic.LineReceiver): - """ - A line receiver that parses data received and make actions on some tokens. - - @type delimiter: C{bytes} - @ivar delimiter: character used between received lines. - @type MAX_LENGTH: C{int} - @ivar MAX_LENGTH: size of a line when C{lineLengthExceeded} will be called. - @type clock: L{twisted.internet.task.Clock} - @ivar clock: clock simulating reactor callLater. Pass it to constructor if - you want to use the pause/rawpause functionalities. - """ - - delimiter = b'\n' - MAX_LENGTH = 64 - - def __init__(self, clock=None): - """ - If given, use a clock to make callLater calls. - """ - self.clock = clock - - - def connectionMade(self): - """ - Create/clean data received on connection. - """ - self.received = [] - - - def lineReceived(self, line): - """ - Receive line and make some action for some tokens: pause, rawpause, - stop, len, produce, unproduce. - """ - self.received.append(line) - if line == b'': - self.setRawMode() - elif line == b'pause': - self.pauseProducing() - self.clock.callLater(0, self.resumeProducing) - elif line == b'rawpause': - self.pauseProducing() - self.setRawMode() - self.received.append(b'') - self.clock.callLater(0, self.resumeProducing) - elif line == b'stop': - self.stopProducing() - elif line[:4] == b'len ': - self.length = int(line[4:]) - elif line.startswith(b'produce'): - self.transport.registerProducer(self, False) - elif line.startswith(b'unproduce'): - self.transport.unregisterProducer() - - - def rawDataReceived(self, data): - """ - Read raw data, until the quantity specified by a previous 'len' line is - reached. - """ - data, rest = data[:self.length], data[self.length:] - self.length = self.length - len(data) - self.received[-1] = self.received[-1] + data - if self.length == 0: - self.setLineMode(rest) - - - def lineLengthExceeded(self, line): - """ - Adjust line mode when long lines received. - """ - if len(line) > self.MAX_LENGTH + 1: - self.setLineMode(line[self.MAX_LENGTH + 1:]) - - - -class LineOnlyTester(basic.LineOnlyReceiver): - """ - A buffering line only receiver. - """ - delimiter = b'\n' - MAX_LENGTH = 64 - - def connectionMade(self): - """ - Create/clean data received on connection. - """ - self.received = [] - - - def lineReceived(self, line): - """ - Save received data. - """ - self.received.append(line) - - - -class LineReceiverTests(unittest.SynchronousTestCase): - """ - Test L{twisted.protocols.basic.LineReceiver}, using the C{LineTester} - wrapper. - """ - buffer = b'''\ -len 10 - -0123456789len 5 - -1234 -len 20 -foo 123 - -0123456789 -012345678len 0 -foo 5 - -1234567890123456789012345678901234567890123456789012345678901234567890 -len 1 - -a''' - - output = [b'len 10', b'0123456789', b'len 5', b'1234\n', - b'len 20', b'foo 123', b'0123456789\n012345678', - b'len 0', b'foo 5', b'', b'67890', b'len 1', b'a'] - - def test_buffer(self): - """ - Test buffering for different packet size, checking received matches - expected data. - """ - for packet_size in range(1, 10): - t = proto_helpers.StringIOWithoutClosing() - a = LineTester() - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.buffer) // packet_size + 1): - s = self.buffer[i * packet_size:(i + 1) * packet_size] - a.dataReceived(s) - self.assertEqual(self.output, a.received) - - - pauseBuf = b'twiddle1\ntwiddle2\npause\ntwiddle3\n' - - pauseOutput1 = [b'twiddle1', b'twiddle2', b'pause'] - pauseOutput2 = pauseOutput1 + [b'twiddle3'] - - - def test_pausing(self): - """ - Test pause inside data receiving. It uses fake clock to see if - pausing/resuming work. - """ - for packet_size in range(1, 10): - t = proto_helpers.StringIOWithoutClosing() - clock = task.Clock() - a = LineTester(clock) - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.pauseBuf) // packet_size + 1): - s = self.pauseBuf[i * packet_size:(i + 1) * packet_size] - a.dataReceived(s) - self.assertEqual(self.pauseOutput1, a.received) - clock.advance(0) - self.assertEqual(self.pauseOutput2, a.received) - - rawpauseBuf = b'twiddle1\ntwiddle2\nlen 5\nrawpause\n12345twiddle3\n' - - rawpauseOutput1 = [b'twiddle1', b'twiddle2', b'len 5', b'rawpause', b''] - rawpauseOutput2 = [b'twiddle1', b'twiddle2', b'len 5', b'rawpause', - b'12345', b'twiddle3'] - - - def test_rawPausing(self): - """ - Test pause inside raw date receiving. - """ - for packet_size in range(1, 10): - t = proto_helpers.StringIOWithoutClosing() - clock = task.Clock() - a = LineTester(clock) - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.rawpauseBuf) // packet_size + 1): - s = self.rawpauseBuf[i * packet_size:(i + 1) * packet_size] - a.dataReceived(s) - self.assertEqual(self.rawpauseOutput1, a.received) - clock.advance(0) - self.assertEqual(self.rawpauseOutput2, a.received) - - stop_buf = b'twiddle1\ntwiddle2\nstop\nmore\nstuff\n' - - stop_output = [b'twiddle1', b'twiddle2', b'stop'] - - - def test_stopProducing(self): - """ - Test stop inside producing. - """ - for packet_size in range(1, 10): - t = proto_helpers.StringIOWithoutClosing() - a = LineTester() - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.stop_buf) // packet_size + 1): - s = self.stop_buf[i * packet_size:(i + 1) * packet_size] - a.dataReceived(s) - self.assertEqual(self.stop_output, a.received) - - - def test_lineReceiverAsProducer(self): - """ - Test produce/unproduce in receiving. - """ - a = LineTester() - t = proto_helpers.StringIOWithoutClosing() - a.makeConnection(protocol.FileWrapper(t)) - a.dataReceived(b'produce\nhello world\nunproduce\ngoodbye\n') - self.assertEqual( - a.received, [b'produce', b'hello world', b'unproduce', b'goodbye']) - - - def test_clearLineBuffer(self): - """ - L{LineReceiver.clearLineBuffer} removes all buffered data and returns - it as a C{bytes} and can be called from beneath C{dataReceived}. - """ - class ClearingReceiver(basic.LineReceiver): - def lineReceived(self, line): - self.line = line - self.rest = self.clearLineBuffer() - - protocol = ClearingReceiver() - protocol.dataReceived(b'foo\r\nbar\r\nbaz') - self.assertEqual(protocol.line, b'foo') - self.assertEqual(protocol.rest, b'bar\r\nbaz') - - # Deliver another line to make sure the previously buffered data is - # really gone. - protocol.dataReceived(b'quux\r\n') - self.assertEqual(protocol.line, b'quux') - self.assertEqual(protocol.rest, b'') - - - def test_stackRecursion(self): - """ - Test switching modes many times on the same data. - """ - proto = FlippingLineTester() - transport = proto_helpers.StringIOWithoutClosing() - proto.makeConnection(protocol.FileWrapper(transport)) - limit = sys.getrecursionlimit() - proto.dataReceived(b'x\nx' * limit) - self.assertEqual(b'x' * limit, b''.join(proto.lines)) - - - def test_rawDataError(self): - """ - C{LineReceiver.dataReceived} forwards errors returned by - C{rawDataReceived}. - """ - proto = basic.LineReceiver() - proto.rawDataReceived = lambda data: RuntimeError("oops") - transport = proto_helpers.StringTransport() - proto.makeConnection(transport) - proto.setRawMode() - why = proto.dataReceived(b'data') - self.assertIsInstance(why, RuntimeError) - - - def test_rawDataReceivedNotImplemented(self): - """ - When L{LineReceiver.rawDataReceived} is not overridden in a - subclass, calling it raises C{NotImplementedError}. - """ - proto = basic.LineReceiver() - self.assertRaises(NotImplementedError, proto.rawDataReceived, 'foo') - - - def test_lineReceivedNotImplemented(self): - """ - When L{LineReceiver.lineReceived} is not overridden in a subclass, - calling it raises C{NotImplementedError}. - """ - proto = basic.LineReceiver() - self.assertRaises(NotImplementedError, proto.lineReceived, 'foo') - - - -class ExcessivelyLargeLineCatcher(basic.LineReceiver): - """ - Helper for L{LineReceiverLineLengthExceededTests}. - - @ivar longLines: A L{list} of L{bytes} giving the values - C{lineLengthExceeded} has been called with. - """ - def connectionMade(self): - self.longLines = [] - - - def lineReceived(self, line): - """ - Disregard any received lines. - """ - - - def lineLengthExceeded(self, data): - """ - Record any data that exceeds the line length limits. - """ - self.longLines.append(data) - - - -class LineReceiverLineLengthExceededTests(unittest.SynchronousTestCase): - """ - Tests for L{twisted.protocols.basic.LineReceiver.lineLengthExceeded}. - """ - def setUp(self): - self.proto = ExcessivelyLargeLineCatcher() - self.proto.MAX_LENGTH = 6 - self.transport = proto_helpers.StringTransport() - self.proto.makeConnection(self.transport) - - - def test_longUnendedLine(self): - """ - If more bytes than C{LineReceiver.MAX_LENGTH} arrive containing no line - delimiter, all of the bytes are passed as a single string to - L{LineReceiver.lineLengthExceeded}. - """ - excessive = b'x' * (self.proto.MAX_LENGTH * 2 + 2) - self.proto.dataReceived(excessive) - self.assertEqual([excessive], self.proto.longLines) - - - def test_longLineAfterShortLine(self): - """ - If L{LineReceiver.dataReceived} is called with bytes representing a - short line followed by bytes that exceed the length limit without a - line delimiter, L{LineReceiver.lineLengthExceeded} is called with all - of the bytes following the short line's delimiter. - """ - excessive = b'x' * (self.proto.MAX_LENGTH * 2 + 2) - self.proto.dataReceived(b'x' + self.proto.delimiter + excessive) - self.assertEqual([excessive], self.proto.longLines) - - - def test_longLineWithDelimiter(self): - """ - If L{LineReceiver.dataReceived} is called with more than - C{LineReceiver.MAX_LENGTH} bytes containing a line delimiter somewhere - not in the first C{MAX_LENGTH} bytes, the entire byte string is passed - to L{LineReceiver.lineLengthExceeded}. - """ - excessive = self.proto.delimiter.join( - [b'x' * (self.proto.MAX_LENGTH * 2 + 2)] * 2) - self.proto.dataReceived(excessive) - self.assertEqual([excessive], self.proto.longLines) - - - def test_multipleLongLines(self): - """ - If L{LineReceiver.dataReceived} is called with more than - C{LineReceiver.MAX_LENGTH} bytes containing multiple line delimiters - somewhere not in the first C{MAX_LENGTH} bytes, the entire byte string - is passed to L{LineReceiver.lineLengthExceeded}. - """ - excessive = ( - b'x' * (self.proto.MAX_LENGTH * 2 + 2) + self.proto.delimiter) * 2 - self.proto.dataReceived(excessive) - self.assertEqual([excessive], self.proto.longLines) - - - def test_maximumLineLength(self): - """ - C{LineReceiver} disconnects the transport if it receives a line longer - than its C{MAX_LENGTH}. - """ - proto = basic.LineReceiver() - transport = proto_helpers.StringTransport() - proto.makeConnection(transport) - proto.dataReceived(b'x' * (proto.MAX_LENGTH + 1) + b'\r\nr') - self.assertTrue(transport.disconnecting) - - - def test_maximumLineLengthRemaining(self): - """ - C{LineReceiver} disconnects the transport it if receives a non-finished - line longer than its C{MAX_LENGTH}. - """ - proto = basic.LineReceiver() - transport = proto_helpers.StringTransport() - proto.makeConnection(transport) - proto.dataReceived(b'x' * (proto.MAX_LENGTH + 1)) - self.assertTrue(transport.disconnecting) - - - -class LineOnlyReceiverTests(unittest.SynchronousTestCase): - """ - Tests for L{twisted.protocols.basic.LineOnlyReceiver}. - """ - - buffer = b"""foo - bleakness - desolation - plastic forks - """ - - def test_buffer(self): - """ - Test buffering over line protocol: data received should match buffer. - """ - t = proto_helpers.StringTransport() - a = LineOnlyTester() - a.makeConnection(t) - for c in iterbytes(self.buffer): - a.dataReceived(c) - self.assertEqual(a.received, self.buffer.split(b'\n')[:-1]) - - - def test_lineTooLong(self): - """ - Test sending a line too long: it should close the connection. - """ - t = proto_helpers.StringTransport() - a = LineOnlyTester() - a.makeConnection(t) - res = a.dataReceived(b'x' * 200) - self.assertIsInstance(res, error.ConnectionLost) - - - def test_lineReceivedNotImplemented(self): - """ - When L{LineOnlyReceiver.lineReceived} is not overridden in a subclass, - calling it raises C{NotImplementedError}. - """ - proto = basic.LineOnlyReceiver() - self.assertRaises(NotImplementedError, proto.lineReceived, 'foo') - - - -class TestMixin: - - def connectionMade(self): - self.received = [] - - - def stringReceived(self, s): - self.received.append(s) - - MAX_LENGTH = 50 - closed = 0 - - - def connectionLost(self, reason): - self.closed = 1 - - - -class TestNetstring(TestMixin, basic.NetstringReceiver): - - def stringReceived(self, s): - self.received.append(s) - self.transport.write(s) - - - -class LPTestCaseMixin: - - illegalStrings = [] - protocol = None - - - def getProtocol(self): - """ - Return a new instance of C{self.protocol} connected to a new instance - of L{proto_helpers.StringTransport}. - """ - t = proto_helpers.StringTransport() - a = self.protocol() - a.makeConnection(t) - return a - - - def test_illegal(self): - """ - Assert that illegal strings cause the transport to be closed. - """ - for s in self.illegalStrings: - r = self.getProtocol() - for c in iterbytes(s): - r.dataReceived(c) - self.assertTrue(r.transport.disconnecting) - - - -class NetstringReceiverTests(unittest.SynchronousTestCase, LPTestCaseMixin): - """ - Tests for L{twisted.protocols.basic.NetstringReceiver}. - """ - strings = [b'hello', b'world', b'how', b'are', b'you123', b':today', - b"a" * 515] - - illegalStrings = [ - b'9999999999999999999999', b'abc', b'4:abcde', - b'51:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab,',] - - protocol = TestNetstring - - def setUp(self): - self.transport = proto_helpers.StringTransport() - self.netstringReceiver = TestNetstring() - self.netstringReceiver.makeConnection(self.transport) - - - def test_buffer(self): - """ - Strings can be received in chunks of different lengths. - """ - for packet_size in range(1, 10): - t = proto_helpers.StringTransport() - a = TestNetstring() - a.MAX_LENGTH = 699 - a.makeConnection(t) - for s in self.strings: - a.sendString(s) - out = t.value() - for i in range(len(out) // packet_size + 1): - s = out[i * packet_size:(i + 1) * packet_size] - if s: - a.dataReceived(s) - self.assertEqual(a.received, self.strings) - - - def test_receiveEmptyNetstring(self): - """ - Empty netstrings (with length '0') can be received. - """ - self.netstringReceiver.dataReceived(b"0:,") - self.assertEqual(self.netstringReceiver.received, [b""]) - - - def test_receiveOneCharacter(self): - """ - One-character netstrings can be received. - """ - self.netstringReceiver.dataReceived(b"1:a,") - self.assertEqual(self.netstringReceiver.received, [b"a"]) - - - def test_receiveTwoCharacters(self): - """ - Two-character netstrings can be received. - """ - self.netstringReceiver.dataReceived(b"2:ab,") - self.assertEqual(self.netstringReceiver.received, [b"ab"]) - - - def test_receiveNestedNetstring(self): - """ - Netstrings with embedded netstrings. This test makes sure that - the parser does not become confused about the ',' and ':' - characters appearing inside the data portion of the netstring. - """ - self.netstringReceiver.dataReceived(b"4:1:a,,") - self.assertEqual(self.netstringReceiver.received, [b"1:a,"]) - - - def test_moreDataThanSpecified(self): - """ - Netstrings containing more data than expected are refused. - """ - self.netstringReceiver.dataReceived(b"2:aaa,") - self.assertTrue(self.transport.disconnecting) - - - def test_moreDataThanSpecifiedBorderCase(self): - """ - Netstrings that should be empty according to their length - specification are refused if they contain data. - """ - self.netstringReceiver.dataReceived(b"0:a,") - self.assertTrue(self.transport.disconnecting) - - - def test_missingNumber(self): - """ - Netstrings without leading digits that specify the length - are refused. - """ - self.netstringReceiver.dataReceived(b":aaa,") - self.assertTrue(self.transport.disconnecting) - - - def test_missingColon(self): - """ - Netstrings without a colon between length specification and - data are refused. - """ - self.netstringReceiver.dataReceived(b"3aaa,") - self.assertTrue(self.transport.disconnecting) - - - def test_missingNumberAndColon(self): - """ - Netstrings that have no leading digits nor a colon are - refused. - """ - self.netstringReceiver.dataReceived(b"aaa,") - self.assertTrue(self.transport.disconnecting) - - - def test_onlyData(self): - """ - Netstrings consisting only of data are refused. - """ - self.netstringReceiver.dataReceived(b"aaa") - self.assertTrue(self.transport.disconnecting) - - - def test_receiveNetstringPortions_1(self): - """ - Netstrings can be received in two portions. - """ - self.netstringReceiver.dataReceived(b"4:aa") - self.netstringReceiver.dataReceived(b"aa,") - self.assertEqual(self.netstringReceiver.received, [b"aaaa"]) - self.assertTrue(self.netstringReceiver._payloadComplete()) - - - def test_receiveNetstringPortions_2(self): - """ - Netstrings can be received in more than two portions, even if - the length specification is split across two portions. - """ - for part in [b"1", b"0:01234", b"56789", b","]: - self.netstringReceiver.dataReceived(part) - self.assertEqual(self.netstringReceiver.received, [b"0123456789"]) - - - def test_receiveNetstringPortions_3(self): - """ - Netstrings can be received one character at a time. - """ - for part in [b"2", b":", b"a", b"b", b","]: - self.netstringReceiver.dataReceived(part) - self.assertEqual(self.netstringReceiver.received, [b"ab"]) - - - def test_receiveTwoNetstrings(self): - """ - A stream of two netstrings can be received in two portions, - where the first portion contains the complete first netstring - and the length specification of the second netstring. - """ - self.netstringReceiver.dataReceived(b"1:a,1") - self.assertTrue(self.netstringReceiver._payloadComplete()) - self.assertEqual(self.netstringReceiver.received, [b"a"]) - self.netstringReceiver.dataReceived(b":b,") - self.assertEqual(self.netstringReceiver.received, [b"a", b"b"]) - - - def test_maxReceiveLimit(self): - """ - Netstrings with a length specification exceeding the specified - C{MAX_LENGTH} are refused. - """ - tooLong = self.netstringReceiver.MAX_LENGTH + 1 - self.netstringReceiver.dataReceived(b"".join( - (bytes(tooLong), b":", b"a" * tooLong))) - self.assertTrue(self.transport.disconnecting) - - - def test_consumeLength(self): - """ - C{_consumeLength} returns the expected length of the - netstring, including the trailing comma. - """ - self.netstringReceiver._remainingData = b"12:" - self.netstringReceiver._consumeLength() - self.assertEqual(self.netstringReceiver._expectedPayloadSize, 13) - - - def test_consumeLengthBorderCase1(self): - """ - C{_consumeLength} works as expected if the length specification - contains the value of C{MAX_LENGTH} (border case). - """ - self.netstringReceiver._remainingData = b"12:" - self.netstringReceiver.MAX_LENGTH = 12 - self.netstringReceiver._consumeLength() - self.assertEqual(self.netstringReceiver._expectedPayloadSize, 13) - - - def test_consumeLengthBorderCase2(self): - """ - C{_consumeLength} raises a L{basic.NetstringParseError} if - the length specification exceeds the value of C{MAX_LENGTH} - by 1 (border case). - """ - self.netstringReceiver._remainingData = b"12:" - self.netstringReceiver.MAX_LENGTH = 11 - self.assertRaises(basic.NetstringParseError, - self.netstringReceiver._consumeLength) - - - def test_consumeLengthBorderCase3(self): - """ - C{_consumeLength} raises a L{basic.NetstringParseError} if - the length specification exceeds the value of C{MAX_LENGTH} - by more than 1. - """ - self.netstringReceiver._remainingData = b"1000:" - self.netstringReceiver.MAX_LENGTH = 11 - self.assertRaises(basic.NetstringParseError, - self.netstringReceiver._consumeLength) - - - def test_stringReceivedNotImplemented(self): - """ - When L{NetstringReceiver.stringReceived} is not overridden in a - subclass, calling it raises C{NotImplementedError}. - """ - proto = basic.NetstringReceiver() - self.assertRaises(NotImplementedError, proto.stringReceived, 'foo') - - - -class IntNTestCaseMixin(LPTestCaseMixin): - """ - TestCase mixin for int-prefixed protocols. - """ - - protocol = None - strings = None - illegalStrings = None - partialStrings = None - - def test_receive(self): - """ - Test receiving data find the same data send. - """ - r = self.getProtocol() - for s in self.strings: - for c in iterbytes(struct.pack(r.structFormat,len(s)) + s): - r.dataReceived(c) - self.assertEqual(r.received, self.strings) - - - def test_partial(self): - """ - Send partial data, nothing should be definitely received. - """ - for s in self.partialStrings: - r = self.getProtocol() - for c in iterbytes(s): - r.dataReceived(c) - self.assertEqual(r.received, []) - - - def test_send(self): - """ - Test sending data over protocol. - """ - r = self.getProtocol() - r.sendString(b"b" * 16) - self.assertEqual(r.transport.value(), - struct.pack(r.structFormat, 16) + b"b" * 16) - - - def test_lengthLimitExceeded(self): - """ - When a length prefix is received which is greater than the protocol's - C{MAX_LENGTH} attribute, the C{lengthLimitExceeded} method is called - with the received length prefix. - """ - length = [] - r = self.getProtocol() - r.lengthLimitExceeded = length.append - r.MAX_LENGTH = 10 - r.dataReceived(struct.pack(r.structFormat, 11)) - self.assertEqual(length, [11]) - - - def test_longStringNotDelivered(self): - """ - If a length prefix for a string longer than C{MAX_LENGTH} is delivered - to C{dataReceived} at the same time as the entire string, the string is - not passed to C{stringReceived}. - """ - r = self.getProtocol() - r.MAX_LENGTH = 10 - r.dataReceived( - struct.pack(r.structFormat, 11) + b'x' * 11) - self.assertEqual(r.received, []) - - - def test_stringReceivedNotImplemented(self): - """ - When L{IntNStringReceiver.stringReceived} is not overridden in a - subclass, calling it raises C{NotImplementedError}. - """ - proto = basic.IntNStringReceiver() - self.assertRaises(NotImplementedError, proto.stringReceived, 'foo') - - - -class RecvdAttributeMixin(object): - """ - Mixin defining tests for string receiving protocols with a C{recvd} - attribute which should be settable by application code, to be combined with - L{IntNTestCaseMixin} on a L{TestCase} subclass - """ - - def makeMessage(self, protocol, data): - """ - Return C{data} prefixed with message length in C{protocol.structFormat} - form. - """ - return struct.pack(protocol.structFormat, len(data)) + data - - - def test_recvdContainsRemainingData(self): - """ - In stringReceived, recvd contains the remaining data that was passed to - dataReceived that was not part of the current message. - """ - result = [] - r = self.getProtocol() - def stringReceived(receivedString): - result.append(r.recvd) - r.stringReceived = stringReceived - completeMessage = (struct.pack(r.structFormat, 5) + (b'a' * 5)) - incompleteMessage = (struct.pack(r.structFormat, 5) + (b'b' * 4)) - # Receive a complete message, followed by an incomplete one - r.dataReceived(completeMessage + incompleteMessage) - self.assertEquals(result, [incompleteMessage]) - - - def test_recvdChanged(self): - """ - In stringReceived, if recvd is changed, messages should be parsed from - it rather than the input to dataReceived. - """ - r = self.getProtocol() - result = [] - payloadC = b'c' * 5 - messageC = self.makeMessage(r, payloadC) - def stringReceived(receivedString): - if not result: - r.recvd = messageC - result.append(receivedString) - r.stringReceived = stringReceived - payloadA = b'a' * 5 - payloadB = b'b' * 5 - messageA = self.makeMessage(r, payloadA) - messageB = self.makeMessage(r, payloadB) - r.dataReceived(messageA + messageB) - self.assertEquals(result, [payloadA, payloadC]) - - - def test_switching(self): - """ - Data already parsed by L{IntNStringReceiver.dataReceived} is not - reparsed if C{stringReceived} consumes some of the - L{IntNStringReceiver.recvd} buffer. - """ - proto = self.getProtocol() - mix = [] - SWITCH = b"\x00\x00\x00\x00" - for s in self.strings: - mix.append(self.makeMessage(proto, s)) - mix.append(SWITCH) - - result = [] - def stringReceived(receivedString): - result.append(receivedString) - proto.recvd = proto.recvd[len(SWITCH):] - - proto.stringReceived = stringReceived - proto.dataReceived(b"".join(mix)) - # Just another byte, to trigger processing of anything that might have - # been left in the buffer (should be nothing). - proto.dataReceived(b"\x01") - self.assertEqual(result, self.strings) - # And verify that another way - self.assertEqual(proto.recvd, b"\x01") - - - def test_recvdInLengthLimitExceeded(self): - """ - The L{IntNStringReceiver.recvd} buffer contains all data not yet - processed by L{IntNStringReceiver.dataReceived} if the - C{lengthLimitExceeded} event occurs. - """ - proto = self.getProtocol() - DATA = b"too long" - proto.MAX_LENGTH = len(DATA) - 1 - message = self.makeMessage(proto, DATA) - - result = [] - def lengthLimitExceeded(length): - result.append(length) - result.append(proto.recvd) - - proto.lengthLimitExceeded = lengthLimitExceeded - proto.dataReceived(message) - self.assertEqual(result[0], len(DATA)) - self.assertEqual(result[1], message) - - - -class TestInt32(TestMixin, basic.Int32StringReceiver): - """ - A L{basic.Int32StringReceiver} storing received strings in an array. - - @ivar received: array holding received strings. - """ - - - -class Int32Tests(unittest.SynchronousTestCase, IntNTestCaseMixin, - RecvdAttributeMixin): - """ - Test case for int32-prefixed protocol - """ - protocol = TestInt32 - strings = [b"a", b"b" * 16] - illegalStrings = [b"\x10\x00\x00\x00aaaaaa"] - partialStrings = [b"\x00\x00\x00", b"hello there", b""] - - def test_data(self): - """ - Test specific behavior of the 32-bits length. - """ - r = self.getProtocol() - r.sendString(b"foo") - self.assertEqual(r.transport.value(), b"\x00\x00\x00\x03foo") - r.dataReceived(b"\x00\x00\x00\x04ubar") - self.assertEqual(r.received, [b"ubar"]) - - - -class TestInt16(TestMixin, basic.Int16StringReceiver): - """ - A L{basic.Int16StringReceiver} storing received strings in an array. - - @ivar received: array holding received strings. - """ - - - -class Int16Tests(unittest.SynchronousTestCase, IntNTestCaseMixin, - RecvdAttributeMixin): - """ - Test case for int16-prefixed protocol - """ - protocol = TestInt16 - strings = [b"a", b"b" * 16] - illegalStrings = [b"\x10\x00aaaaaa"] - partialStrings = [b"\x00", b"hello there", b""] - - def test_data(self): - """ - Test specific behavior of the 16-bits length. - """ - r = self.getProtocol() - r.sendString(b"foo") - self.assertEqual(r.transport.value(), b"\x00\x03foo") - r.dataReceived(b"\x00\x04ubar") - self.assertEqual(r.received, [b"ubar"]) - - - def test_tooLongSend(self): - """ - Send too much data: that should cause an error. - """ - r = self.getProtocol() - tooSend = b"b" * (2**(r.prefixLength * 8) + 1) - self.assertRaises(AssertionError, r.sendString, tooSend) - - - -class NewStyleTestInt16(TestInt16, object): - """ - A new-style class version of TestInt16 - """ - - - -class NewStyleInt16Tests(Int16Tests): - """ - This test case verifies that IntNStringReceiver still works when inherited - by a new-style class. - """ - if _PY3: - skip = _PY3NEWSTYLESKIP - - protocol = NewStyleTestInt16 - - - -class TestInt8(TestMixin, basic.Int8StringReceiver): - """ - A L{basic.Int8StringReceiver} storing received strings in an array. - - @ivar received: array holding received strings. - """ - - - -class Int8Tests(unittest.SynchronousTestCase, IntNTestCaseMixin, - RecvdAttributeMixin): - """ - Test case for int8-prefixed protocol - """ - protocol = TestInt8 - strings = [b"a", b"b" * 16] - illegalStrings = [b"\x00\x00aaaaaa"] - partialStrings = [b"\x08", b"dzadz", b""] - - - def test_data(self): - """ - Test specific behavior of the 8-bits length. - """ - r = self.getProtocol() - r.sendString(b"foo") - self.assertEqual(r.transport.value(), b"\x03foo") - r.dataReceived(b"\x04ubar") - self.assertEqual(r.received, [b"ubar"]) - - - def test_tooLongSend(self): - """ - Send too much data: that should cause an error. - """ - r = self.getProtocol() - tooSend = b"b" * (2**(r.prefixLength * 8) + 1) - self.assertRaises(AssertionError, r.sendString, tooSend) - - - -class OnlyProducerTransport(object): - """ - Transport which isn't really a transport, just looks like one to - someone not looking very hard. - """ - - paused = False - disconnecting = False - - def __init__(self): - self.data = [] - - - def pauseProducing(self): - self.paused = True - - - def resumeProducing(self): - self.paused = False - - - def write(self, bytes): - self.data.append(bytes) - - - -class ConsumingProtocol(basic.LineReceiver): - """ - Protocol that really, really doesn't want any more bytes. - """ - - def lineReceived(self, line): - self.transport.write(line) - self.pauseProducing() - - - -class ProducerTests(unittest.SynchronousTestCase): - """ - Tests for L{basic._PausableMixin} and L{basic.LineReceiver.paused}. - """ - - def test_pauseResume(self): - """ - When L{basic.LineReceiver} is paused, it doesn't deliver lines to - L{basic.LineReceiver.lineReceived} and delivers them immediately upon - being resumed. - - L{ConsumingProtocol} is a L{LineReceiver} that pauses itself after - every line, and writes that line to its transport. - """ - p = ConsumingProtocol() - t = OnlyProducerTransport() - p.makeConnection(t) - - # Deliver a partial line. - # This doesn't trigger a pause and doesn't deliver a line. - p.dataReceived(b'hello, ') - self.assertEqual(t.data, []) - self.assertFalse(t.paused) - self.assertFalse(p.paused) - - # Deliver the rest of the line. - # This triggers the pause, and the line is echoed. - p.dataReceived(b'world\r\n') - self.assertEqual(t.data, [b'hello, world']) - self.assertTrue(t.paused) - self.assertTrue(p.paused) - - # Unpausing doesn't deliver more data, and the protocol is unpaused. - p.resumeProducing() - self.assertEqual(t.data, [b'hello, world']) - self.assertFalse(t.paused) - self.assertFalse(p.paused) - - # Deliver two lines at once. - # The protocol is paused after receiving and echoing the first line. - p.dataReceived(b'hello\r\nworld\r\n') - self.assertEqual(t.data, [b'hello, world', b'hello']) - self.assertTrue(t.paused) - self.assertTrue(p.paused) - - # Unpausing delivers the waiting line, and causes the protocol to - # pause agin. - p.resumeProducing() - self.assertEqual(t.data, [b'hello, world', b'hello', b'world']) - self.assertTrue(t.paused) - self.assertTrue(p.paused) - - # Deliver a line while paused. - # This doesn't have a visible effect. - p.dataReceived(b'goodbye\r\n') - self.assertEqual(t.data, [b'hello, world', b'hello', b'world']) - self.assertTrue(t.paused) - self.assertTrue(p.paused) - - # Unpausing delivers the waiting line, and causes the protocol to - # pause agin. - p.resumeProducing() - self.assertEqual( - t.data, [b'hello, world', b'hello', b'world', b'goodbye']) - self.assertTrue(t.paused) - self.assertTrue(p.paused) - - # Unpausing doesn't deliver more data, and the protocol is unpaused. - p.resumeProducing() - self.assertEqual( - t.data, [b'hello, world', b'hello', b'world', b'goodbye']) - self.assertFalse(t.paused) - self.assertFalse(p.paused) - - - -class FileSenderTests(unittest.TestCase): - """ - Tests for L{basic.FileSender}. - """ - - def test_interface(self): - """ - L{basic.FileSender} implements the L{IPullProducer} interface. - """ - sender = basic.FileSender() - self.assertTrue(verifyObject(IProducer, sender)) - - - def test_producerRegistered(self): - """ - When L{basic.FileSender.beginFileTransfer} is called, it registers - itself with provided consumer, as a non-streaming producer. - """ - source = BytesIO(b"Test content") - consumer = proto_helpers.StringTransport() - sender = basic.FileSender() - sender.beginFileTransfer(source, consumer) - self.assertEqual(consumer.producer, sender) - self.assertFalse(consumer.streaming) - - - def test_transfer(self): - """ - L{basic.FileSender} sends the content of the given file using a - C{IConsumer} interface via C{beginFileTransfer}. It returns a - L{Deferred} which fires with the last byte sent. - """ - source = BytesIO(b"Test content") - consumer = proto_helpers.StringTransport() - sender = basic.FileSender() - d = sender.beginFileTransfer(source, consumer) - sender.resumeProducing() - # resumeProducing only finishes after trying to read at eof - sender.resumeProducing() - self.assertEqual(consumer.producer, None) - - self.assertEqual(b"t", self.successResultOf(d)) - self.assertEqual(b"Test content", consumer.value()) - - - def test_transferMultipleChunks(self): - """ - L{basic.FileSender} reads at most C{CHUNK_SIZE} every time it resumes - producing. - """ - source = BytesIO(b"Test content") - consumer = proto_helpers.StringTransport() - sender = basic.FileSender() - sender.CHUNK_SIZE = 4 - d = sender.beginFileTransfer(source, consumer) - # Ideally we would assertNoResult(d) here, but - sender.resumeProducing() - self.assertEqual(b"Test", consumer.value()) - sender.resumeProducing() - self.assertEqual(b"Test con", consumer.value()) - sender.resumeProducing() - self.assertEqual(b"Test content", consumer.value()) - # resumeProducing only finishes after trying to read at eof - sender.resumeProducing() - - self.assertEqual(b"t", self.successResultOf(d)) - self.assertEqual(b"Test content", consumer.value()) - - - def test_transferWithTransform(self): - """ - L{basic.FileSender.beginFileTransfer} takes a C{transform} argument - which allows to manipulate the data on the fly. - """ - - def transform(chunk): - return chunk.swapcase() - - source = BytesIO(b"Test content") - consumer = proto_helpers.StringTransport() - sender = basic.FileSender() - d = sender.beginFileTransfer(source, consumer, transform) - sender.resumeProducing() - # resumeProducing only finishes after trying to read at eof - sender.resumeProducing() - - self.assertEqual(b"T", self.successResultOf(d)) - self.assertEqual(b"tEST CONTENT", consumer.value()) - - - def test_abortedTransfer(self): - """ - The C{Deferred} returned by L{basic.FileSender.beginFileTransfer} fails - with an C{Exception} if C{stopProducing} when the transfer is not - complete. - """ - source = BytesIO(b"Test content") - consumer = proto_helpers.StringTransport() - sender = basic.FileSender() - d = sender.beginFileTransfer(source, consumer) - # Abort the transfer right away - sender.stopProducing() - - failure = self.failureResultOf(d) - failure.trap(Exception) - self.assertEqual("Consumer asked us to stop producing", - str(failure.value)) - - - -class GPSDeprecationTests(unittest.TestCase): - """ - Contains tests to make sure twisted.protocols.gps is marked as deprecated. - """ - if _PY3: - skip = "twisted.protocols.gps is not being ported to Python 3." - - - def test_GPSDeprecation(self): - """ - L{twisted.protocols.gps} is deprecated since Twisted 15.2. - """ - reflect.namedAny("twisted.protocols.gps") - warningsShown = self.flushWarnings() - self.assertEqual(1, len(warningsShown)) - self.assertEqual( - "twisted.protocols.gps was deprecated in Twisted 15.2.0: " - "Use twisted.positioning instead.", warningsShown[0]['message']) - - - def test_RockwellDeprecation(self): - """ - L{twisted.protocols.gps.rockwell} is deprecated since Twisted 15.2. - """ - reflect.namedAny("twisted.protocols.gps.rockwell") - warningsShown = self.flushWarnings() - self.assertEqual(1, len(warningsShown)) - self.assertEqual( - "twisted.protocols.gps was deprecated in Twisted 15.2.0: " - "Use twisted.positioning instead.", warningsShown[0]['message']) - - - def test_NMEADeprecation(self): - """ - L{twisted.protocols.gps.nmea} is deprecated since Twisted 15.2. - """ - reflect.namedAny("twisted.protocols.gps.nmea") - warningsShown = self.flushWarnings() - self.assertEqual(1, len(warningsShown)) - self.assertEqual( - "twisted.protocols.gps was deprecated in Twisted 15.2.0: " - "Use twisted.positioning instead.", warningsShown[0]['message']) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/test_tls.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/test_tls.py deleted file mode 100644 index d284f6e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/test/test_tls.py +++ /dev/null @@ -1,1523 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.protocols.tls}. -""" - -from __future__ import division, absolute_import - -from zope.interface.verify import verifyObject -from zope.interface import Interface, directlyProvides - -from twisted.python.compat import intToBytes, iterbytes -try: - from twisted.protocols.tls import TLSMemoryBIOProtocol, TLSMemoryBIOFactory - from twisted.protocols.tls import _PullToPush, _ProducerMembrane -except ImportError: - # Skip the whole test module if it can't be imported. - skip = "pyOpenSSL 0.10 or newer required for twisted.protocol.tls" -else: - # Otherwise, the pyOpenSSL dependency must be satisfied, so all these - # imports will work. - from OpenSSL.crypto import X509Type - from OpenSSL.SSL import (TLSv1_METHOD, Error, Context, ConnectionType, - WantReadError) - from twisted.internet.ssl import PrivateCertificate - from twisted.test.ssl_helpers import (ClientTLSContext, ServerTLSContext, - certPath) - -from twisted.python.filepath import FilePath -from twisted.python.failure import Failure -from twisted.python import log -from twisted.internet.interfaces import ISystemHandle, ISSLTransport -from twisted.internet.interfaces import IPushProducer -from twisted.internet.error import ConnectionDone, ConnectionLost -from twisted.internet.defer import Deferred, gatherResults -from twisted.internet.protocol import Protocol, ClientFactory, ServerFactory -from twisted.internet.task import TaskStopped -from twisted.protocols.loopback import loopbackAsync, collapsingPumpPolicy -from twisted.trial.unittest import TestCase -from twisted.test.test_tcp import ConnectionLostNotifyingProtocol -from twisted.test.proto_helpers import StringTransport - - -class HandshakeCallbackContextFactory: - """ - L{HandshakeCallbackContextFactory} is a factory for SSL contexts which - allows applications to get notification when the SSL handshake completes. - - @ivar _finished: A L{Deferred} which will be called back when the handshake - is done. - """ - # pyOpenSSL needs to expose this. - # https://bugs.launchpad.net/pyopenssl/+bug/372832 - SSL_CB_HANDSHAKE_DONE = 0x20 - - def __init__(self): - self._finished = Deferred() - - - def factoryAndDeferred(cls): - """ - Create a new L{HandshakeCallbackContextFactory} and return a two-tuple - of it and a L{Deferred} which will fire when a connection created with - it completes a TLS handshake. - """ - contextFactory = cls() - return contextFactory, contextFactory._finished - factoryAndDeferred = classmethod(factoryAndDeferred) - - - def _info(self, connection, where, ret): - """ - This is the "info callback" on the context. It will be called - periodically by pyOpenSSL with information about the state of a - connection. When it indicates the handshake is complete, it will fire - C{self._finished}. - """ - if where & self.SSL_CB_HANDSHAKE_DONE: - self._finished.callback(None) - - - def getContext(self): - """ - Create and return an SSL context configured to use L{self._info} as the - info callback. - """ - context = Context(TLSv1_METHOD) - context.set_info_callback(self._info) - return context - - - -class AccumulatingProtocol(Protocol): - """ - A protocol which collects the bytes it receives and closes its connection - after receiving a certain minimum of data. - - @ivar howMany: The number of bytes of data to wait for before closing the - connection. - - @ivar receiving: A C{list} of C{str} of the bytes received so far. - """ - def __init__(self, howMany): - self.howMany = howMany - - - def connectionMade(self): - self.received = [] - - - def dataReceived(self, bytes): - self.received.append(bytes) - if sum(map(len, self.received)) >= self.howMany: - self.transport.loseConnection() - - - def connectionLost(self, reason): - if not reason.check(ConnectionDone): - log.err(reason) - - - -def buildTLSProtocol(server=False, transport=None): - """ - Create a protocol hooked up to a TLS transport hooked up to a - StringTransport. - """ - # We want to accumulate bytes without disconnecting, so set high limit: - clientProtocol = AccumulatingProtocol(999999999999) - clientFactory = ClientFactory() - clientFactory.protocol = lambda: clientProtocol - - if server: - contextFactory = ServerTLSContext() - else: - contextFactory = ClientTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - contextFactory, not server, clientFactory) - sslProtocol = wrapperFactory.buildProtocol(None) - - if transport is None: - transport = StringTransport() - sslProtocol.makeConnection(transport) - return clientProtocol, sslProtocol - - - -class TLSMemoryBIOFactoryTests(TestCase): - """ - Ensure TLSMemoryBIOFactory logging acts correctly. - """ - - def test_quiet(self): - """ - L{TLSMemoryBIOFactory.doStart} and L{TLSMemoryBIOFactory.doStop} do - not log any messages. - """ - contextFactory = ServerTLSContext() - - logs = [] - logger = logs.append - log.addObserver(logger) - self.addCleanup(log.removeObserver, logger) - wrappedFactory = ServerFactory() - # Disable logging on the wrapped factory: - wrappedFactory.doStart = lambda: None - wrappedFactory.doStop = lambda: None - factory = TLSMemoryBIOFactory(contextFactory, False, wrappedFactory) - factory.doStart() - factory.doStop() - self.assertEqual(logs, []) - - - def test_logPrefix(self): - """ - L{TLSMemoryBIOFactory.logPrefix} amends the wrapped factory's log prefix - with a short string (C{"TLS"}) indicating the wrapping, rather than its - full class name. - """ - contextFactory = ServerTLSContext() - factory = TLSMemoryBIOFactory(contextFactory, False, ServerFactory()) - self.assertEqual("ServerFactory (TLS)", factory.logPrefix()) - - - def test_logPrefixFallback(self): - """ - If the wrapped factory does not provide L{ILoggingContext}, - L{TLSMemoryBIOFactory.logPrefix} uses the wrapped factory's class name. - """ - class NoFactory(object): - pass - - contextFactory = ServerTLSContext() - factory = TLSMemoryBIOFactory(contextFactory, False, NoFactory()) - self.assertEqual("NoFactory (TLS)", factory.logPrefix()) - - - -class TLSMemoryBIOTests(TestCase): - """ - Tests for the implementation of L{ISSLTransport} which runs over another - L{ITransport}. - """ - - def test_interfaces(self): - """ - L{TLSMemoryBIOProtocol} instances provide L{ISSLTransport} and - L{ISystemHandle}. - """ - proto = TLSMemoryBIOProtocol(None, None) - self.assertTrue(ISSLTransport.providedBy(proto)) - self.assertTrue(ISystemHandle.providedBy(proto)) - - - def test_wrappedProtocolInterfaces(self): - """ - L{TLSMemoryBIOProtocol} instances provide the interfaces provided by - the transport they wrap. - """ - class ITransport(Interface): - pass - - class MyTransport(object): - def write(self, bytes): - pass - - clientFactory = ClientFactory() - contextFactory = ClientTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - contextFactory, True, clientFactory) - - transport = MyTransport() - directlyProvides(transport, ITransport) - tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, Protocol()) - tlsProtocol.makeConnection(transport) - self.assertTrue(ITransport.providedBy(tlsProtocol)) - - - def test_getHandle(self): - """ - L{TLSMemoryBIOProtocol.getHandle} returns the L{OpenSSL.SSL.Connection} - instance it uses to actually implement TLS. - - This may seem odd. In fact, it is. The L{OpenSSL.SSL.Connection} is - not actually the "system handle" here, nor even an object the reactor - knows about directly. However, L{twisted.internet.ssl.Certificate}'s - C{peerFromTransport} and C{hostFromTransport} methods depend on being - able to get an L{OpenSSL.SSL.Connection} object in order to work - properly. Implementing L{ISystemHandle.getHandle} like this is the - easiest way for those APIs to be made to work. If they are changed, - then it may make sense to get rid of this implementation of - L{ISystemHandle} and return the underlying socket instead. - """ - factory = ClientFactory() - contextFactory = ClientTLSContext() - wrapperFactory = TLSMemoryBIOFactory(contextFactory, True, factory) - proto = TLSMemoryBIOProtocol(wrapperFactory, Protocol()) - transport = StringTransport() - proto.makeConnection(transport) - self.assertIsInstance(proto.getHandle(), ConnectionType) - - - def test_makeConnection(self): - """ - When L{TLSMemoryBIOProtocol} is connected to a transport, it connects - the protocol it wraps to a transport. - """ - clientProtocol = Protocol() - clientFactory = ClientFactory() - clientFactory.protocol = lambda: clientProtocol - - contextFactory = ClientTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - contextFactory, True, clientFactory) - sslProtocol = wrapperFactory.buildProtocol(None) - - transport = StringTransport() - sslProtocol.makeConnection(transport) - - self.assertNotIdentical(clientProtocol.transport, None) - self.assertNotIdentical(clientProtocol.transport, transport) - self.assertIdentical(clientProtocol.transport, sslProtocol) - - - def handshakeProtocols(self): - """ - Start handshake between TLS client and server. - """ - clientFactory = ClientFactory() - clientFactory.protocol = Protocol - - clientContextFactory, handshakeDeferred = ( - HandshakeCallbackContextFactory.factoryAndDeferred()) - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverFactory = ServerFactory() - serverFactory.protocol = Protocol - - serverContextFactory = ServerTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) - return (sslClientProtocol, sslServerProtocol, handshakeDeferred, - connectionDeferred) - - - def test_handshake(self): - """ - The TLS handshake is performed when L{TLSMemoryBIOProtocol} is - connected to a transport. - """ - tlsClient, tlsServer, handshakeDeferred, _ = self.handshakeProtocols() - - # Only wait for the handshake to complete. Anything after that isn't - # important here. - return handshakeDeferred - - - def test_handshakeFailure(self): - """ - L{TLSMemoryBIOProtocol} reports errors in the handshake process to the - application-level protocol object using its C{connectionLost} method - and disconnects the underlying transport. - """ - clientConnectionLost = Deferred() - clientFactory = ClientFactory() - clientFactory.protocol = ( - lambda: ConnectionLostNotifyingProtocol( - clientConnectionLost)) - - clientContextFactory = HandshakeCallbackContextFactory() - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverConnectionLost = Deferred() - serverFactory = ServerFactory() - serverFactory.protocol = ( - lambda: ConnectionLostNotifyingProtocol( - serverConnectionLost)) - - # This context factory rejects any clients which do not present a - # certificate. - certificateData = FilePath(certPath).getContent() - certificate = PrivateCertificate.loadPEM(certificateData) - serverContextFactory = certificate.options(certificate) - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) - - def cbConnectionLost(protocol): - # The connection should close on its own in response to the error - # induced by the client not supplying the required certificate. - # After that, check to make sure the protocol's connectionLost was - # called with the right thing. - protocol.lostConnectionReason.trap(Error) - clientConnectionLost.addCallback(cbConnectionLost) - serverConnectionLost.addCallback(cbConnectionLost) - - # Additionally, the underlying transport should have been told to - # go away. - return gatherResults([ - clientConnectionLost, serverConnectionLost, - connectionDeferred]) - - - def test_getPeerCertificate(self): - """ - L{TLSMemoryBIOProtocol.getPeerCertificate} returns the - L{OpenSSL.crypto.X509Type} instance representing the peer's - certificate. - """ - # Set up a client and server so there's a certificate to grab. - clientFactory = ClientFactory() - clientFactory.protocol = Protocol - - clientContextFactory, handshakeDeferred = ( - HandshakeCallbackContextFactory.factoryAndDeferred()) - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverFactory = ServerFactory() - serverFactory.protocol = Protocol - - serverContextFactory = ServerTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - loopbackAsync(sslServerProtocol, sslClientProtocol) - - # Wait for the handshake - def cbHandshook(ignored): - # Grab the server's certificate and check it out - cert = sslClientProtocol.getPeerCertificate() - self.assertIsInstance(cert, X509Type) - self.assertEqual( - cert.digest('sha1'), - # openssl x509 -noout -sha1 -fingerprint -in server.pem - b'45:DD:FD:E2:BD:BF:8B:D0:00:B7:D2:7A:BB:20:F5:34:05:4B:15:80') - handshakeDeferred.addCallback(cbHandshook) - return handshakeDeferred - - - def test_writeAfterHandshake(self): - """ - Bytes written to L{TLSMemoryBIOProtocol} before the handshake is - complete are received by the protocol on the other side of the - connection once the handshake succeeds. - """ - bytes = b"some bytes" - - clientProtocol = Protocol() - clientFactory = ClientFactory() - clientFactory.protocol = lambda: clientProtocol - - clientContextFactory, handshakeDeferred = ( - HandshakeCallbackContextFactory.factoryAndDeferred()) - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverProtocol = AccumulatingProtocol(len(bytes)) - serverFactory = ServerFactory() - serverFactory.protocol = lambda: serverProtocol - - serverContextFactory = ServerTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) - - # Wait for the handshake to finish before writing anything. - def cbHandshook(ignored): - clientProtocol.transport.write(bytes) - - # The server will drop the connection once it gets the bytes. - return connectionDeferred - handshakeDeferred.addCallback(cbHandshook) - - # Once the connection is lost, make sure the server received the - # expected bytes. - def cbDisconnected(ignored): - self.assertEqual(b"".join(serverProtocol.received), bytes) - handshakeDeferred.addCallback(cbDisconnected) - - return handshakeDeferred - - - def writeBeforeHandshakeTest(self, sendingProtocol, bytes): - """ - Run test where client sends data before handshake, given the sending - protocol and expected bytes. - """ - clientFactory = ClientFactory() - clientFactory.protocol = sendingProtocol - - clientContextFactory, handshakeDeferred = ( - HandshakeCallbackContextFactory.factoryAndDeferred()) - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverProtocol = AccumulatingProtocol(len(bytes)) - serverFactory = ServerFactory() - serverFactory.protocol = lambda: serverProtocol - - serverContextFactory = ServerTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) - - # Wait for the connection to end, then make sure the server received - # the bytes sent by the client. - def cbConnectionDone(ignored): - self.assertEqual(b"".join(serverProtocol.received), bytes) - connectionDeferred.addCallback(cbConnectionDone) - return connectionDeferred - - - def test_writeBeforeHandshake(self): - """ - Bytes written to L{TLSMemoryBIOProtocol} before the handshake is - complete are received by the protocol on the other side of the - connection once the handshake succeeds. - """ - bytes = b"some bytes" - - class SimpleSendingProtocol(Protocol): - def connectionMade(self): - self.transport.write(bytes) - - return self.writeBeforeHandshakeTest(SimpleSendingProtocol, bytes) - - - def test_writeSequence(self): - """ - Bytes written to L{TLSMemoryBIOProtocol} with C{writeSequence} are - received by the protocol on the other side of the connection. - """ - bytes = b"some bytes" - class SimpleSendingProtocol(Protocol): - def connectionMade(self): - self.transport.writeSequence(list(iterbytes(bytes))) - - return self.writeBeforeHandshakeTest(SimpleSendingProtocol, bytes) - - - def test_writeAfterLoseConnection(self): - """ - Bytes written to L{TLSMemoryBIOProtocol} after C{loseConnection} is - called are not transmitted (unless there is a registered producer, - which will be tested elsewhere). - """ - bytes = b"some bytes" - class SimpleSendingProtocol(Protocol): - def connectionMade(self): - self.transport.write(bytes) - self.transport.loseConnection() - self.transport.write(b"hello") - self.transport.writeSequence([b"world"]) - return self.writeBeforeHandshakeTest(SimpleSendingProtocol, bytes) - - - def test_writeUnicodeRaisesTypeError(self): - """ - Writing C{unicode} to L{TLSMemoryBIOProtocol} throws a C{TypeError}. - """ - notBytes = u"hello" - result = [] - class SimpleSendingProtocol(Protocol): - def connectionMade(self): - try: - self.transport.write(notBytes) - except TypeError: - result.append(True) - self.transport.write(b"bytes") - self.transport.loseConnection() - d = self.writeBeforeHandshakeTest(SimpleSendingProtocol, b"bytes") - return d.addCallback(lambda ign: self.assertEqual(result, [True])) - - - def test_multipleWrites(self): - """ - If multiple separate TLS messages are received in a single chunk from - the underlying transport, all of the application bytes from each - message are delivered to the application-level protocol. - """ - bytes = [b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i'] - class SimpleSendingProtocol(Protocol): - def connectionMade(self): - for b in bytes: - self.transport.write(b) - - clientFactory = ClientFactory() - clientFactory.protocol = SimpleSendingProtocol - - clientContextFactory = HandshakeCallbackContextFactory() - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverProtocol = AccumulatingProtocol(sum(map(len, bytes))) - serverFactory = ServerFactory() - serverFactory.protocol = lambda: serverProtocol - - serverContextFactory = ServerTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol, collapsingPumpPolicy) - - # Wait for the connection to end, then make sure the server received - # the bytes sent by the client. - def cbConnectionDone(ignored): - self.assertEqual(b"".join(serverProtocol.received), b''.join(bytes)) - connectionDeferred.addCallback(cbConnectionDone) - return connectionDeferred - - - def test_hugeWrite(self): - """ - If a very long string is passed to L{TLSMemoryBIOProtocol.write}, any - trailing part of it which cannot be send immediately is buffered and - sent later. - """ - bytes = b"some bytes" - factor = 8192 - class SimpleSendingProtocol(Protocol): - def connectionMade(self): - self.transport.write(bytes * factor) - - clientFactory = ClientFactory() - clientFactory.protocol = SimpleSendingProtocol - - clientContextFactory = HandshakeCallbackContextFactory() - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverProtocol = AccumulatingProtocol(len(bytes) * factor) - serverFactory = ServerFactory() - serverFactory.protocol = lambda: serverProtocol - - serverContextFactory = ServerTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) - - # Wait for the connection to end, then make sure the server received - # the bytes sent by the client. - def cbConnectionDone(ignored): - self.assertEqual(b"".join(serverProtocol.received), bytes * factor) - connectionDeferred.addCallback(cbConnectionDone) - return connectionDeferred - - - def test_disorderlyShutdown(self): - """ - If a L{TLSMemoryBIOProtocol} loses its connection unexpectedly, this is - reported to the application. - """ - clientConnectionLost = Deferred() - clientFactory = ClientFactory() - clientFactory.protocol = ( - lambda: ConnectionLostNotifyingProtocol( - clientConnectionLost)) - - clientContextFactory = HandshakeCallbackContextFactory() - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - # Client speaks first, so the server can be dumb. - serverProtocol = Protocol() - - loopbackAsync(serverProtocol, sslClientProtocol) - - # Now destroy the connection. - serverProtocol.transport.loseConnection() - - # And when the connection completely dies, check the reason. - def cbDisconnected(clientProtocol): - clientProtocol.lostConnectionReason.trap(Error) - clientConnectionLost.addCallback(cbDisconnected) - return clientConnectionLost - - - def test_loseConnectionAfterHandshake(self): - """ - L{TLSMemoryBIOProtocol.loseConnection} sends a TLS close alert and - shuts down the underlying connection cleanly on both sides, after - transmitting all buffered data. - """ - class NotifyingProtocol(ConnectionLostNotifyingProtocol): - def __init__(self, onConnectionLost): - ConnectionLostNotifyingProtocol.__init__(self, - onConnectionLost) - self.data = [] - - def dataReceived(self, bytes): - self.data.append(bytes) - - clientConnectionLost = Deferred() - clientFactory = ClientFactory() - clientProtocol = NotifyingProtocol(clientConnectionLost) - clientFactory.protocol = lambda: clientProtocol - - clientContextFactory, handshakeDeferred = ( - HandshakeCallbackContextFactory.factoryAndDeferred()) - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - - serverConnectionLost = Deferred() - serverProtocol = NotifyingProtocol(serverConnectionLost) - serverFactory = ServerFactory() - serverFactory.protocol = lambda: serverProtocol - - serverContextFactory = ServerTLSContext() - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - loopbackAsync(sslServerProtocol, sslClientProtocol) - chunkOfBytes = b"123456890" * 100000 - - # Wait for the handshake before dropping the connection. - def cbHandshake(ignored): - # Write more than a single bio_read, to ensure client will still - # have some data it needs to write when it receives the TLS close - # alert, and that simply doing a single bio_read won't be - # sufficient. Thus we will verify that any amount of buffered data - # will be written out before the connection is closed, rather than - # just small amounts that can be returned in a single bio_read: - clientProtocol.transport.write(chunkOfBytes) - serverProtocol.transport.loseConnection() - - # Now wait for the client and server to notice. - return gatherResults([clientConnectionLost, serverConnectionLost]) - handshakeDeferred.addCallback(cbHandshake) - - # Wait for the connection to end, then make sure the client and server - # weren't notified of a handshake failure that would cause the test to - # fail. - def cbConnectionDone(result): - (clientProtocol, serverProtocol) = result - clientProtocol.lostConnectionReason.trap(ConnectionDone) - serverProtocol.lostConnectionReason.trap(ConnectionDone) - - # The server should have received all bytes sent by the client: - self.assertEqual(b"".join(serverProtocol.data), chunkOfBytes) - - # The server should have closed its underlying transport, in - # addition to whatever it did to shut down the TLS layer. - self.assertTrue(serverProtocol.transport.q.disconnect) - - # The client should also have closed its underlying transport once - # it saw the server shut down the TLS layer, so as to avoid relying - # on the server to close the underlying connection. - self.assertTrue(clientProtocol.transport.q.disconnect) - handshakeDeferred.addCallback(cbConnectionDone) - return handshakeDeferred - - - def test_connectionLostOnlyAfterUnderlyingCloses(self): - """ - The user protocol's connectionLost is only called when transport - underlying TLS is disconnected. - """ - class LostProtocol(Protocol): - disconnected = None - def connectionLost(self, reason): - self.disconnected = reason - wrapperFactory = TLSMemoryBIOFactory(ClientTLSContext(), - True, ClientFactory()) - protocol = LostProtocol() - tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, protocol) - transport = StringTransport() - tlsProtocol.makeConnection(transport) - - # Pretend TLS shutdown finished cleanly; the underlying transport - # should be told to close, but the user protocol should not yet be - # notified: - tlsProtocol._tlsShutdownFinished(None) - self.assertEqual(transport.disconnecting, True) - self.assertEqual(protocol.disconnected, None) - - # Now close the underlying connection; the user protocol should be - # notified with the given reason (since TLS closed cleanly): - tlsProtocol.connectionLost(Failure(ConnectionLost("ono"))) - self.assertTrue(protocol.disconnected.check(ConnectionLost)) - self.assertEqual(protocol.disconnected.value.args, ("ono",)) - - - def test_loseConnectionTwice(self): - """ - If TLSMemoryBIOProtocol.loseConnection is called multiple times, all - but the first call have no effect. - """ - wrapperFactory = TLSMemoryBIOFactory(ClientTLSContext(), - True, ClientFactory()) - tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, Protocol()) - transport = StringTransport() - tlsProtocol.makeConnection(transport) - self.assertEqual(tlsProtocol.disconnecting, False) - - # Make sure loseConnection calls _shutdownTLS the first time (mostly - # to make sure we've overriding it correctly): - calls = [] - def _shutdownTLS(shutdown=tlsProtocol._shutdownTLS): - calls.append(1) - return shutdown() - tlsProtocol._shutdownTLS = _shutdownTLS - tlsProtocol.loseConnection() - self.assertEqual(tlsProtocol.disconnecting, True) - self.assertEqual(calls, [1]) - - # Make sure _shutdownTLS isn't called a second time: - tlsProtocol.loseConnection() - self.assertEqual(calls, [1]) - - - def test_unexpectedEOF(self): - """ - Unexpected disconnects get converted to ConnectionLost errors. - """ - tlsClient, tlsServer, handshakeDeferred, disconnectDeferred = ( - self.handshakeProtocols()) - serverProtocol = tlsServer.wrappedProtocol - data = [] - reason = [] - serverProtocol.dataReceived = data.append - serverProtocol.connectionLost = reason.append - - # Write data, then disconnect *underlying* transport, resulting in an - # unexpected TLS disconnect: - def handshakeDone(ign): - tlsClient.write(b"hello") - tlsClient.transport.loseConnection() - handshakeDeferred.addCallback(handshakeDone) - - # Receiver should be disconnected, with ConnectionLost notification - # (masking the Unexpected EOF SSL error): - def disconnected(ign): - self.assertTrue(reason[0].check(ConnectionLost), reason[0]) - disconnectDeferred.addCallback(disconnected) - return disconnectDeferred - - - def test_errorWriting(self): - """ - Errors while writing cause the protocols to be disconnected. - """ - tlsClient, tlsServer, handshakeDeferred, disconnectDeferred = ( - self.handshakeProtocols()) - reason = [] - tlsClient.wrappedProtocol.connectionLost = reason.append - - # Pretend TLS connection is unhappy sending: - class Wrapper(object): - def __init__(self, wrapped): - self._wrapped = wrapped - def __getattr__(self, attr): - return getattr(self._wrapped, attr) - def send(self, *args): - raise Error("ONO!") - tlsClient._tlsConnection = Wrapper(tlsClient._tlsConnection) - - # Write some data: - def handshakeDone(ign): - tlsClient.write(b"hello") - handshakeDeferred.addCallback(handshakeDone) - - # Failed writer should be disconnected with SSL error: - def disconnected(ign): - self.assertTrue(reason[0].check(Error), reason[0]) - disconnectDeferred.addCallback(disconnected) - return disconnectDeferred - - - -class TLSProducerTests(TestCase): - """ - The TLS transport must support the IConsumer interface. - """ - - def setupStreamingProducer(self, transport=None): - class HistoryStringTransport(StringTransport): - def __init__(self): - StringTransport.__init__(self) - self.producerHistory = [] - - def pauseProducing(self): - self.producerHistory.append("pause") - StringTransport.pauseProducing(self) - - def resumeProducing(self): - self.producerHistory.append("resume") - StringTransport.resumeProducing(self) - - def stopProducing(self): - self.producerHistory.append("stop") - StringTransport.stopProducing(self) - - clientProtocol, tlsProtocol = buildTLSProtocol(transport=transport) - producer = HistoryStringTransport() - clientProtocol.transport.registerProducer(producer, True) - self.assertEqual(tlsProtocol.transport.streaming, True) - return clientProtocol, tlsProtocol, producer - - - def flushTwoTLSProtocols(self, tlsProtocol, serverTLSProtocol): - """ - Transfer bytes back and forth between two TLS protocols. - """ - # We want to make sure all bytes are passed back and forth; JP - # estimated that 3 rounds should be enough: - for i in range(3): - clientData = tlsProtocol.transport.value() - if clientData: - serverTLSProtocol.dataReceived(clientData) - tlsProtocol.transport.clear() - serverData = serverTLSProtocol.transport.value() - if serverData: - tlsProtocol.dataReceived(serverData) - serverTLSProtocol.transport.clear() - if not serverData and not clientData: - break - self.assertEqual(tlsProtocol.transport.value(), b"") - self.assertEqual(serverTLSProtocol.transport.value(), b"") - - - def test_streamingProducerPausedInNormalMode(self): - """ - When the TLS transport is not blocked on reads, it correctly calls - pauseProducing on the registered producer. - """ - _, tlsProtocol, producer = self.setupStreamingProducer() - - # The TLS protocol's transport pretends to be full, pausing its - # producer: - tlsProtocol.transport.producer.pauseProducing() - self.assertEqual(producer.producerState, 'paused') - self.assertEqual(producer.producerHistory, ['pause']) - self.assertEqual(tlsProtocol._producer._producerPaused, True) - - - def test_streamingProducerResumedInNormalMode(self): - """ - When the TLS transport is not blocked on reads, it correctly calls - resumeProducing on the registered producer. - """ - _, tlsProtocol, producer = self.setupStreamingProducer() - tlsProtocol.transport.producer.pauseProducing() - self.assertEqual(producer.producerHistory, ['pause']) - - # The TLS protocol's transport pretends to have written everything - # out, so it resumes its producer: - tlsProtocol.transport.producer.resumeProducing() - self.assertEqual(producer.producerState, 'producing') - self.assertEqual(producer.producerHistory, ['pause', 'resume']) - self.assertEqual(tlsProtocol._producer._producerPaused, False) - - - def test_streamingProducerPausedInWriteBlockedOnReadMode(self): - """ - When the TLS transport is blocked on reads, it correctly calls - pauseProducing on the registered producer. - """ - clientProtocol, tlsProtocol, producer = self.setupStreamingProducer() - - # Write to TLS transport. Because we do this before the initial TLS - # handshake is finished, writing bytes triggers a WantReadError, - # indicating that until bytes are read for the handshake, more bytes - # cannot be written. Thus writing bytes before the handshake should - # cause the producer to be paused: - clientProtocol.transport.write(b"hello") - self.assertEqual(producer.producerState, 'paused') - self.assertEqual(producer.producerHistory, ['pause']) - self.assertEqual(tlsProtocol._producer._producerPaused, True) - - - def test_streamingProducerResumedInWriteBlockedOnReadMode(self): - """ - When the TLS transport is blocked on reads, it correctly calls - resumeProducing on the registered producer. - """ - clientProtocol, tlsProtocol, producer = self.setupStreamingProducer() - - # Write to TLS transport, triggering WantReadError; this should cause - # the producer to be paused. We use a large chunk of data to make sure - # large writes don't trigger multiple pauses: - clientProtocol.transport.write(b"hello world" * 320000) - self.assertEqual(producer.producerHistory, ['pause']) - - # Now deliver bytes that will fix the WantRead condition; this should - # unpause the producer: - serverProtocol, serverTLSProtocol = buildTLSProtocol(server=True) - self.flushTwoTLSProtocols(tlsProtocol, serverTLSProtocol) - self.assertEqual(producer.producerHistory, ['pause', 'resume']) - self.assertEqual(tlsProtocol._producer._producerPaused, False) - - # Make sure we haven't disconnected for some reason: - self.assertEqual(tlsProtocol.transport.disconnecting, False) - self.assertEqual(producer.producerState, 'producing') - - - def test_streamingProducerTwice(self): - """ - Registering a streaming producer twice throws an exception. - """ - clientProtocol, tlsProtocol, producer = self.setupStreamingProducer() - originalProducer = tlsProtocol._producer - producer2 = object() - self.assertRaises(RuntimeError, - clientProtocol.transport.registerProducer, producer2, True) - self.assertIdentical(tlsProtocol._producer, originalProducer) - - - def test_streamingProducerUnregister(self): - """ - Unregistering a streaming producer removes it, reverting to initial state. - """ - clientProtocol, tlsProtocol, producer = self.setupStreamingProducer() - clientProtocol.transport.unregisterProducer() - self.assertEqual(tlsProtocol._producer, None) - self.assertEqual(tlsProtocol.transport.producer, None) - - - def loseConnectionWithProducer(self, writeBlockedOnRead): - """ - Common code for tests involving writes by producer after - loseConnection is called. - """ - clientProtocol, tlsProtocol, producer = self.setupStreamingProducer() - serverProtocol, serverTLSProtocol = buildTLSProtocol(server=True) - - if not writeBlockedOnRead: - # Do the initial handshake before write: - self.flushTwoTLSProtocols(tlsProtocol, serverTLSProtocol) - else: - # In this case the write below will trigger write-blocked-on-read - # condition... - pass - - # Now write, then lose connection: - clientProtocol.transport.write(b"x ") - clientProtocol.transport.loseConnection() - self.flushTwoTLSProtocols(tlsProtocol, serverTLSProtocol) - - # Underlying transport should not have loseConnection called yet, nor - # should producer be stopped: - self.assertEqual(tlsProtocol.transport.disconnecting, False) - self.assertFalse("stop" in producer.producerHistory) - - # Writes from client to server should continue to go through, since we - # haven't unregistered producer yet: - clientProtocol.transport.write(b"hello") - clientProtocol.transport.writeSequence([b" ", b"world"]) - - # Unregister producer; this should trigger TLS shutdown: - clientProtocol.transport.unregisterProducer() - self.assertNotEqual(tlsProtocol.transport.value(), b"") - self.assertEqual(tlsProtocol.transport.disconnecting, False) - - # Additional writes should not go through: - clientProtocol.transport.write(b"won't") - clientProtocol.transport.writeSequence([b"won't!"]) - - # Finish TLS close handshake: - self.flushTwoTLSProtocols(tlsProtocol, serverTLSProtocol) - self.assertEqual(tlsProtocol.transport.disconnecting, True) - - # Bytes made it through, as long as they were written before producer - # was unregistered: - self.assertEqual(b"".join(serverProtocol.received), b"x hello world") - - - def test_streamingProducerLoseConnectionWithProducer(self): - """ - loseConnection() waits for the producer to unregister itself, then - does a clean TLS close alert, then closes the underlying connection. - """ - return self.loseConnectionWithProducer(False) - - - def test_streamingProducerLoseConnectionWithProducerWBOR(self): - """ - Even when writes are blocked on reading, loseConnection() waits for - the producer to unregister itself, then does a clean TLS close alert, - then closes the underlying connection. - """ - return self.loseConnectionWithProducer(True) - - - def test_streamingProducerBothTransportsDecideToPause(self): - """ - pauseProducing() events can come from both the TLS transport layer and - the underlying transport. In this case, both decide to pause, - underlying first. - """ - class PausingStringTransport(StringTransport): - _didPause = False - - def write(self, data): - if not self._didPause and self.producer is not None: - self._didPause = True - self.producer.pauseProducing() - StringTransport.write(self, data) - - - class TLSConnection(object): - def __init__(self): - self.l = [] - - def send(self, bytes): - # on first write, don't send all bytes: - if not self.l: - bytes = bytes[:-1] - # pause on second write: - if len(self.l) == 1: - self.l.append("paused") - raise WantReadError() - # otherwise just take in data: - self.l.append(bytes) - return len(bytes) - - def bio_write(self, data): - pass - - def bio_read(self, size): - return b'X' - - def recv(self, size): - raise WantReadError() - - transport = PausingStringTransport() - clientProtocol, tlsProtocol, producer = self.setupStreamingProducer( - transport) - self.assertEqual(producer.producerState, 'producing') - - # Shove in fake TLSConnection that will raise WantReadError the second - # time send() is called. This will allow us to have bytes written to - # to the PausingStringTransport, so it will pause the producer. Then, - # WantReadError will be thrown, triggering the TLS transport's - # producer code path. - tlsProtocol._tlsConnection = TLSConnection() - clientProtocol.transport.write(b"hello") - self.assertEqual(producer.producerState, 'paused') - self.assertEqual(producer.producerHistory, ['pause']) - - # Now, underlying transport resumes, and then we deliver some data to - # TLS transport so that it will resume: - tlsProtocol.transport.producer.resumeProducing() - self.assertEqual(producer.producerState, 'producing') - self.assertEqual(producer.producerHistory, ['pause', 'resume']) - tlsProtocol.dataReceived(b"hello") - self.assertEqual(producer.producerState, 'producing') - self.assertEqual(producer.producerHistory, ['pause', 'resume']) - - - def test_streamingProducerStopProducing(self): - """ - If the underlying transport tells its producer to stopProducing(), - this is passed on to the high-level producer. - """ - _, tlsProtocol, producer = self.setupStreamingProducer() - tlsProtocol.transport.producer.stopProducing() - self.assertEqual(producer.producerState, 'stopped') - - - def test_nonStreamingProducer(self): - """ - Non-streaming producers get wrapped as streaming producers. - """ - clientProtocol, tlsProtocol = buildTLSProtocol() - producer = NonStreamingProducer(clientProtocol.transport) - - # Register non-streaming producer: - clientProtocol.transport.registerProducer(producer, False) - streamingProducer = tlsProtocol.transport.producer._producer - - # Verify it was wrapped into streaming producer: - self.assertIsInstance(streamingProducer, _PullToPush) - self.assertEqual(streamingProducer._producer, producer) - self.assertEqual(streamingProducer._consumer, clientProtocol.transport) - self.assertEqual(tlsProtocol.transport.streaming, True) - - # Verify the streaming producer was started, and ran until the end: - def done(ignore): - # Our own producer is done: - self.assertEqual(producer.consumer, None) - # The producer has been unregistered: - self.assertEqual(tlsProtocol.transport.producer, None) - # The streaming producer wrapper knows it's done: - self.assertEqual(streamingProducer._finished, True) - producer.result.addCallback(done) - - serverProtocol, serverTLSProtocol = buildTLSProtocol(server=True) - self.flushTwoTLSProtocols(tlsProtocol, serverTLSProtocol) - return producer.result - - - def test_interface(self): - """ - L{_ProducerMembrane} implements L{IPushProducer}. - """ - producer = StringTransport() - membrane = _ProducerMembrane(producer) - self.assertTrue(verifyObject(IPushProducer, membrane)) - - - def registerProducerAfterConnectionLost(self, streaming): - """ - If a producer is registered after the transport has disconnected, the - producer is not used, and its stopProducing method is called. - """ - clientProtocol, tlsProtocol = buildTLSProtocol() - clientProtocol.connectionLost = lambda reason: reason.trap(Error) - - class Producer(object): - stopped = False - - def resumeProducing(self): - return 1/0 # this should never be called - - def stopProducing(self): - self.stopped = True - - # Disconnect the transport: - tlsProtocol.connectionLost(Failure(ConnectionDone())) - - # Register the producer; startProducing should not be called, but - # stopProducing will: - producer = Producer() - tlsProtocol.registerProducer(producer, False) - self.assertIdentical(tlsProtocol.transport.producer, None) - self.assertEqual(producer.stopped, True) - - - def test_streamingProducerAfterConnectionLost(self): - """ - If a streaming producer is registered after the transport has - disconnected, the producer is not used, and its stopProducing method - is called. - """ - self.registerProducerAfterConnectionLost(True) - - - def test_nonStreamingProducerAfterConnectionLost(self): - """ - If a non-streaming producer is registered after the transport has - disconnected, the producer is not used, and its stopProducing method - is called. - """ - self.registerProducerAfterConnectionLost(False) - - - -class NonStreamingProducer(object): - """ - A pull producer which writes 10 times only. - """ - - counter = 0 - stopped = False - - def __init__(self, consumer): - self.consumer = consumer - self.result = Deferred() - - def resumeProducing(self): - if self.counter < 10: - self.consumer.write(intToBytes(self.counter)) - self.counter += 1 - if self.counter == 10: - self.consumer.unregisterProducer() - self._done() - else: - if self.consumer is None: - raise RuntimeError("BUG: resume after unregister/stop.") - - - def pauseProducing(self): - raise RuntimeError("BUG: pause should never be called.") - - - def _done(self): - self.consumer = None - d = self.result - del self.result - d.callback(None) - - - def stopProducing(self): - self.stopped = True - self._done() - - - -class NonStreamingProducerTests(TestCase): - """ - Non-streaming producers can be adapted into being streaming producers. - """ - - def streamUntilEnd(self, consumer): - """ - Verify the consumer writes out all its data, but is not called after - that. - """ - nsProducer = NonStreamingProducer(consumer) - streamingProducer = _PullToPush(nsProducer, consumer) - consumer.registerProducer(streamingProducer, True) - - # The producer will call unregisterProducer(), and we need to hook - # that up so the streaming wrapper is notified; the - # TLSMemoryBIOProtocol will have to do this itself, which is tested - # elsewhere: - def unregister(orig=consumer.unregisterProducer): - orig() - streamingProducer.stopStreaming() - consumer.unregisterProducer = unregister - - done = nsProducer.result - def doneStreaming(_): - # All data was streamed, and the producer unregistered itself: - self.assertEqual(consumer.value(), b"0123456789") - self.assertEqual(consumer.producer, None) - # And the streaming wrapper stopped: - self.assertEqual(streamingProducer._finished, True) - done.addCallback(doneStreaming) - - # Now, start streaming: - streamingProducer.startStreaming() - return done - - - def test_writeUntilDone(self): - """ - When converted to a streaming producer, the non-streaming producer - writes out all its data, but is not called after that. - """ - consumer = StringTransport() - return self.streamUntilEnd(consumer) - - - def test_pause(self): - """ - When the streaming producer is paused, the underlying producer stops - getting resumeProducing calls. - """ - class PausingStringTransport(StringTransport): - writes = 0 - - def __init__(self): - StringTransport.__init__(self) - self.paused = Deferred() - - def write(self, data): - self.writes += 1 - StringTransport.write(self, data) - if self.writes == 3: - self.producer.pauseProducing() - d = self.paused - del self.paused - d.callback(None) - - - consumer = PausingStringTransport() - nsProducer = NonStreamingProducer(consumer) - streamingProducer = _PullToPush(nsProducer, consumer) - consumer.registerProducer(streamingProducer, True) - - # Make sure the consumer does not continue: - def shouldNotBeCalled(ignore): - self.fail("BUG: The producer should not finish!") - nsProducer.result.addCallback(shouldNotBeCalled) - - done = consumer.paused - def paused(ignore): - # The CooperatorTask driving the producer was paused: - self.assertEqual(streamingProducer._coopTask._pauseCount, 1) - done.addCallback(paused) - - # Now, start streaming: - streamingProducer.startStreaming() - return done - - - def test_resume(self): - """ - When the streaming producer is paused and then resumed, the underlying - producer starts getting resumeProducing calls again after the resume. - - The test will never finish (or rather, time out) if the resume - producing call is not working. - """ - class PausingStringTransport(StringTransport): - writes = 0 - - def write(self, data): - self.writes += 1 - StringTransport.write(self, data) - if self.writes == 3: - self.producer.pauseProducing() - self.producer.resumeProducing() - - consumer = PausingStringTransport() - return self.streamUntilEnd(consumer) - - - def test_stopProducing(self): - """ - When the streaming producer is stopped by the consumer, the underlying - producer is stopped, and streaming is stopped. - """ - class StoppingStringTransport(StringTransport): - writes = 0 - - def write(self, data): - self.writes += 1 - StringTransport.write(self, data) - if self.writes == 3: - self.producer.stopProducing() - - consumer = StoppingStringTransport() - nsProducer = NonStreamingProducer(consumer) - streamingProducer = _PullToPush(nsProducer, consumer) - consumer.registerProducer(streamingProducer, True) - - done = nsProducer.result - def doneStreaming(_): - # Not all data was streamed, and the producer was stopped: - self.assertEqual(consumer.value(), b"012") - self.assertEqual(nsProducer.stopped, True) - # And the streaming wrapper stopped: - self.assertEqual(streamingProducer._finished, True) - done.addCallback(doneStreaming) - - # Now, start streaming: - streamingProducer.startStreaming() - return done - - - def resumeProducingRaises(self, consumer, expectedExceptions): - """ - Common implementation for tests where the underlying producer throws - an exception when its resumeProducing is called. - """ - class ThrowingProducer(NonStreamingProducer): - - def resumeProducing(self): - if self.counter == 2: - return 1/0 - else: - NonStreamingProducer.resumeProducing(self) - - nsProducer = ThrowingProducer(consumer) - streamingProducer = _PullToPush(nsProducer, consumer) - consumer.registerProducer(streamingProducer, True) - - # Register log observer: - loggedMsgs = [] - log.addObserver(loggedMsgs.append) - self.addCleanup(log.removeObserver, loggedMsgs.append) - - # Make consumer unregister do what TLSMemoryBIOProtocol would do: - def unregister(orig=consumer.unregisterProducer): - orig() - streamingProducer.stopStreaming() - consumer.unregisterProducer = unregister - - # Start streaming: - streamingProducer.startStreaming() - - done = streamingProducer._coopTask.whenDone() - done.addErrback(lambda reason: reason.trap(TaskStopped)) - def stopped(ign): - self.assertEqual(consumer.value(), b"01") - # Any errors from resumeProducing were logged: - errors = self.flushLoggedErrors() - self.assertEqual(len(errors), len(expectedExceptions)) - for f, (expected, msg), logMsg in zip( - errors, expectedExceptions, loggedMsgs): - self.assertTrue(f.check(expected)) - self.assertIn(msg, logMsg['why']) - # And the streaming wrapper stopped: - self.assertEqual(streamingProducer._finished, True) - done.addCallback(stopped) - return done - - - def test_resumeProducingRaises(self): - """ - If the underlying producer raises an exception when resumeProducing is - called, the streaming wrapper should log the error, unregister from - the consumer and stop streaming. - """ - consumer = StringTransport() - done = self.resumeProducingRaises( - consumer, - [(ZeroDivisionError, "failed, producing will be stopped")]) - def cleanShutdown(ignore): - # Producer was unregistered from consumer: - self.assertEqual(consumer.producer, None) - done.addCallback(cleanShutdown) - return done - - - def test_resumeProducingRaiseAndUnregisterProducerRaises(self): - """ - If the underlying producer raises an exception when resumeProducing is - called, the streaming wrapper should log the error, unregister from - the consumer and stop streaming even if the unregisterProducer call - also raise. - """ - consumer = StringTransport() - def raiser(): - raise RuntimeError() - consumer.unregisterProducer = raiser - return self.resumeProducingRaises( - consumer, - [(ZeroDivisionError, "failed, producing will be stopped"), - (RuntimeError, "failed to unregister producer")]) - - - def test_stopStreamingTwice(self): - """ - stopStreaming() can be called more than once without blowing - up. This is useful for error-handling paths. - """ - consumer = StringTransport() - nsProducer = NonStreamingProducer(consumer) - streamingProducer = _PullToPush(nsProducer, consumer) - streamingProducer.startStreaming() - streamingProducer.stopStreaming() - streamingProducer.stopStreaming() - self.assertEqual(streamingProducer._finished, True) - - - def test_interface(self): - """ - L{_PullToPush} implements L{IPushProducer}. - """ - consumer = StringTransport() - nsProducer = NonStreamingProducer(consumer) - streamingProducer = _PullToPush(nsProducer, consumer) - self.assertTrue(verifyObject(IPushProducer, streamingProducer)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/tls.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/tls.py deleted file mode 100644 index df093dc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/tls.py +++ /dev/null @@ -1,806 +0,0 @@ -# -*- test-case-name: twisted.protocols.test.test_tls,twisted.internet.test.test_tls,twisted.test.test_sslverify -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Implementation of a TLS transport (L{ISSLTransport}) as an -L{IProtocol} layered on top of any -L{ITransport} implementation, based on -U{OpenSSL}'s memory BIO features. - -L{TLSMemoryBIOFactory} is a L{WrappingFactory} which wraps protocols created by -the factory it wraps with L{TLSMemoryBIOProtocol}. L{TLSMemoryBIOProtocol} -intercedes between the underlying transport and the wrapped protocol to -implement SSL and TLS. Typical usage of this module looks like this:: - - from twisted.protocols.tls import TLSMemoryBIOFactory - from twisted.internet.protocol import ServerFactory - from twisted.internet.ssl import PrivateCertificate - from twisted.internet import reactor - - from someapplication import ApplicationProtocol - - serverFactory = ServerFactory() - serverFactory.protocol = ApplicationProtocol - certificate = PrivateCertificate.loadPEM(certPEMData) - contextFactory = certificate.options() - tlsFactory = TLSMemoryBIOFactory(contextFactory, False, serverFactory) - reactor.listenTCP(12345, tlsFactory) - reactor.run() - -This API offers somewhat more flexibility than -L{twisted.internet.interfaces.IReactorSSL}; for example, a -L{TLSMemoryBIOProtocol} instance can use another instance of -L{TLSMemoryBIOProtocol} as its transport, yielding TLS over TLS - useful to -implement onion routing. It can also be used to run TLS over unusual -transports, such as UNIX sockets and stdio. -""" - -from __future__ import division, absolute_import - -from OpenSSL.SSL import Error, ZeroReturnError, WantReadError -from OpenSSL.SSL import TLSv1_METHOD, Context, Connection - -try: - Connection(Context(TLSv1_METHOD), None) -except TypeError as e: - if str(e) != "argument must be an int, or have a fileno() method.": - raise - raise ImportError("twisted.protocols.tls requires pyOpenSSL 0.10 or newer.") - -from zope.interface import implementer, providedBy, directlyProvides - -from twisted.python.compat import unicode -from twisted.python.failure import Failure -from twisted.python import log -from twisted.python.reflect import safe_str -from twisted.internet.interfaces import ( - ISystemHandle, ISSLTransport, IPushProducer, ILoggingContext, - IOpenSSLServerConnectionCreator, IOpenSSLClientConnectionCreator, -) -from twisted.internet.main import CONNECTION_LOST -from twisted.internet.protocol import Protocol -from twisted.internet.task import cooperate -from twisted.protocols.policies import ProtocolWrapper, WrappingFactory - - -@implementer(IPushProducer) -class _PullToPush(object): - """ - An adapter that converts a non-streaming to a streaming producer. - - Because of limitations of the producer API, this adapter requires the - cooperation of the consumer. When the consumer's C{registerProducer} is - called with a non-streaming producer, it must wrap it with L{_PullToPush} - and then call C{startStreaming} on the resulting object. When the - consumer's C{unregisterProducer} is called, it must call - C{stopStreaming} on the L{_PullToPush} instance. - - If the underlying producer throws an exception from C{resumeProducing}, - the producer will be unregistered from the consumer. - - @ivar _producer: the underling non-streaming producer. - - @ivar _consumer: the consumer with which the underlying producer was - registered. - - @ivar _finished: C{bool} indicating whether the producer has finished. - - @ivar _coopTask: the result of calling L{cooperate}, the task driving the - streaming producer. - """ - - _finished = False - - - def __init__(self, pullProducer, consumer): - self._producer = pullProducer - self._consumer = consumer - - - def _pull(self): - """ - A generator that calls C{resumeProducing} on the underlying producer - forever. - - If C{resumeProducing} throws an exception, the producer is - unregistered, which should result in streaming stopping. - """ - while True: - try: - self._producer.resumeProducing() - except: - log.err(None, "%s failed, producing will be stopped:" % - (safe_str(self._producer),)) - try: - self._consumer.unregisterProducer() - # The consumer should now call stopStreaming() on us, - # thus stopping the streaming. - except: - # Since the consumer blew up, we may not have had - # stopStreaming() called, so we just stop on our own: - log.err(None, "%s failed to unregister producer:" % - (safe_str(self._consumer),)) - self._finished = True - return - yield None - - - def startStreaming(self): - """ - This should be called by the consumer when the producer is registered. - - Start streaming data to the consumer. - """ - self._coopTask = cooperate(self._pull()) - - - def stopStreaming(self): - """ - This should be called by the consumer when the producer is unregistered. - - Stop streaming data to the consumer. - """ - if self._finished: - return - self._finished = True - self._coopTask.stop() - - - # IPushProducer implementation: - def pauseProducing(self): - self._coopTask.pause() - - - def resumeProducing(self): - self._coopTask.resume() - - - def stopProducing(self): - self.stopStreaming() - self._producer.stopProducing() - - - -@implementer(IPushProducer) -class _ProducerMembrane(object): - """ - Stand-in for producer registered with a L{TLSMemoryBIOProtocol} transport. - - Ensures that producer pause/resume events from the undelying transport are - coordinated with pause/resume events from the TLS layer. - - @ivar _producer: The application-layer producer. - """ - - _producerPaused = False - - def __init__(self, producer): - self._producer = producer - - - def pauseProducing(self): - """ - C{pauseProducing} the underlying producer, if it's not paused. - """ - if self._producerPaused: - return - self._producerPaused = True - self._producer.pauseProducing() - - - def resumeProducing(self): - """ - C{resumeProducing} the underlying producer, if it's paused. - """ - if not self._producerPaused: - return - self._producerPaused = False - self._producer.resumeProducing() - - - def stopProducing(self): - """ - C{stopProducing} the underlying producer. - - There is only a single source for this event, so it's simply passed - on. - """ - self._producer.stopProducing() - - - -@implementer(ISystemHandle, ISSLTransport) -class TLSMemoryBIOProtocol(ProtocolWrapper): - """ - L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a - memory BIO to encrypt bytes written to it before sending them on to the - underlying transport and decrypts bytes received from the underlying - transport before delivering them to the wrapped protocol. - - In addition to producer events from the underlying transport, the need to - wait for reads before a write can proceed means the L{TLSMemoryBIOProtocol} - may also want to pause a producer. Pause/resume events are therefore - merged using the L{_ProducerMembrane} wrapper. Non-streaming (pull) - producers are supported by wrapping them with L{_PullToPush}. - - @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is - encrypted and decrypting this connection. - - @ivar _lostTLSConnection: A flag indicating whether connection loss has - already been dealt with (C{True}) or not (C{False}). TLS disconnection - is distinct from the underlying connection being lost. - - @ivar _writeBlockedOnRead: A flag indicating whether further writing must - wait for data to be received (C{True}) or not (C{False}). - - @ivar _appSendBuffer: A C{list} of C{str} of application-level (cleartext) - data which is waiting for C{_writeBlockedOnRead} to be reset to - C{False} so it can be passed to and perhaps accepted by - C{_tlsConnection.send}. - - @ivar _connectWrapped: A flag indicating whether or not to call - C{makeConnection} on the wrapped protocol. This is for the reactor's - L{twisted.internet.interfaces.ITLSTransport.startTLS} implementation, - since it has a protocol which it has already called C{makeConnection} - on, and which has no interest in a new transport. See #3821. - - @ivar _handshakeDone: A flag indicating whether or not the handshake is - known to have completed successfully (C{True}) or not (C{False}). This - is used to control error reporting behavior. If the handshake has not - completed, the underlying L{OpenSSL.SSL.Error} will be passed to the - application's C{connectionLost} method. If it has completed, any - unexpected L{OpenSSL.SSL.Error} will be turned into a - L{ConnectionLost}. This is weird; however, it is simply an attempt at - a faithful re-implementation of the behavior provided by - L{twisted.internet.ssl}. - - @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes - the connection to be lost, it is saved here. If appropriate, this may - be used as the reason passed to the application protocol's - C{connectionLost} method. - - @ivar _producer: The current producer registered via C{registerProducer}, - or C{None} if no producer has been registered or a previous one was - unregistered. - - @ivar _aborted: C{abortConnection} has been called. No further data will - be received to the wrapped protocol's C{dataReceived}. - @type _aborted: L{bool} - """ - - _reason = None - _handshakeDone = False - _lostTLSConnection = False - _writeBlockedOnRead = False - _producer = None - _aborted = False - - def __init__(self, factory, wrappedProtocol, _connectWrapped=True): - ProtocolWrapper.__init__(self, factory, wrappedProtocol) - self._connectWrapped = _connectWrapped - - - def getHandle(self): - """ - Return the L{OpenSSL.SSL.Connection} object being used to encrypt and - decrypt this connection. - - This is done for the benefit of L{twisted.internet.ssl.Certificate}'s - C{peerFromTransport} and C{hostFromTransport} methods only. A - different system handle may be returned by future versions of this - method. - """ - return self._tlsConnection - - - def makeConnection(self, transport): - """ - Connect this wrapper to the given transport and initialize the - necessary L{OpenSSL.SSL.Connection} with a memory BIO. - """ - self._tlsConnection = self.factory._createConnection(self) - self._appSendBuffer = [] - - # Add interfaces provided by the transport we are wrapping: - for interface in providedBy(transport): - directlyProvides(self, interface) - - # Intentionally skip ProtocolWrapper.makeConnection - it might call - # wrappedProtocol.makeConnection, which we want to make conditional. - Protocol.makeConnection(self, transport) - self.factory.registerProtocol(self) - if self._connectWrapped: - # Now that the TLS layer is initialized, notify the application of - # the connection. - ProtocolWrapper.makeConnection(self, transport) - - # Now that we ourselves have a transport (initialized by the - # ProtocolWrapper.makeConnection call above), kick off the TLS - # handshake. - try: - self._tlsConnection.do_handshake() - except WantReadError: - # This is the expected case - there's no data in the connection's - # input buffer yet, so it won't be able to complete the whole - # handshake now. If this is the speak-first side of the - # connection, then some bytes will be in the send buffer now; flush - # them. - self._flushSendBIO() - - - def _flushSendBIO(self): - """ - Read any bytes out of the send BIO and write them to the underlying - transport. - """ - try: - bytes = self._tlsConnection.bio_read(2 ** 15) - except WantReadError: - # There may be nothing in the send BIO right now. - pass - else: - self.transport.write(bytes) - - - def _flushReceiveBIO(self): - """ - Try to receive any application-level bytes which are now available - because of a previous write into the receive BIO. This will take - care of delivering any application-level bytes which are received to - the protocol, as well as handling of the various exceptions which - can come from trying to get such bytes. - """ - # Keep trying this until an error indicates we should stop or we - # close the connection. Looping is necessary to make sure we - # process all of the data which was put into the receive BIO, as - # there is no guarantee that a single recv call will do it all. - while not self._lostTLSConnection: - try: - bytes = self._tlsConnection.recv(2 ** 15) - except WantReadError: - # The newly received bytes might not have been enough to produce - # any application data. - break - except ZeroReturnError: - # TLS has shut down and no more TLS data will be received over - # this connection. - self._shutdownTLS() - # Passing in None means the user protocol's connnectionLost - # will get called with reason from underlying transport: - self._tlsShutdownFinished(None) - except Error as e: - # Something went pretty wrong. For example, this might be a - # handshake failure (because there were no shared ciphers, because - # a certificate failed to verify, etc). TLS can no longer proceed. - - # Squash EOF in violation of protocol into ConnectionLost; we - # create Failure before calling _flushSendBio so that no new - # exception will get thrown in the interim. - if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': - failure = Failure(CONNECTION_LOST) - else: - failure = Failure() - - self._flushSendBIO() - self._tlsShutdownFinished(failure) - else: - # If we got application bytes, the handshake must be done by - # now. Keep track of this to control error reporting later. - self._handshakeDone = True - if not self._aborted: - ProtocolWrapper.dataReceived(self, bytes) - - # The received bytes might have generated a response which needs to be - # sent now. For example, the handshake involves several round-trip - # exchanges without ever producing application-bytes. - self._flushSendBIO() - - - def dataReceived(self, bytes): - """ - Deliver any received bytes to the receive BIO and then read and deliver - to the application any application-level data which becomes available - as a result of this. - """ - self._tlsConnection.bio_write(bytes) - - if self._writeBlockedOnRead: - # A read just happened, so we might not be blocked anymore. Try to - # flush all the pending application bytes. - self._writeBlockedOnRead = False - appSendBuffer = self._appSendBuffer - self._appSendBuffer = [] - for bytes in appSendBuffer: - self._write(bytes) - if (not self._writeBlockedOnRead and self.disconnecting and - self.producer is None): - self._shutdownTLS() - if self._producer is not None: - self._producer.resumeProducing() - - self._flushReceiveBIO() - - - def _shutdownTLS(self): - """ - Initiate, or reply to, the shutdown handshake of the TLS layer. - """ - try: - shutdownSuccess = self._tlsConnection.shutdown() - except Error: - # Mid-handshake, a call to shutdown() can result in a - # WantWantReadError, or rather an SSL_ERR_WANT_READ; but pyOpenSSL - # doesn't allow us to get at the error. See: - # https://github.com/pyca/pyopenssl/issues/91 - shutdownSuccess = False - self._flushSendBIO() - if shutdownSuccess: - # Both sides have shutdown, so we can start closing lower-level - # transport. This will also happen if we haven't started - # negotiation at all yet, in which case shutdown succeeds - # immediately. - self.transport.loseConnection() - - - def _tlsShutdownFinished(self, reason): - """ - Called when TLS connection has gone away; tell underlying transport to - disconnect. - """ - if self._reason is None: - self._reason = reason - self._lostTLSConnection = True - # Using loseConnection causes the application protocol's - # connectionLost method to be invoked non-reentrantly, which is always - # a nice feature. However, for error cases (reason != None) we might - # want to use abortConnection when it becomes available. The - # loseConnection call is basically tested by test_handshakeFailure. - # At least one side will need to do it or the test never finishes. - self.transport.loseConnection() - - - def connectionLost(self, reason): - """ - Handle the possible repetition of calls to this method (due to either - the underlying transport going away or due to an error at the TLS - layer) and make sure the base implementation only gets invoked once. - """ - if not self._lostTLSConnection: - # Tell the TLS connection that it's not going to get any more data - # and give it a chance to finish reading. - self._tlsConnection.bio_shutdown() - self._flushReceiveBIO() - self._lostTLSConnection = True - reason = self._reason or reason - self._reason = None - ProtocolWrapper.connectionLost(self, reason) - - - def loseConnection(self): - """ - Send a TLS close alert and close the underlying connection. - """ - if self.disconnecting: - return - self.disconnecting = True - if not self._writeBlockedOnRead and self._producer is None: - self._shutdownTLS() - - - def abortConnection(self): - """ - Tear down TLS state so that if the connection is aborted mid-handshake - we don't deliver any further data from the application. - """ - self._aborted = True - self.disconnecting = True - self._shutdownTLS() - self.transport.abortConnection() - - - def failVerification(self, reason): - """ - Abort the connection during connection setup, giving a reason that - certificate verification failed. - - @param reason: The reason that the verification failed; reported to the - application protocol's C{connectionLost} method. - @type reason: L{Failure} - """ - self._reason = reason - self.abortConnection() - - - def write(self, bytes): - """ - Process the given application bytes and send any resulting TLS traffic - which arrives in the send BIO. - - If C{loseConnection} was called, subsequent calls to C{write} will - drop the bytes on the floor. - """ - if isinstance(bytes, unicode): - raise TypeError("Must write bytes to a TLS transport, not unicode.") - # Writes after loseConnection are not supported, unless a producer has - # been registered, in which case writes can happen until the producer - # is unregistered: - if self.disconnecting and self._producer is None: - return - self._write(bytes) - - - def _write(self, bytes): - """ - Process the given application bytes and send any resulting TLS traffic - which arrives in the send BIO. - - This may be called by C{dataReceived} with bytes that were buffered - before C{loseConnection} was called, which is why this function - doesn't check for disconnection but accepts the bytes regardless. - """ - if self._lostTLSConnection: - return - - # A TLS payload is 16kB max - bufferSize = 2 ** 16 - - # How far into the input we've gotten so far - alreadySent = 0 - - while alreadySent < len(bytes): - toSend = bytes[alreadySent:alreadySent + bufferSize] - try: - sent = self._tlsConnection.send(toSend) - except WantReadError: - self._writeBlockedOnRead = True - self._appSendBuffer.append(bytes[alreadySent:]) - if self._producer is not None: - self._producer.pauseProducing() - break - except Error: - # Pretend TLS connection disconnected, which will trigger - # disconnect of underlying transport. The error will be passed - # to the application protocol's connectionLost method. The - # other SSL implementation doesn't, but losing helpful - # debugging information is a bad idea. - self._tlsShutdownFinished(Failure()) - break - else: - # If we sent some bytes, the handshake must be done. Keep - # track of this to control error reporting behavior. - self._handshakeDone = True - self._flushSendBIO() - alreadySent += sent - - - def writeSequence(self, iovec): - """ - Write a sequence of application bytes by joining them into one string - and passing them to L{write}. - """ - self.write(b"".join(iovec)) - - - def getPeerCertificate(self): - return self._tlsConnection.get_peer_certificate() - - - def registerProducer(self, producer, streaming): - # If we've already disconnected, nothing to do here: - if self._lostTLSConnection: - producer.stopProducing() - return - - # If we received a non-streaming producer, wrap it so it becomes a - # streaming producer: - if not streaming: - producer = streamingProducer = _PullToPush(producer, self) - producer = _ProducerMembrane(producer) - # This will raise an exception if a producer is already registered: - self.transport.registerProducer(producer, True) - self._producer = producer - # If we received a non-streaming producer, we need to start the - # streaming wrapper: - if not streaming: - streamingProducer.startStreaming() - - - def unregisterProducer(self): - # If we received a non-streaming producer, we need to stop the - # streaming wrapper: - if isinstance(self._producer._producer, _PullToPush): - self._producer._producer.stopStreaming() - self._producer = None - self._producerPaused = False - self.transport.unregisterProducer() - if self.disconnecting and not self._writeBlockedOnRead: - self._shutdownTLS() - - - -@implementer(IOpenSSLClientConnectionCreator, IOpenSSLServerConnectionCreator) -class _ContextFactoryToConnectionFactory(object): - """ - Adapter wrapping "something" (ideally something like a - L{twisted.internet.ssl.ContextFactory}; implementations of this interface - don't actually typically subclass though, so "something" is more likely - just something with a C{getContext} method) into an - L{IOpenSSLClientConnectionCreator} or L{IOpenSSLServerConnectionCreator}. - - See U{https://twistedmatrix.com/trac/ticket/7215} for work that should make - this unnecessary. - """ - - def __init__(self, oldStyleContextFactory): - """ - Construct a L{_ContextFactoryToConnectionFactory} with an old-style - context factory. - - Immediately call C{getContext} on C{oldStyleContextFactory} in order to - force advance parameter checking, since old-style context factories - don't actually check that their arguments to L{OpenSSL} are correct. - - @param oldStyleContextFactory: A factory that can produce contexts. - @type oldStyleContextFactory: L{twisted.internet.ssl.ContextFactory} or - something like it. - """ - oldStyleContextFactory.getContext() - self._oldStyleContextFactory = oldStyleContextFactory - - - def _connectionForTLS(self, protocol): - """ - Create an L{OpenSSL.SSL.Connection} object. - - @param protocol: The protocol initiating a TLS connection. - @type protocol: L{TLSMemoryBIOProtocol} - - @return: a connection - @rtype: L{OpenSSL.SSL.Connection} - """ - context = self._oldStyleContextFactory.getContext() - return Connection(context, None) - - - def serverConnectionForTLS(self, protocol): - """ - Construct an OpenSSL server connection from the wrapped old-style - context factory. - - @note: Since old-style context factories don't distinguish between - clients and servers, this is exactly the same as - L{_ContextFactoryToConnectionFactory.clientConnectionForTLS}. - - @param protocol: The protocol initiating a TLS connection. - @type protocol: L{TLSMemoryBIOProtocol} - - @return: a connection - @rtype: L{OpenSSL.SSL.Connection} - """ - return self._connectionForTLS(protocol) - - - def clientConnectionForTLS(self, protocol): - """ - Construct an OpenSSL server connection from the wrapped old-style - context factory. - - @note: Since old-style context factories don't distinguish between - clients and servers, this is exactly the same as - L{_ContextFactoryToConnectionFactory.serverConnectionForTLS}. - - @param protocol: The protocol initiating a TLS connection. - @type protocol: L{TLSMemoryBIOProtocol} - - @return: a connection - @rtype: L{OpenSSL.SSL.Connection} - """ - return self._connectionForTLS(protocol) - - - -class TLSMemoryBIOFactory(WrappingFactory): - """ - L{TLSMemoryBIOFactory} adds TLS to connections. - - @ivar _creatorInterface: the interface which L{_connectionCreator} is - expected to implement. - @type _creatorInterface: L{zope.interface.Interface} - - @ivar _connectionCreator: a callable which creates an OpenSSL Connection - object. - @type _connectionCreator: 1-argument callable taking - L{TLSMemoryBIOProtocol} and returning L{OpenSSL.SSL.Connection}. - """ - protocol = TLSMemoryBIOProtocol - - noisy = False # disable unnecessary logging. - - def __init__(self, contextFactory, isClient, wrappedFactory): - """ - Create a L{TLSMemoryBIOFactory}. - - @param contextFactory: Configuration parameters used to create an - OpenSSL connection. In order of preference, what you should pass - here should be: - - 1. L{twisted.internet.ssl.CertificateOptions} (if you're - writing a server) or the result of - L{twisted.internet.ssl.optionsForClientTLS} (if you're - writing a client). If you want security you should really - use one of these. - - 2. If you really want to implement something yourself, supply a - provider of L{IOpenSSLClientConnectionCreator} or - L{IOpenSSLServerConnectionCreator}. - - 3. If you really have to, supply a - L{twisted.internet.ssl.ContextFactory}. This will likely be - deprecated at some point so please upgrade to the new - interfaces. - - @type contextFactory: L{IOpenSSLClientConnectionCreator} or - L{IOpenSSLServerConnectionCreator}, or, for compatibility with - older code, L{twisted.internet.ssl.ContextFactory}. See - U{https://twistedmatrix.com/trac/ticket/7215} for information on - the upcoming deprecation of passing a - L{twisted.internet.ssl.ContextFactory} here. - - @param isClient: Is this a factory for TLS client connections; in other - words, those that will send a C{ClientHello} greeting? L{True} if - so, L{False} otherwise. This flag determines what interface is - expected of C{contextFactory}. If L{True}, C{contextFactory} - should provide L{IOpenSSLClientConnectionCreator}; otherwise it - should provide L{IOpenSSLServerConnectionCreator}. - @type isClient: L{bool} - - @param wrappedFactory: A factory which will create the - application-level protocol. - @type wrappedFactory: L{twisted.internet.interfaces.IProtocolFactory} - """ - WrappingFactory.__init__(self, wrappedFactory) - if isClient: - creatorInterface = IOpenSSLClientConnectionCreator - else: - creatorInterface = IOpenSSLServerConnectionCreator - self._creatorInterface = creatorInterface - if not creatorInterface.providedBy(contextFactory): - contextFactory = _ContextFactoryToConnectionFactory(contextFactory) - self._connectionCreator = contextFactory - - - def logPrefix(self): - """ - Annotate the wrapped factory's log prefix with some text indicating TLS - is in use. - - @rtype: C{str} - """ - if ILoggingContext.providedBy(self.wrappedFactory): - logPrefix = self.wrappedFactory.logPrefix() - else: - logPrefix = self.wrappedFactory.__class__.__name__ - return "%s (TLS)" % (logPrefix,) - - - def _createConnection(self, tlsProtocol): - """ - Create an OpenSSL connection and set it up good. - - @param tlsProtocol: The protocol which is establishing the connection. - @type tlsProtocol: L{TLSMemoryBIOProtocol} - - @return: an OpenSSL connection object for C{tlsProtocol} to use - @rtype: L{OpenSSL.SSL.Connection} - """ - connectionCreator = self._connectionCreator - if self._creatorInterface is IOpenSSLClientConnectionCreator: - connection = connectionCreator.clientConnectionForTLS(tlsProtocol) - connection.set_connect_state() - else: - connection = connectionCreator.serverConnectionForTLS(tlsProtocol) - connection.set_accept_state() - return connection - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/wire.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/wire.py deleted file mode 100644 index dddf215..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/protocols/wire.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Implement standard (and unused) TCP protocols. - -These protocols are either provided by inetd, or are not provided at all. -""" - -# system imports -import time, struct -from zope.interface import implements - -# twisted import -from twisted.internet import protocol, interfaces - - -class Echo(protocol.Protocol): - """As soon as any data is received, write it back (RFC 862)""" - - def dataReceived(self, data): - self.transport.write(data) - - -class Discard(protocol.Protocol): - """Discard any received data (RFC 863)""" - - def dataReceived(self, data): - # I'm ignoring you, nyah-nyah - pass - - -class Chargen(protocol.Protocol): - """Generate repeating noise (RFC 864)""" - noise = r'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&?' - - implements(interfaces.IProducer) - - def connectionMade(self): - self.transport.registerProducer(self, 0) - - def resumeProducing(self): - self.transport.write(self.noise) - - def pauseProducing(self): - pass - - def stopProducing(self): - pass - - -class QOTD(protocol.Protocol): - """Return a quote of the day (RFC 865)""" - - def connectionMade(self): - self.transport.write(self.getQuote()) - self.transport.loseConnection() - - def getQuote(self): - """Return a quote. May be overrriden in subclasses.""" - return "An apple a day keeps the doctor away.\r\n" - -class Who(protocol.Protocol): - """Return list of active users (RFC 866)""" - - def connectionMade(self): - self.transport.write(self.getUsers()) - self.transport.loseConnection() - - def getUsers(self): - """Return active users. Override in subclasses.""" - return "root\r\n" - - -class Daytime(protocol.Protocol): - """Send back the daytime in ASCII form (RFC 867)""" - - def connectionMade(self): - self.transport.write(time.asctime(time.gmtime(time.time())) + '\r\n') - self.transport.loseConnection() - - -class Time(protocol.Protocol): - """Send back the time in machine readable form (RFC 868)""" - - def connectionMade(self): - # is this correct only for 32-bit machines? - result = struct.pack("!i", int(time.time())) - self.transport.write(result) - self.transport.loseConnection() - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/__init__.py deleted file mode 100644 index ae78c7b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Python: Utilities and Enhancements for Python. - -""" - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_initgroups.c b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_initgroups.c deleted file mode 100644 index 93500b5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_initgroups.c +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - - Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved. - - This software is subject to the provisions of the Zope Public License, - Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. - THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED - WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS - FOR A PARTICULAR PURPOSE - - ****************************************************************************/ - -/* - * This has been reported for inclusion in Python here: http://bugs.python.org/issue7333 - * Hopefully we may be able to remove this file in some years. - */ - -#include "Python.h" - -#if defined(__unix__) || defined(unix) || defined(__NetBSD__) || defined(__MACH__) /* Mac OS X */ - -#include -#include -#include - -static PyObject * -initgroups_initgroups(PyObject *self, PyObject *args) -{ - char *username; - unsigned int igid; - gid_t gid; - - if (!PyArg_ParseTuple(args, "sI:initgroups", &username, &igid)) - return NULL; - - gid = igid; - - if (initgroups(username, gid) == -1) - return PyErr_SetFromErrno(PyExc_OSError); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef InitgroupsMethods[] = { - {"initgroups", initgroups_initgroups, METH_VARARGS}, - {NULL, NULL} -}; - -#else - -/* This module is empty on non-UNIX systems. */ - -static PyMethodDef InitgroupsMethods[] = { - {NULL, NULL} -}; - -#endif /* defined(__unix__) || defined(unix) */ - -void -init_initgroups(void) -{ - Py_InitModule("_initgroups", InitgroupsMethods); -} - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_inotify.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_inotify.py deleted file mode 100644 index dbbe688..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_inotify.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- test-case-name: twisted.internet.test.test_inotify -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Very low-level ctypes-based interface to Linux inotify(7). - -ctypes and a version of libc which supports inotify system calls are -required. -""" - -import ctypes -import ctypes.util - - - -class INotifyError(Exception): - """ - Unify all the possible exceptions that can be raised by the INotify API. - """ - - - -def init(): - """ - Create an inotify instance and return the associated file descriptor. - """ - fd = libc.inotify_init() - if fd < 0: - raise INotifyError("INotify initialization error.") - return fd - - - -def add(fd, path, mask): - """ - Add a watch for the given path to the inotify file descriptor, and return - the watch descriptor. - """ - wd = libc.inotify_add_watch(fd, path, mask) - if wd < 0: - raise INotifyError("Failed to add watch on '%r' - (%r)" % (path, wd)) - return wd - - - -def remove(fd, wd): - """ - Remove the given watch descriptor from the inotify file descriptor. - """ - # When inotify_rm_watch returns -1 there's an error: - # The errno for this call can be either one of the following: - # EBADF: fd is not a valid file descriptor. - # EINVAL: The watch descriptor wd is not valid; or fd is - # not an inotify file descriptor. - # - # if we can't access the errno here we cannot even raise - # an exception and we need to ignore the problem, one of - # the most common cases is when you remove a directory from - # the filesystem and that directory is observed. When inotify - # tries to call inotify_rm_watch with a non existing directory - # either of the 2 errors might come up because the files inside - # it might have events generated way before they were handled. - # Unfortunately only ctypes in Python 2.6 supports accessing errno: - # http://bugs.python.org/issue1798 and in order to solve - # the problem for previous versions we need to introduce - # code that is quite complex: - # http://stackoverflow.com/questions/661017/access-to-errno-from-python - # - # See #4310 for future resolution of this issue. - libc.inotify_rm_watch(fd, wd) - - - -def initializeModule(libc): - """ - Initialize the module, checking if the expected APIs exist and setting the - argtypes and restype for C{inotify_init}, C{inotify_add_watch}, and - C{inotify_rm_watch}. - """ - for function in ("inotify_add_watch", "inotify_init", "inotify_rm_watch"): - if getattr(libc, function, None) is None: - raise ImportError("libc6 2.4 or higher needed") - libc.inotify_init.argtypes = [] - libc.inotify_init.restype = ctypes.c_int - - libc.inotify_rm_watch.argtypes = [ - ctypes.c_int, ctypes.c_int] - libc.inotify_rm_watch.restype = ctypes.c_int - - libc.inotify_add_watch.argtypes = [ - ctypes.c_int, ctypes.c_char_p, ctypes.c_uint32] - libc.inotify_add_watch.restype = ctypes.c_int - - - -name = ctypes.util.find_library('c') -if not name: - raise ImportError("Can't find C library.") -libc = ctypes.cdll.LoadLibrary(name) -initializeModule(libc) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_release.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_release.py deleted file mode 100644 index 8d80d45..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_release.py +++ /dev/null @@ -1,1158 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_release -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted's automated release system. - -This module is only for use within Twisted's release system. If you are anyone -else, do not use it. The interface and behaviour will change without notice. - -Only Linux is supported by this code. It should not be used by any tools -which must run on multiple platforms (eg the setup.py script). -""" - -import textwrap -from datetime import date -import re -import sys -import os -from tempfile import mkdtemp -import tarfile - -from subprocess import PIPE, STDOUT, Popen - -from twisted.python.versions import Version -from twisted.python.filepath import FilePath -from twisted.python.dist import twisted_subprojects -from twisted.python.compat import execfile -from twisted.python.usage import Options, UsageError - -# The offset between a year and the corresponding major version number. -VERSION_OFFSET = 2000 - - -def runCommand(args): - """ - Execute a vector of arguments. - - @type args: C{list} of C{str} - @param args: A list of arguments, the first of which will be used as the - executable to run. - - @rtype: C{str} - @return: All of the standard output. - - @raise CommandFailed: when the program exited with a non-0 exit code. - """ - process = Popen(args, stdout=PIPE, stderr=STDOUT) - stdout = process.stdout.read() - exitCode = process.wait() - if exitCode < 0: - raise CommandFailed(None, -exitCode, stdout) - elif exitCode > 0: - raise CommandFailed(exitCode, None, stdout) - return stdout - - - -class CommandFailed(Exception): - """ - Raised when a child process exits unsuccessfully. - - @type exitStatus: C{int} - @ivar exitStatus: The exit status for the child process. - - @type exitSignal: C{int} - @ivar exitSignal: The exit signal for the child process. - - @type output: C{str} - @ivar output: The bytes read from stdout and stderr of the child process. - """ - def __init__(self, exitStatus, exitSignal, output): - Exception.__init__(self, exitStatus, exitSignal, output) - self.exitStatus = exitStatus - self.exitSignal = exitSignal - self.output = output - - - -def _changeVersionInFile(old, new, filename): - """ - Replace the C{old} version number with the C{new} one in the given - C{filename}. - """ - replaceInFile(filename, {old.base(): new.base()}) - - - -def getNextVersion(version, prerelease, patch, today): - """ - Calculate the version number for a new release of Twisted based on - the previous version number. - - @param version: The previous version number. - - @type prerelease: C{bool} - @param prerelease: If C{True}, make the next version a pre-release one. If - C{version} is a pre-release, it increments the pre-release counter, - otherwise create a new version with prerelease set to 1. - - @type patch: C{bool} - @param patch: If C{True}, make the next version a patch release. It - increments the micro counter. - - @type today: C{datetime} - @param today: The current date. - """ - micro = 0 - major = today.year - VERSION_OFFSET - if major != version.major: - minor = 0 - else: - minor = version.minor + 1 - - if patch: - micro = version.micro + 1 - major = version.major - minor = version.minor - - newPrerelease = None - if version.prerelease is not None: - major = version.major - minor = version.minor - micro = version.micro - if prerelease: - newPrerelease = version.prerelease + 1 - elif prerelease: - newPrerelease = 1 - return Version(version.package, major, minor, micro, newPrerelease) - - - -def changeAllProjectVersions(root, prerelease, patch, today=None): - """ - Change the version of all projects (including core and all subprojects). - - If the current version of a project is pre-release, then also change the - versions in the current NEWS entries for that project. - - @type root: L{FilePath} - @param root: The root of the Twisted source tree. - - @type prerelease: C{bool} - @param prerelease: - - @type patch: C{bool} - @param patch: - - @type today: C{datetime} - @param today: Defaults to the current day, according to the system clock. - """ - if not today: - today = date.today() - formattedToday = today.strftime('%Y-%m-%d') - for project in findTwistedProjects(root): - if project.directory.basename() == "twisted": - packageName = "twisted" - else: - packageName = "twisted." + project.directory.basename() - oldVersion = project.getVersion() - newVersion = getNextVersion(oldVersion, prerelease, patch, today) - if oldVersion.prerelease: - builder = NewsBuilder() - builder._changeNewsVersion( - root.child("NEWS"), builder._getNewsName(project), - oldVersion, newVersion, formattedToday) - builder._changeNewsVersion( - project.directory.child("topfiles").child("NEWS"), - builder._getNewsName(project), oldVersion, newVersion, - formattedToday) - - # The placement of the top-level README with respect to other files (eg - # _version.py) is sufficiently different from the others that we just - # have to handle it specially. - if packageName == "twisted": - _changeVersionInFile( - oldVersion, newVersion, root.child('README').path) - - project.updateVersion(newVersion) - - - -class Project(object): - """ - A representation of a project that has a version. - - @ivar directory: A L{twisted.python.filepath.FilePath} pointing to the base - directory of a Twisted-style Python package. The package should contain - a C{_version.py} file and a C{topfiles} directory that contains a - C{README} file. - """ - - def __init__(self, directory): - self.directory = directory - - - def __repr__(self): - return '%s(%r)' % ( - self.__class__.__name__, self.directory) - - - def getVersion(self): - """ - @return: A L{Version} specifying the version number of the project - based on live python modules. - """ - namespace = {} - execfile(self.directory.child("_version.py").path, namespace) - return namespace["version"] - - - def updateVersion(self, version): - """ - Replace the existing version numbers in _version.py and README files - with the specified version. - """ - oldVersion = self.getVersion() - replaceProjectVersion(self.directory.child("_version.py").path, - version) - _changeVersionInFile( - oldVersion, version, - self.directory.child("topfiles").child("README").path) - - - -def findTwistedProjects(baseDirectory): - """ - Find all Twisted-style projects beneath a base directory. - - @param baseDirectory: A L{twisted.python.filepath.FilePath} to look inside. - @return: A list of L{Project}. - """ - projects = [] - for filePath in baseDirectory.walk(): - if filePath.basename() == 'topfiles': - projectDirectory = filePath.parent() - projects.append(Project(projectDirectory)) - return projects - - - - -def generateVersionFileData(version): - """ - Generate the data to be placed into a _version.py file. - - @param version: A version object. - """ - if version.prerelease is not None: - prerelease = ", prerelease=%r" % (version.prerelease,) - else: - prerelease = "" - data = '''\ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This is an auto-generated file. Do not edit it. - -""" -Provides Twisted version information. -""" - -from twisted.python import versions -version = versions.Version(%r, %s, %s, %s%s) -''' % (version.package, version.major, version.minor, version.micro, - prerelease) - return data - - - -def replaceProjectVersion(filename, newversion): - """ - Write version specification code into the given filename, which - sets the version to the given version number. - - @param filename: A filename which is most likely a "_version.py" - under some Twisted project. - @param newversion: A version object. - """ - # XXX - this should be moved to Project and renamed to writeVersionFile. - # jml, 2007-11-15. - f = open(filename, 'w') - f.write(generateVersionFileData(newversion)) - f.close() - - - -def replaceInFile(filename, oldToNew): - """ - I replace the text `oldstr' with `newstr' in `filename' using science. - """ - os.rename(filename, filename + '.bak') - f = open(filename + '.bak') - d = f.read() - f.close() - for k, v in oldToNew.items(): - d = d.replace(k, v) - f = open(filename + '.new', 'w') - f.write(d) - f.close() - os.rename(filename + '.new', filename) - os.unlink(filename + '.bak') - - - -class NoDocumentsFound(Exception): - """ - Raised when no input documents are found. - """ - - - -class APIBuilder(object): - """ - Generate API documentation from source files using - U{pydoctor}. This requires - pydoctor to be installed and usable. - """ - def build(self, projectName, projectURL, sourceURL, packagePath, - outputPath): - """ - Call pydoctor's entry point with options which will generate HTML - documentation for the specified package's API. - - @type projectName: C{str} - @param projectName: The name of the package for which to generate - documentation. - - @type projectURL: C{str} - @param projectURL: The location (probably an HTTP URL) of the project - on the web. - - @type sourceURL: C{str} - @param sourceURL: The location (probably an HTTP URL) of the root of - the source browser for the project. - - @type packagePath: L{FilePath} - @param packagePath: The path to the top-level of the package named by - C{projectName}. - - @type outputPath: L{FilePath} - @param outputPath: An existing directory to which the generated API - documentation will be written. - """ - from pydoctor.driver import main - main( - ["--project-name", projectName, - "--project-url", projectURL, - "--system-class", "pydoctor.twistedmodel.TwistedSystem", - "--project-base-dir", packagePath.parent().path, - "--html-viewsource-base", sourceURL, - "--add-package", packagePath.path, - "--html-output", outputPath.path, - "--html-write-function-pages", "--quiet", "--make-html"]) - - - -class NewsBuilder(object): - """ - Generate the new section of a NEWS file. - - The C{_FEATURE}, C{_BUGFIX}, C{_DOC}, C{_REMOVAL}, and C{_MISC} - attributes of this class are symbolic names for the news entry types - which are supported. Conveniently, they each also take on the value of - the file name extension which indicates a news entry of that type. - - @cvar _headings: A C{dict} mapping one of the news entry types to the - heading to write out for that type of news entry. - - @cvar _NO_CHANGES: A C{str} giving the text which appears when there are - no significant changes in a release. - - @cvar _TICKET_HINT: A C{str} giving the text which appears at the top of - each news file and which should be kept at the top, not shifted down - with all the other content. Put another way, this is the text after - which the new news text is inserted. - """ - - _FEATURE = ".feature" - _BUGFIX = ".bugfix" - _DOC = ".doc" - _REMOVAL = ".removal" - _MISC = ".misc" - - _headings = { - _FEATURE: "Features", - _BUGFIX: "Bugfixes", - _DOC: "Improved Documentation", - _REMOVAL: "Deprecations and Removals", - _MISC: "Other"} - - _NO_CHANGES = "No significant changes have been made for this release.\n" - - _TICKET_HINT = ( - 'Ticket numbers in this file can be looked up by visiting\n' - 'http://twistedmatrix.com/trac/ticket/\n' - '\n') - - def _today(self): - """ - Return today's date as a string in YYYY-MM-DD format. - """ - return date.today().strftime('%Y-%m-%d') - - - def _findChanges(self, path, ticketType): - """ - Load all the feature ticket summaries. - - @param path: A L{FilePath} the direct children of which to search - for news entries. - - @param ticketType: The type of news entries to search for. One of - L{NewsBuilder._FEATURE}, L{NewsBuilder._BUGFIX}, - L{NewsBuilder._REMOVAL}, or L{NewsBuilder._MISC}. - - @return: A C{list} of two-tuples. The first element is the ticket - number as an C{int}. The second element of each tuple is the - description of the feature. - """ - results = [] - for child in path.children(): - base, ext = os.path.splitext(child.basename()) - if ext == ticketType: - results.append(( - int(base), - ' '.join(child.getContent().splitlines()))) - results.sort() - return results - - - def _formatHeader(self, header): - """ - Format a header for a NEWS file. - - A header is a title with '=' signs underlining it. - - @param header: The header string to format. - @type header: C{str} - @return: A C{str} containing C{header}. - """ - return header + '\n' + '=' * len(header) + '\n\n' - - - def _writeHeader(self, fileObj, header): - """ - Write a version header to the given file. - - @param fileObj: A file-like object to which to write the header. - @param header: The header to write to the file. - @type header: C{str} - """ - fileObj.write(self._formatHeader(header)) - - - def _writeSection(self, fileObj, header, tickets): - """ - Write out one section (features, bug fixes, etc) to the given file. - - @param fileObj: A file-like object to which to write the news section. - - @param header: The header for the section to write. - @type header: C{str} - - @param tickets: A C{list} of ticket information of the sort returned - by L{NewsBuilder._findChanges}. - """ - if not tickets: - return - - reverse = {} - for (ticket, description) in tickets: - reverse.setdefault(description, []).append(ticket) - for description in reverse: - reverse[description].sort() - reverse = reverse.items() - reverse.sort(key=lambda (descr, tickets): tickets[0]) - - fileObj.write(header + '\n' + '-' * len(header) + '\n') - for (description, relatedTickets) in reverse: - ticketList = ', '.join([ - '#' + str(ticket) for ticket in relatedTickets]) - entry = ' - %s (%s)' % (description, ticketList) - entry = textwrap.fill(entry, subsequent_indent=' ') - fileObj.write(entry + '\n') - fileObj.write('\n') - - - def _writeMisc(self, fileObj, header, tickets): - """ - Write out a miscellaneous-changes section to the given file. - - @param fileObj: A file-like object to which to write the news section. - - @param header: The header for the section to write. - @type header: C{str} - - @param tickets: A C{list} of ticket information of the sort returned - by L{NewsBuilder._findChanges}. - """ - if not tickets: - return - - fileObj.write(header + '\n' + '-' * len(header) + '\n') - formattedTickets = [] - for (ticket, ignored) in tickets: - formattedTickets.append('#' + str(ticket)) - entry = ' - ' + ', '.join(formattedTickets) - entry = textwrap.fill(entry, subsequent_indent=' ') - fileObj.write(entry + '\n\n') - - - def build(self, path, output, header): - """ - Load all of the change information from the given directory and write - it out to the given output file. - - @param path: A directory (probably a I{topfiles} directory) containing - change information in the form of . files. - @type path: L{FilePath} - - @param output: The NEWS file to which the results will be prepended. - @type output: L{FilePath} - - @param header: The top-level header to use when writing the news. - @type header: L{str} - - @raise NotWorkingDirectory: If the C{path} is not an SVN checkout. - """ - changes = [] - for part in (self._FEATURE, self._BUGFIX, self._DOC, self._REMOVAL): - tickets = self._findChanges(path, part) - if tickets: - changes.append((part, tickets)) - misc = self._findChanges(path, self._MISC) - - oldNews = output.getContent() - newNews = output.sibling('NEWS.new').open('w') - if oldNews.startswith(self._TICKET_HINT): - newNews.write(self._TICKET_HINT) - oldNews = oldNews[len(self._TICKET_HINT):] - - self._writeHeader(newNews, header) - if changes: - for (part, tickets) in changes: - self._writeSection(newNews, self._headings.get(part), tickets) - else: - newNews.write(self._NO_CHANGES) - newNews.write('\n') - self._writeMisc(newNews, self._headings.get(self._MISC), misc) - newNews.write('\n') - newNews.write(oldNews) - newNews.close() - output.sibling('NEWS.new').moveTo(output) - - - def _deleteFragments(self, path): - """ - Delete the change information, to clean up the repository once the - NEWS files have been built. It requires C{path} to be in a SVN - directory. - - @param path: A directory (probably a I{topfiles} directory) containing - change information in the form of . files. - @type path: L{FilePath} - """ - ticketTypes = self._headings.keys() - for child in path.children(): - base, ext = os.path.splitext(child.basename()) - if ext in ticketTypes: - runCommand(["svn", "rm", child.path]) - - - def _getNewsName(self, project): - """ - Return the name of C{project} that should appear in NEWS. - - @param project: A L{Project} - @return: The name of C{project}. - """ - name = project.directory.basename().title() - if name == 'Twisted': - name = 'Core' - return name - - - def _iterProjects(self, baseDirectory): - """ - Iterate through the Twisted projects in C{baseDirectory}, yielding - everything we need to know to build news for them. - - Yields C{topfiles}, C{name}, C{version}, for each sub-project in - reverse-alphabetical order. C{topfile} is the L{FilePath} for the - topfiles directory, C{name} is the nice name of the project (as should - appear in the NEWS file), C{version} is the current version string for - that project. - - @param baseDirectory: A L{FilePath} representing the root directory - beneath which to find Twisted projects for which to generate - news (see L{findTwistedProjects}). - @type baseDirectory: L{FilePath} - """ - # Get all the subprojects to generate news for - projects = findTwistedProjects(baseDirectory) - # And order them alphabetically for ease of reading - projects.sort(key=lambda proj: proj.directory.path) - # And generate them backwards since we write news by prepending to - # files. - projects.reverse() - - for project in projects: - topfiles = project.directory.child("topfiles") - name = self._getNewsName(project) - version = project.getVersion() - yield topfiles, name, version - - - def buildAll(self, baseDirectory): - """ - Find all of the Twisted subprojects beneath C{baseDirectory} and update - their news files from the ticket change description files in their - I{topfiles} directories and update the news file in C{baseDirectory} - with all of the news. - - @param baseDirectory: A L{FilePath} representing the root directory - beneath which to find Twisted projects for which to generate - news (see L{findTwistedProjects}). - """ - try: - runCommand(["svn", "info", baseDirectory.path]) - except CommandFailed: - raise NotWorkingDirectory( - "%s does not appear to be an SVN working directory." - % (baseDirectory.path,)) - - today = self._today() - for topfiles, name, version in self._iterProjects(baseDirectory): - # We first build for the subproject - news = topfiles.child("NEWS") - header = "Twisted %s %s (%s)" % (name, version.base(), today) - self.build(topfiles, news, header) - # Then for the global NEWS file - news = baseDirectory.child("NEWS") - self.build(topfiles, news, header) - # Finally, delete the fragments - self._deleteFragments(topfiles) - - - def _changeNewsVersion(self, news, name, oldVersion, newVersion, today): - """ - Change all references to the current version number in a NEWS file to - refer to C{newVersion} instead. - - @param news: The NEWS file to change. - @type news: L{FilePath} - @param name: The name of the project to change. - @type name: C{str} - @param oldVersion: The old version of the project. - @type oldVersion: L{Version} - @param newVersion: The new version of the project. - @type newVersion: L{Version} - @param today: A YYYY-MM-DD string representing today's date. - @type today: C{str} - """ - newHeader = self._formatHeader( - "Twisted %s %s (%s)" % (name, newVersion.base(), today)) - expectedHeaderRegex = re.compile( - r"Twisted %s %s \(\d{4}-\d\d-\d\d\)\n=+\n\n" % ( - re.escape(name), re.escape(oldVersion.base()))) - oldNews = news.getContent() - match = expectedHeaderRegex.search(oldNews) - if match: - oldHeader = match.group() - replaceInFile(news.path, {oldHeader: newHeader}) - - - def main(self, args): - """ - Build all news files. - - @param args: The command line arguments to process. This must contain - one string, the path to the base of the Twisted checkout for which - to build the news. - @type args: C{list} of C{str} - """ - if len(args) != 1: - sys.exit("Must specify one argument: the path to the " - "Twisted checkout") - self.buildAll(FilePath(args[0])) - - - -class SphinxBuilder(object): - """ - Generate HTML documentation using Sphinx. - - Generates and runs a shell command that looks something like:: - - sphinx-build -b html -d [BUILDDIR]/doctrees - [DOCDIR]/source - [BUILDDIR]/html - - where DOCDIR is a directory containing another directory called "source" - which contains the Sphinx source files, and BUILDDIR is the directory in - which the Sphinx output will be created. - """ - - def main(self, args): - """ - Build the main documentation. - - @type args: list of str - @param args: The command line arguments to process. This must contain - one string argument: the path to the root of a Twisted checkout. - Additional arguments will be ignored for compatibility with legacy - build infrastructure. - """ - self.build(FilePath(args[0]).child("docs")) - - - def build(self, docDir, buildDir=None, version=''): - """ - Build the documentation in C{docDir} with Sphinx. - - @param docDir: The directory of the documentation. This is a directory - which contains another directory called "source" which contains the - Sphinx "conf.py" file and sphinx source documents. - @type docDir: L{twisted.python.filepath.FilePath} - - @param buildDir: The directory to build the documentation in. By - default this will be a child directory of {docDir} named "build". - @type buildDir: L{twisted.python.filepath.FilePath} - - @param version: The version of Twisted to set in the docs. - @type version: C{str} - """ - if buildDir is None: - buildDir = docDir.parent().child('doc') - - doctreeDir = buildDir.child('doctrees') - - runCommand(['sphinx-build', '-b', 'html', - '-d', doctreeDir.path, docDir.path, - buildDir.path]) - - for path in docDir.walk(): - if path.basename() == "man": - segments = path.segmentsFrom(docDir) - dest = buildDir - while segments: - dest = dest.child(segments.pop(0)) - if not dest.parent().isdir(): - dest.parent().makedirs() - path.copyTo(dest) - - - -def filePathDelta(origin, destination): - """ - Return a list of strings that represent C{destination} as a path relative - to C{origin}. - - It is assumed that both paths represent directories, not files. That is to - say, the delta of L{twisted.python.filepath.FilePath} /foo/bar to - L{twisted.python.filepath.FilePath} /foo/baz will be C{../baz}, - not C{baz}. - - @type origin: L{twisted.python.filepath.FilePath} - @param origin: The origin of the relative path. - - @type destination: L{twisted.python.filepath.FilePath} - @param destination: The destination of the relative path. - """ - commonItems = 0 - path1 = origin.path.split(os.sep) - path2 = destination.path.split(os.sep) - for elem1, elem2 in zip(path1, path2): - if elem1 == elem2: - commonItems += 1 - else: - break - path = [".."] * (len(path1) - commonItems) - return path + path2[commonItems:] - - - -class DistributionBuilder(object): - """ - A builder of Twisted distributions. - - This knows how to build tarballs for Twisted and all of its subprojects. - """ - subprojects = twisted_subprojects - - def __init__(self, rootDirectory, outputDirectory, templatePath=None): - """ - Create a distribution builder. - - @param rootDirectory: root of a Twisted export which will populate - subsequent tarballs. - @type rootDirectory: L{FilePath}. - - @param outputDirectory: The directory in which to create the tarballs. - @type outputDirectory: L{FilePath} - - @param templatePath: Path to the template file that is used for the - howto documentation. - @type templatePath: L{FilePath} - """ - self.rootDirectory = rootDirectory - self.outputDirectory = outputDirectory - self.templatePath = templatePath - - - def buildTwisted(self, version): - """ - Build the main Twisted distribution in C{Twisted-.tar.bz2}. - - bin/admin is excluded. - - @type version: C{str} - @param version: The version of Twisted to build. - - @return: The tarball file. - @rtype: L{FilePath}. - """ - releaseName = "Twisted-%s" % (version,) - buildPath = lambda *args: '/'.join((releaseName,) + args) - - outputFile = self.outputDirectory.child(releaseName + ".tar.bz2") - tarball = tarfile.TarFile.open(outputFile.path, 'w:bz2') - - docPath = self.rootDirectory.child("docs") - - # Generate docs! - if docPath.isdir(): - SphinxBuilder().build(docPath) - - for binthing in self.rootDirectory.child("bin").children(): - # bin/admin should not be included. - if binthing.basename() != "admin": - tarball.add(binthing.path, - buildPath("bin", binthing.basename())) - - for submodule in self.rootDirectory.child("twisted").children(): - if submodule.basename() == "plugins": - for plugin in submodule.children(): - tarball.add(plugin.path, buildPath("twisted", "plugins", - plugin.basename())) - else: - tarball.add(submodule.path, buildPath("twisted", - submodule.basename())) - - for docDir in self.rootDirectory.child("doc").children(): - if docDir.basename() != "historic": - tarball.add(docDir.path, buildPath("doc", docDir.basename())) - - for toplevel in self.rootDirectory.children(): - if not toplevel.isdir(): - tarball.add(toplevel.path, buildPath(toplevel.basename())) - - tarball.close() - - return outputFile - - - def buildCore(self, version): - """ - Build a core distribution in C{TwistedCore-.tar.bz2}. - - This is very similar to L{buildSubProject}, but core tarballs and the - input are laid out slightly differently. - - - scripts are in the top level of the C{bin} directory. - - code is included directly from the C{twisted} directory, excluding - subprojects. - - all plugins except the subproject plugins are included. - - @type version: C{str} - @param version: The version of Twisted to build. - - @return: The tarball file. - @rtype: L{FilePath}. - """ - releaseName = "TwistedCore-%s" % (version,) - outputFile = self.outputDirectory.child(releaseName + ".tar.bz2") - buildPath = lambda *args: '/'.join((releaseName,) + args) - tarball = self._createBasicSubprojectTarball( - "core", version, outputFile) - - # Include the bin directory for the subproject. - for path in self.rootDirectory.child("bin").children(): - if not path.isdir(): - tarball.add(path.path, buildPath("bin", path.basename())) - - # Include all files within twisted/ that aren't part of a subproject. - for path in self.rootDirectory.child("twisted").children(): - if path.basename() == "plugins": - for plugin in path.children(): - for subproject in self.subprojects: - if (plugin.basename() == - "twisted_%s.py" % (subproject,)): - break - else: - tarball.add(plugin.path, - buildPath("twisted", "plugins", - plugin.basename())) - elif not path.basename() in self.subprojects + ["topfiles"]: - tarball.add(path.path, buildPath("twisted", path.basename())) - - tarball.add(self.rootDirectory.child("twisted").child("topfiles").path, - releaseName) - tarball.close() - - return outputFile - - - def buildSubProject(self, projectName, version): - """ - Build a subproject distribution in - C{Twisted-.tar.bz2}. - - @type projectName: C{str} - @param projectName: The lowercase name of the subproject to build. - @type version: C{str} - @param version: The version of Twisted to build. - - @return: The tarball file. - @rtype: L{FilePath}. - """ - releaseName = "Twisted%s-%s" % (projectName.capitalize(), version) - outputFile = self.outputDirectory.child(releaseName + ".tar.bz2") - buildPath = lambda *args: '/'.join((releaseName,) + args) - subProjectDir = self.rootDirectory.child("twisted").child(projectName) - - tarball = self._createBasicSubprojectTarball(projectName, version, - outputFile) - - tarball.add(subProjectDir.child("topfiles").path, releaseName) - - # Include all files in the subproject package except for topfiles. - for child in subProjectDir.children(): - name = child.basename() - if name != "topfiles": - tarball.add( - child.path, - buildPath("twisted", projectName, name)) - - pluginsDir = self.rootDirectory.child("twisted").child("plugins") - # Include the plugin for the subproject. - pluginFileName = "twisted_%s.py" % (projectName,) - pluginFile = pluginsDir.child(pluginFileName) - if pluginFile.exists(): - tarball.add(pluginFile.path, - buildPath("twisted", "plugins", pluginFileName)) - - # Include the bin directory for the subproject. - binPath = self.rootDirectory.child("bin").child(projectName) - if binPath.isdir(): - tarball.add(binPath.path, buildPath("bin")) - tarball.close() - - return outputFile - - - def _createBasicSubprojectTarball(self, projectName, version, outputFile): - """ - Helper method to create and fill a tarball with things common between - subprojects and core. - - @param projectName: The subproject's name. - @type projectName: C{str} - @param version: The version of the release. - @type version: C{str} - @param outputFile: The location of the tar file to create. - @type outputFile: L{FilePath} - """ - releaseName = "Twisted%s-%s" % (projectName.capitalize(), version) - buildPath = lambda *args: '/'.join((releaseName,) + args) - - tarball = tarfile.TarFile.open(outputFile.path, 'w:bz2') - - tarball.add(self.rootDirectory.child("LICENSE").path, - buildPath("LICENSE")) - return tarball - - - -class UncleanWorkingDirectory(Exception): - """ - Raised when the working directory of an SVN checkout is unclean. - """ - - - -class NotWorkingDirectory(Exception): - """ - Raised when a directory does not appear to be an SVN working directory. - """ - - - -def buildAllTarballs(checkout, destination, templatePath=None): - """ - Build complete tarballs (including documentation) for Twisted and all - subprojects. - - This should be called after the version numbers have been updated and - NEWS files created. - - @type checkout: L{FilePath} - @param checkout: The SVN working copy from which a pristine source tree - will be exported. - @type destination: L{FilePath} - @param destination: The directory in which tarballs will be placed. - @type templatePath: L{FilePath} - @param templatePath: Location of the template file that is used for the - howto documentation. - - @raise UncleanWorkingDirectory: If there are modifications to the - working directory of C{checkout}. - @raise NotWorkingDirectory: If the C{checkout} path is not an SVN checkout. - """ - if not checkout.child(".svn").exists(): - raise NotWorkingDirectory( - "%s does not appear to be an SVN working directory." - % (checkout.path,)) - if runCommand(["svn", "st", checkout.path]).strip(): - raise UncleanWorkingDirectory( - "There are local modifications to the SVN checkout in %s." - % (checkout.path,)) - - workPath = FilePath(mkdtemp()) - export = workPath.child("export") - runCommand(["svn", "export", checkout.path, export.path]) - twistedPath = export.child("twisted") - version = Project(twistedPath).getVersion() - versionString = version.base() - - if not destination.exists(): - destination.createDirectory() - db = DistributionBuilder(export, destination, templatePath=templatePath) - - db.buildCore(versionString) - for subproject in twisted_subprojects: - if twistedPath.child(subproject).exists(): - db.buildSubProject(subproject, versionString) - - db.buildTwisted(versionString) - workPath.remove() - - - -class ChangeVersionsScriptOptions(Options): - """ - Options for L{ChangeVersionsScript}. - """ - optFlags = [["prerelease", None, "Change to the next prerelease"], - ["patch", None, "Make a patch version"]] - - - -class ChangeVersionsScript(object): - """ - A thing for changing version numbers. See L{main}. - """ - changeAllProjectVersions = staticmethod(changeAllProjectVersions) - - def main(self, args): - """ - Given a list of command-line arguments, change all the Twisted versions - in the current directory. - - @type args: list of str - @param args: List of command line arguments. This should only - contain the version number. - """ - options = ChangeVersionsScriptOptions() - - try: - options.parseOptions(args) - except UsageError as e: - raise SystemExit(e) - - self.changeAllProjectVersions(FilePath("."), options["prerelease"], - options["patch"]) - - - -class BuildTarballsScript(object): - """ - A thing for building release tarballs. See L{main}. - """ - buildAllTarballs = staticmethod(buildAllTarballs) - - def main(self, args): - """ - Build all release tarballs. - - @type args: list of C{str} - @param args: The command line arguments to process. This must contain - at least two strings: the checkout directory and the destination - directory. An optional third string can be specified for the - website template file, used for building the howto documentation. - If this string isn't specified, the default template included in - twisted will be used. - """ - if len(args) < 2 or len(args) > 3: - sys.exit("Must specify at least two arguments: " - "Twisted checkout and destination path. The optional " - "third argument is the website template path.") - if len(args) == 2: - self.buildAllTarballs(FilePath(args[0]), FilePath(args[1])) - elif len(args) == 3: - self.buildAllTarballs(FilePath(args[0]), FilePath(args[1]), - FilePath(args[2])) - - - -class BuildAPIDocsScript(object): - """ - A thing for building API documentation. See L{main}. - """ - - def buildAPIDocs(self, projectRoot, output): - """ - Build the API documentation of Twisted, with our project policy. - - @param projectRoot: A L{FilePath} representing the root of the Twisted - checkout. - @param output: A L{FilePath} pointing to the desired output directory. - """ - version = Project(projectRoot.child("twisted")).getVersion() - versionString = version.base() - sourceURL = ("http://twistedmatrix.com/trac/browser/tags/releases/" - "twisted-%s" % (versionString,)) - apiBuilder = APIBuilder() - apiBuilder.build( - "Twisted", - "http://twistedmatrix.com/", - sourceURL, - projectRoot.child("twisted"), - output) - - - def main(self, args): - """ - Build API documentation. - - @type args: list of str - @param args: The command line arguments to process. This must contain - two strings: the path to the root of the Twisted checkout, and a - path to an output directory. - """ - if len(args) != 2: - sys.exit("Must specify two arguments: " - "Twisted checkout and destination path") - self.buildAPIDocs(FilePath(args[0]), FilePath(args[1])) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_shellcomp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_shellcomp.py deleted file mode 100644 index 6ec9ccb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_shellcomp.py +++ /dev/null @@ -1,664 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_shellcomp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -No public APIs are provided by this module. Internal use only. - -This module implements dynamic tab-completion for any command that uses -twisted.python.usage. Currently, only zsh is supported. Bash support may -be added in the future. - -Maintainer: Eric P. Mangold - twisted AT teratorn DOT org - -In order for zsh completion to take place the shell must be able to find an -appropriate "stub" file ("completion function") that invokes this code and -displays the results to the user. - -The stub used for Twisted commands is in the file C{twisted-completion.zsh}, -which is also included in the official Zsh distribution at -C{Completion/Unix/Command/_twisted}. Use this file as a basis for completion -functions for your own commands. You should only need to change the first line -to something like C{#compdef mycommand}. - -The main public documentation exists in the L{twisted.python.usage.Options} -docstring, the L{twisted.python.usage.Completions} docstring, and the -Options howto. -""" -import itertools, getopt, inspect - -from twisted.python import reflect, util, usage - - - -def shellComplete(config, cmdName, words, shellCompFile): - """ - Perform shell completion. - - A completion function (shell script) is generated for the requested - shell and written to C{shellCompFile}, typically C{stdout}. The result - is then eval'd by the shell to produce the desired completions. - - @type config: L{twisted.python.usage.Options} - @param config: The L{twisted.python.usage.Options} instance to generate - completions for. - - @type cmdName: C{str} - @param cmdName: The name of the command we're generating completions for. - In the case of zsh, this is used to print an appropriate - "#compdef $CMD" line at the top of the output. This is - not necessary for the functionality of the system, but it - helps in debugging, since the output we produce is properly - formed and may be saved in a file and used as a stand-alone - completion function. - - @type words: C{list} of C{str} - @param words: The raw command-line words passed to use by the shell - stub function. argv[0] has already been stripped off. - - @type shellCompFile: C{file} - @param shellCompFile: The file to write completion data to. - """ - # shellName is provided for forward-compatibility. It is not used, - # since we currently only support zsh. - shellName, position = words[-1].split(":") - position = int(position) - # zsh gives the completion position ($CURRENT) as a 1-based index, - # and argv[0] has already been stripped off, so we subtract 2 to - # get the real 0-based index. - position -= 2 - cWord = words[position] - - # since the user may hit TAB at any time, we may have been called with an - # incomplete command-line that would generate getopt errors if parsed - # verbatim. However, we must do *some* parsing in order to determine if - # there is a specific subcommand that we need to provide completion for. - # So, to make the command-line more sane we work backwards from the - # current completion position and strip off all words until we find one - # that "looks" like a subcommand. It may in fact be the argument to a - # normal command-line option, but that won't matter for our purposes. - while position >= 1: - if words[position - 1].startswith("-"): - position -= 1 - else: - break - words = words[:position] - - subCommands = getattr(config, 'subCommands', None) - if subCommands: - # OK, this command supports sub-commands, so lets see if we have been - # given one. - - # If the command-line arguments are not valid then we won't be able to - # sanely detect the sub-command, so just generate completions as if no - # sub-command was found. - args = None - try: - opts, args = getopt.getopt(words, - config.shortOpt, config.longOpt) - except getopt.error: - pass - - if args: - # yes, we have a subcommand. Try to find it. - for (cmd, short, parser, doc) in config.subCommands: - if args[0] == cmd or args[0] == short: - subOptions = parser() - subOptions.parent = config - - gen = ZshSubcommandBuilder(subOptions, config, cmdName, - shellCompFile) - gen.write() - return - - # sub-command not given, or did not match any knowns sub-command names - genSubs = True - if cWord.startswith("-"): - # optimization: if the current word being completed starts - # with a hyphen then it can't be a sub-command, so skip - # the expensive generation of the sub-command list - genSubs = False - gen = ZshBuilder(config, cmdName, shellCompFile) - gen.write(genSubs=genSubs) - else: - gen = ZshBuilder(config, cmdName, shellCompFile) - gen.write() - - - -class SubcommandAction(usage.Completer): - def _shellCode(self, optName, shellType): - if shellType == usage._ZSH: - return '*::subcmd:->subcmd' - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class ZshBuilder(object): - """ - Constructs zsh code that will complete options for a given usage.Options - instance, possibly including a list of subcommand names. - - Completions for options to subcommands won't be generated because this - class will never be used if the user is completing options for a specific - subcommand. (See L{ZshSubcommandBuilder} below) - - @type options: L{twisted.python.usage.Options} - @ivar options: The L{twisted.python.usage.Options} instance defined for this - command. - - @type cmdName: C{str} - @ivar cmdName: The name of the command we're generating completions for. - - @type file: C{file} - @ivar file: The C{file} to write the completion function to. - """ - def __init__(self, options, cmdName, file): - self.options = options - self.cmdName = cmdName - self.file = file - - - def write(self, genSubs=True): - """ - Generate the completion function and write it to the output file - @return: C{None} - - @type genSubs: C{bool} - @param genSubs: Flag indicating whether or not completions for the list - of subcommand should be generated. Only has an effect - if the C{subCommands} attribute has been defined on the - L{twisted.python.usage.Options} instance. - """ - if genSubs and getattr(self.options, 'subCommands', None) is not None: - gen = ZshArgumentsGenerator(self.options, self.cmdName, self.file) - gen.extraActions.insert(0, SubcommandAction()) - gen.write() - self.file.write('local _zsh_subcmds_array\n_zsh_subcmds_array=(\n') - for (cmd, short, parser, desc) in self.options.subCommands: - self.file.write('"%s:%s"\n' % (cmd, desc)) - self.file.write(")\n\n") - self.file.write('_describe "sub-command" _zsh_subcmds_array\n') - else: - gen = ZshArgumentsGenerator(self.options, self.cmdName, self.file) - gen.write() - - - -class ZshSubcommandBuilder(ZshBuilder): - """ - Constructs zsh code that will complete options for a given usage.Options - instance, and also for a single sub-command. This will only be used in - the case where the user is completing options for a specific subcommand. - - @type subOptions: L{twisted.python.usage.Options} - @ivar subOptions: The L{twisted.python.usage.Options} instance defined for - the sub command. - """ - def __init__(self, subOptions, *args): - self.subOptions = subOptions - ZshBuilder.__init__(self, *args) - - - def write(self): - """ - Generate the completion function and write it to the output file - @return: C{None} - """ - gen = ZshArgumentsGenerator(self.options, self.cmdName, self.file) - gen.extraActions.insert(0, SubcommandAction()) - gen.write() - - gen = ZshArgumentsGenerator(self.subOptions, self.cmdName, self.file) - gen.write() - - - -class ZshArgumentsGenerator(object): - """ - Generate a call to the zsh _arguments completion function - based on data in a usage.Options instance - - @type options: L{twisted.python.usage.Options} - @ivar options: The L{twisted.python.usage.Options} instance to generate for - - @type cmdName: C{str} - @ivar cmdName: The name of the command we're generating completions for. - - @type file: C{file} - @ivar file: The C{file} to write the completion function to - - The following non-constructor variables are populated by this class - with data gathered from the C{Options} instance passed in, and its - base classes. - - @type descriptions: C{dict} - @ivar descriptions: A dict mapping long option names to alternate - descriptions. When this variable is defined, the descriptions - contained here will override those descriptions provided in the - optFlags and optParameters variables. - - @type multiUse: C{list} - @ivar multiUse: An iterable containing those long option names which may - appear on the command line more than once. By default, options will - only be completed one time. - - @type mutuallyExclusive: C{list} of C{tuple} - @ivar mutuallyExclusive: A sequence of sequences, with each sub-sequence - containing those long option names that are mutually exclusive. That is, - those options that cannot appear on the command line together. - - @type optActions: C{dict} - @ivar optActions: A dict mapping long option names to shell "actions". - These actions define what may be completed as the argument to the - given option, and should be given as instances of - L{twisted.python.usage.Completer}. - - Callables may instead be given for the values in this dict. The - callable should accept no arguments, and return a C{Completer} - instance used as the action. - - @type extraActions: C{list} of C{twisted.python.usage.Completer} - @ivar extraActions: Extra arguments are those arguments typically - appearing at the end of the command-line, which are not associated - with any particular named option. That is, the arguments that are - given to the parseArgs() method of your usage.Options subclass. - """ - def __init__(self, options, cmdName, file): - self.options = options - self.cmdName = cmdName - self.file = file - - self.descriptions = {} - self.multiUse = set() - self.mutuallyExclusive = [] - self.optActions = {} - self.extraActions = [] - - for cls in reversed(inspect.getmro(options.__class__)): - data = getattr(cls, 'compData', None) - if data: - self.descriptions.update(data.descriptions) - self.optActions.update(data.optActions) - self.multiUse.update(data.multiUse) - - self.mutuallyExclusive.extend(data.mutuallyExclusive) - - # I don't see any sane way to aggregate extraActions, so just - # take the one at the top of the MRO (nearest the `options' - # instance). - if data.extraActions: - self.extraActions = data.extraActions - - aCL = reflect.accumulateClassList - - optFlags = [] - optParams = [] - - aCL(options.__class__, 'optFlags', optFlags) - aCL(options.__class__, 'optParameters', optParams) - - for i, optList in enumerate(optFlags): - if len(optList) != 3: - optFlags[i] = util.padTo(3, optList) - - for i, optList in enumerate(optParams): - if len(optList) != 5: - optParams[i] = util.padTo(5, optList) - - - self.optFlags = optFlags - self.optParams = optParams - - paramNameToDefinition = {} - for optList in optParams: - paramNameToDefinition[optList[0]] = optList[1:] - self.paramNameToDefinition = paramNameToDefinition - - flagNameToDefinition = {} - for optList in optFlags: - flagNameToDefinition[optList[0]] = optList[1:] - self.flagNameToDefinition = flagNameToDefinition - - allOptionsNameToDefinition = {} - allOptionsNameToDefinition.update(paramNameToDefinition) - allOptionsNameToDefinition.update(flagNameToDefinition) - self.allOptionsNameToDefinition = allOptionsNameToDefinition - - self.addAdditionalOptions() - - # makes sure none of the Completions metadata references - # option names that don't exist. (great for catching typos) - self.verifyZshNames() - - self.excludes = self.makeExcludesDict() - - - def write(self): - """ - Write the zsh completion code to the file given to __init__ - @return: C{None} - """ - self.writeHeader() - self.writeExtras() - self.writeOptions() - self.writeFooter() - - - def writeHeader(self): - """ - This is the start of the code that calls _arguments - @return: C{None} - """ - self.file.write('#compdef %s\n\n' - '_arguments -s -A "-*" \\\n' % (self.cmdName,)) - - - def writeOptions(self): - """ - Write out zsh code for each option in this command - @return: C{None} - """ - optNames = self.allOptionsNameToDefinition.keys() - optNames.sort() - for longname in optNames: - self.writeOpt(longname) - - - def writeExtras(self): - """ - Write out completion information for extra arguments appearing on the - command-line. These are extra positional arguments not associated - with a named option. That is, the stuff that gets passed to - Options.parseArgs(). - - @return: C{None} - - @raises: ValueError: if C{Completer} with C{repeat=True} is found and - is not the last item in the C{extraActions} list. - """ - for i, action in enumerate(self.extraActions): - # a repeatable action must be the last action in the list - if action._repeat and i != len(self.extraActions) - 1: - raise ValueError("Completer with repeat=True must be " - "last item in Options.extraActions") - self.file.write(escape(action._shellCode('', usage._ZSH))) - self.file.write(' \\\n') - - - def writeFooter(self): - """ - Write the last bit of code that finishes the call to _arguments - @return: C{None} - """ - self.file.write('&& return 0\n') - - - def verifyZshNames(self): - """ - Ensure that none of the option names given in the metadata are typoed - @return: C{None} - @raise ValueError: Raised if unknown option names have been found. - """ - def err(name): - raise ValueError("Unknown option name \"%s\" found while\n" - "examining Completions instances on %s" % ( - name, self.options)) - - for name in itertools.chain(self.descriptions, self.optActions, - self.multiUse): - if name not in self.allOptionsNameToDefinition: - err(name) - - for seq in self.mutuallyExclusive: - for name in seq: - if name not in self.allOptionsNameToDefinition: - err(name) - - - def excludeStr(self, longname, buildShort=False): - """ - Generate an "exclusion string" for the given option - - @type longname: C{str} - @param longname: The long option name (e.g. "verbose" instead of "v") - - @type buildShort: C{bool} - @param buildShort: May be True to indicate we're building an excludes - string for the short option that correspondes to the given long opt. - - @return: The generated C{str} - """ - if longname in self.excludes: - exclusions = self.excludes[longname].copy() - else: - exclusions = set() - - # if longname isn't a multiUse option (can't appear on the cmd line more - # than once), then we have to exclude the short option if we're - # building for the long option, and vice versa. - if longname not in self.multiUse: - if buildShort is False: - short = self.getShortOption(longname) - if short is not None: - exclusions.add(short) - else: - exclusions.add(longname) - - if not exclusions: - return '' - - strings = [] - for optName in exclusions: - if len(optName) == 1: - # short option - strings.append("-" + optName) - else: - strings.append("--" + optName) - strings.sort() # need deterministic order for reliable unit-tests - return "(%s)" % " ".join(strings) - - - def makeExcludesDict(self): - """ - @return: A C{dict} that maps each option name appearing in - self.mutuallyExclusive to a list of those option names that is it - mutually exclusive with (can't appear on the cmd line with). - """ - - #create a mapping of long option name -> single character name - longToShort = {} - for optList in itertools.chain(self.optParams, self.optFlags): - if optList[1] != None: - longToShort[optList[0]] = optList[1] - - excludes = {} - for lst in self.mutuallyExclusive: - for i, longname in enumerate(lst): - tmp = set(lst[:i] + lst[i+1:]) - for name in tmp.copy(): - if name in longToShort: - tmp.add(longToShort[name]) - - if longname in excludes: - excludes[longname] = excludes[longname].union(tmp) - else: - excludes[longname] = tmp - return excludes - - - def writeOpt(self, longname): - """ - Write out the zsh code for the given argument. This is just part of the - one big call to _arguments - - @type longname: C{str} - @param longname: The long option name (e.g. "verbose" instead of "v") - - @return: C{None} - """ - if longname in self.flagNameToDefinition: - # It's a flag option. Not one that takes a parameter. - longField = "--%s" % longname - else: - longField = "--%s=" % longname - - short = self.getShortOption(longname) - if short != None: - shortField = "-" + short - else: - shortField = '' - - descr = self.getDescription(longname) - descriptionField = descr.replace("[", "\[") - descriptionField = descriptionField.replace("]", "\]") - descriptionField = '[%s]' % descriptionField - - actionField = self.getAction(longname) - if longname in self.multiUse: - multiField = '*' - else: - multiField = '' - - longExclusionsField = self.excludeStr(longname) - - if short: - #we have to write an extra line for the short option if we have one - shortExclusionsField = self.excludeStr(longname, buildShort=True) - self.file.write(escape('%s%s%s%s%s' % (shortExclusionsField, - multiField, shortField, descriptionField, actionField))) - self.file.write(' \\\n') - - self.file.write(escape('%s%s%s%s%s' % (longExclusionsField, - multiField, longField, descriptionField, actionField))) - self.file.write(' \\\n') - - - def getAction(self, longname): - """ - Return a zsh "action" string for the given argument - @return: C{str} - """ - if longname in self.optActions: - if callable(self.optActions[longname]): - action = self.optActions[longname]() - else: - action = self.optActions[longname] - return action._shellCode(longname, usage._ZSH) - - if longname in self.paramNameToDefinition: - return ':%s:_files' % (longname,) - return '' - - - def getDescription(self, longname): - """ - Return the description to be used for this argument - @return: C{str} - """ - #check if we have an alternate descr for this arg, and if so use it - if longname in self.descriptions: - return self.descriptions[longname] - - #otherwise we have to get it from the optFlags or optParams - try: - descr = self.flagNameToDefinition[longname][1] - except KeyError: - try: - descr = self.paramNameToDefinition[longname][2] - except KeyError: - descr = None - - if descr is not None: - return descr - - # let's try to get it from the opt_foo method doc string if there is one - longMangled = longname.replace('-', '_') # this is what t.p.usage does - obj = getattr(self.options, 'opt_%s' % longMangled, None) - if obj is not None: - descr = descrFromDoc(obj) - if descr is not None: - return descr - - return longname # we really ought to have a good description to use - - - def getShortOption(self, longname): - """ - Return the short option letter or None - @return: C{str} or C{None} - """ - optList = self.allOptionsNameToDefinition[longname] - return optList[0] or None - - - def addAdditionalOptions(self): - """ - Add additional options to the optFlags and optParams lists. - These will be defined by 'opt_foo' methods of the Options subclass - @return: C{None} - """ - methodsDict = {} - reflect.accumulateMethods(self.options, methodsDict, 'opt_') - methodToShort = {} - for name in methodsDict.copy(): - if len(name) == 1: - methodToShort[methodsDict[name]] = name - del methodsDict[name] - - for methodName, methodObj in methodsDict.items(): - longname = methodName.replace('_', '-') # t.p.usage does this - # if this option is already defined by the optFlags or - # optParameters then we don't want to override that data - if longname in self.allOptionsNameToDefinition: - continue - - descr = self.getDescription(longname) - - short = None - if methodObj in methodToShort: - short = methodToShort[methodObj] - - reqArgs = methodObj.im_func.func_code.co_argcount - if reqArgs == 2: - self.optParams.append([longname, short, None, descr]) - self.paramNameToDefinition[longname] = [short, None, descr] - self.allOptionsNameToDefinition[longname] = [short, None, descr] - else: - # reqArgs must equal 1. self.options would have failed - # to instantiate if it had opt_ methods with bad signatures. - self.optFlags.append([longname, short, descr]) - self.flagNameToDefinition[longname] = [short, descr] - self.allOptionsNameToDefinition[longname] = [short, None, descr] - - - -def descrFromDoc(obj): - """ - Generate an appropriate description from docstring of the given object - """ - if obj.__doc__ is None or obj.__doc__.isspace(): - return None - - lines = [x.strip() for x in obj.__doc__.split("\n") - if x and not x.isspace()] - return " ".join(lines) - - - -def escape(x): - """ - Shell escape the given string - - Implementation borrowed from now-deprecated commands.mkarg() in the stdlib - """ - if '\'' not in x: - return '\'' + x + '\'' - s = '"' - for c in x: - if c in '\\$"`': - s = s + '\\' - s = s + c - s = s + '"' - return s - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_textattributes.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_textattributes.py deleted file mode 100644 index 648bd51..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_textattributes.py +++ /dev/null @@ -1,316 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_textattributes -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module provides some common functionality for the manipulation of -formatting states. - -Defining the mechanism by which text containing character attributes is -constructed begins by subclassing L{CharacterAttributesMixin}. - -Defining how a single formatting state is to be serialized begins by -subclassing L{_FormattingStateMixin}. - -Serializing a formatting structure is done with L{flatten}. - -@see: L{twisted.conch.insults.helper._FormattingState} -@see: L{twisted.conch.insults.text._CharacterAttributes} -@see: L{twisted.words.protocols.irc._FormattingState} -@see: L{twisted.words.protocols.irc._CharacterAttributes} -""" - -from twisted.python.util import FancyEqMixin - - - -class _Attribute(object, FancyEqMixin): - """ - A text attribute. - - Indexing a text attribute with a C{str} or another text attribute adds that - object as a child, indexing with a C{list} or C{tuple} adds the elements as - children; in either case C{self} is returned. - - @type children: C{list} - @ivar children: Child attributes. - """ - compareAttributes = ('children',) - - - def __init__(self): - self.children = [] - - - def __repr__(self): - return '<%s %r>' % (type(self).__name__, vars(self)) - - - def __getitem__(self, item): - assert isinstance(item, (list, tuple, _Attribute, str)) - if isinstance(item, (list, tuple)): - self.children.extend(item) - else: - self.children.append(item) - return self - - - def serialize(self, write, attrs=None, attributeRenderer='toVT102'): - """ - Serialize the text attribute and its children. - - @param write: C{callable}, taking one C{str} argument, called to output - a single text attribute at a time. - - @param attrs: A formatting state instance used to determine how to - serialize the attribute children. - - @type attributeRenderer: C{str} - @param attributeRenderer: Name of the method on L{attrs} that should be - called to render the attributes during serialization. Defaults to - C{'toVT102'}. - """ - if attrs is None: - attrs = DefaultFormattingState() - for ch in self.children: - if isinstance(ch, _Attribute): - ch.serialize(write, attrs.copy(), attributeRenderer) - else: - renderMeth = getattr(attrs, attributeRenderer) - write(renderMeth()) - write(ch) - - - -class _NormalAttr(_Attribute): - """ - A text attribute for normal text. - """ - def serialize(self, write, attrs, attributeRenderer): - attrs.__init__() - _Attribute.serialize(self, write, attrs, attributeRenderer) - - - -class _OtherAttr(_Attribute): - """ - A text attribute for text with formatting attributes. - - The unary minus operator returns the inverse of this attribute, where that - makes sense. - - @type attrname: C{str} - @ivar attrname: Text attribute name. - - @ivar attrvalue: Text attribute value. - """ - compareAttributes = ('attrname', 'attrvalue', 'children') - - - def __init__(self, attrname, attrvalue): - _Attribute.__init__(self) - self.attrname = attrname - self.attrvalue = attrvalue - - - def __neg__(self): - result = _OtherAttr(self.attrname, not self.attrvalue) - result.children.extend(self.children) - return result - - - def serialize(self, write, attrs, attributeRenderer): - attrs = attrs._withAttribute(self.attrname, self.attrvalue) - _Attribute.serialize(self, write, attrs, attributeRenderer) - - - -class _ColorAttr(_Attribute): - """ - Generic color attribute. - - @param color: Color value. - - @param ground: Foreground or background attribute name. - """ - compareAttributes = ('color', 'ground', 'children') - - - def __init__(self, color, ground): - _Attribute.__init__(self) - self.color = color - self.ground = ground - - - def serialize(self, write, attrs, attributeRenderer): - attrs = attrs._withAttribute(self.ground, self.color) - _Attribute.serialize(self, write, attrs, attributeRenderer) - - - -class _ForegroundColorAttr(_ColorAttr): - """ - Foreground color attribute. - """ - def __init__(self, color): - _ColorAttr.__init__(self, color, 'foreground') - - - -class _BackgroundColorAttr(_ColorAttr): - """ - Background color attribute. - """ - def __init__(self, color): - _ColorAttr.__init__(self, color, 'background') - - - -class _ColorAttribute(object): - """ - A color text attribute. - - Attribute access results in a color value lookup, by name, in L{attrs}. - - @type ground: L{_ColorAttr} - @param ground: Foreground or background color attribute to look color names - up from. - - @param attrs: Mapping of color names to color values. - """ - def __init__(self, ground, attrs): - self.ground = ground - self.attrs = attrs - - - def __getattr__(self, name): - try: - return self.ground(self.attrs[name]) - except KeyError: - raise AttributeError(name) - - - -class CharacterAttributesMixin(object): - """ - Mixin for character attributes that implements a C{__getattr__} method - returning a new C{_NormalAttr} instance when attempting to access - a C{'normal'} attribute; otherwise a new C{_OtherAttr} instance is returned - for names that appears in the C{'attrs'} attribute. - """ - def __getattr__(self, name): - if name == 'normal': - return _NormalAttr() - if name in self.attrs: - return _OtherAttr(name, True) - raise AttributeError(name) - - - -class DefaultFormattingState(object, FancyEqMixin): - """ - A character attribute that does nothing, thus applying no attributes to - text. - """ - compareAttributes = ('_dummy',) - - _dummy = 0 - - - def copy(self): - """ - Make a copy of this formatting state. - - @return: A formatting state instance. - """ - return type(self)() - - - def _withAttribute(self, name, value): - """ - Add a character attribute to a copy of this formatting state. - - @param name: Attribute name to be added to formatting state. - - @param value: Attribute value. - - @return: A formatting state instance with the new attribute. - """ - return self.copy() - - - def toVT102(self): - """ - Emit a VT102 control sequence that will set up all the attributes this - formatting state has set. - - @return: A string containing VT102 control sequences that mimic this - formatting state. - """ - return '' - - - -class _FormattingStateMixin(DefaultFormattingState): - """ - Mixin for the formatting state/attributes of a single character. - """ - def copy(self): - c = DefaultFormattingState.copy(self) - c.__dict__.update(vars(self)) - return c - - - def _withAttribute(self, name, value): - if getattr(self, name) != value: - attr = self.copy() - attr._subtracting = not value - setattr(attr, name, value) - return attr - else: - return self.copy() - - - -def flatten(output, attrs, attributeRenderer='toVT102'): - """ - Serialize a sequence of characters with attribute information - - The resulting string can be interpreted by compatible software so that the - contained characters are displayed and, for those attributes which are - supported by the software, the attributes expressed. The exact result of - the serialization depends on the behavior of the method specified by - L{attributeRenderer}. - - For example, if your terminal is VT102 compatible, you might run - this for a colorful variation on the \"hello world\" theme:: - - from twisted.conch.insults.text import flatten, attributes as A - from twisted.conch.insults.helper import CharacterAttribute - print flatten( - A.normal[A.bold[A.fg.red['He'], A.fg.green['ll'], A.fg.magenta['o'], ' ', - A.fg.yellow['Wo'], A.fg.blue['rl'], A.fg.cyan['d!']]], - CharacterAttribute()) - - @param output: Object returned by accessing attributes of the - module-level attributes object. - - @param attrs: A formatting state instance used to determine how to - serialize C{output}. - - @type attributeRenderer: C{str} - @param attributeRenderer: Name of the method on L{attrs} that should be - called to render the attributes during serialization. Defaults to - C{'toVT102'}. - - @return: A string expressing the text and display attributes specified by - L{output}. - """ - flattened = [] - output.serialize(flattened.append, attrs, attributeRenderer) - return ''.join(flattened) - - - -__all__ = [ - 'flatten', 'DefaultFormattingState', 'CharacterAttributesMixin'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_tzhelper.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_tzhelper.py deleted file mode 100644 index 614f62b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/_tzhelper.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_tzhelper -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Time zone utilities. -""" - -from datetime import datetime, timedelta, tzinfo - -__all__ = [ - "FixedOffsetTimeZone", - "UTC", -] - - - -class FixedOffsetTimeZone(tzinfo): - """ - Represents a fixed timezone offset (without daylight saving time). - - @ivar name: A L{str} giving the name of this timezone; the name just - includes how much time this offset represents. - - @ivar offset: A L{timedelta} giving the amount of time this timezone is - offset. - """ - - def __init__(self, offset, name=None): - """ - Construct a L{FixedOffsetTimeZone} with a fixed offset. - - @param offset: a delta representing the offset from UTC. - @type offset: L{timedelta} - - @param name: A name to be given for this timezone. - @type name: L{str} or L{NoneType} - """ - self.offset = offset - self.name = name - - - @classmethod - def fromSignHoursMinutes(cls, sign, hours, minutes): - """ - Construct a L{FixedOffsetTimeZone} from an offset described by sign - ('+' or '-'), hours, and minutes. - - @note: For protocol compatibility with AMP, this method never uses 'Z' - - @param sign: A string describing the positive or negative-ness of the - offset. - - @param hours: The number of hours in the offset. - @type hours: L{int} - - @param minutes: The number of minutes in the offset - @type minutes: L{int} - - @return: A time zone with the given offset, and a name describing the - offset. - @rtype: L{FixedOffsetTimeZone} - """ - name = "%s%02i:%02i" % (sign, hours, minutes) - if sign == "-": - hours = -hours - minutes = -minutes - elif sign != "+": - raise ValueError("Invalid sign for timezone %r" % (sign,)) - return cls(timedelta(hours=hours, minutes=minutes), name) - - - @classmethod - def fromLocalTimeStamp(cls, timeStamp): - """ - Create a time zone with a fixed offset corresponding to a time stamp in - the system's locally configured time zone. - - @param timeStamp: a time stamp - @type timeStamp: L{int} - - @return: a time zone - @rtype: L{FixedOffsetTimeZone} - """ - offset = ( - datetime.fromtimestamp(timeStamp) - - datetime.utcfromtimestamp(timeStamp) - ) - return cls(offset) - - - def utcoffset(self, dt): - """ - Return this timezone's offset from UTC. - """ - return self.offset - - - def dst(self, dt): - """ - Return a zero C{datetime.timedelta} for the daylight saving time - offset, since there is never one. - """ - return timedelta(0) - - - def tzname(self, dt): - """ - Return a string describing this timezone. - """ - if self.name is not None: - return self.name - # XXX this is wrong; the tests are - dt = datetime.fromtimestamp(0, self) - return dt.strftime("UTC%z") - - - -UTC = FixedOffsetTimeZone.fromSignHoursMinutes("+", 0, 0) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/compat.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/compat.py deleted file mode 100644 index 39def97..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/compat.py +++ /dev/null @@ -1,566 +0,0 @@ -# -*- test-case-name: twisted.test.test_compat -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Compatibility module to provide backwards compatibility for useful Python -features. - -This is mainly for use of internal Twisted code. We encourage you to use -the latest version of Python directly from your code, if possible. - -@var unicode: The type of Unicode strings, C{unicode} on Python 2 and C{str} - on Python 3. - -@var NativeStringIO: An in-memory file-like object that operates on the native - string type (bytes in Python 2, unicode in Python 3). -""" - -from __future__ import division - -import sys, string, socket, struct, inspect -from io import TextIOBase, IOBase - - -if sys.version_info < (3, 0): - _PY3 = False -else: - _PY3 = True - - - -def currentframe(n=0): - """ - In Python 3, L{inspect.currentframe} does not take a stack-level argument. - Restore that functionality from Python 2 so we don't have to re-implement - the C{f_back}-walking loop in places where it's called. - - @param n: The number of stack levels above the caller to walk. - @type n: L{int} - - @return: a frame, n levels up the stack from the caller. - @rtype: L{types.FrameType} - """ - f = inspect.currentframe() - for x in range(n + 1): - f = f.f_back - return f - - - -def inet_pton(af, addr): - if af == socket.AF_INET: - return socket.inet_aton(addr) - elif af == getattr(socket, 'AF_INET6', 'AF_INET6'): - if [x for x in addr if x not in string.hexdigits + ':.']: - raise ValueError("Illegal characters: %r" % (''.join(x),)) - - parts = addr.split(':') - elided = parts.count('') - ipv4Component = '.' in parts[-1] - - if len(parts) > (8 - ipv4Component) or elided > 3: - raise ValueError("Syntactically invalid address") - - if elided == 3: - return '\x00' * 16 - - if elided: - zeros = ['0'] * (8 - len(parts) - ipv4Component + elided) - - if addr.startswith('::'): - parts[:2] = zeros - elif addr.endswith('::'): - parts[-2:] = zeros - else: - idx = parts.index('') - parts[idx:idx+1] = zeros - - if len(parts) != 8 - ipv4Component: - raise ValueError("Syntactically invalid address") - else: - if len(parts) != (8 - ipv4Component): - raise ValueError("Syntactically invalid address") - - if ipv4Component: - if parts[-1].count('.') != 3: - raise ValueError("Syntactically invalid address") - rawipv4 = socket.inet_aton(parts[-1]) - unpackedipv4 = struct.unpack('!HH', rawipv4) - parts[-1:] = [hex(x)[2:] for x in unpackedipv4] - - parts = [int(x, 16) for x in parts] - return struct.pack('!8H', *parts) - else: - raise socket.error(97, 'Address family not supported by protocol') - -def inet_ntop(af, addr): - if af == socket.AF_INET: - return socket.inet_ntoa(addr) - elif af == socket.AF_INET6: - if len(addr) != 16: - raise ValueError("address length incorrect") - parts = struct.unpack('!8H', addr) - curBase = bestBase = None - for i in range(8): - if not parts[i]: - if curBase is None: - curBase = i - curLen = 0 - curLen += 1 - else: - if curBase is not None: - bestLen = None - if bestBase is None or curLen > bestLen: - bestBase = curBase - bestLen = curLen - curBase = None - if curBase is not None and (bestBase is None or curLen > bestLen): - bestBase = curBase - bestLen = curLen - parts = [hex(x)[2:] for x in parts] - if bestBase is not None: - parts[bestBase:bestBase + bestLen] = [''] - if parts[0] == '': - parts.insert(0, '') - if parts[-1] == '': - parts.insert(len(parts) - 1, '') - return ':'.join(parts) - else: - raise socket.error(97, 'Address family not supported by protocol') - -try: - socket.AF_INET6 -except AttributeError: - socket.AF_INET6 = 'AF_INET6' - -try: - socket.inet_pton(socket.AF_INET6, "::") -except (AttributeError, NameError, socket.error): - socket.inet_pton = inet_pton - socket.inet_ntop = inet_ntop - - -adict = dict - - - -if _PY3: - # These are actually useless in Python 2 as well, but we need to go - # through deprecation process there (ticket #5895): - del adict, inet_pton, inet_ntop - - -set = set -frozenset = frozenset - - -try: - from functools import reduce -except ImportError: - reduce = reduce - - - -def execfile(filename, globals, locals=None): - """ - Execute a Python script in the given namespaces. - - Similar to the execfile builtin, but a namespace is mandatory, partly - because that's a sensible thing to require, and because otherwise we'd - have to do some frame hacking. - - This is a compatibility implementation for Python 3 porting, to avoid the - use of the deprecated builtin C{execfile} function. - """ - if locals is None: - locals = globals - fin = open(filename, "rbU") - try: - source = fin.read() - finally: - fin.close() - code = compile(source, filename, "exec") - exec(code, globals, locals) - - -try: - cmp = cmp -except NameError: - def cmp(a, b): - """ - Compare two objects. - - Returns a negative number if C{a < b}, zero if they are equal, and a - positive number if C{a > b}. - """ - if a < b: - return -1 - elif a == b: - return 0 - else: - return 1 - - - -def comparable(klass): - """ - Class decorator that ensures support for the special C{__cmp__} method. - - On Python 2 this does nothing. - - On Python 3, C{__eq__}, C{__lt__}, etc. methods are added to the class, - relying on C{__cmp__} to implement their comparisons. - """ - # On Python 2, __cmp__ will just work, so no need to add extra methods: - if not _PY3: - return klass - - def __eq__(self, other): - c = self.__cmp__(other) - if c is NotImplemented: - return c - return c == 0 - - - def __ne__(self, other): - c = self.__cmp__(other) - if c is NotImplemented: - return c - return c != 0 - - - def __lt__(self, other): - c = self.__cmp__(other) - if c is NotImplemented: - return c - return c < 0 - - - def __le__(self, other): - c = self.__cmp__(other) - if c is NotImplemented: - return c - return c <= 0 - - - def __gt__(self, other): - c = self.__cmp__(other) - if c is NotImplemented: - return c - return c > 0 - - - def __ge__(self, other): - c = self.__cmp__(other) - if c is NotImplemented: - return c - return c >= 0 - - klass.__lt__ = __lt__ - klass.__gt__ = __gt__ - klass.__le__ = __le__ - klass.__ge__ = __ge__ - klass.__eq__ = __eq__ - klass.__ne__ = __ne__ - return klass - - - -if _PY3: - unicode = str -else: - unicode = unicode - - - -def ioType(fileIshObject, default=unicode): - """ - Determine the type which will be returned from the given file object's - read() and accepted by its write() method as an argument. - - In other words, determine whether the given file is 'opened in text mode'. - - @param fileIshObject: Any object, but ideally one which resembles a file. - @type fileIshObject: L{object} - - @param default: A default value to return when the type of C{fileIshObject} - cannot be determined. - @type default: L{type} - - @return: There are 3 possible return values: - - 1. L{unicode}, if the file is unambiguously opened in text mode. - - 2. L{bytes}, if the file is unambiguously opened in binary mode. - - 3. L{basestring}, if we are on python 2 (the L{basestring} type - does not exist on python 3) and the file is opened in binary - mode, but has an encoding and can therefore accept both bytes - and text reliably for writing, but will return L{bytes} from - read methods. - - 4. The C{default} parameter, if the given type is not understood. - - @rtype: L{type} - """ - if isinstance(fileIshObject, TextIOBase): - # If it's for text I/O, then it's for text I/O. - return unicode - if isinstance(fileIshObject, IOBase): - # If it's for I/O but it's _not_ for text I/O, it's for bytes I/O. - return bytes - encoding = getattr(fileIshObject, 'encoding', None) - import codecs - if isinstance(fileIshObject, (codecs.StreamReader, codecs.StreamWriter)): - # On StreamReaderWriter, the 'encoding' attribute has special meaning; - # it is unambiguously unicode. - if encoding: - return unicode - else: - return bytes - if not _PY3: - # Special case: if we have an encoding file, we can *give* it unicode, - # but we can't expect to *get* unicode. - if isinstance(fileIshObject, file): - if encoding is not None: - return basestring - else: - return bytes - from cStringIO import InputType, OutputType - from StringIO import StringIO - if isinstance(fileIshObject, (StringIO, InputType, OutputType)): - return bytes - return default - - - -def nativeString(s): - """ - Convert C{bytes} or C{unicode} to the native C{str} type, using ASCII - encoding if conversion is necessary. - - @raise UnicodeError: The input string is not ASCII encodable/decodable. - @raise TypeError: The input is neither C{bytes} nor C{unicode}. - """ - if not isinstance(s, (bytes, unicode)): - raise TypeError("%r is neither bytes nor unicode" % s) - if _PY3: - if isinstance(s, bytes): - return s.decode("ascii") - else: - # Ensure we're limited to ASCII subset: - s.encode("ascii") - else: - if isinstance(s, unicode): - return s.encode("ascii") - else: - # Ensure we're limited to ASCII subset: - s.decode("ascii") - return s - - - -if _PY3: - def reraise(exception, traceback): - raise exception.with_traceback(traceback) -else: - exec("""def reraise(exception, traceback): - raise exception.__class__, exception, traceback""") - -reraise.__doc__ = """ -Re-raise an exception, with an optional traceback, in a way that is compatible -with both Python 2 and Python 3. - -Note that on Python 3, re-raised exceptions will be mutated, with their -C{__traceback__} attribute being set. - -@param exception: The exception instance. -@param traceback: The traceback to use, or C{None} indicating a new traceback. -""" - - - -if _PY3: - from io import StringIO as NativeStringIO -else: - from io import BytesIO as NativeStringIO - - - -# Functions for dealing with Python 3's bytes type, which is somewhat -# different than Python 2's: -if _PY3: - def iterbytes(originalBytes): - for i in range(len(originalBytes)): - yield originalBytes[i:i+1] - - - def intToBytes(i): - return ("%d" % i).encode("ascii") - - - # Ideally we would use memoryview, but it has a number of differences from - # the Python 2 buffer() that make that impractical - # (http://bugs.python.org/issue15945, incompatibility with pyOpenSSL due to - # PyArg_ParseTuple differences.) - def lazyByteSlice(object, offset=0, size=None): - """ - Return a copy of the given bytes-like object. - - If an offset is given, the copy starts at that offset. If a size is - given, the copy will only be of that length. - - @param object: C{bytes} to be copied. - - @param offset: C{int}, starting index of copy. - - @param size: Optional, if an C{int} is given limit the length of copy - to this size. - """ - if size is None: - return object[offset:] - else: - return object[offset:(offset + size)] - - - def networkString(s): - if not isinstance(s, unicode): - raise TypeError("Can only convert text to bytes on Python 3") - return s.encode('ascii') -else: - def iterbytes(originalBytes): - return originalBytes - - - def intToBytes(i): - return b"%d" % i - - - lazyByteSlice = buffer - - def networkString(s): - if not isinstance(s, str): - raise TypeError("Can only pass-through bytes on Python 2") - # Ensure we're limited to ASCII subset: - s.decode('ascii') - return s - -iterbytes.__doc__ = """ -Return an iterable wrapper for a C{bytes} object that provides the behavior of -iterating over C{bytes} on Python 2. - -In particular, the results of iteration are the individual bytes (rather than -integers as on Python 3). - -@param originalBytes: A C{bytes} object that will be wrapped. -""" - -intToBytes.__doc__ = """ -Convert the given integer into C{bytes}, as ASCII-encoded Arab numeral. - -In other words, this is equivalent to calling C{bytes} in Python 2 on an -integer. - -@param i: The C{int} to convert to C{bytes}. -@rtype: C{bytes} -""" - -networkString.__doc__ = """ -Convert the native string type to C{bytes} if it is not already C{bytes} using -ASCII encoding if conversion is necessary. - -This is useful for sending text-like bytes that are constructed using string -interpolation. For example, this is safe on Python 2 and Python 3: - - networkString("Hello %d" % (n,)) - -@param s: A native string to convert to bytes if necessary. -@type s: C{str} - -@raise UnicodeError: The input string is not ASCII encodable/decodable. -@raise TypeError: The input is neither C{bytes} nor C{unicode}. - -@rtype: C{bytes} -""" - - -try: - StringType = basestring -except NameError: - # Python 3+ - StringType = str - -try: - from types import InstanceType -except ImportError: - # Python 3+ - InstanceType = object - -try: - from types import FileType -except ImportError: - # Python 3+ - FileType = IOBase - - - -# Dealing with the differences in items/iteritems -if _PY3: - def iteritems(d): - return d.items() - - def items(d): - return list(d.items()) - - xrange = range -else: - def iteritems(d): - return d.iteritems() - - def items(d): - return d.items() - - xrange = xrange - - -iteritems.__doc__ = """ -Return an iterable of the items of C{d}. - -@type d: L{dict} -@rtype: iterable -""" - -items.__doc__ = """ -Return a list of the items of C{d}. - -@type d: L{dict} -@rtype: L{list} -""" - - - -__all__ = [ - "reraise", - "execfile", - "frozenset", - "reduce", - "set", - "cmp", - "comparable", - "nativeString", - "NativeStringIO", - "networkString", - "unicode", - "iterbytes", - "intToBytes", - "lazyByteSlice", - "StringType", - "InstanceType", - "FileType", - "items", - "iteritems", - "xrange", -] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/components.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/components.py deleted file mode 100644 index 8d71ca6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/components.py +++ /dev/null @@ -1,447 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_components -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Component architecture for Twisted, based on Zope3 components. - -Using the Zope3 API directly is strongly recommended. Everything -you need is in the top-level of the zope.interface package, e.g.:: - - from zope.interface import Interface, implements - - class IFoo(Interface): - pass - - class Foo: - implements(IFoo) - - print IFoo.implementedBy(Foo) # True - print IFoo.providedBy(Foo()) # True - -L{twisted.python.components.registerAdapter} from this module may be used to -add to Twisted's global adapter registry. - -L{twisted.python.components.proxyForInterface} is a factory for classes -which allow access to only the parts of another class defined by a specified -interface. -""" - -from __future__ import division, absolute_import - -# zope3 imports -from zope.interface import interface, declarations -from zope.interface.adapter import AdapterRegistry - -# twisted imports -from twisted.python.compat import NativeStringIO -from twisted.python import reflect - - - -# Twisted's global adapter registry -globalRegistry = AdapterRegistry() - -# Attribute that registerAdapter looks at. Is this supposed to be public? -ALLOW_DUPLICATES = 0 - -# Define a function to find the registered adapter factory, using either a -# version of Zope Interface which has the `registered' method or an older -# version which does not. -if getattr(AdapterRegistry, 'registered', None) is None: - def _registered(registry, required, provided): - """ - Return the adapter factory for the given parameters in the given - registry, or None if there is not one. - """ - return registry.get(required).selfImplied.get(provided, {}).get('') -else: - def _registered(registry, required, provided): - """ - Return the adapter factory for the given parameters in the given - registry, or None if there is not one. - """ - return registry.registered([required], provided) - - -def registerAdapter(adapterFactory, origInterface, *interfaceClasses): - """Register an adapter class. - - An adapter class is expected to implement the given interface, by - adapting instances implementing 'origInterface'. An adapter class's - __init__ method should accept one parameter, an instance implementing - 'origInterface'. - """ - self = globalRegistry - assert interfaceClasses, "You need to pass an Interface" - global ALLOW_DUPLICATES - - # deal with class->interface adapters: - if not isinstance(origInterface, interface.InterfaceClass): - origInterface = declarations.implementedBy(origInterface) - - for interfaceClass in interfaceClasses: - factory = _registered(self, origInterface, interfaceClass) - if factory is not None and not ALLOW_DUPLICATES: - raise ValueError("an adapter (%s) was already registered." % (factory, )) - for interfaceClass in interfaceClasses: - self.register([origInterface], interfaceClass, '', adapterFactory) - - -def getAdapterFactory(fromInterface, toInterface, default): - """Return registered adapter for a given class and interface. - - Note that is tied to the *Twisted* global registry, and will - thus not find adapters registered elsewhere. - """ - self = globalRegistry - if not isinstance(fromInterface, interface.InterfaceClass): - fromInterface = declarations.implementedBy(fromInterface) - factory = self.lookup1(fromInterface, toInterface) - if factory is None: - factory = default - return factory - - -def _addHook(registry): - """ - Add an adapter hook which will attempt to look up adapters in the given - registry. - - @type registry: L{zope.interface.adapter.AdapterRegistry} - - @return: The hook which was added, for later use with L{_removeHook}. - """ - lookup = registry.lookup1 - def _hook(iface, ob): - factory = lookup(declarations.providedBy(ob), iface) - if factory is None: - return None - else: - return factory(ob) - interface.adapter_hooks.append(_hook) - return _hook - - -def _removeHook(hook): - """ - Remove a previously added adapter hook. - - @param hook: An object previously returned by a call to L{_addHook}. This - will be removed from the list of adapter hooks. - """ - interface.adapter_hooks.remove(hook) - -# add global adapter lookup hook for our newly created registry -_addHook(globalRegistry) - - -def getRegistry(): - """Returns the Twisted global - C{zope.interface.adapter.AdapterRegistry} instance. - """ - return globalRegistry - -# FIXME: deprecate attribute somehow? -CannotAdapt = TypeError - -class Adapter: - """I am the default implementation of an Adapter for some interface. - - This docstring contains a limerick, by popular demand:: - - Subclassing made Zope and TR - much harder to work with by far. - So before you inherit, - be sure to declare it - Adapter, not PyObject* - - @cvar temporaryAdapter: If this is True, the adapter will not be - persisted on the Componentized. - @cvar multiComponent: If this adapter is persistent, should it be - automatically registered for all appropriate interfaces. - """ - - # These attributes are used with Componentized. - - temporaryAdapter = 0 - multiComponent = 1 - - def __init__(self, original): - """Set my 'original' attribute to be the object I am adapting. - """ - self.original = original - - def __conform__(self, interface): - """ - I forward __conform__ to self.original if it has it, otherwise I - simply return None. - """ - if hasattr(self.original, "__conform__"): - return self.original.__conform__(interface) - return None - - def isuper(self, iface, adapter): - """ - Forward isuper to self.original - """ - return self.original.isuper(iface, adapter) - - -class Componentized: - """I am a mixin to allow you to be adapted in various ways persistently. - - I define a list of persistent adapters. This is to allow adapter classes - to store system-specific state, and initialized on demand. The - getComponent method implements this. You must also register adapters for - this class for the interfaces that you wish to pass to getComponent. - - Many other classes and utilities listed here are present in Zope3; this one - is specific to Twisted. - """ - - persistenceVersion = 1 - - def __init__(self): - self._adapterCache = {} - - def locateAdapterClass(self, klass, interfaceClass, default): - return getAdapterFactory(klass, interfaceClass, default) - - def setAdapter(self, interfaceClass, adapterClass): - """ - Cache a provider for the given interface, by adapting C{self} using - the given adapter class. - """ - self.setComponent(interfaceClass, adapterClass(self)) - - def addAdapter(self, adapterClass, ignoreClass=0): - """Utility method that calls addComponent. I take an adapter class and - instantiate it with myself as the first argument. - - @return: The adapter instantiated. - """ - adapt = adapterClass(self) - self.addComponent(adapt, ignoreClass) - return adapt - - def setComponent(self, interfaceClass, component): - """ - Cache a provider of the given interface. - """ - self._adapterCache[reflect.qual(interfaceClass)] = component - - def addComponent(self, component, ignoreClass=0): - """ - Add a component to me, for all appropriate interfaces. - - In order to determine which interfaces are appropriate, the component's - provided interfaces will be scanned. - - If the argument 'ignoreClass' is True, then all interfaces are - considered appropriate. - - Otherwise, an 'appropriate' interface is one for which its class has - been registered as an adapter for my class according to the rules of - getComponent. - - @return: the list of appropriate interfaces - """ - for iface in declarations.providedBy(component): - if (ignoreClass or - (self.locateAdapterClass(self.__class__, iface, None) - == component.__class__)): - self._adapterCache[reflect.qual(iface)] = component - - def unsetComponent(self, interfaceClass): - """Remove my component specified by the given interface class.""" - del self._adapterCache[reflect.qual(interfaceClass)] - - def removeComponent(self, component): - """ - Remove the given component from me entirely, for all interfaces for which - it has been registered. - - @return: a list of the interfaces that were removed. - """ - l = [] - for k, v in list(self._adapterCache.items()): - if v is component: - del self._adapterCache[k] - l.append(reflect.namedObject(k)) - return l - - def getComponent(self, interface, default=None): - """Create or retrieve an adapter for the given interface. - - If such an adapter has already been created, retrieve it from the cache - that this instance keeps of all its adapters. Adapters created through - this mechanism may safely store system-specific state. - - If you want to register an adapter that will be created through - getComponent, but you don't require (or don't want) your adapter to be - cached and kept alive for the lifetime of this Componentized object, - set the attribute 'temporaryAdapter' to True on your adapter class. - - If you want to automatically register an adapter for all appropriate - interfaces (with addComponent), set the attribute 'multiComponent' to - True on your adapter class. - """ - k = reflect.qual(interface) - if k in self._adapterCache: - return self._adapterCache[k] - else: - adapter = interface.__adapt__(self) - if adapter is not None and not ( - hasattr(adapter, "temporaryAdapter") and - adapter.temporaryAdapter): - self._adapterCache[k] = adapter - if (hasattr(adapter, "multiComponent") and - adapter.multiComponent): - self.addComponent(adapter) - if adapter is None: - return default - return adapter - - - def __conform__(self, interface): - return self.getComponent(interface) - - -class ReprableComponentized(Componentized): - def __init__(self): - Componentized.__init__(self) - - def __repr__(self): - from pprint import pprint - sio = NativeStringIO() - pprint(self._adapterCache, sio) - return sio.getvalue() - - - -def proxyForInterface(iface, originalAttribute='original'): - """ - Create a class which proxies all method calls which adhere to an interface - to another provider of that interface. - - This function is intended for creating specialized proxies. The typical way - to use it is by subclassing the result:: - - class MySpecializedProxy(proxyForInterface(IFoo)): - def someInterfaceMethod(self, arg): - if arg == 3: - return 3 - return self.original.someInterfaceMethod(arg) - - @param iface: The Interface to which the resulting object will conform, and - which the wrapped object must provide. - - @param originalAttribute: name of the attribute used to save the original - object in the resulting class. Default to C{original}. - @type originalAttribute: C{str} - - @return: A class whose constructor takes the original object as its only - argument. Constructing the class creates the proxy. - """ - def __init__(self, original): - setattr(self, originalAttribute, original) - contents = {"__init__": __init__} - for name in iface: - contents[name] = _ProxyDescriptor(name, originalAttribute) - proxy = type("(Proxy for %s)" - % (reflect.qual(iface),), (object,), contents) - declarations.classImplements(proxy, iface) - return proxy - - - -class _ProxiedClassMethod(object): - """ - A proxied class method. - - @ivar methodName: the name of the method which this should invoke when - called. - @type methodName: L{str} - - @ivar __name__: The name of the method being proxied (the same as - C{methodName}). - @type __name__: L{str} - - @ivar originalAttribute: name of the attribute of the proxy where the - original object is stored. - @type orginalAttribute: L{str} - """ - def __init__(self, methodName, originalAttribute): - self.methodName = self.__name__ = methodName - self.originalAttribute = originalAttribute - - - def __call__(self, oself, *args, **kw): - """ - Invoke the specified L{methodName} method of the C{original} attribute - for proxyForInterface. - - @param oself: an instance of a L{proxyForInterface} object. - - @return: the result of the underlying method. - """ - original = getattr(oself, self.originalAttribute) - actualMethod = getattr(original, self.methodName) - return actualMethod(*args, **kw) - - - -class _ProxyDescriptor(object): - """ - A descriptor which will proxy attribute access, mutation, and - deletion to the L{original} attribute of the object it is being accessed - from. - - @ivar attributeName: the name of the attribute which this descriptor will - retrieve from instances' C{original} attribute. - @type attributeName: C{str} - - @ivar originalAttribute: name of the attribute of the proxy where the - original object is stored. - @type orginalAttribute: C{str} - """ - def __init__(self, attributeName, originalAttribute): - self.attributeName = attributeName - self.originalAttribute = originalAttribute - - - def __get__(self, oself, type=None): - """ - Retrieve the C{self.attributeName} property from L{oself}. - """ - if oself is None: - return _ProxiedClassMethod(self.attributeName, - self.originalAttribute) - original = getattr(oself, self.originalAttribute) - return getattr(original, self.attributeName) - - - def __set__(self, oself, value): - """ - Set the C{self.attributeName} property of L{oself}. - """ - original = getattr(oself, self.originalAttribute) - setattr(original, self.attributeName, value) - - - def __delete__(self, oself): - """ - Delete the C{self.attributeName} property of L{oself}. - """ - original = getattr(oself, self.originalAttribute) - delattr(original, self.attributeName) - - - -__all__ = [ - "registerAdapter", "getAdapterFactory", - "Adapter", "Componentized", "ReprableComponentized", "getRegistry", - "proxyForInterface", -] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/constants.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/constants.py deleted file mode 100644 index 76b573e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/constants.py +++ /dev/null @@ -1,500 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_constants -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Symbolic constant support, including collections and constants with text, -numeric, and bit flag values. -""" - -from __future__ import division, absolute_import - -__all__ = [ - 'NamedConstant', 'ValueConstant', 'FlagConstant', - 'Names', 'Values', 'Flags'] - -from functools import partial -from itertools import count -from operator import and_, or_, xor - -_unspecified = object() -_constantOrder = partial(next, count()) - - -class _Constant(object): - """ - @ivar _index: A C{int} allocated from a shared counter in order to keep - track of the order in which L{_Constant}s are instantiated. - - @ivar name: A C{str} giving the name of this constant; only set once the - constant is initialized by L{_ConstantsContainer}. - - @ivar _container: The L{_ConstantsContainer} subclass this constant belongs - to; C{None} until the constant is initialized by that subclass. - """ - def __init__(self): - self._container = None - self._index = _constantOrder() - - - def __repr__(self): - """ - Return text identifying both which constant this is and which - collection it belongs to. - """ - return "<%s=%s>" % (self._container.__name__, self.name) - - - def __lt__(self, other): - """ - Implements C{<}. Order is defined by instantiation order. - - @param other: An object. - - @return: C{NotImplemented} if C{other} is not a constant belonging to - the same container as this constant, C{True} if this constant is - defined before C{other}, otherwise C{False}. - """ - if ( - not isinstance(other, self.__class__) or - not self._container == other._container - ): - return NotImplemented - return self._index < other._index - - - def __le__(self, other): - """ - Implements C{<=}. Order is defined by instantiation order. - - @param other: An object. - - @return: C{NotImplemented} if C{other} is not a constant belonging to - the same container as this constant, C{True} if this constant is - defined before or equal to C{other}, otherwise C{False}. - """ - if ( - not isinstance(other, self.__class__) or - not self._container == other._container - ): - return NotImplemented - return self is other or self._index < other._index - - - def __gt__(self, other): - """ - Implements C{>}. Order is defined by instantiation order. - - @param other: An object. - - @return: C{NotImplemented} if C{other} is not a constant belonging to - the same container as this constant, C{True} if this constant is - defined after C{other}, otherwise C{False}. - """ - if ( - not isinstance(other, self.__class__) or - not self._container == other._container - ): - return NotImplemented - return self._index > other._index - - - def __ge__(self, other): - """ - Implements C{>=}. Order is defined by instantiation order. - - @param other: An object. - - @return: C{NotImplemented} if C{other} is not a constant belonging to - the same container as this constant, C{True} if this constant is - defined after or equal to C{other}, otherwise C{False}. - """ - if ( - not isinstance(other, self.__class__) or - not self._container == other._container - ): - return NotImplemented - return self is other or self._index > other._index - - - def _realize(self, container, name, value): - """ - Complete the initialization of this L{_Constant}. - - @param container: The L{_ConstantsContainer} subclass this constant is - part of. - - @param name: The name of this constant in its container. - - @param value: The value of this constant; not used, as named constants - have no value apart from their identity. - """ - self._container = container - self.name = name - - - -class _ConstantsContainerType(type): - """ - L{_ConstantsContainerType} is a metaclass for creating constants container - classes. - """ - def __new__(self, name, bases, attributes): - """ - Create a new constants container class. - - If C{attributes} includes a value of C{None} for the C{"_constantType"} - key, the new class will not be initialized as a constants container and - it will behave as a normal class. - - @param name: The name of the container class. - @type name: L{str} - - @param bases: A tuple of the base classes for the new container class. - @type bases: L{tuple} of L{_ConstantsContainerType} instances - - @param attributes: The attributes of the new container class, including - any constants it is to contain. - @type attributes: L{dict} - """ - cls = super(_ConstantsContainerType, self).__new__( - self, name, bases, attributes) - - # Only realize constants in concrete _ConstantsContainer subclasses. - # Ignore intermediate base classes. - constantType = getattr(cls, '_constantType', None) - if constantType is None: - return cls - - constants = [] - for (name, descriptor) in attributes.items(): - if isinstance(descriptor, cls._constantType): - if descriptor._container is not None: - raise ValueError( - "Cannot use %s as the value of an attribute on %s" % ( - descriptor, cls.__name__)) - constants.append((descriptor._index, name, descriptor)) - - enumerants = {} - for (index, enumerant, descriptor) in sorted(constants): - value = cls._constantFactory(enumerant, descriptor) - descriptor._realize(cls, enumerant, value) - enumerants[enumerant] = descriptor - - # Save the dictionary which contains *only* constants (distinct from - # any other attributes the application may have given the container) - # where the class can use it later (eg for lookupByName). - cls._enumerants = enumerants - - return cls - - - -# In Python3 metaclasses are defined using a C{metaclass} keyword argument in -# the class definition. This would cause a syntax error in Python2. -# So we use L{type} to introduce an intermediate base class with the desired -# metaclass. -# See: -# * http://docs.python.org/2/library/functions.html#type -# * http://docs.python.org/3/reference/datamodel.html#customizing-class-creation -class _ConstantsContainer(_ConstantsContainerType('', (object,), {})): - """ - L{_ConstantsContainer} is a class with attributes used as symbolic - constants. It is up to subclasses to specify what kind of constants are - allowed. - - @cvar _constantType: Specified by a L{_ConstantsContainer} subclass to - specify the type of constants allowed by that subclass. - - @cvar _enumerants: A C{dict} mapping the names of constants (eg - L{NamedConstant} instances) found in the class definition to those - instances. - """ - - _constantType = None - - def __new__(cls): - """ - Classes representing constants containers are not intended to be - instantiated. - - The class object itself is used directly. - """ - raise TypeError("%s may not be instantiated." % (cls.__name__,)) - - - @classmethod - def _constantFactory(cls, name, descriptor): - """ - Construct the value for a new constant to add to this container. - - @param name: The name of the constant to create. - - @param descriptor: An instance of a L{_Constant} subclass (eg - L{NamedConstant}) which is assigned to C{name}. - - @return: L{NamedConstant} instances have no value apart from identity, - so return a meaningless dummy value. - """ - return _unspecified - - - @classmethod - def lookupByName(cls, name): - """ - Retrieve a constant by its name or raise a C{ValueError} if there is no - constant associated with that name. - - @param name: A C{str} giving the name of one of the constants defined - by C{cls}. - - @raise ValueError: If C{name} is not the name of one of the constants - defined by C{cls}. - - @return: The L{NamedConstant} associated with C{name}. - """ - if name in cls._enumerants: - return getattr(cls, name) - raise ValueError(name) - - - @classmethod - def iterconstants(cls): - """ - Iteration over a L{Names} subclass results in all of the constants it - contains. - - @return: an iterator the elements of which are the L{NamedConstant} - instances defined in the body of this L{Names} subclass. - """ - constants = cls._enumerants.values() - - return iter( - sorted(constants, key=lambda descriptor: descriptor._index)) - - - -class NamedConstant(_Constant): - """ - L{NamedConstant} defines an attribute to be a named constant within a - collection defined by a L{Names} subclass. - - L{NamedConstant} is only for use in the definition of L{Names} - subclasses. Do not instantiate L{NamedConstant} elsewhere and do not - subclass it. - """ - - - -class Names(_ConstantsContainer): - """ - A L{Names} subclass contains constants which differ only in their names and - identities. - """ - _constantType = NamedConstant - - - -class ValueConstant(_Constant): - """ - L{ValueConstant} defines an attribute to be a named constant within a - collection defined by a L{Values} subclass. - - L{ValueConstant} is only for use in the definition of L{Values} subclasses. - Do not instantiate L{ValueConstant} elsewhere and do not subclass it. - """ - def __init__(self, value): - _Constant.__init__(self) - self.value = value - - - -class Values(_ConstantsContainer): - """ - A L{Values} subclass contains constants which are associated with arbitrary - values. - """ - _constantType = ValueConstant - - @classmethod - def lookupByValue(cls, value): - """ - Retrieve a constant by its value or raise a C{ValueError} if there is - no constant associated with that value. - - @param value: The value of one of the constants defined by C{cls}. - - @raise ValueError: If C{value} is not the value of one of the constants - defined by C{cls}. - - @return: The L{ValueConstant} associated with C{value}. - """ - for constant in cls.iterconstants(): - if constant.value == value: - return constant - raise ValueError(value) - - - -def _flagOp(op, left, right): - """ - Implement a binary operator for a L{FlagConstant} instance. - - @param op: A two-argument callable implementing the binary operation. For - example, C{operator.or_}. - - @param left: The left-hand L{FlagConstant} instance. - @param right: The right-hand L{FlagConstant} instance. - - @return: A new L{FlagConstant} instance representing the result of the - operation. - """ - value = op(left.value, right.value) - names = op(left.names, right.names) - result = FlagConstant() - result._realize(left._container, names, value) - return result - - - -class FlagConstant(_Constant): - """ - L{FlagConstant} defines an attribute to be a flag constant within a - collection defined by a L{Flags} subclass. - - L{FlagConstant} is only for use in the definition of L{Flags} subclasses. - Do not instantiate L{FlagConstant} elsewhere and do not subclass it. - """ - def __init__(self, value=_unspecified): - _Constant.__init__(self) - self.value = value - - - def _realize(self, container, names, value): - """ - Complete the initialization of this L{FlagConstant}. - - This implementation differs from other C{_realize} implementations in - that a L{FlagConstant} may have several names which apply to it, due to - flags being combined with various operators. - - @param container: The L{Flags} subclass this constant is part of. - - @param names: When a single-flag value is being initialized, a C{str} - giving the name of that flag. This is the case which happens when - a L{Flags} subclass is being initialized and L{FlagConstant} - instances from its body are being realized. Otherwise, a C{set} of - C{str} giving names of all the flags set on this L{FlagConstant} - instance. This is the case when two flags are combined using C{|}, - for example. - """ - if isinstance(names, str): - name = names - names = set([names]) - elif len(names) == 1: - (name,) = names - else: - name = "{" + ",".join(sorted(names)) + "}" - _Constant._realize(self, container, name, value) - self.value = value - self.names = names - - - def __or__(self, other): - """ - Define C{|} on two L{FlagConstant} instances to create a new - L{FlagConstant} instance with all flags set in either instance set. - """ - return _flagOp(or_, self, other) - - - def __and__(self, other): - """ - Define C{&} on two L{FlagConstant} instances to create a new - L{FlagConstant} instance with only flags set in both instances set. - """ - return _flagOp(and_, self, other) - - - def __xor__(self, other): - """ - Define C{^} on two L{FlagConstant} instances to create a new - L{FlagConstant} instance with only flags set on exactly one instance - set. - """ - return _flagOp(xor, self, other) - - - def __invert__(self): - """ - Define C{~} on a L{FlagConstant} instance to create a new - L{FlagConstant} instance with all flags not set on this instance set. - """ - result = FlagConstant() - result._realize(self._container, set(), 0) - for flag in self._container.iterconstants(): - if flag.value & self.value == 0: - result |= flag - return result - - - def __iter__(self): - """ - @return: An iterator of flags set on this instance set. - """ - return (self._container.lookupByName(name) for name in self.names) - - - def __contains__(self, flag): - """ - @param flag: The flag to test for membership in this instance - set. - - @return: C{True} if C{flag} is in this instance set, else - C{False}. - """ - # Optimization for testing membership without iteration. - return bool(flag & self) - - - def __nonzero__(self): - """ - @return: C{False} if this flag's value is 0, else C{True}. - """ - return bool(self.value) - __bool__ = __nonzero__ - - - -class Flags(Values): - """ - A L{Flags} subclass contains constants which can be combined using the - common bitwise operators (C{|}, C{&}, etc) similar to a I{bitvector} from a - language like C. - """ - _constantType = FlagConstant - - _value = 1 - - @classmethod - def _constantFactory(cls, name, descriptor): - """ - For L{FlagConstant} instances with no explicitly defined value, assign - the next power of two as its value. - - @param name: The name of the constant to create. - - @param descriptor: An instance of a L{FlagConstant} which is assigned - to C{name}. - - @return: Either the value passed to the C{descriptor} constructor, or - the next power of 2 value which will be assigned to C{descriptor}, - relative to the value of the last defined L{FlagConstant}. - """ - if descriptor.value is _unspecified: - value = cls._value - cls._value <<= 1 - else: - value = descriptor.value - cls._value = value << 1 - return value diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/context.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/context.py deleted file mode 100644 index cb32be7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/context.py +++ /dev/null @@ -1,133 +0,0 @@ -# -*- test-case-name: twisted.test.test_context -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Dynamic pseudo-scoping for Python. - -Call functions with context.call({key: value}, func); func and -functions that it calls will be able to use 'context.get(key)' to -retrieve 'value'. - -This is thread-safe. -""" - -from __future__ import division, absolute_import - -from threading import local - -defaultContextDict = {} - -setDefault = defaultContextDict.__setitem__ - -class ContextTracker: - """ - A L{ContextTracker} provides a way to pass arbitrary key/value data up and - down a call stack without passing them as parameters to the functions on - that call stack. - - This can be useful when functions on the top and bottom of the call stack - need to cooperate but the functions in between them do not allow passing the - necessary state. For example:: - - from twisted.python.context import call, get - - def handleRequest(request): - call({'request-id': request.id}, renderRequest, request.url) - - def renderRequest(url): - renderHeader(url) - renderBody(url) - - def renderHeader(url): - return "the header" - - def renderBody(url): - return "the body (request id=%r)" % (get("request-id"),) - - This should be used sparingly, since the lack of a clear connection between - the two halves can result in code which is difficult to understand and - maintain. - - @ivar contexts: A C{list} of C{dict}s tracking the context state. Each new - L{ContextTracker.callWithContext} pushes a new C{dict} onto this stack - for the duration of the call, making the data available to the function - called and restoring the previous data once it is complete.. - """ - def __init__(self): - self.contexts = [defaultContextDict] - - - def callWithContext(self, newContext, func, *args, **kw): - """ - Call C{func(*args, **kw)} such that the contents of C{newContext} will - be available for it to retrieve using L{getContext}. - - @param newContext: A C{dict} of data to push onto the context for the - duration of the call to C{func}. - - @param func: A callable which will be called. - - @param *args: Any additional positional arguments to pass to C{func}. - - @param **kw: Any additional keyword arguments to pass to C{func}. - - @return: Whatever is returned by C{func} - - @raise: Whatever is raised by C{func}. - """ - self.contexts.append(newContext) - try: - return func(*args,**kw) - finally: - self.contexts.pop() - - - def getContext(self, key, default=None): - """ - Retrieve the value for a key from the context. - - @param key: The key to look up in the context. - - @param default: The value to return if C{key} is not found in the - context. - - @return: The value most recently remembered in the context for C{key}. - """ - for ctx in reversed(self.contexts): - try: - return ctx[key] - except KeyError: - pass - return default - - - -class ThreadedContextTracker(object): - def __init__(self): - self.storage = local() - - def currentContext(self): - try: - return self.storage.ct - except AttributeError: - ct = self.storage.ct = ContextTracker() - return ct - - def callWithContext(self, ctx, func, *args, **kw): - return self.currentContext().callWithContext(ctx, func, *args, **kw) - - def getContext(self, key, default=None): - return self.currentContext().getContext(key, default) - - -def installContextTracker(ctr): - global theContextTracker - global call - global get - - theContextTracker = ctr - call = theContextTracker.callWithContext - get = theContextTracker.getContext - -installContextTracker(ThreadedContextTracker()) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/deprecate.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/deprecate.py deleted file mode 100644 index 4162bf2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/deprecate.py +++ /dev/null @@ -1,613 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_deprecate -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Deprecation framework for Twisted. - -To mark a method or function as being deprecated do this:: - - from twisted.python.versions import Version - from twisted.python.deprecate import deprecated - - @deprecated(Version("Twisted", 8, 0, 0)) - def badAPI(self, first, second): - ''' - Docstring for badAPI. - ''' - ... - -The newly-decorated badAPI will issue a warning when called. It will also have -a deprecation notice appended to its docstring. - -To mark module-level attributes as being deprecated you can use:: - - badAttribute = "someValue" - - ... - - deprecatedModuleAttribute( - Version("Twisted", 8, 0, 0), - "Use goodAttribute instead.", - "your.full.module.name", - "badAttribute") - -The deprecated attributes will issue a warning whenever they are accessed. If -the attributes being deprecated are in the same module as the -L{deprecatedModuleAttribute} call is being made from, the C{__name__} global -can be used as the C{moduleName} parameter. - -See also L{Version}. - -@type DEPRECATION_WARNING_FORMAT: C{str} -@var DEPRECATION_WARNING_FORMAT: The default deprecation warning string format - to use when one is not provided by the user. -""" - -from __future__ import division, absolute_import - -__all__ = [ - 'deprecated', - 'getDeprecationWarningString', - 'getWarningMethod', - 'setWarningMethod', - 'deprecatedModuleAttribute', - ] - - -import sys, inspect -from warnings import warn, warn_explicit -from dis import findlinestarts -from functools import wraps - -from twisted.python.versions import getVersionString - -DEPRECATION_WARNING_FORMAT = '%(fqpn)s was deprecated in %(version)s' - -# Notionally, part of twisted.python.reflect, but defining it there causes a -# cyclic dependency between this module and that module. Define it here, -# instead, and let reflect import it to re-expose to the public. -def _fullyQualifiedName(obj): - """ - Return the fully qualified name of a module, class, method or function. - Classes and functions need to be module level ones to be correctly - qualified. - - @rtype: C{str}. - """ - try: - name = obj.__qualname__ - except AttributeError: - name = obj.__name__ - - if inspect.isclass(obj) or inspect.isfunction(obj): - moduleName = obj.__module__ - return "%s.%s" % (moduleName, name) - elif inspect.ismethod(obj): - try: - cls = obj.im_class - except AttributeError: - # Python 3 eliminates im_class, substitutes __module__ and - # __qualname__ to provide similar information. - return "%s.%s" % (obj.__module__, obj.__qualname__) - else: - className = _fullyQualifiedName(cls) - return "%s.%s" % (className, name) - return name -# Try to keep it looking like something in twisted.python.reflect. -_fullyQualifiedName.__module__ = 'twisted.python.reflect' -_fullyQualifiedName.__name__ = 'fullyQualifiedName' -_fullyQualifiedName.__qualname__ = 'fullyQualifiedName' - - -def _getReplacementString(replacement): - """ - Surround a replacement for a deprecated API with some polite text exhorting - the user to consider it as an alternative. - - @type replacement: C{str} or callable - - @return: a string like "please use twisted.python.modules.getModule - instead". - """ - if callable(replacement): - replacement = _fullyQualifiedName(replacement) - return "please use %s instead" % (replacement,) - - - -def _getDeprecationDocstring(version, replacement=None): - """ - Generate an addition to a deprecated object's docstring that explains its - deprecation. - - @param version: the version it was deprecated. - @type version: L{Version} - - @param replacement: The replacement, if specified. - @type replacement: C{str} or callable - - @return: a string like "Deprecated in Twisted 27.2.0; please use - twisted.timestream.tachyon.flux instead." - """ - doc = "Deprecated in %s" % (getVersionString(version),) - if replacement: - doc = "%s; %s" % (doc, _getReplacementString(replacement)) - return doc + "." - - - -def _getDeprecationWarningString(fqpn, version, format=None, replacement=None): - """ - Return a string indicating that the Python name was deprecated in the given - version. - - @param fqpn: Fully qualified Python name of the thing being deprecated - @type fqpn: C{str} - - @param version: Version that C{fqpn} was deprecated in. - @type version: L{twisted.python.versions.Version} - - @param format: A user-provided format to interpolate warning values into, or - L{DEPRECATION_WARNING_FORMAT - } if C{None} is - given. - @type format: C{str} - - @param replacement: what should be used in place of C{fqpn}. Either pass in - a string, which will be inserted into the warning message, or a - callable, which will be expanded to its full import path. - @type replacement: C{str} or callable - - @return: A textual description of the deprecation - @rtype: C{str} - """ - if format is None: - format = DEPRECATION_WARNING_FORMAT - warningString = format % { - 'fqpn': fqpn, - 'version': getVersionString(version)} - if replacement: - warningString = "%s; %s" % ( - warningString, _getReplacementString(replacement)) - return warningString - - - -def getDeprecationWarningString(callableThing, version, format=None, - replacement=None): - """ - Return a string indicating that the callable was deprecated in the given - version. - - @type callableThing: C{callable} - @param callableThing: Callable object to be deprecated - - @type version: L{twisted.python.versions.Version} - @param version: Version that C{callableThing} was deprecated in - - @type format: C{str} - @param format: A user-provided format to interpolate warning values into, - or L{DEPRECATION_WARNING_FORMAT - } if C{None} is - given - - @param callableThing: A callable to be deprecated. - - @param version: The L{twisted.python.versions.Version} that the callable - was deprecated in. - - @param replacement: what should be used in place of the callable. Either - pass in a string, which will be inserted into the warning message, - or a callable, which will be expanded to its full import path. - @type replacement: C{str} or callable - - @return: A string describing the deprecation. - @rtype: C{str} - """ - return _getDeprecationWarningString( - _fullyQualifiedName(callableThing), version, format, replacement) - - - -def _appendToDocstring(thingWithDoc, textToAppend): - """ - Append the given text to the docstring of C{thingWithDoc}. - - If C{thingWithDoc} has no docstring, then the text just replaces the - docstring. If it has a single-line docstring then it appends a blank line - and the message text. If it has a multi-line docstring, then in appends a - blank line a the message text, and also does the indentation correctly. - """ - if thingWithDoc.__doc__: - docstringLines = thingWithDoc.__doc__.splitlines() - else: - docstringLines = [] - - if len(docstringLines) == 0: - docstringLines.append(textToAppend) - elif len(docstringLines) == 1: - docstringLines.extend(['', textToAppend, '']) - else: - spaces = docstringLines.pop() - docstringLines.extend(['', - spaces + textToAppend, - spaces]) - thingWithDoc.__doc__ = '\n'.join(docstringLines) - - - -def deprecated(version, replacement=None): - """ - Return a decorator that marks callables as deprecated. - - @type version: L{twisted.python.versions.Version} - @param version: The version in which the callable will be marked as - having been deprecated. The decorated function will be annotated - with this version, having it set as its C{deprecatedVersion} - attribute. - - @param version: the version that the callable was deprecated in. - @type version: L{twisted.python.versions.Version} - - @param replacement: what should be used in place of the callable. Either - pass in a string, which will be inserted into the warning message, - or a callable, which will be expanded to its full import path. - @type replacement: C{str} or callable - """ - def deprecationDecorator(function): - """ - Decorator that marks C{function} as deprecated. - """ - warningString = getDeprecationWarningString( - function, version, None, replacement) - - @wraps(function) - def deprecatedFunction(*args, **kwargs): - warn( - warningString, - DeprecationWarning, - stacklevel=2) - return function(*args, **kwargs) - - _appendToDocstring(deprecatedFunction, - _getDeprecationDocstring(version, replacement)) - deprecatedFunction.deprecatedVersion = version - return deprecatedFunction - - return deprecationDecorator - - - -def getWarningMethod(): - """ - Return the warning method currently used to record deprecation warnings. - """ - return warn - - - -def setWarningMethod(newMethod): - """ - Set the warning method to use to record deprecation warnings. - - The callable should take message, category and stacklevel. The return - value is ignored. - """ - global warn - warn = newMethod - - - -class _InternalState(object): - """ - An L{_InternalState} is a helper object for a L{_ModuleProxy}, so that it - can easily access its own attributes, bypassing its logic for delegating to - another object that it's proxying for. - - @ivar proxy: a L{ModuleProxy} - """ - def __init__(self, proxy): - object.__setattr__(self, 'proxy', proxy) - - - def __getattribute__(self, name): - return object.__getattribute__(object.__getattribute__(self, 'proxy'), - name) - - - def __setattr__(self, name, value): - return object.__setattr__(object.__getattribute__(self, 'proxy'), - name, value) - - - -class _ModuleProxy(object): - """ - Python module wrapper to hook module-level attribute access. - - Access to deprecated attributes first checks - L{_ModuleProxy._deprecatedAttributes}, if the attribute does not appear - there then access falls through to L{_ModuleProxy._module}, the wrapped - module object. - - @ivar _module: Module on which to hook attribute access. - @type _module: C{module} - - @ivar _deprecatedAttributes: Mapping of attribute names to objects that - retrieve the module attribute's original value. - @type _deprecatedAttributes: C{dict} mapping C{str} to - L{_DeprecatedAttribute} - - @ivar _lastWasPath: Heuristic guess as to whether warnings about this - package should be ignored for the next call. If the last attribute - access of this module was a C{getattr} of C{__path__}, we will assume - that it was the import system doing it and we won't emit a warning for - the next access, even if it is to a deprecated attribute. The CPython - import system always tries to access C{__path__}, then the attribute - itself, then the attribute itself again, in both successful and failed - cases. - @type _lastWasPath: C{bool} - """ - def __init__(self, module): - state = _InternalState(self) - state._module = module - state._deprecatedAttributes = {} - state._lastWasPath = False - - - def __repr__(self): - """ - Get a string containing the type of the module proxy and a - representation of the wrapped module object. - """ - state = _InternalState(self) - return '<%s module=%r>' % (type(self).__name__, state._module) - - - def __setattr__(self, name, value): - """ - Set an attribute on the wrapped module object. - """ - state = _InternalState(self) - state._lastWasPath = False - setattr(state._module, name, value) - - - def __getattribute__(self, name): - """ - Get an attribute from the module object, possibly emitting a warning. - - If the specified name has been deprecated, then a warning is issued. - (Unless certain obscure conditions are met; see - L{_ModuleProxy._lastWasPath} for more information about what might quash - such a warning.) - """ - state = _InternalState(self) - if state._lastWasPath: - deprecatedAttribute = None - else: - deprecatedAttribute = state._deprecatedAttributes.get(name) - - if deprecatedAttribute is not None: - # If we have a _DeprecatedAttribute object from the earlier lookup, - # allow it to issue the warning. - value = deprecatedAttribute.get() - else: - # Otherwise, just retrieve the underlying value directly; it's not - # deprecated, there's no warning to issue. - value = getattr(state._module, name) - if name == '__path__': - state._lastWasPath = True - else: - state._lastWasPath = False - return value - - - -class _DeprecatedAttribute(object): - """ - Wrapper for deprecated attributes. - - This is intended to be used by L{_ModuleProxy}. Calling - L{_DeprecatedAttribute.get} will issue a warning and retrieve the - underlying attribute's value. - - @type module: C{module} - @ivar module: The original module instance containing this attribute - - @type fqpn: C{str} - @ivar fqpn: Fully qualified Python name for the deprecated attribute - - @type version: L{twisted.python.versions.Version} - @ivar version: Version that the attribute was deprecated in - - @type message: C{str} - @ivar message: Deprecation message - """ - def __init__(self, module, name, version, message): - """ - Initialise a deprecated name wrapper. - """ - self.module = module - self.__name__ = name - self.fqpn = module.__name__ + '.' + name - self.version = version - self.message = message - - - def get(self): - """ - Get the underlying attribute value and issue a deprecation warning. - """ - # This might fail if the deprecated thing is a module inside a package. - # In that case, don't emit the warning this time. The import system - # will come back again when it's not an AttributeError and we can emit - # the warning then. - result = getattr(self.module, self.__name__) - message = _getDeprecationWarningString(self.fqpn, self.version, - DEPRECATION_WARNING_FORMAT + ': ' + self.message) - warn(message, DeprecationWarning, stacklevel=3) - return result - - - -def _deprecateAttribute(proxy, name, version, message): - """ - Mark a module-level attribute as being deprecated. - - @type proxy: L{_ModuleProxy} - @param proxy: The module proxy instance proxying the deprecated attributes - - @type name: C{str} - @param name: Attribute name - - @type version: L{twisted.python.versions.Version} - @param version: Version that the attribute was deprecated in - - @type message: C{str} - @param message: Deprecation message - """ - _module = object.__getattribute__(proxy, '_module') - attr = _DeprecatedAttribute(_module, name, version, message) - # Add a deprecated attribute marker for this module's attribute. When this - # attribute is accessed via _ModuleProxy a warning is emitted. - _deprecatedAttributes = object.__getattribute__( - proxy, '_deprecatedAttributes') - _deprecatedAttributes[name] = attr - - - -def deprecatedModuleAttribute(version, message, moduleName, name): - """ - Declare a module-level attribute as being deprecated. - - @type version: L{twisted.python.versions.Version} - @param version: Version that the attribute was deprecated in - - @type message: C{str} - @param message: Deprecation message - - @type moduleName: C{str} - @param moduleName: Fully-qualified Python name of the module containing - the deprecated attribute; if called from the same module as the - attributes are being deprecated in, using the C{__name__} global can - be helpful - - @type name: C{str} - @param name: Attribute name to deprecate - """ - module = sys.modules[moduleName] - if not isinstance(module, _ModuleProxy): - module = _ModuleProxy(module) - sys.modules[moduleName] = module - - _deprecateAttribute(module, name, version, message) - - -def warnAboutFunction(offender, warningString): - """ - Issue a warning string, identifying C{offender} as the responsible code. - - This function is used to deprecate some behavior of a function. It differs - from L{warnings.warn} in that it is not limited to deprecating the behavior - of a function currently on the call stack. - - @param function: The function that is being deprecated. - - @param warningString: The string that should be emitted by this warning. - @type warningString: C{str} - - @since: 11.0 - """ - # inspect.getmodule() is attractive, but somewhat - # broken in Python < 2.6. See Python bug 4845. - offenderModule = sys.modules[offender.__module__] - filename = inspect.getabsfile(offenderModule) - lineStarts = list(findlinestarts(offender.__code__)) - lastLineNo = lineStarts[-1][1] - globals = offender.__globals__ - - kwargs = dict( - category=DeprecationWarning, - filename=filename, - lineno=lastLineNo, - module=offenderModule.__name__, - registry=globals.setdefault("__warningregistry__", {}), - module_globals=None) - - warn_explicit(warningString, **kwargs) - - - -def _passed(argspec, positional, keyword): - """ - Take an L{inspect.ArgSpec}, a tuple of positional arguments, and a dict of - keyword arguments, and return a mapping of arguments that were actually - passed to their passed values. - - @param argspec: The argument specification for the function to inspect. - @type argspec: L{inspect.ArgSpec} - - @param positional: The positional arguments that were passed. - @type positional: L{tuple} - - @param keyword: The keyword arguments that were passed. - @type keyword: L{dict} - - @return: A dictionary mapping argument names (those declared in C{argspec}) - to values that were passed explicitly by the user. - @rtype: L{dict} mapping L{str} to L{object} - """ - result = {} - unpassed = len(argspec.args) - len(positional) - if argspec.keywords is not None: - kwargs = result[argspec.keywords] = {} - if unpassed < 0: - if argspec.varargs is None: - raise TypeError("Too many arguments.") - else: - result[argspec.varargs] = positional[len(argspec.args):] - for name, value in zip(argspec.args, positional): - result[name] = value - for name, value in keyword.items(): - if name in argspec.args: - if name in result: - raise TypeError("Already passed.") - result[name] = value - elif argspec.keywords is not None: - kwargs[name] = value - else: - raise TypeError("no such param") - return result - - - -def _mutuallyExclusiveArguments(argumentPairs): - """ - Decorator which causes its decoratee to raise a L{TypeError} if two of the - given arguments are passed at the same time. - - @param argumentPairs: pairs of argument identifiers, each pair indicating - an argument that may not be passed in conjunction with another. - @type argumentPairs: sequence of 2-sequences of L{str} - - @return: A decorator, used like so:: - - @_mutuallyExclusiveArguments([["tweedledum", "tweedledee"]]) - def function(tweedledum=1, tweedledee=2): - "Don't pass tweedledum and tweedledee at the same time." - - @rtype: 1-argument callable taking a callable and returning a callable. - """ - def wrapper(wrappee): - argspec = inspect.getargspec(wrappee) - @wraps(wrappee) - def wrapped(*args, **kwargs): - arguments = _passed(argspec, args, kwargs) - for this, that in argumentPairs: - if this in arguments and that in arguments: - raise TypeError("nope") - return wrappee(*args, **kwargs) - return wrapped - return wrapper diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/dist.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/dist.py deleted file mode 100644 index 679a5b5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/dist.py +++ /dev/null @@ -1,503 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_dist -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Distutils convenience functionality. - -Don't use this outside of Twisted. - -Maintainer: Christopher Armstrong - -@var _EXTRA_OPTIONS: These are the actual package names and versions that will - be used by C{extras_require}. This is not passed to setup directly so that - combinations of the packages can be created without the need to copy - package names multiple times. - -@var _EXTRAS_REQUIRE: C{extras_require} is a dictionary of items that can be - passed to setup.py to install optional dependencies. For example, to - install the optional dev dependencies one would type:: - - pip install -e ".[dev]" - - This has been supported by setuptools since 0.5a4. - -@var _PLATFORM_INDEPENDENT: A list of all optional cross-platform dependencies, - as setuptools version specifiers, used to populate L{_EXTRAS_REQUIRE}. -""" - -from distutils.command import build_scripts, install_data, build_ext -from distutils.errors import CompileError -from distutils import core -from distutils.core import Extension -import fnmatch -import os -import platform -import sys - -from twisted import copyright -from twisted.python.compat import execfile - -STATIC_PACKAGE_METADATA = dict( - name="Twisted", - version=copyright.version, - description="An asynchronous networking framework written in Python", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Glyph Lefkowitz", - maintainer_email="glyph@twistedmatrix.com", - url="http://twistedmatrix.com/", - license="MIT", - long_description="""\ -An extensible framework for Python programming, with special focus -on event-based network programming and multiprotocol integration. -""", - classifiers=[ - "Programming Language :: Python :: 2.6", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - ], - ) - - -twisted_subprojects = ["conch", "lore", "mail", "names", - "news", "pair", "runner", "web", - "words"] - -_EXTRA_OPTIONS = dict( - dev=['twistedchecker >= 0.2.0', - 'pyflakes >= 0.8.1', - 'twisted-dev-tools >= 0.0.2', - 'python-subunit', - 'sphinx >= 1.2.2', - 'pydoctor >= 0.5'], - tls=['pyopenssl >= 0.11', - 'service_identity', - 'idna >= 0.6'], - conch=['gmpy', - 'pyasn1', - 'pycrypto'], - soap=['soappy'], - serial=['pyserial'], - osx=['pyobjc'], - windows=['pypiwin32'] -) - -_PLATFORM_INDEPENDENT = ( - _EXTRA_OPTIONS['tls'] + - _EXTRA_OPTIONS['conch'] + - _EXTRA_OPTIONS['soap'] + - _EXTRA_OPTIONS['serial'] -) - -_EXTRAS_REQUIRE = { - 'dev': _EXTRA_OPTIONS['dev'], - 'tls': _EXTRA_OPTIONS['tls'], - 'conch': _EXTRA_OPTIONS['conch'], - 'soap': _EXTRA_OPTIONS['soap'], - 'serial': _EXTRA_OPTIONS['serial'], - 'all_non_platform': _PLATFORM_INDEPENDENT, - 'osx_platform': ( - _EXTRA_OPTIONS['osx'] + _PLATFORM_INDEPENDENT - ), - 'windows_platform': ( - _EXTRA_OPTIONS['windows'] + _PLATFORM_INDEPENDENT - ), -} - - -class ConditionalExtension(Extension): - """ - An extension module that will only be compiled if certain conditions are - met. - - @param condition: A callable of one argument which returns True or False to - indicate whether the extension should be built. The argument is an - instance of L{build_ext_twisted}, which has useful methods for checking - things about the platform. - """ - def __init__(self, *args, **kwargs): - self.condition = kwargs.pop("condition", lambda builder: True) - Extension.__init__(self, *args, **kwargs) - - - -def setup(**kw): - """ - An alternative to distutils' setup() which is specially designed - for Twisted subprojects. - - Pass twisted_subproject=projname if you want package and data - files to automatically be found for you. - - @param conditionalExtensions: Extensions to optionally build. - @type conditionalExtensions: C{list} of L{ConditionalExtension} - """ - return core.setup(**get_setup_args(**kw)) - - -def get_setup_args(**kw): - if 'twisted_subproject' in kw: - if 'twisted' not in os.listdir('.'): - raise RuntimeError("Sorry, you need to run setup.py from the " - "toplevel source directory.") - projname = kw['twisted_subproject'] - projdir = os.path.join('twisted', projname) - - kw['packages'] = getPackages(projdir, parent='twisted') - kw['version'] = getVersion(projname) - - plugin = "twisted/plugins/twisted_" + projname + ".py" - if os.path.exists(plugin): - kw.setdefault('py_modules', []).append( - plugin.replace("/", ".")[:-3]) - - kw['data_files'] = getDataFiles(projdir, parent='twisted') - - del kw['twisted_subproject'] - else: - if 'plugins' in kw: - py_modules = [] - for plg in kw['plugins']: - py_modules.append("twisted.plugins." + plg) - kw.setdefault('py_modules', []).extend(py_modules) - del kw['plugins'] - - if 'cmdclass' not in kw: - kw['cmdclass'] = { - 'install_data': install_data_twisted, - 'build_scripts': build_scripts_twisted} - - if "conditionalExtensions" in kw: - extensions = kw["conditionalExtensions"] - del kw["conditionalExtensions"] - - if 'ext_modules' not in kw: - # This is a workaround for distutils behavior; ext_modules isn't - # actually used by our custom builder. distutils deep-down checks - # to see if there are any ext_modules defined before invoking - # the build_ext command. We need to trigger build_ext regardless - # because it is the thing that does the conditional checks to see - # if it should build any extensions. The reason we have to delay - # the conditional checks until then is that the compiler objects - # are not yet set up when this code is executed. - kw["ext_modules"] = extensions - - class my_build_ext(build_ext_twisted): - conditionalExtensions = extensions - kw.setdefault('cmdclass', {})['build_ext'] = my_build_ext - return kw - - -def getVersion(proj, base="twisted"): - """ - Extract the version number for a given project. - - @param proj: the name of the project. Examples are "core", - "conch", "words", "mail". - - @rtype: str - @returns: The version number of the project, as a string like - "2.0.0". - """ - if proj == 'core': - vfile = os.path.join(base, '_version.py') - else: - vfile = os.path.join(base, proj, '_version.py') - ns = {'__name__': 'Nothing to see here'} - execfile(vfile, ns) - return ns['version'].base() - - -# Names that are excluded from globbing results: -EXCLUDE_NAMES = ["{arch}", "CVS", ".cvsignore", "_darcs", - "RCS", "SCCS", ".svn"] -EXCLUDE_PATTERNS = ["*.py[cdo]", "*.s[ol]", ".#*", "*~", "*.py"] - - -def _filterNames(names): - """ - Given a list of file names, return those names that should be copied. - """ - names = [n for n in names - if n not in EXCLUDE_NAMES] - # This is needed when building a distro from a working - # copy (likely a checkout) rather than a pristine export: - for pattern in EXCLUDE_PATTERNS: - names = [n for n in names - if (not fnmatch.fnmatch(n, pattern)) - and (not n.endswith('.py'))] - return names - - -def relativeTo(base, relativee): - """ - Gets 'relativee' relative to 'basepath'. - - i.e., - - >>> relativeTo('/home/', '/home/radix/') - 'radix' - >>> relativeTo('.', '/home/radix/Projects/Twisted') # curdir is /home/radix - 'Projects/Twisted' - - The 'relativee' must be a child of 'basepath'. - """ - basepath = os.path.abspath(base) - relativee = os.path.abspath(relativee) - if relativee.startswith(basepath): - relative = relativee[len(basepath):] - if relative.startswith(os.sep): - relative = relative[1:] - return os.path.join(base, relative) - raise ValueError("%s is not a subpath of %s" % (relativee, basepath)) - - -def getDataFiles(dname, ignore=None, parent=None): - """ - Get all the data files that should be included in this distutils Project. - - 'dname' should be the path to the package that you're distributing. - - 'ignore' is a list of sub-packages to ignore. This facilitates - disparate package hierarchies. That's a fancy way of saying that - the 'twisted' package doesn't want to include the 'twisted.conch' - package, so it will pass ['conch'] as the value. - - 'parent' is necessary if you're distributing a subpackage like - twisted.conch. 'dname' should point to 'twisted/conch' and 'parent' - should point to 'twisted'. This ensures that your data_files are - generated correctly, only using relative paths for the first element - of the tuple ('twisted/conch/*'). - The default 'parent' is the current working directory. - """ - parent = parent or "." - ignore = ignore or [] - result = [] - for directory, subdirectories, filenames in os.walk(dname): - resultfiles = [] - for exname in EXCLUDE_NAMES: - if exname in subdirectories: - subdirectories.remove(exname) - for ig in ignore: - if ig in subdirectories: - subdirectories.remove(ig) - for filename in _filterNames(filenames): - resultfiles.append(filename) - if resultfiles: - result.append((relativeTo(parent, directory), - [relativeTo(parent, - os.path.join(directory, filename)) - for filename in resultfiles])) - return result - - -def getExtensions(): - """ - Get all extensions from core and all subprojects. - """ - extensions = [] - - if not sys.platform.startswith('java'): - for dir in os.listdir("twisted") + [""]: - topfiles = os.path.join("twisted", dir, "topfiles") - if os.path.isdir(topfiles): - ns = {} - setup_py = os.path.join(topfiles, "setup.py") - execfile(setup_py, ns, ns) - if "extensions" in ns: - extensions.extend(ns["extensions"]) - - return extensions - - -def getPackages(dname, pkgname=None, results=None, ignore=None, parent=None): - """ - Get all packages which are under dname. This is necessary for - Python 2.2's distutils. Pretty similar arguments to getDataFiles, - including 'parent'. - """ - parent = parent or "" - prefix = [] - if parent: - prefix = [parent] - bname = os.path.basename(dname) - ignore = ignore or [] - if bname in ignore: - return [] - if results is None: - results = [] - if pkgname is None: - pkgname = [] - subfiles = os.listdir(dname) - abssubfiles = [os.path.join(dname, x) for x in subfiles] - if '__init__.py' in subfiles: - results.append(prefix + pkgname + [bname]) - for subdir in filter(os.path.isdir, abssubfiles): - getPackages(subdir, pkgname=pkgname + [bname], - results=results, ignore=ignore, - parent=parent) - res = ['.'.join(result) for result in results] - return res - - - -def getAllScripts(): - # "" is included because core scripts are directly in bin/ - projects = [''] + [x for x in os.listdir('bin') - if os.path.isdir(os.path.join("bin", x)) - and x in twisted_subprojects] - scripts = [] - for i in projects: - scripts.extend(getScripts(i)) - return scripts - - - -def getScripts(projname, basedir=''): - """ - Returns a list of scripts for a Twisted subproject; this works in - any of an SVN checkout, a project-specific tarball. - """ - scriptdir = os.path.join(basedir, 'bin', projname) - if not os.path.isdir(scriptdir): - # Probably a project-specific tarball, in which case only this - # project's bins are included in 'bin' - scriptdir = os.path.join(basedir, 'bin') - if not os.path.isdir(scriptdir): - return [] - thingies = os.listdir(scriptdir) - for specialExclusion in ['.svn', '_preamble.py', '_preamble.pyc']: - if specialExclusion in thingies: - thingies.remove(specialExclusion) - return filter(os.path.isfile, - [os.path.join(scriptdir, x) for x in thingies]) - - -## Helpers and distutil tweaks - -class build_scripts_twisted(build_scripts.build_scripts): - """ - Renames scripts so they end with '.py' on Windows. - """ - def run(self): - build_scripts.build_scripts.run(self) - if not os.name == "nt": - return - for f in os.listdir(self.build_dir): - fpath = os.path.join(self.build_dir, f) - if not fpath.endswith(".py"): - pypath = fpath + ".py" - if os.path.exists(pypath): - os.unlink(pypath) - os.rename(fpath, pypath) - - - -class install_data_twisted(install_data.install_data): - """ - I make sure data files are installed in the package directory. - """ - def finalize_options(self): - self.set_undefined_options('install', - ('install_lib', 'install_dir') - ) - install_data.install_data.finalize_options(self) - - - -class build_ext_twisted(build_ext.build_ext): - """ - Allow subclasses to easily detect and customize Extensions to - build at install-time. - """ - - def prepare_extensions(self): - """ - Prepare the C{self.extensions} attribute (used by - L{build_ext.build_ext}) by checking which extensions in - L{conditionalExtensions} should be built. In addition, if we are - building on NT, define the WIN32 macro to 1. - """ - # always define WIN32 under Windows - if os.name == 'nt': - self.define_macros = [("WIN32", 1)] - else: - self.define_macros = [] - - # On Solaris 10, we need to define the _XOPEN_SOURCE and - # _XOPEN_SOURCE_EXTENDED macros to build in order to gain access to - # the msg_control, msg_controllen, and msg_flags members in - # sendmsg.c. (according to - # http://stackoverflow.com/questions/1034587). See the documentation - # of X/Open CAE in the standards(5) man page of Solaris. - if sys.platform.startswith('sunos'): - self.define_macros.append(('_XOPEN_SOURCE', 1)) - self.define_macros.append(('_XOPEN_SOURCE_EXTENDED', 1)) - - self.extensions = [x for x in self.conditionalExtensions - if x.condition(self)] - - for ext in self.extensions: - ext.define_macros.extend(self.define_macros) - - - def build_extensions(self): - """ - Check to see which extension modules to build and then build them. - """ - self.prepare_extensions() - build_ext.build_ext.build_extensions(self) - - - def _remove_conftest(self): - for filename in ("conftest.c", "conftest.o", "conftest.obj"): - try: - os.unlink(filename) - except EnvironmentError: - pass - - - def _compile_helper(self, content): - conftest = open("conftest.c", "w") - try: - conftest.write(content) - conftest.close() - - try: - self.compiler.compile(["conftest.c"], output_dir='') - except CompileError: - return False - return True - finally: - self._remove_conftest() - - - def _check_header(self, header_name): - """ - Check if the given header can be included by trying to compile a file - that contains only an #include line. - """ - self.compiler.announce("checking for %s ..." % header_name, 0) - return self._compile_helper("#include <%s>\n" % header_name) - - - -def _checkCPython(sys=sys, platform=platform): - """ - Checks if this implementation is CPython. - - This uses C{platform.python_implementation}. - - This takes C{sys} and C{platform} kwargs that by default use the real - modules. You shouldn't care about these -- they are for testing purposes - only. - - @return: C{False} if the implementation is definitely not CPython, C{True} - otherwise. - """ - return platform.python_implementation() == "CPython" - - -_isCPython = _checkCPython() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/dist3.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/dist3.py deleted file mode 100644 index 63c79db..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/dist3.py +++ /dev/null @@ -1,333 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_dist3 -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for installing Twisted on Python 3. - -Only necessary while parts of Twisted are unported. - -@var modules: A list of modules that have been ported, - e.g. "twisted.python.versions"; a package name (e.g. "twisted.python") - indicates the corresponding __init__.py file has been ported - (e.g. "twisted/python/__init__.py"). To reduce merge conflicts, add new - lines in alphabetical sort. - -@var testModules: A list of test modules that have been ported, e.g - "twisted.python.test.test_versions". To reduce merge conflicts, add new - lines in alphabetical sort. - -@var almostModules: A list of any other modules which are needed by any of the - modules in the other two lists, but which themselves have not actually - been properly ported to Python 3. These modules might work well enough to - satisfy some of the requirements of the modules that depend on them, but - cannot be considered generally usable otherwise. - -@var modulesToInstall: A list of all modules that should be installed on - Python 3. -""" - -from __future__ import division - - -modules = [ - "twisted", - "twisted._version", - "twisted.copyright", - "twisted.cred", - "twisted.cred._digest", - "twisted.cred.credentials", - "twisted.cred.error", - "twisted.internet", - "twisted.internet._baseprocess", - "twisted.internet._glibbase", - "twisted.internet._newtls", - "twisted.internet._posixstdio", - "twisted.internet._signals", - "twisted.internet.abstract", - "twisted.internet.address", - "twisted.internet.base", - "twisted.internet.default", - "twisted.internet.defer", - "twisted.internet.endpoints", - "twisted.internet.epollreactor", - "twisted.internet.error", - "twisted.internet.fdesc", - "twisted.internet.gireactor", - "twisted.internet.gtk3reactor", - "twisted.internet.interfaces", - "twisted.internet.kqreactor", - "twisted.internet.main", - "twisted.internet.pollreactor", - "twisted.internet.posixbase", - "twisted.internet.process", - "twisted.internet.protocol", - "twisted.internet.reactor", - "twisted.internet.selectreactor", - "twisted.internet.ssl", - "twisted.internet.task", - "twisted.internet.tcp", - "twisted.internet.test", - "twisted.internet.test._posixifaces", - "twisted.internet.test.connectionmixins", - "twisted.internet.test.modulehelpers", - "twisted.internet.test.reactormixins", - "twisted.internet.threads", - "twisted.internet.udp", - "twisted.internet.utils", - "twisted.logger", - "twisted.logger._buffer", - "twisted.logger._file", - "twisted.logger._filter", - "twisted.logger._flatten", - "twisted.logger._format", - "twisted.logger._global", - "twisted.logger._io", - "twisted.logger._json", - "twisted.logger._legacy", - "twisted.logger._levels", - "twisted.logger._logger", - "twisted.logger._observer", - "twisted.logger._stdlib", - "twisted.logger._util", - "twisted.names", - "twisted.names._rfc1982", - "twisted.names._version", - "twisted.names.cache", - "twisted.names.client", - "twisted.names.common", - "twisted.names.dns", - "twisted.names.error", - "twisted.names.hosts", - "twisted.names.resolve", - "twisted.names.test", - "twisted.protocols", - "twisted.protocols.basic", - "twisted.protocols.policies", - "twisted.protocols.test", - "twisted.protocols.tls", - "twisted.python", - "twisted.python._tzhelper", - "twisted.python.compat", - "twisted.python.components", - "twisted.python.constants", - "twisted.python.context", - "twisted.python.deprecate", - "twisted.python.dist3", - "twisted.python.failure", - "twisted.python.filepath", - "twisted.python.lockfile", - "twisted.python.log", - "twisted.python.modules", - "twisted.python.monkey", - "twisted.python.randbytes", - "twisted.python.reflect", - "twisted.python.runtime", - "twisted.python.systemd", - "twisted.python.procutils", - "twisted.python.test", - "twisted.python.test.deprecatedattributes", - "twisted.python.test.modules_helpers", - "twisted.python.threadable", - "twisted.python.threadpool", - "twisted.python.urlpath", - "twisted.python.usage", - "twisted.python.util", - "twisted.python.versions", - "twisted.test", - "twisted.test.iosim", - "twisted.test.proto_helpers", - "twisted.test.ssl_helpers", - "twisted.trial", - "twisted.trial._asyncrunner", - "twisted.trial._asynctest", - "twisted.trial._synctest", - "twisted.trial.itrial", - "twisted.trial.test", - "twisted.trial.test.detests", - "twisted.trial.test.erroneous", - "twisted.trial.test.packages", - "twisted.trial.test.skipping", - "twisted.trial.test.suppression", - "twisted.trial.test.suppression", - "twisted.trial.unittest", - "twisted.trial.util", - "twisted.web", - "twisted.web._newclient", - "twisted.web._responses", - "twisted.web._version", - "twisted.web.http_headers", - "twisted.web.resource", - "twisted.web.script", - "twisted.web.static", - "twisted.web.test", - "twisted.web.test.requesthelper", -] - - - -testModules = [ - "twisted.cred.test", - "twisted.cred.test.test_cramauth", - "twisted.cred.test.test_digestauth", - "twisted.cred.test.test_simpleauth", - "twisted.internet.test.test_abstract", - "twisted.internet.test.test_address", - "twisted.internet.test.test_base", - "twisted.internet.test.test_core", - "twisted.internet.test.test_default", - "twisted.internet.test.test_endpoints", - "twisted.internet.test.test_epollreactor", - "twisted.internet.test.test_fdset", - "twisted.internet.test.test_filedescriptor", - "twisted.internet.test.test_gireactor", - "twisted.internet.test.test_glibbase", - "twisted.internet.test.test_inlinecb", - "twisted.internet.test.test_main", - "twisted.internet.test.test_newtls", - "twisted.internet.test.test_posixbase", - "twisted.internet.test.test_posixprocess", - "twisted.internet.test.test_process", - "twisted.internet.test.test_protocol", - "twisted.internet.test.test_sigchld", - "twisted.internet.test.test_tcp", - "twisted.internet.test.test_threads", - "twisted.internet.test.test_tls", - "twisted.internet.test.test_udp", - "twisted.internet.test.test_udp_internals", - "twisted.logger.test", - "twisted.logger.test.test_buffer", - "twisted.logger.test.test_file", - "twisted.logger.test.test_filter", - "twisted.logger.test.test_flatten", - "twisted.logger.test.test_format", - "twisted.logger.test.test_global", - "twisted.logger.test.test_io", - "twisted.logger.test.test_json", - "twisted.logger.test.test_legacy", - "twisted.logger.test.test_levels", - "twisted.logger.test.test_logger", - "twisted.logger.test.test_observer", - "twisted.logger.test.test_stdlib", - "twisted.logger.test.test_util", - "twisted.names.test.test_cache", - "twisted.names.test.test_client", - "twisted.names.test.test_common", - "twisted.names.test.test_dns", - "twisted.names.test.test_hosts", - "twisted.names.test.test_rfc1982", - "twisted.names.test.test_util", - "twisted.protocols.test.test_basic", - "twisted.protocols.test.test_tls", - "twisted.python.test.test_components", - "twisted.python.test.test_constants", - "twisted.python.test.test_deprecate", - "twisted.python.test.test_dist3", - "twisted.python.test.test_runtime", - "twisted.python.test.test_systemd", - "twisted.python.test.test_tzhelper", - "twisted.python.test.test_urlpath", - "twisted.python.test.test_util", - "twisted.python.test.test_versions", - "twisted.test.testutils", - "twisted.test.test_abstract", - "twisted.test.test_compat", - "twisted.test.test_context", - "twisted.test.test_cooperator", - "twisted.test.test_defer", - "twisted.test.test_defgen", - "twisted.test.test_error", - "twisted.test.test_factories", - "twisted.test.test_failure", - "twisted.test.test_fdesc", - "twisted.test.test_internet", - "twisted.test.test_iosim", - "twisted.test.test_iutils", - "twisted.test.test_lockfile", - "twisted.test.test_log", - "twisted.test.test_loopback", - "twisted.test.test_modules", - "twisted.test.test_monkey", - "twisted.test.test_paths", - "twisted.test.test_policies", - "twisted.test.test_process", - "twisted.test.test_randbytes", - "twisted.test.test_reflect", - "twisted.test.test_setup", - "twisted.test.test_ssl", - "twisted.test.test_sslverify", - "twisted.test.test_task", - "twisted.test.test_tcp", - "twisted.test.test_tcp_internals", - "twisted.test.test_threadable", - "twisted.test.test_threadpool", - "twisted.test.test_threads", - "twisted.test.test_twisted", - "twisted.test.test_udp", - "twisted.test.test_usage", - "twisted.trial.test.test_assertions", - "twisted.trial.test.test_asyncassertions", - "twisted.trial.test.test_deferred", - "twisted.trial.test.test_log", - "twisted.trial.test.test_pyunitcompat", - "twisted.trial.test.test_suppression", - "twisted.trial.test.test_testcase", - "twisted.trial.test.test_tests", - "twisted.trial.test.test_util", - "twisted.trial.test.test_warning", - "twisted.web.test._util", - # The downloadPage tests weren't ported: - "twisted.web.test.test_http", - "twisted.web.test.test_http_headers", - "twisted.web.test.test_newclient", - "twisted.web.test.test_resource", - "twisted.web.test.test_script", - "twisted.web.test.test_static", - "twisted.web.test.test_web", - "twisted.web.test.test_webclient", -] - - - -almostModules = [ - # Missing test coverage, see #6156: - "twisted.internet._sslverify", - # twisted.names.client semi-depends on twisted.names.root, but only on - # Windows really: - "twisted.names.root", - # Missing test coverage: - "twisted.protocols.loopback", - # Minimally used by setup3.py: - "twisted.python.dist", - # twisted.python.filepath depends on twisted.python.win32, but on Linux it - # only really needs to import: - "twisted.python.win32", - "twisted.test.reflect_helper_IE", - "twisted.test.reflect_helper_VE", - "twisted.test.reflect_helper_ZDE", - # Required by some of the ported trial tests: - "twisted.trial.reporter", - # Agent code and downloadPage aren't ported, test coverage isn't complete: - "twisted.web.client", - # twisted.web.resource depends on twisted.web.error, so it is sorta - # ported, but its tests are not yet ported, so it probably doesn't - # completely work. - "twisted.web.error", - # Required by twisted.web.server, no actual code here: - "twisted.web.iweb", - # Required by twisted.web.server for an error handling case: - "twisted.web.html", - # This module has a lot of missing test coverage. What tests it has pass, - # but it needs a lot more. It was ported only enough to make the client - # work. - "twisted.web.http", - # GzipEncoder and allowed methods functionality not ported, no doubt - # missing lots of test coverage: - "twisted.web.server", - # Parts are ported for twisted.web.static - "twisted.web.util", -] - - - -modulesToInstall = modules + testModules + almostModules diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/failure.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/failure.py deleted file mode 100644 index aa68ac9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/failure.py +++ /dev/null @@ -1,654 +0,0 @@ -# -*- test-case-name: twisted.test.test_failure -*- -# See also test suite twisted.test.test_pbfailure - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Asynchronous-friendly error mechanism. - -See L{Failure}. -""" - -from __future__ import division, absolute_import - -# System Imports -import sys -import linecache -import inspect -import opcode -from inspect import getmro - -from twisted.python.compat import _PY3, NativeStringIO as StringIO -from twisted.python import reflect - -count = 0 -traceupLength = 4 - -class DefaultException(Exception): - pass - -def format_frames(frames, write, detail="default"): - """Format and write frames. - - @param frames: is a list of frames as used by Failure.frames, with - each frame being a list of - (funcName, fileName, lineNumber, locals.items(), globals.items()) - @type frames: list - @param write: this will be called with formatted strings. - @type write: callable - @param detail: Four detail levels are available: - default, brief, verbose, and verbose-vars-not-captured. - C{Failure.printDetailedTraceback} uses the latter when the caller asks - for verbose, but no vars were captured, so that an explicit warning - about the missing data is shown. - @type detail: string - """ - if detail not in ('default', 'brief', 'verbose', - 'verbose-vars-not-captured'): - raise ValueError( - "Detail must be default, brief, verbose, or " - "verbose-vars-not-captured. (not %r)" % (detail,)) - w = write - if detail == "brief": - for method, filename, lineno, localVars, globalVars in frames: - w('%s:%s:%s\n' % (filename, lineno, method)) - elif detail == "default": - for method, filename, lineno, localVars, globalVars in frames: - w( ' File "%s", line %s, in %s\n' % (filename, lineno, method)) - w( ' %s\n' % linecache.getline(filename, lineno).strip()) - elif detail == "verbose-vars-not-captured": - for method, filename, lineno, localVars, globalVars in frames: - w("%s:%d: %s(...)\n" % (filename, lineno, method)) - w(' [Capture of Locals and Globals disabled (use captureVars=True)]\n') - elif detail == "verbose": - for method, filename, lineno, localVars, globalVars in frames: - w("%s:%d: %s(...)\n" % (filename, lineno, method)) - w(' [ Locals ]\n') - # Note: the repr(val) was (self.pickled and val) or repr(val))) - for name, val in localVars: - w(" %s : %s\n" % (name, repr(val))) - w(' ( Globals )\n') - for name, val in globalVars: - w(" %s : %s\n" % (name, repr(val))) - -# slyphon: i have a need to check for this value in trial -# so I made it a module-level constant -EXCEPTION_CAUGHT_HERE = "--- ---" - - - -class NoCurrentExceptionError(Exception): - """ - Raised when trying to create a Failure from the current interpreter - exception state and there is no current exception state. - """ - - -class _Traceback(object): - """ - Fake traceback object which can be passed to functions in the standard - library L{traceback} module. - """ - - def __init__(self, frames): - """ - Construct a fake traceback object using a list of frames. Note that - although frames generally include locals and globals, this information - is not kept by this object, since locals and globals are not used in - standard tracebacks. - - @param frames: [(methodname, filename, lineno, locals, globals), ...] - """ - assert len(frames) > 0, "Must pass some frames" - head, frames = frames[0], frames[1:] - name, filename, lineno, localz, globalz = head - self.tb_frame = _Frame(name, filename) - self.tb_lineno = lineno - if len(frames) == 0: - self.tb_next = None - else: - self.tb_next = _Traceback(frames) - - -class _Frame(object): - """ - A fake frame object, used by L{_Traceback}. - - @ivar f_code: fake L{code} object - @ivar f_globals: fake f_globals dictionary (usually empty) - @ivar f_locals: fake f_locals dictionary (usually empty) - """ - - def __init__(self, name, filename): - """ - @param name: method/function name for this frame. - @type name: C{str} - @param filename: filename for this frame. - @type name: C{str} - """ - self.f_code = _Code(name, filename) - self.f_globals = {} - self.f_locals = {} - - -class _Code(object): - """ - A fake code object, used by L{_Traceback} via L{_Frame}. - """ - def __init__(self, name, filename): - self.co_name = name - self.co_filename = filename - - -class Failure: - """ - A basic abstraction for an error that has occurred. - - This is necessary because Python's built-in error mechanisms are - inconvenient for asynchronous communication. - - The C{stack} and C{frame} attributes contain frames. Each frame is a tuple - of (funcName, fileName, lineNumber, localsItems, globalsItems), where - localsItems and globalsItems are the contents of - C{locals().items()}/C{globals().items()} for that frame, or an empty tuple - if those details were not captured. - - @ivar value: The exception instance responsible for this failure. - @ivar type: The exception's class. - @ivar stack: list of frames, innermost last, excluding C{Failure.__init__}. - @ivar frames: list of frames, innermost first. - """ - - pickled = 0 - stack = None - - # The opcode of "yield" in Python bytecode. We need this in _findFailure in - # order to identify whether an exception was thrown by a - # throwExceptionIntoGenerator. - _yieldOpcode = chr(opcode.opmap["YIELD_VALUE"]) - - def __init__(self, exc_value=None, exc_type=None, exc_tb=None, - captureVars=False): - """ - Initialize me with an explanation of the error. - - By default, this will use the current C{exception} - (L{sys.exc_info}()). However, if you want to specify a - particular kind of failure, you can pass an exception as an - argument. - - If no C{exc_value} is passed, then an "original" C{Failure} will - be searched for. If the current exception handler that this - C{Failure} is being constructed in is handling an exception - raised by L{raiseException}, then this C{Failure} will act like - the original C{Failure}. - - For C{exc_tb} only L{traceback} instances or C{None} are allowed. - If C{None} is supplied for C{exc_value}, the value of C{exc_tb} is - ignored, otherwise if C{exc_tb} is C{None}, it will be found from - execution context (ie, L{sys.exc_info}). - - @param captureVars: if set, capture locals and globals of stack - frames. This is pretty slow, and makes no difference unless you - are going to use L{printDetailedTraceback}. - """ - global count - count = count + 1 - self.count = count - self.type = self.value = tb = None - self.captureVars = captureVars - - if isinstance(exc_value, str) and exc_type is None: - raise TypeError("Strings are not supported by Failure") - - stackOffset = 0 - - if exc_value is None: - exc_value = self._findFailure() - - if exc_value is None: - self.type, self.value, tb = sys.exc_info() - if self.type is None: - raise NoCurrentExceptionError() - stackOffset = 1 - elif exc_type is None: - if isinstance(exc_value, Exception): - self.type = exc_value.__class__ - else: #allow arbitrary objects. - self.type = type(exc_value) - self.value = exc_value - else: - self.type = exc_type - self.value = exc_value - if isinstance(self.value, Failure): - self.__dict__ = self.value.__dict__ - return - if tb is None: - if exc_tb: - tb = exc_tb - elif _PY3: - tb = self.value.__traceback__ - - frames = self.frames = [] - stack = self.stack = [] - - # added 2003-06-23 by Chris Armstrong. Yes, I actually have a - # use case where I need this traceback object, and I've made - # sure that it'll be cleaned up. - self.tb = tb - - if tb: - f = tb.tb_frame - elif not isinstance(self.value, Failure): - # we don't do frame introspection since it's expensive, - # and if we were passed a plain exception with no - # traceback, it's not useful anyway - f = stackOffset = None - - while stackOffset and f: - # This excludes this Failure.__init__ frame from the - # stack, leaving it to start with our caller instead. - f = f.f_back - stackOffset -= 1 - - # Keeps the *full* stack. Formerly in spread.pb.print_excFullStack: - # - # The need for this function arises from the fact that several - # PB classes have the peculiar habit of discarding exceptions - # with bareword "except:"s. This premature exception - # catching means tracebacks generated here don't tend to show - # what called upon the PB object. - - while f: - if captureVars: - localz = f.f_locals.copy() - if f.f_locals is f.f_globals: - globalz = {} - else: - globalz = f.f_globals.copy() - for d in globalz, localz: - if "__builtins__" in d: - del d["__builtins__"] - localz = localz.items() - globalz = globalz.items() - else: - localz = globalz = () - stack.insert(0, ( - f.f_code.co_name, - f.f_code.co_filename, - f.f_lineno, - localz, - globalz, - )) - f = f.f_back - - while tb is not None: - f = tb.tb_frame - if captureVars: - localz = f.f_locals.copy() - if f.f_locals is f.f_globals: - globalz = {} - else: - globalz = f.f_globals.copy() - for d in globalz, localz: - if "__builtins__" in d: - del d["__builtins__"] - localz = list(localz.items()) - globalz = list(globalz.items()) - else: - localz = globalz = () - frames.append(( - f.f_code.co_name, - f.f_code.co_filename, - tb.tb_lineno, - localz, - globalz, - )) - tb = tb.tb_next - if inspect.isclass(self.type) and issubclass(self.type, Exception): - parentCs = getmro(self.type) - self.parents = list(map(reflect.qual, parentCs)) - else: - self.parents = [self.type] - - def trap(self, *errorTypes): - """Trap this failure if its type is in a predetermined list. - - This allows you to trap a Failure in an error callback. It will be - automatically re-raised if it is not a type that you expect. - - The reason for having this particular API is because it's very useful - in Deferred errback chains:: - - def _ebFoo(self, failure): - r = failure.trap(Spam, Eggs) - print 'The Failure is due to either Spam or Eggs!' - if r == Spam: - print 'Spam did it!' - elif r == Eggs: - print 'Eggs did it!' - - If the failure is not a Spam or an Eggs, then the Failure will be - 'passed on' to the next errback. In Python 2 the Failure will be - raised; in Python 3 the underlying exception will be re-raised. - - @type errorTypes: L{Exception} - """ - error = self.check(*errorTypes) - if not error: - if _PY3: - self.raiseException() - else: - raise self - return error - - def check(self, *errorTypes): - """Check if this failure's type is in a predetermined list. - - @type errorTypes: list of L{Exception} classes or - fully-qualified class names. - @returns: the matching L{Exception} type, or None if no match. - """ - for error in errorTypes: - err = error - if inspect.isclass(error) and issubclass(error, Exception): - err = reflect.qual(error) - if err in self.parents: - return error - return None - - - # It would be nice to use twisted.python.compat.reraise, but that breaks - # the stack exploration in _findFailure; possibly this can be fixed in - # #5931. - if _PY3: - def raiseException(self): - raise self.value.with_traceback(self.tb) - else: - exec("""def raiseException(self): - raise self.type, self.value, self.tb""") - - raiseException.__doc__ = ( - """ - raise the original exception, preserving traceback - information if available. - """) - - - def throwExceptionIntoGenerator(self, g): - """ - Throw the original exception into the given generator, - preserving traceback information if available. - - @return: The next value yielded from the generator. - @raise StopIteration: If there are no more values in the generator. - @raise anything else: Anything that the generator raises. - """ - return g.throw(self.type, self.value, self.tb) - - - def _findFailure(cls): - """ - Find the failure that represents the exception currently in context. - """ - tb = sys.exc_info()[-1] - if not tb: - return - - secondLastTb = None - lastTb = tb - while lastTb.tb_next: - secondLastTb = lastTb - lastTb = lastTb.tb_next - - lastFrame = lastTb.tb_frame - - # NOTE: f_locals.get('self') is used rather than - # f_locals['self'] because psyco frames do not contain - # anything in their locals() dicts. psyco makes debugging - # difficult anyhow, so losing the Failure objects (and thus - # the tracebacks) here when it is used is not that big a deal. - - # handle raiseException-originated exceptions - if lastFrame.f_code is cls.raiseException.__code__: - return lastFrame.f_locals.get('self') - - # handle throwExceptionIntoGenerator-originated exceptions - # this is tricky, and differs if the exception was caught - # inside the generator, or above it: - - # it is only really originating from - # throwExceptionIntoGenerator if the bottom of the traceback - # is a yield. - # Pyrex and Cython extensions create traceback frames - # with no co_code, but they can't yield so we know it's okay to just return here. - if ((not lastFrame.f_code.co_code) or - lastFrame.f_code.co_code[lastTb.tb_lasti] != cls._yieldOpcode): - return - - # if the exception was caught above the generator.throw - # (outside the generator), it will appear in the tb (as the - # second last item): - if secondLastTb: - frame = secondLastTb.tb_frame - if frame.f_code is cls.throwExceptionIntoGenerator.__code__: - return frame.f_locals.get('self') - - # if the exception was caught below the generator.throw - # (inside the generator), it will appear in the frames' linked - # list, above the top-level traceback item (which must be the - # generator frame itself, thus its caller is - # throwExceptionIntoGenerator). - frame = tb.tb_frame.f_back - if frame and frame.f_code is cls.throwExceptionIntoGenerator.__code__: - return frame.f_locals.get('self') - - _findFailure = classmethod(_findFailure) - - def __repr__(self): - return "<%s %s>" % (self.__class__, self.type) - - def __str__(self): - return "[Failure instance: %s]" % self.getBriefTraceback() - - def __getstate__(self): - """Avoid pickling objects in the traceback. - """ - if self.pickled: - return self.__dict__ - c = self.__dict__.copy() - - c['frames'] = [ - [ - v[0], v[1], v[2], - _safeReprVars(v[3]), - _safeReprVars(v[4]), - ] for v in self.frames - ] - - # added 2003-06-23. See comment above in __init__ - c['tb'] = None - - if self.stack is not None: - # XXX: This is a band-aid. I can't figure out where these - # (failure.stack is None) instances are coming from. - c['stack'] = [ - [ - v[0], v[1], v[2], - _safeReprVars(v[3]), - _safeReprVars(v[4]), - ] for v in self.stack - ] - - c['pickled'] = 1 - return c - - - def cleanFailure(self): - """ - Remove references to other objects, replacing them with strings. - - On Python 3, this will also set the C{__traceback__} attribute of the - exception instance to C{None}. - """ - self.__dict__ = self.__getstate__() - if _PY3: - self.value.__traceback__ = None - - - def getTracebackObject(self): - """ - Get an object that represents this Failure's stack that can be passed - to traceback.extract_tb. - - If the original traceback object is still present, return that. If this - traceback object has been lost but we still have the information, - return a fake traceback object (see L{_Traceback}). If there is no - traceback information at all, return None. - """ - if self.tb is not None: - return self.tb - elif len(self.frames) > 0: - return _Traceback(self.frames) - else: - return None - - def getErrorMessage(self): - """Get a string of the exception which caused this Failure.""" - if isinstance(self.value, Failure): - return self.value.getErrorMessage() - return reflect.safe_str(self.value) - - def getBriefTraceback(self): - io = StringIO() - self.printBriefTraceback(file=io) - return io.getvalue() - - def getTraceback(self, elideFrameworkCode=0, detail='default'): - io = StringIO() - self.printTraceback(file=io, elideFrameworkCode=elideFrameworkCode, detail=detail) - return io.getvalue() - - - def printTraceback(self, file=None, elideFrameworkCode=False, detail='default'): - """ - Emulate Python's standard error reporting mechanism. - - @param file: If specified, a file-like object to which to write the - traceback. - - @param elideFrameworkCode: A flag indicating whether to attempt to - remove uninteresting frames from within Twisted itself from the - output. - - @param detail: A string indicating how much information to include - in the traceback. Must be one of C{'brief'}, C{'default'}, or - C{'verbose'}. - """ - if file is None: - from twisted.python import log - file = log.logerr - w = file.write - - if detail == 'verbose' and not self.captureVars: - # We don't have any locals or globals, so rather than show them as - # empty make the output explicitly say that we don't have them at - # all. - formatDetail = 'verbose-vars-not-captured' - else: - formatDetail = detail - - # Preamble - if detail == 'verbose': - w( '*--- Failure #%d%s---\n' % - (self.count, - (self.pickled and ' (pickled) ') or ' ')) - elif detail == 'brief': - if self.frames: - hasFrames = 'Traceback' - else: - hasFrames = 'Traceback (failure with no frames)' - w("%s: %s: %s\n" % ( - hasFrames, - reflect.safe_str(self.type), - reflect.safe_str(self.value))) - else: - w( 'Traceback (most recent call last):\n') - - # Frames, formatted in appropriate style - if self.frames: - if not elideFrameworkCode: - format_frames(self.stack[-traceupLength:], w, formatDetail) - w("%s\n" % (EXCEPTION_CAUGHT_HERE,)) - format_frames(self.frames, w, formatDetail) - elif not detail == 'brief': - # Yeah, it's not really a traceback, despite looking like one... - w("Failure: ") - - # postamble, if any - if not detail == 'brief': - w("%s: %s\n" % (reflect.qual(self.type), - reflect.safe_str(self.value))) - - # chaining - if isinstance(self.value, Failure): - # TODO: indentation for chained failures? - file.write(" (chained Failure)\n") - self.value.printTraceback(file, elideFrameworkCode, detail) - if detail == 'verbose': - w('*--- End of Failure #%d ---\n' % self.count) - - - def printBriefTraceback(self, file=None, elideFrameworkCode=0): - """Print a traceback as densely as possible. - """ - self.printTraceback(file, elideFrameworkCode, detail='brief') - - def printDetailedTraceback(self, file=None, elideFrameworkCode=0): - """Print a traceback with detailed locals and globals information. - """ - self.printTraceback(file, elideFrameworkCode, detail='verbose') - - -def _safeReprVars(varsDictItems): - """ - Convert a list of (name, object) pairs into (name, repr) pairs. - - L{twisted.python.reflect.safe_repr} is used to generate the repr, so no - exceptions will be raised by faulty C{__repr__} methods. - - @param varsDictItems: a sequence of (name, value) pairs as returned by e.g. - C{locals().items()}. - @returns: a sequence of (name, repr) pairs. - """ - return [(name, reflect.safe_repr(obj)) for (name, obj) in varsDictItems] - - -# slyphon: make post-morteming exceptions tweakable - -DO_POST_MORTEM = True - -def _debuginit(self, exc_value=None, exc_type=None, exc_tb=None, - captureVars=False, - Failure__init__=Failure.__init__): - """ - Initialize failure object, possibly spawning pdb. - """ - if (exc_value, exc_type, exc_tb) == (None, None, None): - exc = sys.exc_info() - if not exc[0] == self.__class__ and DO_POST_MORTEM: - try: - strrepr = str(exc[1]) - except: - strrepr = "broken str" - print("Jumping into debugger for post-mortem of exception '%s':" % (strrepr,)) - import pdb - pdb.post_mortem(exc[2]) - Failure__init__(self, exc_value, exc_type, exc_tb, captureVars) - - -def startDebugMode(): - """Enable debug hooks for Failures.""" - Failure.__init__ = _debuginit diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/fakepwd.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/fakepwd.py deleted file mode 100644 index 183b30c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/fakepwd.py +++ /dev/null @@ -1,219 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_fakepwd -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -L{twisted.python.fakepwd} provides a fake implementation of the L{pwd} API. -""" - - -__all__ = ['UserDatabase', 'ShadowDatabase'] - - -class _UserRecord(object): - """ - L{_UserRecord} holds the user data for a single user in L{UserDatabase}. - It corresponds to L{pwd.struct_passwd}. See that class for attribute - documentation. - """ - def __init__(self, name, password, uid, gid, gecos, home, shell): - self.pw_name = name - self.pw_passwd = password - self.pw_uid = uid - self.pw_gid = gid - self.pw_gecos = gecos - self.pw_dir = home - self.pw_shell = shell - - - def __len__(self): - return 7 - - - def __getitem__(self, index): - return ( - self.pw_name, self.pw_passwd, self.pw_uid, - self.pw_gid, self.pw_gecos, self.pw_dir, self.pw_shell)[index] - - - -class UserDatabase(object): - """ - L{UserDatabase} holds a traditional POSIX user data in memory and makes it - available via the same API as L{pwd}. - - @ivar _users: A C{list} of L{_UserRecord} instances holding all user data - added to this database. - """ - def __init__(self): - self._users = [] - - - def addUser(self, username, password, uid, gid, gecos, home, shell): - """ - Add a new user record to this database. - - @param username: The value for the C{pw_name} field of the user - record to add. - @type username: C{str} - - @param password: The value for the C{pw_passwd} field of the user - record to add. - @type password: C{str} - - @param uid: The value for the C{pw_uid} field of the user record to - add. - @type uid: C{int} - - @param gid: The value for the C{pw_gid} field of the user record to - add. - @type gid: C{int} - - @param gecos: The value for the C{pw_gecos} field of the user record - to add. - @type gecos: C{str} - - @param home: The value for the C{pw_dir} field of the user record to - add. - @type home: C{str} - - @param shell: The value for the C{pw_shell} field of the user record to - add. - @type shell: C{str} - """ - self._users.append(_UserRecord( - username, password, uid, gid, gecos, home, shell)) - - - def getpwuid(self, uid): - """ - Return the user record corresponding to the given uid. - """ - for entry in self._users: - if entry.pw_uid == uid: - return entry - raise KeyError() - - - def getpwnam(self, name): - """ - Return the user record corresponding to the given username. - """ - for entry in self._users: - if entry.pw_name == name: - return entry - raise KeyError() - - - def getpwall(self): - """ - Return a list of all user records. - """ - return self._users - - - -class _ShadowRecord(object): - """ - L{_ShadowRecord} holds the shadow user data for a single user in - L{ShadowDatabase}. It corresponds to C{spwd.struct_spwd}. See that class - for attribute documentation. - """ - def __init__(self, username, password, lastChange, min, max, warn, inact, - expire, flag): - self.sp_nam = username - self.sp_pwd = password - self.sp_lstchg = lastChange - self.sp_min = min - self.sp_max = max - self.sp_warn = warn - self.sp_inact = inact - self.sp_expire = expire - self.sp_flag = flag - - - def __len__(self): - return 9 - - - def __getitem__(self, index): - return ( - self.sp_nam, self.sp_pwd, self.sp_lstchg, self.sp_min, - self.sp_max, self.sp_warn, self.sp_inact, self.sp_expire, - self.sp_flag)[index] - - - -class ShadowDatabase(object): - """ - L{ShadowDatabase} holds a shadow user database in memory and makes it - available via the same API as C{spwd}. - - @ivar _users: A C{list} of L{_ShadowRecord} instances holding all user data - added to this database. - - @since: 12.0 - """ - def __init__(self): - self._users = [] - - - def addUser(self, username, password, lastChange, min, max, warn, inact, - expire, flag): - """ - Add a new user record to this database. - - @param username: The value for the C{sp_nam} field of the user record to - add. - @type username: C{str} - - @param password: The value for the C{sp_pwd} field of the user record to - add. - @type password: C{str} - - @param lastChange: The value for the C{sp_lstchg} field of the user - record to add. - @type lastChange: C{int} - - @param min: The value for the C{sp_min} field of the user record to add. - @type min: C{int} - - @param max: The value for the C{sp_max} field of the user record to add. - @type max: C{int} - - @param warn: The value for the C{sp_warn} field of the user record to - add. - @type warn: C{int} - - @param inact: The value for the C{sp_inact} field of the user record to - add. - @type inact: C{int} - - @param expire: The value for the C{sp_expire} field of the user record - to add. - @type expire: C{int} - - @param flag: The value for the C{sp_flag} field of the user record to - add. - @type flag: C{int} - """ - self._users.append(_ShadowRecord( - username, password, lastChange, - min, max, warn, inact, expire, flag)) - - - def getspnam(self, username): - """ - Return the shadow user record corresponding to the given username. - """ - for entry in self._users: - if entry.sp_nam == username: - return entry - raise KeyError - - - def getspall(self): - """ - Return a list of all shadow user records. - """ - return self._users diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/filepath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/filepath.py deleted file mode 100644 index 0e6bde7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/filepath.py +++ /dev/null @@ -1,1762 +0,0 @@ -# -*- test-case-name: twisted.test.test_paths -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Object-oriented filesystem path representation. -""" - -from __future__ import division, absolute_import - -import os -import sys -import errno -import base64 - -from hashlib import sha1 -from warnings import warn - -from os.path import isabs, exists, normpath, abspath, splitext -from os.path import basename, dirname, join as joinpath -from os import listdir, utime, stat - -from stat import S_ISREG, S_ISDIR, S_IMODE, S_ISBLK, S_ISSOCK -from stat import S_IRUSR, S_IWUSR, S_IXUSR -from stat import S_IRGRP, S_IWGRP, S_IXGRP -from stat import S_IROTH, S_IWOTH, S_IXOTH - -from zope.interface import Interface, Attribute, implementer - -# Please keep this as light as possible on other Twisted imports; many, many -# things import this module, and it would be good if it could easily be -# modified for inclusion in the standard library. --glyph - -from twisted.python.compat import comparable, cmp, unicode -from twisted.python.deprecate import deprecated -from twisted.python.runtime import platform -from twisted.python.versions import Version - -from twisted.python.win32 import ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND -from twisted.python.win32 import ERROR_INVALID_NAME, ERROR_DIRECTORY, O_BINARY -from twisted.python.win32 import WindowsError - -from twisted.python.util import FancyEqMixin - -_CREATE_FLAGS = (os.O_EXCL | - os.O_CREAT | - os.O_RDWR | - O_BINARY) - - - -def _stub_islink(path): - """ - Always return C{False} if the operating system does not support symlinks. - - @param path: A path string. - @type path: L{str} - - @return: C{False} - @rtype: L{bool} - """ - return False - - -islink = getattr(os.path, 'islink', _stub_islink) -randomBytes = os.urandom -armor = base64.urlsafe_b64encode - - - -class IFilePath(Interface): - """ - File path object. - - A file path represents a location for a file-like-object and can be - organized into a hierarchy; a file path can can children which are - themselves file paths. - - A file path has a name which unique identifies it in the context of its - parent (if it has one); a file path can not have two children with the same - name. This name is referred to as the file path's "base name". - - A series of such names can be used to locate nested children of a file - path; such a series is referred to as the child's "path", relative to the - parent. In this case, each name in the path is referred to as a "path - segment"; the child's base name is the segment in the path. - - When representing a file path as a string, a "path separator" is used to - delimit the path segments within the string. For a file system path, that - would be C{os.sep}. - - Note that the values of child names may be restricted. For example, a file - system path will not allow the use of the path separator in a name, and - certain names (e.g. C{"."} and C{".."}) may be reserved or have special - meanings. - - @since: 12.1 - """ - sep = Attribute("The path separator to use in string representations") - - def child(name): - """ - Obtain a direct child of this file path. The child may or may not - exist. - - @param name: the name of a child of this path. C{name} must be a direct - child of this path and may not contain a path separator. - @return: the child of this path with the given C{name}. - @raise InsecurePath: if C{name} describes a file path that is not a - direct child of this file path. - """ - - def open(mode="r"): - """ - Opens this file path with the given mode. - - @return: a file-like object. - @raise Exception: if this file path cannot be opened. - """ - - def changed(): - """ - Clear any cached information about the state of this path on disk. - """ - - def getsize(): - """ - Retrieve the size of this file in bytes. - - @return: the size of the file at this file path in bytes. - @raise Exception: if the size cannot be obtained. - """ - - def getModificationTime(): - """ - Retrieve the time of last access from this file. - - @return: a number of seconds from the epoch. - @rtype: L{float} - """ - - def getStatusChangeTime(): - """ - Retrieve the time of the last status change for this file. - - @return: a number of seconds from the epoch. - @rtype: L{float} - """ - - def getAccessTime(): - """ - Retrieve the time that this file was last accessed. - - @return: a number of seconds from the epoch. - @rtype: L{float} - """ - - def exists(): - """ - Check if this file path exists. - - @return: C{True} if the file at this file path exists, C{False} - otherwise. - @rtype: L{bool} - """ - - def isdir(): - """ - Check if this file path refers to a directory. - - @return: C{True} if the file at this file path is a directory, C{False} - otherwise. - """ - - def isfile(): - """ - Check if this file path refers to a regular file. - - @return: C{True} if the file at this file path is a regular file, - C{False} otherwise. - """ - - def children(): - """ - List the children of this path object. - - @return: a sequence of the children of the directory at this file path. - @raise Exception: if the file at this file path is not a directory. - """ - - def basename(): - """ - Retrieve the final component of the file path's path (everything - after the final path separator). - - @return: the base name of this file path. - @rtype: L{str} - """ - - def parent(): - """ - A file path for the directory containing the file at this file path. - """ - - def sibling(name): - """ - A file path for the directory containing the file at this file path. - - @param name: the name of a sibling of this path. C{name} must be a - direct sibling of this path and may not contain a path separator. - - @return: a sibling file path of this one. - """ - - -class InsecurePath(Exception): - """ - Error that is raised when the path provided to L{FilePath} is invalid. - """ - - - -class LinkError(Exception): - """ - An error with symlinks - either that there are cyclical symlinks or that - symlink are not supported on this platform. - """ - - - -class UnlistableError(OSError): - """ - An exception which is used to distinguish between errors which mean 'this - is not a directory you can list' and other, more catastrophic errors. - - This error will try to look as much like the original error as possible, - while still being catchable as an independent type. - - @ivar originalException: the actual original exception instance, either an - L{OSError} or a L{WindowsError}. - """ - def __init__(self, originalException): - """ - Create an UnlistableError exception. - - @param originalException: an instance of OSError. - """ - self.__dict__.update(originalException.__dict__) - self.originalException = originalException - - - -class _WindowsUnlistableError(UnlistableError, WindowsError): - """ - This exception is raised on Windows, for compatibility with previous - releases of FilePath where unportable programs may have done "except - WindowsError:" around a call to children(). - - It is private because all application code may portably catch - L{UnlistableError} instead. - """ - - - -def _secureEnoughString(path): - """ - Compute a string usable as a new, temporary filename. - - @param path: The path that the new temporary filename should be able to be - concatenated with. - - @return: A pseudorandom, 16 byte string for use in secure filenames. - @rtype: the type of C{path} - """ - secureishString = armor(sha1(randomBytes(64)).digest())[:16] - return _coerceToFilesystemEncoding(path, secureishString) - - - -class AbstractFilePath(object): - """ - Abstract implementation of an L{IFilePath}; must be completed by a - subclass. - - This class primarily exists to provide common implementations of certain - methods in L{IFilePath}. It is *not* a required parent class for - L{IFilePath} implementations, just a useful starting point. - """ - - def getContent(self): - """ - Retrieve the file-like object for this file path. - """ - fp = self.open() - try: - return fp.read() - finally: - fp.close() - - - def parents(self): - """ - Retrieve an iterator of all the ancestors of this path. - - @return: an iterator of all the ancestors of this path, from the most - recent (its immediate parent) to the root of its filesystem. - """ - path = self - parent = path.parent() - # root.parent() == root, so this means "are we the root" - while path != parent: - yield parent - path = parent - parent = parent.parent() - - - def children(self): - """ - List the children of this path object. - - @raise OSError: If an error occurs while listing the directory. If the - error is 'serious', meaning that the operation failed due to an access - violation, exhaustion of some kind of resource (file descriptors or - memory), OSError or a platform-specific variant will be raised. - - @raise UnlistableError: If the inability to list the directory is due - to this path not existing or not being a directory, the more specific - OSError subclass L{UnlistableError} is raised instead. - - @return: an iterable of all currently-existing children of this object. - """ - try: - subnames = self.listdir() - except WindowsError as winErrObj: - # WindowsError is an OSError subclass, so if not for this clause - # the OSError clause below would be handling these. Windows error - # codes aren't the same as POSIX error codes, so we need to handle - # them differently. - - # Under Python 2.5 on Windows, WindowsError has a winerror - # attribute and an errno attribute. The winerror attribute is - # bound to the Windows error code while the errno attribute is - # bound to a translation of that code to a perhaps equivalent POSIX - # error number. - - # Under Python 2.4 on Windows, WindowsError only has an errno - # attribute. It is bound to the Windows error code. - - # For simplicity of code and to keep the number of paths through - # this suite minimal, we grab the Windows error code under either - # version. - - # Furthermore, attempting to use os.listdir on a non-existent path - # in Python 2.4 will result in a Windows error code of - # ERROR_PATH_NOT_FOUND. However, in Python 2.5, - # ERROR_FILE_NOT_FOUND results instead. -exarkun - winerror = getattr(winErrObj, 'winerror', winErrObj.errno) - if winerror not in (ERROR_PATH_NOT_FOUND, - ERROR_FILE_NOT_FOUND, - ERROR_INVALID_NAME, - ERROR_DIRECTORY): - raise - raise _WindowsUnlistableError(winErrObj) - except OSError as ose: - if ose.errno not in (errno.ENOENT, errno.ENOTDIR): - # Other possible errors here, according to linux manpages: - # EACCES, EMIFLE, ENFILE, ENOMEM. None of these seem like the - # sort of thing which should be handled normally. -glyph - raise - raise UnlistableError(ose) - return map(self.child, subnames) - - def walk(self, descend=None): - """ - Yield myself, then each of my children, and each of those children's - children in turn. - - The optional argument C{descend} is a predicate that takes a FilePath, - and determines whether or not that FilePath is traversed/descended - into. It will be called with each path for which C{isdir} returns - C{True}. If C{descend} is not specified, all directories will be - traversed (including symbolic links which refer to directories). - - @param descend: A one-argument callable that will return True for - FilePaths that should be traversed, False otherwise. - - @return: a generator yielding FilePath-like objects. - """ - yield self - if self.isdir(): - for c in self.children(): - # we should first see if it's what we want, then we - # can walk through the directory - if (descend is None or descend(c)): - for subc in c.walk(descend): - if os.path.realpath(self.path).startswith( - os.path.realpath(subc.path)): - raise LinkError("Cycle in file graph.") - yield subc - else: - yield c - - - def sibling(self, path): - """ - Return a L{FilePath} with the same directory as this instance but with - a basename of C{path}. - - @param path: The basename of the L{FilePath} to return. - @type path: L{str} - - @return: The sibling path. - @rtype: L{FilePath} - """ - return self.parent().child(path) - - - def descendant(self, segments): - """ - Retrieve a child or child's child of this path. - - @param segments: A sequence of path segments as L{str} instances. - - @return: A L{FilePath} constructed by looking up the C{segments[0]} - child of this path, the C{segments[1]} child of that path, and so - on. - - @since: 10.2 - """ - path = self - for name in segments: - path = path.child(name) - return path - - - def segmentsFrom(self, ancestor): - """ - Return a list of segments between a child and its ancestor. - - For example, in the case of a path X representing /a/b/c/d and a path Y - representing /a/b, C{Y.segmentsFrom(X)} will return C{['c', - 'd']}. - - @param ancestor: an instance of the same class as self, ostensibly an - ancestor of self. - - @raise: ValueError if the 'ancestor' parameter is not actually an - ancestor, i.e. a path for /x/y/z is passed as an ancestor for /a/b/c/d. - - @return: a list of strs - """ - # this might be an unnecessarily inefficient implementation but it will - # work on win32 and for zipfiles; later I will deterimine if the - # obvious fast implemenation does the right thing too - f = self - p = f.parent() - segments = [] - while f != ancestor and p != f: - segments[0:0] = [f.basename()] - f = p - p = p.parent() - if f == ancestor and segments: - return segments - raise ValueError("%r not parent of %r" % (ancestor, self)) - - - # new in 8.0 - def __hash__(self): - """ - Hash the same as another L{FilePath} with the same path as mine. - """ - return hash((self.__class__, self.path)) - - - # pending deprecation in 8.0 - def getmtime(self): - """ - Deprecated. Use getModificationTime instead. - """ - return int(self.getModificationTime()) - - - def getatime(self): - """ - Deprecated. Use getAccessTime instead. - """ - return int(self.getAccessTime()) - - - def getctime(self): - """ - Deprecated. Use getStatusChangeTime instead. - """ - return int(self.getStatusChangeTime()) - - - -class RWX(FancyEqMixin, object): - """ - A class representing read/write/execute permissions for a single user - category (i.e. user/owner, group, or other/world). Instantiate with - three boolean values: readable? writable? executable?. - - @type read: C{bool} - @ivar read: Whether permission to read is given - - @type write: C{bool} - @ivar write: Whether permission to write is given - - @type execute: C{bool} - @ivar execute: Whether permission to execute is given - - @since: 11.1 - """ - compareAttributes = ('read', 'write', 'execute') - def __init__(self, readable, writable, executable): - self.read = readable - self.write = writable - self.execute = executable - - - def __repr__(self): - return "RWX(read=%s, write=%s, execute=%s)" % ( - self.read, self.write, self.execute) - - - def shorthand(self): - """ - Returns a short string representing the permission bits. Looks like - part of what is printed by command line utilities such as 'ls -l' - (e.g. 'rwx') - - @return: The shorthand string. - @rtype: L{str} - """ - returnval = ['r', 'w', 'x'] - i = 0 - for val in (self.read, self.write, self.execute): - if not val: - returnval[i] = '-' - i += 1 - return ''.join(returnval) - - - -class Permissions(FancyEqMixin, object): - """ - A class representing read/write/execute permissions. Instantiate with any - portion of the file's mode that includes the permission bits. - - @type user: L{RWX} - @ivar user: User/Owner permissions - - @type group: L{RWX} - @ivar group: Group permissions - - @type other: L{RWX} - @ivar other: Other/World permissions - - @since: 11.1 - """ - - compareAttributes = ('user', 'group', 'other') - - def __init__(self, statModeInt): - self.user, self.group, self.other = ( - [RWX(*[statModeInt & bit > 0 for bit in bitGroup]) for bitGroup in - [[S_IRUSR, S_IWUSR, S_IXUSR], - [S_IRGRP, S_IWGRP, S_IXGRP], - [S_IROTH, S_IWOTH, S_IXOTH]]] - ) - - - def __repr__(self): - return "[%s | %s | %s]" % ( - str(self.user), str(self.group), str(self.other)) - - - def shorthand(self): - """ - Returns a short string representing the permission bits. Looks like - what is printed by command line utilities such as 'ls -l' - (e.g. 'rwx-wx--x') - - @return: The shorthand string. - @rtype: L{str} - """ - return "".join( - [x.shorthand() for x in (self.user, self.group, self.other)]) - - -class _SpecialNoValue(object): - """ - An object that represents 'no value', to be used in deprecating statinfo. - - Please remove once statinfo is removed. - """ - pass - - - -def _asFilesystemBytes(path, encoding=None): - """ - Return C{path} as a string of L{bytes} suitable for use on this system's - filesystem. - - @param path: The path to be made suitable. - @type path: L{bytes} or L{unicode} - @param encoding: The encoding to use if coercing to L{bytes}. If none is - given, L{sys.getfilesystemencoding} is used. - - @return: L{bytes} - """ - if type(path) == bytes: - return path - else: - if encoding is None: - encoding = sys.getfilesystemencoding() - return path.encode(encoding) - - - -def _asFilesystemText(path, encoding=None): - """ - Return C{path} as a string of L{unicode} suitable for use on this system's - filesystem. - - @param path: The path to be made suitable. - @type path: L{bytes} or L{unicode} - - @param encoding: The encoding to use if coercing to L{unicode}. If none - is given, L{sys.getfilesystemencoding} is used. - - @return: L{unicode} - """ - if type(path) == unicode: - return path - else: - if encoding is None: - encoding = sys.getfilesystemencoding() - return path.decode(encoding) - - - -def _coerceToFilesystemEncoding(path, newpath, encoding=None): - """ - Return a C{newpath} that is suitable for joining to C{path}. - - @param path: The path that it should be suitable for joining to. - @param newpath: The new portion of the path to be coerced if needed. - @param encoding: If coerced, the encoding that will be used. - """ - if type(path) == bytes: - return _asFilesystemBytes(newpath, encoding=encoding) - else: - return _asFilesystemText(newpath, encoding=encoding) - - - -@comparable -@implementer(IFilePath) -class FilePath(AbstractFilePath): - """ - I am a path on the filesystem that only permits 'downwards' access. - - Instantiate me with a pathname (for example, - FilePath('/home/myuser/public_html')) and I will attempt to only provide - access to files which reside inside that path. I may be a path to a file, - a directory, or a file which does not exist. - - The correct way to use me is to instantiate me, and then do ALL filesystem - access through me. In other words, do not import the 'os' module; if you - need to open a file, call my 'open' method. If you need to list a - directory, call my 'path' method. - - Even if you pass me a relative path, I will convert that to an absolute - path internally. - - Note: although time-related methods do return floating-point results, they - may still be only second resolution depending on the platform and the last - value passed to L{os.stat_float_times}. If you want greater-than-second - precision, call C{os.stat_float_times(True)}, or use Python 2.5. - Greater-than-second precision is only available in Windows on Python2.5 and - later. - - The type of C{path} when instantiating decides the mode of the L{FilePath}. - That is, C{FilePath(b"/")} will return a L{bytes} mode L{FilePath}, and - C{FilePath(u"/")} will return a L{unicode} mode L{FilePath}. - C{FilePath("/")} will return a L{bytes} mode L{FilePath} on Python 2, and a - L{unicode} mode L{FilePath} on Python 3. - - Methods that return a new L{FilePath} use the type of the given subpath to - decide its mode. For example, C{FilePath(b"/").child(u"tmp")} will return a - L{unicode} mode L{FilePath}. - - @type alwaysCreate: L{bool} - @ivar alwaysCreate: When opening this file, only succeed if the file does - not already exist. - - @type path: L{bytes} or L{unicode} - @ivar path: The path from which 'downward' traversal is permitted. - - @ivar statinfo: (WARNING: statinfo is deprecated as of Twisted 15.0.0 and - will become a private attribute) - The currently cached status information about the file on - the filesystem that this L{FilePath} points to. This attribute is - C{None} if the file is in an indeterminate state (either this - L{FilePath} has not yet had cause to call C{stat()} yet or - L{FilePath.changed} indicated that new information is required), 0 if - C{stat()} was called and returned an error (i.e. the path did not exist - when C{stat()} was called), or a C{stat_result} object that describes - the last known status of the underlying file (or directory, as the case - may be). Trust me when I tell you that you do not want to use this - attribute. Instead, use the methods on L{FilePath} which give you - information about it, like C{getsize()}, C{isdir()}, - C{getModificationTime()}, and so on. - @type statinfo: L{int} or L{types.NoneType} or L{os.stat_result} - """ - _statinfo = None - path = None - - - def __init__(self, path, alwaysCreate=False): - """ - Convert a path string to an absolute path if necessary and initialize - the L{FilePath} with the result. - """ - self.path = abspath(path) - self.alwaysCreate = alwaysCreate - - if type(self.path) != type(path): - warn("os.path.abspath is broken on Python versions below 2.6.5 and" - " coerces Unicode paths to bytes. Please update your Python.", - DeprecationWarning) - self.path = self._getPathAsSameTypeAs(path) - - - def __getstate__(self): - """ - Support serialization by discarding cached L{os.stat} results and - returning everything else. - """ - d = self.__dict__.copy() - if '_statinfo' in d: - del d['_statinfo'] - return d - - - @property - def sep(self): - """ - Return a filesystem separator. - - @return: The native filesystem separator. - @returntype: The same type as C{self.path}. - """ - return _coerceToFilesystemEncoding(self.path, os.sep) - - - def _asBytesPath(self, encoding=None): - """ - Return the path of this L{FilePath} as bytes. - - @param encoding: The encoding to use if coercing to L{bytes}. If none is - given, L{sys.getfilesystemencoding} is used. - - @return: L{bytes} - """ - return _asFilesystemBytes(self.path, encoding=encoding) - - - def _asTextPath(self, encoding=None): - """ - Return the path of this L{FilePath} as text. - - @param encoding: The encoding to use if coercing to L{unicode}. If none - is given, L{sys.getfilesystemencoding} is used. - - @return: L{unicode} - """ - return _asFilesystemText(self.path, encoding=encoding) - - - def asBytesMode(self, encoding=None): - """ - Return this L{FilePath} in L{bytes}-mode. - - @param encoding: The encoding to use if coercing to L{bytes}. If none is - given, L{sys.getfilesystemencoding} is used. - - @return: L{bytes} mode L{FilePath} - """ - if type(self.path) == unicode: - return self.clonePath(self._asBytesPath(encoding=encoding)) - return self - - - def asTextMode(self, encoding=None): - """ - Return this L{FilePath} in L{unicode}-mode. - - @param encoding: The encoding to use if coercing to L{unicode}. If none - is given, L{sys.getfilesystemencoding} is used. - - @return: L{unicode} mode L{FilePath} - """ - if type(self.path) == bytes: - return self.clonePath(self._asTextPath(encoding=encoding)) - return self - - - def _getPathAsSameTypeAs(self, pattern): - """ - If C{pattern} is C{bytes}, return L{FilePath.path} as L{bytes}. - Otherwise, return L{FilePath.path} as L{unicode}. - - @param pattern: The new element of the path that L{FilePath.path} may - need to be coerced to match. - """ - if type(pattern) == bytes: - return self._asBytesPath() - else: - return self._asTextPath() - - - def child(self, path): - """ - Create and return a new L{FilePath} representing a path contained by - C{self}. - - @param path: The base name of the new L{FilePath}. If this contains - directory separators or parent references it will be rejected. - @type path: L{bytes} or L{unicode} - - @raise InsecurePath: If the result of combining this path with C{path} - would result in a path which is not a direct child of this path. - - @return: The child path. - @rtype: L{FilePath} with a mode equal to the type of C{path}. - """ - colon = _coerceToFilesystemEncoding(path, ":") - sep = _coerceToFilesystemEncoding(path, os.sep) - ourPath = self._getPathAsSameTypeAs(path) - - if platform.isWindows() and path.count(colon): - # Catch paths like C:blah that don't have a slash - raise InsecurePath("%r contains a colon." % (path,)) - - norm = normpath(path) - if sep in norm: - raise InsecurePath("%r contains one or more directory separators" % - (path,)) - - newpath = abspath(joinpath(ourPath, norm)) - if not newpath.startswith(ourPath): - raise InsecurePath("%r is not a child of %s" % - (newpath, ourPath)) - return self.clonePath(newpath) - - - def preauthChild(self, path): - """ - Use me if C{path} might have slashes in it, but you know they're safe. - - @param path: A relative path (ie, a path not starting with C{"/"}) - which will be interpreted as a child or descendant of this path. - @type path: L{bytes} or L{unicode} - - @return: The child path. - @rtype: L{FilePath} with a mode equal to the type of C{path}. - """ - ourPath = self._getPathAsSameTypeAs(path) - - newpath = abspath(joinpath(ourPath, normpath(path))) - if not newpath.startswith(ourPath): - raise InsecurePath("%s is not a child of %s" % - (newpath, ourPath)) - return self.clonePath(newpath) - - - def childSearchPreauth(self, *paths): - """ - Return my first existing child with a name in C{paths}. - - C{paths} is expected to be a list of *pre-secured* path fragments; - in most cases this will be specified by a system administrator and not - an arbitrary user. - - If no appropriately-named children exist, this will return C{None}. - - @return: C{None} or the child path. - @rtype: L{types.NoneType} or L{FilePath} - """ - for child in paths: - p = self._getPathAsSameTypeAs(child) - jp = joinpath(p, child) - if exists(jp): - return self.clonePath(jp) - - - def siblingExtensionSearch(self, *exts): - """ - Attempt to return a path with my name, given multiple possible - extensions. - - Each extension in C{exts} will be tested and the first path which - exists will be returned. If no path exists, C{None} will be returned. - If C{''} is in C{exts}, then if the file referred to by this path - exists, C{self} will be returned. - - The extension '*' has a magic meaning, which means "any path that - begins with C{self.path + '.'} is acceptable". - """ - for ext in exts: - if not ext and self.exists(): - return self - - p = self._getPathAsSameTypeAs(ext) - star = _coerceToFilesystemEncoding(ext, "*") - dot = _coerceToFilesystemEncoding(ext, ".") - - if ext == star: - basedot = basename(p) + dot - for fn in listdir(dirname(p)): - if fn.startswith(basedot): - return self.clonePath(joinpath(dirname(p), fn)) - p2 = p + ext - if exists(p2): - return self.clonePath(p2) - - - def realpath(self): - """ - Returns the absolute target as a L{FilePath} if self is a link, self - otherwise. - - The absolute link is the ultimate file or directory the - link refers to (for instance, if the link refers to another link, and - another...). If the filesystem does not support symlinks, or - if the link is cyclical, raises a L{LinkError}. - - Behaves like L{os.path.realpath} in that it does not resolve link - names in the middle (ex. /x/y/z, y is a link to w - realpath on z - will return /x/y/z, not /x/w/z). - - @return: L{FilePath} of the target path. - @rtype: L{FilePath} - @raises LinkError: if links are not supported or links are cyclical. - """ - if self.islink(): - result = os.path.realpath(self.path) - if result == self.path: - raise LinkError("Cyclical link - will loop forever") - return self.clonePath(result) - return self - - - def siblingExtension(self, ext): - """ - Attempt to return a path with my name, given the extension at C{ext}. - - @param ext: File-extension to search for. - @type ext: L{bytes} or L{unicode} - - @return: The sibling path. - @rtype: L{FilePath} with the same mode as the type of C{ext}. - """ - ourPath = self._getPathAsSameTypeAs(ext) - return self.clonePath(ourPath + ext) - - - def linkTo(self, linkFilePath): - """ - Creates a symlink to self to at the path in the L{FilePath} - C{linkFilePath}. - - Only works on posix systems due to its dependence on - L{os.symlink}. Propagates L{OSError}s up from L{os.symlink} if - C{linkFilePath.parent()} does not exist, or C{linkFilePath} already - exists. - - @param linkFilePath: a FilePath representing the link to be created. - @type linkFilePath: L{FilePath} - """ - os.symlink(self.path, linkFilePath.path) - - - def open(self, mode='r'): - """ - Open this file using C{mode} or for writing if C{alwaysCreate} is - C{True}. - - In all cases the file is opened in binary mode, so it is not necessary - to include C{"b"} in C{mode}. - - @param mode: The mode to open the file in. Default is C{"r"}. - @type mode: L{str} - @raises AssertionError: If C{"a"} is included in the mode and - C{alwaysCreate} is C{True}. - @rtype: L{file} - @return: An open L{file} object. - """ - if self.alwaysCreate: - assert 'a' not in mode, ("Appending not supported when " - "alwaysCreate == True") - return self.create() - # This hack is necessary because of a bug in Python 2.7 on Windows: - # http://bugs.python.org/issue7686 - mode = mode.replace('b', '') - return open(self.path, mode + 'b') - - # stat methods below - - def restat(self, reraise=True): - """ - Re-calculate cached effects of 'stat'. To refresh information on this - path after you know the filesystem may have changed, call this method. - - @param reraise: a boolean. If true, re-raise exceptions from - L{os.stat}; otherwise, mark this path as not existing, and remove - any cached stat information. - - @raise Exception: If C{reraise} is C{True} and an exception occurs - while reloading metadata. - """ - try: - self._statinfo = stat(self.path) - except OSError: - self._statinfo = 0 - if reraise: - raise - - - def changed(self): - """ - Clear any cached information about the state of this path on disk. - - @since: 10.1.0 - """ - self._statinfo = None - - - def chmod(self, mode): - """ - Changes the permissions on self, if possible. Propagates errors from - L{os.chmod} up. - - @param mode: integer representing the new permissions desired (same as - the command line chmod) - @type mode: L{int} - """ - os.chmod(self.path, mode) - - - def getsize(self): - """ - Retrieve the size of this file in bytes. - - @return: The size of the file at this file path in bytes. - @raise Exception: if the size cannot be obtained. - @rtype: L{int} - """ - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return st.st_size - - - def getModificationTime(self): - """ - Retrieve the time of last access from this file. - - @return: a number of seconds from the epoch. - @rtype: L{float} - """ - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return float(st.st_mtime) - - - def getStatusChangeTime(self): - """ - Retrieve the time of the last status change for this file. - - @return: a number of seconds from the epoch. - @rtype: L{float} - """ - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return float(st.st_ctime) - - - def getAccessTime(self): - """ - Retrieve the time that this file was last accessed. - - @return: a number of seconds from the epoch. - @rtype: L{float} - """ - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return float(st.st_atime) - - - def getInodeNumber(self): - """ - Retrieve the file serial number, also called inode number, which - distinguishes this file from all other files on the same device. - - @raise NotImplementedError: if the platform is Windows, since the - inode number would be a dummy value for all files in Windows - @return: a number representing the file serial number - @rtype: L{int} - @since: 11.0 - """ - if platform.isWindows(): - raise NotImplementedError - - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return st.st_ino - - - def getDevice(self): - """ - Retrieves the device containing the file. The inode number and device - number together uniquely identify the file, but the device number is - not necessarily consistent across reboots or system crashes. - - @raise NotImplementedError: if the platform is Windows, since the - device number would be 0 for all partitions on a Windows platform - - @return: a number representing the device - @rtype: L{int} - - @since: 11.0 - """ - if platform.isWindows(): - raise NotImplementedError - - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return st.st_dev - - - def getNumberOfHardLinks(self): - """ - Retrieves the number of hard links to the file. - - This count keeps track of how many directories have entries for this - file. If the count is ever decremented to zero then the file itself is - discarded as soon as no process still holds it open. Symbolic links - are not counted in the total. - - @raise NotImplementedError: if the platform is Windows, since Windows - doesn't maintain a link count for directories, and L{os.stat} does - not set C{st_nlink} on Windows anyway. - @return: the number of hard links to the file - @rtype: L{int} - @since: 11.0 - """ - if platform.isWindows(): - raise NotImplementedError - - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return st.st_nlink - - - def getUserID(self): - """ - Returns the user ID of the file's owner. - - @raise NotImplementedError: if the platform is Windows, since the UID - is always 0 on Windows - @return: the user ID of the file's owner - @rtype: L{int} - @since: 11.0 - """ - if platform.isWindows(): - raise NotImplementedError - - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return st.st_uid - - - def getGroupID(self): - """ - Returns the group ID of the file. - - @raise NotImplementedError: if the platform is Windows, since the GID - is always 0 on windows - @return: the group ID of the file - @rtype: L{int} - @since: 11.0 - """ - if platform.isWindows(): - raise NotImplementedError - - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return st.st_gid - - - def getPermissions(self): - """ - Returns the permissions of the file. Should also work on Windows, - however, those permissions may not be what is expected in Windows. - - @return: the permissions for the file - @rtype: L{Permissions} - @since: 11.1 - """ - st = self._statinfo - if not st: - self.restat() - st = self._statinfo - return Permissions(S_IMODE(st.st_mode)) - - - def exists(self): - """ - Check if this L{FilePath} exists. - - @return: C{True} if the stats of C{path} can be retrieved successfully, - C{False} in the other cases. - @rtype: L{bool} - """ - if self._statinfo: - return True - else: - self.restat(False) - if self._statinfo: - return True - else: - return False - - - def isdir(self): - """ - Check if this L{FilePath} refers to a directory. - - @return: C{True} if this L{FilePath} refers to a directory, C{False} - otherwise. - @rtype: L{bool} - """ - st = self._statinfo - if not st: - self.restat(False) - st = self._statinfo - if not st: - return False - return S_ISDIR(st.st_mode) - - - def isfile(self): - """ - Check if this file path refers to a regular file. - - @return: C{True} if this L{FilePath} points to a regular file (not a - directory, socket, named pipe, etc), C{False} otherwise. - @rtype: L{bool} - """ - st = self._statinfo - if not st: - self.restat(False) - st = self._statinfo - if not st: - return False - return S_ISREG(st.st_mode) - - - def isBlockDevice(self): - """ - Returns whether the underlying path is a block device. - - @return: C{True} if it is a block device, C{False} otherwise - @rtype: L{bool} - @since: 11.1 - """ - st = self._statinfo - if not st: - self.restat(False) - st = self._statinfo - if not st: - return False - return S_ISBLK(st.st_mode) - - - def isSocket(self): - """ - Returns whether the underlying path is a socket. - - @return: C{True} if it is a socket, C{False} otherwise - @rtype: L{bool} - @since: 11.1 - """ - st = self._statinfo - if not st: - self.restat(False) - st = self._statinfo - if not st: - return False - return S_ISSOCK(st.st_mode) - - - def islink(self): - """ - Check if this L{FilePath} points to a symbolic link. - - @return: C{True} if this L{FilePath} points to a symbolic link, - C{False} otherwise. - @rtype: L{bool} - """ - # We can't use cached stat results here, because that is the stat of - # the destination - (see #1773) which in *every case* but this one is - # the right thing to use. We could call lstat here and use that, but - # it seems unlikely we'd actually save any work that way. -glyph - return islink(self.path) - - - def isabs(self): - """ - Check if this L{FilePath} refers to an absolute path. - - This always returns C{True}. - - @return: C{True}, always. - @rtype: L{bool} - """ - return isabs(self.path) - - - def listdir(self): - """ - List the base names of the direct children of this L{FilePath}. - - @return: A L{list} of L{bytes}/L{unicode} giving the names of the - contents of the directory this L{FilePath} refers to. These names - are relative to this L{FilePath}. - @rtype: L{list} - - @raise: Anything the platform L{os.listdir} implementation might raise - (typically L{OSError}). - """ - return listdir(self.path) - - - def splitext(self): - """ - Split the file path into a pair C{(root, ext)} such that - C{root + ext == path}. - - @return: Tuple where the first item is the filename and second item is - the file extension. See Python docs for L{os.path.splitext}. - @rtype: L{tuple} - """ - return splitext(self.path) - - - def __repr__(self): - return 'FilePath(%r)' % (self.path,) - - - def touch(self): - """ - Updates the access and last modification times of the file at this - file path to the current time. Also creates the file if it does not - already exist. - - @raise Exception: if unable to create or modify the last modification - time of the file. - """ - try: - self.open('a').close() - except IOError: - pass - utime(self.path, None) - - - def remove(self): - """ - Removes the file or directory that is represented by self. If - C{self.path} is a directory, recursively remove all its children - before removing the directory. If it's a file or link, just delete it. - """ - if self.isdir() and not self.islink(): - for child in self.children(): - child.remove() - os.rmdir(self.path) - else: - os.remove(self.path) - self.changed() - - - def makedirs(self): - """ - Create all directories not yet existing in C{path} segments, using - L{os.makedirs}. - - @return: C{None} - """ - return os.makedirs(self.path) - - - def globChildren(self, pattern): - """ - Assuming I am representing a directory, return a list of FilePaths - representing my children that match the given pattern. - - @param pattern: A glob pattern to use to match child paths. - @type pattern: L{unicode} or L{bytes} - - @return: A L{list} of matching children. - @rtype: L{list} of L{FilePath}, with the mode of C{pattern}'s type - """ - sep = _coerceToFilesystemEncoding(pattern, os.sep) - ourPath = self._getPathAsSameTypeAs(pattern) - - import glob - path = ourPath[-1] == sep and ourPath + pattern \ - or sep.join([ourPath, pattern]) - return list(map(self.clonePath, glob.glob(path))) - - - def basename(self): - """ - Retrieve the final component of the file path's path (everything - after the final path separator). - - @return: The final component of the L{FilePath}'s path (Everything - after the final path separator). - @rtype: the same type as this L{FilePath}'s C{path} attribute - """ - return basename(self.path) - - - def dirname(self): - """ - Retrieve all of the components of the L{FilePath}'s path except the - last one (everything up to the final path separator). - - @return: All of the components of the L{FilePath}'s path except the - last one (everything up to the final path separator). - @rtype: the same type as this L{FilePath}'s C{path} attribute - """ - return dirname(self.path) - - - def parent(self): - """ - A file path for the directory containing the file at this file path. - - @return: A L{FilePath} representing the path which directly contains - this L{FilePath}. - @rtype: L{FilePath} - """ - return self.clonePath(self.dirname()) - - - def setContent(self, content, ext=b'.new'): - """ - Replace the file at this path with a new file that contains the given - bytes, trying to avoid data-loss in the meanwhile. - - On UNIX-like platforms, this method does its best to ensure that by the - time this method returns, either the old contents I{or} the new - contents of the file will be present at this path for subsequent - readers regardless of premature device removal, program crash, or power - loss, making the following assumptions: - - - your filesystem is journaled (i.e. your filesystem will not - I{itself} lose data due to power loss) - - - your filesystem's C{rename()} is atomic - - - your filesystem will not discard new data while preserving new - metadata (see U{http://mjg59.livejournal.com/108257.html} for - more detail) - - On most versions of Windows there is no atomic C{rename()} (see - U{http://bit.ly/win32-overwrite} for more information), so this method - is slightly less helpful. There is a small window where the file at - this path may be deleted before the new file is moved to replace it: - however, the new file will be fully written and flushed beforehand so - in the unlikely event that there is a crash at that point, it should be - possible for the user to manually recover the new version of their - data. In the future, Twisted will support atomic file moves on those - versions of Windows which I{do} support them: see U{Twisted ticket - 3004}. - - This method should be safe for use by multiple concurrent processes, - but note that it is not easy to predict which process's contents will - ultimately end up on disk if they invoke this method at close to the - same time. - - @param content: The desired contents of the file at this path. - @type content: L{bytes} - - @param ext: An extension to append to the temporary filename used to - store the bytes while they are being written. This can be used to - make sure that temporary files can be identified by their suffix, - for cleanup in case of crashes. - @type ext: L{bytes} - """ - sib = self.temporarySibling(ext) - f = sib.open('w') - try: - f.write(content) - finally: - f.close() - if platform.isWindows() and exists(self.path): - os.unlink(self.path) - os.rename(sib.path, self.path) - - - def __cmp__(self, other): - if not isinstance(other, FilePath): - return NotImplemented - return cmp(self.path, other.path) - - - def createDirectory(self): - """ - Create the directory the L{FilePath} refers to. - - @see: L{makedirs} - - @raise OSError: If the directory cannot be created. - """ - os.mkdir(self.path) - - - def requireCreate(self, val=1): - """ - Sets the C{alwaysCreate} variable. - - @param val: C{True} or C{False}, indicating whether opening this path - will be required to create the file or not. - @type val: L{bool} - - @return: C{None} - """ - self.alwaysCreate = val - - - def create(self): - """ - Exclusively create a file, only if this file previously did not exist. - - @return: A file-like object opened from this path. - """ - fdint = os.open(self.path, _CREATE_FLAGS) - - # XXX TODO: 'name' attribute of returned files is not mutable or - # settable via fdopen, so this file is slighly less functional than the - # one returned from 'open' by default. send a patch to Python... - - return os.fdopen(fdint, 'w+b') - - - def temporarySibling(self, extension=b""): - """ - Construct a path referring to a sibling of this path. - - The resulting path will be unpredictable, so that other subprocesses - should neither accidentally attempt to refer to the same path before it - is created, nor they should other processes be able to guess its name - in advance. - - @param extension: A suffix to append to the created filename. (Note - that if you want an extension with a '.' you must include the '.' - yourself.) - @type extension: L{bytes} or L{unicode} - - @return: a path object with the given extension suffix, C{alwaysCreate} - set to True. - @rtype: L{FilePath} with a mode equal to the type of C{extension} - """ - ourPath = self._getPathAsSameTypeAs(extension) - sib = self.sibling(_secureEnoughString(ourPath) + - self.clonePath(ourPath).basename() + extension) - sib.requireCreate() - return sib - - - _chunkSize = 2 ** 2 ** 2 ** 2 - - def copyTo(self, destination, followLinks=True): - """ - Copies self to destination. - - If self doesn't exist, an OSError is raised. - - If self is a directory, this method copies its children (but not - itself) recursively to destination - if destination does not exist as a - directory, this method creates it. If destination is a file, an - IOError will be raised. - - If self is a file, this method copies it to destination. If - destination is a file, this method overwrites it. If destination is a - directory, an IOError will be raised. - - If self is a link (and followLinks is False), self will be copied - over as a new symlink with the same target as returned by os.readlink. - That means that if it is absolute, both the old and new symlink will - link to the same thing. If it's relative, then perhaps not (and - it's also possible that this relative link will be broken). - - File/directory permissions and ownership will NOT be copied over. - - If followLinks is True, symlinks are followed so that they're treated - as their targets. In other words, if self is a link, the link's target - will be copied. If destination is a link, self will be copied to the - destination's target (the actual destination will be destination's - target). Symlinks under self (if self is a directory) will be - followed and its target's children be copied recursively. - - If followLinks is False, symlinks will be copied over as symlinks. - - @param destination: the destination (a FilePath) to which self - should be copied - @param followLinks: whether symlinks in self should be treated as links - or as their targets - """ - if self.islink() and not followLinks: - os.symlink(os.readlink(self.path), destination.path) - return - # XXX TODO: *thorough* audit and documentation of the exact desired - # semantics of this code. Right now the behavior of existent - # destination symlinks is convenient, and quite possibly correct, but - # its security properties need to be explained. - if self.isdir(): - if not destination.exists(): - destination.createDirectory() - for child in self.children(): - destChild = destination.child(child.basename()) - child.copyTo(destChild, followLinks) - elif self.isfile(): - writefile = destination.open('w') - try: - readfile = self.open() - try: - while 1: - # XXX TODO: optionally use os.open, os.read and - # O_DIRECT and use os.fstatvfs to determine chunk sizes - # and make *****sure**** copy is page-atomic; the - # following is good enough for 99.9% of everybody and - # won't take a week to audit though. - chunk = readfile.read(self._chunkSize) - writefile.write(chunk) - if len(chunk) < self._chunkSize: - break - finally: - readfile.close() - finally: - writefile.close() - elif not self.exists(): - raise OSError(errno.ENOENT, "No such file or directory") - else: - # If you see the following message because you want to copy - # symlinks, fifos, block devices, character devices, or unix - # sockets, please feel free to add support to do sensible things in - # reaction to those types! - raise NotImplementedError( - "Only copying of files and directories supported") - - - def moveTo(self, destination, followLinks=True): - """ - Move self to destination - basically renaming self to whatever - destination is named. - - If destination is an already-existing directory, - moves all children to destination if destination is empty. If - destination is a non-empty directory, or destination is a file, an - OSError will be raised. - - If moving between filesystems, self needs to be copied, and everything - that applies to copyTo applies to moveTo. - - @param destination: the destination (a FilePath) to which self - should be copied - @param followLinks: whether symlinks in self should be treated as links - or as their targets (only applicable when moving between - filesystems) - """ - try: - os.rename(self.path, destination.path) - except OSError as ose: - if ose.errno == errno.EXDEV: - # man 2 rename, ubuntu linux 5.10 "breezy": - - # oldpath and newpath are not on the same mounted filesystem. - # (Linux permits a filesystem to be mounted at multiple - # points, but rename(2) does not work across different mount - # points, even if the same filesystem is mounted on both.) - - # that means it's time to copy trees of directories! - secsib = destination.temporarySibling() - self.copyTo(secsib, followLinks) # slow - secsib.moveTo(destination, followLinks) # visible - - # done creating new stuff. let's clean me up. - mysecsib = self.temporarySibling() - self.moveTo(mysecsib, followLinks) # visible - mysecsib.remove() # slow - else: - raise - else: - self.changed() - destination.changed() - - - def statinfo(self, value=_SpecialNoValue): - """ - FilePath.statinfo is deprecated. - - @param value: value to set statinfo to, if setting a value - @return: C{_statinfo} if getting, C{None} if setting - """ - # This is a pretty awful hack to use the deprecated decorator to - # deprecate a class attribute. Ideally, there would just be a - # statinfo property and a statinfo property setter, but the - # 'deprecated' decorator does not produce the correct FQDN on class - # methods. So the property stuff needs to be set outside the class - # definition - but the getter and setter both need the same function - # in order for the 'deprecated' decorator to produce the right - # deprecation string. - if value is _SpecialNoValue: - return self._statinfo - else: - self._statinfo = value - - -# This is all a terrible hack to get statinfo deprecated -_tmp = deprecated( - Version('Twisted', 15, 0, 0), - "other FilePath methods such as getsize(), " - "isdir(), getModificationTime(), etc.")(FilePath.statinfo) -FilePath.statinfo = property(_tmp, _tmp) - - -FilePath.clonePath = FilePath diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/finalize.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/finalize.py deleted file mode 100644 index 8b99bf6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/finalize.py +++ /dev/null @@ -1,46 +0,0 @@ - -""" -A module for externalized finalizers. -""" - -import weakref - -garbageKey = 0 - -def callbackFactory(num, fins): - def _cb(w): - del refs[num] - for fx in fins: - fx() - return _cb - -refs = {} - -def register(inst): - global garbageKey - garbageKey += 1 - r = weakref.ref(inst, callbackFactory(garbageKey, inst.__finalizers__())) - refs[garbageKey] = r - -if __name__ == '__main__': - def fin(): - print 'I am _so_ dead.' - - class Finalizeable: - """ - An un-sucky __del__ - """ - - def __finalizers__(self): - """ - I'm going away. - """ - return [fin] - - f = Finalizeable() - f.f2 = f - register(f) - del f - import gc - gc.collect() - print 'deled' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/formmethod.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/formmethod.py deleted file mode 100644 index b4d905e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/formmethod.py +++ /dev/null @@ -1,363 +0,0 @@ -# -*- test-case-name: twisted.test.test_formmethod -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Form-based method objects. - -This module contains support for descriptive method signatures that can be used -to format methods. -""" - -import calendar - -class FormException(Exception): - """An error occurred calling the form method. - """ - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args) - self.descriptions = kwargs - - -class InputError(FormException): - """ - An error occurred with some input. - """ - - -class Argument: - """Base class for form arguments.""" - - # default value for argument, if no other default is given - defaultDefault = None - - def __init__(self, name, default=None, shortDesc=None, - longDesc=None, hints=None, allowNone=1): - self.name = name - self.allowNone = allowNone - if default is None: - default = self.defaultDefault - self.default = default - self.shortDesc = shortDesc - self.longDesc = longDesc - if not hints: - hints = {} - self.hints = hints - - def addHints(self, **kwargs): - self.hints.update(kwargs) - - def getHint(self, name, default=None): - return self.hints.get(name, default) - - def getShortDescription(self): - return self.shortDesc or self.name.capitalize() - - def getLongDescription(self): - return self.longDesc or '' #self.shortDesc or "The %s." % self.name - - def coerce(self, val): - """Convert the value to the correct format.""" - raise NotImplementedError("implement in subclass") - - -class String(Argument): - """A single string. - """ - defaultDefault = '' - min = 0 - max = None - - def __init__(self, name, default=None, shortDesc=None, - longDesc=None, hints=None, allowNone=1, min=0, max=None): - Argument.__init__(self, name, default=default, shortDesc=shortDesc, - longDesc=longDesc, hints=hints, allowNone=allowNone) - self.min = min - self.max = max - - def coerce(self, val): - s = str(val) - if len(s) < self.min: - raise InputError("Value must be at least %s characters long" % self.min) - if self.max != None and len(s) > self.max: - raise InputError("Value must be at most %s characters long" % self.max) - return str(val) - - -class Text(String): - """A long string. - """ - - -class Password(String): - """A string which should be obscured when input. - """ - - -class VerifiedPassword(String): - """A string that should be obscured when input and needs verification.""" - - def coerce(self, vals): - if len(vals) != 2 or vals[0] != vals[1]: - raise InputError("Please enter the same password twice.") - s = str(vals[0]) - if len(s) < self.min: - raise InputError("Value must be at least %s characters long" % self.min) - if self.max != None and len(s) > self.max: - raise InputError("Value must be at most %s characters long" % self.max) - return s - - -class Hidden(String): - """A string which is not displayed. - - The passed default is used as the value. - """ - - -class Integer(Argument): - """A single integer. - """ - defaultDefault = None - - def __init__(self, name, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - #although Argument now has allowNone, that was recently added, and - #putting it at the end kept things which relied on argument order - #from breaking. However, allowNone originally was in here, so - #I have to keep the same order, to prevent breaking code that - #depends on argument order only - Argument.__init__(self, name, default, shortDesc, longDesc, hints, - allowNone) - - def coerce(self, val): - if not val.strip() and self.allowNone: - return None - try: - return int(val) - except ValueError: - raise InputError("%s is not valid, please enter a whole number, e.g. 10" % val) - - -class IntegerRange(Integer): - - def __init__(self, name, min, max, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - self.min = min - self.max = max - Integer.__init__(self, name, allowNone=allowNone, default=default, shortDesc=shortDesc, - longDesc=longDesc, hints=hints) - - def coerce(self, val): - result = Integer.coerce(self, val) - if self.allowNone and result == None: - return result - if result < self.min: - raise InputError("Value %s is too small, it should be at least %s" % (result, self.min)) - if result > self.max: - raise InputError("Value %s is too large, it should be at most %s" % (result, self.max)) - return result - - -class Float(Argument): - - defaultDefault = None - - def __init__(self, name, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - #although Argument now has allowNone, that was recently added, and - #putting it at the end kept things which relied on argument order - #from breaking. However, allowNone originally was in here, so - #I have to keep the same order, to prevent breaking code that - #depends on argument order only - Argument.__init__(self, name, default, shortDesc, longDesc, hints, - allowNone) - - - def coerce(self, val): - if not val.strip() and self.allowNone: - return None - try: - return float(val) - except ValueError: - raise InputError("Invalid float: %s" % val) - - -class Choice(Argument): - """ - The result of a choice between enumerated types. The choices should - be a list of tuples of tag, value, and description. The tag will be - the value returned if the user hits "Submit", and the description - is the bale for the enumerated type. default is a list of all the - values (seconds element in choices). If no defaults are specified, - initially the first item will be selected. Only one item can (should) - be selected at once. - """ - def __init__(self, name, choices=[], default=[], shortDesc=None, - longDesc=None, hints=None, allowNone=1): - self.choices = choices - if choices and not default: - default.append(choices[0][1]) - Argument.__init__(self, name, default, shortDesc, longDesc, hints, allowNone=allowNone) - - def coerce(self, inIdent): - for ident, val, desc in self.choices: - if ident == inIdent: - return val - else: - raise InputError("Invalid Choice: %s" % inIdent) - - -class Flags(Argument): - """ - The result of a checkbox group or multi-menu. The flags should be a - list of tuples of tag, value, and description. The tag will be - the value returned if the user hits "Submit", and the description - is the bale for the enumerated type. default is a list of all the - values (second elements in flags). If no defaults are specified, - initially nothing will be selected. Several items may be selected at - once. - """ - def __init__(self, name, flags=(), default=(), shortDesc=None, - longDesc=None, hints=None, allowNone=1): - self.flags = flags - Argument.__init__(self, name, default, shortDesc, longDesc, hints, allowNone=allowNone) - - def coerce(self, inFlagKeys): - if not inFlagKeys: - return [] - outFlags = [] - for inFlagKey in inFlagKeys: - for flagKey, flagVal, flagDesc in self.flags: - if inFlagKey == flagKey: - outFlags.append(flagVal) - break - else: - raise InputError("Invalid Flag: %s" % inFlagKey) - return outFlags - - -class CheckGroup(Flags): - pass - - -class RadioGroup(Choice): - pass - - -class Boolean(Argument): - def coerce(self, inVal): - if not inVal: - return 0 - lInVal = str(inVal).lower() - if lInVal in ('no', 'n', 'f', 'false', '0'): - return 0 - return 1 - -class File(Argument): - def __init__(self, name, allowNone=1, shortDesc=None, longDesc=None, - hints=None): - Argument.__init__(self, name, None, shortDesc, longDesc, hints, - allowNone=allowNone) - - def coerce(self, file): - if not file and self.allowNone: - return None - elif file: - return file - else: - raise InputError("Invalid File") - -def positiveInt(x): - x = int(x) - if x <= 0: raise ValueError - return x - -class Date(Argument): - """A date -- (year, month, day) tuple.""" - - defaultDefault = None - - def __init__(self, name, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - Argument.__init__(self, name, default, shortDesc, longDesc, hints) - self.allowNone = allowNone - if not allowNone: - self.defaultDefault = (1970, 1, 1) - - def coerce(self, args): - """Return tuple of ints (year, month, day).""" - if tuple(args) == ("", "", "") and self.allowNone: - return None - - try: - year, month, day = map(positiveInt, args) - except ValueError: - raise InputError("Invalid date") - if (month, day) == (2, 29): - if not calendar.isleap(year): - raise InputError("%d was not a leap year" % year) - else: - return year, month, day - try: - mdays = calendar.mdays[month] - except IndexError: - raise InputError("Invalid date") - if day > mdays: - raise InputError("Invalid date") - return year, month, day - - -class Submit(Choice): - """Submit button or a reasonable facsimile thereof.""" - - def __init__(self, name, choices=[("Submit", "submit", "Submit form")], - reset=0, shortDesc=None, longDesc=None, allowNone=0, hints=None): - Choice.__init__(self, name, choices=choices, shortDesc=shortDesc, - longDesc=longDesc, hints=hints) - self.allowNone = allowNone - self.reset = reset - - def coerce(self, value): - if self.allowNone and not value: - return None - else: - return Choice.coerce(self, value) - - -class PresentationHint: - """ - A hint to a particular system. - """ - - -class MethodSignature: - - def __init__(self, *sigList): - """ - """ - self.methodSignature = sigList - - def getArgument(self, name): - for a in self.methodSignature: - if a.name == name: - return a - - def method(self, callable, takesRequest=False): - return FormMethod(self, callable, takesRequest) - - -class FormMethod: - """A callable object with a signature.""" - - def __init__(self, signature, callable, takesRequest=False): - self.signature = signature - self.callable = callable - self.takesRequest = takesRequest - - def getArgs(self): - return tuple(self.signature.methodSignature) - - def call(self,*args,**kw): - return self.callable(*args,**kw) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/hashlib.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/hashlib.py deleted file mode 100644 index 8eda556..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/hashlib.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_hashlib -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Deprecated in Twisted 13.1.0; please use hashlib from stdlib instead. - -L{twisted.python.hashlib} presents a subset of the interface provided by -U{hashlib}. The subset is the -interface required by various parts of Twisted. This allows application code -to transparently use APIs which existed before C{hashlib} was introduced or to -use C{hashlib} if it is available. -""" -from __future__ import absolute_import -from hashlib import md5, sha1 -import warnings - -__all__ = ["md5", "sha1"] - -warnings.warn( - "twisted.python.hashlib was deprecated in " - "Twisted 13.1.0: Please use hashlib from stdlib.", - DeprecationWarning, stacklevel=2) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/hook.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/hook.py deleted file mode 100644 index c829f73..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/hook.py +++ /dev/null @@ -1,176 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -I define support for hookable instance methods. - -These are methods which you can register pre-call and post-call external -functions to augment their functionality. People familiar with more esoteric -languages may think of these as \"method combinations\". - -This could be used to add optional preconditions, user-extensible callbacks -(a-la emacs) or a thread-safety mechanism. - -The four exported calls are: - - - L{addPre} - - L{addPost} - - L{removePre} - - L{removePost} - -All have the signature (class, methodName, callable), and the callable they -take must always have the signature (instance, *args, **kw) unless the -particular signature of the method they hook is known. - -Hooks should typically not throw exceptions, however, no effort will be made by -this module to prevent them from doing so. Pre-hooks will always be called, -but post-hooks will only be called if the pre-hooks do not raise any exceptions -(they will still be called if the main method raises an exception). The return -values and exception status of the main method will be propagated (assuming -none of the hooks raise an exception). Hooks will be executed in the order in -which they are added. -""" - - -### Public Interface - -class HookError(Exception): - "An error which will fire when an invariant is violated." - -def addPre(klass, name, func): - """hook.addPre(klass, name, func) -> None - - Add a function to be called before the method klass.name is invoked. - """ - - _addHook(klass, name, PRE, func) - -def addPost(klass, name, func): - """hook.addPost(klass, name, func) -> None - - Add a function to be called after the method klass.name is invoked. - """ - _addHook(klass, name, POST, func) - -def removePre(klass, name, func): - """hook.removePre(klass, name, func) -> None - - Remove a function (previously registered with addPre) so that it - is no longer executed before klass.name. - """ - - _removeHook(klass, name, PRE, func) - -def removePost(klass, name, func): - """hook.removePre(klass, name, func) -> None - - Remove a function (previously registered with addPost) so that it - is no longer executed after klass.name. - """ - _removeHook(klass, name, POST, func) - -### "Helper" functions. - -hooked_func = """ - -import %(module)s - -def %(name)s(*args, **kw): - klazz = %(module)s.%(klass)s - for preMethod in klazz.%(preName)s: - preMethod(*args, **kw) - try: - return klazz.%(originalName)s(*args, **kw) - finally: - for postMethod in klazz.%(postName)s: - postMethod(*args, **kw) -""" - -_PRE = '__hook_pre_%s_%s_%s__' -_POST = '__hook_post_%s_%s_%s__' -_ORIG = '__hook_orig_%s_%s_%s__' - - -def _XXX(k,n,s): - """ - String manipulation garbage. - """ - x = s % (k.__module__.replace('.', '_'), k.__name__, n) - return x - -def PRE(k,n): - "(private) munging to turn a method name into a pre-hook-method-name" - return _XXX(k,n,_PRE) - -def POST(k,n): - "(private) munging to turn a method name into a post-hook-method-name" - return _XXX(k,n,_POST) - -def ORIG(k,n): - "(private) munging to turn a method name into an `original' identifier" - return _XXX(k,n,_ORIG) - - -def _addHook(klass, name, phase, func): - "(private) adds a hook to a method on a class" - _enhook(klass, name) - - if not hasattr(klass, phase(klass, name)): - setattr(klass, phase(klass, name), []) - - phaselist = getattr(klass, phase(klass, name)) - phaselist.append(func) - - -def _removeHook(klass, name, phase, func): - "(private) removes a hook from a method on a class" - phaselistname = phase(klass, name) - if not hasattr(klass, ORIG(klass,name)): - raise HookError("no hooks present!") - - phaselist = getattr(klass, phaselistname) - try: phaselist.remove(func) - except ValueError: - raise HookError("hook %s not found in removal list for %s"% - (name,klass)) - - if not getattr(klass, PRE(klass,name)) and not getattr(klass, POST(klass, name)): - _dehook(klass, name) - -def _enhook(klass, name): - "(private) causes a certain method name to be hooked on a class" - if hasattr(klass, ORIG(klass, name)): - return - - def newfunc(*args, **kw): - for preMethod in getattr(klass, PRE(klass, name)): - preMethod(*args, **kw) - try: - return getattr(klass, ORIG(klass, name))(*args, **kw) - finally: - for postMethod in getattr(klass, POST(klass, name)): - postMethod(*args, **kw) - try: - newfunc.func_name = name - except TypeError: - # Older python's don't let you do this - pass - - oldfunc = getattr(klass, name).im_func - setattr(klass, ORIG(klass, name), oldfunc) - setattr(klass, PRE(klass, name), []) - setattr(klass, POST(klass, name), []) - setattr(klass, name, newfunc) - -def _dehook(klass, name): - "(private) causes a certain method name no longer to be hooked on a class" - - if not hasattr(klass, ORIG(klass, name)): - raise HookError("Cannot unhook!") - setattr(klass, name, getattr(klass, ORIG(klass,name))) - delattr(klass, PRE(klass,name)) - delattr(klass, POST(klass,name)) - delattr(klass, ORIG(klass,name)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/htmlizer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/htmlizer.py deleted file mode 100644 index c95fb00..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/htmlizer.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_htmlizer -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -HTML rendering of Python source. -""" - -import tokenize, cgi, keyword -import reflect - -class TokenPrinter: - - currentCol, currentLine = 0, 1 - lastIdentifier = parameters = 0 - - def __init__(self, writer): - self.writer = writer - - def printtoken(self, type, token, (srow, scol), (erow, ecol), line): - #print "printtoken(%r,%r,%r,(%r,%r),(%r,%r),%r), row=%r,col=%r" % ( - # self, type, token, srow,scol, erow,ecol, line, - # self.currentLine, self.currentCol) - if self.currentLine < srow: - self.writer('\n'*(srow-self.currentLine)) - self.currentLine, self.currentCol = srow, 0 - self.writer(' '*(scol-self.currentCol)) - if self.lastIdentifier: - type = "identifier" - self.parameters = 1 - elif type == tokenize.NAME: - if keyword.iskeyword(token): - type = 'keyword' - else: - if self.parameters: - type = 'parameter' - else: - type = 'variable' - else: - type = tokenize.tok_name.get(type).lower() - self.writer(token, type) - self.currentCol = ecol - self.currentLine += token.count('\n') - if self.currentLine != erow: - self.currentCol = 0 - self.lastIdentifier = token in ('def', 'class') - if token == ':': - self.parameters = 0 - - -class HTMLWriter: - - noSpan = [] - - def __init__(self, writer): - self.writer = writer - noSpan = [] - reflect.accumulateClassList(self.__class__, "noSpan", noSpan) - self.noSpan = noSpan - - def write(self, token, type=None): - token = cgi.escape(token) - if (type is None) or (type in self.noSpan): - self.writer(token) - else: - self.writer('%s' % - (type, token)) - - -class SmallerHTMLWriter(HTMLWriter): - """HTMLWriter that doesn't generate spans for some junk. - - Results in much smaller HTML output. - """ - noSpan = ["endmarker", "indent", "dedent", "op", "newline", "nl"] - -def filter(inp, out, writer=HTMLWriter): - out.write('
')
-    printer = TokenPrinter(writer(out.write).write).printtoken
-    try:
-        tokenize.tokenize(inp.readline, printer)
-    except tokenize.TokenError:
-        pass
-    out.write('
\n') - -def main(): - import sys - filter(open(sys.argv[1]), sys.stdout) - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/lockfile.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/lockfile.py deleted file mode 100644 index cb441d9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/lockfile.py +++ /dev/null @@ -1,214 +0,0 @@ -# -*- test-case-name: twisted.test.test_lockfile -*- -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Filesystem-based interprocess mutex. -""" - -__metaclass__ = type - -import errno, os - -from time import time as _uniquefloat - -from twisted.python.runtime import platform - -def unique(): - return str(int(_uniquefloat() * 1000)) - -from os import rename -if not platform.isWindows(): - from os import kill - from os import symlink - from os import readlink - from os import remove as rmlink - _windows = False -else: - _windows = True - - try: - from win32api import OpenProcess - import pywintypes - except ImportError: - kill = None - else: - ERROR_ACCESS_DENIED = 5 - ERROR_INVALID_PARAMETER = 87 - - def kill(pid, signal): - try: - OpenProcess(0, 0, pid) - except pywintypes.error as e: - if e.args[0] == ERROR_ACCESS_DENIED: - return - elif e.args[0] == ERROR_INVALID_PARAMETER: - raise OSError(errno.ESRCH, None) - raise - else: - raise RuntimeError("OpenProcess is required to fail.") - - _open = file - - # XXX Implement an atomic thingamajig for win32 - def symlink(value, filename): - newlinkname = filename+"."+unique()+'.newlink' - newvalname = os.path.join(newlinkname,"symlink") - os.mkdir(newlinkname) - f = _open(newvalname,'wcb') - f.write(value) - f.flush() - f.close() - try: - rename(newlinkname, filename) - except: - os.remove(newvalname) - os.rmdir(newlinkname) - raise - - def readlink(filename): - try: - fObj = _open(os.path.join(filename,'symlink'), 'rb') - except IOError as e: - if e.errno == errno.ENOENT or e.errno == errno.EIO: - raise OSError(e.errno, None) - raise - else: - result = fObj.read() - fObj.close() - return result - - def rmlink(filename): - os.remove(os.path.join(filename, 'symlink')) - os.rmdir(filename) - - - -class FilesystemLock: - """ - A mutex. - - This relies on the filesystem property that creating - a symlink is an atomic operation and that it will - fail if the symlink already exists. Deleting the - symlink will release the lock. - - @ivar name: The name of the file associated with this lock. - - @ivar clean: Indicates whether this lock was released cleanly by its - last owner. Only meaningful after C{lock} has been called and - returns True. - - @ivar locked: Indicates whether the lock is currently held by this - object. - """ - - clean = None - locked = False - - def __init__(self, name): - self.name = name - - - def lock(self): - """ - Acquire this lock. - - @rtype: C{bool} - @return: True if the lock is acquired, false otherwise. - - @raise: Any exception os.symlink() may raise, other than - EEXIST. - """ - clean = True - while True: - try: - symlink(str(os.getpid()), self.name) - except OSError as e: - if _windows and e.errno in (errno.EACCES, errno.EIO): - # The lock is in the middle of being deleted because we're - # on Windows where lock removal isn't atomic. Give up, we - # don't know how long this is going to take. - return False - if e.errno == errno.EEXIST: - try: - pid = readlink(self.name) - except OSError as e: - if e.errno == errno.ENOENT: - # The lock has vanished, try to claim it in the - # next iteration through the loop. - continue - raise - except IOError as e: - if _windows and e.errno == errno.EACCES: - # The lock is in the middle of being - # deleted because we're on Windows where - # lock removal isn't atomic. Give up, we - # don't know how long this is going to - # take. - return False - raise - try: - if kill is not None: - kill(int(pid), 0) - except OSError as e: - if e.errno == errno.ESRCH: - # The owner has vanished, try to claim it in the next - # iteration through the loop. - try: - rmlink(self.name) - except OSError as e: - if e.errno == errno.ENOENT: - # Another process cleaned up the lock. - # Race them to acquire it in the next - # iteration through the loop. - continue - raise - clean = False - continue - raise - return False - raise - self.locked = True - self.clean = clean - return True - - - def unlock(self): - """ - Release this lock. - - This deletes the directory with the given name. - - @raise: Any exception os.readlink() may raise, or - ValueError if the lock is not owned by this process. - """ - pid = readlink(self.name) - if int(pid) != os.getpid(): - raise ValueError("Lock %r not owned by this process" % (self.name,)) - rmlink(self.name) - self.locked = False - - -def isLocked(name): - """Determine if the lock of the given name is held or not. - - @type name: C{str} - @param name: The filesystem path to the lock to test - - @rtype: C{bool} - @return: True if the lock is held, False otherwise. - """ - l = FilesystemLock(name) - result = None - try: - result = l.lock() - finally: - if result: - l.unlock() - return not result - - -__all__ = ['FilesystemLock', 'isLocked'] - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/log.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/log.py deleted file mode 100644 index a1c8e78..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/log.py +++ /dev/null @@ -1,760 +0,0 @@ -# -*- test-case-name: twisted.test.test_log -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Logging and metrics infrastructure. -""" - -from __future__ import division, absolute_import - -import sys -import time -import warnings - -from datetime import datetime - -from zope.interface import Interface - -from twisted.python.compat import unicode, _PY3 -from twisted.python import context -from twisted.python import reflect -from twisted.python import util -from twisted.python import failure -from twisted.python.threadable import synchronize -from twisted.logger import ( - Logger as NewLogger, LogLevel as NewLogLevel, - STDLibLogObserver as NewSTDLibLogObserver, - LegacyLogObserverWrapper, LoggingFile, LogPublisher as NewPublisher, - globalLogPublisher as newGlobalLogPublisher, - globalLogBeginner as newGlobalLogBeginner, -) - -from twisted.logger._global import LogBeginner -from twisted.logger._legacy import publishToNewObserver as _publishNew - - - -class ILogContext: - """ - Actually, this interface is just a synonym for the dictionary interface, - but it serves as a key for the default information in a log. - - I do not inherit from C{Interface} because the world is a cruel place. - """ - - - -class ILogObserver(Interface): - """ - An observer which can do something with log events. - - Given that most log observers are actually bound methods, it's okay to not - explicitly declare provision of this interface. - """ - def __call__(eventDict): - """ - Log an event. - - @type eventDict: C{dict} with C{str} keys. - @param eventDict: A dictionary with arbitrary keys. However, these - keys are often available: - - C{message}: A C{tuple} of C{str} containing messages to be - logged. - - C{system}: A C{str} which indicates the "system" which is - generating this event. - - C{isError}: A C{bool} indicating whether this event represents - an error. - - C{failure}: A L{failure.Failure} instance - - C{why}: Used as header of the traceback in case of errors. - - C{format}: A string format used in place of C{message} to - customize the event. The intent is for the observer to format - a message by doing something like C{format % eventDict}. - """ - - - -context.setDefault(ILogContext, - {"system": "-"}) - - -def callWithContext(ctx, func, *args, **kw): - newCtx = context.get(ILogContext).copy() - newCtx.update(ctx) - return context.call({ILogContext: newCtx}, func, *args, **kw) - - - -def callWithLogger(logger, func, *args, **kw): - """ - Utility method which wraps a function in a try:/except:, logs a failure if - one occurs, and uses the system's logPrefix. - """ - try: - lp = logger.logPrefix() - except KeyboardInterrupt: - raise - except: - lp = '(buggy logPrefix method)' - err(system=lp) - try: - return callWithContext({"system": lp}, func, *args, **kw) - except KeyboardInterrupt: - raise - except: - err(system=lp) - - - -def err(_stuff=None, _why=None, **kw): - """ - Write a failure to the log. - - The C{_stuff} and C{_why} parameters use an underscore prefix to lessen - the chance of colliding with a keyword argument the application wishes - to pass. It is intended that they be supplied with arguments passed - positionally, not by keyword. - - @param _stuff: The failure to log. If C{_stuff} is C{None} a new - L{Failure} will be created from the current exception state. If - C{_stuff} is an C{Exception} instance it will be wrapped in a - L{Failure}. - @type _stuff: C{NoneType}, C{Exception}, or L{Failure}. - - @param _why: The source of this failure. This will be logged along with - C{_stuff} and should describe the context in which the failure - occurred. - @type _why: C{str} - """ - if _stuff is None: - _stuff = failure.Failure() - if isinstance(_stuff, failure.Failure): - msg(failure=_stuff, why=_why, isError=1, **kw) - elif isinstance(_stuff, Exception): - msg(failure=failure.Failure(_stuff), why=_why, isError=1, **kw) - else: - msg(repr(_stuff), why=_why, isError=1, **kw) - -deferr = err - - -class Logger: - """ - This represents a class which may 'own' a log. Used by subclassing. - """ - def logPrefix(self): - """ - Override this method to insert custom logging behavior. Its - return value will be inserted in front of every line. It may - be called more times than the number of output lines. - """ - return '-' - - - -class LogPublisher: - """ - Class for singleton log message publishing. - """ - - synchronized = ['msg'] - - - def __init__(self, observerPublisher=None, publishPublisher=None, - logBeginner=None, warningsModule=warnings): - if publishPublisher is None: - publishPublisher = NewPublisher() - if observerPublisher is None: - observerPublisher = publishPublisher - if observerPublisher is None: - observerPublisher = NewPublisher() - self._observerPublisher = observerPublisher - self._publishPublisher = publishPublisher - self._legacyObservers = [] - if logBeginner is None: - # This default behavior is really only used for testing. - beginnerPublisher = NewPublisher() - beginnerPublisher.addObserver(observerPublisher) - logBeginner = LogBeginner(beginnerPublisher, NullFile(), sys, - warnings) - self._logBeginner = logBeginner - self._warningsModule = warningsModule - self._oldshowwarning = warningsModule.showwarning - self.showwarning = self._logBeginner.showwarning - - - @property - def observers(self): - """ - Property returning all observers registered on this L{LogPublisher}. - - @return: observers previously added with L{LogPublisher.addObserver} - @rtype: L{list} of L{callable} - """ - return [x.legacyObserver for x in self._legacyObservers] - - - def _startLogging(self, other, setStdout): - """ - Begin logging to the L{LogBeginner} associated with this - L{LogPublisher}. - - @param other: the observer to log to. - @type other: L{LogBeginner} - - @param setStdout: if true, send standard I/O to the observer as well. - @type setStdout: L{bool} - """ - wrapped = LegacyLogObserverWrapper(other) - self._legacyObservers.append(wrapped) - self._logBeginner.beginLoggingTo([wrapped], True, setStdout) - - - def _stopLogging(self): - """ - Clean-up hook for fixing potentially global state. Only for testing of - this module itself. If you want less global state, use the new - warnings system in L{twisted.logger}. - """ - if self._warningsModule.showwarning == self.showwarning: - self._warningsModule.showwarning = self._oldshowwarning - - - def addObserver(self, other): - """ - Add a new observer. - - @type other: Provider of L{ILogObserver} - @param other: A callable object that will be called with each new log - message (a dict). - """ - wrapped = LegacyLogObserverWrapper(other) - self._legacyObservers.append(wrapped) - self._observerPublisher.addObserver(wrapped) - - - def removeObserver(self, other): - """ - Remove an observer. - """ - for observer in self._legacyObservers: - if observer.legacyObserver == other: - self._legacyObservers.remove(observer) - self._observerPublisher.removeObserver(observer) - break - - - def msg(self, *message, **kw): - """ - Log a new message. - - The message should be a native string, i.e. bytes on Python 2 and - Unicode on Python 3. For compatibility with both use the native string - syntax, for example:: - - >>> log.msg('Hello, world.') - - You MUST avoid passing in Unicode on Python 2, and the form:: - - >>> log.msg('Hello ', 'world.') - - This form only works (sometimes) by accident. - - Keyword arguments will be converted into items in the event - dict that is passed to L{ILogObserver} implementations. - Each implementation, in turn, can define keys that are used - by it specifically, in addition to common keys listed at - L{ILogObserver.__call__}. - - For example, to set the C{system} parameter while logging - a message:: - - >>> log.msg('Started', system='Foo') - - """ - actualEventDict = (context.get(ILogContext) or {}).copy() - actualEventDict.update(kw) - actualEventDict['message'] = message - actualEventDict['time'] = time.time() - if "isError" not in actualEventDict: - actualEventDict["isError"] = 0 - - _publishNew(self._publishPublisher, actualEventDict, textFromEventDict) - - -synchronize(LogPublisher) - - - -if 'theLogPublisher' not in globals(): - def _actually(something): - """ - A decorator that returns its argument rather than the thing it is - decorating. - - This allows the documentation generator to see an alias for a method or - constant as an object with a docstring and thereby document it and - allow references to it statically. - - @param something: An object to create an alias for. - @type something: L{object} - - @return: a 1-argument callable that returns C{something} - @rtype: L{object} - """ - def decorate(thingWithADocstring): - return something - return decorate - - theLogPublisher = LogPublisher( - observerPublisher=newGlobalLogPublisher, - publishPublisher=newGlobalLogPublisher, - logBeginner=newGlobalLogBeginner, - ) - - - @_actually(theLogPublisher.addObserver) - def addObserver(observer): - """ - Add a log observer to the global publisher. - - @see: L{LogPublisher.addObserver} - - @param observer: a log observer - @type observer: L{callable} - """ - - - @_actually(theLogPublisher.removeObserver) - def removeObserver(observer): - """ - Remove a log observer from the global publisher. - - @see: L{LogPublisher.removeObserver} - - @param observer: a log observer previously added with L{addObserver} - @type observer: L{callable} - """ - - - @_actually(theLogPublisher.msg) - def msg(*message, **event): - """ - Publish a message to the global log publisher. - - @see: L{LogPublisher.msg} - - @param message: the log message - @type message: C{tuple} of L{str} (native string) - - @param event: fields for the log event - @type event: L{dict} mapping L{str} (native string) to L{object} - """ - - - @_actually(theLogPublisher.showwarning) - def showwarning(): - """ - Publish a Python warning through the global log publisher. - - @see: L{LogPublisher.showwarning} - """ - - - -def _safeFormat(fmtString, fmtDict): - """ - Try to format a string, swallowing all errors to always return a string. - - @note: For backward-compatibility reasons, this function ensures that it - returns a native string, meaning C{bytes} in Python 2 and C{unicode} in - Python 3. - - @param fmtString: a C{%}-format string - - @param fmtDict: string formatting arguments for C{fmtString} - - @return: A native string, formatted from C{fmtString} and C{fmtDict}. - @rtype: L{str} - """ - # There's a way we could make this if not safer at least more - # informative: perhaps some sort of str/repr wrapper objects - # could be wrapped around the things inside of C{fmtDict}. That way - # if the event dict contains an object with a bad __repr__, we - # can only cry about that individual object instead of the - # entire event dict. - try: - text = fmtString % fmtDict - except KeyboardInterrupt: - raise - except: - try: - text = ('Invalid format string or unformattable object in ' - 'log message: %r, %s' % (fmtString, fmtDict)) - except: - try: - text = ('UNFORMATTABLE OBJECT WRITTEN TO LOG with fmt %r, ' - 'MESSAGE LOST' % (fmtString,)) - except: - text = ('PATHOLOGICAL ERROR IN BOTH FORMAT STRING AND ' - 'MESSAGE DETAILS, MESSAGE LOST') - - # Return a native string - if _PY3: - if isinstance(text, bytes): - text = text.decode("utf-8") - else: - if isinstance(text, unicode): - text = text.encode("utf-8") - - return text - - - -def textFromEventDict(eventDict): - """ - Extract text from an event dict passed to a log observer. If it cannot - handle the dict, it returns None. - - The possible keys of eventDict are: - - C{message}: by default, it holds the final text. It's required, but can - be empty if either C{isError} or C{format} is provided (the first - having the priority). - - C{isError}: boolean indicating the nature of the event. - - C{failure}: L{failure.Failure} instance, required if the event is an - error. - - C{why}: if defined, used as header of the traceback in case of errors. - - C{format}: string format used in place of C{message} to customize - the event. It uses all keys present in C{eventDict} to format - the text. - Other keys will be used when applying the C{format}, or ignored. - """ - edm = eventDict['message'] - if not edm: - if eventDict['isError'] and 'failure' in eventDict: - why = eventDict.get('why') - if why: - why = reflect.safe_str(why) - else: - why = 'Unhandled Error' - try: - traceback = eventDict['failure'].getTraceback() - except Exception as e: - traceback = '(unable to obtain traceback): ' + str(e) - text = (why + '\n' + traceback) - elif 'format' in eventDict: - text = _safeFormat(eventDict['format'], eventDict) - else: - # We don't know how to log this - return None - else: - text = ' '.join(map(reflect.safe_str, edm)) - return text - - - -class _GlobalStartStopMixIn: - """ - Mix-in for global log observers that can start and stop. - """ - - def start(self): - """ - Start observing log events. - """ - addObserver(self.emit) - - - def stop(self): - """ - Stop observing log events. - """ - removeObserver(self.emit) - - - -class FileLogObserver(_GlobalStartStopMixIn): - """ - Log observer that writes to a file-like object. - - @type timeFormat: C{str} or C{NoneType} - @ivar timeFormat: If not C{None}, the format string passed to strftime(). - """ - - timeFormat = None - - def __init__(self, f): - # Compatibility - self.write = f.write - self.flush = f.flush - - - def getTimezoneOffset(self, when): - """ - Return the current local timezone offset from UTC. - - @type when: C{int} - @param when: POSIX (ie, UTC) timestamp for which to find the offset. - - @rtype: C{int} - @return: The number of seconds offset from UTC. West is positive, - east is negative. - """ - offset = datetime.utcfromtimestamp(when) - datetime.fromtimestamp(when) - return offset.days * (60 * 60 * 24) + offset.seconds - - - def formatTime(self, when): - """ - Format the given UTC value as a string representing that time in the - local timezone. - - By default it's formatted as a ISO8601-like string (ISO8601 date and - ISO8601 time separated by a space). It can be customized using the - C{timeFormat} attribute, which will be used as input for the underlying - L{datetime.datetime.strftime} call. - - @type when: C{int} - @param when: POSIX (ie, UTC) timestamp for which to find the offset. - - @rtype: C{str} - """ - if self.timeFormat is not None: - return datetime.fromtimestamp(when).strftime(self.timeFormat) - - tzOffset = -self.getTimezoneOffset(when) - when = datetime.utcfromtimestamp(when + tzOffset) - tzHour = abs(int(tzOffset / 60 / 60)) - tzMin = abs(int(tzOffset / 60 % 60)) - if tzOffset < 0: - tzSign = '-' - else: - tzSign = '+' - return '%d-%02d-%02d %02d:%02d:%02d%s%02d%02d' % ( - when.year, when.month, when.day, - when.hour, when.minute, when.second, - tzSign, tzHour, tzMin) - - - def emit(self, eventDict): - """ - Format the given log event as text and write it to the output file. - - @param eventDict: a log event - @type eventDict: L{dict} mapping L{str} (native string) to L{object} - """ - text = textFromEventDict(eventDict) - if text is None: - return - - timeStr = self.formatTime(eventDict["time"]) - fmtDict = { - "system": eventDict["system"], - "text": text.replace("\n", "\n\t") - } - msgStr = _safeFormat("[%(system)s] %(text)s\n", fmtDict) - - util.untilConcludes(self.write, timeStr + " " + msgStr) - util.untilConcludes(self.flush) # Hoorj! - - - -class PythonLoggingObserver(_GlobalStartStopMixIn, object): - """ - Output twisted messages to Python standard library L{logging} module. - - WARNING: specific logging configurations (example: network) can lead to - a blocking system. Nothing is done here to prevent that, so be sure to not - use this: code within Twisted, such as twisted.web, assumes that logging - does not block. - """ - - def __init__(self, loggerName="twisted"): - """ - @param loggerName: identifier used for getting logger. - @type loggerName: C{str} - """ - self._newObserver = NewSTDLibLogObserver(loggerName) - - - def emit(self, eventDict): - """ - Receive a twisted log entry, format it and bridge it to python. - - By default the logging level used is info; log.err produces error - level, and you can customize the level by using the C{logLevel} key:: - - >>> log.msg('debugging', logLevel=logging.DEBUG) - """ - if 'log_format' in eventDict: - _publishNew(self._newObserver, eventDict, textFromEventDict) - - - -class StdioOnnaStick: - """ - Class that pretends to be stdout/err, and turns writes into log messages. - - @ivar isError: boolean indicating whether this is stderr, in which cases - log messages will be logged as errors. - - @ivar encoding: unicode encoding used to encode any unicode strings - written to this object. - """ - - closed = 0 - softspace = 0 - mode = 'wb' - name = '' - - def __init__(self, isError=0, encoding=None): - self.isError = isError - if encoding is None: - encoding = sys.getdefaultencoding() - self.encoding = encoding - self.buf = '' - - - def close(self): - pass - - - def fileno(self): - return -1 - - - def flush(self): - pass - - - def read(self): - raise IOError("can't read from the log!") - - readline = read - readlines = read - seek = read - tell = read - - - def write(self, data): - if not _PY3 and isinstance(data, unicode): - data = data.encode(self.encoding) - d = (self.buf + data).split('\n') - self.buf = d[-1] - messages = d[0:-1] - for message in messages: - msg(message, printed=1, isError=self.isError) - - - def writelines(self, lines): - for line in lines: - if not _PY3 and isinstance(line, unicode): - line = line.encode(self.encoding) - msg(line, printed=1, isError=self.isError) - - - -def startLogging(file, *a, **kw): - """ - Initialize logging to a specified file. - - @return: A L{FileLogObserver} if a new observer is added, None otherwise. - """ - if isinstance(file, LoggingFile): - return - flo = FileLogObserver(file) - startLoggingWithObserver(flo.emit, *a, **kw) - return flo - - - -def startLoggingWithObserver(observer, setStdout=1): - """ - Initialize logging to a specified observer. If setStdout is true - (defaults to yes), also redirect sys.stdout and sys.stderr - to the specified file. - """ - theLogPublisher._startLogging(observer, setStdout) - msg("Log opened.") - - - -class NullFile: - """ - A file-like object that discards everything. - """ - softspace = 0 - - def read(self): - """ - Do nothing. - """ - - - def write(self, bytes): - """ - Do nothing. - - @param bytes: data - @type bytes: L{bytes} - """ - - - def flush(self): - """ - Do nothing. - """ - - - def close(self): - """ - Do nothing. - """ - - - -def discardLogs(): - """ - Discard messages logged via the global C{logfile} object. - """ - global logfile - logfile = NullFile() - - - -# Prevent logfile from being erased on reload. This only works in cpython. -if 'logfile' not in globals(): - logfile = LoggingFile(logger=NewLogger(), - level=NewLogLevel.info, - encoding=getattr(sys.stdout, "encoding", None)) - logerr = LoggingFile(logger=NewLogger(), - level=NewLogLevel.error, - encoding=getattr(sys.stderr, "encoding", None)) - - - -class DefaultObserver(_GlobalStartStopMixIn): - """ - Default observer. - - Will ignore all non-error messages and send error messages to sys.stderr. - Will be removed when startLogging() is called for the first time. - """ - stderr = sys.stderr - - def emit(self, eventDict): - """ - Emit an event dict. - - @param eventDict: an event dict - @type eventDict: dict - """ - if eventDict["isError"]: - text = textFromEventDict(eventDict) - self.stderr.write(text) - self.stderr.flush() - - - -if 'defaultObserver' not in globals(): - defaultObserver = DefaultObserver() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/logfile.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/logfile.py deleted file mode 100644 index f74bd3e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/logfile.py +++ /dev/null @@ -1,323 +0,0 @@ -# -*- test-case-name: twisted.test.test_logfile -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A rotating, browsable log file. -""" - -# System Imports -import os, glob, time, stat - -from twisted.python import threadable - - - -class BaseLogFile: - """ - The base class for a log file that can be rotated. - """ - - synchronized = ["write", "rotate"] - - def __init__(self, name, directory, defaultMode=None): - """ - Create a log file. - - @param name: name of the file - @param directory: directory holding the file - @param defaultMode: permissions used to create the file. Default to - current permissions of the file if the file exists. - """ - self.directory = directory - self.name = name - self.path = os.path.join(directory, name) - if defaultMode is None and os.path.exists(self.path): - self.defaultMode = stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]) - else: - self.defaultMode = defaultMode - self._openFile() - - def fromFullPath(cls, filename, *args, **kwargs): - """ - Construct a log file from a full file path. - """ - logPath = os.path.abspath(filename) - return cls(os.path.basename(logPath), - os.path.dirname(logPath), *args, **kwargs) - fromFullPath = classmethod(fromFullPath) - - def shouldRotate(self): - """ - Override with a method to that returns true if the log - should be rotated. - """ - raise NotImplementedError - - def _openFile(self): - """ - Open the log file. - """ - self.closed = False - if os.path.exists(self.path): - self._file = file(self.path, "r+", 1) - self._file.seek(0, 2) - else: - if self.defaultMode is not None: - # Set the lowest permissions - oldUmask = os.umask(0o777) - try: - self._file = file(self.path, "w+", 1) - finally: - os.umask(oldUmask) - else: - self._file = file(self.path, "w+", 1) - if self.defaultMode is not None: - try: - os.chmod(self.path, self.defaultMode) - except OSError: - # Probably /dev/null or something? - pass - - def __getstate__(self): - state = self.__dict__.copy() - del state["_file"] - return state - - def __setstate__(self, state): - self.__dict__ = state - self._openFile() - - def write(self, data): - """ - Write some data to the file. - """ - if self.shouldRotate(): - self.flush() - self.rotate() - self._file.write(data) - - def flush(self): - """ - Flush the file. - """ - self._file.flush() - - def close(self): - """ - Close the file. - - The file cannot be used once it has been closed. - """ - self.closed = True - self._file.close() - self._file = None - - - def reopen(self): - """ - Reopen the log file. This is mainly useful if you use an external log - rotation tool, which moves under your feet. - - Note that on Windows you probably need a specific API to rename the - file, as it's not supported to simply use os.rename, for example. - """ - self.close() - self._openFile() - - - def getCurrentLog(self): - """ - Return a LogReader for the current log file. - """ - return LogReader(self.path) - - -class LogFile(BaseLogFile): - """ - A log file that can be rotated. - - A rotateLength of None disables automatic log rotation. - """ - def __init__(self, name, directory, rotateLength=1000000, defaultMode=None, - maxRotatedFiles=None): - """ - Create a log file rotating on length. - - @param name: file name. - @type name: C{str} - @param directory: path of the log file. - @type directory: C{str} - @param rotateLength: size of the log file where it rotates. Default to - 1M. - @type rotateLength: C{int} - @param defaultMode: mode used to create the file. - @type defaultMode: C{int} - @param maxRotatedFiles: if not None, max number of log files the class - creates. Warning: it removes all log files above this number. - @type maxRotatedFiles: C{int} - """ - BaseLogFile.__init__(self, name, directory, defaultMode) - self.rotateLength = rotateLength - self.maxRotatedFiles = maxRotatedFiles - - def _openFile(self): - BaseLogFile._openFile(self) - self.size = self._file.tell() - - def shouldRotate(self): - """ - Rotate when the log file size is larger than rotateLength. - """ - return self.rotateLength and self.size >= self.rotateLength - - def getLog(self, identifier): - """ - Given an integer, return a LogReader for an old log file. - """ - filename = "%s.%d" % (self.path, identifier) - if not os.path.exists(filename): - raise ValueError("no such logfile exists") - return LogReader(filename) - - def write(self, data): - """ - Write some data to the file. - """ - BaseLogFile.write(self, data) - self.size += len(data) - - def rotate(self): - """ - Rotate the file and create a new one. - - If it's not possible to open new logfile, this will fail silently, - and continue logging to old logfile. - """ - if not (os.access(self.directory, os.W_OK) and os.access(self.path, os.W_OK)): - return - logs = self.listLogs() - logs.reverse() - for i in logs: - if self.maxRotatedFiles is not None and i >= self.maxRotatedFiles: - os.remove("%s.%d" % (self.path, i)) - else: - os.rename("%s.%d" % (self.path, i), "%s.%d" % (self.path, i + 1)) - self._file.close() - os.rename(self.path, "%s.1" % self.path) - self._openFile() - - def listLogs(self): - """ - Return sorted list of integers - the old logs' identifiers. - """ - result = [] - for name in glob.glob("%s.*" % self.path): - try: - counter = int(name.split('.')[-1]) - if counter: - result.append(counter) - except ValueError: - pass - result.sort() - return result - - def __getstate__(self): - state = BaseLogFile.__getstate__(self) - del state["size"] - return state - -threadable.synchronize(LogFile) - - -class DailyLogFile(BaseLogFile): - """A log file that is rotated daily (at or after midnight localtime) - """ - def _openFile(self): - BaseLogFile._openFile(self) - self.lastDate = self.toDate(os.stat(self.path)[8]) - - def shouldRotate(self): - """Rotate when the date has changed since last write""" - return self.toDate() > self.lastDate - - def toDate(self, *args): - """Convert a unixtime to (year, month, day) localtime tuple, - or return the current (year, month, day) localtime tuple. - - This function primarily exists so you may overload it with - gmtime, or some cruft to make unit testing possible. - """ - # primarily so this can be unit tested easily - return time.localtime(*args)[:3] - - def suffix(self, tupledate): - """Return the suffix given a (year, month, day) tuple or unixtime""" - try: - return '_'.join(map(str, tupledate)) - except: - # try taking a float unixtime - return '_'.join(map(str, self.toDate(tupledate))) - - def getLog(self, identifier): - """Given a unix time, return a LogReader for an old log file.""" - if self.toDate(identifier) == self.lastDate: - return self.getCurrentLog() - filename = "%s.%s" % (self.path, self.suffix(identifier)) - if not os.path.exists(filename): - raise ValueError("no such logfile exists") - return LogReader(filename) - - def write(self, data): - """Write some data to the log file""" - BaseLogFile.write(self, data) - # Guard against a corner case where time.time() - # could potentially run backwards to yesterday. - # Primarily due to network time. - self.lastDate = max(self.lastDate, self.toDate()) - - def rotate(self): - """Rotate the file and create a new one. - - If it's not possible to open new logfile, this will fail silently, - and continue logging to old logfile. - """ - if not (os.access(self.directory, os.W_OK) and os.access(self.path, os.W_OK)): - return - newpath = "%s.%s" % (self.path, self.suffix(self.lastDate)) - if os.path.exists(newpath): - return - self._file.close() - os.rename(self.path, newpath) - self._openFile() - - def __getstate__(self): - state = BaseLogFile.__getstate__(self) - del state["lastDate"] - return state - -threadable.synchronize(DailyLogFile) - - -class LogReader: - """Read from a log file.""" - - def __init__(self, name): - self._file = file(name, "r") - - def readLines(self, lines=10): - """Read a list of lines from the log file. - - This doesn't returns all of the files lines - call it multiple times. - """ - result = [] - for i in range(lines): - line = self._file.readline() - if not line: - break - result.append(line) - return result - - def close(self): - self._file.close() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/modules.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/modules.py deleted file mode 100644 index 0fb9b43..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/modules.py +++ /dev/null @@ -1,790 +0,0 @@ -# -*- test-case-name: twisted.test.test_modules -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module aims to provide a unified, object-oriented view of Python's -runtime hierarchy. - -Python is a very dynamic language with wide variety of introspection utilities. -However, these utilities can be hard to use, because there is no consistent -API. The introspection API in python is made up of attributes (__name__, -__module__, func_name, etc) on instances, modules, classes and functions which -vary between those four types, utility modules such as 'inspect' which provide -some functionality, the 'imp' module, the "compiler" module, the semantics of -PEP 302 support, and setuptools, among other things. - -At the top, you have "PythonPath", an abstract representation of sys.path which -includes methods to locate top-level modules, with or without loading them. -The top-level exposed functions in this module for accessing the system path -are "walkModules", "iterModules", and "getModule". - -From most to least specific, here are the objects provided:: - - PythonPath # sys.path - | - v - PathEntry # one entry on sys.path: an importer - | - v - PythonModule # a module or package that can be loaded - | - v - PythonAttribute # an attribute of a module (function or class) - | - v - PythonAttribute # an attribute of a function or class - | - v - ... - -Here's an example of idiomatic usage: this is what you would do to list all of -the modules outside the standard library's python-files directory:: - - import os - stdlibdir = os.path.dirname(os.__file__) - - from twisted.python.modules import iterModules - - for modinfo in iterModules(): - if (modinfo.pathEntry.filePath.path != stdlibdir - and not modinfo.isPackage()): - print 'unpackaged: %s: %s' % ( - modinfo.name, modinfo.filePath.path) -""" - -from __future__ import division, absolute_import - -__metaclass__ = type - -# let's try to keep path imports to a minimum... -from os.path import dirname, split as splitpath - -import sys -import inspect -import warnings -from zope.interface import Interface, implementer - -from twisted.python.compat import nativeString, _PY3 -from twisted.python.components import registerAdapter -from twisted.python.filepath import FilePath, UnlistableError -from twisted.python.reflect import namedAny - -if not _PY3: - # TODO: Zippath isn't ported yet. - # See https://tm.tl/#6917. - from twisted.python.zippath import ZipArchive - import zipimport - - -_nothing = object() - -PYTHON_EXTENSIONS = ['.py'] -OPTIMIZED_MODE = __doc__ is None -if OPTIMIZED_MODE: - PYTHON_EXTENSIONS.append('.pyo') -else: - PYTHON_EXTENSIONS.append('.pyc') - -def _isPythonIdentifier(string): - """ - cheezy fake test for proper identifier-ness. - - @param string: a L{str} which might or might not be a valid python - identifier. - @return: True or False - """ - textString = nativeString(string) - return (' ' not in textString and - '.' not in textString and - '-' not in textString) - - - -def _isPackagePath(fpath): - # Determine if a FilePath-like object is a Python package. TODO: deal with - # __init__module.(so|dll|pyd)? - extless = fpath.splitext()[0] - basend = splitpath(extless)[1] - return basend == "__init__" - - - -class _ModuleIteratorHelper: - """ - This mixin provides common behavior between python module and path entries, - since the mechanism for searching sys.path and __path__ attributes is - remarkably similar. - """ - - def iterModules(self): - """ - Loop over the modules present below this entry or package on PYTHONPATH. - - For modules which are not packages, this will yield nothing. - - For packages and path entries, this will only yield modules one level - down; i.e. if there is a package a.b.c, iterModules on a will only - return a.b. If you want to descend deeply, use walkModules. - - @return: a generator which yields PythonModule instances that describe - modules which can be, or have been, imported. - """ - yielded = {} - if not self.filePath.exists(): - return - - for placeToLook in self._packagePaths(): - try: - children = sorted(placeToLook.children()) - except UnlistableError: - continue - - for potentialTopLevel in children: - ext = potentialTopLevel.splitext()[1] - potentialBasename = potentialTopLevel.basename()[:-len(ext)] - if ext in PYTHON_EXTENSIONS: - # TODO: this should be a little choosier about which path entry - # it selects first, and it should do all the .so checking and - # crud - if not _isPythonIdentifier(potentialBasename): - continue - modname = self._subModuleName(potentialBasename) - if modname.split(".")[-1] == '__init__': - # This marks the directory as a package so it can't be - # a module. - continue - if modname not in yielded: - yielded[modname] = True - pm = PythonModule(modname, potentialTopLevel, self._getEntry()) - assert pm != self - yield pm - else: - if (ext or not _isPythonIdentifier(potentialBasename) - or not potentialTopLevel.isdir()): - continue - modname = self._subModuleName(potentialTopLevel.basename()) - for ext in PYTHON_EXTENSIONS: - initpy = potentialTopLevel.child("__init__"+ext) - if initpy.exists() and modname not in yielded: - yielded[modname] = True - pm = PythonModule(modname, initpy, self._getEntry()) - assert pm != self - yield pm - break - - def walkModules(self, importPackages=False): - """ - Similar to L{iterModules}, this yields self, and then every module in my - package or entry, and every submodule in each package or entry. - - In other words, this is deep, and L{iterModules} is shallow. - """ - yield self - for package in self.iterModules(): - for module in package.walkModules(importPackages=importPackages): - yield module - - def _subModuleName(self, mn): - """ - This is a hook to provide packages with the ability to specify their names - as a prefix to submodules here. - """ - return mn - - def _packagePaths(self): - """ - Implement in subclasses to specify where to look for modules. - - @return: iterable of FilePath-like objects. - """ - raise NotImplementedError() - - def _getEntry(self): - """ - Implement in subclasses to specify what path entry submodules will come - from. - - @return: a PathEntry instance. - """ - raise NotImplementedError() - - - def __getitem__(self, modname): - """ - Retrieve a module from below this path or package. - - @param modname: a str naming a module to be loaded. For entries, this - is a top-level, undotted package name, and for packages it is the name - of the module without the package prefix. For example, if you have a - PythonModule representing the 'twisted' package, you could use:: - - twistedPackageObj['python']['modules'] - - to retrieve this module. - - @raise: KeyError if the module is not found. - - @return: a PythonModule. - """ - for module in self.iterModules(): - if module.name == self._subModuleName(modname): - return module - raise KeyError(modname) - - def __iter__(self): - """ - Implemented to raise NotImplementedError for clarity, so that attempting to - loop over this object won't call __getitem__. - - Note: in the future there might be some sensible default for iteration, - like 'walkEverything', so this is deliberately untested and undefined - behavior. - """ - raise NotImplementedError() - -class PythonAttribute: - """ - I represent a function, class, or other object that is present. - - @ivar name: the fully-qualified python name of this attribute. - - @ivar onObject: a reference to a PythonModule or other PythonAttribute that - is this attribute's logical parent. - - @ivar name: the fully qualified python name of the attribute represented by - this class. - """ - def __init__(self, name, onObject, loaded, pythonValue): - """ - Create a PythonAttribute. This is a private constructor. Do not construct - me directly, use PythonModule.iterAttributes. - - @param name: the FQPN - @param onObject: see ivar - @param loaded: always True, for now - @param pythonValue: the value of the attribute we're pointing to. - """ - self.name = name - self.onObject = onObject - self._loaded = loaded - self.pythonValue = pythonValue - - def __repr__(self): - return 'PythonAttribute<%r>'%(self.name,) - - def isLoaded(self): - """ - Return a boolean describing whether the attribute this describes has - actually been loaded into memory by importing its module. - - Note: this currently always returns true; there is no Python parser - support in this module yet. - """ - return self._loaded - - def load(self, default=_nothing): - """ - Load the value associated with this attribute. - - @return: an arbitrary Python object, or 'default' if there is an error - loading it. - """ - return self.pythonValue - - def iterAttributes(self): - for name, val in inspect.getmembers(self.load()): - yield PythonAttribute(self.name+'.'+name, self, True, val) - -class PythonModule(_ModuleIteratorHelper): - """ - Representation of a module which could be imported from sys.path. - - @ivar name: the fully qualified python name of this module. - - @ivar filePath: a FilePath-like object which points to the location of this - module. - - @ivar pathEntry: a L{PathEntry} instance which this module was located - from. - """ - - def __init__(self, name, filePath, pathEntry): - """ - Create a PythonModule. Do not construct this directly, instead inspect a - PythonPath or other PythonModule instances. - - @param name: see ivar - @param filePath: see ivar - @param pathEntry: see ivar - """ - _name = nativeString(name) - assert not _name.endswith(".__init__") - self.name = _name - self.filePath = filePath - self.parentPath = filePath.parent() - self.pathEntry = pathEntry - - def _getEntry(self): - return self.pathEntry - - def __repr__(self): - """ - Return a string representation including the module name. - """ - return 'PythonModule<%r>' % (self.name,) - - - def isLoaded(self): - """ - Determine if the module is loaded into sys.modules. - - @return: a boolean: true if loaded, false if not. - """ - return self.pathEntry.pythonPath.moduleDict.get(self.name) is not None - - - def iterAttributes(self): - """ - List all the attributes defined in this module. - - Note: Future work is planned here to make it possible to list python - attributes on a module without loading the module by inspecting ASTs or - bytecode, but currently any iteration of PythonModule objects insists - they must be loaded, and will use inspect.getmodule. - - @raise NotImplementedError: if this module is not loaded. - - @return: a generator yielding PythonAttribute instances describing the - attributes of this module. - """ - if not self.isLoaded(): - raise NotImplementedError( - "You can't load attributes from non-loaded modules yet.") - for name, val in inspect.getmembers(self.load()): - yield PythonAttribute(self.name+'.'+name, self, True, val) - - def isPackage(self): - """ - Returns true if this module is also a package, and might yield something - from iterModules. - """ - return _isPackagePath(self.filePath) - - def load(self, default=_nothing): - """ - Load this module. - - @param default: if specified, the value to return in case of an error. - - @return: a genuine python module. - - @raise: any type of exception. Importing modules is a risky business; - the erorrs of any code run at module scope may be raised from here, as - well as ImportError if something bizarre happened to the system path - between the discovery of this PythonModule object and the attempt to - import it. If you specify a default, the error will be swallowed - entirely, and not logged. - - @rtype: types.ModuleType. - """ - try: - return self.pathEntry.pythonPath.moduleLoader(self.name) - except: # this needs more thought... - if default is not _nothing: - return default - raise - - def __eq__(self, other): - """ - PythonModules with the same name are equal. - """ - if not isinstance(other, PythonModule): - return False - return other.name == self.name - - def __ne__(self, other): - """ - PythonModules with different names are not equal. - """ - if not isinstance(other, PythonModule): - return True - return other.name != self.name - - def walkModules(self, importPackages=False): - if importPackages and self.isPackage(): - self.load() - return super(PythonModule, self).walkModules(importPackages=importPackages) - - def _subModuleName(self, mn): - """ - submodules of this module are prefixed with our name. - """ - return self.name + '.' + mn - - def _packagePaths(self): - """ - Yield a sequence of FilePath-like objects which represent path segments. - """ - if not self.isPackage(): - return - if self.isLoaded(): - load = self.load() - if hasattr(load, '__path__'): - for fn in load.__path__: - if fn == self.parentPath.path: - # this should _really_ exist. - assert self.parentPath.exists() - yield self.parentPath - else: - smp = self.pathEntry.pythonPath._smartPath(fn) - if smp.exists(): - yield smp - else: - yield self.parentPath - - -class PathEntry(_ModuleIteratorHelper): - """ - I am a proxy for a single entry on sys.path. - - @ivar filePath: a FilePath-like object pointing at the filesystem location - or archive file where this path entry is stored. - - @ivar pythonPath: a PythonPath instance. - """ - def __init__(self, filePath, pythonPath): - """ - Create a PathEntry. This is a private constructor. - """ - self.filePath = filePath - self.pythonPath = pythonPath - - def _getEntry(self): - return self - - def __repr__(self): - return 'PathEntry<%r>' % (self.filePath,) - - def _packagePaths(self): - yield self.filePath - -class IPathImportMapper(Interface): - """ - This is an internal interface, used to map importers to factories for - FilePath-like objects. - """ - def mapPath(self, pathLikeString): - """ - Return a FilePath-like object. - - @param pathLikeString: a path-like string, like one that might be - passed to an import hook. - - @return: a L{FilePath}, or something like it (currently only a - L{ZipPath}, but more might be added later). - """ - - - -@implementer(IPathImportMapper) -class _DefaultMapImpl: - """ Wrapper for the default importer, i.e. None. """ - def mapPath(self, fsPathString): - return FilePath(fsPathString) -_theDefaultMapper = _DefaultMapImpl() - - -if not _PY3: - @implementer(IPathImportMapper) - class _ZipMapImpl: - """ IPathImportMapper implementation for zipimport.ZipImporter. """ - def __init__(self, importer): - self.importer = importer - - def mapPath(self, fsPathString): - """ - Map the given FS path to a ZipPath, by looking at the ZipImporter's - "archive" attribute and using it as our ZipArchive root, then walking - down into the archive from there. - - @return: a L{zippath.ZipPath} or L{zippath.ZipArchive} instance. - """ - za = ZipArchive(self.importer.archive) - myPath = FilePath(self.importer.archive) - itsPath = FilePath(fsPathString) - if myPath == itsPath: - return za - # This is NOT a general-purpose rule for sys.path or __file__: - # zipimport specifically uses regular OS path syntax in its - # pathnames, even though zip files specify that slashes are always - # the separator, regardless of platform. - segs = itsPath.segmentsFrom(myPath) - zp = za - for seg in segs: - zp = zp.child(seg) - return zp - - registerAdapter(_ZipMapImpl, zipimport.zipimporter, IPathImportMapper) - - - -def _defaultSysPathFactory(): - """ - Provide the default behavior of PythonPath's sys.path factory, which is to - return the current value of sys.path. - - @return: L{sys.path} - """ - return sys.path - - -class PythonPath: - """ - I represent the very top of the Python object-space, the module list in - C{sys.path} and the modules list in C{sys.modules}. - - @ivar _sysPath: A sequence of strings like C{sys.path}. This attribute is - read-only. - - @ivar sysPath: The current value of the module search path list. - @type sysPath: C{list} - - @ivar moduleDict: A dictionary mapping string module names to module - objects, like C{sys.modules}. - - @ivar sysPathHooks: A list of PEP-302 path hooks, like C{sys.path_hooks}. - - @ivar moduleLoader: A function that takes a fully-qualified python name and - returns a module, like L{twisted.python.reflect.namedAny}. - """ - - def __init__(self, - sysPath=None, - moduleDict=sys.modules, - sysPathHooks=sys.path_hooks, - importerCache=sys.path_importer_cache, - moduleLoader=namedAny, - sysPathFactory=None): - """ - Create a PythonPath. You almost certainly want to use - modules.theSystemPath, or its aliased methods, rather than creating a - new instance yourself, though. - - All parameters are optional, and if unspecified, will use 'system' - equivalents that makes this PythonPath like the global L{theSystemPath} - instance. - - @param sysPath: a sys.path-like list to use for this PythonPath, to - specify where to load modules from. - - @param moduleDict: a sys.modules-like dictionary to use for keeping - track of what modules this PythonPath has loaded. - - @param sysPathHooks: sys.path_hooks-like list of PEP-302 path hooks to - be used for this PythonPath, to determie which importers should be - used. - - @param importerCache: a sys.path_importer_cache-like list of PEP-302 - importers. This will be used in conjunction with the given - sysPathHooks. - - @param moduleLoader: a module loader function which takes a string and - returns a module. That is to say, it is like L{namedAny} - *not* like - L{__import__}. - - @param sysPathFactory: a 0-argument callable which returns the current - value of a sys.path-like list of strings. Specify either this, or - sysPath, not both. This alternative interface is provided because the - way the Python import mechanism works, you can re-bind the 'sys.path' - name and that is what is used for current imports, so it must be a - factory rather than a value to deal with modification by rebinding - rather than modification by mutation. Note: it is not recommended to - rebind sys.path. Although this mechanism can deal with that, it is a - subtle point which some tools that it is easy for tools which interact - with sys.path to miss. - """ - if sysPath is not None: - sysPathFactory = lambda : sysPath - elif sysPathFactory is None: - sysPathFactory = _defaultSysPathFactory - self._sysPathFactory = sysPathFactory - self._sysPath = sysPath - self.moduleDict = moduleDict - self.sysPathHooks = sysPathHooks - self.importerCache = importerCache - self.moduleLoader = moduleLoader - - - def _getSysPath(self): - """ - Retrieve the current value of the module search path list. - """ - return self._sysPathFactory() - - sysPath = property(_getSysPath) - - def _findEntryPathString(self, modobj): - """ - Determine where a given Python module object came from by looking at path - entries. - """ - topPackageObj = modobj - while '.' in topPackageObj.__name__: - topPackageObj = self.moduleDict['.'.join( - topPackageObj.__name__.split('.')[:-1])] - if _isPackagePath(FilePath(topPackageObj.__file__)): - # if package 'foo' is on sys.path at /a/b/foo, package 'foo's - # __file__ will be /a/b/foo/__init__.py, and we are looking for - # /a/b here, the path-entry; so go up two steps. - rval = dirname(dirname(topPackageObj.__file__)) - else: - # the module is completely top-level, not within any packages. The - # path entry it's on is just its dirname. - rval = dirname(topPackageObj.__file__) - - # There are probably some awful tricks that an importer could pull - # which would break this, so let's just make sure... it's a loaded - # module after all, which means that its path MUST be in - # path_importer_cache according to PEP 302 -glyph - if rval not in self.importerCache: - warnings.warn( - "%s (for module %s) not in path importer cache " - "(PEP 302 violation - check your local configuration)." % ( - rval, modobj.__name__), - stacklevel=3) - - return rval - - def _smartPath(self, pathName): - """ - Given a path entry from sys.path which may refer to an importer, - return the appropriate FilePath-like instance. - - @param pathName: a str describing the path. - - @return: a FilePath-like object. - """ - importr = self.importerCache.get(pathName, _nothing) - if importr is _nothing: - for hook in self.sysPathHooks: - try: - importr = hook(pathName) - except ImportError: - pass - if importr is _nothing: # still - importr = None - return IPathImportMapper(importr, _theDefaultMapper).mapPath(pathName) - - def iterEntries(self): - """ - Iterate the entries on my sysPath. - - @return: a generator yielding PathEntry objects - """ - for pathName in self.sysPath: - fp = self._smartPath(pathName) - yield PathEntry(fp, self) - - - def __getitem__(self, modname): - """ - Get a python module by its given fully-qualified name. - - @param modname: The fully-qualified Python module name to load. - - @type modname: C{str} - - @return: an object representing the module identified by C{modname} - - @rtype: L{PythonModule} - - @raise KeyError: if the module name is not a valid module name, or no - such module can be identified as loadable. - """ - # See if the module is already somewhere in Python-land. - moduleObject = self.moduleDict.get(modname) - if moduleObject is not None: - # we need 2 paths; one of the path entry and one for the module. - pe = PathEntry( - self._smartPath( - self._findEntryPathString(moduleObject)), - self) - mp = self._smartPath(moduleObject.__file__) - return PythonModule(modname, mp, pe) - - # Recurse if we're trying to get a submodule. - if '.' in modname: - pkg = self - for name in modname.split('.'): - pkg = pkg[name] - return pkg - - # Finally do the slowest possible thing and iterate - for module in self.iterModules(): - if module.name == modname: - return module - raise KeyError(modname) - - - def __contains__(self, module): - """ - Check to see whether or not a module exists on my import path. - - @param module: The name of the module to look for on my import path. - @type module: C{str} - """ - try: - self.__getitem__(module) - return True - except KeyError: - return False - - - def __repr__(self): - """ - Display my sysPath and moduleDict in a string representation. - """ - return "PythonPath(%r,%r)" % (self.sysPath, self.moduleDict) - - def iterModules(self): - """ - Yield all top-level modules on my sysPath. - """ - for entry in self.iterEntries(): - for module in entry.iterModules(): - yield module - - def walkModules(self, importPackages=False): - """ - Similar to L{iterModules}, this yields every module on the path, then every - submodule in each package or entry. - """ - for package in self.iterModules(): - for module in package.walkModules(importPackages=False): - yield module - -theSystemPath = PythonPath() - -def walkModules(importPackages=False): - """ - Deeply iterate all modules on the global python path. - - @param importPackages: Import packages as they are seen. - """ - return theSystemPath.walkModules(importPackages=importPackages) - -def iterModules(): - """ - Iterate all modules and top-level packages on the global Python path, but - do not descend into packages. - - @param importPackages: Import packages as they are seen. - """ - return theSystemPath.iterModules() - -def getModule(moduleName): - """ - Retrieve a module from the system path. - """ - return theSystemPath[moduleName] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/monkey.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/monkey.py deleted file mode 100644 index 4911f87..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/monkey.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- test-case-name: twisted.test.test_monkey -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from __future__ import division, absolute_import - - -class MonkeyPatcher(object): - """ - Cover up attributes with new objects. Neat for monkey-patching things for - unit-testing purposes. - """ - - def __init__(self, *patches): - # List of patches to apply in (obj, name, value). - self._patchesToApply = [] - # List of the original values for things that have been patched. - # (obj, name, value) format. - self._originals = [] - for patch in patches: - self.addPatch(*patch) - - - def addPatch(self, obj, name, value): - """ - Add a patch so that the attribute C{name} on C{obj} will be assigned to - C{value} when C{patch} is called or during C{runWithPatches}. - - You can restore the original values with a call to restore(). - """ - self._patchesToApply.append((obj, name, value)) - - - def _alreadyPatched(self, obj, name): - """ - Has the C{name} attribute of C{obj} already been patched by this - patcher? - """ - for o, n, v in self._originals: - if (o, n) == (obj, name): - return True - return False - - - def patch(self): - """ - Apply all of the patches that have been specified with L{addPatch}. - Reverse this operation using L{restore}. - """ - for obj, name, value in self._patchesToApply: - if not self._alreadyPatched(obj, name): - self._originals.append((obj, name, getattr(obj, name))) - setattr(obj, name, value) - - - def restore(self): - """ - Restore all original values to any patched objects. - """ - while self._originals: - obj, name, value = self._originals.pop() - setattr(obj, name, value) - - - def runWithPatches(self, f, *args, **kw): - """ - Apply each patch already specified. Then run the function f with the - given args and kwargs. Restore everything when done. - """ - self.patch() - try: - return f(*args, **kw) - finally: - self.restore() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/procutils.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/procutils.py deleted file mode 100644 index 9251e7d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/procutils.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Utilities for dealing with processes. -""" - -from __future__ import division, absolute_import - -import os - - -def which(name, flags=os.X_OK): - """ - Search PATH for executable files with the given name. - - On newer versions of MS-Windows, the PATHEXT environment variable will be - set to the list of file extensions for files considered executable. This - will normally include things like ".EXE". This function will also find files - with the given name ending with any of these extensions. - - On MS-Windows the only flag that has any meaning is os.F_OK. Any other - flags will be ignored. - - @type name: C{str} - @param name: The name for which to search. - - @type flags: C{int} - @param flags: Arguments to L{os.access}. - - @rtype: C{list} - @param: A list of the full paths to files found, in the order in which they - were found. - """ - result = [] - exts = list(filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))) - path = os.environ.get('PATH', None) - - if path is None: - return [] - - for p in os.environ.get('PATH', '').split(os.pathsep): - p = os.path.join(p, name) - if os.access(p, flags): - result.append(p) - for e in exts: - pext = p + e - if os.access(pext, flags): - result.append(pext) - - return result diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/randbytes.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/randbytes.py deleted file mode 100644 index 4062ed2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/randbytes.py +++ /dev/null @@ -1,150 +0,0 @@ -# -*- test-case-name: twisted.test.test_randbytes -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cryptographically secure random implementation, with fallback on normal random. -""" - -from __future__ import division, absolute_import - -import warnings, os, random, string - -from twisted.python.compat import _PY3 - -getrandbits = getattr(random, 'getrandbits', None) - -if _PY3: - _fromhex = bytes.fromhex -else: - def _fromhex(hexBytes): - return hexBytes.decode('hex') - - -class SecureRandomNotAvailable(RuntimeError): - """ - Exception raised when no secure random algorithm is found. - """ - - - -class SourceNotAvailable(RuntimeError): - """ - Internal exception used when a specific random source is not available. - """ - - - -class RandomFactory(object): - """ - Factory providing L{secureRandom} and L{insecureRandom} methods. - - You shouldn't have to instantiate this class, use the module level - functions instead: it is an implementation detail and could be removed or - changed arbitrarily. - """ - - # This variable is no longer used, and will eventually be removed. - randomSources = () - - getrandbits = getrandbits - - - def _osUrandom(self, nbytes): - """ - Wrapper around C{os.urandom} that cleanly manage its absence. - """ - try: - return os.urandom(nbytes) - except (AttributeError, NotImplementedError) as e: - raise SourceNotAvailable(e) - - - def secureRandom(self, nbytes, fallback=False): - """ - Return a number of secure random bytes. - - @param nbytes: number of bytes to generate. - @type nbytes: C{int} - @param fallback: Whether the function should fallback on non-secure - random or not. Default to C{False}. - @type fallback: C{bool} - - @return: a string of random bytes. - @rtype: C{str} - """ - try: - return self._osUrandom(nbytes) - except SourceNotAvailable: - pass - - if fallback: - warnings.warn( - "urandom unavailable - " - "proceeding with non-cryptographically secure random source", - category=RuntimeWarning, - stacklevel=2) - return self.insecureRandom(nbytes) - else: - raise SecureRandomNotAvailable("No secure random source available") - - - def _randBits(self, nbytes): - """ - Wrapper around C{os.getrandbits}. - """ - if self.getrandbits is not None: - n = self.getrandbits(nbytes * 8) - hexBytes = ("%%0%dx" % (nbytes * 2)) % n - return _fromhex(hexBytes) - raise SourceNotAvailable("random.getrandbits is not available") - - - if _PY3: - _maketrans = bytes.maketrans - def _randModule(self, nbytes): - """ - Wrapper around the C{random} module. - """ - return b"".join([ - bytes([random.choice(self._BYTES)]) for i in range(nbytes)]) - else: - _maketrans = string.maketrans - def _randModule(self, nbytes): - """ - Wrapper around the C{random} module. - """ - return b"".join([ - random.choice(self._BYTES) for i in range(nbytes)]) - - _BYTES = _maketrans(b'', b'') - - - def insecureRandom(self, nbytes): - """ - Return a number of non secure random bytes. - - @param nbytes: number of bytes to generate. - @type nbytes: C{int} - - @return: a string of random bytes. - @rtype: C{str} - """ - for src in ("_randBits", "_randModule"): - try: - return getattr(self, src)(nbytes) - except SourceNotAvailable: - pass - - - -factory = RandomFactory() - -secureRandom = factory.secureRandom - -insecureRandom = factory.insecureRandom - -del factory - - -__all__ = ["secureRandom", "insecureRandom", "SecureRandomNotAvailable"] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/rebuild.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/rebuild.py deleted file mode 100644 index 28a7675..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/rebuild.py +++ /dev/null @@ -1,271 +0,0 @@ -# -*- test-case-name: twisted.test.test_rebuild -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -*Real* reloading support for Python. -""" - -# System Imports -import sys -import types -import time -import linecache - -# Sibling Imports -from twisted.python import log, reflect - -lastRebuild = time.time() - - -class Sensitive: - """ - A utility mixin that's sensitive to rebuilds. - - This is a mixin for classes (usually those which represent collections of - callbacks) to make sure that their code is up-to-date before running. - """ - - lastRebuild = lastRebuild - - def needRebuildUpdate(self): - yn = (self.lastRebuild < lastRebuild) - return yn - - def rebuildUpToDate(self): - self.lastRebuild = time.time() - - def latestVersionOf(self, anObject): - """ - Get the latest version of an object. - - This can handle just about anything callable; instances, functions, - methods, and classes. - """ - t = type(anObject) - if t == types.FunctionType: - return latestFunction(anObject) - elif t == types.MethodType: - if anObject.im_self is None: - return getattr(anObject.im_class, anObject.__name__) - else: - return getattr(anObject.im_self, anObject.__name__) - elif t == types.InstanceType: - # Kick it, if it's out of date. - getattr(anObject, 'nothing', None) - return anObject - elif t == types.ClassType: - return latestClass(anObject) - else: - log.msg('warning returning anObject!') - return anObject - -_modDictIDMap = {} - -def latestFunction(oldFunc): - """ - Get the latest version of a function. - """ - # This may be CPython specific, since I believe jython instantiates a new - # module upon reload. - dictID = id(oldFunc.func_globals) - module = _modDictIDMap.get(dictID) - if module is None: - return oldFunc - return getattr(module, oldFunc.__name__) - - -def latestClass(oldClass): - """ - Get the latest version of a class. - """ - module = reflect.namedModule(oldClass.__module__) - newClass = getattr(module, oldClass.__name__) - newBases = [latestClass(base) for base in newClass.__bases__] - - try: - # This makes old-style stuff work - newClass.__bases__ = tuple(newBases) - return newClass - except TypeError: - if newClass.__module__ == "__builtin__": - # __builtin__ members can't be reloaded sanely - return newClass - ctor = getattr(newClass, '__metaclass__', type) - return ctor(newClass.__name__, tuple(newBases), dict(newClass.__dict__)) - - -class RebuildError(Exception): - """ - Exception raised when trying to rebuild a class whereas it's not possible. - """ - - -def updateInstance(self): - """ - Updates an instance to be current. - """ - try: - self.__class__ = latestClass(self.__class__) - except TypeError: - if hasattr(self.__class__, '__slots__'): - raise RebuildError("Can't rebuild class with __slots__ on Python < 2.6") - else: - raise - - -def __getattr__(self, name): - """ - A getattr method to cause a class to be refreshed. - """ - if name == '__del__': - raise AttributeError("Without this, Python segfaults.") - updateInstance(self) - log.msg("(rebuilding stale %s instance (%s))" % (reflect.qual(self.__class__), name)) - result = getattr(self, name) - return result - - -def rebuild(module, doLog=1): - """ - Reload a module and do as much as possible to replace its references. - """ - global lastRebuild - lastRebuild = time.time() - if hasattr(module, 'ALLOW_TWISTED_REBUILD'): - # Is this module allowed to be rebuilt? - if not module.ALLOW_TWISTED_REBUILD: - raise RuntimeError("I am not allowed to be rebuilt.") - if doLog: - log.msg('Rebuilding %s...' % str(module.__name__)) - - ## Safely handle adapter re-registration - from twisted.python import components - components.ALLOW_DUPLICATES = True - - d = module.__dict__ - _modDictIDMap[id(d)] = module - newclasses = {} - classes = {} - functions = {} - values = {} - if doLog: - log.msg(' (scanning %s): ' % str(module.__name__)) - for k, v in d.items(): - if type(v) == types.ClassType: - # Failure condition -- instances of classes with buggy - # __hash__/__cmp__ methods referenced at the module level... - if v.__module__ == module.__name__: - classes[v] = 1 - if doLog: - log.logfile.write("c") - log.logfile.flush() - elif type(v) == types.FunctionType: - if v.func_globals is module.__dict__: - functions[v] = 1 - if doLog: - log.logfile.write("f") - log.logfile.flush() - elif isinstance(v, type): - if v.__module__ == module.__name__: - newclasses[v] = 1 - if doLog: - log.logfile.write("o") - log.logfile.flush() - - values.update(classes) - values.update(functions) - fromOldModule = values.__contains__ - newclasses = newclasses.keys() - classes = classes.keys() - functions = functions.keys() - - if doLog: - log.msg('') - log.msg(' (reload %s)' % str(module.__name__)) - - # Boom. - reload(module) - # Make sure that my traceback printing will at least be recent... - linecache.clearcache() - - if doLog: - log.msg(' (cleaning %s): ' % str(module.__name__)) - - for clazz in classes: - if getattr(module, clazz.__name__) is clazz: - log.msg("WARNING: class %s not replaced by reload!" % reflect.qual(clazz)) - else: - if doLog: - log.logfile.write("x") - log.logfile.flush() - clazz.__bases__ = () - clazz.__dict__.clear() - clazz.__getattr__ = __getattr__ - clazz.__module__ = module.__name__ - if newclasses: - import gc - for nclass in newclasses: - ga = getattr(module, nclass.__name__) - if ga is nclass: - log.msg("WARNING: new-class %s not replaced by reload!" % reflect.qual(nclass)) - else: - for r in gc.get_referrers(nclass): - if getattr(r, '__class__', None) is nclass: - r.__class__ = ga - if doLog: - log.msg('') - log.msg(' (fixing %s): ' % str(module.__name__)) - modcount = 0 - for mk, mod in sys.modules.items(): - modcount = modcount + 1 - if mod == module or mod is None: - continue - - if not hasattr(mod, '__file__'): - # It's a builtin module; nothing to replace here. - continue - - if hasattr(mod, '__bundle__'): - # PyObjC has a few buggy objects which segfault if you hash() them. - # It doesn't make sense to try rebuilding extension modules like - # this anyway, so don't try. - continue - - changed = 0 - - for k, v in mod.__dict__.items(): - try: - hash(v) - except Exception: - continue - if fromOldModule(v): - if type(v) == types.ClassType: - if doLog: - log.logfile.write("c") - log.logfile.flush() - nv = latestClass(v) - else: - if doLog: - log.logfile.write("f") - log.logfile.flush() - nv = latestFunction(v) - changed = 1 - setattr(mod, k, nv) - else: - # Replace bases of non-module classes just to be sure. - if type(v) == types.ClassType: - for base in v.__bases__: - if fromOldModule(base): - latestClass(v) - if doLog and not changed and ((modcount % 10) ==0) : - log.logfile.write(".") - log.logfile.flush() - - components.ALLOW_DUPLICATES = False - if doLog: - log.msg('') - log.msg(' Rebuilt %s.' % str(module.__name__)) - return module - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/reflect.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/reflect.py deleted file mode 100644 index 51d08ae..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/reflect.py +++ /dev/null @@ -1,728 +0,0 @@ -# -*- test-case-name: twisted.test.test_reflect -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Standardized versions of various cool and/or strange things that you can do -with Python's reflection capabilities. -""" - -from __future__ import division, absolute_import, print_function - -import sys -import types -import os -import pickle -import weakref -import re -import traceback -import warnings -from collections import deque - -RegexType = type(re.compile("")) - - -from twisted.python.compat import reraise, nativeString, NativeStringIO -from twisted.python.compat import _PY3 -from twisted.python.deprecate import deprecated -from twisted.python import compat -from twisted.python.deprecate import _fullyQualifiedName as fullyQualifiedName -from twisted.python.versions import Version - - -def prefixedMethodNames(classObj, prefix): - """ - Given a class object C{classObj}, returns a list of method names that match - the string C{prefix}. - - @param classObj: A class object from which to collect method names. - - @param prefix: A native string giving a prefix. Each method with a name - which begins with this prefix will be returned. - @type prefix: L{str} - - @return: A list of the names of matching methods of C{classObj} (and base - classes of C{classObj}). - @rtype: L{list} of L{str} - """ - dct = {} - addMethodNamesToDict(classObj, dct, prefix) - return list(dct.keys()) - - - -def addMethodNamesToDict(classObj, dict, prefix, baseClass=None): - """ - This goes through C{classObj} (and its bases) and puts method names - starting with 'prefix' in 'dict' with a value of 1. if baseClass isn't - None, methods will only be added if classObj is-a baseClass - - If the class in question has the methods 'prefix_methodname' and - 'prefix_methodname2', the resulting dict should look something like: - {"methodname": 1, "methodname2": 1}. - - @param classObj: A class object from which to collect method names. - - @param dict: A L{dict} which will be updated with the results of the - accumulation. Items are added to this dictionary, with method names as - keys and C{1} as values. - @type dict: L{dict} - - @param prefix: A native string giving a prefix. Each method of C{classObj} - (and base classes of C{classObj}) with a name which begins with this - prefix will be returned. - @type prefix: L{str} - - @param baseClass: A class object at which to stop searching upwards for new - methods. To collect all method names, do not pass a value for this - parameter. - - @return: C{None} - """ - for base in classObj.__bases__: - addMethodNamesToDict(base, dict, prefix, baseClass) - - if baseClass is None or baseClass in classObj.__bases__: - for name, method in classObj.__dict__.items(): - optName = name[len(prefix):] - if ((type(method) is types.FunctionType) - and (name[:len(prefix)] == prefix) - and (len(optName))): - dict[optName] = 1 - - - -def prefixedMethods(obj, prefix=''): - """ - Given an object C{obj}, returns a list of method objects that match the - string C{prefix}. - - @param obj: An arbitrary object from which to collect methods. - - @param prefix: A native string giving a prefix. Each method of C{obj} with - a name which begins with this prefix will be returned. - @type prefix: L{str} - - @return: A list of the matching method objects. - @rtype: L{list} - """ - dct = {} - accumulateMethods(obj, dct, prefix) - return list(dct.values()) - - - -def accumulateMethods(obj, dict, prefix='', curClass=None): - """ - Given an object C{obj}, add all methods that begin with C{prefix}. - - @param obj: An arbitrary object to collect methods from. - - @param dict: A L{dict} which will be updated with the results of the - accumulation. Items are added to this dictionary, with method names as - keys and corresponding instance method objects as values. - @type dict: L{dict} - - @param prefix: A native string giving a prefix. Each method of C{obj} with - a name which begins with this prefix will be returned. - @type prefix: L{str} - - @param curClass: The class in the inheritance hierarchy at which to start - collecting methods. Collection proceeds up. To collect all methods - from C{obj}, do not pass a value for this parameter. - - @return: C{None} - """ - if not curClass: - curClass = obj.__class__ - for base in curClass.__bases__: - accumulateMethods(obj, dict, prefix, base) - - for name, method in curClass.__dict__.items(): - optName = name[len(prefix):] - if ((type(method) is types.FunctionType) - and (name[:len(prefix)] == prefix) - and (len(optName))): - dict[optName] = getattr(obj, name) - - - -def namedModule(name): - """ - Return a module given its name. - """ - topLevel = __import__(name) - packages = name.split(".")[1:] - m = topLevel - for p in packages: - m = getattr(m, p) - return m - - - -def namedObject(name): - """ - Get a fully named module-global object. - """ - classSplit = name.split('.') - module = namedModule('.'.join(classSplit[:-1])) - return getattr(module, classSplit[-1]) - -namedClass = namedObject # backwards compat - - - -def requireModule(name, default=None): - """ - Try to import a module given its name, returning C{default} value if - C{ImportError} is raised during import. - - @param name: Module name as it would have been passed to C{import}. - @type name: C{str}. - - @param default: Value returned in case C{ImportError} is raised while - importing the module. - - @return: Module or default value. - """ - try: - return namedModule(name) - except ImportError: - return default - - - -class _NoModuleFound(Exception): - """ - No module was found because none exists. - """ - - - -class InvalidName(ValueError): - """ - The given name is not a dot-separated list of Python objects. - """ - - - -class ModuleNotFound(InvalidName): - """ - The module associated with the given name doesn't exist and it can't be - imported. - """ - - - -class ObjectNotFound(InvalidName): - """ - The object associated with the given name doesn't exist and it can't be - imported. - """ - - - -def _importAndCheckStack(importName): - """ - Import the given name as a module, then walk the stack to determine whether - the failure was the module not existing, or some code in the module (for - example a dependent import) failing. This can be helpful to determine - whether any actual application code was run. For example, to distiguish - administrative error (entering the wrong module name), from programmer - error (writing buggy code in a module that fails to import). - - @param importName: The name of the module to import. - @type importName: C{str} - @raise Exception: if something bad happens. This can be any type of - exception, since nobody knows what loading some arbitrary code might - do. - @raise _NoModuleFound: if no module was found. - """ - try: - return __import__(importName) - except ImportError: - excType, excValue, excTraceback = sys.exc_info() - while excTraceback: - execName = excTraceback.tb_frame.f_globals["__name__"] - # in Python 2 execName is None when an ImportError is encountered, - # where in Python 3 execName is equal to the importName. - if execName is None or execName == importName: - reraise(excValue, excTraceback) - excTraceback = excTraceback.tb_next - raise _NoModuleFound() - - - -def namedAny(name): - """ - Retrieve a Python object by its fully qualified name from the global Python - module namespace. The first part of the name, that describes a module, - will be discovered and imported. Each subsequent part of the name is - treated as the name of an attribute of the object specified by all of the - name which came before it. For example, the fully-qualified name of this - object is 'twisted.python.reflect.namedAny'. - - @type name: L{str} - @param name: The name of the object to return. - - @raise InvalidName: If the name is an empty string, starts or ends with - a '.', or is otherwise syntactically incorrect. - - @raise ModuleNotFound: If the name is syntactically correct but the - module it specifies cannot be imported because it does not appear to - exist. - - @raise ObjectNotFound: If the name is syntactically correct, includes at - least one '.', but the module it specifies cannot be imported because - it does not appear to exist. - - @raise AttributeError: If an attribute of an object along the way cannot be - accessed, or a module along the way is not found. - - @return: the Python object identified by 'name'. - """ - if not name: - raise InvalidName('Empty module name') - - names = name.split('.') - - # if the name starts or ends with a '.' or contains '..', the __import__ - # will raise an 'Empty module name' error. This will provide a better error - # message. - if '' in names: - raise InvalidName( - "name must be a string giving a '.'-separated list of Python " - "identifiers, not %r" % (name,)) - - topLevelPackage = None - moduleNames = names[:] - while not topLevelPackage: - if moduleNames: - trialname = '.'.join(moduleNames) - try: - topLevelPackage = _importAndCheckStack(trialname) - except _NoModuleFound: - moduleNames.pop() - else: - if len(names) == 1: - raise ModuleNotFound("No module named %r" % (name,)) - else: - raise ObjectNotFound('%r does not name an object' % (name,)) - - obj = topLevelPackage - for n in names[1:]: - obj = getattr(obj, n) - - return obj - - - -def filenameToModuleName(fn): - """ - Convert a name in the filesystem to the name of the Python module it is. - - This is aggressive about getting a module name back from a file; it will - always return a string. Aggressive means 'sometimes wrong'; it won't look - at the Python path or try to do any error checking: don't use this method - unless you already know that the filename you're talking about is a Python - module. - - @param fn: A filesystem path to a module or package; C{bytes} on Python 2, - C{bytes} or C{unicode} on Python 3. - - @return: A hopefully importable module name. - @rtype: C{str} - """ - if isinstance(fn, bytes): - initPy = b"__init__.py" - else: - initPy = "__init__.py" - fullName = os.path.abspath(fn) - base = os.path.basename(fn) - if not base: - # this happens when fn ends with a path separator, just skit it - base = os.path.basename(fn[:-1]) - modName = nativeString(os.path.splitext(base)[0]) - while 1: - fullName = os.path.dirname(fullName) - if os.path.exists(os.path.join(fullName, initPy)): - modName = "%s.%s" % ( - nativeString(os.path.basename(fullName)), - nativeString(modName)) - else: - break - return modName - - - -def qual(clazz): - """ - Return full import path of a class. - """ - return clazz.__module__ + '.' + clazz.__name__ - - - -def _determineClass(x): - try: - return x.__class__ - except: - return type(x) - - - -def _determineClassName(x): - c = _determineClass(x) - try: - return c.__name__ - except: - try: - return str(c) - except: - return '' % id(c) - - - -def _safeFormat(formatter, o): - """ - Helper function for L{safe_repr} and L{safe_str}. - - Called when C{repr} or C{str} fail. Returns a string containing info about - C{o} and the latest exception. - - @param formatter: C{str} or C{repr}. - @type formatter: C{type} - @param o: Any object. - - @rtype: C{str} - @return: A string containing information about C{o} and the raised - exception. - """ - io = NativeStringIO() - traceback.print_exc(file=io) - className = _determineClassName(o) - tbValue = io.getvalue() - return "<%s instance at 0x%x with %s error:\n %s>" % ( - className, id(o), formatter.__name__, tbValue) - - - -def safe_repr(o): - """ - Returns a string representation of an object, or a string containing a - traceback, if that object's __repr__ raised an exception. - - @param o: Any object. - - @rtype: C{str} - """ - try: - return repr(o) - except: - return _safeFormat(repr, o) - - - -def safe_str(o): - """ - Returns a string representation of an object, or a string containing a - traceback, if that object's __str__ raised an exception. - - @param o: Any object. - - @rtype: C{str} - """ - if _PY3 and isinstance(o, bytes): - # If o is bytes and seems to holds a utf-8 encoded string, - # convert it to str. - try: - return o.decode('utf-8') - except: - pass - try: - return str(o) - except: - return _safeFormat(str, o) - - -class QueueMethod: - """ - I represent a method that doesn't exist yet. - """ - def __init__(self, name, calls): - self.name = name - self.calls = calls - def __call__(self, *args): - self.calls.append((self.name, args)) - - -def funcinfo(function): - """ - this is more documentation for myself than useful code. - """ - warnings.warn( - "[v2.5] Use inspect.getargspec instead of twisted.python.reflect.funcinfo", - DeprecationWarning, - stacklevel=2) - code=function.func_code - name=function.func_name - argc=code.co_argcount - argv=code.co_varnames[:argc] - defaults=function.func_defaults - - out = [] - - out.append('The function %s accepts %s arguments' % (name ,argc)) - if defaults: - required=argc-len(defaults) - out.append('It requires %s arguments' % required) - out.append('The arguments required are: %s' % argv[:required]) - out.append('additional arguments are:') - for i in range(argc-required): - j=i+required - out.append('%s which has a default of' % (argv[j], defaults[i])) - return out - - -ISNT=0 -WAS=1 -IS=2 - - -def fullFuncName(func): - qualName = (str(pickle.whichmodule(func, func.__name__)) + '.' + func.__name__) - if namedObject(qualName) is not func: - raise Exception("Couldn't find %s as %s." % (func, qualName)) - return qualName - - -def getClass(obj): - """ - Return the class or type of object 'obj'. - Returns sensible result for oldstyle and newstyle instances and types. - """ - if hasattr(obj, '__class__'): - return obj.__class__ - else: - return type(obj) - - -## the following were factored out of usage - -if not _PY3: - # The following functions aren't documented, nor tested, have much simpler - # builtin implementations and are not used within Twisted or "known" - # projects. - - @deprecated(Version("Twisted", 14, 0, 0)) - def getcurrent(clazz): - assert type(clazz) == types.ClassType, 'must be a class...' - module = namedModule(clazz.__module__) - currclass = getattr(module, clazz.__name__, None) - if currclass is None: - return clazz - return currclass - - - # Class graph nonsense - # I should really have a better name for this... - @deprecated(Version("Twisted", 14, 0, 0), "isinstance") - def isinst(inst,clazz): - if type(inst) != compat.InstanceType or type(clazz)!= types.ClassType: - return isinstance(inst,clazz) - cl = inst.__class__ - cl2 = getcurrent(cl) - clazz = getcurrent(clazz) - if issubclass(cl2,clazz): - if cl == cl2: - return WAS - else: - inst.__class__ = cl2 - return IS - else: - return ISNT - - - # These functions are still imported by libraries used in turn by the - # Twisted unit tests, like Nevow 0.10. Since they are deprecated, - # there's no need to port them to Python 3 (hence the condition above). - # https://bazaar.launchpad.net/~divmod-dev/divmod.org/trunk/revision/2716 - # removed the dependency in Nevow. Once that is released, these functions - # can be safely removed from Twisted. - - @deprecated(Version("Twisted", 11, 0, 0), "inspect.getmro") - def allYourBase(classObj, baseClass=None): - """ - allYourBase(classObj, baseClass=None) -> list of all base - classes that are subclasses of baseClass, unless it is None, - in which case all bases will be added. - """ - l = [] - _accumulateBases(classObj, l, baseClass) - return l - - - @deprecated(Version("Twisted", 11, 0, 0), "inspect.getmro") - def accumulateBases(classObj, l, baseClass=None): - _accumulateBases(classObj, l, baseClass) - - - def _accumulateBases(classObj, l, baseClass=None): - for base in classObj.__bases__: - if baseClass is None or issubclass(base, baseClass): - l.append(base) - _accumulateBases(base, l, baseClass) - - -def accumulateClassDict(classObj, attr, adict, baseClass=None): - """ - Accumulate all attributes of a given name in a class hierarchy into a single dictionary. - - Assuming all class attributes of this name are dictionaries. - If any of the dictionaries being accumulated have the same key, the - one highest in the class heirarchy wins. - (XXX: If \"highest\" means \"closest to the starting class\".) - - Ex:: - - class Soy: - properties = {\"taste\": \"bland\"} - - class Plant: - properties = {\"colour\": \"green\"} - - class Seaweed(Plant): - pass - - class Lunch(Soy, Seaweed): - properties = {\"vegan\": 1 } - - dct = {} - - accumulateClassDict(Lunch, \"properties\", dct) - - print dct - - {\"taste\": \"bland\", \"colour\": \"green\", \"vegan\": 1} - """ - for base in classObj.__bases__: - accumulateClassDict(base, attr, adict) - if baseClass is None or baseClass in classObj.__bases__: - adict.update(classObj.__dict__.get(attr, {})) - - -def accumulateClassList(classObj, attr, listObj, baseClass=None): - """ - Accumulate all attributes of a given name in a class heirarchy into a single list. - - Assuming all class attributes of this name are lists. - """ - for base in classObj.__bases__: - accumulateClassList(base, attr, listObj) - if baseClass is None or baseClass in classObj.__bases__: - listObj.extend(classObj.__dict__.get(attr, [])) - - -def isSame(a, b): - return (a is b) - - -def isLike(a, b): - return (a == b) - - -def modgrep(goal): - return objgrep(sys.modules, goal, isLike, 'sys.modules') - - -def isOfType(start, goal): - return ((type(start) is goal) or - (isinstance(start, compat.InstanceType) and - start.__class__ is goal)) - - -def findInstances(start, t): - return objgrep(start, t, isOfType) - - -if not _PY3: - # The function objgrep() currently doesn't work on Python 3 due to some - # edge cases, as described in #6986. - # twisted.python.reflect is quite important and objgrep is not used in - # Twisted itself, so in #5929, we decided to port everything but objgrep() - # and to finish the porting in #6986 - def objgrep(start, goal, eq=isLike, path='', paths=None, seen=None, - showUnknowns=0, maxDepth=None): - """ - An insanely CPU-intensive process for finding stuff. - """ - if paths is None: - paths = [] - if seen is None: - seen = {} - if eq(start, goal): - paths.append(path) - if id(start) in seen: - if seen[id(start)] is start: - return - if maxDepth is not None: - if maxDepth == 0: - return - maxDepth -= 1 - seen[id(start)] = start - # Make an alias for those arguments which are passed recursively to - # objgrep for container objects. - args = (paths, seen, showUnknowns, maxDepth) - if isinstance(start, dict): - for k, v in start.items(): - objgrep(k, goal, eq, path+'{'+repr(v)+'}', *args) - objgrep(v, goal, eq, path+'['+repr(k)+']', *args) - elif isinstance(start, (list, tuple, deque)): - for idx, _elem in enumerate(start): - objgrep(start[idx], goal, eq, path+'['+str(idx)+']', *args) - elif isinstance(start, types.MethodType): - objgrep(start.__self__, goal, eq, path+'.__self__', *args) - objgrep(start.__func__, goal, eq, path+'.__func__', *args) - objgrep(start.__self__.__class__, goal, eq, - path+'.__self__.__class__', *args) - elif hasattr(start, '__dict__'): - for k, v in start.__dict__.items(): - objgrep(v, goal, eq, path+'.'+k, *args) - if isinstance(start, compat.InstanceType): - objgrep(start.__class__, goal, eq, path+'.__class__', *args) - elif isinstance(start, weakref.ReferenceType): - objgrep(start(), goal, eq, path+'()', *args) - elif (isinstance(start, (compat.StringType, - int, types.FunctionType, - types.BuiltinMethodType, RegexType, float, - type(None), compat.FileType)) or - type(start).__name__ in ('wrapper_descriptor', - 'method_descriptor', 'member_descriptor', - 'getset_descriptor')): - pass - elif showUnknowns: - print('unknown type', type(start), start) - return paths - - - -__all__ = [ - 'InvalidName', 'ModuleNotFound', 'ObjectNotFound', - - 'ISNT', 'WAS', 'IS', - - 'QueueMethod', - - 'funcinfo', 'fullFuncName', 'qual', 'getcurrent', 'getClass', 'isinst', - 'namedModule', 'namedObject', 'namedClass', 'namedAny', 'requireModule', - 'safe_repr', 'safe_str', 'allYourBase', 'accumulateBases', - 'prefixedMethodNames', 'addMethodNamesToDict', 'prefixedMethods', - 'accumulateMethods', - 'accumulateClassDict', 'accumulateClassList', 'isSame', 'isLike', - 'modgrep', 'isOfType', 'findInstances', 'objgrep', 'filenameToModuleName', - 'fullyQualifiedName'] - - -if _PY3: - # This is to be removed when fixing #6986 - __all__.remove('objgrep') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/release.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/release.py deleted file mode 100644 index 2454792..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/release.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A release-automation toolkit. - -Don't use this outside of Twisted. - -Maintainer: Christopher Armstrong -""" - -import os - - -# errors - -class DirectoryExists(OSError): - """ - Some directory exists when it shouldn't. - """ - pass - - - -class DirectoryDoesntExist(OSError): - """ - Some directory doesn't exist when it should. - """ - pass - - - -class CommandFailed(OSError): - pass - - - -# utilities - -def sh(command, null=True, prompt=False): - """ - I'll try to execute C{command}, and if C{prompt} is true, I'll - ask before running it. If the command returns something other - than 0, I'll raise C{CommandFailed(command)}. - """ - print "--$", command - - if prompt: - if raw_input("run ?? ").startswith('n'): - return - if null: - command = "%s > /dev/null" % command - if os.system(command) != 0: - raise CommandFailed(command) - - - -def runChdirSafe(f, *args, **kw): - origdir = os.path.abspath('.') - try: - return f(*args, **kw) - finally: - os.chdir(origdir) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/roots.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/roots.py deleted file mode 100644 index ee3c8a3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/roots.py +++ /dev/null @@ -1,248 +0,0 @@ -# -*- test-case-name: twisted.test.test_roots -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Python Roots: an abstract hierarchy representation for Twisted. - -Maintainer: Glyph Lefkowitz -""" - -# System imports -import types -from twisted.python import reflect - -class NotSupportedError(NotImplementedError): - """ - An exception meaning that the tree-manipulation operation - you're attempting to perform is not supported. - """ - - -class Request: - """I am an abstract representation of a request for an entity. - - I also function as the response. The request is responded to by calling - self.write(data) until there is no data left and then calling - self.finish(). - """ - # This attribute should be set to the string name of the protocol being - # responded to (e.g. HTTP or FTP) - wireProtocol = None - def write(self, data): - """Add some data to the response to this request. - """ - raise NotImplementedError("%s.write" % reflect.qual(self.__class__)) - - def finish(self): - """The response to this request is finished; flush all data to the network stream. - """ - raise NotImplementedError("%s.finish" % reflect.qual(self.__class__)) - - -class Entity: - """I am a terminal object in a hierarchy, with no children. - - I represent a null interface; certain non-instance objects (strings and - integers, notably) are Entities. - - Methods on this class are suggested to be implemented, but are not - required, and will be emulated on a per-protocol basis for types which do - not handle them. - """ - def render(self, request): - """ - I produce a stream of bytes for the request, by calling request.write() - and request.finish(). - """ - raise NotImplementedError("%s.render" % reflect.qual(self.__class__)) - - -class Collection: - """I represent a static collection of entities. - - I contain methods designed to represent collections that can be dynamically - created. - """ - - def __init__(self, entities=None): - """Initialize me. - """ - if entities is not None: - self.entities = entities - else: - self.entities = {} - - def getStaticEntity(self, name): - """Get an entity that was added to me using putEntity. - - This method will return 'None' if it fails. - """ - return self.entities.get(name) - - def getDynamicEntity(self, name, request): - """Subclass this to generate an entity on demand. - - This method should return 'None' if it fails. - """ - - def getEntity(self, name, request): - """Retrieve an entity from me. - - I will first attempt to retrieve an entity statically; static entities - will obscure dynamic ones. If that fails, I will retrieve the entity - dynamically. - - If I cannot retrieve an entity, I will return 'None'. - """ - ent = self.getStaticEntity(name) - if ent is not None: - return ent - ent = self.getDynamicEntity(name, request) - if ent is not None: - return ent - return None - - def putEntity(self, name, entity): - """Store a static reference on 'name' for 'entity'. - - Raises a KeyError if the operation fails. - """ - self.entities[name] = entity - - def delEntity(self, name): - """Remove a static reference for 'name'. - - Raises a KeyError if the operation fails. - """ - del self.entities[name] - - def storeEntity(self, name, request): - """Store an entity for 'name', based on the content of 'request'. - """ - raise NotSupportedError("%s.storeEntity" % reflect.qual(self.__class__)) - - def removeEntity(self, name, request): - """Remove an entity for 'name', based on the content of 'request'. - """ - raise NotSupportedError("%s.removeEntity" % reflect.qual(self.__class__)) - - def listStaticEntities(self): - """Retrieve a list of all name, entity pairs that I store references to. - - See getStaticEntity. - """ - return self.entities.items() - - def listDynamicEntities(self, request): - """A list of all name, entity that I can generate on demand. - - See getDynamicEntity. - """ - return [] - - def listEntities(self, request): - """Retrieve a list of all name, entity pairs I contain. - - See getEntity. - """ - return self.listStaticEntities() + self.listDynamicEntities(request) - - def listStaticNames(self): - """Retrieve a list of the names of entities that I store references to. - - See getStaticEntity. - """ - return self.entities.keys() - - - def listDynamicNames(self): - """Retrieve a list of the names of entities that I store references to. - - See getDynamicEntity. - """ - return [] - - - def listNames(self, request): - """Retrieve a list of all names for entities that I contain. - - See getEntity. - """ - return self.listStaticNames() - - -class ConstraintViolation(Exception): - """An exception raised when a constraint is violated. - """ - - -class Constrained(Collection): - """A collection that has constraints on its names and/or entities.""" - - def nameConstraint(self, name): - """A method that determines whether an entity may be added to me with a given name. - - If the constraint is satisfied, return 1; if the constraint is not - satisfied, either return 0 or raise a descriptive ConstraintViolation. - """ - return 1 - - def entityConstraint(self, entity): - """A method that determines whether an entity may be added to me. - - If the constraint is satisfied, return 1; if the constraint is not - satisfied, either return 0 or raise a descriptive ConstraintViolation. - """ - return 1 - - def reallyPutEntity(self, name, entity): - Collection.putEntity(self, name, entity) - - def putEntity(self, name, entity): - """Store an entity if it meets both constraints. - - Otherwise raise a ConstraintViolation. - """ - if self.nameConstraint(name): - if self.entityConstraint(entity): - self.reallyPutEntity(name, entity) - else: - raise ConstraintViolation("Entity constraint violated.") - else: - raise ConstraintViolation("Name constraint violated.") - - -class Locked(Constrained): - """A collection that can be locked from adding entities.""" - - locked = 0 - - def lock(self): - self.locked = 1 - - def entityConstraint(self, entity): - return not self.locked - - -class Homogenous(Constrained): - """A homogenous collection of entities. - - I will only contain entities that are an instance of the class or type - specified by my 'entityType' attribute. - """ - - entityType = types.InstanceType - - def entityConstraint(self, entity): - if isinstance(entity, self.entityType): - return 1 - else: - raise ConstraintViolation("%s of incorrect type (%s)" % - (entity, self.entityType)) - - def getNameType(self): - return "Name" - - def getEntityType(self): - return self.entityType.__name__ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/runtime.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/runtime.py deleted file mode 100644 index 9181147..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/runtime.py +++ /dev/null @@ -1,178 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_runtime -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from __future__ import division, absolute_import - -import os -import sys -import time -import imp -import warnings - -from twisted.python import compat - -if compat._PY3: - _threadModule = "_thread" -else: - _threadModule = "thread" - - - -def shortPythonVersion(): - """ - Returns the Python version as a dot-separated string. - """ - return "%s.%s.%s" % sys.version_info[:3] - - - -knownPlatforms = { - 'nt': 'win32', - 'ce': 'win32', - 'posix': 'posix', - 'java': 'java', - 'org.python.modules.os': 'java', - } - - - -_timeFunctions = { - #'win32': time.clock, - 'win32': time.time, - } - - - -class Platform: - """ - Gives us information about the platform we're running on. - """ - - type = knownPlatforms.get(os.name) - seconds = staticmethod(_timeFunctions.get(type, time.time)) - _platform = sys.platform - - def __init__(self, name=None, platform=None): - if name is not None: - self.type = knownPlatforms.get(name) - self.seconds = _timeFunctions.get(self.type, time.time) - if platform is not None: - self._platform = platform - - - def isKnown(self): - """ - Do we know about this platform? - - @return: Boolean indicating whether this is a known platform or not. - @rtype: C{bool} - """ - return self.type != None - - - def getType(self): - """ - Get platform type. - - @return: Either 'posix', 'win32' or 'java' - @rtype: C{str} - """ - return self.type - - - def isMacOSX(self): - """ - Check if current platform is Mac OS X. - - @return: C{True} if the current platform has been detected as OS X. - @rtype: C{bool} - """ - return self._platform == "darwin" - - - def isWinNT(self): - """ - Are we running in Windows NT? - - This is deprecated and always returns C{True} on win32 because - Twisted only supports Windows NT-derived platforms at this point. - - @return: C{True} if the current platform has been detected as - Windows NT. - @rtype: C{bool} - """ - warnings.warn( - "twisted.python.runtime.Platform.isWinNT was deprecated in " - "Twisted 13.0. Use Platform.isWindows instead.", - DeprecationWarning, stacklevel=2) - return self.isWindows() - - - def isWindows(self): - """ - Are we running in Windows? - - @return: C{True} if the current platform has been detected as - Windows. - @rtype: C{bool} - """ - return self.getType() == 'win32' - - - def isVista(self): - """ - Check if current platform is Windows Vista or Windows Server 2008. - - @return: C{True} if the current platform has been detected as Vista - @rtype: C{bool} - """ - if getattr(sys, "getwindowsversion", None) is not None: - return sys.getwindowsversion()[0] == 6 - else: - return False - - - def isLinux(self): - """ - Check if current platform is Linux. - - @return: C{True} if the current platform has been detected as Linux. - @rtype: C{bool} - """ - return self._platform.startswith("linux") - - - def supportsThreads(self): - """ - Can threads be created? - - @return: C{True} if the threads are supported on the current platform. - @rtype: C{bool} - """ - try: - return imp.find_module(_threadModule)[0] is None - except ImportError: - return False - - - def supportsINotify(self): - """ - Return C{True} if we can use the inotify API on this platform. - - @since: 10.1 - """ - try: - from twisted.python._inotify import INotifyError, init - except ImportError: - return False - try: - os.close(init()) - except INotifyError: - return False - return True - - -platform = Platform() -platformType = platform.getType() -seconds = platform.seconds diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/sendmsg.c b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/sendmsg.c deleted file mode 100644 index 6e9cbac..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/sendmsg.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright (c) Twisted Matrix Laboratories. - * See LICENSE for details. - */ - -#define PY_SSIZE_T_CLEAN 1 -#include - -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -/* This may cause some warnings, but if you want to get rid of them, upgrade - * your Python version. */ -typedef int Py_ssize_t; -#endif - -#include -#include -#include - -#include - -#ifdef BSD -#include -#endif - -/* - * As per - * : - * - * "To forestall portability problems, it is recommended that applications - * not use values larger than (2**31)-1 for the socklen_t type." - */ - -#define SOCKLEN_MAX 0x7FFFFFFF - -PyObject *sendmsg_socket_error; - -static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds); -static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds); -static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args, PyObject *keywds); - -static char sendmsg_doc[] = "\ -Bindings for sendmsg(2), recvmsg(2), and a minimal helper for inspecting\n\ -address family of a socket.\n\ -"; - -static char sendmsg_sendmsg_doc[] = "\ -Wrap the C sendmsg(2) function for sending \"messages\" on a socket.\n\ -\n\ -@param fd: The file descriptor of the socket over which to send a message.\n\ -@type fd: C{int}\n\ -\n\ -@param data: Bytes to write to the socket.\n\ -@type data: C{str}\n\ -\n\ -@param flags: Flags to affect how the message is sent. See the C{MSG_}\n\ - constants in the sendmsg(2) manual page. By default no flags are set.\n\ -@type flags: C{int}\n\ -\n\ -@param ancillary: Extra data to send over the socket outside of the normal\n\ - datagram or stream mechanism. By default no ancillary data is sent.\n\ -@type ancillary: C{list} of C{tuple} of C{int}, C{int}, and C{str}.\n\ -\n\ -@raise OverflowError: Raised if too much ancillary data is given.\n\ -@raise socket.error: Raised if the underlying syscall indicates an error.\n\ -\n\ -@return: The return value of the underlying syscall, if it succeeds.\n\ -"; - -static char sendmsg_recvmsg_doc[] = "\ -Wrap the C recvmsg(2) function for receiving \"messages\" on a socket.\n\ -\n\ -@param fd: The file descriptor of the socket over which to receive a message.\n\ -@type fd: C{int}\n\ -\n\ -@param flags: Flags to affect how the message is sent. See the C{MSG_}\n\ - constants in the sendmsg(2) manual page. By default no flags are set.\n\ -@type flags: C{int}\n\ -\n\ -@param maxsize: The maximum number of bytes to receive from the socket\n\ - using the datagram or stream mechanism. The default maximum is 8192.\n\ -@type maxsize: C{int}\n\ -\n\ -@param cmsg_size: The maximum number of bytes to receive from the socket\n\ - outside of the normal datagram or stream mechanism. The default maximum is 4096.\n\ -\n\ -@raise OverflowError: Raised if too much ancillary data is given.\n\ -@raise socket.error: Raised if the underlying syscall indicates an error.\n\ -\n\ -@return: A C{tuple} of three elements: the bytes received using the\n\ - datagram/stream mechanism, flags as an C{int} describing the data\n\ - received, and a C{list} of C{tuples} giving ancillary received data.\n\ -"; - -static char sendmsg_getsockfam_doc[] = "\ -Retrieve the address family of a given socket.\n\ -\n\ -@param fd: The file descriptor of the socket the address family of which\n\ - to retrieve.\n\ -@type fd: C{int}\n\ -\n\ -@raise socket.error: Raised if the underlying getsockname call indicates\n\ - an error.\n\ -\n\ -@return: A C{int} representing the address family of the socket. For\n\ - example, L{socket.AF_INET}, L{socket.AF_INET6}, or L{socket.AF_UNIX}.\n\ -"; - -static PyMethodDef sendmsg_methods[] = { - {"send1msg", (PyCFunction) sendmsg_sendmsg, METH_VARARGS | METH_KEYWORDS, - sendmsg_sendmsg_doc}, - {"recv1msg", (PyCFunction) sendmsg_recvmsg, METH_VARARGS | METH_KEYWORDS, - sendmsg_recvmsg_doc}, - {"getsockfam", (PyCFunction) sendmsg_getsockfam, - METH_VARARGS | METH_KEYWORDS, sendmsg_getsockfam_doc}, - {NULL, NULL, 0, NULL} -}; - - -PyMODINIT_FUNC initsendmsg(void) { - PyObject *module; - - sendmsg_socket_error = NULL; /* Make sure that this has a known value - before doing anything that might exit. */ - - module = Py_InitModule3("sendmsg", sendmsg_methods, sendmsg_doc); - - if (!module) { - return; - } - - /* - The following is the only value mentioned by POSIX: - http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html - */ - - if (-1 == PyModule_AddIntConstant(module, "SCM_RIGHTS", SCM_RIGHTS)) { - return; - } - - - /* BSD, Darwin, Hurd */ -#if defined(SCM_CREDS) - if (-1 == PyModule_AddIntConstant(module, "SCM_CREDS", SCM_CREDS)) { - return; - } -#endif - - /* Linux */ -#if defined(SCM_CREDENTIALS) - if (-1 == PyModule_AddIntConstant(module, "SCM_CREDENTIALS", SCM_CREDENTIALS)) { - return; - } -#endif - - /* Apparently everywhere, but not standardized. */ -#if defined(SCM_TIMESTAMP) - if (-1 == PyModule_AddIntConstant(module, "SCM_TIMESTAMP", SCM_TIMESTAMP)) { - return; - } -#endif - - module = PyImport_ImportModule("socket"); - if (!module) { - return; - } - - sendmsg_socket_error = PyObject_GetAttrString(module, "error"); - if (!sendmsg_socket_error) { - return; - } -} - -static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) { - - int fd; - int flags = 0; - Py_ssize_t sendmsg_result, iovec_length; - struct msghdr message_header; - struct iovec iov[1]; - PyObject *ancillary = NULL; - PyObject *iterator = NULL; - PyObject *item = NULL; - PyObject *result_object = NULL; - - static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL}; - - if (!PyArg_ParseTupleAndKeywords( - args, keywds, "it#|iO:sendmsg", kwlist, - &fd, - &iov[0].iov_base, - &iovec_length, - &flags, - &ancillary)) { - return NULL; - } - - iov[0].iov_len = iovec_length; - - message_header.msg_name = NULL; - message_header.msg_namelen = 0; - - message_header.msg_iov = iov; - message_header.msg_iovlen = 1; - - message_header.msg_control = NULL; - message_header.msg_controllen = 0; - - message_header.msg_flags = 0; - - if (ancillary) { - - if (!PyList_Check(ancillary)) { - PyErr_Format(PyExc_TypeError, - "send1msg argument 3 expected list, got %s", - ancillary->ob_type->tp_name); - goto finished; - } - - iterator = PyObject_GetIter(ancillary); - - if (iterator == NULL) { - goto finished; - } - - size_t all_data_len = 0; - - /* First we need to know how big the buffer needs to be in order to - have enough space for all of the messages. */ - while ( (item = PyIter_Next(iterator)) ) { - int type, level; - Py_ssize_t data_len; - size_t prev_all_data_len; - char *data; - - if (!PyTuple_Check(item)) { - PyErr_Format(PyExc_TypeError, - "send1msg argument 3 expected list of tuple, " - "got list containing %s", - item->ob_type->tp_name); - goto finished; - } - - if (!PyArg_ParseTuple( - item, "iit#:sendmsg ancillary data (level, type, data)", - &level, &type, &data, &data_len)) { - goto finished; - } - - prev_all_data_len = all_data_len; - all_data_len += CMSG_SPACE(data_len); - - Py_DECREF(item); - item = NULL; - - if (all_data_len < prev_all_data_len) { - PyErr_Format(PyExc_OverflowError, - "Too much msg_control to fit in a size_t: %zu", - prev_all_data_len); - goto finished; - } - } - - Py_DECREF(iterator); - iterator = NULL; - - /* Allocate the buffer for all of the ancillary elements, if we have - * any. */ - if (all_data_len) { - if (all_data_len > SOCKLEN_MAX) { - PyErr_Format(PyExc_OverflowError, - "Too much msg_control to fit in a socklen_t: %zu", - all_data_len); - goto finished; - } - message_header.msg_control = PyMem_Malloc(all_data_len); - if (!message_header.msg_control) { - PyErr_NoMemory(); - goto finished; - } - } else { - message_header.msg_control = NULL; - } - message_header.msg_controllen = (socklen_t) all_data_len; - - iterator = PyObject_GetIter(ancillary); /* again */ - - if (!iterator) { - goto finished; - } - - /* Unpack the tuples into the control message. */ - struct cmsghdr *control_message = CMSG_FIRSTHDR(&message_header); - while ( (item = PyIter_Next(iterator)) ) { - int type, level; - Py_ssize_t data_len; - size_t data_size; - unsigned char *data, *cmsg_data; - - /* We explicitly allocated enough space for all ancillary data - above; if there isn't enough room, all bets are off. */ - assert(control_message); - - if (!PyArg_ParseTuple(item, - "iit#:sendmsg ancillary data (level, type, data)", - &level, - &type, - &data, - &data_len)) { - goto finished; - } - - control_message->cmsg_level = level; - control_message->cmsg_type = type; - data_size = CMSG_LEN(data_len); - - if (data_size > SOCKLEN_MAX) { - PyErr_Format(PyExc_OverflowError, - "CMSG_LEN(%zd) > SOCKLEN_MAX", data_len); - goto finished; - } - - control_message->cmsg_len = (socklen_t) data_size; - - cmsg_data = CMSG_DATA(control_message); - memcpy(cmsg_data, data, data_len); - - Py_DECREF(item); - item = NULL; - - control_message = CMSG_NXTHDR(&message_header, control_message); - } - Py_DECREF(iterator); - iterator = NULL; - - if (PyErr_Occurred()) { - goto finished; - } - } - - sendmsg_result = sendmsg(fd, &message_header, flags); - - if (sendmsg_result < 0) { - PyErr_SetFromErrno(sendmsg_socket_error); - goto finished; - } - - result_object = Py_BuildValue("n", sendmsg_result); - - finished: - - if (item) { - Py_DECREF(item); - item = NULL; - } - if (iterator) { - Py_DECREF(iterator); - iterator = NULL; - } - if (message_header.msg_control) { - PyMem_Free(message_header.msg_control); - message_header.msg_control = NULL; - } - return result_object; -} - -static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) { - int fd = -1; - int flags = 0; - int maxsize = 8192; - int cmsg_size = 4096; - size_t cmsg_space; - size_t cmsg_overhead; - Py_ssize_t recvmsg_result; - - struct msghdr message_header; - struct cmsghdr *control_message; - struct iovec iov[1]; - char *cmsgbuf; - PyObject *ancillary; - PyObject *final_result = NULL; - - static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist, - &fd, &flags, &maxsize, &cmsg_size)) { - return NULL; - } - - cmsg_space = CMSG_SPACE(cmsg_size); - - /* overflow check */ - if (cmsg_space > SOCKLEN_MAX) { - PyErr_Format(PyExc_OverflowError, - "CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d", - cmsg_size); - return NULL; - } - - message_header.msg_name = NULL; - message_header.msg_namelen = 0; - - iov[0].iov_len = maxsize; - iov[0].iov_base = PyMem_Malloc(maxsize); - - if (!iov[0].iov_base) { - PyErr_NoMemory(); - return NULL; - } - - message_header.msg_iov = iov; - message_header.msg_iovlen = 1; - - cmsgbuf = PyMem_Malloc(cmsg_space); - - if (!cmsgbuf) { - PyMem_Free(iov[0].iov_base); - PyErr_NoMemory(); - return NULL; - } - - memset(cmsgbuf, 0, cmsg_space); - message_header.msg_control = cmsgbuf; - /* see above for overflow check */ - message_header.msg_controllen = (socklen_t) cmsg_space; - - recvmsg_result = recvmsg(fd, &message_header, flags); - if (recvmsg_result < 0) { - PyErr_SetFromErrno(sendmsg_socket_error); - goto finished; - } - - ancillary = PyList_New(0); - if (!ancillary) { - goto finished; - } - - for (control_message = CMSG_FIRSTHDR(&message_header); - control_message; - control_message = CMSG_NXTHDR(&message_header, - control_message)) { - PyObject *entry; - - /* Some platforms apparently always fill out the ancillary data - structure with a single bogus value if none is provided; ignore it, - if that is the case. */ - - if ((!(control_message->cmsg_level)) && - (!(control_message->cmsg_type))) { - continue; - } - - /* - * Figure out how much of the cmsg size is cmsg structure overhead - in - * other words, how much is not part of the application data. This lets - * us compute the right application data size below. There should - * really be a CMSG_ macro for this. - */ - cmsg_overhead = (char*)CMSG_DATA(control_message) - (char*)control_message; - - entry = Py_BuildValue( - "(iis#)", - control_message->cmsg_level, - control_message->cmsg_type, - CMSG_DATA(control_message), - (Py_ssize_t) (control_message->cmsg_len - cmsg_overhead)); - - if (!entry) { - Py_DECREF(ancillary); - goto finished; - } - - if (PyList_Append(ancillary, entry) < 0) { - Py_DECREF(ancillary); - Py_DECREF(entry); - goto finished; - } else { - Py_DECREF(entry); - } - } - - final_result = Py_BuildValue( - "s#iO", - iov[0].iov_base, - recvmsg_result, - message_header.msg_flags, - ancillary); - - Py_DECREF(ancillary); - - finished: - PyMem_Free(iov[0].iov_base); - PyMem_Free(cmsgbuf); - return final_result; -} - -static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args, - PyObject *keywds) { - int fd; - struct sockaddr sa; - static char *kwlist[] = {"fd", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist, &fd)) { - return NULL; - } - socklen_t sz = sizeof(sa); - if (getsockname(fd, &sa, &sz)) { - PyErr_SetFromErrno(sendmsg_socket_error); - return NULL; - } - return Py_BuildValue("i", sa.sa_family); -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/shortcut.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/shortcut.py deleted file mode 100644 index b60f858..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/shortcut.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Creation of Windows shortcuts. - -Requires win32all. -""" - -from win32com.shell import shell -import pythoncom -import os - - -def open(filename): - """Open an existing shortcut for reading. - - @return: The shortcut object - @rtype: Shortcut - """ - sc=Shortcut() - sc.load(filename) - return sc - - -class Shortcut: - """A shortcut on Win32. - >>> sc=Shortcut(path, arguments, description, workingdir, iconpath, iconidx) - @param path: Location of the target - @param arguments: If path points to an executable, optional arguments to - pass - @param description: Human-readable description of target - @param workingdir: Directory from which target is launched - @param iconpath: Filename that contains an icon for the shortcut - @param iconidx: If iconpath is set, optional index of the icon desired - """ - - def __init__(self, - path=None, - arguments=None, - description=None, - workingdir=None, - iconpath=None, - iconidx=0): - self._base = pythoncom.CoCreateInstance( - shell.CLSID_ShellLink, None, - pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink - ) - data = map(None, - ['"%s"' % os.path.abspath(path), arguments, description, - os.path.abspath(workingdir), os.path.abspath(iconpath)], - ("SetPath", "SetArguments", "SetDescription", - "SetWorkingDirectory") ) - for value, function in data: - if value and function: - # call function on each non-null value - getattr(self, function)(value) - if iconpath: - self.SetIconLocation(iconpath, iconidx) - - def load( self, filename ): - """Read a shortcut file from disk.""" - self._base.QueryInterface(pythoncom.IID_IPersistFile).Load(filename) - - def save( self, filename ): - """Write the shortcut to disk. - - The file should be named something.lnk. - """ - self._base.QueryInterface(pythoncom.IID_IPersistFile).Save(filename, 0) - - def __getattr__( self, name ): - if name != "_base": - return getattr(self._base, name) - raise AttributeError, "%s instance has no attribute %s" % \ - (self.__class__.__name__, name) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/syslog.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/syslog.py deleted file mode 100644 index 7f8afad..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/syslog.py +++ /dev/null @@ -1,107 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_syslog -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Classes and utility functions for integrating Twisted and syslog. - -You probably want to call L{startLogging}. -""" - -syslog = __import__('syslog') - -from twisted.python import log - -# These defaults come from the Python syslog docs. -DEFAULT_OPTIONS = 0 -DEFAULT_FACILITY = syslog.LOG_USER - - - -class SyslogObserver: - """ - A log observer for logging to syslog. - - See L{twisted.python.log} for context. - - This logObserver will automatically use LOG_ALERT priority for logged - failures (such as from C{log.err()}), but you can use any priority and - facility by setting the 'C{syslogPriority}' and 'C{syslogFacility}' keys in - the event dict. - """ - openlog = syslog.openlog - syslog = syslog.syslog - - def __init__(self, prefix, options=DEFAULT_OPTIONS, - facility=DEFAULT_FACILITY): - """ - @type prefix: C{str} - @param prefix: The syslog prefix to use. - - @type options: C{int} - @param options: A bitvector represented as an integer of the syslog - options to use. - - @type facility: C{int} - @param facility: An indication to the syslog daemon of what sort of - program this is (essentially, an additional arbitrary metadata - classification for messages sent to syslog by this observer). - """ - self.openlog(prefix, options, facility) - - - def emit(self, eventDict): - """ - Send a message event to the I{syslog}. - - @param eventDict: The event to send. If it has no C{'message'} key, it - will be ignored. Otherwise, if it has C{'syslogPriority'} and/or - C{'syslogFacility'} keys, these will be used as the syslog priority - and facility. If it has no C{'syslogPriority'} key but a true - value for the C{'isError'} key, the B{LOG_ALERT} priority will be - used; if it has a false value for C{'isError'}, B{LOG_INFO} will be - used. If the C{'message'} key is multiline, each line will be sent - to the syslog separately. - """ - # Figure out what the message-text is. - text = log.textFromEventDict(eventDict) - if text is None: - return - - # Figure out what syslog parameters we might need to use. - priority = syslog.LOG_INFO - facility = 0 - if eventDict['isError']: - priority = syslog.LOG_ALERT - if 'syslogPriority' in eventDict: - priority = int(eventDict['syslogPriority']) - if 'syslogFacility' in eventDict: - facility = int(eventDict['syslogFacility']) - - # Break the message up into lines and send them. - lines = text.split('\n') - while lines[-1:] == ['']: - lines.pop() - - firstLine = True - for line in lines: - if firstLine: - firstLine = False - else: - line = '\t' + line - self.syslog(priority | facility, - '[%s] %s' % (eventDict['system'], line)) - - - -def startLogging(prefix='Twisted', options=DEFAULT_OPTIONS, - facility=DEFAULT_FACILITY, setStdout=1): - """ - Send all Twisted logging output to syslog from now on. - - The prefix, options and facility arguments are passed to - C{syslog.openlog()}, see the Python syslog documentation for details. For - other parameters, see L{twisted.python.log.startLoggingWithObserver}. - """ - obs = SyslogObserver(prefix, options, facility) - log.startLoggingWithObserver(obs.emit, setStdout=setStdout) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/systemd.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/systemd.py deleted file mode 100644 index 337e729..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/systemd.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_systemd -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Integration with systemd. - -Currently only the minimum APIs necessary for using systemd's socket activation -feature are supported. -""" - -from __future__ import division, absolute_import - -__all__ = ['ListenFDs'] - -from os import getpid - - -class ListenFDs(object): - """ - L{ListenFDs} provides access to file descriptors inherited from systemd. - - Typically L{ListenFDs.fromEnvironment} should be used to construct a new - instance of L{ListenFDs}. - - @cvar _START: File descriptors inherited from systemd are always - consecutively numbered, with a fixed lowest "starting" descriptor. This - gives the default starting descriptor. Since this must agree with the - value systemd is using, it typically should not be overridden. - @type _START: C{int} - - @ivar _descriptors: A C{list} of C{int} giving the descriptors which were - inherited. - """ - _START = 3 - - def __init__(self, descriptors): - """ - @param descriptors: The descriptors which will be returned from calls to - C{inheritedDescriptors}. - """ - self._descriptors = descriptors - - - @classmethod - def fromEnvironment(cls, environ=None, start=None): - """ - @param environ: A dictionary-like object to inspect to discover - inherited descriptors. By default, C{None}, indicating that the - real process environment should be inspected. The default is - suitable for typical usage. - - @param start: An integer giving the lowest value of an inherited - descriptor systemd will give us. By default, C{None}, indicating - the known correct (that is, in agreement with systemd) value will be - used. The default is suitable for typical usage. - - @return: A new instance of C{cls} which can be used to look up the - descriptors which have been inherited. - """ - if environ is None: - from os import environ - if start is None: - start = cls._START - - descriptors = [] - - try: - pid = int(environ['LISTEN_PID']) - except (KeyError, ValueError): - pass - else: - if pid == getpid(): - try: - count = int(environ['LISTEN_FDS']) - except (KeyError, ValueError): - pass - else: - descriptors = range(start, start + count) - del environ['LISTEN_PID'], environ['LISTEN_FDS'] - - return cls(descriptors) - - - def inheritedDescriptors(self): - """ - @return: The configured list of descriptors. - """ - return list(self._descriptors) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/__init__.py deleted file mode 100644 index cfdc40d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Unit tests for L{twisted.python}. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/deprecatedattributes.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/deprecatedattributes.py deleted file mode 100644 index 5e7672a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/deprecatedattributes.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A module that is deprecated, used by L{twisted.python.test.test_deprecate} for -testing purposes. -""" - -from __future__ import division, absolute_import - -from twisted.python.versions import Version -from twisted.python.deprecate import deprecatedModuleAttribute - - -# Known module-level attributes. -DEPRECATED_ATTRIBUTE = 42 -ANOTHER_ATTRIBUTE = 'hello' - - -version = Version('Twisted', 8, 0, 0) -message = 'Oh noes!' - - -deprecatedModuleAttribute( - version, - message, - __name__, - 'DEPRECATED_ATTRIBUTE') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/modules_helpers.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/modules_helpers.py deleted file mode 100644 index 2b574dd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/modules_helpers.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Facilities for helping test code which interacts with Python's module system -to load code. -""" - -from __future__ import division, absolute_import - -import sys - -from twisted.python.filepath import FilePath - - -class TwistedModulesMixin: - """ - A mixin for C{twisted.trial.unittest.SynchronousTestCase} providing useful - methods for manipulating Python's module system. - """ - - def replaceSysPath(self, sysPath): - """ - Replace sys.path, for the duration of the test, with the given value. - """ - originalSysPath = sys.path[:] - def cleanUpSysPath(): - sys.path[:] = originalSysPath - self.addCleanup(cleanUpSysPath) - sys.path[:] = sysPath - - - def replaceSysModules(self, sysModules): - """ - Replace sys.modules, for the duration of the test, with the given value. - """ - originalSysModules = sys.modules.copy() - def cleanUpSysModules(): - sys.modules.clear() - sys.modules.update(originalSysModules) - self.addCleanup(cleanUpSysModules) - sys.modules.clear() - sys.modules.update(sysModules) - - - def pathEntryWithOnePackage(self, pkgname="test_package"): - """ - Generate a L{FilePath} with one package, named C{pkgname}, on it, and - return the L{FilePath} of the path entry. - """ - entry = FilePath(self.mktemp()) - pkg = entry.child("test_package") - pkg.makedirs() - pkg.child("__init__.py").setContent(b"") - return entry diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/pullpipe.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/pullpipe.py deleted file mode 100644 index e606662..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/pullpipe.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python -# -*- test-case-name: twisted.python.test.test_sendmsg -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys, os -from struct import unpack - -# This makes me sad. Why aren't things nice? -sys.path.insert(0, __file__.rsplit('/', 4)[0]) - -from twisted.python.sendmsg import recv1msg - -def recvfd(socketfd): - """ - Receive a file descriptor from a L{send1msg} message on the given C{AF_UNIX} - socket. - - @param socketfd: An C{AF_UNIX} socket, attached to another process waiting - to send sockets via the ancillary data mechanism in L{send1msg}. - - @param fd: C{int} - - @return: a 2-tuple of (new file descriptor, description). - - @rtype: 2-tuple of (C{int}, C{str}) - """ - data, flags, ancillary = recv1msg(socketfd) - [(cmsg_level, cmsg_type, packedFD)] = ancillary - # cmsg_level and cmsg_type really need to be SOL_SOCKET / SCM_RIGHTS, but - # since those are the *only* standard values, there's not much point in - # checking. - [unpackedFD] = unpack("i", packedFD) - return (unpackedFD, data) - - -if __name__ == '__main__': - fd, description = recvfd(int(sys.argv[1])) - os.write(fd, "Test fixture data: %s.\n" % (description,)) - os.close(fd) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_components.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_components.py deleted file mode 100644 index 30cc93c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_components.py +++ /dev/null @@ -1,858 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for Twisted component architecture. -""" - -from __future__ import division, absolute_import - -from functools import wraps - -from zope.interface import Interface, implementer, Attribute -from zope.interface.adapter import AdapterRegistry - -from twisted.python.compat import comparable, cmp -from twisted.trial import unittest -from twisted.python import components -from twisted.python.components import _addHook, _removeHook, proxyForInterface - - -class Compo(components.Componentized): - num = 0 - def inc(self): - self.num = self.num + 1 - return self.num - -class IAdept(Interface): - def adaptorFunc(): - raise NotImplementedError() - -class IElapsed(Interface): - def elapsedFunc(): - """ - 1! - """ - -@implementer(IAdept) -class Adept(components.Adapter): - def __init__(self, orig): - self.original = orig - self.num = 0 - def adaptorFunc(self): - self.num = self.num + 1 - return self.num, self.original.inc() - -@implementer(IElapsed) -class Elapsed(components.Adapter): - def elapsedFunc(self): - return 1 - -class AComp(components.Componentized): - pass -class BComp(AComp): - pass -class CComp(BComp): - pass - -class ITest(Interface): - pass - - -class ITest2(Interface): - pass - - -class ITest3(Interface): - pass - - -class ITest4(Interface): - pass - - -@implementer(ITest, ITest3, ITest4) -class Test(components.Adapter): - def __init__(self, orig): - pass - - -@implementer(ITest2) -class Test2: - temporaryAdapter = 1 - def __init__(self, orig): - pass - - - -class RegistryUsingMixin(object): - """ - Mixin for test cases which modify the global registry somehow. - """ - def setUp(self): - """ - Configure L{twisted.python.components.registerAdapter} to mutate an - alternate registry to improve test isolation. - """ - # Create a brand new, empty registry and put it onto the components - # module where registerAdapter will use it. Also ensure that it goes - # away at the end of the test. - scratchRegistry = AdapterRegistry() - self.patch(components, 'globalRegistry', scratchRegistry) - # Hook the new registry up to the adapter lookup system and ensure that - # association is also discarded after the test. - hook = _addHook(scratchRegistry) - self.addCleanup(_removeHook, hook) - - - -class ComponentizedTests(unittest.SynchronousTestCase, RegistryUsingMixin): - """ - Simple test case for caching in Componentized. - """ - def setUp(self): - RegistryUsingMixin.setUp(self) - - components.registerAdapter(Test, AComp, ITest) - components.registerAdapter(Test, AComp, ITest3) - components.registerAdapter(Test2, AComp, ITest2) - - - def testComponentized(self): - components.registerAdapter(Adept, Compo, IAdept) - components.registerAdapter(Elapsed, Compo, IElapsed) - - c = Compo() - assert c.getComponent(IAdept).adaptorFunc() == (1, 1) - assert c.getComponent(IAdept).adaptorFunc() == (2, 2) - assert IElapsed(IAdept(c)).elapsedFunc() == 1 - - def testInheritanceAdaptation(self): - c = CComp() - co1 = c.getComponent(ITest) - co2 = c.getComponent(ITest) - co3 = c.getComponent(ITest2) - co4 = c.getComponent(ITest2) - assert co1 is co2 - assert co3 is not co4 - c.removeComponent(co1) - co5 = c.getComponent(ITest) - co6 = c.getComponent(ITest) - assert co5 is co6 - assert co1 is not co5 - - def testMultiAdapter(self): - c = CComp() - co1 = c.getComponent(ITest) - co3 = c.getComponent(ITest3) - co4 = c.getComponent(ITest4) - self.assertIdentical(None, co4) - self.assertIdentical(co1, co3) - - - def test_getComponentDefaults(self): - """ - Test that a default value specified to Componentized.getComponent if - there is no component for the requested interface. - """ - componentized = components.Componentized() - default = object() - self.assertIdentical( - componentized.getComponent(ITest, default), - default) - self.assertIdentical( - componentized.getComponent(ITest, default=default), - default) - self.assertIdentical( - componentized.getComponent(ITest), - None) - - - def test_setAdapter(self): - """ - C{Componentized.setAdapter} sets a component for an interface by - wrapping the instance with the given adapter class. - """ - componentized = components.Componentized() - componentized.setAdapter(IAdept, Adept) - component = componentized.getComponent(IAdept) - self.assertEqual(component.original, componentized) - self.assertIsInstance(component, Adept) - - - def test_addAdapter(self): - """ - C{Componentized.setAdapter} adapts the instance by wrapping it with - given adapter class, then stores it using C{addComponent}. - """ - componentized = components.Componentized() - componentized.addAdapter(Adept, ignoreClass=True) - component = componentized.getComponent(IAdept) - self.assertEqual(component.original, componentized) - self.assertIsInstance(component, Adept) - - - def test_setComponent(self): - """ - C{Componentized.setComponent} stores the given component using the - given interface as the key. - """ - componentized = components.Componentized() - obj = object() - componentized.setComponent(ITest, obj) - self.assertIdentical(componentized.getComponent(ITest), obj) - - - def test_unsetComponent(self): - """ - C{Componentized.setComponent} removes the cached component for the - given interface. - """ - componentized = components.Componentized() - obj = object() - componentized.setComponent(ITest, obj) - componentized.unsetComponent(ITest) - self.assertIdentical(componentized.getComponent(ITest), None) - - - def test_reprableComponentized(self): - """ - C{ReprableComponentized} has a C{__repr__} that lists its cache. - """ - rc = components.ReprableComponentized() - rc.setComponent(ITest, "hello") - result = repr(rc) - self.assertIn("ITest", result) - self.assertIn("hello", result) - - - -class AdapterTests(unittest.SynchronousTestCase): - """Test adapters.""" - - def testAdapterGetComponent(self): - o = object() - a = Adept(o) - self.assertRaises(components.CannotAdapt, ITest, a) - self.assertEqual(ITest(a, None), None) - - - -class IMeta(Interface): - pass - -@implementer(IMeta) -class MetaAdder(components.Adapter): - def add(self, num): - return self.original.num + num - -@implementer(IMeta) -class BackwardsAdder(components.Adapter): - def add(self, num): - return self.original.num - num - -class MetaNumber: - def __init__(self, num): - self.num = num - -class FakeAdder: - def add(self, num): - return num + 5 - -class FakeNumber: - num = 3 - -class ComponentNumber(components.Componentized): - def __init__(self): - self.num = 0 - components.Componentized.__init__(self) - -implementer(IMeta) -class ComponentMeta(components.Adapter): - def __init__(self, original): - components.Adapter.__init__(self, original) - self.num = self.original.num - -class ComponentAdder(ComponentMeta): - def add(self, num): - self.num += num - return self.num - -class ComponentDoubler(ComponentMeta): - def add(self, num): - self.num += (num * 2) - return self.original.num - -class IAttrX(Interface): - def x(): - pass - -class IAttrXX(Interface): - def xx(): - pass - -@implementer(IAttrX) -class Xcellent: - def x(self): - return 'x!' - -@comparable -class DoubleXAdapter: - num = 42 - def __init__(self, original): - self.original = original - def xx(self): - return (self.original.x(), self.original.x()) - def __cmp__(self, other): - return cmp(self.num, other.num) - - -class MetaInterfaceTests(RegistryUsingMixin, unittest.SynchronousTestCase): - def testBasic(self): - components.registerAdapter(MetaAdder, MetaNumber, IMeta) - n = MetaNumber(1) - self.assertEqual(IMeta(n).add(1), 2) - - def testComponentizedInteraction(self): - components.registerAdapter(ComponentAdder, ComponentNumber, IMeta) - c = ComponentNumber() - IMeta(c).add(1) - IMeta(c).add(1) - self.assertEqual(IMeta(c).add(1), 3) - - def testAdapterWithCmp(self): - # Make sure that a __cmp__ on an adapter doesn't break anything - components.registerAdapter(DoubleXAdapter, IAttrX, IAttrXX) - xx = IAttrXX(Xcellent()) - self.assertEqual(('x!', 'x!'), xx.xx()) - - -class RegistrationTests(RegistryUsingMixin, unittest.SynchronousTestCase): - """ - Tests for adapter registration. - """ - def _registerAdapterForClassOrInterface(self, original): - """ - Register an adapter with L{components.registerAdapter} for the given - class or interface and verify that the adapter can be looked up with - L{components.getAdapterFactory}. - """ - adapter = lambda o: None - components.registerAdapter(adapter, original, ITest) - self.assertIdentical( - components.getAdapterFactory(original, ITest, None), - adapter) - - - def test_registerAdapterForClass(self): - """ - Test that an adapter from a class can be registered and then looked - up. - """ - class TheOriginal(object): - pass - return self._registerAdapterForClassOrInterface(TheOriginal) - - - def test_registerAdapterForInterface(self): - """ - Test that an adapter from an interface can be registered and then - looked up. - """ - return self._registerAdapterForClassOrInterface(ITest2) - - - def _duplicateAdapterForClassOrInterface(self, original): - """ - Verify that L{components.registerAdapter} raises L{ValueError} if the - from-type/interface and to-interface pair is not unique. - """ - firstAdapter = lambda o: False - secondAdapter = lambda o: True - components.registerAdapter(firstAdapter, original, ITest) - self.assertRaises( - ValueError, - components.registerAdapter, - secondAdapter, original, ITest) - # Make sure that the original adapter is still around as well - self.assertIdentical( - components.getAdapterFactory(original, ITest, None), - firstAdapter) - - - def test_duplicateAdapterForClass(self): - """ - Test that attempting to register a second adapter from a class - raises the appropriate exception. - """ - class TheOriginal(object): - pass - return self._duplicateAdapterForClassOrInterface(TheOriginal) - - - def test_duplicateAdapterForInterface(self): - """ - Test that attempting to register a second adapter from an interface - raises the appropriate exception. - """ - return self._duplicateAdapterForClassOrInterface(ITest2) - - - def _duplicateAdapterForClassOrInterfaceAllowed(self, original): - """ - Verify that when C{components.ALLOW_DUPLICATES} is set to C{True}, new - adapter registrations for a particular from-type/interface and - to-interface pair replace older registrations. - """ - firstAdapter = lambda o: False - secondAdapter = lambda o: True - class TheInterface(Interface): - pass - components.registerAdapter(firstAdapter, original, TheInterface) - components.ALLOW_DUPLICATES = True - try: - components.registerAdapter(secondAdapter, original, TheInterface) - self.assertIdentical( - components.getAdapterFactory(original, TheInterface, None), - secondAdapter) - finally: - components.ALLOW_DUPLICATES = False - - # It should be rejected again at this point - self.assertRaises( - ValueError, - components.registerAdapter, - firstAdapter, original, TheInterface) - - self.assertIdentical( - components.getAdapterFactory(original, TheInterface, None), - secondAdapter) - - - def test_duplicateAdapterForClassAllowed(self): - """ - Test that when L{components.ALLOW_DUPLICATES} is set to a true - value, duplicate registrations from classes are allowed to override - the original registration. - """ - class TheOriginal(object): - pass - return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal) - - - def test_duplicateAdapterForInterfaceAllowed(self): - """ - Test that when L{components.ALLOW_DUPLICATES} is set to a true - value, duplicate registrations from interfaces are allowed to - override the original registration. - """ - class TheOriginal(Interface): - pass - return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal) - - - def _multipleInterfacesForClassOrInterface(self, original): - """ - Verify that an adapter can be registered for multiple to-interfaces at a - time. - """ - adapter = lambda o: None - components.registerAdapter(adapter, original, ITest, ITest2) - self.assertIdentical( - components.getAdapterFactory(original, ITest, None), adapter) - self.assertIdentical( - components.getAdapterFactory(original, ITest2, None), adapter) - - - def test_multipleInterfacesForClass(self): - """ - Test the registration of an adapter from a class to several - interfaces at once. - """ - class TheOriginal(object): - pass - return self._multipleInterfacesForClassOrInterface(TheOriginal) - - - def test_multipleInterfacesForInterface(self): - """ - Test the registration of an adapter from an interface to several - interfaces at once. - """ - return self._multipleInterfacesForClassOrInterface(ITest3) - - - def _subclassAdapterRegistrationForClassOrInterface(self, original): - """ - Verify that a new adapter can be registered for a particular - to-interface from a subclass of a type or interface which already has an - adapter registered to that interface and that the subclass adapter takes - precedence over the base class adapter. - """ - firstAdapter = lambda o: True - secondAdapter = lambda o: False - class TheSubclass(original): - pass - components.registerAdapter(firstAdapter, original, ITest) - components.registerAdapter(secondAdapter, TheSubclass, ITest) - self.assertIdentical( - components.getAdapterFactory(original, ITest, None), - firstAdapter) - self.assertIdentical( - components.getAdapterFactory(TheSubclass, ITest, None), - secondAdapter) - - - def test_subclassAdapterRegistrationForClass(self): - """ - Test that an adapter to a particular interface can be registered - from both a class and its subclass. - """ - class TheOriginal(object): - pass - return self._subclassAdapterRegistrationForClassOrInterface(TheOriginal) - - - def test_subclassAdapterRegistrationForInterface(self): - """ - Test that an adapter to a particular interface can be registered - from both an interface and its subclass. - """ - return self._subclassAdapterRegistrationForClassOrInterface(ITest2) - - - -class IProxiedInterface(Interface): - """ - An interface class for use by L{proxyForInterface}. - """ - - ifaceAttribute = Attribute(""" - An example declared attribute, which should be proxied.""") - - def yay(*a, **kw): - """ - A sample method which should be proxied. - """ - -class IProxiedSubInterface(IProxiedInterface): - """ - An interface that derives from another for use with L{proxyForInterface}. - """ - - def boo(self): - """ - A different sample method which should be proxied. - """ - - -@implementer(IProxiedInterface) -class Yayable(object): - """ - A provider of L{IProxiedInterface} which increments a counter for - every call to C{yay}. - - @ivar yays: The number of times C{yay} has been called. - """ - - def __init__(self): - self.yays = 0 - self.yayArgs = [] - - def yay(self, *a, **kw): - """ - Increment C{self.yays}. - """ - self.yays += 1 - self.yayArgs.append((a, kw)) - return self.yays - - - -@implementer(IProxiedSubInterface) -class Booable(object): - """ - An implementation of IProxiedSubInterface - """ - yayed = False - booed = False - def yay(self): - """ - Mark the fact that 'yay' has been called. - """ - self.yayed = True - - - def boo(self): - """ - Mark the fact that 'boo' has been called.1 - """ - self.booed = True - - - -class IMultipleMethods(Interface): - """ - An interface with multiple methods. - """ - - def methodOne(): - """ - The first method. Should return 1. - """ - - def methodTwo(): - """ - The second method. Should return 2. - """ - - - -class MultipleMethodImplementor(object): - """ - A precise implementation of L{IMultipleMethods}. - """ - - def methodOne(self): - """ - @return: 1 - """ - return 1 - - - def methodTwo(self): - """ - @return: 2 - """ - return 2 - - - -class ProxyForInterfaceTests(unittest.SynchronousTestCase): - """ - Tests for L{proxyForInterface}. - """ - - def test_original(self): - """ - Proxy objects should have an C{original} attribute which refers to the - original object passed to the constructor. - """ - original = object() - proxy = proxyForInterface(IProxiedInterface)(original) - self.assertIdentical(proxy.original, original) - - - def test_proxyMethod(self): - """ - The class created from L{proxyForInterface} passes methods on an - interface to the object which is passed to its constructor. - """ - klass = proxyForInterface(IProxiedInterface) - yayable = Yayable() - proxy = klass(yayable) - proxy.yay() - self.assertEqual(proxy.yay(), 2) - self.assertEqual(yayable.yays, 2) - - - def test_decoratedProxyMethod(self): - """ - Methods of the class created from L{proxyForInterface} can be used with - the decorator-helper L{functools.wraps}. - """ - base = proxyForInterface(IProxiedInterface) - class klass(base): - @wraps(base.yay) - def yay(self): - self.original.yays += 1 - return base.yay(self) - - original = Yayable() - yayable = klass(original) - yayable.yay() - self.assertEqual(2, original.yays) - - - def test_proxyAttribute(self): - """ - Proxy objects should proxy declared attributes, but not other - attributes. - """ - yayable = Yayable() - yayable.ifaceAttribute = object() - proxy = proxyForInterface(IProxiedInterface)(yayable) - self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute) - self.assertRaises(AttributeError, lambda: proxy.yays) - - - def test_proxySetAttribute(self): - """ - The attributes that proxy objects proxy should be assignable and affect - the original object. - """ - yayable = Yayable() - proxy = proxyForInterface(IProxiedInterface)(yayable) - thingy = object() - proxy.ifaceAttribute = thingy - self.assertIdentical(yayable.ifaceAttribute, thingy) - - - def test_proxyDeleteAttribute(self): - """ - The attributes that proxy objects proxy should be deletable and affect - the original object. - """ - yayable = Yayable() - yayable.ifaceAttribute = None - proxy = proxyForInterface(IProxiedInterface)(yayable) - del proxy.ifaceAttribute - self.assertFalse(hasattr(yayable, 'ifaceAttribute')) - - - def test_multipleMethods(self): - """ - [Regression test] The proxy should send its method calls to the correct - method, not the incorrect one. - """ - multi = MultipleMethodImplementor() - proxy = proxyForInterface(IMultipleMethods)(multi) - self.assertEqual(proxy.methodOne(), 1) - self.assertEqual(proxy.methodTwo(), 2) - - - def test_subclassing(self): - """ - It is possible to subclass the result of L{proxyForInterface}. - """ - - class SpecializedProxy(proxyForInterface(IProxiedInterface)): - """ - A specialized proxy which can decrement the number of yays. - """ - def boo(self): - """ - Decrement the number of yays. - """ - self.original.yays -= 1 - - yayable = Yayable() - special = SpecializedProxy(yayable) - self.assertEqual(yayable.yays, 0) - special.boo() - self.assertEqual(yayable.yays, -1) - - - def test_proxyName(self): - """ - The name of a proxy class indicates which interface it proxies. - """ - proxy = proxyForInterface(IProxiedInterface) - self.assertEqual( - proxy.__name__, - "(Proxy for " - "twisted.python.test.test_components.IProxiedInterface)") - - - def test_implements(self): - """ - The resulting proxy implements the interface that it proxies. - """ - proxy = proxyForInterface(IProxiedInterface) - self.assertTrue(IProxiedInterface.implementedBy(proxy)) - - - def test_proxyDescriptorGet(self): - """ - _ProxyDescriptor's __get__ method should return the appropriate - attribute of its argument's 'original' attribute if it is invoked with - an object. If it is invoked with None, it should return a false - class-method emulator instead. - - For some reason, Python's documentation recommends to define - descriptors' __get__ methods with the 'type' parameter as optional, - despite the fact that Python itself never actually calls the descriptor - that way. This is probably do to support 'foo.__get__(bar)' as an - idiom. Let's make sure that the behavior is correct. Since we don't - actually use the 'type' argument at all, this test calls it the - idiomatic way to ensure that signature works; test_proxyInheritance - verifies the how-Python-actually-calls-it signature. - """ - class Sample: - called = False - def hello(self): - self.called = True - fakeProxy = Sample() - testObject = Sample() - fakeProxy.original = testObject - pd = components._ProxyDescriptor("hello", "original") - self.assertEqual(pd.__get__(fakeProxy), testObject.hello) - fakeClassMethod = pd.__get__(None) - fakeClassMethod(fakeProxy) - self.failUnless(testObject.called) - - - def test_proxyInheritance(self): - """ - Subclasses of the class returned from L{proxyForInterface} should be - able to upcall methods by reference to their superclass, as any normal - Python class can. - """ - class YayableWrapper(proxyForInterface(IProxiedInterface)): - """ - This class does not override any functionality. - """ - - class EnhancedWrapper(YayableWrapper): - """ - This class overrides the 'yay' method. - """ - wrappedYays = 1 - def yay(self, *a, **k): - self.wrappedYays += 1 - return YayableWrapper.yay(self, *a, **k) + 7 - - yayable = Yayable() - wrapper = EnhancedWrapper(yayable) - self.assertEqual(wrapper.yay(3, 4, x=5, y=6), 8) - self.assertEqual(yayable.yayArgs, - [((3, 4), dict(x=5, y=6))]) - - - def test_interfaceInheritance(self): - """ - Proxies of subinterfaces generated with proxyForInterface should allow - access to attributes of both the child and the base interfaces. - """ - proxyClass = proxyForInterface(IProxiedSubInterface) - booable = Booable() - proxy = proxyClass(booable) - proxy.yay() - proxy.boo() - self.failUnless(booable.yayed) - self.failUnless(booable.booed) - - - def test_attributeCustomization(self): - """ - The original attribute name can be customized via the - C{originalAttribute} argument of L{proxyForInterface}: the attribute - should change, but the methods of the original object should still be - callable, and the attributes still accessible. - """ - yayable = Yayable() - yayable.ifaceAttribute = object() - proxy = proxyForInterface( - IProxiedInterface, originalAttribute='foo')(yayable) - self.assertIdentical(proxy.foo, yayable) - - # Check the behavior - self.assertEqual(proxy.yay(), 1) - self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute) - thingy = object() - proxy.ifaceAttribute = thingy - self.assertIdentical(yayable.ifaceAttribute, thingy) - del proxy.ifaceAttribute - self.assertFalse(hasattr(yayable, 'ifaceAttribute')) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_constants.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_constants.py deleted file mode 100644 index ba44421..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_constants.py +++ /dev/null @@ -1,1128 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Unit tests for L{twisted.python.constants}. -""" - -from __future__ import division, absolute_import - -from twisted.trial.unittest import TestCase - -from twisted.python.constants import ( - NamedConstant, Names, ValueConstant, Values, FlagConstant, Flags -) - - - -class NamedConstantTests(TestCase): - """ - Tests for the L{twisted.python.constants.NamedConstant} class which is used - to represent individual values. - """ - def setUp(self): - """ - Create a dummy container into which constants can be placed. - """ - class foo(Names): - pass - self.container = foo - - - def test_name(self): - """ - The C{name} attribute of a L{NamedConstant} refers to the value passed - for the C{name} parameter to C{_realize}. - """ - name = NamedConstant() - name._realize(self.container, "bar", None) - self.assertEqual("bar", name.name) - - - def test_representation(self): - """ - The string representation of an instance of L{NamedConstant} includes - the container the instances belongs to as well as the instance's name. - """ - name = NamedConstant() - name._realize(self.container, "bar", None) - self.assertEqual("", repr(name)) - - - def test_equality(self): - """ - A L{NamedConstant} instance compares equal to itself. - """ - name = NamedConstant() - name._realize(self.container, "bar", None) - self.assertTrue(name == name) - self.assertFalse(name != name) - - - def test_nonequality(self): - """ - Two different L{NamedConstant} instances do not compare equal to each - other. - """ - first = NamedConstant() - first._realize(self.container, "bar", None) - second = NamedConstant() - second._realize(self.container, "bar", None) - self.assertFalse(first == second) - self.assertTrue(first != second) - - - def test_hash(self): - """ - Because two different L{NamedConstant} instances do not compare as - equal to each other, they also have different hashes to avoid - collisions when added to a C{dict} or C{set}. - """ - first = NamedConstant() - first._realize(self.container, "bar", None) - second = NamedConstant() - second._realize(self.container, "bar", None) - self.assertNotEqual(hash(first), hash(second)) - - - -class _ConstantsTestsMixin(object): - """ - Mixin defining test helpers common to multiple types of constants - collections. - """ - def _notInstantiableTest(self, name, cls): - """ - Assert that an attempt to instantiate the constants class raises - C{TypeError}. - - @param name: A C{str} giving the name of the constants collection. - @param cls: The constants class to test. - """ - exc = self.assertRaises(TypeError, cls) - self.assertEqual(name + " may not be instantiated.", str(exc)) - - - def _initializedOnceTest(self, container, constantName): - """ - Assert that C{container._enumerants} does not change as a side-effect - of one of its attributes being accessed. - - @param container: A L{_ConstantsContainer} subclass which will be - tested. - @param constantName: The name of one of the constants which is an - attribute of C{container}. - """ - first = container._enumerants - - # Accessing an attribute of the container should not have any - # observable side-effect on the _enumerants attribute. - getattr(container, constantName) - - second = container._enumerants - self.assertIdentical(first, second) - - - -class NamesTests(TestCase, _ConstantsTestsMixin): - """ - Tests for L{twisted.python.constants.Names}, a base class for containers of - related constraints. - """ - def setUp(self): - """ - Create a fresh new L{Names} subclass for each unit test to use. Since - L{Names} is stateful, re-using the same subclass across test methods - makes exercising all of the implementation code paths difficult. - """ - class METHOD(Names): - """ - A container for some named constants to use in unit tests for - L{Names}. - """ - GET = NamedConstant() - PUT = NamedConstant() - POST = NamedConstant() - DELETE = NamedConstant() - - extra = object() - - self.METHOD = METHOD - - - def test_notInstantiable(self): - """ - A subclass of L{Names} raises C{TypeError} if an attempt is made to - instantiate it. - """ - self._notInstantiableTest("METHOD", self.METHOD) - - - def test_symbolicAttributes(self): - """ - Each name associated with a L{NamedConstant} instance in the definition - of a L{Names} subclass is available as an attribute on the resulting - class. - """ - self.assertTrue(hasattr(self.METHOD, "GET")) - self.assertTrue(hasattr(self.METHOD, "PUT")) - self.assertTrue(hasattr(self.METHOD, "POST")) - self.assertTrue(hasattr(self.METHOD, "DELETE")) - - - def test_withoutOtherAttributes(self): - """ - As usual, names not defined in the class scope of a L{Names} - subclass are not available as attributes on the resulting class. - """ - self.assertFalse(hasattr(self.METHOD, "foo")) - - - def test_representation(self): - """ - The string representation of a constant on a L{Names} subclass includes - the name of the L{Names} subclass and the name of the constant itself. - """ - self.assertEqual("", repr(self.METHOD.GET)) - - - def test_lookupByName(self): - """ - Constants can be looked up by name using L{Names.lookupByName}. - """ - method = self.METHOD.lookupByName("GET") - self.assertIdentical(self.METHOD.GET, method) - - - def test_notLookupMissingByName(self): - """ - Names not defined with a L{NamedConstant} instance cannot be looked up - using L{Names.lookupByName}. - """ - self.assertRaises(ValueError, self.METHOD.lookupByName, "lookupByName") - self.assertRaises(ValueError, self.METHOD.lookupByName, "__init__") - self.assertRaises(ValueError, self.METHOD.lookupByName, "foo") - self.assertRaises(ValueError, self.METHOD.lookupByName, "extra") - - - def test_name(self): - """ - The C{name} attribute of one of the named constants gives that - constant's name. - """ - self.assertEqual("GET", self.METHOD.GET.name) - - - def test_attributeIdentity(self): - """ - Repeated access of an attribute associated with a L{NamedConstant} - value in a L{Names} subclass results in the same object. - """ - self.assertIdentical(self.METHOD.GET, self.METHOD.GET) - - - def test_iterconstants(self): - """ - L{Names.iterconstants} returns an iterator over all of the constants - defined in the class, in the order they were defined. - """ - constants = list(self.METHOD.iterconstants()) - self.assertEqual( - [self.METHOD.GET, self.METHOD.PUT, - self.METHOD.POST, self.METHOD.DELETE], - constants) - - - def test_attributeIterconstantsIdentity(self): - """ - The constants returned from L{Names.iterconstants} are identical to the - constants accessible using attributes. - """ - constants = list(self.METHOD.iterconstants()) - self.assertIdentical(self.METHOD.GET, constants[0]) - self.assertIdentical(self.METHOD.PUT, constants[1]) - self.assertIdentical(self.METHOD.POST, constants[2]) - self.assertIdentical(self.METHOD.DELETE, constants[3]) - - - def test_iterconstantsIdentity(self): - """ - The constants returned from L{Names.iterconstants} are identical on - each call to that method. - """ - constants = list(self.METHOD.iterconstants()) - again = list(self.METHOD.iterconstants()) - self.assertIdentical(again[0], constants[0]) - self.assertIdentical(again[1], constants[1]) - self.assertIdentical(again[2], constants[2]) - self.assertIdentical(again[3], constants[3]) - - - def test_initializedOnce(self): - """ - L{Names._enumerants} is initialized once and its value re-used on - subsequent access. - """ - self._initializedOnceTest(self.METHOD, "GET") - - - def test_asForeignClassAttribute(self): - """ - A constant defined on a L{Names} subclass may be set as an attribute of - another class and then retrieved using that attribute. - """ - class Another(object): - something = self.METHOD.GET - - self.assertIdentical(self.METHOD.GET, Another.something) - - - def test_asForeignClassAttributeViaInstance(self): - """ - A constant defined on a L{Names} subclass may be set as an attribute of - another class and then retrieved from an instance of that class using - that attribute. - """ - class Another(object): - something = self.METHOD.GET - - self.assertIdentical(self.METHOD.GET, Another().something) - - - def test_notAsAlternateContainerAttribute(self): - """ - It is explicitly disallowed (via a L{ValueError}) to use a constant - defined on a L{Names} subclass as the value of an attribute of another - L{Names} subclass. - """ - def defineIt(): - class AnotherNames(Names): - something = self.METHOD.GET - - exc = self.assertRaises(ValueError, defineIt) - self.assertEqual( - "Cannot use as the value of an attribute on " - "AnotherNames", - str(exc)) - - - -class ValuesTests(TestCase, _ConstantsTestsMixin): - """ - Tests for L{twisted.python.constants.Names}, a base class for containers of - related constraints with arbitrary values. - """ - def setUp(self): - """ - Create a fresh new L{Values} subclass for each unit test to use. Since - L{Values} is stateful, re-using the same subclass across test methods - makes exercising all of the implementation code paths difficult. - """ - class STATUS(Values): - OK = ValueConstant("200") - NOT_FOUND = ValueConstant("404") - - self.STATUS = STATUS - - - def test_notInstantiable(self): - """ - A subclass of L{Values} raises C{TypeError} if an attempt is made to - instantiate it. - """ - self._notInstantiableTest("STATUS", self.STATUS) - - - def test_symbolicAttributes(self): - """ - Each name associated with a L{ValueConstant} instance in the definition - of a L{Values} subclass is available as an attribute on the resulting - class. - """ - self.assertTrue(hasattr(self.STATUS, "OK")) - self.assertTrue(hasattr(self.STATUS, "NOT_FOUND")) - - - def test_withoutOtherAttributes(self): - """ - As usual, names not defined in the class scope of a L{Values} - subclass are not available as attributes on the resulting class. - """ - self.assertFalse(hasattr(self.STATUS, "foo")) - - - def test_representation(self): - """ - The string representation of a constant on a L{Values} subclass - includes the name of the L{Values} subclass and the name of the - constant itself. - """ - self.assertEqual("", repr(self.STATUS.OK)) - - - def test_lookupByName(self): - """ - Constants can be looked up by name using L{Values.lookupByName}. - """ - method = self.STATUS.lookupByName("OK") - self.assertIdentical(self.STATUS.OK, method) - - - def test_notLookupMissingByName(self): - """ - Names not defined with a L{ValueConstant} instance cannot be looked up - using L{Values.lookupByName}. - """ - self.assertRaises(ValueError, self.STATUS.lookupByName, "lookupByName") - self.assertRaises(ValueError, self.STATUS.lookupByName, "__init__") - self.assertRaises(ValueError, self.STATUS.lookupByName, "foo") - - - def test_lookupByValue(self): - """ - Constants can be looked up by their associated value, defined by the - argument passed to L{ValueConstant}, using L{Values.lookupByValue}. - """ - status = self.STATUS.lookupByValue("200") - self.assertIdentical(self.STATUS.OK, status) - - - def test_lookupDuplicateByValue(self): - """ - If more than one constant is associated with a particular value, - L{Values.lookupByValue} returns whichever of them is defined first. - """ - class TRANSPORT_MESSAGE(Values): - """ - Message types supported by an SSH transport. - """ - KEX_DH_GEX_REQUEST_OLD = ValueConstant(30) - KEXDH_INIT = ValueConstant(30) - - self.assertIdentical( - TRANSPORT_MESSAGE.lookupByValue(30), - TRANSPORT_MESSAGE.KEX_DH_GEX_REQUEST_OLD) - - - def test_notLookupMissingByValue(self): - """ - L{Values.lookupByValue} raises L{ValueError} when called with a value - with which no constant is associated. - """ - self.assertRaises(ValueError, self.STATUS.lookupByValue, "OK") - self.assertRaises(ValueError, self.STATUS.lookupByValue, 200) - self.assertRaises(ValueError, self.STATUS.lookupByValue, "200.1") - - - def test_name(self): - """ - The C{name} attribute of one of the constants gives that constant's - name. - """ - self.assertEqual("OK", self.STATUS.OK.name) - - - def test_attributeIdentity(self): - """ - Repeated access of an attribute associated with a L{ValueConstant} - value in a L{Values} subclass results in the same object. - """ - self.assertIdentical(self.STATUS.OK, self.STATUS.OK) - - - def test_iterconstants(self): - """ - L{Values.iterconstants} returns an iterator over all of the constants - defined in the class, in the order they were defined. - """ - constants = list(self.STATUS.iterconstants()) - self.assertEqual( - [self.STATUS.OK, self.STATUS.NOT_FOUND], - constants) - - - def test_attributeIterconstantsIdentity(self): - """ - The constants returned from L{Values.iterconstants} are identical to - the constants accessible using attributes. - """ - constants = list(self.STATUS.iterconstants()) - self.assertIdentical(self.STATUS.OK, constants[0]) - self.assertIdentical(self.STATUS.NOT_FOUND, constants[1]) - - - def test_iterconstantsIdentity(self): - """ - The constants returned from L{Values.iterconstants} are identical on - each call to that method. - """ - constants = list(self.STATUS.iterconstants()) - again = list(self.STATUS.iterconstants()) - self.assertIdentical(again[0], constants[0]) - self.assertIdentical(again[1], constants[1]) - - - def test_initializedOnce(self): - """ - L{Values._enumerants} is initialized once and its value re-used on - subsequent access. - """ - self._initializedOnceTest(self.STATUS, "OK") - - - -class _FlagsTestsMixin(object): - """ - Mixin defining setup code for any tests for L{Flags} subclasses. - - @ivar FXF: A L{Flags} subclass created for each test method. - """ - def setUp(self): - """ - Create a fresh new L{Flags} subclass for each unit test to use. Since - L{Flags} is stateful, re-using the same subclass across test methods - makes exercising all of the implementation code paths difficult. - """ - class FXF(Flags): - # Implicitly assign three flag values based on definition order - READ = FlagConstant() - WRITE = FlagConstant() - APPEND = FlagConstant() - - # Explicitly assign one flag value by passing it in - EXCLUSIVE = FlagConstant(0x20) - - # Implicitly assign another flag value, following the previously - # specified explicit value. - TEXT = FlagConstant() - - self.FXF = FXF - - - -class FlagsTests(_FlagsTestsMixin, TestCase, _ConstantsTestsMixin): - """ - Tests for L{twisted.python.constants.Flags}, a base class for containers of - related, combinable flag or bitvector-like constants. - """ - def test_notInstantiable(self): - """ - A subclass of L{Flags} raises L{TypeError} if an attempt is made to - instantiate it. - """ - self._notInstantiableTest("FXF", self.FXF) - - - def test_symbolicAttributes(self): - """ - Each name associated with a L{FlagConstant} instance in the definition - of a L{Flags} subclass is available as an attribute on the resulting - class. - """ - self.assertTrue(hasattr(self.FXF, "READ")) - self.assertTrue(hasattr(self.FXF, "WRITE")) - self.assertTrue(hasattr(self.FXF, "APPEND")) - self.assertTrue(hasattr(self.FXF, "EXCLUSIVE")) - self.assertTrue(hasattr(self.FXF, "TEXT")) - - - def test_withoutOtherAttributes(self): - """ - As usual, names not defined in the class scope of a L{Flags} subclass - are not available as attributes on the resulting class. - """ - self.assertFalse(hasattr(self.FXF, "foo")) - - - def test_representation(self): - """ - The string representation of a constant on a L{Flags} subclass includes - the name of the L{Flags} subclass and the name of the constant itself. - """ - self.assertEqual("", repr(self.FXF.READ)) - - - def test_lookupByName(self): - """ - Constants can be looked up by name using L{Flags.lookupByName}. - """ - flag = self.FXF.lookupByName("READ") - self.assertIdentical(self.FXF.READ, flag) - - - def test_notLookupMissingByName(self): - """ - Names not defined with a L{FlagConstant} instance cannot be looked up - using L{Flags.lookupByName}. - """ - self.assertRaises(ValueError, self.FXF.lookupByName, "lookupByName") - self.assertRaises(ValueError, self.FXF.lookupByName, "__init__") - self.assertRaises(ValueError, self.FXF.lookupByName, "foo") - - - def test_lookupByValue(self): - """ - Constants can be looked up by their associated value, defined - implicitly by the position in which the constant appears in the class - definition or explicitly by the argument passed to L{FlagConstant}. - """ - flag = self.FXF.lookupByValue(0x01) - self.assertIdentical(flag, self.FXF.READ) - - flag = self.FXF.lookupByValue(0x02) - self.assertIdentical(flag, self.FXF.WRITE) - - flag = self.FXF.lookupByValue(0x04) - self.assertIdentical(flag, self.FXF.APPEND) - - flag = self.FXF.lookupByValue(0x20) - self.assertIdentical(flag, self.FXF.EXCLUSIVE) - - flag = self.FXF.lookupByValue(0x40) - self.assertIdentical(flag, self.FXF.TEXT) - - - def test_lookupDuplicateByValue(self): - """ - If more than one constant is associated with a particular value, - L{Flags.lookupByValue} returns whichever of them is defined first. - """ - class TIMEX(Flags): - # (timex.mode) - ADJ_OFFSET = FlagConstant(0x0001) # time offset - - # xntp 3.4 compatibility names - MOD_OFFSET = FlagConstant(0x0001) - - self.assertIdentical(TIMEX.lookupByValue(0x0001), TIMEX.ADJ_OFFSET) - - - def test_notLookupMissingByValue(self): - """ - L{Flags.lookupByValue} raises L{ValueError} when called with a value - with which no constant is associated. - """ - self.assertRaises(ValueError, self.FXF.lookupByValue, 0x10) - - - def test_name(self): - """ - The C{name} attribute of one of the constants gives that constant's - name. - """ - self.assertEqual("READ", self.FXF.READ.name) - - - def test_attributeIdentity(self): - """ - Repeated access of an attribute associated with a L{FlagConstant} value - in a L{Flags} subclass results in the same object. - """ - self.assertIdentical(self.FXF.READ, self.FXF.READ) - - - def test_iterconstants(self): - """ - L{Flags.iterconstants} returns an iterator over all of the constants - defined in the class, in the order they were defined. - """ - constants = list(self.FXF.iterconstants()) - self.assertEqual( - [self.FXF.READ, self.FXF.WRITE, self.FXF.APPEND, - self.FXF.EXCLUSIVE, self.FXF.TEXT], - constants) - - - def test_attributeIterconstantsIdentity(self): - """ - The constants returned from L{Flags.iterconstants} are identical to the - constants accessible using attributes. - """ - constants = list(self.FXF.iterconstants()) - self.assertIdentical(self.FXF.READ, constants[0]) - self.assertIdentical(self.FXF.WRITE, constants[1]) - self.assertIdentical(self.FXF.APPEND, constants[2]) - self.assertIdentical(self.FXF.EXCLUSIVE, constants[3]) - self.assertIdentical(self.FXF.TEXT, constants[4]) - - - def test_iterconstantsIdentity(self): - """ - The constants returned from L{Flags.iterconstants} are identical on - each call to that method. - """ - constants = list(self.FXF.iterconstants()) - again = list(self.FXF.iterconstants()) - self.assertIdentical(again[0], constants[0]) - self.assertIdentical(again[1], constants[1]) - self.assertIdentical(again[2], constants[2]) - self.assertIdentical(again[3], constants[3]) - self.assertIdentical(again[4], constants[4]) - - - def test_initializedOnce(self): - """ - L{Flags._enumerants} is initialized once and its value re-used on - subsequent access. - """ - self._initializedOnceTest(self.FXF, "READ") - - - -class FlagConstantSimpleOrTests(_FlagsTestsMixin, TestCase): - """ - Tests for the C{|} operator as defined for L{FlagConstant} instances, used - to create new L{FlagConstant} instances representing both of two existing - L{FlagConstant} instances from the same L{Flags} class. - """ - def test_value(self): - """ - The value of the L{FlagConstant} which results from C{|} has all of the - bits set which were set in either of the values of the two original - constants. - """ - flag = self.FXF.READ | self.FXF.WRITE - self.assertEqual( - self.FXF.READ.value | self.FXF.WRITE.value, flag.value - ) - - - def test_name(self): - """ - The name of the L{FlagConstant} instance which results from C{|} - includes the names of both of the two original constants. - """ - flag = self.FXF.READ | self.FXF.WRITE - self.assertEqual("{READ,WRITE}", flag.name) - - - def test_representation(self): - """ - The string representation of a L{FlagConstant} instance which results - from C{|} includes the names of both of the two original constants. - """ - flag = self.FXF.READ | self.FXF.WRITE - self.assertEqual("", repr(flag)) - - - def test_iterate(self): - """ - A L{FlagConstant} instance which results from C{|} can be - iterated upon to yield the original constants. - """ - self.assertEqual( - set(self.FXF.WRITE & self.FXF.READ), # No flags - set(())) - self.assertEqual( - set(self.FXF.WRITE), - set((self.FXF.WRITE,))) - self.assertEqual( - set(self.FXF.WRITE | self.FXF.EXCLUSIVE), - set((self.FXF.WRITE, self.FXF.EXCLUSIVE))) - - - def test_membership(self): - """ - A L{FlagConstant} instance which results from C{|} can be - tested for membership. - """ - flags = self.FXF.WRITE | self.FXF.EXCLUSIVE - self.assertIn(self.FXF.WRITE, flags) - self.assertNotIn(self.FXF.READ, flags) - - - def test_truthiness(self): - """ - Empty flags is false, non-empty flags is true. - """ - self.assertTrue(self.FXF.WRITE) - self.assertTrue(self.FXF.WRITE | self.FXF.EXCLUSIVE) - self.assertFalse(self.FXF.WRITE & self.FXF.EXCLUSIVE) - - - -class FlagConstantSimpleAndTests(_FlagsTestsMixin, TestCase): - """ - Tests for the C{&} operator as defined for L{FlagConstant} instances, used - to create new L{FlagConstant} instances representing the common parts of - two existing L{FlagConstant} instances from the same L{Flags} class. - """ - def test_value(self): - """ - The value of the L{FlagConstant} which results from C{&} has all of the - bits set which were set in both of the values of the two original - constants. - """ - readWrite = (self.FXF.READ | self.FXF.WRITE) - writeAppend = (self.FXF.WRITE | self.FXF.APPEND) - flag = readWrite & writeAppend - self.assertEqual(self.FXF.WRITE.value, flag.value) - - - def test_name(self): - """ - The name of the L{FlagConstant} instance which results from C{&} - includes the names of only the flags which were set in both of the two - original constants. - """ - readWrite = (self.FXF.READ | self.FXF.WRITE) - writeAppend = (self.FXF.WRITE | self.FXF.APPEND) - flag = readWrite & writeAppend - self.assertEqual("WRITE", flag.name) - - - def test_representation(self): - """ - The string representation of a L{FlagConstant} instance which results - from C{&} includes the names of only the flags which were set in both - both of the two original constants. - """ - readWrite = (self.FXF.READ | self.FXF.WRITE) - writeAppend = (self.FXF.WRITE | self.FXF.APPEND) - flag = readWrite & writeAppend - self.assertEqual("", repr(flag)) - - - -class FlagConstantSimpleExclusiveOrTests(_FlagsTestsMixin, TestCase): - """ - Tests for the C{^} operator as defined for L{FlagConstant} instances, used - to create new L{FlagConstant} instances representing the uncommon parts of - two existing L{FlagConstant} instances from the same L{Flags} class. - """ - def test_value(self): - """ - The value of the L{FlagConstant} which results from C{^} has all of the - bits set which were set in exactly one of the values of the two - original constants. - """ - readWrite = (self.FXF.READ | self.FXF.WRITE) - writeAppend = (self.FXF.WRITE | self.FXF.APPEND) - flag = readWrite ^ writeAppend - self.assertEqual( - self.FXF.READ.value | self.FXF.APPEND.value, flag.value - ) - - - def test_name(self): - """ - The name of the L{FlagConstant} instance which results from C{^} - includes the names of only the flags which were set in exactly one of - the two original constants. - """ - readWrite = (self.FXF.READ | self.FXF.WRITE) - writeAppend = (self.FXF.WRITE | self.FXF.APPEND) - flag = readWrite ^ writeAppend - self.assertEqual("{APPEND,READ}", flag.name) - - - def test_representation(self): - """ - The string representation of a L{FlagConstant} instance which results - from C{^} includes the names of only the flags which were set in - exactly one of the two original constants. - """ - readWrite = (self.FXF.READ | self.FXF.WRITE) - writeAppend = (self.FXF.WRITE | self.FXF.APPEND) - flag = readWrite ^ writeAppend - self.assertEqual("", repr(flag)) - - - -class FlagConstantNegationTests(_FlagsTestsMixin, TestCase): - """ - Tests for the C{~} operator as defined for L{FlagConstant} instances, used - to create new L{FlagConstant} instances representing all the flags from a - L{Flags} class not set in a particular L{FlagConstant} instance. - """ - def test_value(self): - """ - The value of the L{FlagConstant} which results from C{~} has all of the - bits set which were not set in the original constant. - """ - flag = ~self.FXF.READ - self.assertEqual( - self.FXF.WRITE.value | - self.FXF.APPEND.value | - self.FXF.EXCLUSIVE.value | - self.FXF.TEXT.value, - flag.value) - - flag = ~self.FXF.WRITE - self.assertEqual( - self.FXF.READ.value | - self.FXF.APPEND.value | - self.FXF.EXCLUSIVE.value | - self.FXF.TEXT.value, - flag.value) - - - def test_name(self): - """ - The name of the L{FlagConstant} instance which results from C{~} - includes the names of all the flags which were not set in the original - constant. - """ - flag = ~self.FXF.WRITE - self.assertEqual("{APPEND,EXCLUSIVE,READ,TEXT}", flag.name) - - - def test_representation(self): - """ - The string representation of a L{FlagConstant} instance which results - from C{~} includes the names of all the flags which were not set in the - original constant. - """ - flag = ~self.FXF.WRITE - self.assertEqual("", repr(flag)) - - - -class OrderedConstantsTests(TestCase): - """ - Tests for the ordering of constants. All constants are ordered by - the order in which they are defined in their container class. - The ordering of constants that are not in the same container is not - defined. - """ - def test_orderedNameConstants_lt(self): - """ - L{twisted.python.constants.NamedConstant} preserves definition - order in C{<} comparisons. - """ - self.assertTrue(NamedLetters.alpha < NamedLetters.beta) - - - def test_orderedNameConstants_le(self): - """ - L{twisted.python.constants.NamedConstant} preserves definition - order in C{<=} comparisons. - """ - self.assertTrue(NamedLetters.alpha <= NamedLetters.alpha) - self.assertTrue(NamedLetters.alpha <= NamedLetters.beta) - - - def test_orderedNameConstants_gt(self): - """ - L{twisted.python.constants.NamedConstant} preserves definition - order in C{>} comparisons. - """ - self.assertTrue(NamedLetters.beta > NamedLetters.alpha) - - - def test_orderedNameConstants_ge(self): - """ - L{twisted.python.constants.NamedConstant} preserves definition - order in C{>=} comparisons. - """ - self.assertTrue(NamedLetters.alpha >= NamedLetters.alpha) - self.assertTrue(NamedLetters.beta >= NamedLetters.alpha) - - - def test_orderedValueConstants_lt(self): - """ - L{twisted.python.constants.ValueConstant} preserves definition - order in C{<} comparisons. - """ - self.assertTrue(ValuedLetters.alpha < ValuedLetters.digamma) - self.assertTrue(ValuedLetters.digamma < ValuedLetters.zeta) - - - def test_orderedValueConstants_le(self): - """ - L{twisted.python.constants.ValueConstant} preserves definition - order in C{<=} comparisons. - """ - self.assertTrue(ValuedLetters.alpha <= ValuedLetters.alpha) - self.assertTrue(ValuedLetters.alpha <= ValuedLetters.digamma) - self.assertTrue(ValuedLetters.digamma <= ValuedLetters.zeta) - - - def test_orderedValueConstants_gt(self): - """ - L{twisted.python.constants.ValueConstant} preserves definition - order in C{>} comparisons. - """ - self.assertTrue(ValuedLetters.digamma > ValuedLetters.alpha) - self.assertTrue(ValuedLetters.zeta > ValuedLetters.digamma) - - - def test_orderedValueConstants_ge(self): - """ - L{twisted.python.constants.ValueConstant} preserves definition - order in C{>=} comparisons. - """ - self.assertTrue(ValuedLetters.alpha >= ValuedLetters.alpha) - self.assertTrue(ValuedLetters.digamma >= ValuedLetters.alpha) - self.assertTrue(ValuedLetters.zeta >= ValuedLetters.digamma) - - - def test_orderedFlagConstants_lt(self): - """ - L{twisted.python.constants.FlagConstant} preserves definition - order in C{<} comparisons. - """ - self.assertTrue(PizzaToppings.mozzarella < PizzaToppings.pesto) - self.assertTrue(PizzaToppings.pesto < PizzaToppings.pepperoni) - - - def test_orderedFlagConstants_le(self): - """ - L{twisted.python.constants.FlagConstant} preserves definition - order in C{<=} comparisons. - """ - self.assertTrue(PizzaToppings.mozzarella <= PizzaToppings.mozzarella) - self.assertTrue(PizzaToppings.mozzarella <= PizzaToppings.pesto) - self.assertTrue(PizzaToppings.pesto <= PizzaToppings.pepperoni) - - - def test_orderedFlagConstants_gt(self): - """ - L{twisted.python.constants.FlagConstant} preserves definition - order in C{>} comparisons. - """ - self.assertTrue(PizzaToppings.pesto > PizzaToppings.mozzarella) - self.assertTrue(PizzaToppings.pepperoni > PizzaToppings.pesto) - - - def test_orderedFlagConstants_ge(self): - """ - L{twisted.python.constants.FlagConstant} preserves definition - order in C{>=} comparisons. - """ - self.assertTrue(PizzaToppings.mozzarella >= PizzaToppings.mozzarella) - self.assertTrue(PizzaToppings.pesto >= PizzaToppings.mozzarella) - self.assertTrue(PizzaToppings.pepperoni >= PizzaToppings.pesto) - - - def test_orderedDifferentConstants_lt(self): - """ - L{twisted.python.constants._Constant.__lt__} returns C{NotImplemented} - when comparing constants of different types. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__lt__(ValuedLetters.alpha) - ) - - - def test_orderedDifferentConstants_le(self): - """ - L{twisted.python.constants._Constant.__le__} returns C{NotImplemented} - when comparing constants of different types. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__le__(ValuedLetters.alpha) - ) - - - def test_orderedDifferentConstants_gt(self): - """ - L{twisted.python.constants._Constant.__gt__} returns C{NotImplemented} - when comparing constants of different types. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__gt__(ValuedLetters.alpha) - ) - - - def test_orderedDifferentConstants_ge(self): - """ - L{twisted.python.constants._Constant.__ge__} returns C{NotImplemented} - when comparing constants of different types. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__ge__(ValuedLetters.alpha) - ) - - - def test_orderedDifferentContainers_lt(self): - """ - L{twisted.python.constants._Constant.__lt__} returns C{NotImplemented} - when comparing constants belonging to different containers. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__lt__(MoreNamedLetters.digamma) - ) - - - def test_orderedDifferentContainers_le(self): - """ - L{twisted.python.constants._Constant.__le__} returns C{NotImplemented} - when comparing constants belonging to different containers. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__le__(MoreNamedLetters.digamma) - ) - - - def test_orderedDifferentContainers_gt(self): - """ - L{twisted.python.constants._Constant.__gt__} returns C{NotImplemented} - when comparing constants belonging to different containers. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__gt__(MoreNamedLetters.digamma) - ) - - - def test_orderedDifferentContainers_ge(self): - """ - L{twisted.python.constants._Constant.__ge__} returns C{NotImplemented} - when comparing constants belonging to different containers. - """ - self.assertEquals( - NotImplemented, - NamedLetters.alpha.__ge__(MoreNamedLetters.digamma) - ) - - - -class NamedLetters(Names): - """ - Some letters, named. - """ - alpha = NamedConstant() - beta = NamedConstant() - - - -class MoreNamedLetters(Names): - """ - Some more letters, named. - """ - digamma = NamedConstant() - zeta = NamedConstant() - - - -class ValuedLetters(Values): - """ - Some more letters, with cooresponding unicode values. - """ - # Note u'\u0391' < u'\u03dc' > u'\u0396'. We are ensuring here that the - # definition is order different from the order of the values, which lets us - # test that we're not somehow ordering by value and happen the get the same - # results. - alpha = ValueConstant(u'\u0391') - digamma = ValueConstant(u'\u03dc') - zeta = ValueConstant(u'\u0396') - - - -class PizzaToppings(Flags): - """ - Some pizza toppings, with obviously meaningful bitwise values. - """ - # Note 1<<1 < 1<<4 > 1<<2, so we are ensuring here that the definition - # order is different from the order of the values, which lets us test that - # we're not somehow ordering by value and happen the get the same results. - mozzarella = FlagConstant(1 << 1) - pesto = FlagConstant(1 << 4) - pepperoni = FlagConstant(1 << 2) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_deprecate.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_deprecate.py deleted file mode 100644 index dd07b95..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_deprecate.py +++ /dev/null @@ -1,917 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for Twisted's deprecation framework, L{twisted.python.deprecate}. -""" - -from __future__ import division, absolute_import - -import sys, types, warnings, inspect -from os.path import normcase -from warnings import simplefilter, catch_warnings -try: - from importlib import invalidate_caches -except ImportError: - invalidate_caches = None - -from twisted.python import deprecate -from twisted.python.deprecate import _getDeprecationWarningString -from twisted.python.deprecate import DEPRECATION_WARNING_FORMAT -from twisted.python.deprecate import ( - getDeprecationWarningString, - deprecated, _appendToDocstring, _getDeprecationDocstring, - _fullyQualifiedName as fullyQualifiedName, - _passed, _mutuallyExclusiveArguments -) - -from twisted.python.versions import Version -from twisted.python.filepath import FilePath - -from twisted.python.test import deprecatedattributes -from twisted.python.test.modules_helpers import TwistedModulesMixin - -from twisted.trial.unittest import SynchronousTestCase - -# Note that various tests in this module require manual encoding of paths to -# utf-8. This can be fixed once FilePath supports Unicode; see #2366, #4736, -# #5203. - - -class _MockDeprecatedAttribute(object): - """ - Mock of L{twisted.python.deprecate._DeprecatedAttribute}. - - @ivar value: The value of the attribute. - """ - def __init__(self, value): - self.value = value - - - def get(self): - """ - Get a known value. - """ - return self.value - - - -class ModuleProxyTests(SynchronousTestCase): - """ - Tests for L{twisted.python.deprecate._ModuleProxy}, which proxies - access to module-level attributes, intercepting access to deprecated - attributes and passing through access to normal attributes. - """ - def _makeProxy(self, **attrs): - """ - Create a temporary module proxy object. - - @param **kw: Attributes to initialise on the temporary module object - - @rtype: L{twistd.python.deprecate._ModuleProxy} - """ - mod = types.ModuleType('foo') - for key, value in attrs.items(): - setattr(mod, key, value) - return deprecate._ModuleProxy(mod) - - - def test_getattrPassthrough(self): - """ - Getting a normal attribute on a L{twisted.python.deprecate._ModuleProxy} - retrieves the underlying attribute's value, and raises C{AttributeError} - if a non-existent attribute is accessed. - """ - proxy = self._makeProxy(SOME_ATTRIBUTE='hello') - self.assertIdentical(proxy.SOME_ATTRIBUTE, 'hello') - self.assertRaises(AttributeError, getattr, proxy, 'DOES_NOT_EXIST') - - - def test_getattrIntercept(self): - """ - Getting an attribute marked as being deprecated on - L{twisted.python.deprecate._ModuleProxy} results in calling the - deprecated wrapper's C{get} method. - """ - proxy = self._makeProxy() - _deprecatedAttributes = object.__getattribute__( - proxy, '_deprecatedAttributes') - _deprecatedAttributes['foo'] = _MockDeprecatedAttribute(42) - self.assertEqual(proxy.foo, 42) - - - def test_privateAttributes(self): - """ - Private attributes of L{twisted.python.deprecate._ModuleProxy} are - inaccessible when regular attribute access is used. - """ - proxy = self._makeProxy() - self.assertRaises(AttributeError, getattr, proxy, '_module') - self.assertRaises( - AttributeError, getattr, proxy, '_deprecatedAttributes') - - - def test_setattr(self): - """ - Setting attributes on L{twisted.python.deprecate._ModuleProxy} proxies - them through to the wrapped module. - """ - proxy = self._makeProxy() - proxy._module = 1 - self.assertNotEquals(object.__getattribute__(proxy, '_module'), 1) - self.assertEqual(proxy._module, 1) - - - def test_repr(self): - """ - L{twisted.python.deprecated._ModuleProxy.__repr__} produces a string - containing the proxy type and a representation of the wrapped module - object. - """ - proxy = self._makeProxy() - realModule = object.__getattribute__(proxy, '_module') - self.assertEqual( - repr(proxy), '<%s module=%r>' % (type(proxy).__name__, realModule)) - - - -class DeprecatedAttributeTests(SynchronousTestCase): - """ - Tests for L{twisted.python.deprecate._DeprecatedAttribute} and - L{twisted.python.deprecate.deprecatedModuleAttribute}, which issue - warnings for deprecated module-level attributes. - """ - def setUp(self): - self.version = deprecatedattributes.version - self.message = deprecatedattributes.message - self._testModuleName = __name__ + '.foo' - - - def _getWarningString(self, attr): - """ - Create the warning string used by deprecated attributes. - """ - return _getDeprecationWarningString( - deprecatedattributes.__name__ + '.' + attr, - deprecatedattributes.version, - DEPRECATION_WARNING_FORMAT + ': ' + deprecatedattributes.message) - - - def test_deprecatedAttributeHelper(self): - """ - L{twisted.python.deprecate._DeprecatedAttribute} correctly sets its - __name__ to match that of the deprecated attribute and emits a warning - when the original attribute value is accessed. - """ - name = 'ANOTHER_DEPRECATED_ATTRIBUTE' - setattr(deprecatedattributes, name, 42) - attr = deprecate._DeprecatedAttribute( - deprecatedattributes, name, self.version, self.message) - - self.assertEqual(attr.__name__, name) - - # Since we're accessing the value getter directly, as opposed to via - # the module proxy, we need to match the warning's stack level. - def addStackLevel(): - attr.get() - - # Access the deprecated attribute. - addStackLevel() - warningsShown = self.flushWarnings([ - self.test_deprecatedAttributeHelper]) - self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEqual( - warningsShown[0]['message'], - self._getWarningString(name)) - self.assertEqual(len(warningsShown), 1) - - - def test_deprecatedAttribute(self): - """ - L{twisted.python.deprecate.deprecatedModuleAttribute} wraps a - module-level attribute in an object that emits a deprecation warning - when it is accessed the first time only, while leaving other unrelated - attributes alone. - """ - # Accessing non-deprecated attributes does not issue a warning. - deprecatedattributes.ANOTHER_ATTRIBUTE - warningsShown = self.flushWarnings([self.test_deprecatedAttribute]) - self.assertEqual(len(warningsShown), 0) - - name = 'DEPRECATED_ATTRIBUTE' - - # Access the deprecated attribute. This uses getattr to avoid repeating - # the attribute name. - getattr(deprecatedattributes, name) - - warningsShown = self.flushWarnings([self.test_deprecatedAttribute]) - self.assertEqual(len(warningsShown), 1) - self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEqual( - warningsShown[0]['message'], - self._getWarningString(name)) - - - def test_wrappedModule(self): - """ - Deprecating an attribute in a module replaces and wraps that module - instance, in C{sys.modules}, with a - L{twisted.python.deprecate._ModuleProxy} instance but only if it hasn't - already been wrapped. - """ - sys.modules[self._testModuleName] = mod = types.ModuleType('foo') - self.addCleanup(sys.modules.pop, self._testModuleName) - - setattr(mod, 'first', 1) - setattr(mod, 'second', 2) - - deprecate.deprecatedModuleAttribute( - Version('Twisted', 8, 0, 0), - 'message', - self._testModuleName, - 'first') - - proxy = sys.modules[self._testModuleName] - self.assertNotEqual(proxy, mod) - - deprecate.deprecatedModuleAttribute( - Version('Twisted', 8, 0, 0), - 'message', - self._testModuleName, - 'second') - - self.assertIdentical(proxy, sys.modules[self._testModuleName]) - - - -class ImportedModuleAttributeTests(TwistedModulesMixin, SynchronousTestCase): - """ - Tests for L{deprecatedModuleAttribute} which involve loading a module via - 'import'. - """ - - _packageInit = """\ -from twisted.python.deprecate import deprecatedModuleAttribute -from twisted.python.versions import Version - -deprecatedModuleAttribute( - Version('Package', 1, 2, 3), 'message', __name__, 'module') -""" - - - def pathEntryTree(self, tree): - """ - Create some files in a hierarchy, based on a dictionary describing those - files. The resulting hierarchy will be placed onto sys.path for the - duration of the test. - - @param tree: A dictionary representing a directory structure. Keys are - strings, representing filenames, dictionary values represent - directories, string values represent file contents. - - @return: another dictionary similar to the input, with file content - strings replaced with L{FilePath} objects pointing at where those - contents are now stored. - """ - def makeSomeFiles(pathobj, dirdict): - pathdict = {} - for (key, value) in dirdict.items(): - child = pathobj.child(key) - if isinstance(value, bytes): - pathdict[key] = child - child.setContent(value) - elif isinstance(value, dict): - child.createDirectory() - pathdict[key] = makeSomeFiles(child, value) - else: - raise ValueError("only strings and dicts allowed as values") - return pathdict - base = FilePath(self.mktemp().encode("utf-8")) - base.makedirs() - - result = makeSomeFiles(base, tree) - # On Python 3, sys.path cannot include byte paths: - self.replaceSysPath([base.path.decode("utf-8")] + sys.path) - self.replaceSysModules(sys.modules.copy()) - return result - - - def simpleModuleEntry(self): - """ - Add a sample module and package to the path, returning a L{FilePath} - pointing at the module which will be loadable as C{package.module}. - """ - paths = self.pathEntryTree( - {b"package": {b"__init__.py": self._packageInit.encode("utf-8"), - b"module.py": b""}}) - return paths[b'package'][b'module.py'] - - - def checkOneWarning(self, modulePath): - """ - Verification logic for L{test_deprecatedModule}. - """ - from package import module - self.assertEqual(FilePath(module.__file__.encode("utf-8")), - modulePath) - emitted = self.flushWarnings([self.checkOneWarning]) - self.assertEqual(len(emitted), 1) - self.assertEqual(emitted[0]['message'], - 'package.module was deprecated in Package 1.2.3: ' - 'message') - self.assertEqual(emitted[0]['category'], DeprecationWarning) - - - def test_deprecatedModule(self): - """ - If L{deprecatedModuleAttribute} is used to deprecate a module attribute - of a package, only one deprecation warning is emitted when the - deprecated module is imported. - """ - self.checkOneWarning(self.simpleModuleEntry()) - - - def test_deprecatedModuleMultipleTimes(self): - """ - If L{deprecatedModuleAttribute} is used to deprecate a module attribute - of a package, only one deprecation warning is emitted when the - deprecated module is subsequently imported. - """ - mp = self.simpleModuleEntry() - # The first time, the code needs to be loaded. - self.checkOneWarning(mp) - # The second time, things are slightly different; the object's already - # in the namespace. - self.checkOneWarning(mp) - # The third and fourth times, things things should all be exactly the - # same, but this is a sanity check to make sure the implementation isn't - # special casing the second time. Also, putting these cases into a loop - # means that the stack will be identical, to make sure that the - # implementation doesn't rely too much on stack-crawling. - for x in range(2): - self.checkOneWarning(mp) - - - -class WarnAboutFunctionTests(SynchronousTestCase): - """ - Tests for L{twisted.python.deprecate.warnAboutFunction} which allows the - callers of a function to issue a C{DeprecationWarning} about that function. - """ - def setUp(self): - """ - Create a file that will have known line numbers when emitting warnings. - """ - self.package = FilePath(self.mktemp().encode("utf-8") - ).child(b'twisted_private_helper') - self.package.makedirs() - self.package.child(b'__init__.py').setContent(b'') - self.package.child(b'module.py').setContent(b''' -"A module string" - -from twisted.python import deprecate - -def testFunction(): - "A doc string" - a = 1 + 2 - return a - -def callTestFunction(): - b = testFunction() - if b == 3: - deprecate.warnAboutFunction(testFunction, "A Warning String") -''') - # Python 3 doesn't accept bytes in sys.path: - packagePath = self.package.parent().path.decode("utf-8") - sys.path.insert(0, packagePath) - self.addCleanup(sys.path.remove, packagePath) - - modules = sys.modules.copy() - self.addCleanup( - lambda: (sys.modules.clear(), sys.modules.update(modules))) - - - def test_warning(self): - """ - L{deprecate.warnAboutFunction} emits a warning the file and line number - of which point to the beginning of the implementation of the function - passed to it. - """ - def aFunc(): - pass - deprecate.warnAboutFunction(aFunc, 'A Warning Message') - warningsShown = self.flushWarnings() - filename = __file__ - if filename.lower().endswith('.pyc'): - filename = filename[:-1] - self.assertSamePath( - FilePath(warningsShown[0]["filename"]), FilePath(filename)) - self.assertEqual(warningsShown[0]["message"], "A Warning Message") - - - def test_warningLineNumber(self): - """ - L{deprecate.warnAboutFunction} emits a C{DeprecationWarning} with the - number of a line within the implementation of the function passed to it. - """ - from twisted_private_helper import module - module.callTestFunction() - warningsShown = self.flushWarnings() - self.assertSamePath( - FilePath(warningsShown[0]["filename"].encode("utf-8")), - self.package.sibling(b'twisted_private_helper').child(b'module.py')) - # Line number 9 is the last line in the testFunction in the helper - # module. - self.assertEqual(warningsShown[0]["lineno"], 9) - self.assertEqual(warningsShown[0]["message"], "A Warning String") - self.assertEqual(len(warningsShown), 1) - - - def assertSamePath(self, first, second): - """ - Assert that the two paths are the same, considering case normalization - appropriate for the current platform. - - @type first: L{FilePath} - @type second: L{FilePath} - - @raise C{self.failureType}: If the paths are not the same. - """ - self.assertTrue( - normcase(first.path) == normcase(second.path), - "%r != %r" % (first, second)) - - - def test_renamedFile(self): - """ - Even if the implementation of a deprecated function is moved around on - the filesystem, the line number in the warning emitted by - L{deprecate.warnAboutFunction} points to a line in the implementation of - the deprecated function. - """ - from twisted_private_helper import module - # Clean up the state resulting from that import; we're not going to use - # this module, so it should go away. - del sys.modules['twisted_private_helper'] - del sys.modules[module.__name__] - - # Rename the source directory - self.package.moveTo(self.package.sibling(b'twisted_renamed_helper')) - - # Make sure importlib notices we've changed importable packages: - if invalidate_caches: - invalidate_caches() - - # Import the newly renamed version - from twisted_renamed_helper import module - self.addCleanup(sys.modules.pop, 'twisted_renamed_helper') - self.addCleanup(sys.modules.pop, module.__name__) - - module.callTestFunction() - warningsShown = self.flushWarnings() - warnedPath = FilePath(warningsShown[0]["filename"].encode("utf-8")) - expectedPath = self.package.sibling( - b'twisted_renamed_helper').child(b'module.py') - self.assertSamePath(warnedPath, expectedPath) - self.assertEqual(warningsShown[0]["lineno"], 9) - self.assertEqual(warningsShown[0]["message"], "A Warning String") - self.assertEqual(len(warningsShown), 1) - - - def test_filteredWarning(self): - """ - L{deprecate.warnAboutFunction} emits a warning that will be filtered if - L{warnings.filterwarning} is called with the module name of the - deprecated function. - """ - # Clean up anything *else* that might spuriously filter out the warning, - # such as the "always" simplefilter set up by unittest._collectWarnings. - # We'll also rely on trial to restore the original filters afterwards. - del warnings.filters[:] - - warnings.filterwarnings( - action="ignore", module="twisted_private_helper") - - from twisted_private_helper import module - module.callTestFunction() - - warningsShown = self.flushWarnings() - self.assertEqual(len(warningsShown), 0) - - - def test_filteredOnceWarning(self): - """ - L{deprecate.warnAboutFunction} emits a warning that will be filtered - once if L{warnings.filterwarning} is called with the module name of the - deprecated function and an action of once. - """ - # Clean up anything *else* that might spuriously filter out the warning, - # such as the "always" simplefilter set up by unittest._collectWarnings. - # We'll also rely on trial to restore the original filters afterwards. - del warnings.filters[:] - - warnings.filterwarnings( - action="module", module="twisted_private_helper") - - from twisted_private_helper import module - module.callTestFunction() - module.callTestFunction() - - warningsShown = self.flushWarnings() - self.assertEqual(len(warningsShown), 1) - message = warningsShown[0]['message'] - category = warningsShown[0]['category'] - filename = warningsShown[0]['filename'] - lineno = warningsShown[0]['lineno'] - msg = warnings.formatwarning(message, category, filename, lineno) - self.assertTrue( - msg.endswith("module.py:9: DeprecationWarning: A Warning String\n" - " return a\n"), - "Unexpected warning string: %r" % (msg,)) - - -def dummyCallable(): - """ - Do nothing. - - This is used to test the deprecation decorators. - """ - - - -def dummyReplacementMethod(): - """ - Do nothing. - - This is used to test the replacement parameter to L{deprecated}. - """ - - - -class DeprecationWarningsTests(SynchronousTestCase): - def test_getDeprecationWarningString(self): - """ - L{getDeprecationWarningString} returns a string that tells us that a - callable was deprecated at a certain released version of Twisted. - """ - version = Version('Twisted', 8, 0, 0) - self.assertEqual( - getDeprecationWarningString(self.test_getDeprecationWarningString, - version), - "%s.DeprecationWarningsTests.test_getDeprecationWarningString " - "was deprecated in Twisted 8.0.0" % (__name__,)) - - - def test_getDeprecationWarningStringWithFormat(self): - """ - L{getDeprecationWarningString} returns a string that tells us that a - callable was deprecated at a certain released version of Twisted, with - a message containing additional information about the deprecation. - """ - version = Version('Twisted', 8, 0, 0) - format = DEPRECATION_WARNING_FORMAT + ': This is a message' - self.assertEqual( - getDeprecationWarningString(self.test_getDeprecationWarningString, - version, format), - '%s.DeprecationWarningsTests.test_getDeprecationWarningString was ' - 'deprecated in Twisted 8.0.0: This is a message' % (__name__,)) - - - def test_deprecateEmitsWarning(self): - """ - Decorating a callable with L{deprecated} emits a warning. - """ - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(dummyCallable) - def addStackLevel(): - dummy() - with catch_warnings(record=True) as caught: - simplefilter("always") - addStackLevel() - self.assertEqual(caught[0].category, DeprecationWarning) - self.assertEqual(str(caught[0].message), getDeprecationWarningString(dummyCallable, version)) - # rstrip in case .pyc/.pyo - self.assertEqual(caught[0].filename.rstrip('co'), __file__.rstrip('co')) - - - def test_deprecatedPreservesName(self): - """ - The decorated function has the same name as the original. - """ - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(dummyCallable) - self.assertEqual(dummyCallable.__name__, dummy.__name__) - self.assertEqual(fullyQualifiedName(dummyCallable), - fullyQualifiedName(dummy)) - - - def test_getDeprecationDocstring(self): - """ - L{_getDeprecationDocstring} returns a note about the deprecation to go - into a docstring. - """ - version = Version('Twisted', 8, 0, 0) - self.assertEqual( - "Deprecated in Twisted 8.0.0.", - _getDeprecationDocstring(version, '')) - - - def test_deprecatedUpdatesDocstring(self): - """ - The docstring of the deprecated function is appended with information - about the deprecation. - """ - - def localDummyCallable(): - """ - Do nothing. - - This is used to test the deprecation decorators. - """ - - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(localDummyCallable) - - _appendToDocstring( - localDummyCallable, - _getDeprecationDocstring(version, '')) - - self.assertEqual(localDummyCallable.__doc__, dummy.__doc__) - - - def test_versionMetadata(self): - """ - Deprecating a function adds version information to the decorated - version of that function. - """ - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(dummyCallable) - self.assertEqual(version, dummy.deprecatedVersion) - - - def test_getDeprecationWarningStringReplacement(self): - """ - L{getDeprecationWarningString} takes an additional replacement parameter - that can be used to add information to the deprecation. If the - replacement parameter is a string, it will be interpolated directly into - the result. - """ - version = Version('Twisted', 8, 0, 0) - warningString = getDeprecationWarningString( - self.test_getDeprecationWarningString, version, - replacement="something.foobar") - self.assertEqual( - warningString, - "%s was deprecated in Twisted 8.0.0; please use something.foobar " - "instead" % ( - fullyQualifiedName(self.test_getDeprecationWarningString),)) - - - def test_getDeprecationWarningStringReplacementWithCallable(self): - """ - L{getDeprecationWarningString} takes an additional replacement parameter - that can be used to add information to the deprecation. If the - replacement parameter is a callable, its fully qualified name will be - interpolated into the result. - """ - version = Version('Twisted', 8, 0, 0) - warningString = getDeprecationWarningString( - self.test_getDeprecationWarningString, version, - replacement=dummyReplacementMethod) - self.assertEqual( - warningString, - "%s was deprecated in Twisted 8.0.0; please use " - "%s.dummyReplacementMethod instead" % ( - fullyQualifiedName(self.test_getDeprecationWarningString), - __name__)) - - - def test_deprecatedReplacement(self): - """ - L{deprecated} takes an additional replacement parameter that can be used - to indicate the new, non-deprecated method developers should use. If - the replacement parameter is a string, it will be interpolated directly - into the warning message. - """ - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version, "something.foobar")(dummyCallable) - self.assertEqual(dummy.__doc__, - "\n" - " Do nothing.\n\n" - " This is used to test the deprecation decorators.\n\n" - " Deprecated in Twisted 8.0.0; please use " - "something.foobar" - " instead.\n" - " ") - - - def test_deprecatedReplacementWithCallable(self): - """ - L{deprecated} takes an additional replacement parameter that can be used - to indicate the new, non-deprecated method developers should use. If - the replacement parameter is a callable, its fully qualified name will - be interpolated into the warning message. - """ - version = Version('Twisted', 8, 0, 0) - decorator = deprecated(version, replacement=dummyReplacementMethod) - dummy = decorator(dummyCallable) - self.assertEqual(dummy.__doc__, - "\n" - " Do nothing.\n\n" - " This is used to test the deprecation decorators.\n\n" - " Deprecated in Twisted 8.0.0; please use " - "%s.dummyReplacementMethod instead.\n" - " " % (__name__,)) - - - -class AppendToDocstringTests(SynchronousTestCase): - """ - Test the _appendToDocstring function. - - _appendToDocstring is used to add text to a docstring. - """ - - def test_appendToEmptyDocstring(self): - """ - Appending to an empty docstring simply replaces the docstring. - """ - - def noDocstring(): - pass - - _appendToDocstring(noDocstring, "Appended text.") - self.assertEqual("Appended text.", noDocstring.__doc__) - - - def test_appendToSingleLineDocstring(self): - """ - Appending to a single line docstring places the message on a new line, - with a blank line separating it from the rest of the docstring. - - The docstring ends with a newline, conforming to Twisted and PEP 8 - standards. Unfortunately, the indentation is incorrect, since the - existing docstring doesn't have enough info to help us indent - properly. - """ - - def singleLineDocstring(): - """This doesn't comply with standards, but is here for a test.""" - - _appendToDocstring(singleLineDocstring, "Appended text.") - self.assertEqual( - ["This doesn't comply with standards, but is here for a test.", - "", - "Appended text."], - singleLineDocstring.__doc__.splitlines()) - self.assertTrue(singleLineDocstring.__doc__.endswith('\n')) - - - def test_appendToMultilineDocstring(self): - """ - Appending to a multi-line docstring places the messade on a new line, - with a blank line separating it from the rest of the docstring. - - Because we have multiple lines, we have enough information to do - indentation. - """ - - def multiLineDocstring(): - """ - This is a multi-line docstring. - """ - - def expectedDocstring(): - """ - This is a multi-line docstring. - - Appended text. - """ - - _appendToDocstring(multiLineDocstring, "Appended text.") - self.assertEqual( - expectedDocstring.__doc__, multiLineDocstring.__doc__) - - - -class MutualArgumentExclusionTests(SynchronousTestCase): - """ - Tests for L{mutuallyExclusiveArguments}. - """ - - def checkPassed(self, func, *args, **kw): - """ - Test an invocation of L{passed} with the given function, arguments, and - keyword arguments. - - @param func: A function whose argspec to pass to L{_passed}. - @type func: A callable. - - @param args: The arguments which could be passed to L{func}. - - @param kw: The keyword arguments which could be passed to L{func}. - - @return: L{_passed}'s return value - @rtype: L{dict} - """ - return _passed(inspect.getargspec(func), args, kw) - - - def test_passed_simplePositional(self): - """ - L{passed} identifies the arguments passed by a simple - positional test. - """ - def func(a, b): - pass - self.assertEqual(self.checkPassed(func, 1, 2), dict(a=1, b=2)) - - - def test_passed_tooManyArgs(self): - """ - L{passed} raises a L{TypeError} if too many arguments are - passed. - """ - def func(a, b): - pass - self.assertRaises(TypeError, self.checkPassed, func, 1, 2, 3) - - - def test_passed_doublePassKeyword(self): - """ - L{passed} raises a L{TypeError} if a argument is passed both - positionally and by keyword. - """ - def func(a): - pass - self.assertRaises(TypeError, self.checkPassed, func, 1, a=2) - - - def test_passed_unspecifiedKeyword(self): - """ - L{passed} raises a L{TypeError} if a keyword argument not - present in the function's declaration is passed. - """ - def func(a): - pass - self.assertRaises(TypeError, self.checkPassed, func, 1, z=2) - - - def test_passed_star(self): - """ - L{passed} places additional positional arguments into a tuple - under the name of the star argument. - """ - def func(a, *b): - pass - self.assertEqual(self.checkPassed(func, 1, 2, 3), - dict(a=1, b=(2, 3))) - - - def test_passed_starStar(self): - """ - Additional keyword arguments are passed as a dict to the star star - keyword argument. - """ - def func(a, **b): - pass - self.assertEqual(self.checkPassed(func, 1, x=2, y=3, z=4), - dict(a=1, b=dict(x=2, y=3, z=4))) - - - def test_passed_noDefaultValues(self): - """ - The results of L{passed} only include arguments explicitly - passed, not default values. - """ - def func(a, b, c=1, d=2, e=3): - pass - self.assertEqual(self.checkPassed(func, 1, 2, e=7), - dict(a=1, b=2, e=7)) - - - def test_mutualExclusionPrimeDirective(self): - """ - L{mutuallyExclusiveArguments} does not interfere in its - decoratee's operation, either its receipt of arguments or its return - value. - """ - @_mutuallyExclusiveArguments([('a', 'b')]) - def func(x, y, a=3, b=4): - return x + y + a + b - - self.assertEqual(func(1, 2), 10) - self.assertEqual(func(1, 2, 7), 14) - self.assertEqual(func(1, 2, b=7), 13) - - - def test_mutualExclusionExcludesByKeyword(self): - """ - L{mutuallyExclusiveArguments} raises a L{TypeError}n if its - decoratee is passed a pair of mutually exclusive arguments. - """ - @_mutuallyExclusiveArguments([['a', 'b']]) - def func(a=3, b=4): - return a + b - - self.assertRaises(TypeError, func, a=3, b=4) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_dist.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_dist.py deleted file mode 100644 index 72e8a4a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_dist.py +++ /dev/null @@ -1,604 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for parts of our release automation system. -""" - - -import os -import sys - - -from setuptools.dist import Distribution - -from twisted.trial.unittest import TestCase - -from twisted.python import dist -from twisted.python.dist import (get_setup_args, ConditionalExtension, - build_scripts_twisted, _EXTRAS_REQUIRE) -from twisted.python.filepath import FilePath - - - -class SetupTests(TestCase): - """ - Tests for L{get_setup_args}. - """ - def test_conditionalExtensions(self): - """ - Passing C{conditionalExtensions} as a list of L{ConditionalExtension} - objects to get_setup_args inserts a custom build_ext into the result - which knows how to check whether they should be built. - """ - good_ext = ConditionalExtension("whatever", ["whatever.c"], - condition=lambda b: True) - bad_ext = ConditionalExtension("whatever", ["whatever.c"], - condition=lambda b: False) - args = get_setup_args(conditionalExtensions=[good_ext, bad_ext]) - # ext_modules should be set even though it's not used. See comment - # in get_setup_args - self.assertEqual(args["ext_modules"], [good_ext, bad_ext]) - cmdclass = args["cmdclass"] - build_ext = cmdclass["build_ext"] - builder = build_ext(Distribution()) - builder.prepare_extensions() - self.assertEqual(builder.extensions, [good_ext]) - - - def test_win32Definition(self): - """ - When building on Windows NT, the WIN32 macro will be defined as 1. - """ - ext = ConditionalExtension("whatever", ["whatever.c"], - define_macros=[("whatever", 2)]) - args = get_setup_args(conditionalExtensions=[ext]) - builder = args["cmdclass"]["build_ext"](Distribution()) - self.patch(os, "name", "nt") - builder.prepare_extensions() - self.assertEqual(ext.define_macros, [("whatever", 2), ("WIN32", 1)]) - - - -class OptionalDependenciesTests(TestCase): - """ - Tests for L{_EXTRAS_REQUIRE} - """ - - def test_distributeTakesExtrasRequire(self): - """ - Setuptools' Distribution object parses and stores its C{extras_require} - argument as an attribute. - """ - extras = dict(im_an_extra_dependency="thing") - attrs = dict(extras_require=extras) - distribution = Distribution(attrs) - self.assertEqual( - extras, - distribution.extras_require - ) - - - def test_extrasRequireDictContainsKeys(self): - """ - L{_EXTRAS_REQUIRE} contains options for all documented extras: C{dev}, - C{tls}, C{conch}, C{soap}, C{serial}, C{all_non_platform}, - C{osx_platform}, and C{windows_platform}. - """ - self.assertIn('dev', _EXTRAS_REQUIRE) - self.assertIn('tls', _EXTRAS_REQUIRE) - self.assertIn('conch', _EXTRAS_REQUIRE) - self.assertIn('soap', _EXTRAS_REQUIRE) - self.assertIn('serial', _EXTRAS_REQUIRE) - self.assertIn('all_non_platform', _EXTRAS_REQUIRE) - self.assertIn('osx_platform', _EXTRAS_REQUIRE) - self.assertIn('windows_platform', _EXTRAS_REQUIRE) - - - def test_extrasRequiresDevDeps(self): - """ - L{_EXTRAS_REQUIRE}'s C{dev} extra contains setuptools requirements for - the tools required for Twisted development. - """ - deps = _EXTRAS_REQUIRE['dev'] - self.assertIn('twistedchecker >= 0.2.0', deps) - self.assertIn('pyflakes >= 0.8.1', deps) - self.assertIn('twisted-dev-tools >= 0.0.2', deps) - self.assertIn('python-subunit', deps) - self.assertIn('sphinx >= 1.2.2', deps) - self.assertIn('pydoctor >= 0.5', deps) - - - def test_extrasRequiresTlsDeps(self): - """ - L{_EXTRAS_REQUIRE}'s C{tls} extra contains setuptools requirements for - the packages required to make Twisted's transport layer security fully - work for both clients and servers. - """ - deps = _EXTRAS_REQUIRE['tls'] - self.assertIn('pyopenssl >= 0.11', deps) - self.assertIn('service_identity', deps) - self.assertIn('idna >= 0.6', deps) - - - def test_extrasRequiresConchDeps(self): - """ - L{_EXTRAS_REQUIRE}'s C{conch} extra contains setuptools requirements - for the packages required to make Twisted Conch's secure shell server - work. - """ - deps = _EXTRAS_REQUIRE['conch'] - self.assertIn('gmpy', deps) - self.assertIn('pyasn1', deps) - self.assertIn('pycrypto', deps) - - - def test_extrasRequiresSoapDeps(self): - """ - L{_EXTRAS_REQUIRE}' C{soap} extra contains setuptools requirements for - the packages required to make the C{twisted.web.soap} module function. - """ - self.assertIn( - 'soappy', - _EXTRAS_REQUIRE['soap'] - ) - - - def test_extrasRequiresSerialDeps(self): - """ - L{_EXTRAS_REQUIRE}'s C{serial} extra contains setuptools requirements - for the packages required to make Twisted's serial support work. - """ - self.assertIn( - 'pyserial', - _EXTRAS_REQUIRE['serial'] - ) - - - def test_extrasRequiresAllNonPlatformDeps(self): - """ - L{_EXTRAS_REQUIRE}'s C{all_non_platform} extra contains setuptools - requirements for all of Twisted's optional dependencies which work on - all supported operating systems. - """ - deps = _EXTRAS_REQUIRE['all_non_platform'] - self.assertIn('pyopenssl >= 0.11', deps) - self.assertIn('service_identity', deps) - self.assertIn('idna >= 0.6', deps) - self.assertIn('gmpy', deps) - self.assertIn('pyasn1', deps) - self.assertIn('pycrypto', deps) - self.assertIn('soappy', deps) - self.assertIn('pyserial', deps) - - - def test_extrasRequiresOsxPlatformDeps(self): - """ - L{_EXTRAS_REQUIRE}'s C{osx_platform} extra contains setuptools - requirements for all of Twisted's optional dependencies usable on the - Mac OS X platform. - """ - deps = _EXTRAS_REQUIRE['osx_platform'] - self.assertIn('pyopenssl >= 0.11', deps) - self.assertIn('service_identity', deps) - self.assertIn('idna >= 0.6', deps) - self.assertIn('gmpy', deps) - self.assertIn('pyasn1', deps) - self.assertIn('pycrypto', deps) - self.assertIn('soappy', deps) - self.assertIn('pyserial', deps) - self.assertIn('pyobjc', deps) - - - def test_extrasRequiresWindowsPlatformDeps(self): - """ - L{_EXTRAS_REQUIRE}'s C{windows_platform} extra contains setuptools - requirements for all of Twisted's optional dependencies usable on the - Microsoft Windows platform. - """ - deps = _EXTRAS_REQUIRE['windows_platform'] - self.assertIn('pyopenssl >= 0.11', deps) - self.assertIn('service_identity', deps) - self.assertIn('idna >= 0.6', deps) - self.assertIn('gmpy', deps) - self.assertIn('pyasn1', deps) - self.assertIn('pycrypto', deps) - self.assertIn('soappy', deps) - self.assertIn('pyserial', deps) - self.assertIn('pypiwin32', deps) - - - -class GetExtensionsTests(TestCase): - """ - Tests for L{dist.getExtensions}. - """ - - setupTemplate = ( - "from twisted.python.dist import ConditionalExtension\n" - "extensions = [\n" - " ConditionalExtension(\n" - " '%s', ['twisted/some/thing.c'],\n" - " condition=lambda builder: True)\n" - " ]\n") - - def setUp(self): - self.basedir = FilePath(self.mktemp()).child("twisted") - self.basedir.makedirs() - self.addCleanup(os.chdir, os.getcwd()) - os.chdir(self.basedir.parent().path) - - - def writeSetup(self, name, *path): - """ - Write out a C{setup.py} file to a location determined by - L{self.basedir} and L{path}. L{self.setupTemplate} is used to - generate its contents. - """ - outdir = self.basedir.descendant(path) - outdir.makedirs() - setup = outdir.child("setup.py") - setup.setContent(self.setupTemplate % (name,)) - - - def writeEmptySetup(self, *path): - """ - Write out an empty C{setup.py} file to a location determined by - L{self.basedir} and L{path}. - """ - outdir = self.basedir.descendant(path) - outdir.makedirs() - outdir.child("setup.py").setContent("") - - - def assertExtensions(self, expected): - """ - Assert that the given names match the (sorted) names of discovered - extensions. - """ - extensions = dist.getExtensions() - names = [extension.name for extension in extensions] - self.assertEqual(sorted(names), expected) - - - def test_getExtensions(self): - """ - Files named I{setup.py} in I{twisted/topfiles} and I{twisted/*/topfiles} - are executed with L{execfile} in order to discover the extensions they - declare. - """ - self.writeSetup("twisted.transmutate", "topfiles") - self.writeSetup("twisted.tele.port", "tele", "topfiles") - self.assertExtensions(["twisted.tele.port", "twisted.transmutate"]) - - - def test_getExtensionsTooDeep(self): - """ - Files named I{setup.py} in I{topfiles} directories are not considered if - they are too deep in the directory hierarchy. - """ - self.writeSetup("twisted.trans.mog.rify", "trans", "mog", "topfiles") - self.assertExtensions([]) - - - def test_getExtensionsNotTopfiles(self): - """ - The folder in which I{setup.py} is discovered must be called I{topfiles} - otherwise it is ignored. - """ - self.writeSetup("twisted.metamorphosis", "notfiles") - self.assertExtensions([]) - - - def test_getExtensionsNotSupportedOnJava(self): - """ - Extensions are not supported on Java-based platforms. - """ - self.addCleanup(setattr, sys, "platform", sys.platform) - sys.platform = "java" - self.writeSetup("twisted.sorcery", "topfiles") - self.assertExtensions([]) - - - def test_getExtensionsExtensionsLocalIsOptional(self): - """ - It is acceptable for extensions to not define the C{extensions} local - variable. - """ - self.writeEmptySetup("twisted.necromancy", "topfiles") - self.assertExtensions([]) - - - -class GetVersionTests(TestCase): - """ - Tests for L{dist.getVersion}. - """ - - def setUp(self): - self.dirname = self.mktemp() - os.mkdir(self.dirname) - - def test_getVersionCore(self): - """ - Test that getting the version of core reads from the - [base]/_version.py file. - """ - f = open(os.path.join(self.dirname, "_version.py"), "w") - f.write(""" -from twisted.python import versions -version = versions.Version("twisted", 0, 1, 2) -""") - f.close() - self.assertEqual(dist.getVersion("core", base=self.dirname), "0.1.2") - - def test_getVersionOther(self): - """ - Test that getting the version of a non-core project reads from - the [base]/[projname]/_version.py file. - """ - os.mkdir(os.path.join(self.dirname, "blat")) - f = open(os.path.join(self.dirname, "blat", "_version.py"), "w") - f.write(""" -from twisted.python import versions -version = versions.Version("twisted.blat", 9, 8, 10) -""") - f.close() - self.assertEqual(dist.getVersion("blat", base=self.dirname), "9.8.10") - - - -class GetScriptsTests(TestCase): - """ - Tests for L{dist.getScripts} which returns the scripts which should be - included in the distribution of a project. - """ - - def test_scriptsInSVN(self): - """ - getScripts should return the scripts associated with a project - in the context of Twisted SVN. - """ - basedir = self.mktemp() - os.mkdir(basedir) - os.mkdir(os.path.join(basedir, 'bin')) - os.mkdir(os.path.join(basedir, 'bin', 'proj')) - f = open(os.path.join(basedir, 'bin', 'proj', 'exy'), 'w') - f.write('yay') - f.close() - scripts = dist.getScripts('proj', basedir=basedir) - self.assertEqual(len(scripts), 1) - self.assertEqual(os.path.basename(scripts[0]), 'exy') - - - def test_excludedPreamble(self): - """ - L{dist.getScripts} includes neither C{"_preamble.py"} nor - C{"_preamble.pyc"}. - """ - basedir = FilePath(self.mktemp()) - bin = basedir.child('bin') - bin.makedirs() - bin.child('_preamble.py').setContent('some preamble code\n') - bin.child('_preamble.pyc').setContent('some preamble byte code\n') - bin.child('program').setContent('good program code\n') - scripts = dist.getScripts("", basedir=basedir.path) - self.assertEqual(scripts, [bin.child('program').path]) - - - def test_scriptsInRelease(self): - """ - getScripts should return the scripts associated with a project - in the context of a released subproject tarball. - """ - basedir = self.mktemp() - os.mkdir(basedir) - os.mkdir(os.path.join(basedir, 'bin')) - f = open(os.path.join(basedir, 'bin', 'exy'), 'w') - f.write('yay') - f.close() - scripts = dist.getScripts('proj', basedir=basedir) - self.assertEqual(len(scripts), 1) - self.assertEqual(os.path.basename(scripts[0]), 'exy') - - - def test_noScriptsInSVN(self): - """ - When calling getScripts for a project which doesn't actually - have any scripts, in the context of an SVN checkout, an - empty list should be returned. - """ - basedir = self.mktemp() - os.mkdir(basedir) - os.mkdir(os.path.join(basedir, 'bin')) - os.mkdir(os.path.join(basedir, 'bin', 'otherproj')) - scripts = dist.getScripts('noscripts', basedir=basedir) - self.assertEqual(scripts, []) - - - def test_getScriptsTopLevel(self): - """ - Passing the empty string to getScripts returns scripts that are (only) - in the top level bin directory. - """ - basedir = FilePath(self.mktemp()) - basedir.createDirectory() - bindir = basedir.child("bin") - bindir.createDirectory() - included = bindir.child("included") - included.setContent("yay included") - subdir = bindir.child("subdir") - subdir.createDirectory() - subdir.child("not-included").setContent("not included") - - scripts = dist.getScripts("", basedir=basedir.path) - self.assertEqual(scripts, [included.path]) - - - def test_noScriptsInSubproject(self): - """ - When calling getScripts for a project which doesn't actually - have any scripts in the context of that project's individual - project structure, an empty list should be returned. - """ - basedir = self.mktemp() - os.mkdir(basedir) - scripts = dist.getScripts('noscripts', basedir=basedir) - self.assertEqual(scripts, []) - - - -class DummyCommand: - """ - A fake Command. - """ - def __init__(self, **kwargs): - for kw, val in kwargs.items(): - setattr(self, kw, val) - - def ensure_finalized(self): - pass - - - -class BuildScriptsTests(TestCase): - """ - Tests for L{dist.build_scripts_twisted}. - """ - - def setUp(self): - self.source = FilePath(self.mktemp()) - self.target = FilePath(self.mktemp()) - self.source.makedirs() - self.addCleanup(os.chdir, os.getcwd()) - os.chdir(self.source.path) - - - def buildScripts(self): - """ - Write 3 types of scripts and run the L{build_scripts_twisted} - command. - """ - self.writeScript(self.source, "script1", - ("#! /usr/bin/env python2.7\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - - self.writeScript(self.source, "script2.py", - ("#!/usr/bin/python\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - - self.writeScript(self.source, "shell.sh", - ("#!/bin/sh\n" - "# bogus shell script w/ sh-bang\n" - "exit 0\n")) - - expected = ['script1', 'script2.py', 'shell.sh'] - cmd = self.getBuildScriptsCmd(self.target, - [self.source.child(fn).path - for fn in expected]) - cmd.finalize_options() - cmd.run() - - return self.target.listdir() - - - def getBuildScriptsCmd(self, target, scripts): - """ - Create a distutils L{Distribution} with a L{DummyCommand} and wrap it - in L{build_scripts_twisted}. - - @type target: L{FilePath} - """ - dist = Distribution() - dist.scripts = scripts - dist.command_obj["build"] = DummyCommand( - build_scripts = target.path, - force = 1, - executable = sys.executable - ) - return build_scripts_twisted(dist) - - - def writeScript(self, dir, name, text): - """ - Write the script to disk. - """ - with open(dir.child(name).path, "w") as f: - f.write(text) - - - def test_notWindows(self): - """ - L{build_scripts_twisted} does not rename scripts on non-Windows - platforms. - """ - self.patch(os, "name", "twisted") - built = self.buildScripts() - for name in ['script1', 'script2.py', 'shell.sh']: - self.assertTrue(name in built) - - - def test_windows(self): - """ - L{build_scripts_twisted} renames scripts so they end with '.py' on - the Windows platform. - """ - self.patch(os, "name", "nt") - built = self.buildScripts() - for name in ['script1.py', 'script2.py', 'shell.sh.py']: - self.assertTrue(name in built) - - - -class FakeModule(object): - """ - A fake module, suitable for dependency injection in testing. - """ - def __init__(self, attrs): - """ - Initializes a fake module. - - @param attrs: The attrs that will be accessible on the module. - @type attrs: C{dict} of C{str} (Python names) to objects - """ - self._attrs = attrs - - - def __getattr__(self, name): - """ - Gets an attribute of this fake module from its attrs. - - @raise AttributeError: When the requested attribute is missing. - """ - try: - return self._attrs[name] - except KeyError: - raise AttributeError() - - - -fakeCPythonPlatform = FakeModule({"python_implementation": lambda: "CPython"}) -fakeOtherPlatform = FakeModule({"python_implementation": lambda: "lvhpy"}) - - - -class WithPlatformTests(TestCase): - """ - Tests for L{_checkCPython} when used with a (fake) C{platform} module. - """ - def test_cpython(self): - """ - L{_checkCPython} returns C{True} when C{platform.python_implementation} - says we're running on CPython. - """ - self.assertTrue(dist._checkCPython(platform=fakeCPythonPlatform)) - - - def test_other(self): - """ - L{_checkCPython} returns C{False} when C{platform.python_implementation} - says we're not running on CPython. - """ - self.assertFalse(dist._checkCPython(platform=fakeOtherPlatform)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_dist3.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_dist3.py deleted file mode 100644 index 5302b08..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_dist3.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.dist3}. -""" - -from __future__ import division - -import os -from twisted.trial.unittest import TestCase - -from twisted.python.dist3 import modulesToInstall - - -class ModulesToInstallTests(TestCase): - """ - Tests for L{modulesToInstall}. - """ - def test_sanityCheck(self): - """ - L{modulesToInstall} includes some obvious module names. - """ - self.assertIn("twisted.internet.reactor", modulesToInstall) - self.assertIn("twisted.python.test.test_dist3", modulesToInstall) - - - def test_exist(self): - """ - All modules listed in L{modulesToInstall} exist. - """ - import twisted - root = os.path.dirname(os.path.dirname(twisted.__file__)) - for module in modulesToInstall: - segments = module.split(".") - segments[-1] += ".py" - path = os.path.join(root, *segments) - alternateSegments = module.split(".") + ["__init__.py"] - packagePath = os.path.join(root, *alternateSegments) - self.assertTrue(os.path.exists(path) or - os.path.exists(packagePath), - "Module {0} does not exist".format(module)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_fakepwd.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_fakepwd.py deleted file mode 100644 index b99ac0a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_fakepwd.py +++ /dev/null @@ -1,414 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.fakepwd}. -""" - -try: - import pwd -except ImportError: - pwd = None - -try: - import spwd -except ImportError: - spwd = None - -import os -from operator import getitem - -from twisted.trial.unittest import TestCase -from twisted.python.fakepwd import UserDatabase, ShadowDatabase - -SYSTEM_UID_MAX = 999 - -def findInvalidUID(): - """ - By convention, UIDs less than 1000 are reserved for the system. A system - which allocated every single one of those UIDs would likely have practical - problems with allocating new ones, so let's assume that we'll be able to - find one. (If we don't, this will wrap around to negative values and - I{eventually} find something.) - - @return: a user ID which does not exist on the local system. Or, on - systems without a L{pwd} module, return C{SYSTEM_UID_MAX}. - """ - guess = SYSTEM_UID_MAX - if pwd is not None: - while True: - try: - pwd.getpwuid(guess) - except KeyError: - break - else: - guess -= 1 - return guess - - - -INVALID_UID = findInvalidUID() - - - -class UserDatabaseTestsMixin: - """ - L{UserDatabaseTestsMixin} defines tests which apply to any user database - implementation. Subclasses should mix it in, implement C{setUp} to create - C{self.database} bound to a user database instance, and implement - C{getExistingUserInfo} to return information about a user (such information - should be unique per test method). - """ - def test_getpwuid(self): - """ - I{getpwuid} accepts a uid and returns the user record associated with - it. - """ - for i in range(2): - # Get some user which exists in the database. - username, password, uid, gid, gecos, dir, shell = self.getExistingUserInfo() - - # Now try to look it up and make sure the result is correct. - entry = self.database.getpwuid(uid) - self.assertEqual(entry.pw_name, username) - self.assertEqual(entry.pw_passwd, password) - self.assertEqual(entry.pw_uid, uid) - self.assertEqual(entry.pw_gid, gid) - self.assertEqual(entry.pw_gecos, gecos) - self.assertEqual(entry.pw_dir, dir) - self.assertEqual(entry.pw_shell, shell) - - - def test_noSuchUID(self): - """ - I{getpwuid} raises L{KeyError} when passed a uid which does not exist - in the user database. - """ - self.assertRaises(KeyError, self.database.getpwuid, INVALID_UID) - - - def test_getpwnam(self): - """ - I{getpwnam} accepts a username and returns the user record associated - with it. - """ - for i in range(2): - # Get some user which exists in the database. - username, password, uid, gid, gecos, dir, shell = self.getExistingUserInfo() - - # Now try to look it up and make sure the result is correct. - entry = self.database.getpwnam(username) - self.assertEqual(entry.pw_name, username) - self.assertEqual(entry.pw_passwd, password) - self.assertEqual(entry.pw_uid, uid) - self.assertEqual(entry.pw_gid, gid) - self.assertEqual(entry.pw_gecos, gecos) - self.assertEqual(entry.pw_dir, dir) - self.assertEqual(entry.pw_shell, shell) - - - def test_noSuchName(self): - """ - I{getpwnam} raises L{KeyError} when passed a username which does not - exist in the user database. - """ - self.assertRaises( - KeyError, self.database.getpwnam, - 'no' 'such' 'user' 'exists' 'the' 'name' 'is' 'too' 'long' 'and' 'has' - '\1' 'in' 'it' 'too') - - - def test_recordLength(self): - """ - The user record returned by I{getpwuid}, I{getpwnam}, and I{getpwall} - has a length. - """ - db = self.database - username, password, uid, gid, gecos, dir, shell = self.getExistingUserInfo() - for entry in [db.getpwuid(uid), db.getpwnam(username), db.getpwall()[0]]: - self.assertIsInstance(len(entry), int) - self.assertEqual(len(entry), 7) - - - def test_recordIndexable(self): - """ - The user record returned by I{getpwuid}, I{getpwnam}, and I{getpwall} - is indexable, with successive indexes starting from 0 corresponding to - the values of the C{pw_name}, C{pw_passwd}, C{pw_uid}, C{pw_gid}, - C{pw_gecos}, C{pw_dir}, and C{pw_shell} attributes, respectively. - """ - db = self.database - username, password, uid, gid, gecos, dir, shell = self.getExistingUserInfo() - for entry in [db.getpwuid(uid), db.getpwnam(username), db.getpwall()[0]]: - self.assertEqual(entry[0], username) - self.assertEqual(entry[1], password) - self.assertEqual(entry[2], uid) - self.assertEqual(entry[3], gid) - self.assertEqual(entry[4], gecos) - self.assertEqual(entry[5], dir) - self.assertEqual(entry[6], shell) - - self.assertEqual(len(entry), len(list(entry))) - self.assertRaises(IndexError, getitem, entry, 7) - - - -class UserDatabaseTests(TestCase, UserDatabaseTestsMixin): - """ - Tests for L{UserDatabase}. - """ - def setUp(self): - """ - Create a L{UserDatabase} with no user data in it. - """ - self.database = UserDatabase() - self._counter = SYSTEM_UID_MAX + 1 - - - def getExistingUserInfo(self): - """ - Add a new user to C{self.database} and return its information. - """ - self._counter += 1 - suffix = '_' + str(self._counter) - username = 'username' + suffix - password = 'password' + suffix - uid = self._counter - gid = self._counter + 1000 - gecos = 'gecos' + suffix - dir = 'dir' + suffix - shell = 'shell' + suffix - - self.database.addUser(username, password, uid, gid, gecos, dir, shell) - return (username, password, uid, gid, gecos, dir, shell) - - - def test_addUser(self): - """ - L{UserDatabase.addUser} accepts seven arguments, one for each field of - a L{pwd.struct_passwd}, and makes the new record available via - L{UserDatabase.getpwuid}, L{UserDatabase.getpwnam}, and - L{UserDatabase.getpwall}. - """ - username = 'alice' - password = 'secr3t' - uid = 123 - gid = 456 - gecos = 'Alice,,,' - home = '/users/alice' - shell = '/usr/bin/foosh' - - db = self.database - db.addUser(username, password, uid, gid, gecos, home, shell) - - for [entry] in [[db.getpwuid(uid)], [db.getpwnam(username)], - db.getpwall()]: - self.assertEqual(entry.pw_name, username) - self.assertEqual(entry.pw_passwd, password) - self.assertEqual(entry.pw_uid, uid) - self.assertEqual(entry.pw_gid, gid) - self.assertEqual(entry.pw_gecos, gecos) - self.assertEqual(entry.pw_dir, home) - self.assertEqual(entry.pw_shell, shell) - - - -class PwdModuleTests(TestCase, UserDatabaseTestsMixin): - """ - L{PwdModuleTests} runs the tests defined by L{UserDatabaseTestsMixin} - against the built-in C{pwd} module. This serves to verify that - L{UserDatabase} is really a fake of that API. - """ - if pwd is None: - skip = "Cannot verify UserDatabase against pwd without pwd" - else: - database = pwd - - def setUp(self): - self._users = iter(self.database.getpwall()) - self._uids = set() - - - def getExistingUserInfo(self): - """ - Read and return the next record from C{self._users}, filtering out - any records with previously seen uid values (as these cannot be - found with C{getpwuid} and only cause trouble). - """ - while True: - entry = next(self._users) - uid = entry.pw_uid - if uid not in self._uids: - self._uids.add(uid) - return entry - - - -class ShadowDatabaseTestsMixin: - """ - L{ShadowDatabaseTestsMixin} defines tests which apply to any shadow user - database implementation. Subclasses should mix it in, implement C{setUp} to - create C{self.database} bound to a shadow user database instance, and - implement C{getExistingUserInfo} to return information about a user (such - information should be unique per test method). - """ - def test_getspnam(self): - """ - L{getspnam} accepts a username and returns the user record associated - with it. - """ - for i in range(2): - # Get some user which exists in the database. - (username, password, lastChange, min, max, warn, inact, expire, - flag) = self.getExistingUserInfo() - - entry = self.database.getspnam(username) - self.assertEqual(entry.sp_nam, username) - self.assertEqual(entry.sp_pwd, password) - self.assertEqual(entry.sp_lstchg, lastChange) - self.assertEqual(entry.sp_min, min) - self.assertEqual(entry.sp_max, max) - self.assertEqual(entry.sp_warn, warn) - self.assertEqual(entry.sp_inact, inact) - self.assertEqual(entry.sp_expire, expire) - self.assertEqual(entry.sp_flag, flag) - - - def test_noSuchName(self): - """ - I{getspnam} raises L{KeyError} when passed a username which does not - exist in the user database. - """ - self.assertRaises(KeyError, self.database.getspnam, "alice") - - - def test_recordLength(self): - """ - The shadow user record returned by I{getspnam} and I{getspall} has a - length. - """ - db = self.database - username = self.getExistingUserInfo()[0] - for entry in [db.getspnam(username), db.getspall()[0]]: - self.assertIsInstance(len(entry), int) - self.assertEqual(len(entry), 9) - - - def test_recordIndexable(self): - """ - The shadow user record returned by I{getpwnam} and I{getspall} is - indexable, with successive indexes starting from 0 corresponding to the - values of the C{sp_nam}, C{sp_pwd}, C{sp_lstchg}, C{sp_min}, C{sp_max}, - C{sp_warn}, C{sp_inact}, C{sp_expire}, and C{sp_flag} attributes, - respectively. - """ - db = self.database - (username, password, lastChange, min, max, warn, inact, expire, - flag) = self.getExistingUserInfo() - for entry in [db.getspnam(username), db.getspall()[0]]: - self.assertEqual(entry[0], username) - self.assertEqual(entry[1], password) - self.assertEqual(entry[2], lastChange) - self.assertEqual(entry[3], min) - self.assertEqual(entry[4], max) - self.assertEqual(entry[5], warn) - self.assertEqual(entry[6], inact) - self.assertEqual(entry[7], expire) - self.assertEqual(entry[8], flag) - - self.assertEqual(len(entry), len(list(entry))) - self.assertRaises(IndexError, getitem, entry, 9) - - - -class ShadowDatabaseTests(TestCase, ShadowDatabaseTestsMixin): - """ - Tests for L{ShadowDatabase}. - """ - def setUp(self): - """ - Create a L{ShadowDatabase} with no user data in it. - """ - self.database = ShadowDatabase() - self._counter = 0 - - - def getExistingUserInfo(self): - """ - Add a new user to C{self.database} and return its information. - """ - self._counter += 1 - suffix = '_' + str(self._counter) - username = 'username' + suffix - password = 'password' + suffix - lastChange = self._counter + 1 - min = self._counter + 2 - max = self._counter + 3 - warn = self._counter + 4 - inact = self._counter + 5 - expire = self._counter + 6 - flag = self._counter + 7 - - self.database.addUser(username, password, lastChange, min, max, warn, - inact, expire, flag) - return (username, password, lastChange, min, max, warn, inact, - expire, flag) - - - def test_addUser(self): - """ - L{UserDatabase.addUser} accepts seven arguments, one for each field of - a L{pwd.struct_passwd}, and makes the new record available via - L{UserDatabase.getpwuid}, L{UserDatabase.getpwnam}, and - L{UserDatabase.getpwall}. - """ - username = 'alice' - password = 'secr3t' - lastChange = 17 - min = 42 - max = 105 - warn = 12 - inact = 3 - expire = 400 - flag = 3 - - db = self.database - db.addUser(username, password, lastChange, min, max, warn, inact, - expire, flag) - - for [entry] in [[db.getspnam(username)], db.getspall()]: - self.assertEqual(entry.sp_nam, username) - self.assertEqual(entry.sp_pwd, password) - self.assertEqual(entry.sp_lstchg, lastChange) - self.assertEqual(entry.sp_min, min) - self.assertEqual(entry.sp_max, max) - self.assertEqual(entry.sp_warn, warn) - self.assertEqual(entry.sp_inact, inact) - self.assertEqual(entry.sp_expire, expire) - self.assertEqual(entry.sp_flag, flag) - - - -class SPwdModuleTests(TestCase, ShadowDatabaseTestsMixin): - """ - L{SPwdModuleTests} runs the tests defined by L{ShadowDatabaseTestsMixin} - against the built-in C{spwd} module. This serves to verify that - L{ShadowDatabase} is really a fake of that API. - """ - if spwd is None: - skip = "Cannot verify ShadowDatabase against spwd without spwd" - elif os.getuid() != 0: - skip = "Cannot access shadow user database except as root" - else: - database = spwd - - def setUp(self): - self._users = iter(self.database.getspall()) - - - def getExistingUserInfo(self): - """ - Read and return the next record from C{self._users}. - """ - return next(self._users) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_hashlib.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_hashlib.py deleted file mode 100644 index 576535d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_hashlib.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.hashlib} -""" -from twisted.trial.unittest import TestCase -from twisted.trial import util - - - -class HashObjectTests(TestCase): - """ - Tests for the hash object APIs presented by L{hashlib}, C{md5} and C{sha1}. - """ - def test_deprecation(self): - """ - Ensure the deprecation of L{twisted.python.hashlib} is working. - """ - __import__('twisted.python.hashlib') - warnings = self.flushWarnings( - offendingFunctions=[self.test_deprecation]) - self.assertIdentical(warnings[0]['category'], DeprecationWarning) - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['message'], - "twisted.python.hashlib was deprecated in " - "Twisted 13.1.0: Please use hashlib from stdlib.") - - - def test_md5(self): - """ - L{hashlib.md5} returns an object which can be used to compute an MD5 - hash as defined by U{RFC 1321}. - """ - from twisted.python.hashlib import md5 - - # Test the result using values from section A.5 of the RFC. - self.assertEqual( - md5().hexdigest(), "d41d8cd98f00b204e9800998ecf8427e") - self.assertEqual( - md5("a").hexdigest(), "0cc175b9c0f1b6a831c399e269772661") - self.assertEqual( - md5("abc").hexdigest(), "900150983cd24fb0d6963f7d28e17f72") - self.assertEqual( - md5("message digest").hexdigest(), - "f96b697d7cb7938d525a2f31aaf161d0") - self.assertEqual( - md5("abcdefghijklmnopqrstuvwxyz").hexdigest(), - "c3fcd3d76192e4007dfb496cca67e13b") - self.assertEqual( - md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789").hexdigest(), - "d174ab98d277d9f5a5611c2c9f419d9f") - self.assertEqual( - md5("1234567890123456789012345678901234567890123456789012345678901" - "2345678901234567890").hexdigest(), - "57edf4a22be3c955ac49da2e2107b67a") - - # It should have digest and update methods, too. - self.assertEqual( - md5().digest().encode('hex'), - "d41d8cd98f00b204e9800998ecf8427e") - hash = md5() - hash.update("a") - self.assertEqual( - hash.digest().encode('hex'), - "0cc175b9c0f1b6a831c399e269772661") - - # Instances of it should have a digest_size attribute - self.assertEqual(md5().digest_size, 16) - test_md5.suppress = [util.suppress(message="twisted.python.hashlib" - "was deprecated in Twisted 13.1.0: Please use hashlib from stdlib.")] - - - def test_sha1(self): - """ - L{hashlib.sha1} returns an object which can be used to compute a SHA1 - hash as defined by U{RFC 3174}. - """ - - from twisted.python.hashlib import sha1 - - def format(s): - return ''.join(s.split()).lower() - # Test the result using values from section 7.3 of the RFC. - self.assertEqual( - sha1("abc").hexdigest(), - format( - "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D")) - self.assertEqual( - sha1("abcdbcdecdefdefgefghfghighijhi" - "jkijkljklmklmnlmnomnopnopq").hexdigest(), - format( - "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1")) - - # It should have digest and update methods, too. - self.assertEqual( - sha1("abc").digest().encode('hex'), - format( - "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D")) - hash = sha1() - hash.update("abc") - self.assertEqual( - hash.digest().encode('hex'), - format( - "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D")) - - # Instances of it should have a digest_size attribute. - self.assertEqual( - sha1().digest_size, 20) - test_sha1.suppress = [util.suppress(message="twisted.python.hashlib" - "was deprecated in Twisted 13.1.0: Please use hashlib from stdlib.")] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_htmlizer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_htmlizer.py deleted file mode 100644 index 38e607a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_htmlizer.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.htmlizer}. -""" - -from StringIO import StringIO - -from twisted.trial.unittest import TestCase -from twisted.python.htmlizer import filter - - -class FilterTests(TestCase): - """ - Tests for L{twisted.python.htmlizer.filter}. - """ - def test_empty(self): - """ - If passed an empty input file, L{filter} writes a I{pre} tag containing - only an end marker to the output file. - """ - input = StringIO("") - output = StringIO() - filter(input, output) - self.assertEqual(output.getvalue(), '
\n') - - - def test_variable(self): - """ - If passed an input file containing a variable access, L{filter} writes - a I{pre} tag containing a I{py-src-variable} span containing the - variable. - """ - input = StringIO("foo\n") - output = StringIO() - filter(input, output) - self.assertEqual( - output.getvalue(), - '
foo\n'
-            '
\n') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_inotify.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_inotify.py deleted file mode 100644 index a6cea65..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_inotify.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python._inotify}. -""" - -from twisted.trial.unittest import TestCase -from twisted.python.runtime import platform - -if platform.supportsINotify(): - from ctypes import c_int, c_uint32, c_char_p - from twisted.python import _inotify - from twisted.python._inotify import ( - INotifyError, initializeModule, init, add) -else: - _inotify = None - - - -class INotifyTests(TestCase): - """ - Tests for L{twisted.python._inotify}. - """ - if _inotify is None: - skip = "This platform doesn't support INotify." - - def test_missingInit(self): - """ - If the I{libc} object passed to L{initializeModule} has no - C{inotify_init} attribute, L{ImportError} is raised. - """ - class libc: - def inotify_add_watch(self): - pass - def inotify_rm_watch(self): - pass - self.assertRaises(ImportError, initializeModule, libc()) - - - def test_missingAdd(self): - """ - If the I{libc} object passed to L{initializeModule} has no - C{inotify_add_watch} attribute, L{ImportError} is raised. - """ - class libc: - def inotify_init(self): - pass - def inotify_rm_watch(self): - pass - self.assertRaises(ImportError, initializeModule, libc()) - - - def test_missingRemove(self): - """ - If the I{libc} object passed to L{initializeModule} has no - C{inotify_rm_watch} attribute, L{ImportError} is raised. - """ - class libc: - def inotify_init(self): - pass - def inotify_add_watch(self): - pass - self.assertRaises(ImportError, initializeModule, libc()) - - - def test_setTypes(self): - """ - If the I{libc} object passed to L{initializeModule} has all of the - necessary attributes, it sets the C{argtypes} and C{restype} attributes - of the three ctypes methods used from libc. - """ - class libc: - def inotify_init(self): - pass - inotify_init = staticmethod(inotify_init) - - def inotify_rm_watch(self): - pass - inotify_rm_watch = staticmethod(inotify_rm_watch) - - def inotify_add_watch(self): - pass - inotify_add_watch = staticmethod(inotify_add_watch) - - c = libc() - initializeModule(c) - self.assertEqual(c.inotify_init.argtypes, []) - self.assertEqual(c.inotify_init.restype, c_int) - - self.assertEqual(c.inotify_rm_watch.argtypes, [c_int, c_int]) - self.assertEqual(c.inotify_rm_watch.restype, c_int) - - self.assertEqual( - c.inotify_add_watch.argtypes, [c_int, c_char_p, c_uint32]) - self.assertEqual(c.inotify_add_watch.restype, c_int) - - - def test_failedInit(self): - """ - If C{inotify_init} returns a negative number, L{init} raises - L{INotifyError}. - """ - class libc: - def inotify_init(self): - return -1 - self.patch(_inotify, 'libc', libc()) - self.assertRaises(INotifyError, init) - - - def test_failedAddWatch(self): - """ - If C{inotify_add_watch} returns a negative number, L{add} - raises L{INotifyError}. - """ - class libc: - def inotify_add_watch(self, fd, path, mask): - return -1 - self.patch(_inotify, 'libc', libc()) - self.assertRaises(INotifyError, add, 3, '/foo', 0) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_release.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_release.py deleted file mode 100644 index 312f95b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_release.py +++ /dev/null @@ -1,1982 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.release} and L{twisted.python._release}. - -All of these tests are skipped on platforms other than Linux, as the release is -only ever performed on Linux. -""" - - -import glob -import operator -import os -import sys -import textwrap -from StringIO import StringIO -import tarfile -from datetime import date - -from twisted.trial.unittest import TestCase - -from twisted.python.compat import execfile -from twisted.python.procutils import which -from twisted.python import release -from twisted.python.filepath import FilePath -from twisted.python.versions import Version - -from twisted.web.microdom import parseXMLString -from twisted.python._release import ( - _changeVersionInFile, getNextVersion, findTwistedProjects, replaceInFile, - replaceProjectVersion, Project, generateVersionFileData, - changeAllProjectVersions, VERSION_OFFSET, filePathDelta, CommandFailed, - DistributionBuilder, APIBuilder, BuildAPIDocsScript, buildAllTarballs, - runCommand, UncleanWorkingDirectory, NotWorkingDirectory, - ChangeVersionsScript, BuildTarballsScript, NewsBuilder, SphinxBuilder) - -if os.name != 'posix': - skip = "Release toolchain only supported on POSIX." -else: - skip = None - -testingSphinxConf = "master_doc = 'index'\n" - -try: - import pydoctor.driver - # it might not be installed, or it might use syntax not available in - # this version of Python. -except (ImportError, SyntaxError): - pydoctorSkip = "Pydoctor is not present." -else: - if getattr(pydoctor, "version_info", (0,)) < (0, 1): - pydoctorSkip = "Pydoctor is too old." - else: - pydoctorSkip = skip - - -if which("sphinx-build"): - sphinxSkip = None -else: - sphinxSkip = "Sphinx not available." - - - -if which("svn") and which("svnadmin"): - svnSkip = skip -else: - svnSkip = "svn or svnadmin is not present." - - - -def genVersion(*args, **kwargs): - """ - A convenience for generating _version.py data. - - @param args: Arguments to pass to L{Version}. - @param kwargs: Keyword arguments to pass to L{Version}. - """ - return generateVersionFileData(Version(*args, **kwargs)) - - - -class StructureAssertingMixin(object): - """ - A mixin for L{TestCase} subclasses which provides some methods for - asserting the structure and contents of directories and files on the - filesystem. - """ - def createStructure(self, root, dirDict): - """ - Create a set of directories and files given a dict defining their - structure. - - @param root: The directory in which to create the structure. It must - already exist. - @type root: L{FilePath} - - @param dirDict: The dict defining the structure. Keys should be strings - naming files, values should be strings describing file contents OR - dicts describing subdirectories. All files are written in binary - mode. Any string values are assumed to describe text files and - will have their newlines replaced with the platform-native newline - convention. For example:: - - {"foofile": "foocontents", - "bardir": {"barfile": "bar\ncontents"}} - @type dirDict: C{dict} - """ - for x in dirDict: - child = root.child(x) - if isinstance(dirDict[x], dict): - child.createDirectory() - self.createStructure(child, dirDict[x]) - else: - child.setContent(dirDict[x].replace('\n', os.linesep)) - - def assertStructure(self, root, dirDict): - """ - Assert that a directory is equivalent to one described by a dict. - - @param root: The filesystem directory to compare. - @type root: L{FilePath} - @param dirDict: The dict that should describe the contents of the - directory. It should be the same structure as the C{dirDict} - parameter to L{createStructure}. - @type dirDict: C{dict} - """ - children = [each.basename() for each in root.children()] - for pathSegment, expectation in dirDict.items(): - child = root.child(pathSegment) - if callable(expectation): - self.assertTrue(expectation(child)) - elif isinstance(expectation, dict): - self.assertTrue(child.isdir(), "%s is not a dir!" - % (child.path,)) - self.assertStructure(child, expectation) - else: - actual = child.getContent().replace(os.linesep, '\n') - self.assertEqual(actual, expectation) - children.remove(pathSegment) - if children: - self.fail("There were extra children in %s: %s" - % (root.path, children)) - - - def assertExtractedStructure(self, outputFile, dirDict): - """ - Assert that a tarfile content is equivalent to one described by a dict. - - @param outputFile: The tar file built by L{DistributionBuilder}. - @type outputFile: L{FilePath}. - @param dirDict: The dict that should describe the contents of the - directory. It should be the same structure as the C{dirDict} - parameter to L{createStructure}. - @type dirDict: C{dict} - """ - tarFile = tarfile.TarFile.open(outputFile.path, "r:bz2") - extracted = FilePath(self.mktemp()) - extracted.createDirectory() - for info in tarFile: - tarFile.extract(info, path=extracted.path) - self.assertStructure(extracted.children()[0], dirDict) - - - -class ChangeVersionTests(TestCase, StructureAssertingMixin): - """ - Twisted has the ability to change versions. - """ - - def makeFile(self, relativePath, content): - """ - Create a file with the given content relative to a temporary directory. - - @param relativePath: The basename of the file to create. - @param content: The content that the file will have. - @return: The filename. - """ - baseDirectory = FilePath(self.mktemp()) - directory, filename = os.path.split(relativePath) - directory = baseDirectory.preauthChild(directory) - directory.makedirs() - file = directory.child(filename) - directory.child(filename).setContent(content) - return file - - - def test_getNextVersion(self): - """ - When calculating the next version to release when a release is - happening in the same year as the last release, the minor version - number is incremented. - """ - now = date.today() - major = now.year - VERSION_OFFSET - version = Version("twisted", major, 9, 0) - self.assertEqual( - getNextVersion(version, prerelease=False, patch=False, today=now), - Version("twisted", major, 10, 0)) - - - def test_getNextVersionAfterYearChange(self): - """ - When calculating the next version to release when a release is - happening in a later year, the minor version number is reset to 0. - """ - now = date.today() - major = now.year - VERSION_OFFSET - version = Version("twisted", major - 1, 9, 0) - self.assertEqual( - getNextVersion(version, prerelease=False, patch=False, today=now), - Version("twisted", major, 0, 0)) - - - def test_getNextVersionPreRelease(self): - """ - L{getNextVersion} updates the major to the current year, and resets the - minor when creating a pre-release. - """ - now = date.today() - major = now.year - VERSION_OFFSET - version = Version("twisted", 3, 9, 0) - self.assertEqual( - getNextVersion(version, prerelease=True, patch=False, today=now), - Version("twisted", major, 0, 0, 1)) - - - def test_getNextVersionFinalRelease(self): - """ - L{getNextVersion} resets the pre-release count when making a final - release after a pre-release. - """ - now = date.today() - version = Version("twisted", 3, 9, 0, 1) - self.assertEqual( - getNextVersion(version, prerelease=False, patch=False, today=now), - Version("twisted", 3, 9, 0)) - - - def test_getNextVersionNextPreRelease(self): - """ - L{getNextVersion} just increments the pre-release number when operating - on a pre-release. - """ - now = date.today() - version = Version("twisted", 3, 9, 1, 1) - self.assertEqual( - getNextVersion(version, prerelease=True, patch=False, today=now), - Version("twisted", 3, 9, 1, 2)) - - - def test_getNextVersionPatchRelease(self): - """ - L{getNextVersion} sets the micro number when creating a patch release. - """ - now = date.today() - version = Version("twisted", 3, 9, 0) - self.assertEqual( - getNextVersion(version, prerelease=False, patch=True, today=now), - Version("twisted", 3, 9, 1)) - - - def test_getNextVersionNextPatchRelease(self): - """ - L{getNextVersion} just increments the micro number when creating a - patch release. - """ - now = date.today() - version = Version("twisted", 3, 9, 1) - self.assertEqual( - getNextVersion(version, prerelease=False, patch=True, today=now), - Version("twisted", 3, 9, 2)) - - - def test_getNextVersionNextPatchPreRelease(self): - """ - L{getNextVersion} updates both the micro version and the pre-release - count when making a patch pre-release. - """ - now = date.today() - version = Version("twisted", 3, 9, 1) - self.assertEqual( - getNextVersion(version, prerelease=True, patch=True, today=now), - Version("twisted", 3, 9, 2, 1)) - - - def test_changeVersionInFile(self): - """ - _changeVersionInFile replaces the old version information in a file - with the given new version information. - """ - # The version numbers are arbitrary, the name is only kind of - # arbitrary. - packageName = 'foo' - oldVersion = Version(packageName, 2, 5, 0) - file = self.makeFile('README', - "Hello and welcome to %s." % oldVersion.base()) - - newVersion = Version(packageName, 7, 6, 0) - _changeVersionInFile(oldVersion, newVersion, file.path) - - self.assertEqual(file.getContent(), - "Hello and welcome to %s." % newVersion.base()) - - - def test_changeAllProjectVersions(self): - """ - L{changeAllProjectVersions} changes all version numbers in _version.py - and README files for all projects as well as in the top-level - README file. - """ - root = FilePath(self.mktemp()) - root.createDirectory() - structure = { - "README": "Hi this is 1.0.0.", - "twisted": { - "topfiles": { - "README": "Hi this is 1.0.0"}, - "_version.py": genVersion("twisted", 1, 0, 0), - "web": { - "topfiles": { - "README": "Hi this is 1.0.0"}, - "_version.py": genVersion("twisted.web", 1, 0, 0)}}} - self.createStructure(root, structure) - releaseDate = date(2010, 1, 1) - changeAllProjectVersions(root, False, False, releaseDate) - outStructure = { - "README": "Hi this is 10.0.0.", - "twisted": { - "topfiles": { - "README": "Hi this is 10.0.0"}, - "_version.py": genVersion("twisted", 10, 0, 0), - "web": { - "topfiles": { - "README": "Hi this is 10.0.0"}, - "_version.py": genVersion("twisted.web", 10, 0, 0)}}} - self.assertStructure(root, outStructure) - - - def test_changeAllProjectVersionsPreRelease(self): - """ - L{changeAllProjectVersions} changes all version numbers in _version.py - and README files for all projects as well as in the top-level - README file. If the old version was a pre-release, it will change the - version in NEWS files as well. - """ - root = FilePath(self.mktemp()) - root.createDirectory() - coreNews = ("Twisted Core 1.0.0 (2009-12-25)\n" - "===============================\n" - "\n") - webNews = ("Twisted Web 1.0.0pre1 (2009-12-25)\n" - "==================================\n" - "\n") - structure = { - "README": "Hi this is 1.0.0.", - "NEWS": coreNews + webNews, - "twisted": { - "topfiles": { - "README": "Hi this is 1.0.0", - "NEWS": coreNews}, - "_version.py": genVersion("twisted", 1, 0, 0), - "web": { - "topfiles": { - "README": "Hi this is 1.0.0pre1", - "NEWS": webNews}, - "_version.py": genVersion("twisted.web", 1, 0, 0, 1)}}} - self.createStructure(root, structure) - releaseDate = date(2010, 1, 1) - changeAllProjectVersions(root, False, False, releaseDate) - coreNews = ("Twisted Core 1.0.0 (2009-12-25)\n" - "===============================\n" - "\n") - webNews = ("Twisted Web 1.0.0 (2010-01-01)\n" - "==============================\n" - "\n") - outStructure = { - "README": "Hi this is 10.0.0.", - "NEWS": coreNews + webNews, - "twisted": { - "topfiles": { - "README": "Hi this is 10.0.0", - "NEWS": coreNews}, - "_version.py": genVersion("twisted", 10, 0, 0), - "web": { - "topfiles": { - "README": "Hi this is 1.0.0", - "NEWS": webNews}, - "_version.py": genVersion("twisted.web", 1, 0, 0)}}} - self.assertStructure(root, outStructure) - - - -class ProjectTests(TestCase): - """ - There is a first-class representation of a project. - """ - - def assertProjectsEqual(self, observedProjects, expectedProjects): - """ - Assert that two lists of L{Project}s are equal. - """ - self.assertEqual(len(observedProjects), len(expectedProjects)) - observedProjects = sorted(observedProjects, - key=operator.attrgetter('directory')) - expectedProjects = sorted(expectedProjects, - key=operator.attrgetter('directory')) - for observed, expected in zip(observedProjects, expectedProjects): - self.assertEqual(observed.directory, expected.directory) - - - def makeProject(self, version, baseDirectory=None): - """ - Make a Twisted-style project in the given base directory. - - @param baseDirectory: The directory to create files in - (as a L{FilePath). - @param version: The version information for the project. - @return: L{Project} pointing to the created project. - """ - if baseDirectory is None: - baseDirectory = FilePath(self.mktemp()) - baseDirectory.createDirectory() - segments = version.package.split('.') - directory = baseDirectory - for segment in segments: - directory = directory.child(segment) - if not directory.exists(): - directory.createDirectory() - directory.child('__init__.py').setContent('') - directory.child('topfiles').createDirectory() - directory.child('topfiles').child('README').setContent(version.base()) - replaceProjectVersion( - directory.child('_version.py').path, version) - return Project(directory) - - - def makeProjects(self, *versions): - """ - Create a series of projects underneath a temporary base directory. - - @return: A L{FilePath} for the base directory. - """ - baseDirectory = FilePath(self.mktemp()) - baseDirectory.createDirectory() - for version in versions: - self.makeProject(version, baseDirectory) - return baseDirectory - - - def test_getVersion(self): - """ - Project objects know their version. - """ - version = Version('foo', 2, 1, 0) - project = self.makeProject(version) - self.assertEqual(project.getVersion(), version) - - - def test_updateVersion(self): - """ - Project objects know how to update the version numbers in those - projects. - """ - project = self.makeProject(Version("bar", 2, 1, 0)) - newVersion = Version("bar", 3, 2, 9) - project.updateVersion(newVersion) - self.assertEqual(project.getVersion(), newVersion) - self.assertEqual( - project.directory.child("topfiles").child("README").getContent(), - "3.2.9") - - - def test_repr(self): - """ - The representation of a Project is Project(directory). - """ - foo = Project(FilePath('bar')) - self.assertEqual( - repr(foo), 'Project(%r)' % (foo.directory)) - - - def test_findTwistedStyleProjects(self): - """ - findTwistedStyleProjects finds all projects underneath a particular - directory. A 'project' is defined by the existence of a 'topfiles' - directory and is returned as a Project object. - """ - baseDirectory = self.makeProjects( - Version('foo', 2, 3, 0), Version('foo.bar', 0, 7, 4)) - projects = findTwistedProjects(baseDirectory) - self.assertProjectsEqual( - projects, - [Project(baseDirectory.child('foo')), - Project(baseDirectory.child('foo').child('bar'))]) - - - -class UtilityTests(TestCase): - """ - Tests for various utility functions for releasing. - """ - - def test_chdir(self): - """ - Test that the runChdirSafe is actually safe, i.e., it still - changes back to the original directory even if an error is - raised. - """ - cwd = os.getcwd() - - def chAndBreak(): - os.mkdir('releaseCh') - os.chdir('releaseCh') - 1 // 0 - - self.assertRaises(ZeroDivisionError, - release.runChdirSafe, chAndBreak) - self.assertEqual(cwd, os.getcwd()) - - - - def test_replaceInFile(self): - """ - L{replaceInFile} replaces data in a file based on a dict. A key from - the dict that is found in the file is replaced with the corresponding - value. - """ - content = 'foo\nhey hey $VER\nbar\n' - outf = open('release.replace', 'w') - outf.write(content) - outf.close() - - expected = content.replace('$VER', '2.0.0') - replaceInFile('release.replace', {'$VER': '2.0.0'}) - self.assertEqual(open('release.replace').read(), expected) - - - expected = expected.replace('2.0.0', '3.0.0') - replaceInFile('release.replace', {'2.0.0': '3.0.0'}) - self.assertEqual(open('release.replace').read(), expected) - - - -class VersionWritingTests(TestCase): - """ - Tests for L{replaceProjectVersion}. - """ - - def test_replaceProjectVersion(self): - """ - L{replaceProjectVersion} writes a Python file that defines a - C{version} variable that corresponds to the given name and version - number. - """ - replaceProjectVersion("test_project", - Version("twisted.test_project", 0, 82, 7)) - ns = {'__name___': 'twisted.test_project'} - execfile("test_project", ns) - self.assertEqual(ns["version"].base(), "0.82.7") - - - def test_replaceProjectVersionWithPrerelease(self): - """ - L{replaceProjectVersion} will write a Version instantiation that - includes a prerelease parameter if necessary. - """ - replaceProjectVersion("test_project", - Version("twisted.test_project", 0, 82, 7, - prerelease=8)) - ns = {'__name___': 'twisted.test_project'} - execfile("test_project", ns) - self.assertEqual(ns["version"].base(), "0.82.7pre8") - - - -class APIBuilderTests(TestCase): - """ - Tests for L{APIBuilder}. - """ - skip = pydoctorSkip - - def test_build(self): - """ - L{APIBuilder.build} writes an index file which includes the name of the - project specified. - """ - stdout = StringIO() - self.patch(sys, 'stdout', stdout) - - projectName = "Foobar" - packageName = "quux" - projectURL = "scheme:project" - sourceURL = "scheme:source" - docstring = "text in docstring" - privateDocstring = "should also appear in output" - - inputPath = FilePath(self.mktemp()).child(packageName) - inputPath.makedirs() - inputPath.child("__init__.py").setContent( - "def foo():\n" - " '%s'\n" - "def _bar():\n" - " '%s'" % (docstring, privateDocstring)) - - outputPath = FilePath(self.mktemp()) - outputPath.makedirs() - - builder = APIBuilder() - builder.build(projectName, projectURL, sourceURL, inputPath, - outputPath) - - indexPath = outputPath.child("index.html") - self.assertTrue( - indexPath.exists(), - "API index %r did not exist." % (outputPath.path,)) - self.assertIn( - '
%s' % (projectURL, projectName), - indexPath.getContent(), - "Project name/location not in file contents.") - - quuxPath = outputPath.child("quux.html") - self.assertTrue( - quuxPath.exists(), - "Package documentation file %r did not exist." % (quuxPath.path,)) - self.assertIn( - docstring, quuxPath.getContent(), - "Docstring not in package documentation file.") - self.assertIn( - 'View Source' % (sourceURL, packageName), - quuxPath.getContent()) - self.assertIn( - '' % ( - sourceURL, packageName), - quuxPath.getContent()) - self.assertIn(privateDocstring, quuxPath.getContent()) - - # There should also be a page for the foo function in quux. - self.assertTrue(quuxPath.sibling('quux.foo.html').exists()) - - self.assertEqual(stdout.getvalue(), '') - - - def test_buildWithPolicy(self): - """ - L{BuildAPIDocsScript.buildAPIDocs} builds the API docs with values - appropriate for the Twisted project. - """ - stdout = StringIO() - self.patch(sys, 'stdout', stdout) - docstring = "text in docstring" - - projectRoot = FilePath(self.mktemp()) - packagePath = projectRoot.child("twisted") - packagePath.makedirs() - packagePath.child("__init__.py").setContent( - "def foo():\n" - " '%s'\n" % (docstring,)) - packagePath.child("_version.py").setContent( - genVersion("twisted", 1, 0, 0)) - outputPath = FilePath(self.mktemp()) - - script = BuildAPIDocsScript() - script.buildAPIDocs(projectRoot, outputPath) - - indexPath = outputPath.child("index.html") - self.assertTrue( - indexPath.exists(), - "API index %r did not exist." % (outputPath.path,)) - self.assertIn( - 'Twisted', - indexPath.getContent(), - "Project name/location not in file contents.") - - twistedPath = outputPath.child("twisted.html") - self.assertTrue( - twistedPath.exists(), - "Package documentation file %r did not exist." - % (twistedPath.path,)) - self.assertIn( - docstring, twistedPath.getContent(), - "Docstring not in package documentation file.") - #Here we check that it figured out the correct version based on the - #source code. - self.assertIn( - 'View Source', - twistedPath.getContent()) - - self.assertEqual(stdout.getvalue(), '') - - - def test_apiBuilderScriptMainRequiresTwoArguments(self): - """ - SystemExit is raised when the incorrect number of command line - arguments are passed to the API building script. - """ - script = BuildAPIDocsScript() - self.assertRaises(SystemExit, script.main, []) - self.assertRaises(SystemExit, script.main, ["foo"]) - self.assertRaises(SystemExit, script.main, ["foo", "bar", "baz"]) - - - def test_apiBuilderScriptMain(self): - """ - The API building script invokes the same code that - L{test_buildWithPolicy} tests. - """ - script = BuildAPIDocsScript() - calls = [] - script.buildAPIDocs = lambda a, b: calls.append((a, b)) - script.main(["hello", "there"]) - self.assertEqual(calls, [(FilePath("hello"), FilePath("there"))]) - - - -class FilePathDeltaTests(TestCase): - """ - Tests for L{filePathDelta}. - """ - - def test_filePathDeltaSubdir(self): - """ - L{filePathDelta} can create a simple relative path to a child path. - """ - self.assertEqual(filePathDelta(FilePath("/foo/bar"), - FilePath("/foo/bar/baz")), - ["baz"]) - - - def test_filePathDeltaSiblingDir(self): - """ - L{filePathDelta} can traverse upwards to create relative paths to - siblings. - """ - self.assertEqual(filePathDelta(FilePath("/foo/bar"), - FilePath("/foo/baz")), - ["..", "baz"]) - - - def test_filePathNoCommonElements(self): - """ - L{filePathDelta} can create relative paths to totally unrelated paths - for maximum portability. - """ - self.assertEqual(filePathDelta(FilePath("/foo/bar"), - FilePath("/baz/quux")), - ["..", "..", "baz", "quux"]) - - - def test_filePathDeltaSimilarEndElements(self): - """ - L{filePathDelta} doesn't take into account final elements when - comparing 2 paths, but stops at the first difference. - """ - self.assertEqual(filePathDelta(FilePath("/foo/bar/bar/spam"), - FilePath("/foo/bar/baz/spam")), - ["..", "..", "baz", "spam"]) - - - -class NewsBuilderTests(TestCase, StructureAssertingMixin): - """ - Tests for L{NewsBuilder}. - """ - skip = svnSkip - - def setUp(self): - """ - Create a fake project and stuff some basic structure and content into - it. - """ - self.builder = NewsBuilder() - self.project = FilePath(self.mktemp()) - self.project.createDirectory() - - self.existingText = 'Here is stuff which was present previously.\n' - self.createStructure( - self.project, { - 'NEWS': self.existingText, - '5.feature': 'We now support the web.\n', - '12.feature': 'The widget is more robust.\n', - '15.feature': ( - 'A very long feature which takes many words to ' - 'describe with any accuracy was introduced so that ' - 'the line wrapping behavior of the news generating ' - 'code could be verified.\n'), - '16.feature': ( - 'A simpler feature\ndescribed on multiple lines\n' - 'was added.\n'), - '23.bugfix': 'Broken stuff was fixed.\n', - '25.removal': 'Stupid stuff was deprecated.\n', - '30.misc': '', - '35.misc': '', - '40.doc': 'foo.bar.Baz.quux', - '41.doc': 'writing Foo servers'}) - - - def svnCommit(self, project=None): - """ - Make the C{project} directory a valid subversion directory with all - files committed. - """ - if project is None: - project = self.project - repositoryPath = self.mktemp() - repository = FilePath(repositoryPath) - - runCommand(["svnadmin", "create", repository.path]) - runCommand(["svn", "checkout", "file://" + repository.path, - project.path]) - - runCommand(["svn", "add"] + glob.glob(project.path + "/*")) - runCommand(["svn", "commit", project.path, "-m", "yay"]) - - - def test_today(self): - """ - L{NewsBuilder._today} returns today's date in YYYY-MM-DD form. - """ - self.assertEqual( - self.builder._today(), date.today().strftime('%Y-%m-%d')) - - - def test_findFeatures(self): - """ - When called with L{NewsBuilder._FEATURE}, L{NewsBuilder._findChanges} - returns a list of bugfix ticket numbers and descriptions as a list of - two-tuples. - """ - features = self.builder._findChanges( - self.project, self.builder._FEATURE) - self.assertEqual( - features, - [(5, "We now support the web."), - (12, "The widget is more robust."), - (15, - "A very long feature which takes many words to describe with " - "any accuracy was introduced so that the line wrapping behavior " - "of the news generating code could be verified."), - (16, "A simpler feature described on multiple lines was added.")]) - - - def test_findBugfixes(self): - """ - When called with L{NewsBuilder._BUGFIX}, L{NewsBuilder._findChanges} - returns a list of bugfix ticket numbers and descriptions as a list of - two-tuples. - """ - bugfixes = self.builder._findChanges( - self.project, self.builder._BUGFIX) - self.assertEqual( - bugfixes, - [(23, 'Broken stuff was fixed.')]) - - - def test_findRemovals(self): - """ - When called with L{NewsBuilder._REMOVAL}, L{NewsBuilder._findChanges} - returns a list of removal/deprecation ticket numbers and descriptions - as a list of two-tuples. - """ - removals = self.builder._findChanges( - self.project, self.builder._REMOVAL) - self.assertEqual( - removals, - [(25, 'Stupid stuff was deprecated.')]) - - - def test_findDocumentation(self): - """ - When called with L{NewsBuilder._DOC}, L{NewsBuilder._findChanges} - returns a list of documentation ticket numbers and descriptions as a - list of two-tuples. - """ - doc = self.builder._findChanges( - self.project, self.builder._DOC) - self.assertEqual( - doc, - [(40, 'foo.bar.Baz.quux'), - (41, 'writing Foo servers')]) - - - def test_findMiscellaneous(self): - """ - When called with L{NewsBuilder._MISC}, L{NewsBuilder._findChanges} - returns a list of removal/deprecation ticket numbers and descriptions - as a list of two-tuples. - """ - misc = self.builder._findChanges( - self.project, self.builder._MISC) - self.assertEqual( - misc, - [(30, ''), - (35, '')]) - - - def test_writeHeader(self): - """ - L{NewsBuilder._writeHeader} accepts a file-like object opened for - writing and a header string and writes out a news file header to it. - """ - output = StringIO() - self.builder._writeHeader(output, "Super Awesometastic 32.16") - self.assertEqual( - output.getvalue(), - "Super Awesometastic 32.16\n" - "=========================\n" - "\n") - - - def test_writeSection(self): - """ - L{NewsBuilder._writeSection} accepts a file-like object opened for - writing, a section name, and a list of ticket information (as returned - by L{NewsBuilder._findChanges}) and writes out a section header and all - of the given ticket information. - """ - output = StringIO() - self.builder._writeSection( - output, "Features", - [(3, "Great stuff."), - (17, "Very long line which goes on and on and on, seemingly " - "without end until suddenly without warning it does end.")]) - self.assertEqual( - output.getvalue(), - "Features\n" - "--------\n" - " - Great stuff. (#3)\n" - " - Very long line which goes on and on and on, seemingly " - "without end\n" - " until suddenly without warning it does end. (#17)\n" - "\n") - - - def test_writeMisc(self): - """ - L{NewsBuilder._writeMisc} accepts a file-like object opened for - writing, a section name, and a list of ticket information (as returned - by L{NewsBuilder._findChanges} and writes out a section header and all - of the ticket numbers, but excludes any descriptions. - """ - output = StringIO() - self.builder._writeMisc( - output, "Other", - [(x, "") for x in range(2, 50, 3)]) - self.assertEqual( - output.getvalue(), - "Other\n" - "-----\n" - " - #2, #5, #8, #11, #14, #17, #20, #23, #26, #29, #32, #35, " - "#38, #41,\n" - " #44, #47\n" - "\n") - - - def test_build(self): - """ - L{NewsBuilder.build} updates a NEWS file with new features based on the - I{.feature} files found in the directory specified. - """ - self.builder.build( - self.project, self.project.child('NEWS'), - "Super Awesometastic 32.16") - - results = self.project.child('NEWS').getContent() - self.assertEqual( - results, - 'Super Awesometastic 32.16\n' - '=========================\n' - '\n' - 'Features\n' - '--------\n' - ' - We now support the web. (#5)\n' - ' - The widget is more robust. (#12)\n' - ' - A very long feature which takes many words to describe ' - 'with any\n' - ' accuracy was introduced so that the line wrapping behavior ' - 'of the\n' - ' news generating code could be verified. (#15)\n' - ' - A simpler feature described on multiple lines was ' - 'added. (#16)\n' - '\n' - 'Bugfixes\n' - '--------\n' - ' - Broken stuff was fixed. (#23)\n' - '\n' - 'Improved Documentation\n' - '----------------------\n' - ' - foo.bar.Baz.quux (#40)\n' - ' - writing Foo servers (#41)\n' - '\n' - 'Deprecations and Removals\n' - '-------------------------\n' - ' - Stupid stuff was deprecated. (#25)\n' - '\n' - 'Other\n' - '-----\n' - ' - #30, #35\n' - '\n\n' + self.existingText) - - - def test_emptyProjectCalledOut(self): - """ - If no changes exist for a project, I{NEWS} gains a new section for - that project that includes some helpful text about how there were no - interesting changes. - """ - project = FilePath(self.mktemp()).child("twisted") - project.makedirs() - self.createStructure(project, {'NEWS': self.existingText}) - - self.builder.build( - project, project.child('NEWS'), - "Super Awesometastic 32.16") - results = project.child('NEWS').getContent() - self.assertEqual( - results, - 'Super Awesometastic 32.16\n' - '=========================\n' - '\n' + - self.builder._NO_CHANGES + - '\n\n' + self.existingText) - - - def test_preserveTicketHint(self): - """ - If a I{NEWS} file begins with the two magic lines which point readers - at the issue tracker, those lines are kept at the top of the new file. - """ - news = self.project.child('NEWS') - news.setContent( - 'Ticket numbers in this file can be looked up by visiting\n' - 'http://twistedmatrix.com/trac/ticket/\n' - '\n' - 'Blah blah other stuff.\n') - - self.builder.build(self.project, news, "Super Awesometastic 32.16") - - self.assertEqual( - news.getContent(), - 'Ticket numbers in this file can be looked up by visiting\n' - 'http://twistedmatrix.com/trac/ticket/\n' - '\n' - 'Super Awesometastic 32.16\n' - '=========================\n' - '\n' - 'Features\n' - '--------\n' - ' - We now support the web. (#5)\n' - ' - The widget is more robust. (#12)\n' - ' - A very long feature which takes many words to describe ' - 'with any\n' - ' accuracy was introduced so that the line wrapping behavior ' - 'of the\n' - ' news generating code could be verified. (#15)\n' - ' - A simpler feature described on multiple lines was ' - 'added. (#16)\n' - '\n' - 'Bugfixes\n' - '--------\n' - ' - Broken stuff was fixed. (#23)\n' - '\n' - 'Improved Documentation\n' - '----------------------\n' - ' - foo.bar.Baz.quux (#40)\n' - ' - writing Foo servers (#41)\n' - '\n' - 'Deprecations and Removals\n' - '-------------------------\n' - ' - Stupid stuff was deprecated. (#25)\n' - '\n' - 'Other\n' - '-----\n' - ' - #30, #35\n' - '\n\n' - 'Blah blah other stuff.\n') - - - def test_emptySectionsOmitted(self): - """ - If there are no changes of a particular type (feature, bugfix, etc), no - section for that type is written by L{NewsBuilder.build}. - """ - for ticket in self.project.children(): - if ticket.splitext()[1] in ('.feature', '.misc', '.doc'): - ticket.remove() - - self.builder.build( - self.project, self.project.child('NEWS'), - 'Some Thing 1.2') - - self.assertEqual( - self.project.child('NEWS').getContent(), - 'Some Thing 1.2\n' - '==============\n' - '\n' - 'Bugfixes\n' - '--------\n' - ' - Broken stuff was fixed. (#23)\n' - '\n' - 'Deprecations and Removals\n' - '-------------------------\n' - ' - Stupid stuff was deprecated. (#25)\n' - '\n\n' - 'Here is stuff which was present previously.\n') - - - def test_duplicatesMerged(self): - """ - If two change files have the same contents, they are merged in the - generated news entry. - """ - def feature(s): - return self.project.child(s + '.feature') - feature('5').copyTo(feature('15')) - feature('5').copyTo(feature('16')) - - self.builder.build( - self.project, self.project.child('NEWS'), - 'Project Name 5.0') - - self.assertEqual( - self.project.child('NEWS').getContent(), - 'Project Name 5.0\n' - '================\n' - '\n' - 'Features\n' - '--------\n' - ' - We now support the web. (#5, #15, #16)\n' - ' - The widget is more robust. (#12)\n' - '\n' - 'Bugfixes\n' - '--------\n' - ' - Broken stuff was fixed. (#23)\n' - '\n' - 'Improved Documentation\n' - '----------------------\n' - ' - foo.bar.Baz.quux (#40)\n' - ' - writing Foo servers (#41)\n' - '\n' - 'Deprecations and Removals\n' - '-------------------------\n' - ' - Stupid stuff was deprecated. (#25)\n' - '\n' - 'Other\n' - '-----\n' - ' - #30, #35\n' - '\n\n' - 'Here is stuff which was present previously.\n') - - - def createFakeTwistedProject(self): - """ - Create a fake-looking Twisted project to build from. - """ - project = FilePath(self.mktemp()).child("twisted") - project.makedirs() - self.createStructure( - project, { - 'NEWS': 'Old boring stuff from the past.\n', - '_version.py': genVersion("twisted", 1, 2, 3), - 'topfiles': { - 'NEWS': 'Old core news.\n', - '3.feature': 'Third feature addition.\n', - '5.misc': ''}, - 'conch': { - '_version.py': genVersion("twisted.conch", 3, 4, 5), - 'topfiles': { - 'NEWS': 'Old conch news.\n', - '7.bugfix': 'Fixed that bug.\n'}}}) - return project - - - def test_buildAll(self): - """ - L{NewsBuilder.buildAll} calls L{NewsBuilder.build} once for each - subproject, passing that subproject's I{topfiles} directory as C{path}, - the I{NEWS} file in that directory as C{output}, and the subproject's - name as C{header}, and then again for each subproject with the - top-level I{NEWS} file for C{output}. Blacklisted subprojects are - skipped. - """ - builds = [] - builder = NewsBuilder() - builder.build = lambda path, output, header: builds.append(( - path, output, header)) - builder._today = lambda: '2009-12-01' - - project = self.createFakeTwistedProject() - self.svnCommit(project) - builder.buildAll(project) - - coreTopfiles = project.child("topfiles") - coreNews = coreTopfiles.child("NEWS") - coreHeader = "Twisted Core 1.2.3 (2009-12-01)" - - conchTopfiles = project.child("conch").child("topfiles") - conchNews = conchTopfiles.child("NEWS") - conchHeader = "Twisted Conch 3.4.5 (2009-12-01)" - - aggregateNews = project.child("NEWS") - - self.assertEqual( - builds, - [(conchTopfiles, conchNews, conchHeader), - (conchTopfiles, aggregateNews, conchHeader), - (coreTopfiles, coreNews, coreHeader), - (coreTopfiles, aggregateNews, coreHeader)]) - - - def test_buildAllAggregate(self): - """ - L{NewsBuilder.buildAll} aggregates I{NEWS} information into the top - files, only deleting fragments once it's done. - """ - builder = NewsBuilder() - project = self.createFakeTwistedProject() - self.svnCommit(project) - builder.buildAll(project) - - aggregateNews = project.child("NEWS") - - aggregateContent = aggregateNews.getContent() - self.assertIn("Third feature addition", aggregateContent) - self.assertIn("Fixed that bug", aggregateContent) - self.assertIn("Old boring stuff from the past", aggregateContent) - - - def test_changeVersionInNews(self): - """ - L{NewsBuilder._changeVersions} gets the release date for a given - version of a project as a string. - """ - builder = NewsBuilder() - builder._today = lambda: '2009-12-01' - project = self.createFakeTwistedProject() - self.svnCommit(project) - builder.buildAll(project) - newVersion = Version('TEMPLATE', 7, 7, 14) - coreNews = project.child('topfiles').child('NEWS') - # twisted 1.2.3 is the old version. - builder._changeNewsVersion( - coreNews, "Core", Version("twisted", 1, 2, 3), - newVersion, '2010-01-01') - expectedCore = ( - 'Twisted Core 7.7.14 (2010-01-01)\n' - '================================\n' - '\n' - 'Features\n' - '--------\n' - ' - Third feature addition. (#3)\n' - '\n' - 'Other\n' - '-----\n' - ' - #5\n\n\n') - self.assertEqual( - expectedCore + 'Old core news.\n', coreNews.getContent()) - - - def test_removeNEWSfragments(self): - """ - L{NewsBuilder.buildALL} removes all the NEWS fragments after the build - process, using the C{svn} C{rm} command. - """ - builder = NewsBuilder() - project = self.createFakeTwistedProject() - self.svnCommit(project) - builder.buildAll(project) - - self.assertEqual(5, len(project.children())) - output = runCommand(["svn", "status", project.path]) - removed = [line for line in output.splitlines() - if line.startswith("D ")] - self.assertEqual(3, len(removed)) - - - def test_checkSVN(self): - """ - L{NewsBuilder.buildAll} raises L{NotWorkingDirectory} when the given - path is not a SVN checkout. - """ - self.assertRaises( - NotWorkingDirectory, self.builder.buildAll, self.project) - - - -class SphinxBuilderTests(TestCase): - """ - Tests for L{SphinxBuilder}. - - @note: This test case depends on twisted.web, which violates the standard - Twisted practice of not having anything in twisted.python depend on - other Twisted packages and opens up the possibility of creating - circular dependencies. Do not use this as an example of how to - structure your dependencies. - - @ivar builder: A plain L{SphinxBuilder}. - - @ivar sphinxDir: A L{FilePath} representing a directory to be used for - containing a Sphinx project. - - @ivar sourceDir: A L{FilePath} representing a directory to be used for - containing the source files for a Sphinx project. - """ - skip = sphinxSkip - - confContent = """\ - source_suffix = '.rst' - master_doc = 'index' - """ - confContent = textwrap.dedent(confContent) - - indexContent = """\ - ============== - This is a Test - ============== - - This is only a test - ------------------- - - In case you hadn't figured it out yet, this is a test. - """ - indexContent = textwrap.dedent(indexContent) - - - def setUp(self): - """ - Set up a few instance variables that will be useful. - """ - self.builder = SphinxBuilder() - - # set up a place for a fake sphinx project - self.twistedRootDir = FilePath(self.mktemp()) - self.sphinxDir = self.twistedRootDir.child("docs") - self.sphinxDir.makedirs() - self.sourceDir = self.sphinxDir - - - def createFakeSphinxProject(self): - """ - Create a fake Sphinx project for test purposes. - - Creates a fake Sphinx project with the absolute minimum of source - files. This includes a single source file ('index.rst') and the - smallest 'conf.py' file possible in order to find that source file. - """ - self.sourceDir.child("conf.py").setContent(self.confContent) - self.sourceDir.child("index.rst").setContent(self.indexContent) - - - def verifyFileExists(self, fileDir, fileName): - """ - Helper which verifies that C{fileName} exists in C{fileDir}, has some - content, and that the content is parseable by L{parseXMLString} if the - file extension indicates that it should be html. - - @param fileDir: A path to a directory. - @type fileDir: L{FilePath} - - @param fileName: The last path segment of a file which may exist within - C{fileDir}. - @type fileName: L{str} - - @raise: L{FailTest } if - C{fileDir.child(fileName)}: - - 1. Does not exist. - - 2. Is empty. - - 3. In the case where it's a path to a C{.html} file, the - contents at least look enough like HTML to parse according - to microdom's generous criteria. - - @return: C{None} - """ - # check that file exists - fpath = fileDir.child(fileName) - self.assertTrue(fpath.exists()) - - # check that the output files have some content - fcontents = fpath.getContent() - self.assertTrue(len(fcontents) > 0) - - # check that the html files are at least html-ish - # this is not a terribly rigorous check - if fpath.path.endswith('.html'): - parseXMLString(fcontents) - - - def test_build(self): - """ - Creates and builds a fake Sphinx project using a L{SphinxBuilder}. - """ - self.createFakeSphinxProject() - self.builder.build(self.sphinxDir) - self.verifyBuilt() - - - def test_main(self): - """ - Creates and builds a fake Sphinx project as if via the command line. - """ - self.createFakeSphinxProject() - self.builder.main([self.sphinxDir.parent().path]) - self.verifyBuilt() - - - def verifyBuilt(self): - """ - Verify that a sphinx project has been built. - """ - htmlDir = self.sphinxDir.sibling('doc') - self.assertTrue(htmlDir.isdir()) - doctreeDir = htmlDir.child("doctrees") - self.assertTrue(doctreeDir.isdir()) - - self.verifyFileExists(htmlDir, 'index.html') - self.verifyFileExists(htmlDir, 'genindex.html') - self.verifyFileExists(htmlDir, 'objects.inv') - self.verifyFileExists(htmlDir, 'search.html') - self.verifyFileExists(htmlDir, 'searchindex.js') - - - def test_failToBuild(self): - """ - Check that SphinxBuilder.build fails when run against a non-sphinx - directory. - """ - # note no fake sphinx project is created - self.assertRaises(CommandFailed, - self.builder.build, - self.sphinxDir) - - - -class DistributionBuilderTestBase(StructureAssertingMixin, TestCase): - """ - Base for tests of L{DistributionBuilder}. - """ - - def setUp(self): - self.rootDir = FilePath(self.mktemp()) - self.rootDir.createDirectory() - - self.outputDir = FilePath(self.mktemp()) - self.outputDir.createDirectory() - self.builder = DistributionBuilder(self.rootDir, self.outputDir) - - - -class DistributionBuilderTests(DistributionBuilderTestBase): - - def test_twistedDistribution(self): - """ - The Twisted tarball contains everything in the source checkout, with - built documentation. - """ - manInput1 = "pretend there's some troff in here or something" - structure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"web": {"websetroot": "SET ROOT"}, - "twistd": "TWISTD"}, - "twisted": { - "web": { - "__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}, - "words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG"}}, - "docs": { - "conf.py": testingSphinxConf, - "index.rst": "", - "core": {"man": {"twistd.1": manInput1}} - } - } - - def hasManpagesAndSphinx(path): - self.assertTrue(path.isdir()) - self.assertEqual( - path.child("core").child("man").child("twistd.1").getContent(), - manInput1 - ) - return True - - outStructure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"web": {"websetroot": "SET ROOT"}, - "twistd": "TWISTD"}, - "twisted": { - "web": {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}, - "words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG"}}, - "doc": hasManpagesAndSphinx, - } - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildTwisted("10.0.0") - - self.assertExtractedStructure(outputFile, outStructure) - - test_twistedDistribution.skip = sphinxSkip - - - def test_excluded(self): - """ - bin/admin and doc/historic are excluded from the Twisted tarball. - """ - structure = { - "bin": {"admin": {"blah": "ADMIN"}, - "twistd": "TWISTD"}, - "twisted": { - "web": { - "__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}}, - "doc": {"historic": {"hello": "there"}, - "other": "contents"}} - - outStructure = { - "bin": {"twistd": "TWISTD"}, - "twisted": { - "web": { - "__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}}, - "doc": {"other": "contents"}} - - self.createStructure(self.rootDir, structure) - outputFile = self.builder.buildTwisted("10.0.0") - self.assertExtractedStructure(outputFile, outStructure) - - - def test_subProjectLayout(self): - """ - The subproject tarball includes files like so: - - 1. twisted//topfiles defines the files that will be in the - top level in the tarball, except LICENSE, which comes from the real - top-level directory. - 2. twisted/ is included, but without the topfiles entry - in that directory. No other twisted subpackages are included. - 3. twisted/plugins/twisted_.py is included, but nothing - else in plugins is. - """ - structure = { - "README": "HI!@", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"web": {"websetroot": "SET ROOT"}, - "words": {"im": "#!im"}}, - "twisted": { - "web": { - "__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}, - "words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG"}}} - - outStructure = { - "README": "WEB!", - "LICENSE": "copyright!", - "setup.py": "import WEBINSTALL", - "bin": {"websetroot": "SET ROOT"}, - "twisted": {"web": {"__init__.py": "import WEB"}, - "plugins": {"twisted_web.py": "import WEBPLUG"}}} - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildSubProject("web", "0.3.0") - - self.assertExtractedStructure(outputFile, outStructure) - - - def test_minimalSubProjectLayout(self): - """ - buildSubProject should work with minimal subprojects. - """ - structure = { - "LICENSE": "copyright!", - "bin": {}, - "twisted": { - "web": {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL"}}, - "plugins": {}}} - - outStructure = { - "setup.py": "import WEBINSTALL", - "LICENSE": "copyright!", - "twisted": {"web": {"__init__.py": "import WEB"}}} - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildSubProject("web", "0.3.0") - - self.assertExtractedStructure(outputFile, outStructure) - - - def test_coreProjectLayout(self): - """ - The core tarball looks a lot like a subproject tarball, except it - doesn't include: - - - Python packages from other subprojects - - plugins from other subprojects - - scripts from other subprojects - """ - structure = { - "LICENSE": "copyright!", - "twisted": {"__init__.py": "twisted", - "python": {"__init__.py": "python", - "roots.py": "roots!"}, - "conch": {"__init__.py": "conch", - "unrelated.py": "import conch"}, - "plugin.py": "plugin", - "plugins": {"twisted_web.py": "webplug", - "twisted_whatever.py": "include!", - "cred.py": "include!"}, - "topfiles": {"setup.py": "import CORE", - "README": "core readme"}}, - "bin": {"twistd": "TWISTD", - "web": {"websetroot": "websetroot"}}} - - outStructure = { - "LICENSE": "copyright!", - "setup.py": "import CORE", - "README": "core readme", - "twisted": {"__init__.py": "twisted", - "python": {"__init__.py": "python", - "roots.py": "roots!"}, - "plugin.py": "plugin", - "plugins": {"twisted_whatever.py": "include!", - "cred.py": "include!"}}, - "bin": {"twistd": "TWISTD"}} - - self.createStructure(self.rootDir, structure) - outputFile = self.builder.buildCore("8.0.0") - self.assertExtractedStructure(outputFile, outStructure) - - - def test_setup3(self): - """ - setup3.py is included in the release tarball. - """ - structure = { - "setup3.py": "install python 3 version", - "bin": {"twistd": "TWISTD"}, - "twisted": { - "web": { - "__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}}, - "doc": {"web": {"howto": {"index.html": "hello"}}}, - } - - self.createStructure(self.rootDir, structure) - outputFile = self.builder.buildTwisted("13.2.0") - self.assertExtractedStructure(outputFile, structure) - - - -class BuildAllTarballsTests(DistributionBuilderTestBase): - """ - Tests for L{DistributionBuilder.buildAllTarballs}. - """ - skip = svnSkip or sphinxSkip - - def test_buildAllTarballs(self): - """ - L{buildAllTarballs} builds tarballs for Twisted and all of its - subprojects based on an SVN checkout; the resulting tarballs contain - no SVN metadata. This involves building documentation, which it will - build with the correct API documentation reference base URL. - """ - repositoryPath = self.mktemp() - repository = FilePath(repositoryPath) - checkoutPath = self.mktemp() - checkout = FilePath(checkoutPath) - self.outputDir.remove() - - runCommand(["svnadmin", "create", repositoryPath]) - runCommand(["svn", "checkout", "file://" + repository.path, - checkout.path]) - - structure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"words": {"im": "import im"}, - "twistd": "TWISTD"}, - "twisted": { - "topfiles": {"setup.py": "import TOPINSTALL", - "README": "CORE!"}, - "_version.py": genVersion("twisted", 1, 2, 0), - "words": {"__init__.py": "import WORDS", - "_version.py": genVersion("twisted.words", 1, 2, 0), - "topfiles": {"setup.py": "import WORDSINSTALL", - "README": "WORDS!"}}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG", - "twisted_yay.py": "import YAY"}}, - "docs": { - "conf.py": testingSphinxConf, - "index.rst": "", - } - } - - def smellsLikeSphinxOutput(actual): - self.assertTrue(actual.isdir()) - self.assertIn("index.html", actual.listdir()) - self.assertIn("objects.inv", actual.listdir()) - return True - - twistedStructure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"twistd": "TWISTD", - "words": {"im": "import im"}}, - "twisted": { - "topfiles": {"setup.py": "import TOPINSTALL", - "README": "CORE!"}, - "_version.py": genVersion("twisted", 1, 2, 0), - "words": {"__init__.py": "import WORDS", - "_version.py": genVersion("twisted.words", 1, 2, 0), - "topfiles": {"setup.py": "import WORDSINSTALL", - "README": "WORDS!"}}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG", - "twisted_yay.py": "import YAY"}}, - "doc": smellsLikeSphinxOutput} - - coreStructure = { - "setup.py": "import TOPINSTALL", - "README": "CORE!", - "LICENSE": "copyright!", - "bin": {"twistd": "TWISTD"}, - "twisted": { - "_version.py": genVersion("twisted", 1, 2, 0), - "plugins": {"twisted_yay.py": "import YAY"}}, - } - - wordsStructure = { - "README": "WORDS!", - "LICENSE": "copyright!", - "setup.py": "import WORDSINSTALL", - "bin": {"im": "import im"}, - "twisted": { - "words": {"__init__.py": "import WORDS", - "_version.py": genVersion("twisted.words", 1, 2, 0)}, - "plugins": {"twisted_words.py": "import WORDPLUG"}}} - - self.createStructure(checkout, structure) - childs = [x.path for x in checkout.children()] - runCommand(["svn", "add"] + childs) - runCommand(["svn", "commit", checkout.path, "-m", "yay"]) - - buildAllTarballs(checkout, self.outputDir) - self.assertEqual( - set(self.outputDir.children()), - set([self.outputDir.child("Twisted-1.2.0.tar.bz2"), - self.outputDir.child("TwistedCore-1.2.0.tar.bz2"), - self.outputDir.child("TwistedWords-1.2.0.tar.bz2")])) - - self.assertExtractedStructure( - self.outputDir.child("Twisted-1.2.0.tar.bz2"), - twistedStructure) - self.assertExtractedStructure( - self.outputDir.child("TwistedCore-1.2.0.tar.bz2"), - coreStructure) - self.assertExtractedStructure( - self.outputDir.child("TwistedWords-1.2.0.tar.bz2"), - wordsStructure) - - - def test_buildAllTarballsEnsuresCleanCheckout(self): - """ - L{UncleanWorkingDirectory} is raised by L{buildAllTarballs} when the - SVN checkout provided has uncommitted changes. - """ - repositoryPath = self.mktemp() - repository = FilePath(repositoryPath) - checkoutPath = self.mktemp() - checkout = FilePath(checkoutPath) - - runCommand(["svnadmin", "create", repositoryPath]) - runCommand(["svn", "checkout", "file://" + repository.path, - checkout.path]) - - checkout.child("foo").setContent("whatever") - self.assertRaises(UncleanWorkingDirectory, - buildAllTarballs, checkout, FilePath(self.mktemp())) - - - def test_buildAllTarballsEnsuresExistingCheckout(self): - """ - L{NotWorkingDirectory} is raised by L{buildAllTarballs} when the - checkout passed does not exist or is not an SVN checkout. - """ - checkout = FilePath(self.mktemp()) - self.assertRaises(NotWorkingDirectory, - buildAllTarballs, - checkout, FilePath(self.mktemp())) - checkout.createDirectory() - self.assertRaises(NotWorkingDirectory, - buildAllTarballs, - checkout, FilePath(self.mktemp())) - - - -class ScriptTests(StructureAssertingMixin, TestCase): - """ - Tests for the release script functionality. - """ - - def _testVersionChanging(self, prerelease, patch): - """ - Check that L{ChangeVersionsScript.main} calls the version-changing - function with the appropriate version data and filesystem path. - """ - versionUpdates = [] - - def myVersionChanger(sourceTree, prerelease, patch): - versionUpdates.append((sourceTree, prerelease, patch)) - - versionChanger = ChangeVersionsScript() - versionChanger.changeAllProjectVersions = myVersionChanger - args = [] - if prerelease: - args.append("--prerelease") - if patch: - args.append("--patch") - versionChanger.main(args) - self.assertEqual(len(versionUpdates), 1) - self.assertEqual(versionUpdates[0][0], FilePath(".")) - self.assertEqual(versionUpdates[0][1], prerelease) - self.assertEqual(versionUpdates[0][2], patch) - - - def test_changeVersions(self): - """ - L{ChangeVersionsScript.main} changes version numbers for all Twisted - projects. - """ - self._testVersionChanging(False, False) - - - def test_changeVersionsWithPrerelease(self): - """ - A prerelease can be created with L{changeVersionsScript}. - """ - self._testVersionChanging(True, False) - - - def test_changeVersionsWithPatch(self): - """ - A patch release can be created with L{changeVersionsScript}. - """ - self._testVersionChanging(False, True) - - - def test_defaultChangeVersionsVersionChanger(self): - """ - The default implementation of C{changeAllProjectVersions} is - L{changeAllProjectVersions}. - """ - versionChanger = ChangeVersionsScript() - self.assertEqual(versionChanger.changeAllProjectVersions, - changeAllProjectVersions) - - - def test_badNumberOfArgumentsToChangeVersionsScript(self): - """ - L{changeVersionsScript} raises SystemExit when the wrong arguments are - passed. - """ - versionChanger = ChangeVersionsScript() - self.assertRaises(SystemExit, versionChanger.main, ["12.3.0"]) - - - def test_tooManyDotsToChangeVersionsScript(self): - """ - L{changeVersionsScript} raises SystemExit when there are the wrong - number of segments in the version number passed. - """ - versionChanger = ChangeVersionsScript() - self.assertRaises(SystemExit, versionChanger.main, - ["3.2.1.0"]) - - - def test_nonIntPartsToChangeVersionsScript(self): - """ - L{changeVersionsScript} raises SystemExit when the version number isn't - made out of numbers. - """ - versionChanger = ChangeVersionsScript() - self.assertRaises(SystemExit, versionChanger.main, - ["my united.states.of prewhatever"]) - - - def test_buildTarballsScript(self): - """ - L{BuildTarballsScript.main} invokes L{buildAllTarballs} with - 2 or 3 L{FilePath} instances representing the paths passed to it. - """ - builds = [] - - def myBuilder(checkout, destination, template=None): - builds.append((checkout, destination, template)) - - tarballBuilder = BuildTarballsScript() - tarballBuilder.buildAllTarballs = myBuilder - - tarballBuilder.main(["checkoutDir", "destinationDir"]) - self.assertEqual( - builds, - [(FilePath("checkoutDir"), FilePath("destinationDir"), None)]) - - builds = [] - tarballBuilder.main(["checkoutDir", "destinationDir", "templatePath"]) - self.assertEqual( - builds, - [(FilePath("checkoutDir"), FilePath("destinationDir"), - FilePath("templatePath"))]) - - - def test_defaultBuildTarballsScriptBuilder(self): - """ - The default implementation of L{BuildTarballsScript.buildAllTarballs} - is L{buildAllTarballs}. - """ - tarballBuilder = BuildTarballsScript() - self.assertEqual(tarballBuilder.buildAllTarballs, buildAllTarballs) - - - def test_badNumberOfArgumentsToBuildTarballs(self): - """ - L{BuildTarballsScript.main} raises SystemExit when the wrong number of - arguments are passed. - """ - tarballBuilder = BuildTarballsScript() - self.assertRaises(SystemExit, tarballBuilder.main, []) - self.assertRaises(SystemExit, tarballBuilder.main, - ["a", "b", "c", "d"]) - - - def test_badNumberOfArgumentsToBuildNews(self): - """ - L{NewsBuilder.main} raises L{SystemExit} when other than 1 argument is - passed to it. - """ - newsBuilder = NewsBuilder() - self.assertRaises(SystemExit, newsBuilder.main, []) - self.assertRaises(SystemExit, newsBuilder.main, ["hello", "world"]) - - - def test_buildNews(self): - """ - L{NewsBuilder.main} calls L{NewsBuilder.buildAll} with a L{FilePath} - instance constructed from the path passed to it. - """ - builds = [] - newsBuilder = NewsBuilder() - newsBuilder.buildAll = builds.append - newsBuilder.main(["/foo/bar/baz"]) - self.assertEqual(builds, [FilePath("/foo/bar/baz")]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_runtime.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_runtime.py deleted file mode 100644 index 70fc127..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_runtime.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.runtime}. -""" - -from __future__ import division, absolute_import - -import sys - -from twisted.python.reflect import namedModule -from twisted.trial.util import suppress as SUPRESS -from twisted.trial.unittest import SynchronousTestCase - -from twisted.python.runtime import Platform, shortPythonVersion - - -class PythonVersionTests(SynchronousTestCase): - """ - Tests the shortPythonVersion method. - """ - - def test_shortPythonVersion(self): - """ - Verify if the Python version is returned correctly. - """ - ver = shortPythonVersion().split('.') - for i in range(3): - self.assertEqual(int(ver[i]), sys.version_info[i]) - - - -class PlatformTests(SynchronousTestCase): - """ - Tests for the default L{Platform} initializer. - """ - - isWinNTDeprecationMessage = ('twisted.python.runtime.Platform.isWinNT was ' - 'deprecated in Twisted 13.0. Use Platform.isWindows instead.') - - - def test_isKnown(self): - """ - L{Platform.isKnown} returns a boolean indicating whether this is one of - the L{runtime.knownPlatforms}. - """ - platform = Platform() - self.assertTrue(platform.isKnown()) - - - def test_isVistaConsistency(self): - """ - Verify consistency of L{Platform.isVista}: it can only be C{True} if - L{Platform.isWinNT} and L{Platform.isWindows} are C{True}. - """ - platform = Platform() - if platform.isVista(): - self.assertTrue(platform.isWinNT()) - self.assertTrue(platform.isWindows()) - self.assertFalse(platform.isMacOSX()) - - - def test_isMacOSXConsistency(self): - """ - L{Platform.isMacOSX} can only return C{True} if L{Platform.getType} - returns C{'posix'}. - """ - platform = Platform() - if platform.isMacOSX(): - self.assertEqual(platform.getType(), 'posix') - - - def test_isLinuxConsistency(self): - """ - L{Platform.isLinux} can only return C{True} if L{Platform.getType} - returns C{'posix'} and L{sys.platform} starts with C{"linux"}. - """ - platform = Platform() - if platform.isLinux(): - self.assertTrue(sys.platform.startswith("linux")) - - - def test_isWinNT(self): - """ - L{Platform.isWinNT} can return only C{False} or C{True} and can not - return C{True} if L{Platform.getType} is not C{"win32"}. - """ - platform = Platform() - isWinNT = platform.isWinNT() - self.assertIn(isWinNT, (False, True)) - if platform.getType() != "win32": - self.assertEqual(isWinNT, False) - - test_isWinNT.suppress = [SUPRESS(category=DeprecationWarning, - message=isWinNTDeprecationMessage)] - - - def test_isWinNTDeprecated(self): - """ - L{Platform.isWinNT} is deprecated in favor of L{platform.isWindows}. - """ - platform = Platform() - platform.isWinNT() - warnings = self.flushWarnings([self.test_isWinNTDeprecated]) - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], self.isWinNTDeprecationMessage) - - - def test_supportsThreads(self): - """ - L{Platform.supportsThreads} returns C{True} if threads can be created in - this runtime, C{False} otherwise. - """ - # It's difficult to test both cases of this without faking the threading - # module. Perhaps an adequate test is to just test the behavior with - # the current runtime, whatever that happens to be. - try: - namedModule('threading') - except ImportError: - self.assertFalse(Platform().supportsThreads()) - else: - self.assertTrue(Platform().supportsThreads()) - - - -class ForeignPlatformTests(SynchronousTestCase): - """ - Tests for L{Platform} based overridden initializer values. - """ - - def test_getType(self): - """ - If an operating system name is supplied to L{Platform}'s initializer, - L{Platform.getType} returns the platform type which corresponds to that - name. - """ - self.assertEqual(Platform('nt').getType(), 'win32') - self.assertEqual(Platform('ce').getType(), 'win32') - self.assertEqual(Platform('posix').getType(), 'posix') - self.assertEqual(Platform('java').getType(), 'java') - - - def test_isMacOSX(self): - """ - If a system platform name is supplied to L{Platform}'s initializer, it - is used to determine the result of L{Platform.isMacOSX}, which returns - C{True} for C{"darwin"}, C{False} otherwise. - """ - self.assertTrue(Platform(None, 'darwin').isMacOSX()) - self.assertFalse(Platform(None, 'linux2').isMacOSX()) - self.assertFalse(Platform(None, 'win32').isMacOSX()) - - - def test_isLinux(self): - """ - If a system platform name is supplied to L{Platform}'s initializer, it - is used to determine the result of L{Platform.isLinux}, which returns - C{True} for values beginning with C{"linux"}, C{False} otherwise. - """ - self.assertFalse(Platform(None, 'darwin').isLinux()) - self.assertTrue(Platform(None, 'linux').isLinux()) - self.assertTrue(Platform(None, 'linux2').isLinux()) - self.assertTrue(Platform(None, 'linux3').isLinux()) - self.assertFalse(Platform(None, 'win32').isLinux()) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_sendmsg.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_sendmsg.py deleted file mode 100644 index 9a40a89..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_sendmsg.py +++ /dev/null @@ -1,543 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.sendmsg}. -""" - -import sys -import errno - -from socket import SOL_SOCKET, AF_INET, AF_INET6, socket, error - -try: - from socket import AF_UNIX, socketpair -except ImportError: - nonUNIXSkip = "Platform does not support AF_UNIX sockets" -else: - nonUNIXSkip = None - -from struct import pack -from os import devnull, pipe, read, close, environ - -from twisted.internet.defer import Deferred -from twisted.internet.error import ProcessDone -from twisted.trial.unittest import TestCase -from twisted.internet.defer import inlineCallbacks -from twisted.internet import reactor -from twisted.python.filepath import FilePath -from twisted.python.runtime import platform - -from twisted.internet.protocol import ProcessProtocol - -if platform.isLinux(): - from socket import MSG_DONTWAIT - dontWaitSkip = None -else: - # It would be nice to be able to test flags on more platforms, but finding a - # flag that works *at all* is somewhat challenging. - dontWaitSkip = "MSG_DONTWAIT is only known to work as intended on Linux" - -try: - from twisted.python.sendmsg import SCM_RIGHTS, send1msg, recv1msg, getsockfam -except ImportError: - importSkip = "Cannot import twisted.python.sendmsg" -else: - importSkip = None - - -class ExitedWithStderr(Exception): - """ - A process exited with some stderr. - """ - - def __str__(self): - """ - Dump the errors in a pretty way in the event of a subprocess traceback. - """ - return '\n'.join([''] + list(self.args)) - - -class StartStopProcessProtocol(ProcessProtocol): - """ - An L{IProcessProtocol} with a Deferred for events where the subprocess - starts and stops. - - @ivar started: A L{Deferred} which fires with this protocol's - L{IProcessTransport} provider when it is connected to one. - - @ivar stopped: A L{Deferred} which fires with the process output or a - failure if the process produces output on standard error. - - @ivar output: A C{str} used to accumulate standard output. - - @ivar errors: A C{str} used to accumulate standard error. - """ - def __init__(self): - self.started = Deferred() - self.stopped = Deferred() - self.output = '' - self.errors = '' - - - def connectionMade(self): - self.started.callback(self.transport) - - - def outReceived(self, data): - self.output += data - - - def errReceived(self, data): - self.errors += data - - - def processEnded(self, reason): - if reason.check(ProcessDone): - self.stopped.callback(self.output) - else: - self.stopped.errback(ExitedWithStderr( - self.errors, self.output)) - - - -class BadList(list): - """ - A list which cannot be iterated sometimes. - - This is a C{list} subclass to get past the type check in L{send1msg}, not as - an example of how real programs might want to interact with L{send1msg} (or - anything else). A custom C{list} subclass makes it easier to trigger - certain error cases in the implementation. - - @ivar iterate: A flag which indicates whether an instance of L{BadList} will - allow iteration over itself or not. If C{False}, an attempt to iterate - over the instance will raise an exception. - """ - iterate = True - - def __iter__(self): - """ - Allow normal list iteration, or raise an exception. - - If C{self.iterate} is C{True}, it will be flipped to C{False} and then - normal iteration will proceed. If C{self.iterate} is C{False}, - L{RuntimeError} is raised instead. - """ - if self.iterate: - self.iterate = False - return super(BadList, self).__iter__() - raise RuntimeError("Something bad happened") - - - -class WorseList(list): - """ - A list which at first gives the appearance of being iterable, but then - raises an exception. - - See L{BadList} for a warning about not writing code like this. - """ - def __iter__(self): - """ - Return an iterator which will raise an exception as soon as C{next} is - called on it. - """ - class BadIterator(object): - def next(self): - raise RuntimeError("This is a really bad case.") - return BadIterator() - - - -class SendmsgTests(TestCase): - """ - Tests for sendmsg extension module and associated file-descriptor sending - functionality. - """ - if nonUNIXSkip is not None: - skip = nonUNIXSkip - elif importSkip is not None: - skip = importSkip - - def setUp(self): - """ - Create a pair of UNIX sockets. - """ - self.input, self.output = socketpair(AF_UNIX) - - - def tearDown(self): - """ - Close the sockets opened by setUp. - """ - self.input.close() - self.output.close() - - - def test_sendmsgBadArguments(self): - """ - The argument types accepted by L{send1msg} are: - - 1. C{int} - 2. read-only character buffer - 3. C{int} - 4. sequence - - The 3rd and 4th arguments are optional. If fewer than two arguments or - more than four arguments are passed, or if any of the arguments passed - are not compatible with these types, L{TypeError} is raised. - """ - # Exercise the wrong number of arguments cases - self.assertRaises(TypeError, send1msg) - self.assertRaises(TypeError, send1msg, 1) - self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [], object()) - - # Exercise the wrong type of arguments cases - self.assertRaises(TypeError, send1msg, object(), "hello world", 2, []) - self.assertRaises(TypeError, send1msg, 1, object(), 2, []) - self.assertRaises(TypeError, send1msg, 1, "hello world", object(), []) - self.assertRaises(TypeError, send1msg, 1, "hello world", 2, object()) - - - def test_badAncillaryIter(self): - """ - If iteration over the ancillary data list fails (at the point of the - C{__iter__} call), the exception with which it fails is propagated to - the caller of L{send1msg}. - """ - badList = BadList() - badList.append((1, 2, "hello world")) - badList.iterate = False - - self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, badList) - - # Hit the second iteration - badList.iterate = True - self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, badList) - - - def test_badAncillaryNext(self): - """ - If iteration over the ancillary data list fails (at the point of a - C{next} call), the exception with which it fails is propagated to the - caller of L{send1msg}. - """ - worseList = WorseList() - self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, worseList) - - - def test_sendmsgBadAncillaryItem(self): - """ - The ancillary data list contains three-tuples with element types of: - - 1. C{int} - 2. C{int} - 3. read-only character buffer - - If a tuple in the ancillary data list does not elements of these types, - L{TypeError} is raised. - """ - # Exercise the wrong number of arguments cases - self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [()]) - self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [(1,)]) - self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [(1, 2)]) - self.assertRaises( - TypeError, - send1msg, 1, "hello world", 2, [(1, 2, "goodbye", object())]) - - # Exercise the wrong type of arguments cases - exc = self.assertRaises( - TypeError, send1msg, 1, "hello world", 2, [object()]) - self.assertEqual( - "send1msg argument 3 expected list of tuple, " - "got list containing object", - str(exc)) - self.assertRaises( - TypeError, - send1msg, 1, "hello world", 2, [(object(), 1, "goodbye")]) - self.assertRaises( - TypeError, - send1msg, 1, "hello world", 2, [(1, object(), "goodbye")]) - self.assertRaises( - TypeError, - send1msg, 1, "hello world", 2, [(1, 1, object())]) - - - def test_syscallError(self): - """ - If the underlying C{sendmsg} call fails, L{send1msg} raises - L{socket.error} with its errno set to the underlying errno value. - """ - probe = file(devnull) - fd = probe.fileno() - probe.close() - exc = self.assertRaises(error, send1msg, fd, "hello, world") - self.assertEqual(exc.args[0], errno.EBADF) - - - def test_syscallErrorWithControlMessage(self): - """ - The behavior when the underlying C{sendmsg} call fails is the same - whether L{send1msg} is passed ancillary data or not. - """ - probe = file(devnull) - fd = probe.fileno() - probe.close() - exc = self.assertRaises( - error, send1msg, fd, "hello, world", 0, [(0, 0, "0123")]) - self.assertEqual(exc.args[0], errno.EBADF) - - - def test_roundtrip(self): - """ - L{recv1msg} will retrieve a message sent via L{send1msg}. - """ - message = "hello, world!" - self.assertEqual( - len(message), - send1msg(self.input.fileno(), message, 0)) - - result = recv1msg(fd=self.output.fileno()) - self.assertEqual(result, (message, 0, [])) - - - def test_shortsend(self): - """ - L{send1msg} returns the number of bytes which it was able to send. - """ - message = "x" * 1024 * 1024 - self.input.setblocking(False) - sent = send1msg(self.input.fileno(), message) - # Sanity check - make sure we did fill the send buffer and then some - self.assertTrue(sent < len(message)) - received = recv1msg(self.output.fileno(), 0, len(message)) - self.assertEqual(len(received[0]), sent) - - - def test_roundtripEmptyAncillary(self): - """ - L{send1msg} treats an empty ancillary data list the same way it treats - receiving no argument for the ancillary parameter at all. - """ - send1msg(self.input.fileno(), "hello, world!", 0, []) - - result = recv1msg(fd=self.output.fileno()) - self.assertEqual(result, ("hello, world!", 0, [])) - - - def test_flags(self): - """ - The C{flags} argument to L{send1msg} is passed on to the underlying - C{sendmsg} call, to affect it in whatever way is defined by those flags. - """ - # Just exercise one flag with simple, well-known behavior. MSG_DONTWAIT - # makes the send a non-blocking call, even if the socket is in blocking - # mode. See also test_flags in RecvmsgTests - for i in range(1024): - try: - send1msg(self.input.fileno(), "x" * 1024, MSG_DONTWAIT) - except error, e: - self.assertEqual(e.args[0], errno.EAGAIN) - break - else: - self.fail( - "Failed to fill up the send buffer, " - "or maybe send1msg blocked for a while") - if dontWaitSkip is not None: - test_flags.skip = dontWaitSkip - - - def test_wrongTypeAncillary(self): - """ - L{send1msg} will show a helpful exception message when given the wrong - type of object for the 'ancillary' argument. - """ - error = self.assertRaises(TypeError, - send1msg, self.input.fileno(), - "hello, world!", 0, 4321) - self.assertEqual(str(error), - "send1msg argument 3 expected list, got int") - - - def spawn(self, script): - """ - Start a script that is a peer of this test as a subprocess. - - @param script: the module name of the script in this directory (no - package prefix, no '.py') - @type script: C{str} - - @rtype: L{StartStopProcessProtocol} - """ - sspp = StartStopProcessProtocol() - reactor.spawnProcess( - sspp, sys.executable, [ - sys.executable, - FilePath(__file__).sibling(script + ".py").path, - str(self.output.fileno()), - ], - environ, - childFDs={0: "w", 1: "r", 2: "r", - self.output.fileno(): self.output.fileno()} - ) - return sspp - - - @inlineCallbacks - def test_sendSubProcessFD(self): - """ - Calling L{sendsmsg} with SOL_SOCKET, SCM_RIGHTS, and a platform-endian - packed file descriptor number should send that file descriptor to a - different process, where it can be retrieved by using L{recv1msg}. - """ - sspp = self.spawn("pullpipe") - yield sspp.started - pipeOut, pipeIn = pipe() - self.addCleanup(close, pipeOut) - - send1msg( - self.input.fileno(), "blonk", 0, - [(SOL_SOCKET, SCM_RIGHTS, pack("i", pipeIn))]) - - close(pipeIn) - yield sspp.stopped - self.assertEqual(read(pipeOut, 1024), "Test fixture data: blonk.\n") - # Make sure that the pipe is actually closed now. - self.assertEqual(read(pipeOut, 1024), "") - - - -class RecvmsgTests(TestCase): - """ - Tests for L{recv1msg} (primarily error handling cases). - """ - if importSkip is not None: - skip = importSkip - - def test_badArguments(self): - """ - The argument types accepted by L{recv1msg} are: - - 1. C{int} - 2. C{int} - 3. C{int} - 4. C{int} - - The 2nd, 3rd, and 4th arguments are optional. If fewer than one - argument or more than four arguments are passed, or if any of the - arguments passed are not compatible with these types, L{TypeError} is - raised. - """ - # Exercise the wrong number of arguments cases - self.assertRaises(TypeError, recv1msg) - self.assertRaises(TypeError, recv1msg, 1, 2, 3, 4, object()) - - # Exercise the wrong type of arguments cases - self.assertRaises(TypeError, recv1msg, object(), 2, 3, 4) - self.assertRaises(TypeError, recv1msg, 1, object(), 3, 4) - self.assertRaises(TypeError, recv1msg, 1, 2, object(), 4) - self.assertRaises(TypeError, recv1msg, 1, 2, 3, object()) - - - def test_cmsgSpaceOverflow(self): - """ - L{recv1msg} raises L{OverflowError} if passed a value for the - C{cmsg_size} argument which exceeds C{SOCKLEN_MAX}. - """ - self.assertRaises(OverflowError, recv1msg, 0, 0, 0, 0x7FFFFFFF) - - - def test_syscallError(self): - """ - If the underlying C{recvmsg} call fails, L{recv1msg} raises - L{socket.error} with its errno set to the underlying errno value. - """ - probe = file(devnull) - fd = probe.fileno() - probe.close() - exc = self.assertRaises(error, recv1msg, fd) - self.assertEqual(exc.args[0], errno.EBADF) - - - def test_flags(self): - """ - The C{flags} argument to L{recv1msg} is passed on to the underlying - C{recvmsg} call, to affect it in whatever way is defined by those flags. - """ - # See test_flags in SendmsgTests - reader, writer = socketpair(AF_UNIX) - exc = self.assertRaises( - error, recv1msg, reader.fileno(), MSG_DONTWAIT) - self.assertEqual(exc.args[0], errno.EAGAIN) - if dontWaitSkip is not None: - test_flags.skip = dontWaitSkip - - - -class GetSocketFamilyTests(TestCase): - """ - Tests for L{getsockfam}, a helper which reveals the address family of an - arbitrary socket. - """ - if importSkip is not None: - skip = importSkip - - def _socket(self, addressFamily): - """ - Create a new socket using the given address family and return that - socket's file descriptor. The socket will automatically be closed when - the test is torn down. - """ - s = socket(addressFamily) - self.addCleanup(s.close) - return s.fileno() - - - def test_badArguments(self): - """ - L{getsockfam} accepts a single C{int} argument. If it is called in some - other way, L{TypeError} is raised. - """ - self.assertRaises(TypeError, getsockfam) - self.assertRaises(TypeError, getsockfam, 1, 2) - - self.assertRaises(TypeError, getsockfam, object()) - - - def test_syscallError(self): - """ - If the underlying C{getsockname} call fails, L{getsockfam} raises - L{socket.error} with its errno set to the underlying errno value. - """ - probe = file(devnull) - fd = probe.fileno() - probe.close() - exc = self.assertRaises(error, getsockfam, fd) - self.assertEqual(errno.EBADF, exc.args[0]) - - - def test_inet(self): - """ - When passed the file descriptor of a socket created with the C{AF_INET} - address family, L{getsockfam} returns C{AF_INET}. - """ - self.assertEqual(AF_INET, getsockfam(self._socket(AF_INET))) - - - def test_inet6(self): - """ - When passed the file descriptor of a socket created with the C{AF_INET6} - address family, L{getsockfam} returns C{AF_INET6}. - """ - self.assertEqual(AF_INET6, getsockfam(self._socket(AF_INET6))) - - - def test_unix(self): - """ - When passed the file descriptor of a socket created with the C{AF_UNIX} - address family, L{getsockfam} returns C{AF_UNIX}. - """ - self.assertEqual(AF_UNIX, getsockfam(self._socket(AF_UNIX))) - if nonUNIXSkip is not None: - test_unix.skip = nonUNIXSkip diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_shellcomp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_shellcomp.py deleted file mode 100755 index 3ae6b35..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_shellcomp.py +++ /dev/null @@ -1,623 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.python._shellcomp -""" - -import sys -from cStringIO import StringIO - -from twisted.trial import unittest -from twisted.python import _shellcomp, usage, reflect -from twisted.python.usage import Completions, Completer, CompleteFiles -from twisted.python.usage import CompleteList - - - -class ZshScriptTestMeta(type): - """ - Metaclass of ZshScriptTestMixin. - """ - def __new__(cls, name, bases, attrs): - def makeTest(cmdName, optionsFQPN): - def runTest(self): - return test_genZshFunction(self, cmdName, optionsFQPN) - return runTest - - # add test_ methods to the class for each script - # we are testing. - if 'generateFor' in attrs: - for cmdName, optionsFQPN in attrs['generateFor']: - test = makeTest(cmdName, optionsFQPN) - attrs['test_genZshFunction_' + cmdName] = test - - return type.__new__(cls, name, bases, attrs) - - - -class ZshScriptTestMixin(object): - """ - Integration test helper to show that C{usage.Options} classes can have zsh - completion functions generated for them without raising errors. - - In your subclasses set a class variable like so: - - # | cmd name | Fully Qualified Python Name of Options class | - # - generateFor = [('conch', 'twisted.conch.scripts.conch.ClientOptions'), - ('twistd', 'twisted.scripts.twistd.ServerOptions'), - ] - - Each package that contains Twisted scripts should contain one TestCase - subclass which also inherits from this mixin, and contains a C{generateFor} - list appropriate for the scripts in that package. - """ - __metaclass__ = ZshScriptTestMeta - - - -def test_genZshFunction(self, cmdName, optionsFQPN): - """ - Generate completion functions for given twisted command - no errors - should be raised - - @type cmdName: C{str} - @param cmdName: The name of the command-line utility e.g. 'twistd' - - @type optionsFQPN: C{str} - @param optionsFQPN: The Fully Qualified Python Name of the C{Options} - class to be tested. - """ - outputFile = StringIO() - self.patch(usage.Options, '_shellCompFile', outputFile) - - # some scripts won't import or instantiate because of missing - # dependencies (PyCrypto, etc) so we have to skip them. - try: - o = reflect.namedAny(optionsFQPN)() - except Exception, e: - raise unittest.SkipTest("Couldn't import or instantiate " - "Options class: %s" % (e,)) - - try: - o.parseOptions(["", "--_shell-completion", "zsh:2"]) - except ImportError, e: - # this can happen for commands which don't have all - # the necessary dependencies installed. skip test. - # skip - raise unittest.SkipTest("ImportError calling parseOptions(): %s", (e,)) - except SystemExit: - pass # expected - else: - self.fail('SystemExit not raised') - outputFile.seek(0) - # test that we got some output - self.assertEqual(1, len(outputFile.read(1))) - outputFile.seek(0) - outputFile.truncate() - - # now, if it has sub commands, we have to test those too - if hasattr(o, 'subCommands'): - for (cmd, short, parser, doc) in o.subCommands: - try: - o.parseOptions([cmd, "", "--_shell-completion", - "zsh:3"]) - except ImportError, e: - # this can happen for commands which don't have all - # the necessary dependencies installed. skip test. - raise unittest.SkipTest("ImportError calling parseOptions() " - "on subcommand: %s", (e,)) - except SystemExit: - pass # expected - else: - self.fail('SystemExit not raised') - - outputFile.seek(0) - # test that we got some output - self.assertEqual(1, len(outputFile.read(1))) - outputFile.seek(0) - outputFile.truncate() - - # flushed because we don't want DeprecationWarnings to be printed when - # running these test cases. - self.flushWarnings() - - - -class ZshTests(unittest.TestCase): - """ - Tests for zsh completion code - """ - def test_accumulateMetadata(self): - """ - Are `compData' attributes you can place on Options classes - picked up correctly? - """ - opts = FighterAceExtendedOptions() - ag = _shellcomp.ZshArgumentsGenerator(opts, 'ace', 'dummy_value') - - descriptions = FighterAceOptions.compData.descriptions.copy() - descriptions.update(FighterAceExtendedOptions.compData.descriptions) - - self.assertEqual(ag.descriptions, descriptions) - self.assertEqual(ag.multiUse, - set(FighterAceOptions.compData.multiUse)) - self.assertEqual(ag.mutuallyExclusive, - FighterAceOptions.compData.mutuallyExclusive) - - optActions = FighterAceOptions.compData.optActions.copy() - optActions.update(FighterAceExtendedOptions.compData.optActions) - self.assertEqual(ag.optActions, optActions) - - self.assertEqual(ag.extraActions, - FighterAceOptions.compData.extraActions) - - - def test_mutuallyExclusiveCornerCase(self): - """ - Exercise a corner-case of ZshArgumentsGenerator.makeExcludesDict() - where the long option name already exists in the `excludes` dict being - built. - """ - class OddFighterAceOptions(FighterAceExtendedOptions): - # since "fokker", etc, are already defined as mutually- - # exclusive on the super-class, defining them again here forces - # the corner-case to be exercised. - optFlags = [['anatra', None, - 'Select the Anatra DS as your dogfighter aircraft']] - compData = Completions( - mutuallyExclusive=[['anatra', 'fokker', 'albatros', - 'spad', 'bristol']]) - - opts = OddFighterAceOptions() - ag = _shellcomp.ZshArgumentsGenerator(opts, 'ace', 'dummy_value') - - expected = { - 'albatros': set(['anatra', 'b', 'bristol', 'f', - 'fokker', 's', 'spad']), - 'anatra': set(['a', 'albatros', 'b', 'bristol', - 'f', 'fokker', 's', 'spad']), - 'bristol': set(['a', 'albatros', 'anatra', 'f', - 'fokker', 's', 'spad']), - 'fokker': set(['a', 'albatros', 'anatra', 'b', - 'bristol', 's', 'spad']), - 'spad': set(['a', 'albatros', 'anatra', 'b', - 'bristol', 'f', 'fokker'])} - - self.assertEqual(ag.excludes, expected) - - - def test_accumulateAdditionalOptions(self): - """ - We pick up options that are only defined by having an - appropriately named method on your Options class, - e.g. def opt_foo(self, foo) - """ - opts = FighterAceExtendedOptions() - ag = _shellcomp.ZshArgumentsGenerator(opts, 'ace', 'dummy_value') - - self.assertIn('nocrash', ag.flagNameToDefinition) - self.assertIn('nocrash', ag.allOptionsNameToDefinition) - - self.assertIn('difficulty', ag.paramNameToDefinition) - self.assertIn('difficulty', ag.allOptionsNameToDefinition) - - - def test_verifyZshNames(self): - """ - Using a parameter/flag name that doesn't exist - will raise an error - """ - class TmpOptions(FighterAceExtendedOptions): - # Note typo of detail - compData = Completions(optActions={'detaill' : None}) - - self.assertRaises(ValueError, _shellcomp.ZshArgumentsGenerator, - TmpOptions(), 'ace', 'dummy_value') - - class TmpOptions2(FighterAceExtendedOptions): - # Note that 'foo' and 'bar' are not real option - # names defined in this class - compData = Completions( - mutuallyExclusive=[("foo", "bar")]) - - self.assertRaises(ValueError, _shellcomp.ZshArgumentsGenerator, - TmpOptions2(), 'ace', 'dummy_value') - - - def test_zshCode(self): - """ - Generate a completion function, and test the textual output - against a known correct output - """ - outputFile = StringIO() - self.patch(usage.Options, '_shellCompFile', outputFile) - self.patch(sys, 'argv', ["silly", "", "--_shell-completion", "zsh:2"]) - opts = SimpleProgOptions() - self.assertRaises(SystemExit, opts.parseOptions) - self.assertEqual(testOutput1, outputFile.getvalue()) - - - def test_zshCodeWithSubs(self): - """ - Generate a completion function with subcommands, - and test the textual output against a known correct output - """ - outputFile = StringIO() - self.patch(usage.Options, '_shellCompFile', outputFile) - self.patch(sys, 'argv', ["silly2", "", "--_shell-completion", "zsh:2"]) - opts = SimpleProgWithSubcommands() - self.assertRaises(SystemExit, opts.parseOptions) - self.assertEqual(testOutput2, outputFile.getvalue()) - - - def test_incompleteCommandLine(self): - """ - Completion still happens even if a command-line is given - that would normally throw UsageError. - """ - outputFile = StringIO() - self.patch(usage.Options, '_shellCompFile', outputFile) - opts = FighterAceOptions() - - self.assertRaises(SystemExit, opts.parseOptions, - ["--fokker", "server", "--unknown-option", - "--unknown-option2", - "--_shell-completion", "zsh:5"]) - outputFile.seek(0) - # test that we got some output - self.assertEqual(1, len(outputFile.read(1))) - - - def test_incompleteCommandLine_case2(self): - """ - Completion still happens even if a command-line is given - that would normally throw UsageError. - - The existence of --unknown-option prior to the subcommand - will break subcommand detection... but we complete anyway - """ - outputFile = StringIO() - self.patch(usage.Options, '_shellCompFile', outputFile) - opts = FighterAceOptions() - - self.assertRaises(SystemExit, opts.parseOptions, - ["--fokker", "--unknown-option", "server", - "--list-server", "--_shell-completion", "zsh:5"]) - outputFile.seek(0) - # test that we got some output - self.assertEqual(1, len(outputFile.read(1))) - - outputFile.seek(0) - outputFile.truncate() - - - def test_incompleteCommandLine_case3(self): - """ - Completion still happens even if a command-line is given - that would normally throw UsageError. - - Break subcommand detection in a different way by providing - an invalid subcommand name. - """ - outputFile = StringIO() - self.patch(usage.Options, '_shellCompFile', outputFile) - opts = FighterAceOptions() - - self.assertRaises(SystemExit, opts.parseOptions, - ["--fokker", "unknown-subcommand", - "--list-server", "--_shell-completion", "zsh:4"]) - outputFile.seek(0) - # test that we got some output - self.assertEqual(1, len(outputFile.read(1))) - - - def test_skipSubcommandList(self): - """ - Ensure the optimization which skips building the subcommand list - under certain conditions isn't broken. - """ - outputFile = StringIO() - self.patch(usage.Options, '_shellCompFile', outputFile) - opts = FighterAceOptions() - - self.assertRaises(SystemExit, opts.parseOptions, - ["--alba", "--_shell-completion", "zsh:2"]) - outputFile.seek(0) - # test that we got some output - self.assertEqual(1, len(outputFile.read(1))) - - - def test_poorlyDescribedOptMethod(self): - """ - Test corner case fetching an option description from a method docstring - """ - opts = FighterAceOptions() - argGen = _shellcomp.ZshArgumentsGenerator(opts, 'ace', None) - - descr = argGen.getDescription('silly') - - # docstring for opt_silly is useless so it should just use the - # option name as the description - self.assertEqual(descr, 'silly') - - - def test_brokenActions(self): - """ - A C{Completer} with repeat=True may only be used as the - last item in the extraActions list. - """ - class BrokenActions(usage.Options): - compData = usage.Completions( - extraActions=[usage.Completer(repeat=True), - usage.Completer()] - ) - - outputFile = StringIO() - opts = BrokenActions() - self.patch(opts, '_shellCompFile', outputFile) - self.assertRaises(ValueError, opts.parseOptions, - ["", "--_shell-completion", "zsh:2"]) - - - def test_optMethodsDontOverride(self): - """ - opt_* methods on Options classes should not override the - data provided in optFlags or optParameters. - """ - class Options(usage.Options): - optFlags = [['flag', 'f', 'A flag']] - optParameters = [['param', 'p', None, 'A param']] - - def opt_flag(self): - """ junk description """ - - def opt_param(self, param): - """ junk description """ - - opts = Options() - argGen = _shellcomp.ZshArgumentsGenerator(opts, 'ace', None) - - self.assertEqual(argGen.getDescription('flag'), 'A flag') - self.assertEqual(argGen.getDescription('param'), 'A param') - - - -class EscapeTests(unittest.TestCase): - def test_escape(self): - """ - Verify _shellcomp.escape() function - """ - esc = _shellcomp.escape - - test = "$" - self.assertEqual(esc(test), "'$'") - - test = 'A--\'$"\\`--B' - self.assertEqual(esc(test), '"A--\'\\$\\"\\\\\\`--B"') - - - -class CompleterNotImplementedTests(unittest.TestCase): - """ - Test that using an unknown shell constant with SubcommandAction - raises NotImplementedError - - The other Completer() subclasses are tested in test_usage.py - """ - def test_unknownShell(self): - """ - Using an unknown shellType should raise NotImplementedError - """ - action = _shellcomp.SubcommandAction() - - self.assertRaises(NotImplementedError, action._shellCode, - None, "bad_shell_type") - - - -class FighterAceServerOptions(usage.Options): - """ - Options for FighterAce 'server' subcommand - """ - optFlags = [['list-server', None, - 'List this server with the online FighterAce network']] - optParameters = [['packets-per-second', None, - 'Number of update packets to send per second', '20']] - - - -class FighterAceOptions(usage.Options): - """ - Command-line options for an imaginary `Fighter Ace` game - """ - optFlags = [['fokker', 'f', - 'Select the Fokker Dr.I as your dogfighter aircraft'], - ['albatros', 'a', - 'Select the Albatros D-III as your dogfighter aircraft'], - ['spad', 's', - 'Select the SPAD S.VII as your dogfighter aircraft'], - ['bristol', 'b', - 'Select the Bristol Scout as your dogfighter aircraft'], - ['physics', 'p', - 'Enable secret Twisted physics engine'], - ['jam', 'j', - 'Enable a small chance that your machine guns will jam!'], - ['verbose', 'v', - 'Verbose logging (may be specified more than once)'], - ] - - optParameters = [['pilot-name', None, "What's your name, Ace?", - 'Manfred von Richthofen'], - ['detail', 'd', - 'Select the level of rendering detail (1-5)', '3'], - ] - - subCommands = [['server', None, FighterAceServerOptions, - 'Start FighterAce game-server.'], - ] - - compData = Completions( - descriptions={'physics' : 'Twisted-Physics', - 'detail' : 'Rendering detail level'}, - multiUse=['verbose'], - mutuallyExclusive=[['fokker', 'albatros', 'spad', - 'bristol']], - optActions={'detail' : CompleteList(['1' '2' '3' - '4' '5'])}, - extraActions=[CompleteFiles(descr='saved game file to load')] - ) - - def opt_silly(self): - # A silly option which nobody can explain - """ """ - - - -class FighterAceExtendedOptions(FighterAceOptions): - """ - Extend the options and zsh metadata provided by FighterAceOptions. - _shellcomp must accumulate options and metadata from all classes in the - hiearchy so this is important to test. - """ - optFlags = [['no-stalls', None, - 'Turn off the ability to stall your aircraft']] - optParameters = [['reality-level', None, - 'Select the level of physics reality (1-5)', '5']] - - compData = Completions( - descriptions={'no-stalls' : 'Can\'t stall your plane'}, - optActions={'reality-level' : - Completer(descr='Physics reality level')} - ) - - def opt_nocrash(self): - """ - Select that you can't crash your plane - """ - - - def opt_difficulty(self, difficulty): - """ - How tough are you? (1-10) - """ - - - -def _accuracyAction(): - # add tick marks just to exercise quoting - return CompleteList(['1', '2', '3'], descr='Accuracy\'`?') - - - -class SimpleProgOptions(usage.Options): - """ - Command-line options for a `Silly` imaginary program - """ - optFlags = [['color', 'c', 'Turn on color output'], - ['gray', 'g', 'Turn on gray-scale output'], - ['verbose', 'v', - 'Verbose logging (may be specified more than once)'], - ] - - optParameters = [['optimization', None, '5', - 'Select the level of optimization (1-5)'], - ['accuracy', 'a', '3', - 'Select the level of accuracy (1-3)'], - ] - - - compData = Completions( - descriptions={'color' : 'Color on', - 'optimization' : 'Optimization level'}, - multiUse=['verbose'], - mutuallyExclusive=[['color', 'gray']], - optActions={'optimization' : CompleteList(['1', '2', '3', '4', '5'], - descr='Optimization?'), - 'accuracy' : _accuracyAction}, - extraActions=[CompleteFiles(descr='output file')] - ) - - def opt_X(self): - """ - usage.Options does not recognize single-letter opt_ methods - """ - - - -class SimpleProgSub1(usage.Options): - optFlags = [['sub-opt', 's', 'Sub Opt One']] - - - -class SimpleProgSub2(usage.Options): - optFlags = [['sub-opt', 's', 'Sub Opt Two']] - - - -class SimpleProgWithSubcommands(SimpleProgOptions): - optFlags = [['some-option'], - ['other-option', 'o']] - - optParameters = [['some-param'], - ['other-param', 'p'], - ['another-param', 'P', 'Yet Another Param']] - - subCommands = [ ['sub1', None, SimpleProgSub1, 'Sub Command 1'], - ['sub2', None, SimpleProgSub2, 'Sub Command 2']] - - - -testOutput1 = """#compdef silly - -_arguments -s -A "-*" \\ -':output file (*):_files -g "*"' \\ -"(--accuracy)-a[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ -"(-a)--accuracy=[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ -'(--color --gray -g)-c[Color on]' \\ -'(--gray -c -g)--color[Color on]' \\ -'(--color --gray -c)-g[Turn on gray-scale output]' \\ -'(--color -c -g)--gray[Turn on gray-scale output]' \\ -'--help[Display this help and exit.]' \\ -'--optimization=[Optimization level]:Optimization?:(1 2 3 4 5)' \\ -'*-v[Verbose logging (may be specified more than once)]' \\ -'*--verbose[Verbose logging (may be specified more than once)]' \\ -'--version[Display Twisted version and exit.]' \\ -&& return 0 -""" - -# with sub-commands -testOutput2 = """#compdef silly2 - -_arguments -s -A "-*" \\ -'*::subcmd:->subcmd' \\ -':output file (*):_files -g "*"' \\ -"(--accuracy)-a[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ -"(-a)--accuracy=[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ -'(--another-param)-P[another-param]:another-param:_files' \\ -'(-P)--another-param=[another-param]:another-param:_files' \\ -'(--color --gray -g)-c[Color on]' \\ -'(--gray -c -g)--color[Color on]' \\ -'(--color --gray -c)-g[Turn on gray-scale output]' \\ -'(--color -c -g)--gray[Turn on gray-scale output]' \\ -'--help[Display this help and exit.]' \\ -'--optimization=[Optimization level]:Optimization?:(1 2 3 4 5)' \\ -'(--other-option)-o[other-option]' \\ -'(-o)--other-option[other-option]' \\ -'(--other-param)-p[other-param]:other-param:_files' \\ -'(-p)--other-param=[other-param]:other-param:_files' \\ -'--some-option[some-option]' \\ -'--some-param=[some-param]:some-param:_files' \\ -'*-v[Verbose logging (may be specified more than once)]' \\ -'*--verbose[Verbose logging (may be specified more than once)]' \\ -'--version[Display Twisted version and exit.]' \\ -&& return 0 -local _zsh_subcmds_array -_zsh_subcmds_array=( -"sub1:Sub Command 1" -"sub2:Sub Command 2" -) - -_describe "sub-command" _zsh_subcmds_array -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_syslog.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_syslog.py deleted file mode 100644 index 559c62f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_syslog.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial.unittest import TestCase -from twisted.python.failure import Failure - -try: - import syslog as stdsyslog -except ImportError: - stdsyslog = None -else: - from twisted.python import syslog - - - -class SyslogObserverTests(TestCase): - """ - Tests for L{SyslogObserver} which sends Twisted log events to the syslog. - """ - events = None - - if stdsyslog is None: - skip = "syslog is not supported on this platform" - - def setUp(self): - self.patch(syslog.SyslogObserver, 'openlog', self.openlog) - self.patch(syslog.SyslogObserver, 'syslog', self.syslog) - self.observer = syslog.SyslogObserver('SyslogObserverTests') - - - def openlog(self, prefix, options, facility): - self.logOpened = (prefix, options, facility) - self.events = [] - - - def syslog(self, options, message): - self.events.append((options, message)) - - - def test_emitWithoutMessage(self): - """ - L{SyslogObserver.emit} ignores events with an empty value for the - C{'message'} key. - """ - self.observer.emit({'message': (), 'isError': False, 'system': '-'}) - self.assertEqual(self.events, []) - - - def test_emitCustomPriority(self): - """ - L{SyslogObserver.emit} uses the value of the C{'syslogPriority'} as the - syslog priority, if that key is present in the event dictionary. - """ - self.observer.emit({ - 'message': ('hello, world',), 'isError': False, 'system': '-', - 'syslogPriority': stdsyslog.LOG_DEBUG}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_DEBUG, '[-] hello, world')]) - - - def test_emitErrorPriority(self): - """ - L{SyslogObserver.emit} uses C{LOG_ALERT} if the event represents an - error. - """ - self.observer.emit({ - 'message': ('hello, world',), 'isError': True, 'system': '-', - 'failure': Failure(Exception("foo"))}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_ALERT, '[-] hello, world')]) - - - def test_emitCustomPriorityOverridesError(self): - """ - L{SyslogObserver.emit} uses the value of the C{'syslogPriority'} key if - it is specified even if the event dictionary represents an error. - """ - self.observer.emit({ - 'message': ('hello, world',), 'isError': True, 'system': '-', - 'syslogPriority': stdsyslog.LOG_NOTICE, - 'failure': Failure(Exception("bar"))}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_NOTICE, '[-] hello, world')]) - - - def test_emitCustomFacility(self): - """ - L{SyslogObserver.emit} uses the value of the C{'syslogPriority'} as the - syslog priority, if that key is present in the event dictionary. - """ - self.observer.emit({ - 'message': ('hello, world',), 'isError': False, 'system': '-', - 'syslogFacility': stdsyslog.LOG_CRON}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_INFO | stdsyslog.LOG_CRON, '[-] hello, world')]) - - - def test_emitCustomSystem(self): - """ - L{SyslogObserver.emit} uses the value of the C{'system'} key to prefix - the logged message. - """ - self.observer.emit({'message': ('hello, world',), 'isError': False, - 'system': 'nonDefaultSystem'}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_INFO, "[nonDefaultSystem] hello, world")]) - - - def test_emitMessage(self): - """ - L{SyslogObserver.emit} logs the value of the C{'message'} key of the - event dictionary it is passed to the syslog. - """ - self.observer.emit({ - 'message': ('hello, world',), 'isError': False, - 'system': '-'}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_INFO, "[-] hello, world")]) - - - def test_emitMultilineMessage(self): - """ - Each line of a multiline message is emitted separately to the syslog. - """ - self.observer.emit({ - 'message': ('hello,\nworld',), 'isError': False, - 'system': '-'}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_INFO, '[-] hello,'), - (stdsyslog.LOG_INFO, '[-] \tworld')]) - - - def test_emitStripsTrailingEmptyLines(self): - """ - Trailing empty lines of a multiline message are omitted from the - messages sent to the syslog. - """ - self.observer.emit({ - 'message': ('hello,\nworld\n\n',), 'isError': False, - 'system': '-'}) - self.assertEqual( - self.events, - [(stdsyslog.LOG_INFO, '[-] hello,'), - (stdsyslog.LOG_INFO, '[-] \tworld')]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_systemd.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_systemd.py deleted file mode 100644 index 91c7b44..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_systemd.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.systemd}. -""" - -from __future__ import division, absolute_import - -import os - -from twisted.trial.unittest import TestCase -from twisted.python.systemd import ListenFDs - - -class InheritedDescriptorsMixin(object): - """ - Mixin for a L{TestCase} subclass which defines test methods for some kind of - systemd sd-daemon class. In particular, it defines tests for a - C{inheritedDescriptors} method. - """ - def test_inheritedDescriptors(self): - """ - C{inheritedDescriptors} returns a list of integers giving the file - descriptors which were inherited from systemd. - """ - sddaemon = self.getDaemon(7, 3) - self.assertEqual([7, 8, 9], sddaemon.inheritedDescriptors()) - - - def test_repeated(self): - """ - Any subsequent calls to C{inheritedDescriptors} return the same list. - """ - sddaemon = self.getDaemon(7, 3) - self.assertEqual( - sddaemon.inheritedDescriptors(), - sddaemon.inheritedDescriptors()) - - - -class MemoryOnlyMixin(object): - """ - Mixin for a L{TestCase} subclass which creates creating a fake, in-memory - implementation of C{inheritedDescriptors}. This provides verification that - the fake behaves in a compatible way with the real implementation. - """ - def getDaemon(self, start, count): - """ - Invent C{count} new I{file descriptors} (actually integers, attached to - no real file description), starting at C{start}. Construct and return a - new L{ListenFDs} which will claim those integers represent inherited - file descriptors. - """ - return ListenFDs(range(start, start + count)) - - - -class EnvironmentMixin(object): - """ - Mixin for a L{TestCase} subclass which creates a real implementation of - C{inheritedDescriptors} which is based on the environment variables set by - systemd. To facilitate testing, this mixin will also create a fake - environment dictionary and add keys to it to make it look as if some - descriptors have been inherited. - """ - def initializeEnvironment(self, count, pid): - """ - Create a copy of the process environment and add I{LISTEN_FDS} and - I{LISTEN_PID} (the environment variables set by systemd) to it. - """ - result = os.environ.copy() - result['LISTEN_FDS'] = str(count) - result['LISTEN_PID'] = str(pid) - return result - - - def getDaemon(self, start, count): - """ - Create a new L{ListenFDs} instance, initialized with a fake environment - dictionary which will be set up as systemd would have set it up if - C{count} descriptors were being inherited. The descriptors will also - start at C{start}. - """ - fakeEnvironment = self.initializeEnvironment(count, os.getpid()) - return ListenFDs.fromEnvironment(environ=fakeEnvironment, start=start) - - - -class MemoryOnlyTests(MemoryOnlyMixin, InheritedDescriptorsMixin, TestCase): - """ - Apply tests to L{ListenFDs}, explicitly constructed with some fake file - descriptors. - """ - - - -class EnvironmentTests(EnvironmentMixin, InheritedDescriptorsMixin, TestCase): - """ - Apply tests to L{ListenFDs}, constructed based on an environment dictionary. - """ - def test_secondEnvironment(self): - """ - Only a single L{Environment} can extract inherited file descriptors. - """ - fakeEnvironment = self.initializeEnvironment(3, os.getpid()) - first = ListenFDs.fromEnvironment(environ=fakeEnvironment) - second = ListenFDs.fromEnvironment(environ=fakeEnvironment) - self.assertEqual(list(range(3, 6)), first.inheritedDescriptors()) - self.assertEqual([], second.inheritedDescriptors()) - - - def test_mismatchedPID(self): - """ - If the current process PID does not match the PID in the environment, no - inherited descriptors are reported. - """ - fakeEnvironment = self.initializeEnvironment(3, os.getpid() + 1) - sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) - self.assertEqual([], sddaemon.inheritedDescriptors()) - - - def test_missingPIDVariable(self): - """ - If the I{LISTEN_PID} environment variable is not present, no inherited - descriptors are reported. - """ - fakeEnvironment = self.initializeEnvironment(3, os.getpid()) - del fakeEnvironment['LISTEN_PID'] - sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) - self.assertEqual([], sddaemon.inheritedDescriptors()) - - - def test_nonIntegerPIDVariable(self): - """ - If the I{LISTEN_PID} environment variable is set to a string that cannot - be parsed as an integer, no inherited descriptors are reported. - """ - fakeEnvironment = self.initializeEnvironment(3, "hello, world") - sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) - self.assertEqual([], sddaemon.inheritedDescriptors()) - - - def test_missingFDSVariable(self): - """ - If the I{LISTEN_FDS} environment variable is not present, no inherited - descriptors are reported. - """ - fakeEnvironment = self.initializeEnvironment(3, os.getpid()) - del fakeEnvironment['LISTEN_FDS'] - sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) - self.assertEqual([], sddaemon.inheritedDescriptors()) - - - def test_nonIntegerFDSVariable(self): - """ - If the I{LISTEN_FDS} environment variable is set to a string that cannot - be parsed as an integer, no inherited descriptors are reported. - """ - fakeEnvironment = self.initializeEnvironment("hello, world", os.getpid()) - sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) - self.assertEqual([], sddaemon.inheritedDescriptors()) - - - def test_defaultEnviron(self): - """ - If the process environment is not explicitly passed to - L{Environment.__init__}, the real process environment dictionary is - used. - """ - self.patch(os, 'environ', { - 'LISTEN_PID': str(os.getpid()), - 'LISTEN_FDS': '5'}) - sddaemon = ListenFDs.fromEnvironment() - self.assertEqual(list(range(3, 3 + 5)), - sddaemon.inheritedDescriptors()) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_textattributes.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_textattributes.py deleted file mode 100644 index 3e954f2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_textattributes.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.textattributes}. -""" - -from twisted.trial import unittest -from twisted.python._textattributes import DefaultFormattingState - - - -class DefaultFormattingStateTests(unittest.TestCase): - """ - Tests for L{twisted.python._textattributes.DefaultFormattingState}. - """ - def test_equality(self): - """ - L{DefaultFormattingState}s are always equal to other - L{DefaultFormattingState}s. - """ - self.assertEqual( - DefaultFormattingState(), - DefaultFormattingState()) - self.assertNotEquals( - DefaultFormattingState(), - 'hello') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_tzhelper.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_tzhelper.py deleted file mode 100644 index aedc0c7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_tzhelper.py +++ /dev/null @@ -1,153 +0,0 @@ -# # Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python._tzhelper}. -""" - -from os import environ - -try: - from time import tzset -except ImportError: - tzset = None - -from twisted.python._tzhelper import FixedOffsetTimeZone -from twisted.trial.unittest import TestCase, SkipTest -from datetime import timedelta - -from time import mktime as mktime_real - - -# On some rare platforms (FreeBSD 8? I was not able to reproduce -# on FreeBSD 9) 'mktime' seems to always fail once tzset() has been -# called more than once in a process lifetime. I think this is -# just a platform bug, so let's work around it. -glyph - -def mktime(t9): - """ - Call L{mktime_real}, and if it raises L{OverflowError}, catch it and raise - SkipTest instead. - - @param t9: A time as a 9-item tuple. - @type t9: L{tuple} - - @return: A timestamp. - @rtype: L{float} - """ - try: - return mktime_real(t9) - except OverflowError: - raise SkipTest( - "Platform cannot construct time zone for {0!r}" - .format(t9) - ) - - - -def setTZ(name): - """ - Set time zone. - - @param name: a time zone name - @type name: L{str} - """ - if tzset is None: - return - - if name is None: - try: - del environ["TZ"] - except KeyError: - pass - else: - environ["TZ"] = name - tzset() - - - -def addTZCleanup(testCase): - """ - Add cleanup hooks to a test case to reset timezone to original value. - - @param testCase: the test case to add the cleanup to. - @type testCase: L{unittest.TestCase} - """ - tzIn = environ.get("TZ", None) - - @testCase.addCleanup - def resetTZ(): - setTZ(tzIn) - - - -class FixedOffsetTimeZoneTests(TestCase): - """ - Tests for L{FixedOffsetTimeZone}. - """ - - def test_tzinfo(self): - """ - Test that timezone attributes respect the timezone as set by the - standard C{TZ} environment variable and L{tzset} API. - """ - if tzset is None: - raise SkipTest( - "Platform cannot change timezone; unable to verify offsets." - ) - - def testForTimeZone(name, expectedOffsetDST, expectedOffsetSTD): - setTZ(name) - - localDST = mktime((2006, 6, 30, 0, 0, 0, 4, 181, 1)) - localSTD = mktime((2007, 1, 31, 0, 0, 0, 2, 31, 0)) - - tzDST = FixedOffsetTimeZone.fromLocalTimeStamp(localDST) - tzSTD = FixedOffsetTimeZone.fromLocalTimeStamp(localSTD) - - self.assertEquals( - tzDST.tzname(localDST), - "UTC{0}".format(expectedOffsetDST) - ) - self.assertEquals( - tzSTD.tzname(localSTD), - "UTC{0}".format(expectedOffsetSTD) - ) - - self.assertEquals(tzDST.dst(localDST), timedelta(0)) - self.assertEquals(tzSTD.dst(localSTD), timedelta(0)) - - def timeDeltaFromOffset(offset): - assert len(offset) == 5 - - sign = offset[0] - hours = int(offset[1:3]) - minutes = int(offset[3:5]) - - if sign == "-": - hours = -hours - minutes = -minutes - else: - assert sign == "+" - - return timedelta(hours=hours, minutes=minutes) - - self.assertEquals( - tzDST.utcoffset(localDST), - timeDeltaFromOffset(expectedOffsetDST) - ) - self.assertEquals( - tzSTD.utcoffset(localSTD), - timeDeltaFromOffset(expectedOffsetSTD) - ) - - addTZCleanup(self) - - # UTC - testForTimeZone("UTC+00", "+0000", "+0000") - # West of UTC - testForTimeZone("EST+05EDT,M4.1.0,M10.5.0", "-0400", "-0500") - # East of UTC - testForTimeZone("CEST-01CEDT,M4.1.0,M10.5.0", "+0200", "+0100") - # No DST - testForTimeZone("CST+06", "-0600", "-0600") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_urlpath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_urlpath.py deleted file mode 100644 index 0263378..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_urlpath.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.urlpath}. -""" - -from twisted.trial import unittest -from twisted.python import urlpath - - -class URLPathTests(unittest.TestCase): - def setUp(self): - self.path = urlpath.URLPath.fromString("http://example.com/foo/bar?yes=no&no=yes#footer") - - def testStringConversion(self): - self.assertEqual(str(self.path), "http://example.com/foo/bar?yes=no&no=yes#footer") - - def testChildString(self): - self.assertEqual(str(self.path.child('hello')), "http://example.com/foo/bar/hello") - self.assertEqual(str(self.path.child('hello').child('')), "http://example.com/foo/bar/hello/") - - def testSiblingString(self): - self.assertEqual(str(self.path.sibling('baz')), 'http://example.com/foo/baz') - - # The sibling of http://example.com/foo/bar/ - # is http://example.comf/foo/bar/baz - # because really we are constructing a sibling of - # http://example.com/foo/bar/index.html - self.assertEqual(str(self.path.child('').sibling('baz')), 'http://example.com/foo/bar/baz') - - def testParentString(self): - # parent should be equivalent to '..' - # 'foo' is the current directory, '/' is the parent directory - self.assertEqual(str(self.path.parent()), 'http://example.com/') - self.assertEqual(str(self.path.child('').parent()), 'http://example.com/foo/') - self.assertEqual(str(self.path.child('baz').parent()), 'http://example.com/foo/') - self.assertEqual(str(self.path.parent().parent().parent().parent().parent()), 'http://example.com/') - - def testHereString(self): - # here should be equivalent to '.' - self.assertEqual(str(self.path.here()), 'http://example.com/foo/') - self.assertEqual(str(self.path.child('').here()), 'http://example.com/foo/bar/') - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_util.py deleted file mode 100644 index efcdf9b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_util.py +++ /dev/null @@ -1,1162 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_util -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.util}. -""" - -from __future__ import division, absolute_import - -import os.path, sys -import shutil, errno, warnings -try: - import pwd, grp -except ImportError: - pwd = grp = None - -from twisted.trial import unittest -from twisted.trial.util import suppress as SUPPRESS - -from twisted.python.compat import _PY3 -from twisted.python import util -from twisted.python.reflect import fullyQualifiedName -from twisted.internet import reactor -from twisted.internet.interfaces import IReactorProcess -from twisted.internet.protocol import ProcessProtocol -from twisted.internet.defer import Deferred -from twisted.internet.error import ProcessDone - -if _PY3: - MockOS = None -else: - from twisted.test.test_process import MockOS - - - -class UtilTests(unittest.TestCase): - - def testUniq(self): - l = ["a", 1, "ab", "a", 3, 4, 1, 2, 2, 4, 6] - self.assertEqual(util.uniquify(l), ["a", 1, "ab", 3, 4, 2, 6]) - - def testRaises(self): - self.failUnless(util.raises(ZeroDivisionError, divmod, 1, 0)) - self.failIf(util.raises(ZeroDivisionError, divmod, 0, 1)) - - try: - util.raises(TypeError, divmod, 1, 0) - except ZeroDivisionError: - pass - else: - raise unittest.FailTest("util.raises didn't raise when it should have") - - - def test_uidFromNumericString(self): - """ - When L{uidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - self.assertEqual(util.uidFromString("100"), 100) - - - def test_uidFromUsernameString(self): - """ - When L{uidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - pwent = pwd.getpwuid(os.getuid()) - self.assertEqual(util.uidFromString(pwent.pw_name), pwent.pw_uid) - if pwd is None: - test_uidFromUsernameString.skip = ( - "Username/UID conversion requires the pwd module.") - - - def test_gidFromNumericString(self): - """ - When L{gidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - self.assertEqual(util.gidFromString("100"), 100) - - - def test_gidFromGroupnameString(self): - """ - When L{gidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - grent = grp.getgrgid(os.getgid()) - self.assertEqual(util.gidFromString(grent.gr_name), grent.gr_gid) - if grp is None: - test_gidFromGroupnameString.skip = ( - "Group Name/GID conversion requires the grp module.") - - - -class NameToLabelTests(unittest.TestCase): - """ - Tests for L{nameToLabel}. - """ - - def test_nameToLabel(self): - """ - Test the various kinds of inputs L{nameToLabel} supports. - """ - nameData = [ - ('f', 'F'), - ('fo', 'Fo'), - ('foo', 'Foo'), - ('fooBar', 'Foo Bar'), - ('fooBarBaz', 'Foo Bar Baz'), - ] - for inp, out in nameData: - got = util.nameToLabel(inp) - self.assertEqual( - got, out, - "nameToLabel(%r) == %r != %r" % (inp, got, out)) - - - -class UntilConcludesTests(unittest.TestCase): - """ - Tests for L{untilConcludes}, an C{EINTR} helper. - """ - def test_uninterruptably(self): - """ - L{untilConcludes} calls the function passed to it until the function - does not raise either L{OSError} or L{IOError} with C{errno} of - C{EINTR}. It otherwise completes with the same result as the function - passed to it. - """ - def f(a, b): - self.calls += 1 - exc = self.exceptions.pop() - if exc is not None: - raise exc(errno.EINTR, "Interrupted system call!") - return a + b - - self.exceptions = [None] - self.calls = 0 - self.assertEqual(util.untilConcludes(f, 1, 2), 3) - self.assertEqual(self.calls, 1) - - self.exceptions = [None, OSError, IOError] - self.calls = 0 - self.assertEqual(util.untilConcludes(f, 2, 3), 5) - self.assertEqual(self.calls, 3) - - - -class SwitchUIDTests(unittest.TestCase): - """ - Tests for L{util.switchUID}. - """ - - if getattr(os, "getuid", None) is None: - skip = "getuid/setuid not available" - - - def setUp(self): - self.mockos = MockOS() - self.patch(util, "os", self.mockos) - self.patch(util, "initgroups", self.initgroups) - self.initgroupsCalls = [] - - - def initgroups(self, uid, gid): - """ - Save L{util.initgroups} calls in C{self.initgroupsCalls}. - """ - self.initgroupsCalls.append((uid, gid)) - - - def test_uid(self): - """ - L{util.switchUID} calls L{util.initgroups} and then C{os.setuid} with - the given uid. - """ - util.switchUID(12000, None) - self.assertEqual(self.initgroupsCalls, [(12000, None)]) - self.assertEqual(self.mockos.actions, [("setuid", 12000)]) - - - def test_euid(self): - """ - L{util.switchUID} calls L{util.initgroups} and then C{os.seteuid} with - the given uid if the C{euid} parameter is set to C{True}. - """ - util.switchUID(12000, None, True) - self.assertEqual(self.initgroupsCalls, [(12000, None)]) - self.assertEqual(self.mockos.seteuidCalls, [12000]) - - - def test_currentUID(self): - """ - If the current uid is the same as the uid passed to L{util.switchUID}, - then initgroups does not get called, but a warning is issued. - """ - uid = self.mockos.getuid() - util.switchUID(uid, None) - self.assertEqual(self.initgroupsCalls, []) - self.assertEqual(self.mockos.actions, []) - currentWarnings = self.flushWarnings([util.switchUID]) - self.assertEqual(len(currentWarnings), 1) - self.assertIn('tried to drop privileges and setuid %i' % uid, - currentWarnings[0]['message']) - self.assertIn( - 'but uid is already %i' % uid, currentWarnings[0]['message']) - - - def test_currentEUID(self): - """ - If the current euid is the same as the euid passed to L{util.switchUID}, - then initgroups does not get called, but a warning is issued. - """ - euid = self.mockos.geteuid() - util.switchUID(euid, None, True) - self.assertEqual(self.initgroupsCalls, []) - self.assertEqual(self.mockos.seteuidCalls, []) - currentWarnings = self.flushWarnings([util.switchUID]) - self.assertEqual(len(currentWarnings), 1) - self.assertIn('tried to drop privileges and seteuid %i' % euid, - currentWarnings[0]['message']) - self.assertIn( - 'but euid is already %i' % euid, currentWarnings[0]['message']) - - - -class MergeFunctionMetadataTests(unittest.TestCase): - """ - Tests for L{mergeFunctionMetadata}. - """ - - def test_mergedFunctionBehavesLikeMergeTarget(self): - """ - After merging C{foo}'s data into C{bar}, the returned function behaves - as if it is C{bar}. - """ - foo_object = object() - bar_object = object() - - def foo(): - return foo_object - - def bar(x, y, ab, c=10, *d, **e): - (a, b) = ab - return bar_object - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertIdentical(baz(1, 2, (3, 4), quux=10), bar_object) - - - def test_moduleIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{foo}'s - C{__module__}. - """ - def foo(): - pass - - def bar(): - pass - bar.__module__ = 'somewhere.else' - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(baz.__module__, foo.__module__) - - - def test_docstringIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{foo}'s docstring. - """ - - def foo(): - """ - This is foo. - """ - - def bar(): - """ - This is bar. - """ - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(baz.__doc__, foo.__doc__) - - - def test_nameIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{foo}'s name. - """ - - def foo(): - pass - - def bar(): - pass - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(baz.__name__, foo.__name__) - - - def test_instanceDictionaryIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{bar}'s - dictionary, updated by C{foo}'s. - """ - - def foo(): - pass - foo.a = 1 - foo.b = 2 - - def bar(): - pass - bar.b = 3 - bar.c = 4 - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(foo.a, baz.a) - self.assertEqual(foo.b, baz.b) - self.assertEqual(bar.c, baz.c) - - - -class OrderedDictTests(unittest.TestCase): - def testOrderedDict(self): - d = util.OrderedDict() - d['a'] = 'b' - d['b'] = 'a' - d[3] = 12 - d[1234] = 4321 - self.assertEqual(repr(d), "{'a': 'b', 'b': 'a', 3: 12, 1234: 4321}") - self.assertEqual(d.values(), ['b', 'a', 12, 4321]) - del d[3] - self.assertEqual(repr(d), "{'a': 'b', 'b': 'a', 1234: 4321}") - self.assertEqual(d, {'a': 'b', 'b': 'a', 1234:4321}) - self.assertEqual(d.keys(), ['a', 'b', 1234]) - self.assertEqual(list(d.iteritems()), - [('a', 'b'), ('b','a'), (1234, 4321)]) - item = d.popitem() - self.assertEqual(item, (1234, 4321)) - - def testInitialization(self): - d = util.OrderedDict({'monkey': 'ook', - 'apple': 'red'}) - self.failUnless(d._order) - - d = util.OrderedDict(((1,1),(3,3),(2,2),(0,0))) - self.assertEqual(repr(d), "{1: 1, 3: 3, 2: 2, 0: 0}") - - - -class InsensitiveDictTests(unittest.TestCase): - """ - Tests for L{util.InsensitiveDict}. - """ - - def test_preserve(self): - """ - L{util.InsensitiveDict} preserves the case of keys if constructed with - C{preserve=True}. - """ - dct = util.InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=1) - self.assertEqual(dct['fnz'], {1:2}) - self.assertEqual(dct['foo'], 'bar') - self.assertEqual(dct.copy(), dct) - self.assertEqual(dct['foo'], dct.get('Foo')) - self.assertIn(1, dct) - self.assertIn('foo', dct) - - result = eval(repr(dct), { - 'dct': dct, - 'InsensitiveDict': util.InsensitiveDict, - }) - self.assertEqual(result, dct) - - keys=['Foo', 'fnz', 1] - for x in keys: - self.assertIn(x, dct.keys()) - self.assertIn((x, dct[x]), dct.items()) - self.assertEqual(len(keys), len(dct)) - del dct[1] - del dct['foo'] - self.assertEqual(dct.keys(), ['fnz']) - - - def test_noPreserve(self): - """ - L{util.InsensitiveDict} does not preserves the case of keys if - constructed with C{preserve=False}. - """ - dct = util.InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=0) - keys=['foo', 'fnz', 1] - for x in keys: - self.assertIn(x, dct.keys()) - self.assertIn((x, dct[x]), dct.items()) - self.assertEqual(len(keys), len(dct)) - del dct[1] - del dct['foo'] - self.assertEqual(dct.keys(), ['fnz']) - - - def test_unicode(self): - """ - Unicode keys are case insensitive. - """ - d = util.InsensitiveDict(preserve=False) - d[u"Foo"] = 1 - self.assertEqual(d[u"FOO"], 1) - self.assertEqual(d.keys(), [u"foo"]) - - - def test_bytes(self): - """ - Bytes keys are case insensitive. - """ - d = util.InsensitiveDict(preserve=False) - d[b"Foo"] = 1 - self.assertEqual(d[b"FOO"], 1) - self.assertEqual(d.keys(), [b"foo"]) - - - -class PasswordTestingProcessProtocol(ProcessProtocol): - """ - Write the string C{"secret\n"} to a subprocess and then collect all of - its output and fire a Deferred with it when the process ends. - """ - def connectionMade(self): - self.output = [] - self.transport.write('secret\n') - - def childDataReceived(self, fd, output): - self.output.append((fd, output)) - - def processEnded(self, reason): - self.finished.callback((reason, self.output)) - - -class GetPasswordTests(unittest.TestCase): - if not IReactorProcess.providedBy(reactor): - skip = "Process support required to test getPassword" - - def test_stdin(self): - """ - Making sure getPassword accepts a password from standard input by - running a child process which uses getPassword to read in a string - which it then writes it out again. Write a string to the child - process and then read one and make sure it is the right string. - """ - p = PasswordTestingProcessProtocol() - p.finished = Deferred() - reactor.spawnProcess( - p, - sys.executable, - [sys.executable, - '-c', - ('import sys\n' - 'from twisted.python.util import getPassword\n' - 'sys.stdout.write(getPassword())\n' - 'sys.stdout.flush()\n')], - env={'PYTHONPATH': os.pathsep.join(sys.path)}) - - def processFinished(result): - (reason, output) = result - reason.trap(ProcessDone) - self.assertIn((1, 'secret'), output) - - return p.finished.addCallback(processFinished) - - - -class SearchUpwardsTests(unittest.TestCase): - def testSearchupwards(self): - os.makedirs('searchupwards/a/b/c') - file('searchupwards/foo.txt', 'w').close() - file('searchupwards/a/foo.txt', 'w').close() - file('searchupwards/a/b/c/foo.txt', 'w').close() - os.mkdir('searchupwards/bar') - os.mkdir('searchupwards/bam') - os.mkdir('searchupwards/a/bar') - os.mkdir('searchupwards/a/b/bam') - actual=util.searchupwards('searchupwards/a/b/c', - files=['foo.txt'], - dirs=['bar', 'bam']) - expected=os.path.abspath('searchupwards') + os.sep - self.assertEqual(actual, expected) - shutil.rmtree('searchupwards') - actual=util.searchupwards('searchupwards/a/b/c', - files=['foo.txt'], - dirs=['bar', 'bam']) - expected=None - self.assertEqual(actual, expected) - - - -class IntervalDifferentialTests(unittest.TestCase): - def testDefault(self): - d = iter(util.IntervalDifferential([], 10)) - for i in range(100): - self.assertEqual(d.next(), (10, None)) - - def testSingle(self): - d = iter(util.IntervalDifferential([5], 10)) - for i in range(100): - self.assertEqual(d.next(), (5, 0)) - - def testPair(self): - d = iter(util.IntervalDifferential([5, 7], 10)) - for i in range(100): - self.assertEqual(d.next(), (5, 0)) - self.assertEqual(d.next(), (2, 1)) - self.assertEqual(d.next(), (3, 0)) - self.assertEqual(d.next(), (4, 1)) - self.assertEqual(d.next(), (1, 0)) - self.assertEqual(d.next(), (5, 0)) - self.assertEqual(d.next(), (1, 1)) - self.assertEqual(d.next(), (4, 0)) - self.assertEqual(d.next(), (3, 1)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (5, 0)) - self.assertEqual(d.next(), (0, 1)) - - def testTriple(self): - d = iter(util.IntervalDifferential([2, 4, 5], 10)) - for i in range(100): - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (0, 1)) - self.assertEqual(d.next(), (1, 2)) - self.assertEqual(d.next(), (1, 0)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (0, 1)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (0, 2)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (0, 1)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (1, 2)) - self.assertEqual(d.next(), (1, 0)) - self.assertEqual(d.next(), (0, 1)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (2, 0)) - self.assertEqual(d.next(), (0, 1)) - self.assertEqual(d.next(), (0, 2)) - - def testInsert(self): - d = iter(util.IntervalDifferential([], 10)) - self.assertEqual(d.next(), (10, None)) - d.addInterval(3) - self.assertEqual(d.next(), (3, 0)) - self.assertEqual(d.next(), (3, 0)) - d.addInterval(6) - self.assertEqual(d.next(), (3, 0)) - self.assertEqual(d.next(), (3, 0)) - self.assertEqual(d.next(), (0, 1)) - self.assertEqual(d.next(), (3, 0)) - self.assertEqual(d.next(), (3, 0)) - self.assertEqual(d.next(), (0, 1)) - - def testRemove(self): - d = iter(util.IntervalDifferential([3, 5], 10)) - self.assertEqual(d.next(), (3, 0)) - self.assertEqual(d.next(), (2, 1)) - self.assertEqual(d.next(), (1, 0)) - d.removeInterval(3) - self.assertEqual(d.next(), (4, 0)) - self.assertEqual(d.next(), (5, 0)) - d.removeInterval(5) - self.assertEqual(d.next(), (10, None)) - self.assertRaises(ValueError, d.removeInterval, 10) - - - -class Record(util.FancyEqMixin): - """ - Trivial user of L{FancyEqMixin} used by tests. - """ - compareAttributes = ('a', 'b') - - def __init__(self, a, b): - self.a = a - self.b = b - - - -class DifferentRecord(util.FancyEqMixin): - """ - Trivial user of L{FancyEqMixin} which is not related to L{Record}. - """ - compareAttributes = ('a', 'b') - - def __init__(self, a, b): - self.a = a - self.b = b - - - -class DerivedRecord(Record): - """ - A class with an inheritance relationship to L{Record}. - """ - - - -class EqualToEverything(object): - """ - A class the instances of which consider themselves equal to everything. - """ - def __eq__(self, other): - return True - - - def __ne__(self, other): - return False - - - -class EqualToNothing(object): - """ - A class the instances of which consider themselves equal to nothing. - """ - def __eq__(self, other): - return False - - - def __ne__(self, other): - return True - - - -class EqualityTests(unittest.TestCase): - """ - Tests for L{FancyEqMixin}. - """ - def test_identity(self): - """ - Instances of a class which mixes in L{FancyEqMixin} but which - defines no comparison attributes compare by identity. - """ - class Empty(util.FancyEqMixin): - pass - - self.assertFalse(Empty() == Empty()) - self.assertTrue(Empty() != Empty()) - empty = Empty() - self.assertTrue(empty == empty) - self.assertFalse(empty != empty) - - - def test_equality(self): - """ - Instances of a class which mixes in L{FancyEqMixin} should compare - equal if all of their attributes compare equal. They should not - compare equal if any of their attributes do not compare equal. - """ - self.assertTrue(Record(1, 2) == Record(1, 2)) - self.assertFalse(Record(1, 2) == Record(1, 3)) - self.assertFalse(Record(1, 2) == Record(2, 2)) - self.assertFalse(Record(1, 2) == Record(3, 4)) - - - def test_unequality(self): - """ - Inequality between instances of a particular L{record} should be - defined as the negation of equality. - """ - self.assertFalse(Record(1, 2) != Record(1, 2)) - self.assertTrue(Record(1, 2) != Record(1, 3)) - self.assertTrue(Record(1, 2) != Record(2, 2)) - self.assertTrue(Record(1, 2) != Record(3, 4)) - - - def test_differentClassesEquality(self): - """ - Instances of different classes which mix in L{FancyEqMixin} should not - compare equal. - """ - self.assertFalse(Record(1, 2) == DifferentRecord(1, 2)) - - - def test_differentClassesInequality(self): - """ - Instances of different classes which mix in L{FancyEqMixin} should - compare unequal. - """ - self.assertTrue(Record(1, 2) != DifferentRecord(1, 2)) - - - def test_inheritedClassesEquality(self): - """ - An instance of a class which derives from a class which mixes in - L{FancyEqMixin} should compare equal to an instance of the base class - if and only if all of their attributes compare equal. - """ - self.assertTrue(Record(1, 2) == DerivedRecord(1, 2)) - self.assertFalse(Record(1, 2) == DerivedRecord(1, 3)) - self.assertFalse(Record(1, 2) == DerivedRecord(2, 2)) - self.assertFalse(Record(1, 2) == DerivedRecord(3, 4)) - - - def test_inheritedClassesInequality(self): - """ - An instance of a class which derives from a class which mixes in - L{FancyEqMixin} should compare unequal to an instance of the base - class if any of their attributes compare unequal. - """ - self.assertFalse(Record(1, 2) != DerivedRecord(1, 2)) - self.assertTrue(Record(1, 2) != DerivedRecord(1, 3)) - self.assertTrue(Record(1, 2) != DerivedRecord(2, 2)) - self.assertTrue(Record(1, 2) != DerivedRecord(3, 4)) - - - def test_rightHandArgumentImplementsEquality(self): - """ - The right-hand argument to the equality operator is given a chance - to determine the result of the operation if it is of a type - unrelated to the L{FancyEqMixin}-based instance on the left-hand - side. - """ - self.assertTrue(Record(1, 2) == EqualToEverything()) - self.assertFalse(Record(1, 2) == EqualToNothing()) - - - def test_rightHandArgumentImplementsUnequality(self): - """ - The right-hand argument to the non-equality operator is given a - chance to determine the result of the operation if it is of a type - unrelated to the L{FancyEqMixin}-based instance on the left-hand - side. - """ - self.assertFalse(Record(1, 2) != EqualToEverything()) - self.assertTrue(Record(1, 2) != EqualToNothing()) - - - -class RunAsEffectiveUserTests(unittest.TestCase): - """ - Test for the L{util.runAsEffectiveUser} function. - """ - - if getattr(os, "geteuid", None) is None: - skip = "geteuid/seteuid not available" - - def setUp(self): - self.mockos = MockOS() - self.patch(os, "geteuid", self.mockos.geteuid) - self.patch(os, "getegid", self.mockos.getegid) - self.patch(os, "seteuid", self.mockos.seteuid) - self.patch(os, "setegid", self.mockos.setegid) - - - def _securedFunction(self, startUID, startGID, wantUID, wantGID): - """ - Check if wanted UID/GID matched start or saved ones. - """ - self.assertTrue(wantUID == startUID or - wantUID == self.mockos.seteuidCalls[-1]) - self.assertTrue(wantGID == startGID or - wantGID == self.mockos.setegidCalls[-1]) - - - def test_forwardResult(self): - """ - L{util.runAsEffectiveUser} forwards the result obtained by calling the - given function - """ - result = util.runAsEffectiveUser(0, 0, lambda: 1) - self.assertEqual(result, 1) - - - def test_takeParameters(self): - """ - L{util.runAsEffectiveUser} pass the given parameters to the given - function. - """ - result = util.runAsEffectiveUser(0, 0, lambda x: 2*x, 3) - self.assertEqual(result, 6) - - - def test_takesKeyworkArguments(self): - """ - L{util.runAsEffectiveUser} pass the keyword parameters to the given - function. - """ - result = util.runAsEffectiveUser(0, 0, lambda x, y=1, z=1: x*y*z, 2, z=3) - self.assertEqual(result, 6) - - - def _testUIDGIDSwitch(self, startUID, startGID, wantUID, wantGID, - expectedUIDSwitches, expectedGIDSwitches): - """ - Helper method checking the calls to C{os.seteuid} and C{os.setegid} - made by L{util.runAsEffectiveUser}, when switching from startUID to - wantUID and from startGID to wantGID. - """ - self.mockos.euid = startUID - self.mockos.egid = startGID - util.runAsEffectiveUser( - wantUID, wantGID, - self._securedFunction, startUID, startGID, wantUID, wantGID) - self.assertEqual(self.mockos.seteuidCalls, expectedUIDSwitches) - self.assertEqual(self.mockos.setegidCalls, expectedGIDSwitches) - self.mockos.seteuidCalls = [] - self.mockos.setegidCalls = [] - - - def test_root(self): - """ - Check UID/GID switches when current effective UID is root. - """ - self._testUIDGIDSwitch(0, 0, 0, 0, [], []) - self._testUIDGIDSwitch(0, 0, 1, 0, [1, 0], []) - self._testUIDGIDSwitch(0, 0, 0, 1, [], [1, 0]) - self._testUIDGIDSwitch(0, 0, 1, 1, [1, 0], [1, 0]) - - - def test_UID(self): - """ - Check UID/GID switches when current effective UID is non-root. - """ - self._testUIDGIDSwitch(1, 0, 0, 0, [0, 1], []) - self._testUIDGIDSwitch(1, 0, 1, 0, [], []) - self._testUIDGIDSwitch(1, 0, 1, 1, [0, 1, 0, 1], [1, 0]) - self._testUIDGIDSwitch(1, 0, 2, 1, [0, 2, 0, 1], [1, 0]) - - - def test_GID(self): - """ - Check UID/GID switches when current effective GID is non-root. - """ - self._testUIDGIDSwitch(0, 1, 0, 0, [], [0, 1]) - self._testUIDGIDSwitch(0, 1, 0, 1, [], []) - self._testUIDGIDSwitch(0, 1, 1, 1, [1, 0], []) - self._testUIDGIDSwitch(0, 1, 1, 2, [1, 0], [2, 1]) - - - def test_UIDGID(self): - """ - Check UID/GID switches when current effective UID/GID is non-root. - """ - self._testUIDGIDSwitch(1, 1, 0, 0, [0, 1], [0, 1]) - self._testUIDGIDSwitch(1, 1, 0, 1, [0, 1], []) - self._testUIDGIDSwitch(1, 1, 1, 0, [0, 1, 0, 1], [0, 1]) - self._testUIDGIDSwitch(1, 1, 1, 1, [], []) - self._testUIDGIDSwitch(1, 1, 2, 1, [0, 2, 0, 1], []) - self._testUIDGIDSwitch(1, 1, 1, 2, [0, 1, 0, 1], [2, 1]) - self._testUIDGIDSwitch(1, 1, 2, 2, [0, 2, 0, 1], [2, 1]) - - - -def _getDeprecationSuppression(f): - """ - Returns a tuple of arguments needed to suppress deprecation warnings from - a specified function. - - @param f: function to suppress dperecation warnings for - @type f: L{callable} - - @return: tuple to add to C{suppress} attribute - """ - return SUPPRESS( - category=DeprecationWarning, - message='%s was deprecated' % (fullyQualifiedName(f),)) - - - -class InitGroupsTests(unittest.TestCase): - """ - Tests for L{util.initgroups}. - """ - - if pwd is None: - skip = "pwd not available" - - - def setUp(self): - self.addCleanup(setattr, util, "_c_initgroups", util._c_initgroups) - self.addCleanup(setattr, util, "setgroups", util.setgroups) - - - def test_initgroupsForceC(self): - """ - If we fake the presence of the C extension, it's called instead of the - Python implementation. - """ - calls = [] - util._c_initgroups = lambda x, y: calls.append((x, y)) - setgroupsCalls = [] - util.setgroups = calls.append - - util.initgroups(os.getuid(), 4) - self.assertEqual(calls, [(pwd.getpwuid(os.getuid())[0], 4)]) - self.assertFalse(setgroupsCalls) - - - def test_initgroupsForcePython(self): - """ - If we fake the absence of the C extension, the Python implementation is - called instead, calling C{os.setgroups}. - """ - util._c_initgroups = None - calls = [] - util.setgroups = calls.append - util.initgroups(os.getuid(), os.getgid()) - # Something should be in the calls, we don't really care what - self.assertTrue(calls) - - - def test_initgroupsInC(self): - """ - If the C extension is present, it's called instead of the Python - version. We check that by making sure C{os.setgroups} is not called. - """ - calls = [] - util.setgroups = calls.append - try: - util.initgroups(os.getuid(), os.getgid()) - except OSError: - pass - self.assertFalse(calls) - - - if util._c_initgroups is None: - test_initgroupsInC.skip = "C initgroups not available" - - -class DeprecationTests(unittest.TestCase): - """ - Tests for deprecations in C{twisted.python.util}. - """ - def test_getPluginDirs(self): - """ - L{util.getPluginDirs} is deprecated. - """ - util.getPluginDirs() - currentWarnings = self.flushWarnings(offendingFunctions=[ - self.test_getPluginDirs]) - self.assertEqual( - currentWarnings[0]['message'], - "twisted.python.util.getPluginDirs is deprecated since Twisted " - "12.2.") - self.assertEqual(currentWarnings[0]['category'], DeprecationWarning) - self.assertEqual(len(currentWarnings), 1) - - - def test_addPluginDir(self): - """ - L{util.addPluginDir} is deprecated. - """ - util.addPluginDir() - currentWarnings = self.flushWarnings(offendingFunctions=[ - self.test_addPluginDir]) - self.assertEqual( - currentWarnings[0]['message'], - "twisted.python.util.addPluginDir is deprecated since Twisted " - "12.2.") - self.assertEqual(currentWarnings[0]['category'], DeprecationWarning) - self.assertEqual(len(currentWarnings), 1) - test_addPluginDir.suppress = [ - SUPPRESS(category=DeprecationWarning, - message="twisted.python.util.getPluginDirs is deprecated") - ] - - - -class SuppressedWarningsTests(unittest.TestCase): - """ - Tests for L{util.runWithWarningsSuppressed}. - """ - runWithWarningsSuppressed = staticmethod(util.runWithWarningsSuppressed) - - def test_runWithWarningsSuppressedFiltered(self): - """ - Warnings from the function called by C{runWithWarningsSuppressed} are - suppressed if they match the passed in filter. - """ - filters = [(("ignore", ".*foo.*"), {}), - (("ignore", ".*bar.*"), {})] - self.runWithWarningsSuppressed(filters, warnings.warn, "ignore foo") - self.runWithWarningsSuppressed(filters, warnings.warn, "ignore bar") - self.assertEqual([], self.flushWarnings()) - - - def test_runWithWarningsSuppressedUnfiltered(self): - """ - Warnings from the function called by C{runWithWarningsSuppressed} are - not suppressed if they do not match the passed in filter. - """ - filters = [(("ignore", ".*foo.*"), {}), - (("ignore", ".*bar.*"), {})] - self.runWithWarningsSuppressed(filters, warnings.warn, "don't ignore") - self.assertEqual( - ["don't ignore"], [w['message'] for w in self.flushWarnings()]) - - - def test_passThrough(self): - """ - C{runWithWarningsSuppressed} returns the result of the function it - called. - """ - self.assertEqual(self.runWithWarningsSuppressed([], lambda: 4), 4) - - - def test_noSideEffects(self): - """ - Once C{runWithWarningsSuppressed} has returned, it no longer - suppresses warnings. - """ - filters = [(("ignore", ".*foo.*"), {}), - (("ignore", ".*bar.*"), {})] - self.runWithWarningsSuppressed(filters, lambda: None) - warnings.warn("ignore foo") - self.assertEqual( - ["ignore foo"], [w['message'] for w in self.flushWarnings()]) - - - -class FancyStrMixinTests(unittest.TestCase): - """ - Tests for L{util.FancyStrMixin}. - """ - - def test_sequenceOfStrings(self): - """ - If C{showAttributes} is set to a sequence of strings, C{__str__} - renders using those by looking them up as attributes on the object. - """ - class Foo(util.FancyStrMixin): - showAttributes = ("first", "second") - first = 1 - second = "hello" - self.assertEqual(str(Foo()), "") - - - def test_formatter(self): - """ - If C{showAttributes} has an item that is a 2-tuple, C{__str__} renders - the first item in the tuple as a key and the result of calling the - second item with the value of the attribute named by the first item as - the value. - """ - class Foo(util.FancyStrMixin): - showAttributes = ( - "first", - ("second", lambda value: repr(value[::-1]))) - first = "hello" - second = "world" - self.assertEqual("", str(Foo())) - - - def test_override(self): - """ - If C{showAttributes} has an item that is a 3-tuple, C{__str__} renders - the second item in the tuple as a key, and the contents of the - attribute named in the first item are rendered as the value. The value - is formatted using the third item in the tuple. - """ - class Foo(util.FancyStrMixin): - showAttributes = ("first", ("second", "2nd", "%.1f")) - first = 1 - second = 2.111 - self.assertEqual(str(Foo()), "") - - - def test_fancybasename(self): - """ - If C{fancybasename} is present, C{__str__} uses it instead of the class name. - """ - class Foo(util.FancyStrMixin): - fancybasename = "Bar" - self.assertEqual(str(Foo()), "") - - - def test_repr(self): - """ - C{__repr__} outputs the same content as C{__str__}. - """ - class Foo(util.FancyStrMixin): - showAttributes = ("first", "second") - first = 1 - second = "hello" - obj = Foo() - self.assertEqual(str(obj), repr(obj)) - - - -class PadToTests(unittest.TestCase): - """ - Tests for L{util.padTo}. - """ - - def test_default(self): - """ - C{None} values can be added to a list to cause it to have a certain - length. - """ - padded = util.padTo(3, []) - self.assertEqual([None] * 3, padded) - - - def test_specificDefaultValue(self): - """ - A specific value can be added to a list to cause it to have a certain - length. - """ - padded = util.padTo(4, [], "x") - self.assertEqual(["x"] * 4, padded) - - - def test_padNonEmptyList(self): - """ - A list which already has some items has the padding value added after - those items. - """ - padded = util.padTo(3, [1, 2], "z") - self.assertEqual([1, 2, "z"], padded) - - - def test_padToSmallerSize(self): - """ - L{util.padTo} can't pad a list if the size requested is smaller than - the size of the list to pad. - """ - self.assertRaises(ValueError, util.padTo, 1, [1, 2]) - - - def test_alreadyPadded(self): - """ - If the list is already the length indicated by the padding argument - then a list with the same value is returned. - """ - items = [1, 2] - padded = util.padTo(len(items), items) - self.assertEqual(items, padded) - - - def test_alreadyPaddedCopies(self): - """ - If the list is already the length indicated by the padding argument - then the return value is a copy of the input. - """ - items = [1, 2] - padded = util.padTo(len(items), items) - self.assertIsNot(padded, items) - - - def test_makeCopy(self): - """ - L{util.padTo} doesn't modify the input list but makes a copy. - """ - items = [] - util.padTo(4, items) - self.assertEqual([], items) - - -if _PY3: - del (SwitchUIDTests, SearchUpwardsTests, RunAsEffectiveUserTests, - OrderedDictTests, IntervalDifferentialTests, UtilTests, - MergeFunctionMetadataTests, DeprecationTests, InitGroupsTests, - GetPasswordTests, - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_versions.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_versions.py deleted file mode 100644 index 649a1b9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_versions.py +++ /dev/null @@ -1,361 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.versions}. -""" - -from __future__ import division, absolute_import - -import sys -import operator -from io import BytesIO - -from twisted.python.versions import getVersionString, IncomparableVersions -from twisted.python.versions import Version, _inf -from twisted.python.filepath import FilePath - -from twisted.trial.unittest import SynchronousTestCase as TestCase - - -VERSION_4_ENTRIES = b"""\ - - - - -""" - - - -VERSION_8_ENTRIES = b"""\ -8 - -dir -22715 -svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk -""" - - -VERSION_9_ENTRIES = b"""\ -9 - -dir -22715 -svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk -""" - - -VERSION_10_ENTRIES = b"""\ -10 - -dir -22715 -svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk -""" - - -class VersionsTests(TestCase): - - def test_versionComparison(self): - """ - Versions can be compared for equality and order. - """ - va = Version("dummy", 1, 0, 0) - vb = Version("dummy", 0, 1, 0) - self.assertTrue(va > vb) - self.assertTrue(vb < va) - self.assertTrue(va >= vb) - self.assertTrue(vb <= va) - self.assertTrue(va != vb) - self.assertTrue(vb == Version("dummy", 0, 1, 0)) - self.assertTrue(vb == vb) - - - def test_comparingPrereleasesWithReleases(self): - """ - Prereleases are always less than versions without prereleases. - """ - va = Version("whatever", 1, 0, 0, prerelease=1) - vb = Version("whatever", 1, 0, 0) - self.assertTrue(va < vb) - self.assertFalse(va > vb) - self.assertNotEquals(vb, va) - - - def test_comparingPrereleases(self): - """ - The value specified as the prerelease is used in version comparisons. - """ - va = Version("whatever", 1, 0, 0, prerelease=1) - vb = Version("whatever", 1, 0, 0, prerelease=2) - self.assertTrue(va < vb) - self.assertTrue(vb > va) - self.assertTrue(va <= vb) - self.assertTrue(vb >= va) - self.assertTrue(va != vb) - self.assertTrue(vb == Version("whatever", 1, 0, 0, prerelease=2)) - self.assertTrue(va == va) - - - def test_infComparison(self): - """ - L{_inf} is equal to L{_inf}. - - This is a regression test. - """ - self.assertEqual(_inf, _inf) - - - def test_disallowBuggyComparisons(self): - """ - The package names of the Version objects need to be the same, - """ - self.assertRaises(IncomparableVersions, - operator.eq, - Version("dummy", 1, 0, 0), - Version("dumym", 1, 0, 0)) - - - def test_notImplementedComparisons(self): - """ - Comparing a L{Version} to some other object type results in - C{NotImplemented}. - """ - va = Version("dummy", 1, 0, 0) - vb = ("dummy", 1, 0, 0) # a tuple is not a Version object - self.assertEqual(va.__cmp__(vb), NotImplemented) - - - def test_repr(self): - """ - Calling C{repr} on a version returns a human-readable string - representation of the version. - """ - self.assertEqual(repr(Version("dummy", 1, 2, 3)), - "Version('dummy', 1, 2, 3)") - - - def test_reprWithPrerelease(self): - """ - Calling C{repr} on a version with a prerelease returns a human-readable - string representation of the version including the prerelease. - """ - self.assertEqual(repr(Version("dummy", 1, 2, 3, prerelease=4)), - "Version('dummy', 1, 2, 3, prerelease=4)") - - - def test_str(self): - """ - Calling C{str} on a version returns a human-readable string - representation of the version. - """ - self.assertEqual(str(Version("dummy", 1, 2, 3)), - "[dummy, version 1.2.3]") - - - def test_strWithPrerelease(self): - """ - Calling C{str} on a version with a prerelease includes the prerelease. - """ - self.assertEqual(str(Version("dummy", 1, 0, 0, prerelease=1)), - "[dummy, version 1.0.0pre1]") - - - def testShort(self): - self.assertEqual(Version('dummy', 1, 2, 3).short(), '1.2.3') - - - def test_goodSVNEntries_4(self): - """ - Version should be able to parse an SVN format 4 entries file. - """ - version = Version("dummy", 1, 0, 0) - self.assertEqual( - version._parseSVNEntries_4(BytesIO(VERSION_4_ENTRIES)), b'18211') - - - def test_goodSVNEntries_8(self): - """ - Version should be able to parse an SVN format 8 entries file. - """ - version = Version("dummy", 1, 0, 0) - self.assertEqual( - version._parseSVNEntries_8(BytesIO(VERSION_8_ENTRIES)), b'22715') - - - def test_goodSVNEntries_9(self): - """ - Version should be able to parse an SVN format 9 entries file. - """ - version = Version("dummy", 1, 0, 0) - self.assertEqual( - version._parseSVNEntries_9(BytesIO(VERSION_9_ENTRIES)), b'22715') - - - def test_goodSVNEntriesTenPlus(self): - """ - Version should be able to parse an SVN format 10 entries file. - """ - version = Version("dummy", 1, 0, 0) - self.assertEqual( - version._parseSVNEntriesTenPlus(BytesIO(VERSION_10_ENTRIES)), b'22715') - - - def test_getVersionString(self): - """ - L{getVersionString} returns a string with the package name and the - short version number. - """ - self.assertEqual( - 'Twisted 8.0.0', getVersionString(Version('Twisted', 8, 0, 0))) - - - def test_getVersionStringWithPrerelease(self): - """ - L{getVersionString} includes the prerelease, if any. - """ - self.assertEqual( - getVersionString(Version("whatever", 8, 0, 0, prerelease=1)), - "whatever 8.0.0pre1") - - - def test_base(self): - """ - The L{base} method returns a very simple representation of the version. - """ - self.assertEqual(Version("foo", 1, 0, 0).base(), "1.0.0") - - - def test_baseWithPrerelease(self): - """ - The base version includes 'preX' for versions with prereleases. - """ - self.assertEqual(Version("foo", 1, 0, 0, prerelease=8).base(), - "1.0.0pre8") - - - -class FormatDiscoveryTests(TestCase): - """ - Tests which discover the parsing method based on the imported module name. - """ - def mktemp(self): - return TestCase.mktemp(self).encode("utf-8") - - - def setUp(self): - """ - Create a temporary directory with a package structure in it. - """ - self.entry = FilePath(self.mktemp()) - self.preTestModules = sys.modules.copy() - sys.path.append(self.entry.path.decode('utf-8')) - pkg = self.entry.child(b"twisted_python_versions_package") - pkg.makedirs() - pkg.child(b"__init__.py").setContent( - b"from twisted.python.versions import Version\n" - b"version = Version('twisted_python_versions_package', 1, 0, 0)\n") - self.svnEntries = pkg.child(b".svn") - self.svnEntries.makedirs() - - - def tearDown(self): - """ - Remove the imported modules and sys.path modifications. - """ - sys.modules.clear() - sys.modules.update(self.preTestModules) - sys.path.remove(self.entry.path.decode('utf-8')) - - - def checkSVNFormat(self, formatVersion, entriesText, expectedRevision): - """ - Check for the given revision being detected after setting the SVN - entries text and format version of the test directory structure. - """ - self.svnEntries.child(b"format").setContent(formatVersion + b"\n") - self.svnEntries.child(b"entries").setContent(entriesText) - self.assertEqual(self.getVersion()._getSVNVersion(), expectedRevision) - - - def getVersion(self): - """ - Import and retrieve the Version object from our dynamically created - package. - """ - import twisted_python_versions_package - return twisted_python_versions_package.version - - - def test_detectVersion4(self): - """ - Verify that version 4 format file will be properly detected and parsed. - """ - self.checkSVNFormat(b"4", VERSION_4_ENTRIES, b'18211') - - - def test_detectVersion8(self): - """ - Verify that version 8 format files will be properly detected and - parsed. - """ - self.checkSVNFormat(b"8", VERSION_8_ENTRIES, b'22715') - - - def test_detectVersion9(self): - """ - Verify that version 9 format files will be properly detected and - parsed. - """ - self.checkSVNFormat(b"9", VERSION_9_ENTRIES, b'22715') - - - def test_unparseableEntries(self): - """ - Verify that the result is C{b"Unknown"} for an apparently supported - version for which parsing of the entries file fails. - """ - self.checkSVNFormat(b"4", b"some unsupported stuff", b"Unknown") - - - def test_detectVersion10(self): - """ - Verify that version 10 format files will be properly detected and - parsed. - - Differing from previous formats, the version 10 format lacks a - I{format} file and B{only} has the version information on the first - line of the I{entries} file. - """ - self.svnEntries.child(b"entries").setContent(VERSION_10_ENTRIES) - self.assertEqual(self.getVersion()._getSVNVersion(), b'22715') - - - def test_detectUnknownVersion(self): - """ - Verify that a new version of SVN will result in the revision 'Unknown'. - """ - self.checkSVNFormat(b"some-random-new-version", b"ooga booga!", b'Unknown') - - - def test_getVersionStringWithRevision(self): - """ - L{getVersionString} includes the discovered revision number. - """ - self.svnEntries.child(b"format").setContent(b"9\n") - self.svnEntries.child(b"entries").setContent(VERSION_10_ENTRIES) - version = getVersionString(self.getVersion()) - self.assertEqual( - "twisted_python_versions_package 1.0.0+r22715", - version) - self.assertTrue(isinstance(version, type(""))) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_win32.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_win32.py deleted file mode 100644 index 8494436..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_win32.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.win32}. -""" - -from twisted.trial import unittest -from twisted.python.runtime import platform -from twisted.python import win32 - - -class CommandLineQuotingTests(unittest.TestCase): - """ - Tests for L{cmdLineQuote}. - """ - - def test_argWithoutSpaces(self): - """ - Calling C{cmdLineQuote} with an argument with no spaces should - return the argument unchanged. - """ - self.assertEqual(win32.cmdLineQuote('an_argument'), 'an_argument') - - - def test_argWithSpaces(self): - """ - Calling C{cmdLineQuote} with an argument containing spaces should - return the argument surrounded by quotes. - """ - self.assertEqual(win32.cmdLineQuote('An Argument'), '"An Argument"') - - - def test_emptyStringArg(self): - """ - Calling C{cmdLineQuote} with an empty string should return a - quoted empty string. - """ - self.assertEqual(win32.cmdLineQuote(''), '""') - - - -class ProgramPathsTests(unittest.TestCase): - """ - Tests for L{getProgramsMenuPath} and L{getProgramFilesPath}. - """ - - def test_getProgramsMenuPath(self): - """ - L{getProgramsMenuPath} guesses the programs menu path on non-win32 - platforms. On non-win32 it will try to figure out the path by - examining the registry. - """ - if not platform.isWindows(): - self.assertEqual(win32.getProgramsMenuPath(), - "C:\\Windows\\Start Menu\\Programs") - else: - self.assertIsInstance(win32.getProgramsMenuPath(), str) - - - def test_getProgramFilesPath(self): - """ - L{getProgramFilesPath} returns the "program files" path on win32. - """ - self.assertIsInstance(win32.getProgramFilesPath(), str) - - if not platform.isWindows(): - test_getProgramFilesPath.skip = ( - "Cannot figure out the program files path on non-win32 platform") - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_zippath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_zippath.py deleted file mode 100644 index a9e23c3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_zippath.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases covering L{twisted.python.zippath}. -""" - -import os, zipfile - -from twisted.test.test_paths import AbstractFilePathTests -from twisted.python.zippath import ZipArchive - - -def zipit(dirname, zfname): - """ - Create a zipfile on zfname, containing the contents of dirname' - """ - zf = zipfile.ZipFile(zfname, "w") - for root, ignored, files, in os.walk(dirname): - for fname in files: - fspath = os.path.join(root, fname) - arcpath = os.path.join(root, fname)[len(dirname)+1:] - # print fspath, '=>', arcpath - zf.write(fspath, arcpath) - zf.close() - - - -class ZipFilePathTests(AbstractFilePathTests): - """ - Test various L{ZipPath} path manipulations as well as reprs for L{ZipPath} - and L{ZipArchive}. - """ - def setUp(self): - AbstractFilePathTests.setUp(self) - zipit(self.cmn, self.cmn + '.zip') - self.path = ZipArchive(self.cmn + '.zip') - self.root = self.path - self.all = [x.replace(self.cmn, self.cmn + '.zip') for x in self.all] - - - def test_zipPathRepr(self): - """ - Make sure that invoking ZipPath's repr prints the correct class name - and an absolute path to the zip file. - """ - child = self.path.child("foo") - pathRepr = "ZipPath(%r)" % ( - os.path.abspath(self.cmn + ".zip" + os.sep + 'foo'),) - - # Check for an absolute path - self.assertEqual(repr(child), pathRepr) - - # Create a path to the file rooted in the current working directory - relativeCommon = self.cmn.replace(os.getcwd() + os.sep, "", 1) + ".zip" - relpath = ZipArchive(relativeCommon) - child = relpath.child("foo") - - # Check using a path without the cwd prepended - self.assertEqual(repr(child), pathRepr) - - - def test_zipPathReprParentDirSegment(self): - """ - The repr of a ZipPath with C{".."} in the internal part of its path - includes the C{".."} rather than applying the usual parent directory - meaning. - """ - child = self.path.child("foo").child("..").child("bar") - pathRepr = "ZipPath(%r)" % ( - self.cmn + ".zip" + os.sep.join(["", "foo", "..", "bar"])) - self.assertEqual(repr(child), pathRepr) - - - def test_zipPathReprEscaping(self): - """ - Bytes in the ZipPath path which have special meaning in Python - string literals are escaped in the ZipPath repr. - """ - child = self.path.child("'") - path = self.cmn + ".zip" + os.sep.join(["", "'"]) - pathRepr = "ZipPath('%s')" % (path.encode('string-escape'),) - self.assertEqual(repr(child), pathRepr) - - - def test_zipArchiveRepr(self): - """ - Make sure that invoking ZipArchive's repr prints the correct class - name and an absolute path to the zip file. - """ - pathRepr = 'ZipArchive(%r)' % (os.path.abspath(self.cmn + '.zip'),) - - # Check for an absolute path - self.assertEqual(repr(self.path), pathRepr) - - # Create a path to the file rooted in the current working directory - relativeCommon = self.cmn.replace(os.getcwd() + os.sep, "", 1) + ".zip" - relpath = ZipArchive(relativeCommon) - - # Check using a path without the cwd prepended - self.assertEqual(repr(relpath), pathRepr) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_zipstream.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_zipstream.py deleted file mode 100644 index c76b088..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/test/test_zipstream.py +++ /dev/null @@ -1,355 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.zipstream} -""" - -import random -import zipfile -from hashlib import md5 - -from twisted.python import zipstream, filepath -from twisted.trial import unittest - - -class FileEntryMixin: - """ - File entry classes should behave as file-like objects - """ - def getFileEntry(self, contents): - """ - Return an appropriate zip file entry - """ - filename = self.mktemp() - z = zipfile.ZipFile(filename, 'w', self.compression) - z.writestr('content', contents) - z.close() - z = zipstream.ChunkingZipFile(filename, 'r') - return z.readfile('content') - - - def test_isatty(self): - """ - zip files should not be ttys, so isatty() should be false - """ - self.assertEqual(self.getFileEntry('').isatty(), False) - - - def test_closed(self): - """ - The C{closed} attribute should reflect whether C{close()} has been - called. - """ - fileEntry = self.getFileEntry('') - self.assertEqual(fileEntry.closed, False) - fileEntry.close() - self.assertEqual(fileEntry.closed, True) - - - def test_readline(self): - """ - C{readline()} should mirror L{file.readline} and return up to a single - deliminter. - """ - fileEntry = self.getFileEntry('hoho\nho') - self.assertEqual(fileEntry.readline(), 'hoho\n') - self.assertEqual(fileEntry.readline(), 'ho') - self.assertEqual(fileEntry.readline(), '') - - - def test_next(self): - """ - Zip file entries should implement the iterator protocol as files do. - """ - fileEntry = self.getFileEntry('ho\nhoho') - self.assertEqual(fileEntry.next(), 'ho\n') - self.assertEqual(fileEntry.next(), 'hoho') - self.assertRaises(StopIteration, fileEntry.next) - - - def test_readlines(self): - """ - C{readlines()} should return a list of all the lines. - """ - fileEntry = self.getFileEntry('ho\nho\nho') - self.assertEqual(fileEntry.readlines(), ['ho\n', 'ho\n', 'ho']) - - - def test_iteration(self): - """ - C{__iter__()} and C{xreadlines()} should return C{self}. - """ - fileEntry = self.getFileEntry('') - self.assertIdentical(iter(fileEntry), fileEntry) - self.assertIdentical(fileEntry.xreadlines(), fileEntry) - - - def test_readWhole(self): - """ - C{.read()} should read the entire file. - """ - contents = "Hello, world!" - entry = self.getFileEntry(contents) - self.assertEqual(entry.read(), contents) - - - def test_readPartial(self): - """ - C{.read(num)} should read num bytes from the file. - """ - contents = "0123456789" - entry = self.getFileEntry(contents) - one = entry.read(4) - two = entry.read(200) - self.assertEqual(one, "0123") - self.assertEqual(two, "456789") - - - def test_tell(self): - """ - C{.tell()} should return the number of bytes that have been read so - far. - """ - contents = "x" * 100 - entry = self.getFileEntry(contents) - entry.read(2) - self.assertEqual(entry.tell(), 2) - entry.read(4) - self.assertEqual(entry.tell(), 6) - - - -class DeflatedZipFileEntryTests(FileEntryMixin, unittest.TestCase): - """ - DeflatedZipFileEntry should be file-like - """ - compression = zipfile.ZIP_DEFLATED - - - -class ZipFileEntryTests(FileEntryMixin, unittest.TestCase): - """ - ZipFileEntry should be file-like - """ - compression = zipfile.ZIP_STORED - - - -class ZipstreamTests(unittest.TestCase): - """ - Tests for twisted.python.zipstream - """ - def setUp(self): - """ - Creates junk data that can be compressed and a test directory for any - files that will be created - """ - self.testdir = filepath.FilePath(self.mktemp()) - self.testdir.makedirs() - self.unzipdir = self.testdir.child('unzipped') - self.unzipdir.makedirs() - - - def makeZipFile(self, contents, directory=''): - """ - Makes a zip file archive containing len(contents) files. Contents - should be a list of strings, each string being the content of one file. - """ - zpfilename = self.testdir.child('zipfile.zip').path - zpfile = zipfile.ZipFile(zpfilename, 'w') - for i, content in enumerate(contents): - filename = str(i) - if directory: - filename = directory + "/" + filename - zpfile.writestr(filename, content) - zpfile.close() - return zpfilename - - - def test_invalidMode(self): - """ - A ChunkingZipFile opened in write-mode should not allow .readfile(), - and raise a RuntimeError instead. - """ - czf = zipstream.ChunkingZipFile(self.mktemp(), "w") - self.assertRaises(RuntimeError, czf.readfile, "something") - - - def test_closedArchive(self): - """ - A closed ChunkingZipFile should raise a L{RuntimeError} when - .readfile() is invoked. - """ - czf = zipstream.ChunkingZipFile(self.makeZipFile(["something"]), "r") - czf.close() - self.assertRaises(RuntimeError, czf.readfile, "something") - - - def test_invalidHeader(self): - """ - A zipfile entry with the wrong magic number should raise BadZipfile for - readfile(), but that should not affect other files in the archive. - """ - fn = self.makeZipFile(["test contents", - "more contents"]) - zf = zipfile.ZipFile(fn, "r") - zeroOffset = zf.getinfo("0").header_offset - zf.close() - # Zero out just the one header. - scribble = file(fn, "r+b") - scribble.seek(zeroOffset, 0) - scribble.write(chr(0) * 4) - scribble.close() - czf = zipstream.ChunkingZipFile(fn) - self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - self.assertEqual(czf.readfile("1").read(), "more contents") - - - def test_filenameMismatch(self): - """ - A zipfile entry with a different filename than is found in the central - directory should raise BadZipfile. - """ - fn = self.makeZipFile(["test contents", - "more contents"]) - zf = zipfile.ZipFile(fn, "r") - info = zf.getinfo("0") - info.filename = "not zero" - zf.close() - scribble = file(fn, "r+b") - scribble.seek(info.header_offset, 0) - scribble.write(info.FileHeader()) - scribble.close() - - czf = zipstream.ChunkingZipFile(fn) - self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - self.assertEqual(czf.readfile("1").read(), "more contents") - - - def test_unsupportedCompression(self): - """ - A zipfile which describes an unsupported compression mechanism should - raise BadZipfile. - """ - fn = self.mktemp() - zf = zipfile.ZipFile(fn, "w") - zi = zipfile.ZipInfo("0") - zf.writestr(zi, "some data") - # Mangle its compression type in the central directory; can't do this - # before the writestr call or zipfile will (correctly) tell us not to - # pass bad compression types :) - zi.compress_type = 1234 - zf.close() - - czf = zipstream.ChunkingZipFile(fn) - self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - - - def test_extraData(self): - """ - readfile() should skip over 'extra' data present in the zip metadata. - """ - fn = self.mktemp() - zf = zipfile.ZipFile(fn, 'w') - zi = zipfile.ZipInfo("0") - zi.extra = "hello, extra" - zf.writestr(zi, "the real data") - zf.close() - czf = zipstream.ChunkingZipFile(fn) - self.assertEqual(czf.readfile("0").read(), "the real data") - - - def test_unzipIterChunky(self): - """ - L{twisted.python.zipstream.unzipIterChunky} returns an iterator which - must be exhausted to completely unzip the input archive. - """ - numfiles = 10 - contents = ['This is test file %d!' % i for i in range(numfiles)] - zpfilename = self.makeZipFile(contents) - list(zipstream.unzipIterChunky(zpfilename, self.unzipdir.path)) - self.assertEqual( - set(self.unzipdir.listdir()), - set(map(str, range(numfiles)))) - - for child in self.unzipdir.children(): - num = int(child.basename()) - self.assertEqual(child.getContent(), contents[num]) - - - def test_unzipIterChunkyDirectory(self): - """ - The path to which a file is extracted by L{zipstream.unzipIterChunky} - is determined by joining the C{directory} argument to C{unzip} with the - path within the archive of the file being extracted. - """ - numfiles = 10 - contents = ['This is test file %d!' % i for i in range(numfiles)] - zpfilename = self.makeZipFile(contents, 'foo') - list(zipstream.unzipIterChunky(zpfilename, self.unzipdir.path)) - self.assertEqual( - set(self.unzipdir.child('foo').listdir()), - set(map(str, range(numfiles)))) - - for child in self.unzipdir.child('foo').children(): - num = int(child.basename()) - self.assertEqual(child.getContent(), contents[num]) - - - # XXX these tests are kind of gross and old, but I think unzipIterChunky is - # kind of a gross function anyway. We should really write an abstract - # copyTo/moveTo that operates on FilePath and make sure ZipPath can support - # it, then just deprecate / remove this stuff. - def _unzipIterChunkyTest(self, compression, chunksize, lower, upper): - """ - unzipIterChunky should unzip the given number of bytes per iteration. - """ - junk = ' '.join([str(random.random()) for n in xrange(1000)]) - junkmd5 = md5(junk).hexdigest() - - tempdir = filepath.FilePath(self.mktemp()) - tempdir.makedirs() - zfpath = tempdir.child('bigfile.zip').path - self._makebigfile(zfpath, compression, junk) - uziter = zipstream.unzipIterChunky(zfpath, tempdir.path, - chunksize=chunksize) - r = uziter.next() - # test that the number of chunks is in the right ballpark; - # this could theoretically be any number but statistically it - # should always be in this range - approx = lower < r < upper - self.failUnless(approx) - for r in uziter: - pass - self.assertEqual(r, 0) - newmd5 = md5( - tempdir.child("zipstreamjunk").open().read()).hexdigest() - self.assertEqual(newmd5, junkmd5) - - def test_unzipIterChunkyStored(self): - """ - unzipIterChunky should unzip the given number of bytes per iteration on - a stored archive. - """ - self._unzipIterChunkyTest(zipfile.ZIP_STORED, 500, 35, 45) - - - def test_chunkyDeflated(self): - """ - unzipIterChunky should unzip the given number of bytes per iteration on - a deflated archive. - """ - self._unzipIterChunkyTest(zipfile.ZIP_DEFLATED, 972, 23, 27) - - - def _makebigfile(self, filename, compression, junk): - """ - Create a zip file with the given file name and compression scheme. - """ - zf = zipfile.ZipFile(filename, 'w', compression) - for i in range(10): - fn = 'zipstream%d' % i - zf.writestr(fn, "") - zf.writestr('zipstreamjunk', junk) - zf.close() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/text.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/text.py deleted file mode 100644 index c800715..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/text.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- test-case-name: twisted.test.test_text -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Miscellany of text-munging functions. -""" - - -def stringyString(object, indentation=''): - """ - Expansive string formatting for sequence types. - - C{list.__str__} and C{dict.__str__} use C{repr()} to display their - elements. This function also turns these sequence types - into strings, but uses C{str()} on their elements instead. - - Sequence elements are also displayed on separate lines, and nested - sequences have nested indentation. - """ - braces = '' - sl = [] - - if type(object) is dict: - braces = '{}' - for key, value in object.items(): - value = stringyString(value, indentation + ' ') - if isMultiline(value): - if endsInNewline(value): - value = value[:-len('\n')] - sl.append("%s %s:\n%s" % (indentation, key, value)) - else: - # Oops. Will have to move that indentation. - sl.append("%s %s: %s" % (indentation, key, - value[len(indentation) + 3:])) - - elif type(object) is tuple or type(object) is list: - if type(object) is tuple: - braces = '()' - else: - braces = '[]' - - for element in object: - element = stringyString(element, indentation + ' ') - sl.append(element.rstrip() + ',') - else: - sl[:] = map(lambda s, i=indentation: i + s, - str(object).split('\n')) - - if not sl: - sl.append(indentation) - - if braces: - sl[0] = indentation + braces[0] + sl[0][len(indentation) + 1:] - sl[-1] = sl[-1] + braces[-1] - - s = "\n".join(sl) - - if isMultiline(s) and not endsInNewline(s): - s = s + '\n' - - return s - - -def isMultiline(s): - """ - Returns C{True} if this string has a newline in it. - """ - return (s.find('\n') != -1) - - -def endsInNewline(s): - """ - Returns C{True} if this string ends in a newline. - """ - return (s[-len('\n'):] == '\n') - - -def greedyWrap(inString, width=80): - """ - Given a string and a column width, return a list of lines. - - Caveat: I'm use a stupid greedy word-wrapping - algorythm. I won't put two spaces at the end - of a sentence. I don't do full justification. - And no, I've never even *heard* of hypenation. - """ - - outLines = [] - - #eww, evil hacks to allow paragraphs delimited by two \ns :( - if inString.find('\n\n') >= 0: - paragraphs = inString.split('\n\n') - for para in paragraphs: - outLines.extend(greedyWrap(para, width) + ['']) - return outLines - inWords = inString.split() - - column = 0 - ptr_line = 0 - while inWords: - column = column + len(inWords[ptr_line]) - ptr_line = ptr_line + 1 - - if (column > width): - if ptr_line == 1: - # This single word is too long, it will be the whole line. - pass - else: - # We've gone too far, stop the line one word back. - ptr_line = ptr_line - 1 - (l, inWords) = (inWords[0:ptr_line], inWords[ptr_line:]) - outLines.append(' '.join(l)) - - ptr_line = 0 - column = 0 - elif not (len(inWords) > ptr_line): - # Clean up the last bit. - outLines.append(' '.join(inWords)) - del inWords[:] - else: - # Space - column = column + 1 - # next word - - return outLines - - -wordWrap = greedyWrap - - -def removeLeadingBlanks(lines): - ret = [] - for line in lines: - if ret or line.strip(): - ret.append(line) - return ret - - -def removeLeadingTrailingBlanks(s): - lines = removeLeadingBlanks(s.split('\n')) - lines.reverse() - lines = removeLeadingBlanks(lines) - lines.reverse() - return '\n'.join(lines)+'\n' - - -def splitQuoted(s): - """ - Like a string split, but don't break substrings inside quotes. - - >>> splitQuoted('the "hairy monkey" likes pie') - ['the', 'hairy monkey', 'likes', 'pie'] - - Another one of those "someone must have a better solution for - this" things. This implementation is a VERY DUMB hack done too - quickly. - """ - out = [] - quot = None - phrase = None - for word in s.split(): - if phrase is None: - if word and (word[0] in ("\"", "'")): - quot = word[0] - word = word[1:] - phrase = [] - - if phrase is None: - out.append(word) - else: - if word and (word[-1] == quot): - word = word[:-1] - phrase.append(word) - out.append(" ".join(phrase)) - phrase = None - else: - phrase.append(word) - - return out - - -def strFile(p, f, caseSensitive=True): - """ - Find whether string C{p} occurs in a read()able object C{f}. - - @rtype: C{bool} - """ - buf = "" - buf_len = max(len(p), 2**2**2**2) - if not caseSensitive: - p = p.lower() - while 1: - r = f.read(buf_len-len(p)) - if not caseSensitive: - r = r.lower() - bytes_read = len(r) - if bytes_read == 0: - return False - l = len(buf)+bytes_read-buf_len - if l <= 0: - buf = buf + r - else: - buf = buf[l:] + r - if buf.find(p) != -1: - return True - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/threadable.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/threadable.py deleted file mode 100644 index 2949fc4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/threadable.py +++ /dev/null @@ -1,141 +0,0 @@ -# -*- test-case-name: twisted.python.test_threadable -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A module to provide some very basic threading primitives, such as -synchronization. -""" - -from __future__ import division, absolute_import - -from functools import wraps - -class DummyLock(object): - """ - Hack to allow locks to be unpickled on an unthreaded system. - """ - - def __reduce__(self): - return (unpickle_lock, ()) - - - -def unpickle_lock(): - if threadingmodule is not None: - return XLock() - else: - return DummyLock() -unpickle_lock.__safe_for_unpickling__ = True - - - -def _synchPre(self): - if '_threadable_lock' not in self.__dict__: - _synchLockCreator.acquire() - if '_threadable_lock' not in self.__dict__: - self.__dict__['_threadable_lock'] = XLock() - _synchLockCreator.release() - self._threadable_lock.acquire() - - - -def _synchPost(self): - self._threadable_lock.release() - - - -def _sync(klass, function): - @wraps(function) - def sync(self, *args, **kwargs): - _synchPre(self) - try: - return function(self, *args, **kwargs) - finally: - _synchPost(self) - return sync - - - -def synchronize(*klasses): - """ - Make all methods listed in each class' synchronized attribute synchronized. - - The synchronized attribute should be a list of strings, consisting of the - names of methods that must be synchronized. If we are running in threaded - mode these methods will be wrapped with a lock. - """ - if threadingmodule is not None: - for klass in klasses: - for methodName in klass.synchronized: - sync = _sync(klass, klass.__dict__[methodName]) - setattr(klass, methodName, sync) - - - -def init(with_threads=1): - """Initialize threading. - - Don't bother calling this. If it needs to happen, it will happen. - """ - global threaded, _synchLockCreator, XLock - - if with_threads: - if not threaded: - if threadingmodule is not None: - threaded = True - - class XLock(threadingmodule._RLock, object): - def __reduce__(self): - return (unpickle_lock, ()) - - _synchLockCreator = XLock() - else: - raise RuntimeError("Cannot initialize threading, platform lacks thread support") - else: - if threaded: - raise RuntimeError("Cannot uninitialize threads") - else: - pass - - - -_dummyID = object() -def getThreadID(): - if threadingmodule is None: - return _dummyID - return threadingmodule.currentThread().ident - - - -def isInIOThread(): - """Are we in the thread responsible for I/O requests (the event loop)? - """ - return ioThread == getThreadID() - - - -def registerAsIOThread(): - """Mark the current thread as responsible for I/O requests. - """ - global ioThread - ioThread = getThreadID() - - -ioThread = None -threaded = False -# Define these globals which might be overwritten in init(). -_synchLockCreator = None -XLock = None - - -try: - import threading as threadingmodule -except ImportError: - threadingmodule = None -else: - init(True) - - - -__all__ = ['isInIOThread', 'registerAsIOThread', 'getThreadID', 'XLock'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/threadpool.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/threadpool.py deleted file mode 100644 index b0a7baf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/threadpool.py +++ /dev/null @@ -1,267 +0,0 @@ -# -*- test-case-name: twisted.test.test_threadpool -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -twisted.python.threadpool: a pool of threads to which we dispatch tasks. - -In most cases you can just use C{reactor.callInThread} and friends -instead of creating a thread pool directly. -""" - -from __future__ import division, absolute_import - -try: - from Queue import Queue -except ImportError: - from queue import Queue -import contextlib -import threading -import copy - -from twisted.python import log, context, failure - - -WorkerStop = object() - - -class ThreadPool: - """ - This class (hopefully) generalizes the functionality of a pool of - threads to which work can be dispatched. - - L{callInThread} and L{stop} should only be called from - a single thread, unless you make a subclass where L{stop} and - L{_startSomeWorkers} are synchronized. - - @ivar started: Whether or not the thread pool is currently running. - @type started: L{bool} - @ivar threads: List of workers currently running in this thread pool. - @type threads: L{list} - """ - min = 5 - max = 20 - joined = False - started = False - workers = 0 - name = None - - threadFactory = threading.Thread - currentThread = staticmethod(threading.currentThread) - - def __init__(self, minthreads=5, maxthreads=20, name=None): - """ - Create a new threadpool. - - @param minthreads: minimum number of threads in the pool - @param maxthreads: maximum number of threads in the pool - """ - assert minthreads >= 0, 'minimum is negative' - assert minthreads <= maxthreads, 'minimum is greater than maximum' - self.q = Queue(0) - self.min = minthreads - self.max = maxthreads - self.name = name - self.waiters = [] - self.threads = [] - self.working = [] - - - def start(self): - """ - Start the threadpool. - """ - self.joined = False - self.started = True - # Start some threads. - self.adjustPoolsize() - - - def startAWorker(self): - self.workers += 1 - name = "PoolThread-%s-%s" % (self.name or id(self), self.workers) - newThread = self.threadFactory(target=self._worker, name=name) - self.threads.append(newThread) - newThread.start() - - - def stopAWorker(self): - self.q.put(WorkerStop) - self.workers -= 1 - - - def __setstate__(self, state): - self.__dict__ = state - ThreadPool.__init__(self, self.min, self.max) - - - def __getstate__(self): - state = {} - state['min'] = self.min - state['max'] = self.max - return state - - - def _startSomeWorkers(self): - neededSize = self.q.qsize() + len(self.working) - # Create enough, but not too many - while self.workers < min(self.max, neededSize): - self.startAWorker() - - - def callInThread(self, func, *args, **kw): - """ - Call a callable object in a separate thread. - - @param func: callable object to be called in separate thread - - @param *args: positional arguments to be passed to C{func} - - @param **kw: keyword args to be passed to C{func} - """ - self.callInThreadWithCallback(None, func, *args, **kw) - - - def callInThreadWithCallback(self, onResult, func, *args, **kw): - """ - Call a callable object in a separate thread and call C{onResult} - with the return value, or a L{twisted.python.failure.Failure} - if the callable raises an exception. - - The callable is allowed to block, but the C{onResult} function - must not block and should perform as little work as possible. - - A typical action for C{onResult} for a threadpool used with a - Twisted reactor would be to schedule a - L{twisted.internet.defer.Deferred} to fire in the main - reactor thread using C{.callFromThread}. Note that C{onResult} - is called inside the separate thread, not inside the reactor thread. - - @param onResult: a callable with the signature C{(success, result)}. - If the callable returns normally, C{onResult} is called with - C{(True, result)} where C{result} is the return value of the - callable. If the callable throws an exception, C{onResult} is - called with C{(False, failure)}. - - Optionally, C{onResult} may be C{None}, in which case it is not - called at all. - - @param func: callable object to be called in separate thread - - @param *args: positional arguments to be passed to C{func} - - @param **kwargs: keyword arguments to be passed to C{func} - """ - if self.joined: - return - ctx = context.theContextTracker.currentContext().contexts[-1] - o = (ctx, func, args, kw, onResult) - self.q.put(o) - if self.started: - self._startSomeWorkers() - - - @contextlib.contextmanager - def _workerState(self, stateList, workerThread): - """ - Manages adding and removing this worker from a list of workers - in a particular state. - - @param stateList: the list managing workers in this state - - @param workerThread: the thread the worker is running in, used to - represent the worker in stateList - """ - stateList.append(workerThread) - try: - yield - finally: - stateList.remove(workerThread) - - - def _worker(self): - """ - Method used as target of the created threads: retrieve a task to run - from the threadpool, run it, and proceed to the next task until - threadpool is stopped. - """ - ct = self.currentThread() - o = self.q.get() - while o is not WorkerStop: - with self._workerState(self.working, ct): - ctx, function, args, kwargs, onResult = o - del o - - try: - result = context.call(ctx, function, *args, **kwargs) - success = True - except: - success = False - if onResult is None: - context.call(ctx, log.err) - result = None - else: - result = failure.Failure() - - del function, args, kwargs - - if onResult is not None: - try: - context.call(ctx, onResult, success, result) - except: - context.call(ctx, log.err) - - del ctx, onResult, result - - with self._workerState(self.waiters, ct): - o = self.q.get() - - self.threads.remove(ct) - - - def stop(self): - """ - Shutdown the threads in the threadpool. - """ - self.joined = True - self.started = False - threads = copy.copy(self.threads) - while self.workers: - self.q.put(WorkerStop) - self.workers -= 1 - - # and let's just make sure - # FIXME: threads that have died before calling stop() are not joined. - for thread in threads: - thread.join() - - - def adjustPoolsize(self, minthreads=None, maxthreads=None): - if minthreads is None: - minthreads = self.min - if maxthreads is None: - maxthreads = self.max - - assert minthreads >= 0, 'minimum is negative' - assert minthreads <= maxthreads, 'minimum is greater than maximum' - - self.min = minthreads - self.max = maxthreads - if not self.started: - return - - # Kill of some threads if we have too many. - while self.workers > self.max: - self.stopAWorker() - # Start some threads if we have too few. - while self.workers < self.min: - self.startAWorker() - # Start some threads if there is a need. - self._startSomeWorkers() - - - def dumpStats(self): - log.msg('queue: %s' % self.q.queue) - log.msg('waiters: %s' % self.waiters) - log.msg('workers: %s' % self.working) - log.msg('total: %s' % self.threads) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/twisted-completion.zsh b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/twisted-completion.zsh deleted file mode 100644 index 02fefc6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/twisted-completion.zsh +++ /dev/null @@ -1,33 +0,0 @@ -#compdef twistd trial conch cftp ckeygen lore pyhtmlizer tap2deb tkconch manhole tap2rpm -# -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked all -# over the user's terminal if completing options for a deprecated command. -# Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/urlpath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/urlpath.py deleted file mode 100644 index 11cc767..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/urlpath.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- test-case-name: twisted.test.test_urlpath -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from __future__ import division, absolute_import - -from twisted.python.compat import _PY3 -if not _PY3: - import urlparse - from urllib import unquote as unquoteFunc -else: - import urllib.parse as urlparse - from urllib.parse import unquote as unquoteFunc - - - -class URLPath(object): - def __init__(self, scheme='', netloc='localhost', path='', - query='', fragment=''): - self.scheme = scheme or 'http' - self.netloc = netloc - self.path = path or '/' - self.query = query - self.fragment = fragment - - _qpathlist = None - _uqpathlist = None - - def pathList(self, unquote=0, copy=1): - if self._qpathlist is None: - self._qpathlist = self.path.split('/') - self._uqpathlist = map(unquoteFunc, self._qpathlist) - if unquote: - result = self._uqpathlist - else: - result = self._qpathlist - if copy: - return result[:] - else: - return result - - def fromString(klass, st): - t = urlparse.urlsplit(st) - u = klass(*t) - return u - - fromString = classmethod(fromString) - - def fromRequest(klass, request): - return klass.fromString(request.prePathURL()) - - fromRequest = classmethod(fromRequest) - - def _pathMod(self, newpathsegs, keepQuery): - if keepQuery: - query = self.query - else: - query = '' - return URLPath(self.scheme, - self.netloc, - '/'.join(newpathsegs), - query) - - def sibling(self, path, keepQuery=0): - l = self.pathList() - l[-1] = path - return self._pathMod(l, keepQuery) - - def child(self, path, keepQuery=0): - l = self.pathList() - if l[-1] == '': - l[-1] = path - else: - l.append(path) - return self._pathMod(l, keepQuery) - - def parent(self, keepQuery=0): - l = self.pathList() - if l[-1] == '': - del l[-2] - else: - # We are a file, such as http://example.com/foo/bar - # our parent directory is http://example.com/ - l.pop() - l[-1] = '' - return self._pathMod(l, keepQuery) - - def here(self, keepQuery=0): - l = self.pathList() - if l[-1] != '': - l[-1] = '' - return self._pathMod(l, keepQuery) - - def click(self, st): - """Return a path which is the URL where a browser would presumably take - you if you clicked on a link with an HREF as given. - """ - scheme, netloc, path, query, fragment = urlparse.urlsplit(st) - if not scheme: - scheme = self.scheme - if not netloc: - netloc = self.netloc - if not path: - path = self.path - if not query: - query = self.query - elif path[0] != '/': - l = self.pathList() - l[-1] = path - path = '/'.join(l) - - return URLPath(scheme, - netloc, - path, - query, - fragment) - - - - def __str__(self): - x = urlparse.urlunsplit(( - self.scheme, self.netloc, self.path, - self.query, self.fragment)) - return x - - def __repr__(self): - return ('URLPath(scheme=%r, netloc=%r, path=%r, query=%r, fragment=%r)' - % (self.scheme, self.netloc, self.path, self.query, self.fragment)) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/usage.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/usage.py deleted file mode 100644 index c145245..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/usage.py +++ /dev/null @@ -1,989 +0,0 @@ -# -*- test-case-name: twisted.test.test_usage -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -twisted.python.usage is a module for parsing/handling the -command line of your program. - -For information on how to use it, see -U{http://twistedmatrix.com/projects/core/documentation/howto/options.html}, -or doc/core/howto/options.xhtml in your Twisted directory. -""" - -from __future__ import print_function -from __future__ import division, absolute_import - -# System Imports -import inspect -import os -import sys -import getopt -from os import path -import textwrap - -# Sibling Imports -from twisted.python import reflect, util - - -class UsageError(Exception): - pass - - -error = UsageError - - -class CoerceParameter(object): - """ - Utility class that can corce a parameter before storing it. - """ - def __init__(self, options, coerce): - """ - @param options: parent Options object - @param coerce: callable used to coerce the value. - """ - self.options = options - self.coerce = coerce - self.doc = getattr(self.coerce, 'coerceDoc', '') - - def dispatch(self, parameterName, value): - """ - When called in dispatch, do the coerce for C{value} and save the - returned value. - """ - if value is None: - raise UsageError("Parameter '%s' requires an argument." - % (parameterName,)) - try: - value = self.coerce(value) - except ValueError as e: - raise UsageError("Parameter type enforcement failed: %s" % (e,)) - - self.options.opts[parameterName] = value - - -class Options(dict): - """ - An option list parser class - - C{optFlags} and C{optParameters} are lists of available parameters - which your program can handle. The difference between the two - is the 'flags' have an on(1) or off(0) state (off by default) - whereas 'parameters' have an assigned value, with an optional - default. (Compare '--verbose' and '--verbosity=2') - - optFlags is assigned a list of lists. Each list represents - a flag parameter, as so:: - - optFlags = [['verbose', 'v', 'Makes it tell you what it doing.'], - ['quiet', 'q', 'Be vewy vewy quiet.']] - - As you can see, the first item is the long option name - (prefixed with '--' on the command line), followed by the - short option name (prefixed with '-'), and the description. - The description is used for the built-in handling of the - --help switch, which prints a usage summary. - - C{optParameters} is much the same, except the list also contains - a default value:: - - optParameters = [['outfile', 'O', 'outfile.log', 'Description...']] - - A coerce function can also be specified as the last element: it will be - called with the argument and should return the value that will be stored - for the option. This function can have a C{coerceDoc} attribute which - will be appended to the documentation of the option. - - subCommands is a list of 4-tuples of (command name, command shortcut, - parser class, documentation). If the first non-option argument found is - one of the given command names, an instance of the given parser class is - instantiated and given the remainder of the arguments to parse and - self.opts[command] is set to the command name. For example:: - - subCommands = [ - ['inquisition', 'inquest', InquisitionOptions, - 'Perform an inquisition'], - ['holyquest', 'quest', HolyQuestOptions, - 'Embark upon a holy quest'] - ] - - In this case, C{" holyquest --horseback --for-grail"} will cause - C{HolyQuestOptions} to be instantiated and asked to parse - C{['--horseback', '--for-grail']}. Currently, only the first sub-command - is parsed, and all options following it are passed to its parser. If a - subcommand is found, the subCommand attribute is set to its name and the - subOptions attribute is set to the Option instance that parses the - remaining options. If a subcommand is not given to parseOptions, - the subCommand attribute will be None. You can also mark one of - the subCommands to be the default:: - - defaultSubCommand = 'holyquest' - - In this case, the subCommand attribute will never be None, and - the subOptions attribute will always be set. - - If you want to handle your own options, define a method named - C{opt_paramname} that takes C{(self, option)} as arguments. C{option} - will be whatever immediately follows the parameter on the - command line. Options fully supports the mapping interface, so you - can do things like C{'self["option"] = val'} in these methods. - - Shell tab-completion is supported by this class, for zsh only at present. - Zsh ships with a stub file ("completion function") which, for Twisted - commands, performs tab-completion on-the-fly using the support provided - by this class. The stub file lives in our tree at - C{twisted/python/twisted-completion.zsh}, and in the Zsh tree at - C{Completion/Unix/Command/_twisted}. - - Tab-completion is based upon the contents of the optFlags and optParameters - lists. And, optionally, additional metadata may be provided by assigning a - special attribute, C{compData}, which should be an instance of - C{Completions}. See that class for details of what can and should be - included - and see the howto for additional help using these features - - including how third-parties may take advantage of tab-completion for their - own commands. - - Advanced functionality is covered in the howto documentation, - available at - U{http://twistedmatrix.com/projects/core/documentation/howto/options.html}, - or doc/core/howto/options.xhtml in your Twisted directory. - """ - - subCommand = None - defaultSubCommand = None - parent = None - completionData = None - _shellCompFile = sys.stdout # file to use if shell completion is requested - def __init__(self): - super(Options, self).__init__() - - self.opts = self - self.defaults = {} - - # These are strings/lists we will pass to getopt - self.longOpt = [] - self.shortOpt = '' - self.docs = {} - self.synonyms = {} - self._dispatch = {} - - - collectors = [ - self._gather_flags, - self._gather_parameters, - self._gather_handlers, - ] - - for c in collectors: - (longOpt, shortOpt, docs, settings, synonyms, dispatch) = c() - self.longOpt.extend(longOpt) - self.shortOpt = self.shortOpt + shortOpt - self.docs.update(docs) - - self.opts.update(settings) - self.defaults.update(settings) - - self.synonyms.update(synonyms) - self._dispatch.update(dispatch) - - - __hash__ = object.__hash__ - - - def opt_help(self): - """ - Display this help and exit. - """ - print(self.__str__()) - sys.exit(0) - - def opt_version(self): - """ - Display Twisted version and exit. - """ - from twisted import copyright - print("Twisted version:", copyright.version) - sys.exit(0) - - #opt_h = opt_help # this conflicted with existing 'host' options. - - def parseOptions(self, options=None): - """ - The guts of the command-line parser. - """ - - if options is None: - options = sys.argv[1:] - - # we really do need to place the shell completion check here, because - # if we used an opt_shell_completion method then it would be possible - # for other opt_* methods to be run first, and they could possibly - # raise validation errors which would result in error output on the - # terminal of the user performing shell completion. Validation errors - # would occur quite frequently, in fact, because users often initiate - # tab-completion while they are editing an unfinished command-line. - if len(options) > 1 and options[-2] == "--_shell-completion": - from twisted.python import _shellcomp - cmdName = path.basename(sys.argv[0]) - _shellcomp.shellComplete(self, cmdName, options, - self._shellCompFile) - sys.exit(0) - - try: - opts, args = getopt.getopt(options, - self.shortOpt, self.longOpt) - except getopt.error as e: - raise UsageError(str(e)) - - for opt, arg in opts: - if opt[1] == '-': - opt = opt[2:] - else: - opt = opt[1:] - - optMangled = opt - if optMangled not in self.synonyms: - optMangled = opt.replace("-", "_") - if optMangled not in self.synonyms: - raise UsageError("No such option '%s'" % (opt,)) - - optMangled = self.synonyms[optMangled] - if isinstance(self._dispatch[optMangled], CoerceParameter): - self._dispatch[optMangled].dispatch(optMangled, arg) - else: - self._dispatch[optMangled](optMangled, arg) - - if (getattr(self, 'subCommands', None) - and (args or self.defaultSubCommand is not None)): - if not args: - args = [self.defaultSubCommand] - sub, rest = args[0], args[1:] - for (cmd, short, parser, doc) in self.subCommands: - if sub == cmd or sub == short: - self.subCommand = cmd - self.subOptions = parser() - self.subOptions.parent = self - self.subOptions.parseOptions(rest) - break - else: - raise UsageError("Unknown command: %s" % sub) - else: - try: - self.parseArgs(*args) - except TypeError: - raise UsageError("Wrong number of arguments.") - - self.postOptions() - - def postOptions(self): - """ - I am called after the options are parsed. - - Override this method in your subclass to do something after - the options have been parsed and assigned, like validate that - all options are sane. - """ - - def parseArgs(self): - """ - I am called with any leftover arguments which were not options. - - Override me to do something with the remaining arguments on - the command line, those which were not flags or options. e.g. - interpret them as a list of files to operate on. - - Note that if there more arguments on the command line - than this method accepts, parseArgs will blow up with - a getopt.error. This means if you don't override me, - parseArgs will blow up if I am passed any arguments at - all! - """ - - def _generic_flag(self, flagName, value=None): - if value not in ('', None): - raise UsageError("Flag '%s' takes no argument." - " Not even \"%s\"." % (flagName, value)) - - self.opts[flagName] = 1 - - def _gather_flags(self): - """ - Gather up boolean (flag) options. - """ - - longOpt, shortOpt = [], '' - docs, settings, synonyms, dispatch = {}, {}, {}, {} - - flags = [] - reflect.accumulateClassList(self.__class__, 'optFlags', flags) - - for flag in flags: - long, short, doc = util.padTo(3, flag) - if not long: - raise ValueError("A flag cannot be without a name.") - - docs[long] = doc - settings[long] = 0 - if short: - shortOpt = shortOpt + short - synonyms[short] = long - longOpt.append(long) - synonyms[long] = long - dispatch[long] = self._generic_flag - - return longOpt, shortOpt, docs, settings, synonyms, dispatch - - def _gather_parameters(self): - """ - Gather options which take a value. - """ - longOpt, shortOpt = [], '' - docs, settings, synonyms, dispatch = {}, {}, {}, {} - - parameters = [] - - reflect.accumulateClassList(self.__class__, 'optParameters', - parameters) - - synonyms = {} - - for parameter in parameters: - long, short, default, doc, paramType = util.padTo(5, parameter) - if not long: - raise ValueError("A parameter cannot be without a name.") - - docs[long] = doc - settings[long] = default - if short: - shortOpt = shortOpt + short + ':' - synonyms[short] = long - longOpt.append(long + '=') - synonyms[long] = long - if paramType is not None: - dispatch[long] = CoerceParameter(self, paramType) - else: - dispatch[long] = CoerceParameter(self, str) - - return longOpt, shortOpt, docs, settings, synonyms, dispatch - - - def _gather_handlers(self): - """ - Gather up options with their own handler methods. - - This returns a tuple of many values. Amongst those values is a - synonyms dictionary, mapping all of the possible aliases (C{str}) - for an option to the longest spelling of that option's name - C({str}). - - Another element is a dispatch dictionary, mapping each user-facing - option name (with - substituted for _) to a callable to handle that - option. - """ - - longOpt, shortOpt = [], '' - docs, settings, synonyms, dispatch = {}, {}, {}, {} - - dct = {} - reflect.addMethodNamesToDict(self.__class__, dct, "opt_") - - for name in dct.keys(): - method = getattr(self, 'opt_'+name) - - takesArg = not flagFunction(method, name) - - prettyName = name.replace('_', '-') - doc = getattr(method, '__doc__', None) - if doc: - ## Only use the first line. - #docs[name] = doc.split('\n')[0] - docs[prettyName] = doc - else: - docs[prettyName] = self.docs.get(prettyName) - - synonyms[prettyName] = prettyName - - # A little slight-of-hand here makes dispatching much easier - # in parseOptions, as it makes all option-methods have the - # same signature. - if takesArg: - fn = lambda name, value, m=method: m(value) - else: - # XXX: This won't raise a TypeError if it's called - # with a value when it shouldn't be. - fn = lambda name, value=None, m=method: m() - - dispatch[prettyName] = fn - - if len(name) == 1: - shortOpt = shortOpt + name - if takesArg: - shortOpt = shortOpt + ':' - else: - if takesArg: - prettyName = prettyName + '=' - longOpt.append(prettyName) - - reverse_dct = {} - # Map synonyms - for name in dct.keys(): - method = getattr(self, 'opt_' + name) - if method not in reverse_dct: - reverse_dct[method] = [] - reverse_dct[method].append(name.replace('_', '-')) - - for method, names in reverse_dct.items(): - if len(names) < 2: - continue - longest = max(names, key=len) - for name in names: - synonyms[name] = longest - - return longOpt, shortOpt, docs, settings, synonyms, dispatch - - - def __str__(self): - return self.getSynopsis() + '\n' + self.getUsage(width=None) - - def getSynopsis(self): - """ - Returns a string containing a description of these options and how to - pass them to the executed file. - """ - - default = "%s%s" % (path.basename(sys.argv[0]), - (self.longOpt and " [options]") or '') - if self.parent is None: - default = "Usage: %s%s" % (path.basename(sys.argv[0]), - (self.longOpt and " [options]") or '') - else: - default = '%s' % ((self.longOpt and "[options]") or '') - synopsis = getattr(self, "synopsis", default) - - synopsis = synopsis.rstrip() - - if self.parent is not None: - synopsis = ' '.join((self.parent.getSynopsis(), - self.parent.subCommand, synopsis)) - - return synopsis - - def getUsage(self, width=None): - # If subOptions exists by now, then there was probably an error while - # parsing its options. - if hasattr(self, 'subOptions'): - return self.subOptions.getUsage(width=width) - - if not width: - width = int(os.environ.get('COLUMNS', '80')) - - if hasattr(self, 'subCommands'): - cmdDicts = [] - for (cmd, short, parser, desc) in self.subCommands: - cmdDicts.append( - {'long': cmd, - 'short': short, - 'doc': desc, - 'optType': 'command', - 'default': None - }) - chunks = docMakeChunks(cmdDicts, width) - commands = 'Commands:\n' + ''.join(chunks) - else: - commands = '' - - longToShort = {} - for key, value in self.synonyms.items(): - longname = value - if (key != longname) and (len(key) == 1): - longToShort[longname] = key - else: - if longname not in longToShort: - longToShort[longname] = None - else: - pass - - optDicts = [] - for opt in self.longOpt: - if opt[-1] == '=': - optType = 'parameter' - opt = opt[:-1] - else: - optType = 'flag' - - optDicts.append( - {'long': opt, - 'short': longToShort[opt], - 'doc': self.docs[opt], - 'optType': optType, - 'default': self.defaults.get(opt, None), - 'dispatch': self._dispatch.get(opt, None) - }) - - if not (getattr(self, "longdesc", None) is None): - longdesc = self.longdesc - else: - import __main__ - if getattr(__main__, '__doc__', None): - longdesc = __main__.__doc__ - else: - longdesc = '' - - if longdesc: - longdesc = ('\n' + - '\n'.join(textwrap.wrap(longdesc, width)).strip() - + '\n') - - if optDicts: - chunks = docMakeChunks(optDicts, width) - s = "Options:\n%s" % (''.join(chunks)) - else: - s = "Options: None\n" - - return s + longdesc + commands - - #def __repr__(self): - # XXX: It'd be cool if we could return a succinct representation - # of which flags and options are set here. - - -_ZSH = 'zsh' -_BASH = 'bash' - -class Completer(object): - """ - A completion "action" - provides completion possibilities for a particular - command-line option. For example we might provide the user a fixed list of - choices, or files/dirs according to a glob. - - This class produces no completion matches itself - see the various - subclasses for specific completion functionality. - """ - _descr = None - def __init__(self, descr=None, repeat=False): - """ - @type descr: C{str} - @param descr: An optional descriptive string displayed above matches. - - @type repeat: C{bool} - @param repeat: A flag, defaulting to False, indicating whether this - C{Completer} should repeat - that is, be used to complete more - than one command-line word. This may ONLY be set to True for - actions in the C{extraActions} keyword argument to C{Completions}. - And ONLY if it is the LAST (or only) action in the C{extraActions} - list. - """ - if descr is not None: - self._descr = descr - self._repeat = repeat - - - def _getRepeatFlag(self): - if self._repeat: - return "*" - else: - return "" - _repeatFlag = property(_getRepeatFlag) - - - def _description(self, optName): - if self._descr is not None: - return self._descr - else: - return optName - - - def _shellCode(self, optName, shellType): - """ - Fetch a fragment of shell code representing this action which is - suitable for use by the completion system in _shellcomp.py - - @type optName: C{str} - @param optName: The long name of the option this action is being - used for. - - @type shellType: C{str} - @param shellType: One of the supported shell constants e.g. - C{twisted.python.usage._ZSH} - """ - if shellType == _ZSH: - return "%s:%s:" % (self._repeatFlag, - self._description(optName)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteFiles(Completer): - """ - Completes file names based on a glob pattern - """ - def __init__(self, globPattern='*', **kw): - Completer.__init__(self, **kw) - self._globPattern = globPattern - - - def _description(self, optName): - if self._descr is not None: - return "%s (%s)" % (self._descr, self._globPattern) - else: - return "%s (%s)" % (optName, self._globPattern) - - - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:_files -g \"%s\"" % (self._repeatFlag, - self._description(optName), - self._globPattern,) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteDirs(Completer): - """ - Completes directory names - """ - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:_directories" % (self._repeatFlag, - self._description(optName)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteList(Completer): - """ - Completes based on a fixed list of words - """ - def __init__(self, items, **kw): - Completer.__init__(self, **kw) - self._items = items - - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:(%s)" % (self._repeatFlag, - self._description(optName), - " ".join(self._items,)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteMultiList(Completer): - """ - Completes multiple comma-separated items based on a fixed list of words - """ - def __init__(self, items, **kw): - Completer.__init__(self, **kw) - self._items = items - - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:_values -s , '%s' %s" % (self._repeatFlag, - self._description(optName), - self._description(optName), - " ".join(self._items)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteUsernames(Completer): - """ - Complete usernames - """ - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:_users" % (self._repeatFlag, - self._description(optName)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteGroups(Completer): - """ - Complete system group names - """ - _descr = 'group' - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:_groups" % (self._repeatFlag, - self._description(optName)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteHostnames(Completer): - """ - Complete hostnames - """ - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:_hosts" % (self._repeatFlag, - self._description(optName)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteUserAtHost(Completer): - """ - A completion action which produces matches in any of these forms:: - - - @ - """ - _descr = 'host | user@host' - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - # Yes this looks insane but it does work. For bonus points - # add code to grep 'Hostname' lines from ~/.ssh/config - return ('%s:%s:{_ssh;if compset -P "*@"; ' - 'then _wanted hosts expl "remote host name" _ssh_hosts ' - '&& ret=0 elif compset -S "@*"; then _wanted users ' - 'expl "login name" _ssh_users -S "" && ret=0 ' - 'else if (( $+opt_args[-l] )); then tmp=() ' - 'else tmp=( "users:login name:_ssh_users -qS@" ) fi; ' - '_alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]"' - ' && ret=0 fi}' % (self._repeatFlag, - self._description(optName))) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class CompleteNetInterfaces(Completer): - """ - Complete network interface names - """ - def _shellCode(self, optName, shellType): - if shellType == _ZSH: - return "%s:%s:_net_interfaces" % (self._repeatFlag, - self._description(optName)) - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class Completions(object): - """ - Extra metadata for the shell tab-completion system. - - @type descriptions: C{dict} - @ivar descriptions: ex. C{{"foo" : "use this description for foo instead"}} - A dict mapping long option names to alternate descriptions. When this - variable is defined, the descriptions contained here will override - those descriptions provided in the optFlags and optParameters - variables. - - @type multiUse: C{list} - @ivar multiUse: ex. C{ ["foo", "bar"] } - An iterable containing those long option names which may appear on the - command line more than once. By default, options will only be completed - one time. - - @type mutuallyExclusive: C{list} of C{tuple} - @ivar mutuallyExclusive: ex. C{ [("foo", "bar"), ("bar", "baz")] } - A sequence of sequences, with each sub-sequence containing those long - option names that are mutually exclusive. That is, those options that - cannot appear on the command line together. - - @type optActions: C{dict} - @ivar optActions: A dict mapping long option names to shell "actions". - These actions define what may be completed as the argument to the - given option. By default, all files/dirs will be completed if no - action is given. For example:: - - {"foo" : CompleteFiles("*.py", descr="python files"), - "bar" : CompleteList(["one", "two", "three"]), - "colors" : CompleteMultiList(["red", "green", "blue"])} - - Callables may instead be given for the values in this dict. The - callable should accept no arguments, and return a C{Completer} - instance used as the action in the same way as the literal actions in - the example above. - - As you can see in the example above. The "foo" option will have files - that end in .py completed when the user presses Tab. The "bar" - option will have either of the strings "one", "two", or "three" - completed when the user presses Tab. - - "colors" will allow multiple arguments to be completed, separated by - commas. The possible arguments are red, green, and blue. Examples:: - - my_command --foo some-file.foo --colors=red,green - my_command --colors=green - my_command --colors=green,blue - - Descriptions for the actions may be given with the optional C{descr} - keyword argument. This is separate from the description of the option - itself. - - Normally Zsh does not show these descriptions unless you have - "verbose" completion turned on. Turn on verbosity with this in your - ~/.zshrc:: - - zstyle ':completion:*' verbose yes - zstyle ':completion:*:descriptions' format '%B%d%b' - - @type extraActions: C{list} - @ivar extraActions: Extra arguments are those arguments typically - appearing at the end of the command-line, which are not associated - with any particular named option. That is, the arguments that are - given to the parseArgs() method of your usage.Options subclass. For - example:: - [CompleteFiles(descr="file to read from"), - Completer(descr="book title")] - - In the example above, the 1st non-option argument will be described as - "file to read from" and all file/dir names will be completed (*). The - 2nd non-option argument will be described as "book title", but no - actual completion matches will be produced. - - See the various C{Completer} subclasses for other types of things which - may be tab-completed (users, groups, network interfaces, etc). - - Also note the C{repeat=True} flag which may be passed to any of the - C{Completer} classes. This is set to allow the C{Completer} instance - to be re-used for subsequent command-line words. See the C{Completer} - docstring for details. - """ - def __init__(self, descriptions={}, multiUse=[], - mutuallyExclusive=[], optActions={}, extraActions=[]): - self.descriptions = descriptions - self.multiUse = multiUse - self.mutuallyExclusive = mutuallyExclusive - self.optActions = optActions - self.extraActions = extraActions - - - -def docMakeChunks(optList, width=80): - """ - Makes doc chunks for option declarations. - - Takes a list of dictionaries, each of which may have one or more - of the keys 'long', 'short', 'doc', 'default', 'optType'. - - Returns a list of strings. - The strings may be multiple lines, - all of them end with a newline. - """ - - # XXX: sanity check to make sure we have a sane combination of keys. - - maxOptLen = 0 - for opt in optList: - optLen = len(opt.get('long', '')) - if optLen: - if opt.get('optType', None) == "parameter": - # these take up an extra character - optLen = optLen + 1 - maxOptLen = max(optLen, maxOptLen) - - colWidth1 = maxOptLen + len(" -s, -- ") - colWidth2 = width - colWidth1 - # XXX - impose some sane minimum limit. - # Then if we don't have enough room for the option and the doc - # to share one line, they can take turns on alternating lines. - - colFiller1 = " " * colWidth1 - - optChunks = [] - seen = {} - for opt in optList: - if opt.get('short', None) in seen or opt.get('long', None) in seen: - continue - for x in opt.get('short', None), opt.get('long', None): - if x is not None: - seen[x] = 1 - - optLines = [] - comma = " " - if opt.get('short', None): - short = "-%c" % (opt['short'],) - else: - short = '' - - if opt.get('long', None): - long = opt['long'] - if opt.get("optType", None) == "parameter": - long = long + '=' - - long = "%-*s" % (maxOptLen, long) - if short: - comma = "," - else: - long = " " * (maxOptLen + len('--')) - - if opt.get('optType', None) == 'command': - column1 = ' %s ' % long - else: - column1 = " %2s%c --%s " % (short, comma, long) - - if opt.get('doc', ''): - doc = opt['doc'].strip() - else: - doc = '' - - if (opt.get("optType", None) == "parameter") \ - and not (opt.get('default', None) is None): - doc = "%s [default: %s]" % (doc, opt['default']) - - if (opt.get("optType", None) == "parameter") \ - and opt.get('dispatch', None) is not None: - d = opt['dispatch'] - if isinstance(d, CoerceParameter) and d.doc: - doc = "%s. %s" % (doc, d.doc) - - if doc: - column2_l = textwrap.wrap(doc, colWidth2) - else: - column2_l = [''] - - optLines.append("%s%s\n" % (column1, column2_l.pop(0))) - - for line in column2_l: - optLines.append("%s%s\n" % (colFiller1, line)) - - optChunks.append(''.join(optLines)) - - return optChunks - - - -def flagFunction(method, name=None): - """ - Determine whether a function is an optional handler for a I{flag} or an - I{option}. - - A I{flag} handler takes no additional arguments. It is used to handle - command-line arguments like I{--nodaemon}. - - An I{option} handler takes one argument. It is used to handle command-line - arguments like I{--path=/foo/bar}. - - @param method: The bound method object to inspect. - - @param name: The name of the option for which the function is a handle. - @type name: L{str} - - @raise UsageError: If the method takes more than one argument. - - @return: If the method is a flag handler, return C{True}. Otherwise return - C{False}. - """ - reqArgs = len(inspect.getargspec(method).args) - if reqArgs > 2: - raise UsageError('Invalid Option function for %s' % - (name or method.__name__)) - if reqArgs == 2: - return False - return True - - - -def portCoerce(value): - """ - Coerce a string value to an int port number, and checks the validity. - """ - value = int(value) - if value < 0 or value > 65535: - raise ValueError("Port number not in range: %s" % (value,)) - return value -portCoerce.coerceDoc = "Must be an int between 0 and 65535." diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/util.py deleted file mode 100644 index 0444550..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/util.py +++ /dev/null @@ -1,1045 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_util -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from __future__ import division, absolute_import - -import os, sys, errno, warnings -try: - import pwd, grp -except ImportError: - pwd = grp = None -try: - from os import setgroups, getgroups -except ImportError: - setgroups = getgroups = None - -from twisted.python.compat import _PY3, unicode -if _PY3: - UserDict = object -else: - from UserDict import UserDict - - - -class InsensitiveDict: - """Dictionary, that has case-insensitive keys. - - Normally keys are retained in their original form when queried with - .keys() or .items(). If initialized with preserveCase=0, keys are both - looked up in lowercase and returned in lowercase by .keys() and .items(). - """ - """ - Modified recipe at - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66315 originally - contributed by Sami Hangaslammi. - """ - - def __init__(self, dict=None, preserve=1): - """Create an empty dictionary, or update from 'dict'.""" - self.data = {} - self.preserve=preserve - if dict: - self.update(dict) - - def __delitem__(self, key): - k=self._lowerOrReturn(key) - del self.data[k] - - def _lowerOrReturn(self, key): - if isinstance(key, bytes) or isinstance(key, unicode): - return key.lower() - else: - return key - - def __getitem__(self, key): - """Retrieve the value associated with 'key' (in any case).""" - k = self._lowerOrReturn(key) - return self.data[k][1] - - def __setitem__(self, key, value): - """Associate 'value' with 'key'. If 'key' already exists, but - in different case, it will be replaced.""" - k = self._lowerOrReturn(key) - self.data[k] = (key, value) - - def has_key(self, key): - """Case insensitive test whether 'key' exists.""" - k = self._lowerOrReturn(key) - return k in self.data - - __contains__=has_key - - def _doPreserve(self, key): - if not self.preserve and (isinstance(key, bytes) - or isinstance(key, unicode)): - return key.lower() - else: - return key - - def keys(self): - """List of keys in their original case.""" - return list(self.iterkeys()) - - def values(self): - """List of values.""" - return list(self.itervalues()) - - def items(self): - """List of (key,value) pairs.""" - return list(self.iteritems()) - - def get(self, key, default=None): - """Retrieve value associated with 'key' or return default value - if 'key' doesn't exist.""" - try: - return self[key] - except KeyError: - return default - - def setdefault(self, key, default): - """If 'key' doesn't exists, associate it with the 'default' value. - Return value associated with 'key'.""" - if not self.has_key(key): - self[key] = default - return self[key] - - def update(self, dict): - """Copy (key,value) pairs from 'dict'.""" - for k,v in dict.items(): - self[k] = v - - def __repr__(self): - """String representation of the dictionary.""" - items = ", ".join([("%r: %r" % (k,v)) for k,v in self.items()]) - return "InsensitiveDict({%s})" % items - - def iterkeys(self): - for v in self.data.values(): - yield self._doPreserve(v[0]) - - def itervalues(self): - for v in self.data.values(): - yield v[1] - - def iteritems(self): - for (k, v) in self.data.values(): - yield self._doPreserve(k), v - - def popitem(self): - i=self.items()[0] - del self[i[0]] - return i - - def clear(self): - for k in self.keys(): - del self[k] - - def copy(self): - return InsensitiveDict(self, self.preserve) - - def __len__(self): - return len(self.data) - - def __eq__(self, other): - for k,v in self.items(): - if not (k in other) or not (other[k]==v): - return 0 - return len(self)==len(other) - - - -class OrderedDict(UserDict): - """A UserDict that preserves insert order whenever possible.""" - def __init__(self, dict=None, **kwargs): - self._order = [] - self.data = {} - if dict is not None: - if hasattr(dict,'keys'): - self.update(dict) - else: - for k,v in dict: # sequence - self[k] = v - if len(kwargs): - self.update(kwargs) - def __repr__(self): - return '{'+', '.join([('%r: %r' % item) for item in self.items()])+'}' - - def __setitem__(self, key, value): - if not self.has_key(key): - self._order.append(key) - UserDict.__setitem__(self, key, value) - - def copy(self): - return self.__class__(self) - - def __delitem__(self, key): - UserDict.__delitem__(self, key) - self._order.remove(key) - - def iteritems(self): - for item in self._order: - yield (item, self[item]) - - def items(self): - return list(self.iteritems()) - - def itervalues(self): - for item in self._order: - yield self[item] - - def values(self): - return list(self.itervalues()) - - def iterkeys(self): - return iter(self._order) - - def keys(self): - return list(self._order) - - def popitem(self): - key = self._order[-1] - value = self[key] - del self[key] - return (key, value) - - def setdefault(self, item, default): - if self.has_key(item): - return self[item] - self[item] = default - return default - - def update(self, d): - for k, v in d.items(): - self[k] = v - -def uniquify(lst): - """Make the elements of a list unique by inserting them into a dictionary. - This must not change the order of the input lst. - """ - dct = {} - result = [] - for k in lst: - if k not in dct: - result.append(k) - dct[k] = 1 - return result - -def padTo(n, seq, default=None): - """ - Pads a sequence out to n elements, - - filling in with a default value if it is not long enough. - - If the input sequence is longer than n, raises ValueError. - - Details, details: - This returns a new list; it does not extend the original sequence. - The new list contains the values of the original sequence, not copies. - """ - - if len(seq) > n: - raise ValueError("%d elements is more than %d." % (len(seq), n)) - - blank = [default] * n - - blank[:len(seq)] = list(seq) - - return blank - - -def getPluginDirs(): - warnings.warn( - "twisted.python.util.getPluginDirs is deprecated since Twisted 12.2.", - DeprecationWarning, stacklevel=2) - import twisted - systemPlugins = os.path.join(os.path.dirname(os.path.dirname( - os.path.abspath(twisted.__file__))), 'plugins') - userPlugins = os.path.expanduser("~/TwistedPlugins") - confPlugins = os.path.expanduser("~/.twisted") - allPlugins = filter(os.path.isdir, [systemPlugins, userPlugins, confPlugins]) - return allPlugins - - -def addPluginDir(): - warnings.warn( - "twisted.python.util.addPluginDir is deprecated since Twisted 12.2.", - DeprecationWarning, stacklevel=2) - sys.path.extend(getPluginDirs()) - - -def sibpath(path, sibling): - """ - Return the path to a sibling of a file in the filesystem. - - This is useful in conjunction with the special C{__file__} attribute - that Python provides for modules, so modules can load associated - resource files. - """ - return os.path.join(os.path.dirname(os.path.abspath(path)), sibling) - - -def _getpass(prompt): - """ - Helper to turn IOErrors into KeyboardInterrupts. - """ - import getpass - try: - return getpass.getpass(prompt) - except IOError as e: - if e.errno == errno.EINTR: - raise KeyboardInterrupt - raise - except EOFError: - raise KeyboardInterrupt - -def getPassword(prompt = 'Password: ', confirm = 0, forceTTY = 0, - confirmPrompt = 'Confirm password: ', - mismatchMessage = "Passwords don't match."): - """Obtain a password by prompting or from stdin. - - If stdin is a terminal, prompt for a new password, and confirm (if - C{confirm} is true) by asking again to make sure the user typed the same - thing, as keystrokes will not be echoed. - - If stdin is not a terminal, and C{forceTTY} is not true, read in a line - and use it as the password, less the trailing newline, if any. If - C{forceTTY} is true, attempt to open a tty and prompt for the password - using it. Raise a RuntimeError if this is not possible. - - @returns: C{str} - """ - isaTTY = hasattr(sys.stdin, 'isatty') and sys.stdin.isatty() - - old = None - try: - if not isaTTY: - if forceTTY: - try: - old = sys.stdin, sys.stdout - sys.stdin = sys.stdout = open('/dev/tty', 'r+') - except: - raise RuntimeError("Cannot obtain a TTY") - else: - password = sys.stdin.readline() - if password[-1] == '\n': - password = password[:-1] - return password - - while 1: - try1 = _getpass(prompt) - if not confirm: - return try1 - try2 = _getpass(confirmPrompt) - if try1 == try2: - return try1 - else: - sys.stderr.write(mismatchMessage + "\n") - finally: - if old: - sys.stdin.close() - sys.stdin, sys.stdout = old - - -def println(*a): - sys.stdout.write(' '.join(map(str, a))+'\n') - -# XXX -# This does not belong here -# But where does it belong? - -def str_xor(s, b): - return ''.join([chr(ord(c) ^ b) for c in s]) - - -def makeStatBar(width, maxPosition, doneChar = '=', undoneChar = '-', currentChar = '>'): - """ - Creates a function that will return a string representing a progress bar. - """ - aValue = width / float(maxPosition) - def statBar(position, force = 0, last = ['']): - assert len(last) == 1, "Don't mess with the last parameter." - done = int(aValue * position) - toDo = width - done - 2 - result = "[%s%s%s]" % (doneChar * done, currentChar, undoneChar * toDo) - if force: - last[0] = result - return result - if result == last[0]: - return '' - last[0] = result - return result - - statBar.__doc__ = """statBar(position, force = 0) -> '[%s%s%s]'-style progress bar - - returned string is %d characters long, and the range goes from 0..%d. - The 'position' argument is where the '%s' will be drawn. If force is false, - '' will be returned instead if the resulting progress bar is identical to the - previously returned progress bar. -""" % (doneChar * 3, currentChar, undoneChar * 3, width, maxPosition, currentChar) - return statBar - - -def spewer(frame, s, ignored): - """ - A trace function for sys.settrace that prints every function or method call. - """ - from twisted.python import reflect - if frame.f_locals.has_key('self'): - se = frame.f_locals['self'] - if hasattr(se, '__class__'): - k = reflect.qual(se.__class__) - else: - k = reflect.qual(type(se)) - print('method %s of %s at %s' % ( - frame.f_code.co_name, k, id(se))) - else: - print('function %s in %s, line %s' % ( - frame.f_code.co_name, - frame.f_code.co_filename, - frame.f_lineno)) - - -def searchupwards(start, files=[], dirs=[]): - """ - Walk upwards from start, looking for a directory containing - all files and directories given as arguments:: - >>> searchupwards('.', ['foo.txt'], ['bar', 'bam']) - - If not found, return None - """ - start=os.path.abspath(start) - parents=start.split(os.sep) - exists=os.path.exists; join=os.sep.join; isdir=os.path.isdir - while len(parents): - candidate=join(parents)+os.sep - allpresent=1 - for f in files: - if not exists("%s%s" % (candidate, f)): - allpresent=0 - break - if allpresent: - for d in dirs: - if not isdir("%s%s" % (candidate, d)): - allpresent=0 - break - if allpresent: return candidate - parents.pop(-1) - return None - - -class LineLog: - """ - A limited-size line-based log, useful for logging line-based - protocols such as SMTP. - - When the log fills up, old entries drop off the end. - """ - def __init__(self, size=10): - """ - Create a new log, with size lines of storage (default 10). - A log size of 0 (or less) means an infinite log. - """ - if size < 0: - size = 0 - self.log = [None]*size - self.size = size - - def append(self,line): - if self.size: - self.log[:-1] = self.log[1:] - self.log[-1] = line - else: - self.log.append(line) - - def str(self): - return '\n'.join(filter(None,self.log)) - - def __getitem__(self, item): - return filter(None,self.log)[item] - - def clear(self): - """Empty the log""" - self.log = [None]*self.size - - -def raises(exception, f, *args, **kwargs): - """ - Determine whether the given call raises the given exception. - """ - try: - f(*args, **kwargs) - except exception: - return 1 - return 0 - - -class IntervalDifferential: - """ - Given a list of intervals, generate the amount of time to sleep between - "instants". - - For example, given 7, 11 and 13, the three (infinite) sequences:: - - 7 14 21 28 35 ... - 11 22 33 44 ... - 13 26 39 52 ... - - will be generated, merged, and used to produce:: - - (7, 0) (4, 1) (2, 2) (1, 0) (7, 0) (1, 1) (4, 2) (2, 0) (5, 1) (2, 0) - - New intervals may be added or removed as iteration proceeds using the - proper methods. - """ - - def __init__(self, intervals, default=60): - """ - @type intervals: C{list} of C{int}, C{long}, or C{float} param - @param intervals: The intervals between instants. - - @type default: C{int}, C{long}, or C{float} - @param default: The duration to generate if the intervals list - becomes empty. - """ - self.intervals = intervals[:] - self.default = default - - def __iter__(self): - return _IntervalDifferentialIterator(self.intervals, self.default) - - -class _IntervalDifferentialIterator: - def __init__(self, i, d): - - self.intervals = [[e, e, n] for (e, n) in zip(i, range(len(i)))] - self.default = d - self.last = 0 - - def next(self): - if not self.intervals: - return (self.default, None) - last, index = self.intervals[0][0], self.intervals[0][2] - self.intervals[0][0] += self.intervals[0][1] - self.intervals.sort() - result = last - self.last - self.last = last - return result, index - - def addInterval(self, i): - if self.intervals: - delay = self.intervals[0][0] - self.intervals[0][1] - self.intervals.append([delay + i, i, len(self.intervals)]) - self.intervals.sort() - else: - self.intervals.append([i, i, 0]) - - def removeInterval(self, interval): - for i in range(len(self.intervals)): - if self.intervals[i][1] == interval: - index = self.intervals[i][2] - del self.intervals[i] - for i in self.intervals: - if i[2] > index: - i[2] -= 1 - return - raise ValueError("Specified interval not in IntervalDifferential") - - - -class FancyStrMixin: - """ - Mixin providing a flexible implementation of C{__str__}. - - C{__str__} output will begin with the name of the class, or the contents - of the attribute C{fancybasename} if it is set. - - The body of C{__str__} can be controlled by overriding C{showAttributes} in - a subclass. Set C{showAttributes} to a sequence of strings naming - attributes, or sequences of C{(attributeName, callable)}, or sequences of - C{(attributeName, displayName, formatCharacter)}. In the second case, the - callable is passed the value of the attribute and its return value used in - the output of C{__str__}. In the final case, the attribute is looked up - using C{attributeName}, but the output uses C{displayName} instead, and - renders the value of the attribute using C{formatCharacter}, e.g. C{"%.3f"} - might be used for a float. - """ - # Override in subclasses: - showAttributes = () - - - def __str__(self): - r = ['<', (hasattr(self, 'fancybasename') and self.fancybasename) - or self.__class__.__name__] - for attr in self.showAttributes: - if isinstance(attr, str): - r.append(' %s=%r' % (attr, getattr(self, attr))) - elif len(attr) == 2: - r.append((' %s=' % (attr[0],)) + attr[1](getattr(self, attr[0]))) - else: - r.append((' %s=' + attr[2]) % (attr[1], getattr(self, attr[0]))) - r.append('>') - return ''.join(r) - - __repr__ = __str__ - - - -class FancyEqMixin: - """ - Mixin that implements C{__eq__} and C{__ne__}. - - Comparison is done using the list of attributes defined in - C{compareAttributes}. - """ - compareAttributes = () - - def __eq__(self, other): - if not self.compareAttributes: - return self is other - if isinstance(self, other.__class__): - return ( - [getattr(self, name) for name in self.compareAttributes] == - [getattr(other, name) for name in self.compareAttributes]) - return NotImplemented - - - def __ne__(self, other): - result = self.__eq__(other) - if result is NotImplemented: - return result - return not result - - - -try: - # Python 2.7 / Python 3.3 - from os import initgroups as _c_initgroups -except ImportError: - try: - # Python 2.6 - from twisted.python._initgroups import initgroups as _c_initgroups - except ImportError: - _c_initgroups = None - - - -if pwd is None or grp is None or setgroups is None or getgroups is None: - def initgroups(uid, primaryGid): - """ - Do nothing. - - Underlying platform support require to manipulate groups is missing. - """ -else: - # Fallback to the inefficient Python version - def _setgroups_until_success(l): - while(1): - # NASTY NASTY HACK (but glibc does it so it must be okay): - # In case sysconfig didn't give the right answer, find the limit - # on max groups by just looping, trying to set fewer and fewer - # groups each time until it succeeds. - try: - setgroups(l) - except ValueError: - # This exception comes from python itself restricting - # number of groups allowed. - if len(l) > 1: - del l[-1] - else: - raise - except OSError as e: - if e.errno == errno.EINVAL and len(l) > 1: - # This comes from the OS saying too many groups - del l[-1] - else: - raise - else: - # Success, yay! - return - - def initgroups(uid, primaryGid): - """ - Initializes the group access list. - - If the C extension is present, we're calling it, which in turn calls - initgroups(3). - - If not, this is done by reading the group database /etc/group and using - all groups of which C{uid} is a member. The additional group - C{primaryGid} is also added to the list. - - If the given user is a member of more than C{NGROUPS}, arbitrary - groups will be silently discarded to bring the number below that - limit. - - @type uid: C{int} - @param uid: The UID for which to look up group information. - - @type primaryGid: C{int} or C{NoneType} - @param primaryGid: If provided, an additional GID to include when - setting the groups. - """ - if _c_initgroups is not None: - return _c_initgroups(pwd.getpwuid(uid)[0], primaryGid) - try: - # Try to get the maximum number of groups - max_groups = os.sysconf("SC_NGROUPS_MAX") - except: - # No predefined limit - max_groups = 0 - - username = pwd.getpwuid(uid)[0] - l = [] - if primaryGid is not None: - l.append(primaryGid) - for groupname, password, gid, userlist in grp.getgrall(): - if username in userlist: - l.append(gid) - if len(l) == max_groups: - break # No more groups, ignore any more - try: - _setgroups_until_success(l) - except OSError as e: - # We might be able to remove this code now that we - # don't try to setgid/setuid even when not asked to. - if e.errno == errno.EPERM: - for g in getgroups(): - if g not in l: - raise - else: - raise - - - -def switchUID(uid, gid, euid=False): - """ - Attempts to switch the uid/euid and gid/egid for the current process. - - If C{uid} is the same value as L{os.getuid} (or L{os.geteuid}), - this function will issue a L{UserWarning} and not raise an exception. - - @type uid: C{int} or C{NoneType} - @param uid: the UID (or EUID) to switch the current process to. This - parameter will be ignored if the value is C{None}. - - @type gid: C{int} or C{NoneType} - @param gid: the GID (or EGID) to switch the current process to. This - parameter will be ignored if the value is C{None}. - - @type euid: C{bool} - @param euid: if True, set only effective user-id rather than real user-id. - (This option has no effect unless the process is running - as root, in which case it means not to shed all - privileges, retaining the option to regain privileges - in cases such as spawning processes. Use with caution.) - """ - if euid: - setuid = os.seteuid - setgid = os.setegid - getuid = os.geteuid - else: - setuid = os.setuid - setgid = os.setgid - getuid = os.getuid - if gid is not None: - setgid(gid) - if uid is not None: - if uid == getuid(): - uidText = (euid and "euid" or "uid") - actionText = "tried to drop privileges and set%s %s" % (uidText, uid) - problemText = "%s is already %s" % (uidText, getuid()) - warnings.warn("%s but %s; should we be root? Continuing." - % (actionText, problemText)) - else: - initgroups(uid, gid) - setuid(uid) - - -class SubclassableCStringIO(object): - """ - A wrapper around cStringIO to allow for subclassing. - """ - __csio = None - - def __init__(self, *a, **kw): - from cStringIO import StringIO - self.__csio = StringIO(*a, **kw) - - def __iter__(self): - return self.__csio.__iter__() - - def next(self): - return self.__csio.next() - - def close(self): - return self.__csio.close() - - def isatty(self): - return self.__csio.isatty() - - def seek(self, pos, mode=0): - return self.__csio.seek(pos, mode) - - def tell(self): - return self.__csio.tell() - - def read(self, n=-1): - return self.__csio.read(n) - - def readline(self, length=None): - return self.__csio.readline(length) - - def readlines(self, sizehint=0): - return self.__csio.readlines(sizehint) - - def truncate(self, size=None): - return self.__csio.truncate(size) - - def write(self, s): - return self.__csio.write(s) - - def writelines(self, list): - return self.__csio.writelines(list) - - def flush(self): - return self.__csio.flush() - - def getvalue(self): - return self.__csio.getvalue() - - - -def untilConcludes(f, *a, **kw): - """ - Call C{f} with the given arguments, handling C{EINTR} by retrying. - - @param f: A function to call. - - @param *a: Positional arguments to pass to C{f}. - - @param **kw: Keyword arguments to pass to C{f}. - - @return: Whatever C{f} returns. - - @raise: Whatever C{f} raises, except for C{IOError} or C{OSError} with - C{errno} set to C{EINTR}. - """ - while True: - try: - return f(*a, **kw) - except (IOError, OSError) as e: - if e.args[0] == errno.EINTR: - continue - raise - - - -def mergeFunctionMetadata(f, g): - """ - Overwrite C{g}'s name and docstring with values from C{f}. Update - C{g}'s instance dictionary with C{f}'s. - - @return: A function that has C{g}'s behavior and metadata merged from - C{f}. - """ - try: - g.__name__ = f.__name__ - except TypeError: - pass - try: - g.__doc__ = f.__doc__ - except (TypeError, AttributeError): - pass - try: - g.__dict__.update(f.__dict__) - except (TypeError, AttributeError): - pass - try: - g.__module__ = f.__module__ - except TypeError: - pass - return g - - - -def nameToLabel(mname): - """ - Convert a string like a variable name into a slightly more human-friendly - string with spaces and capitalized letters. - - @type mname: C{str} - @param mname: The name to convert to a label. This must be a string - which could be used as a Python identifier. Strings which do not take - this form will result in unpredictable behavior. - - @rtype: C{str} - """ - labelList = [] - word = '' - lastWasUpper = False - for letter in mname: - if letter.isupper() == lastWasUpper: - # Continuing a word. - word += letter - else: - # breaking a word OR beginning a word - if lastWasUpper: - # could be either - if len(word) == 1: - # keep going - word += letter - else: - # acronym - # we're processing the lowercase letter after the acronym-then-capital - lastWord = word[:-1] - firstLetter = word[-1] - labelList.append(lastWord) - word = firstLetter + letter - else: - # definitely breaking: lower to upper - labelList.append(word) - word = letter - lastWasUpper = letter.isupper() - if labelList: - labelList[0] = labelList[0].capitalize() - else: - return mname.capitalize() - labelList.append(word) - return ' '.join(labelList) - - - -def uidFromString(uidString): - """ - Convert a user identifier, as a string, into an integer UID. - - @type uid: C{str} - @param uid: A string giving the base-ten representation of a UID or the - name of a user which can be converted to a UID via L{pwd.getpwnam}. - - @rtype: C{int} - @return: The integer UID corresponding to the given string. - - @raise ValueError: If the user name is supplied and L{pwd} is not - available. - """ - try: - return int(uidString) - except ValueError: - if pwd is None: - raise - return pwd.getpwnam(uidString)[2] - - - -def gidFromString(gidString): - """ - Convert a group identifier, as a string, into an integer GID. - - @type uid: C{str} - @param uid: A string giving the base-ten representation of a GID or the - name of a group which can be converted to a GID via L{grp.getgrnam}. - - @rtype: C{int} - @return: The integer GID corresponding to the given string. - - @raise ValueError: If the group name is supplied and L{grp} is not - available. - """ - try: - return int(gidString) - except ValueError: - if grp is None: - raise - return grp.getgrnam(gidString)[2] - - - -def runAsEffectiveUser(euid, egid, function, *args, **kwargs): - """ - Run the given function wrapped with seteuid/setegid calls. - - This will try to minimize the number of seteuid/setegid calls, comparing - current and wanted permissions - - @param euid: effective UID used to call the function. - @type euid: C{int} - - @type egid: effective GID used to call the function. - @param egid: C{int} - - @param function: the function run with the specific permission. - @type function: any callable - - @param *args: arguments passed to C{function} - @param **kwargs: keyword arguments passed to C{function} - """ - uid, gid = os.geteuid(), os.getegid() - if uid == euid and gid == egid: - return function(*args, **kwargs) - else: - if uid != 0 and (uid != euid or gid != egid): - os.seteuid(0) - if gid != egid: - os.setegid(egid) - if euid != 0 and (euid != uid or gid != egid): - os.seteuid(euid) - try: - return function(*args, **kwargs) - finally: - if euid != 0 and (uid != euid or gid != egid): - os.seteuid(0) - if gid != egid: - os.setegid(gid) - if uid != 0 and (uid != euid or gid != egid): - os.seteuid(uid) - - - -def runWithWarningsSuppressed(suppressedWarnings, f, *args, **kwargs): - """ - Run C{f(*args, **kwargs)}, but with some warnings suppressed. - - Unlike L{twisted.internet.utils.runWithWarningsSuppressed}, it has no - special support for L{twisted.internet.defer.Deferred}. - - @param suppressedWarnings: A list of arguments to pass to filterwarnings. - Must be a sequence of 2-tuples (args, kwargs). - - @param f: A callable. - - @param args: Arguments for C{f}. - - @param kwargs: Keyword arguments for C{f} - - @return: The result of C{f(*args, **kwargs)}. - """ - with warnings.catch_warnings(): - for a, kw in suppressedWarnings: - warnings.filterwarnings(*a, **kw) - return f(*args, **kwargs) - - - -__all__ = [ - "uniquify", "padTo", "getPluginDirs", "addPluginDir", "sibpath", - "getPassword", "println", "makeStatBar", "OrderedDict", - "InsensitiveDict", "spewer", "searchupwards", "LineLog", - "raises", "IntervalDifferential", "FancyStrMixin", "FancyEqMixin", - "switchUID", "SubclassableCStringIO", "mergeFunctionMetadata", - "nameToLabel", "uidFromString", "gidFromString", "runAsEffectiveUser", - "untilConcludes", - "runWithWarningsSuppressed", - ] - - -if _PY3: - __all3__ = ["FancyEqMixin", "untilConcludes", - "runWithWarningsSuppressed", "FancyStrMixin", "nameToLabel", - "InsensitiveDict", "padTo", "switchUID", "sibpath"] - for name in __all__[:]: - if name not in __all3__: - __all__.remove(name) - del globals()[name] - del name, __all3__ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/versions.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/versions.py deleted file mode 100644 index 9d56965..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/versions.py +++ /dev/null @@ -1,258 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_versions -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Versions for Python packages. - -See L{Version}. -""" - -from __future__ import division, absolute_import - -import sys, os - -from twisted.python.compat import cmp, comparable, nativeString - -@comparable -class _inf(object): - """ - An object that is bigger than all other objects. - """ - def __cmp__(self, other): - """ - @param other: Another object. - @type other: any - - @return: 0 if other is inf, 1 otherwise. - @rtype: C{int} - """ - if other is _inf: - return 0 - return 1 - -_inf = _inf() - - - -class IncomparableVersions(TypeError): - """ - Two versions could not be compared. - """ - - - -@comparable -class Version(object): - """ - An object that represents a three-part version number. - - If running from an svn checkout, include the revision number in - the version string. - """ - def __init__(self, package, major, minor, micro, prerelease=None): - """ - @param package: Name of the package that this is a version of. - @type package: C{str} - @param major: The major version number. - @type major: C{int} - @param minor: The minor version number. - @type minor: C{int} - @param micro: The micro version number. - @type micro: C{int} - @param prerelease: The prerelease number. - @type prerelease: C{int} - """ - self.package = package - self.major = major - self.minor = minor - self.micro = micro - self.prerelease = prerelease - - - def short(self): - """ - Return a string in canonical short version format, - ..[+rSVNVer]. - """ - s = self.base() - svnver = self._getSVNVersion() - if svnver: - s += '+r' + nativeString(svnver) - return s - - - def base(self): - """ - Like L{short}, but without the +rSVNVer. - """ - if self.prerelease is None: - pre = "" - else: - pre = "pre%s" % (self.prerelease,) - return '%d.%d.%d%s' % (self.major, - self.minor, - self.micro, - pre) - - - def __repr__(self): - svnver = self._formatSVNVersion() - if svnver: - svnver = ' #' + svnver - if self.prerelease is None: - prerelease = "" - else: - prerelease = ", prerelease=%r" % (self.prerelease,) - return '%s(%r, %d, %d, %d%s)%s' % ( - self.__class__.__name__, - self.package, - self.major, - self.minor, - self.micro, - prerelease, - svnver) - - - def __str__(self): - return '[%s, version %s]' % ( - self.package, - self.short()) - - - def __cmp__(self, other): - """ - Compare two versions, considering major versions, minor versions, micro - versions, then prereleases. - - A version with a prerelease is always less than a version without a - prerelease. If both versions have prereleases, they will be included in - the comparison. - - @param other: Another version. - @type other: L{Version} - - @return: NotImplemented when the other object is not a Version, or one - of -1, 0, or 1. - - @raise IncomparableVersions: when the package names of the versions - differ. - """ - if not isinstance(other, self.__class__): - return NotImplemented - if self.package != other.package: - raise IncomparableVersions("%r != %r" - % (self.package, other.package)) - - if self.prerelease is None: - prerelease = _inf - else: - prerelease = self.prerelease - - if other.prerelease is None: - otherpre = _inf - else: - otherpre = other.prerelease - - x = cmp((self.major, - self.minor, - self.micro, - prerelease), - (other.major, - other.minor, - other.micro, - otherpre)) - return x - - - def _parseSVNEntries_4(self, entriesFile): - """ - Given a readable file object which represents a .svn/entries file in - format version 4, return the revision as a string. We do this by - reading first XML element in the document that has a 'revision' - attribute. - """ - from xml.dom.minidom import parse - doc = parse(entriesFile).documentElement - for node in doc.childNodes: - if hasattr(node, 'getAttribute'): - rev = node.getAttribute('revision') - if rev is not None: - return rev.encode('ascii') - - - def _parseSVNEntries_8(self, entriesFile): - """ - Given a readable file object which represents a .svn/entries file in - format version 8, return the revision as a string. - """ - entriesFile.readline() - entriesFile.readline() - entriesFile.readline() - return entriesFile.readline().strip() - - - # Add handlers for version 9 and 10 formats, which are the same as - # version 8 as far as revision information is concerned. - _parseSVNEntries_9 = _parseSVNEntries_8 - _parseSVNEntriesTenPlus = _parseSVNEntries_8 - - - def _getSVNVersion(self): - """ - Figure out the SVN revision number based on the existence of - /.svn/entries, and its contents. This requires discovering the - format version from the 'format' file and parsing the entries file - accordingly. - - @return: None or string containing SVN Revision number. - """ - mod = sys.modules.get(self.package) - if mod: - svn = os.path.join(os.path.dirname(mod.__file__), '.svn') - if not os.path.exists(svn): - # It's not an svn working copy - return None - - formatFile = os.path.join(svn, 'format') - if os.path.exists(formatFile): - # It looks like a less-than-version-10 working copy. - with open(formatFile, 'rb') as fObj: - format = fObj.read().strip() - parser = getattr(self, '_parseSVNEntries_' + format.decode('ascii'), None) - else: - # It looks like a version-10-or-greater working copy, which - # has version information in the entries file. - parser = self._parseSVNEntriesTenPlus - - if parser is None: - return b'Unknown' - - entriesFile = os.path.join(svn, 'entries') - entries = open(entriesFile, 'rb') - try: - try: - return parser(entries) - finally: - entries.close() - except: - return b'Unknown' - - - def _formatSVNVersion(self): - ver = self._getSVNVersion() - if ver is None: - return '' - return ' (SVN r%s)' % (ver,) - - - -def getVersionString(version): - """ - Get a friendly string for the given version object. - - @param version: A L{Version} object. - @return: A string containing the package and short version number. - """ - result = '%s %s' % (version.package, version.short()) - return result diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/win32.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/win32.py deleted file mode 100644 index 6e983cd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/win32.py +++ /dev/null @@ -1,169 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_win32 -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Win32 utilities. - -See also twisted.python.shortcut. - -@var O_BINARY: the 'binary' mode flag on Windows, or 0 on other platforms, so it - may safely be OR'ed into a mask for os.open. -""" - -from __future__ import division, absolute_import - -import re -import os - -try: - import win32api - import win32con -except ImportError: - pass - -from twisted.python.runtime import platform - -# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp -ERROR_FILE_NOT_FOUND = 2 -ERROR_PATH_NOT_FOUND = 3 -ERROR_INVALID_NAME = 123 -ERROR_DIRECTORY = 267 - -O_BINARY = getattr(os, "O_BINARY", 0) - -class FakeWindowsError(OSError): - """ - Stand-in for sometimes-builtin exception on platforms for which it - is missing. - """ - -try: - WindowsError = WindowsError -except NameError: - WindowsError = FakeWindowsError - -# XXX fix this to use python's builtin _winreg? - -def getProgramsMenuPath(): - """ - Get the path to the Programs menu. - - Probably will break on non-US Windows. - - @return: the filesystem location of the common Start Menu->Programs. - @rtype: L{str} - """ - if not platform.isWindows(): - return "C:\\Windows\\Start Menu\\Programs" - keyname = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders' - hShellFolders = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, - keyname, 0, win32con.KEY_READ) - return win32api.RegQueryValueEx(hShellFolders, 'Common Programs')[0] - - -def getProgramFilesPath(): - """Get the path to the Program Files folder.""" - keyname = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion' - currentV = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, - keyname, 0, win32con.KEY_READ) - return win32api.RegQueryValueEx(currentV, 'ProgramFilesDir')[0] - - -_cmdLineQuoteRe = re.compile(r'(\\*)"') -_cmdLineQuoteRe2 = re.compile(r'(\\+)\Z') -def cmdLineQuote(s): - """ - Internal method for quoting a single command-line argument. - - @param s: an unquoted string that you want to quote so that something that - does cmd.exe-style unquoting will interpret it as a single argument, - even if it contains spaces. - @type s: C{str} - - @return: a quoted string. - @rtype: C{str} - """ - quote = ((" " in s) or ("\t" in s) or ('"' in s) or s == '') and '"' or '' - return quote + _cmdLineQuoteRe2.sub(r"\1\1", _cmdLineQuoteRe.sub(r'\1\1\\"', s)) + quote - -def quoteArguments(arguments): - """ - Quote an iterable of command-line arguments for passing to CreateProcess or - a similar API. This allows the list passed to C{reactor.spawnProcess} to - match the child process's C{sys.argv} properly. - - @param arglist: an iterable of C{str}, each unquoted. - - @return: a single string, with the given sequence quoted as necessary. - """ - return ' '.join([cmdLineQuote(a) for a in arguments]) - - -class _ErrorFormatter(object): - """ - Formatter for Windows error messages. - - @ivar winError: A callable which takes one integer error number argument - and returns an L{exceptions.WindowsError} instance for that error (like - L{ctypes.WinError}). - - @ivar formatMessage: A callable which takes one integer error number - argument and returns a C{str} giving the message for that error (like - L{win32api.FormatMessage}). - - @ivar errorTab: A mapping from integer error numbers to C{str} messages - which correspond to those erorrs (like L{socket.errorTab}). - """ - def __init__(self, WinError, FormatMessage, errorTab): - self.winError = WinError - self.formatMessage = FormatMessage - self.errorTab = errorTab - - def fromEnvironment(cls): - """ - Get as many of the platform-specific error translation objects as - possible and return an instance of C{cls} created with them. - """ - try: - from ctypes import WinError - except ImportError: - WinError = None - try: - from win32api import FormatMessage - except ImportError: - FormatMessage = None - try: - from socket import errorTab - except ImportError: - errorTab = None - return cls(WinError, FormatMessage, errorTab) - fromEnvironment = classmethod(fromEnvironment) - - - def formatError(self, errorcode): - """ - Returns the string associated with a Windows error message, such as the - ones found in socket.error. - - Attempts direct lookup against the win32 API via ctypes and then - pywin32 if available), then in the error table in the socket module, - then finally defaulting to C{os.strerror}. - - @param errorcode: the Windows error code - @type errorcode: C{int} - - @return: The error message string - @rtype: C{str} - """ - if self.winError is not None: - return self.winError(errorcode).strerror - if self.formatMessage is not None: - return self.formatMessage(errorcode) - if self.errorTab is not None: - result = self.errorTab.get(errorcode) - if result is not None: - return result - return os.strerror(errorcode) - -formatError = _ErrorFormatter.fromEnvironment().formatError diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zippath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zippath.py deleted file mode 100644 index 698c9a8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zippath.py +++ /dev/null @@ -1,267 +0,0 @@ -# -*- test-case-name: twisted.test.test_paths.ZipFilePathTests -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module contains implementations of IFilePath for zip files. - -See the constructor for ZipArchive for use. -""" - -__metaclass__ = type - -import os -import time -import errno - - -# Python 2.6 includes support for incremental unzipping of zipfiles, and -# thus obviates the need for ChunkingZipFile. -import sys -if sys.version_info[:2] >= (2, 6): - _USE_ZIPFILE = True - from zipfile import ZipFile -else: - _USE_ZIPFILE = False - from twisted.python.zipstream import ChunkingZipFile - -from twisted.python.filepath import IFilePath, FilePath, AbstractFilePath - -from zope.interface import implementer - -# using FilePath here exclusively rather than os to make sure that we don't do -# anything OS-path-specific here. - -ZIP_PATH_SEP = '/' # In zipfiles, "/" is universally used as the - # path separator, regardless of platform. - - -@implementer(IFilePath) -class ZipPath(AbstractFilePath): - """ - I represent a file or directory contained within a zip file. - """ - - sep = ZIP_PATH_SEP - - def __init__(self, archive, pathInArchive): - """ - Don't construct me directly. Use ZipArchive.child(). - - @param archive: a ZipArchive instance. - - @param pathInArchive: a ZIP_PATH_SEP-separated string. - """ - self.archive = archive - self.pathInArchive = pathInArchive - # self.path pretends to be os-specific because that's the way the - # 'zipimport' module does it. - self.path = os.path.join(archive.zipfile.filename, - *(self.pathInArchive.split(ZIP_PATH_SEP))) - - def __cmp__(self, other): - if not isinstance(other, ZipPath): - return NotImplemented - return cmp((self.archive, self.pathInArchive), - (other.archive, other.pathInArchive)) - - - def __repr__(self): - parts = [os.path.abspath(self.archive.path)] - parts.extend(self.pathInArchive.split(ZIP_PATH_SEP)) - path = os.sep.join(parts) - return "ZipPath('%s')" % (path.encode('string-escape'),) - - - def parent(self): - splitup = self.pathInArchive.split(ZIP_PATH_SEP) - if len(splitup) == 1: - return self.archive - return ZipPath(self.archive, ZIP_PATH_SEP.join(splitup[:-1])) - - - def child(self, path): - """ - Return a new ZipPath representing a path in C{self.archive} which is - a child of this path. - - @note: Requesting the C{".."} (or other special name) child will not - cause L{InsecurePath} to be raised since these names do not have - any special meaning inside a zip archive. Be particularly - careful with the C{path} attribute (if you absolutely must use - it) as this means it may include special names with special - meaning outside of the context of a zip archive. - """ - return ZipPath(self.archive, ZIP_PATH_SEP.join([self.pathInArchive, path])) - - - def sibling(self, path): - return self.parent().child(path) - - # preauthChild = child - - def exists(self): - return self.isdir() or self.isfile() - - def isdir(self): - return self.pathInArchive in self.archive.childmap - - def isfile(self): - return self.pathInArchive in self.archive.zipfile.NameToInfo - - def islink(self): - return False - - def listdir(self): - if self.exists(): - if self.isdir(): - return self.archive.childmap[self.pathInArchive].keys() - else: - raise OSError(errno.ENOTDIR, "Leaf zip entry listed") - else: - raise OSError(errno.ENOENT, "Non-existent zip entry listed") - - - def splitext(self): - """ - Return a value similar to that returned by os.path.splitext. - """ - # This happens to work out because of the fact that we use OS-specific - # path separators in the constructor to construct our fake 'path' - # attribute. - return os.path.splitext(self.path) - - - def basename(self): - return self.pathInArchive.split(ZIP_PATH_SEP)[-1] - - def dirname(self): - # XXX NOTE: This API isn't a very good idea on filepath, but it's even - # less meaningful here. - return self.parent().path - - def open(self, mode="r"): - if _USE_ZIPFILE: - return self.archive.zipfile.open(self.pathInArchive, mode=mode) - else: - # XXX oh man, is this too much hax? - self.archive.zipfile.mode = mode - return self.archive.zipfile.readfile(self.pathInArchive) - - def changed(self): - pass - - def getsize(self): - """ - Retrieve this file's size. - - @return: file size, in bytes - """ - - return self.archive.zipfile.NameToInfo[self.pathInArchive].file_size - - def getAccessTime(self): - """ - Retrieve this file's last access-time. This is the same as the last access - time for the archive. - - @return: a number of seconds since the epoch - """ - return self.archive.getAccessTime() - - - def getModificationTime(self): - """ - Retrieve this file's last modification time. This is the time of - modification recorded in the zipfile. - - @return: a number of seconds since the epoch. - """ - return time.mktime( - self.archive.zipfile.NameToInfo[self.pathInArchive].date_time - + (0, 0, 0)) - - - def getStatusChangeTime(self): - """ - Retrieve this file's last modification time. This name is provided for - compatibility, and returns the same value as getmtime. - - @return: a number of seconds since the epoch. - """ - return self.getModificationTime() - - - -class ZipArchive(ZipPath): - """ I am a FilePath-like object which can wrap a zip archive as if it were a - directory. - """ - archive = property(lambda self: self) - def __init__(self, archivePathname): - """Create a ZipArchive, treating the archive at archivePathname as a zip file. - - @param archivePathname: a str, naming a path in the filesystem. - """ - if _USE_ZIPFILE: - self.zipfile = ZipFile(archivePathname) - else: - self.zipfile = ChunkingZipFile(archivePathname) - self.path = archivePathname - self.pathInArchive = '' - # zipfile is already wasting O(N) memory on cached ZipInfo instances, - # so there's no sense in trying to do this lazily or intelligently - self.childmap = {} # map parent: list of children - - for name in self.zipfile.namelist(): - name = name.split(ZIP_PATH_SEP) - for x in range(len(name)): - child = name[-x] - parent = ZIP_PATH_SEP.join(name[:-x]) - if parent not in self.childmap: - self.childmap[parent] = {} - self.childmap[parent][child] = 1 - parent = '' - - def child(self, path): - """ - Create a ZipPath pointing at a path within the archive. - - @param path: a str with no path separators in it, either '/' or the - system path separator, if it's different. - """ - return ZipPath(self, path) - - def exists(self): - """ - Returns true if the underlying archive exists. - """ - return FilePath(self.zipfile.filename).exists() - - - def getAccessTime(self): - """ - Return the archive file's last access time. - """ - return FilePath(self.zipfile.filename).getAccessTime() - - - def getModificationTime(self): - """ - Return the archive file's modification time. - """ - return FilePath(self.zipfile.filename).getModificationTime() - - - def getStatusChangeTime(self): - """ - Return the archive file's status change time. - """ - return FilePath(self.zipfile.filename).getStatusChangeTime() - - - def __repr__(self): - return 'ZipArchive(%r)' % (os.path.abspath(self.path),) - - -__all__ = ['ZipArchive', 'ZipPath'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zipstream.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zipstream.py deleted file mode 100644 index 7ce8c12..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zipstream.py +++ /dev/null @@ -1,319 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_zipstream -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An incremental approach to unzipping files. This allows you to unzip a little -bit of a file at a time, which means you can report progress as a file unzips. -""" - -import zipfile -import os.path -import zlib -import struct - - -_fileHeaderSize = struct.calcsize(zipfile.structFileHeader) - -class ChunkingZipFile(zipfile.ZipFile): - """ - A C{ZipFile} object which, with L{readfile}, also gives you access to a - file-like object for each entry. - """ - - def readfile(self, name): - """ - Return file-like object for name. - """ - if self.mode not in ("r", "a"): - raise RuntimeError('read() requires mode "r" or "a"') - if not self.fp: - raise RuntimeError( - "Attempt to read ZIP archive that was already closed") - zinfo = self.getinfo(name) - - self.fp.seek(zinfo.header_offset, 0) - - fheader = self.fp.read(_fileHeaderSize) - if fheader[0:4] != zipfile.stringFileHeader: - raise zipfile.BadZipfile("Bad magic number for file header") - - fheader = struct.unpack(zipfile.structFileHeader, fheader) - fname = self.fp.read(fheader[zipfile._FH_FILENAME_LENGTH]) - - if fheader[zipfile._FH_EXTRA_FIELD_LENGTH]: - self.fp.read(fheader[zipfile._FH_EXTRA_FIELD_LENGTH]) - - if fname != zinfo.orig_filename: - raise zipfile.BadZipfile( - 'File name in directory "%s" and header "%s" differ.' % ( - zinfo.orig_filename, fname)) - - if zinfo.compress_type == zipfile.ZIP_STORED: - return ZipFileEntry(self, zinfo.compress_size) - elif zinfo.compress_type == zipfile.ZIP_DEFLATED: - return DeflatedZipFileEntry(self, zinfo.compress_size) - else: - raise zipfile.BadZipfile( - "Unsupported compression method %d for file %s" % - (zinfo.compress_type, name)) - - - -class _FileEntry(object): - """ - Abstract superclass of both compressed and uncompressed variants of - file-like objects within a zip archive. - - @ivar chunkingZipFile: a chunking zip file. - @type chunkingZipFile: L{ChunkingZipFile} - - @ivar length: The number of bytes within the zip file that represent this - file. (This is the size on disk, not the number of decompressed bytes - which will result from reading it.) - - @ivar fp: the underlying file object (that contains pkzip data). Do not - touch this, please. It will quite likely move or go away. - - @ivar closed: File-like 'closed' attribute; True before this file has been - closed, False after. - @type closed: C{bool} - - @ivar finished: An older, broken synonym for 'closed'. Do not touch this, - please. - @type finished: C{int} - """ - def __init__(self, chunkingZipFile, length): - """ - Create a L{_FileEntry} from a L{ChunkingZipFile}. - """ - self.chunkingZipFile = chunkingZipFile - self.fp = self.chunkingZipFile.fp - self.length = length - self.finished = 0 - self.closed = False - - - def isatty(self): - """ - Returns false because zip files should not be ttys - """ - return False - - - def close(self): - """ - Close self (file-like object) - """ - self.closed = True - self.finished = 1 - del self.fp - - - def readline(self): - """ - Read a line. - """ - bytes = "" - for byte in iter(lambda : self.read(1), ""): - bytes += byte - if byte == "\n": - break - return bytes - - - def next(self): - """ - Implement next as file does (like readline, except raises StopIteration - at EOF) - """ - nextline = self.readline() - if nextline: - return nextline - raise StopIteration() - - - def readlines(self): - """ - Returns a list of all the lines - """ - return list(self) - - - def xreadlines(self): - """ - Returns an iterator (so self) - """ - return self - - - def __iter__(self): - """ - Returns an iterator (so self) - """ - return self - - - -class ZipFileEntry(_FileEntry): - """ - File-like object used to read an uncompressed entry in a ZipFile - """ - - def __init__(self, chunkingZipFile, length): - _FileEntry.__init__(self, chunkingZipFile, length) - self.readBytes = 0 - - - def tell(self): - return self.readBytes - - - def read(self, n=None): - if n is None: - n = self.length - self.readBytes - if n == 0 or self.finished: - return '' - data = self.chunkingZipFile.fp.read( - min(n, self.length - self.readBytes)) - self.readBytes += len(data) - if self.readBytes == self.length or len(data) < n: - self.finished = 1 - return data - - - -class DeflatedZipFileEntry(_FileEntry): - """ - File-like object used to read a deflated entry in a ZipFile - """ - - def __init__(self, chunkingZipFile, length): - _FileEntry.__init__(self, chunkingZipFile, length) - self.returnedBytes = 0 - self.readBytes = 0 - self.decomp = zlib.decompressobj(-15) - self.buffer = "" - - - def tell(self): - return self.returnedBytes - - - def read(self, n=None): - if self.finished: - return "" - if n is None: - result = [self.buffer,] - result.append( - self.decomp.decompress( - self.chunkingZipFile.fp.read( - self.length - self.readBytes))) - result.append(self.decomp.decompress("Z")) - result.append(self.decomp.flush()) - self.buffer = "" - self.finished = 1 - result = "".join(result) - self.returnedBytes += len(result) - return result - else: - while len(self.buffer) < n: - data = self.chunkingZipFile.fp.read( - min(n, 1024, self.length - self.readBytes)) - self.readBytes += len(data) - if not data: - result = (self.buffer - + self.decomp.decompress("Z") - + self.decomp.flush()) - self.finished = 1 - self.buffer = "" - self.returnedBytes += len(result) - return result - else: - self.buffer += self.decomp.decompress(data) - result = self.buffer[:n] - self.buffer = self.buffer[n:] - self.returnedBytes += len(result) - return result - - - -DIR_BIT = 16 - - -def countZipFileChunks(filename, chunksize): - """ - Predict the number of chunks that will be extracted from the entire - zipfile, given chunksize blocks. - """ - totalchunks = 0 - zf = ChunkingZipFile(filename) - for info in zf.infolist(): - totalchunks += countFileChunks(info, chunksize) - return totalchunks - - -def countFileChunks(zipinfo, chunksize): - """ - Count the number of chunks that will result from the given C{ZipInfo}. - - @param zipinfo: a C{zipfile.ZipInfo} instance describing an entry in a zip - archive to be counted. - - @return: the number of chunks present in the zip file. (Even an empty file - counts as one chunk.) - @rtype: C{int} - """ - count, extra = divmod(zipinfo.file_size, chunksize) - if extra > 0: - count += 1 - return count or 1 - - - -def unzipIterChunky(filename, directory='.', overwrite=0, - chunksize=4096): - """ - Return a generator for the zipfile. This implementation will yield after - every chunksize uncompressed bytes, or at the end of a file, whichever - comes first. - - The value it yields is the number of chunks left to unzip. - """ - czf = ChunkingZipFile(filename, 'r') - if not os.path.exists(directory): - os.makedirs(directory) - remaining = countZipFileChunks(filename, chunksize) - names = czf.namelist() - infos = czf.infolist() - - for entry, info in zip(names, infos): - isdir = info.external_attr & DIR_BIT - f = os.path.join(directory, entry) - if isdir: - # overwrite flag only applies to files - if not os.path.exists(f): - os.makedirs(f) - remaining -= 1 - yield remaining - else: - # create the directory the file will be in first, - # since we can't guarantee it exists - fdir = os.path.split(f)[0] - if not os.path.exists(fdir): - os.makedirs(fdir) - if overwrite or not os.path.exists(f): - outfile = file(f, 'wb') - fp = czf.readfile(entry) - if info.file_size == 0: - remaining -= 1 - yield remaining - while fp.tell() < info.file_size: - hunk = fp.read(chunksize) - outfile.write(hunk) - remaining -= 1 - yield remaining - outfile.close() - else: - remaining -= countFileChunks(info, chunksize) - yield remaining diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/README.txt b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/README.txt deleted file mode 100644 index 2a7b1c2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -THIS DIRECTORY AND ALL FILES INCLUDED ARE DEPRECATED. - -These are the old zsh completion functions for Twisted commands... they used -to contain full completion functions, but now they've simply been replaced -by the current "stub" code that delegates completion control to Twisted. - -This directory and included files need to remain for several years in order -to provide backwards-compatibility with an old version of the Twisted -stub function that was shipped with Zsh. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_cftp b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_cftp deleted file mode 100644 index e89fcdb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_cftp +++ /dev/null @@ -1,34 +0,0 @@ -#compdef cftp -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_ckeygen b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_ckeygen deleted file mode 100644 index 38050a0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_ckeygen +++ /dev/null @@ -1,34 +0,0 @@ -#compdef ckeygen -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_conch b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_conch deleted file mode 100644 index e3ac3b6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_conch +++ /dev/null @@ -1,34 +0,0 @@ -#compdef conch -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_lore b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_lore deleted file mode 100644 index 8b1c328..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_lore +++ /dev/null @@ -1,34 +0,0 @@ -#compdef lore -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_manhole b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_manhole deleted file mode 100644 index 54ec99f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_manhole +++ /dev/null @@ -1,34 +0,0 @@ -#compdef manhole -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_mktap b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_mktap deleted file mode 100644 index 2a08ea4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_mktap +++ /dev/null @@ -1,34 +0,0 @@ -#compdef mktap -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_pyhtmlizer b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_pyhtmlizer deleted file mode 100644 index 2fd2d6d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_pyhtmlizer +++ /dev/null @@ -1,34 +0,0 @@ -#compdef pyhtmlizer -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tap2deb b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tap2deb deleted file mode 100644 index b4e0836..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tap2deb +++ /dev/null @@ -1,34 +0,0 @@ -#compdef tap2deb -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tap2rpm b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tap2rpm deleted file mode 100644 index 10a083f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tap2rpm +++ /dev/null @@ -1,34 +0,0 @@ -#compdef tap2rpm -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tapconvert b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tapconvert deleted file mode 100644 index 41a0e4d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tapconvert +++ /dev/null @@ -1,34 +0,0 @@ -#compdef tapconvert -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tkconch b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tkconch deleted file mode 100644 index 3af1f12..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tkconch +++ /dev/null @@ -1,34 +0,0 @@ -#compdef tkconch -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tkmktap b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tkmktap deleted file mode 100644 index 0e3bdaa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_tkmktap +++ /dev/null @@ -1,34 +0,0 @@ -#compdef tkmktap -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_trial b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_trial deleted file mode 100644 index b692f44..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_trial +++ /dev/null @@ -1,34 +0,0 @@ -#compdef trial -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_twistd b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_twistd deleted file mode 100644 index 171224f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_twistd +++ /dev/null @@ -1,34 +0,0 @@ -#compdef twistd -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_websetroot b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_websetroot deleted file mode 100644 index 58ae550..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/python/zsh/_websetroot +++ /dev/null @@ -1,34 +0,0 @@ -#compdef websetroot -# This file is deprecated. See README. - -# This is the ZSH completion file for Twisted commands. It calls the current -# command-line with the special "--_shell-completion" option which is handled -# by twisted.python.usage. t.p.usage then generates zsh code on stdout to -# handle the completions for this particular command-line. -# -# 3rd parties that wish to provide zsh completion for commands that -# use t.p.usage may copy this file and change the first line to reference -# the name(s) of their command(s). -# -# This file is included in the official Zsh distribution as -# Completion/Unix/Command/_twisted - -# redirect stderr to /dev/null otherwise deprecation warnings may get puked -# all over the user's terminal if completing options for mktap or other -# deprecated commands. Redirect stderr to a file to debug errors. -local cmd output -cmd=("$words[@]" --_shell-completion zsh:$CURRENT) -output=$("$cmd[@]" 2>/dev/null) - -if [[ $output == "#compdef "* ]]; then - # Looks like we got a valid completion function - so eval it to produce - # the completion matches. - eval $output -else - echo "\nCompletion error running command:" ${(qqq)cmd} - echo -n "If output below is unhelpful you may need to edit this file and " - echo "redirect stderr to a file." - echo "Expected completion function, but instead got:" - echo $output - return 1 -fi diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/__init__.py deleted file mode 100644 index 70a7bb8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Runner: Run and monitor processes. -""" - -from twisted.runner._version import version -__version__ = version.short() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/_version.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/_version.py deleted file mode 100644 index 8107053..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/_version.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This is an auto-generated file. Do not edit it. - -""" -Provides Twisted version information. -""" - -from twisted.python import versions -version = versions.Version('twisted.runner', 15, 2, 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetd.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetd.py deleted file mode 100644 index 010b89e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetd.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Twisted inetd. - -Maintainer: Andrew Bennetts - -Future Plans: Bugfixes. Specifically for UDP and Sun-RPC, which don't work -correctly yet. -""" - -import os - -from twisted.internet import process, reactor, fdesc -from twisted.internet.protocol import Protocol, ServerFactory -from twisted.protocols import wire - -# A dict of known 'internal' services (i.e. those that don't involve spawning -# another process. -internalProtocols = { - 'echo': wire.Echo, - 'chargen': wire.Chargen, - 'discard': wire.Discard, - 'daytime': wire.Daytime, - 'time': wire.Time, -} - - -class InetdProtocol(Protocol): - """Forks a child process on connectionMade, passing the socket as fd 0.""" - def connectionMade(self): - sockFD = self.transport.fileno() - childFDs = {0: sockFD, 1: sockFD} - if self.factory.stderrFile: - childFDs[2] = self.factory.stderrFile.fileno() - - # processes run by inetd expect blocking sockets - # FIXME: maybe this should be done in process.py? are other uses of - # Process possibly affected by this? - fdesc.setBlocking(sockFD) - if childFDs.has_key(2): - fdesc.setBlocking(childFDs[2]) - - service = self.factory.service - uid = service.user - gid = service.group - - # don't tell Process to change our UID/GID if it's what we - # already are - if uid == os.getuid(): - uid = None - if gid == os.getgid(): - gid = None - - process.Process(None, service.program, service.programArgs, os.environ, - None, None, uid, gid, childFDs) - - reactor.removeReader(self.transport) - reactor.removeWriter(self.transport) - - -class InetdFactory(ServerFactory): - protocol = InetdProtocol - stderrFile = None - - def __init__(self, service): - self.service = service diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetdconf.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetdconf.py deleted file mode 100644 index f06a2ab..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetdconf.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Parser for inetd.conf files - -Maintainer: Andrew Bennetts - -Future Plans: xinetd configuration file support? -""" - -# Various exceptions -class InvalidConfError(Exception): - """Invalid configuration file""" - - -class InvalidInetdConfError(InvalidConfError): - """Invalid inetd.conf file""" - - -class InvalidServicesConfError(InvalidConfError): - """Invalid services file""" - - -class InvalidRPCServicesConfError(InvalidConfError): - """Invalid rpc services file""" - - -class UnknownService(Exception): - """Unknown service name""" - - -class SimpleConfFile: - """Simple configuration file parser superclass. - - Filters out comments and empty lines (which includes lines that only - contain comments). - - To use this class, override parseLine or parseFields. - """ - - commentChar = '#' - defaultFilename = None - - def parseFile(self, file=None): - """Parse a configuration file - - If file is None and self.defaultFilename is set, it will open - defaultFilename and use it. - """ - if file is None and self.defaultFilename: - file = open(self.defaultFilename,'r') - - for line in file.readlines(): - # Strip out comments - comment = line.find(self.commentChar) - if comment != -1: - line = line[:comment] - - # Strip whitespace - line = line.strip() - - # Skip empty lines (and lines which only contain comments) - if not line: - continue - - self.parseLine(line) - - def parseLine(self, line): - """Override this. - - By default, this will split the line on whitespace and call - self.parseFields (catching any errors). - """ - try: - self.parseFields(*line.split()) - except ValueError: - raise InvalidInetdConfError, 'Invalid line: ' + repr(line) - - def parseFields(self, *fields): - """Override this.""" - - -class InetdService: - """A simple description of an inetd service.""" - name = None - port = None - socketType = None - protocol = None - wait = None - user = None - group = None - program = None - programArgs = None - - def __init__(self, name, port, socketType, protocol, wait, user, group, - program, programArgs): - self.name = name - self.port = port - self.socketType = socketType - self.protocol = protocol - self.wait = wait - self.user = user - self.group = group - self.program = program - self.programArgs = programArgs - - -class InetdConf(SimpleConfFile): - """Configuration parser for a traditional UNIX inetd(8)""" - - defaultFilename = '/etc/inetd.conf' - - def __init__(self, knownServices=None): - self.services = [] - - if knownServices is None: - knownServices = ServicesConf() - knownServices.parseFile() - self.knownServices = knownServices - - def parseFields(self, serviceName, socketType, protocol, wait, user, - program, *programArgs): - """Parse an inetd.conf file. - - Implemented from the description in the Debian inetd.conf man page. - """ - # Extract user (and optional group) - user, group = (user.split('.') + [None])[:2] - - # Find the port for a service - port = self.knownServices.services.get((serviceName, protocol), None) - if not port and not protocol.startswith('rpc/'): - # FIXME: Should this be discarded/ignored, rather than throwing - # an exception? - try: - port = int(serviceName) - serviceName = 'unknown' - except: - raise UnknownService, "Unknown service: %s (%s)" \ - % (serviceName, protocol) - - self.services.append(InetdService(serviceName, port, socketType, - protocol, wait, user, group, program, - programArgs)) - - -class ServicesConf(SimpleConfFile): - """/etc/services parser - - @ivar services: dict mapping service names to (port, protocol) tuples. - """ - - defaultFilename = '/etc/services' - - def __init__(self): - self.services = {} - - def parseFields(self, name, portAndProtocol, *aliases): - try: - port, protocol = portAndProtocol.split('/') - port = long(port) - except: - raise InvalidServicesConfError, 'Invalid port/protocol:' + \ - repr(portAndProtocol) - - self.services[(name, protocol)] = port - for alias in aliases: - self.services[(alias, protocol)] = port - - -class RPCServicesConf(SimpleConfFile): - """/etc/rpc parser - - @ivar self.services: dict mapping rpc service names to rpc ports. - """ - - defaultFilename = '/etc/rpc' - - def __init__(self): - self.services = {} - - def parseFields(self, name, port, *aliases): - try: - port = long(port) - except: - raise InvalidRPCServicesConfError, 'Invalid port:' + repr(port) - - self.services[name] = port - for alias in aliases: - self.services[alias] = port - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetdtap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetdtap.py deleted file mode 100644 index 3e62877..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/inetdtap.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Twisted inetd TAP support - -Maintainer: Andrew Bennetts - -Future Plans: more configurability. -""" - -import os, pwd, grp, socket - -from twisted.runner import inetd, inetdconf -from twisted.python import log, usage -from twisted.internet.protocol import ServerFactory -from twisted.application import internet, service as appservice - -try: - import portmap - rpcOk = 1 -except ImportError: - rpcOk = 0 - - -# Protocol map -protocolDict = {'tcp': socket.IPPROTO_TCP, 'udp': socket.IPPROTO_UDP} - - -class Options(usage.Options): - - optParameters = [ - ['rpc', 'r', '/etc/rpc', 'RPC procedure table file'], - ['file', 'f', '/etc/inetd.conf', 'Service configuration file'] - ] - - optFlags = [['nointernal', 'i', "Don't run internal services"]] - - compData = usage.Completions( - optActions={"file": usage.CompleteFiles('*.conf')} - ) - -class RPCServer(internet.TCPServer): - - def __init__(self, rpcVersions, rpcConf, proto, service): - internet.TCPServer.__init__(0, ServerFactory()) - self.rpcConf = rpcConf - self.proto = proto - self.service = service - - def startService(self): - internet.TCPServer.startService(self) - import portmap - portNo = self._port.getHost()[2] - service = self.service - for version in rpcVersions: - portmap.set(self.rpcConf.services[name], version, self.proto, - portNo) - inetd.forkPassingFD(service.program, service.programArgs, - os.environ, service.user, service.group, p) - -def makeService(config): - s = appservice.MultiService() - conf = inetdconf.InetdConf() - conf.parseFile(open(config['file'])) - - rpcConf = inetdconf.RPCServicesConf() - try: - rpcConf.parseFile(open(config['rpc'])) - except: - # We'll survive even if we can't read /etc/rpc - log.deferr() - - for service in conf.services: - rpc = service.protocol.startswith('rpc/') - protocol = service.protocol - - if rpc and not rpcOk: - log.msg('Skipping rpc service due to lack of rpc support') - continue - - if rpc: - # RPC has extra options, so extract that - protocol = protocol[4:] # trim 'rpc/' - if not protocolDict.has_key(protocol): - log.msg('Bad protocol: ' + protocol) - continue - - try: - name, rpcVersions = service.name.split('/') - except ValueError: - log.msg('Bad RPC service/version: ' + service.name) - continue - - if not rpcConf.services.has_key(name): - log.msg('Unknown RPC service: ' + repr(service.name)) - continue - - try: - if '-' in rpcVersions: - start, end = map(int, rpcVersions.split('-')) - rpcVersions = range(start, end+1) - else: - rpcVersions = [int(rpcVersions)] - except ValueError: - log.msg('Bad RPC versions: ' + str(rpcVersions)) - continue - - if (protocol, service.socketType) not in [('tcp', 'stream'), - ('udp', 'dgram')]: - log.msg('Skipping unsupported type/protocol: %s/%s' - % (service.socketType, service.protocol)) - continue - - # Convert the username into a uid (if necessary) - try: - service.user = int(service.user) - except ValueError: - try: - service.user = pwd.getpwnam(service.user)[2] - except KeyError: - log.msg('Unknown user: ' + service.user) - continue - - # Convert the group name into a gid (if necessary) - if service.group is None: - # If no group was specified, use the user's primary group - service.group = pwd.getpwuid(service.user)[3] - else: - try: - service.group = int(service.group) - except ValueError: - try: - service.group = grp.getgrnam(service.group)[2] - except KeyError: - log.msg('Unknown group: ' + service.group) - continue - - if service.program == 'internal': - if config['nointernal']: - continue - - # Internal services can use a standard ServerFactory - if not inetd.internalProtocols.has_key(service.name): - log.msg('Unknown internal service: ' + service.name) - continue - factory = ServerFactory() - factory.protocol = inetd.internalProtocols[service.name] - elif rpc: - i = RPCServer(rpcVersions, rpcConf, proto, service) - i.setServiceParent(s) - continue - else: - # Non-internal non-rpc services use InetdFactory - factory = inetd.InetdFactory(service) - - if protocol == 'tcp': - internet.TCPServer(service.port, factory).setServiceParent(s) - elif protocol == 'udp': - raise RuntimeError("not supporting UDP") - return s diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/portmap.c b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/portmap.c deleted file mode 100644 index ca0c1c9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/portmap.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2001-2004 Twisted Matrix Laboratories. - * See LICENSE for details. - - * - */ - -/* portmap.c: A simple Python wrapper for pmap_set(3) and pmap_unset(3) */ - -#include -#include -#include - -static PyObject * portmap_set(PyObject *self, PyObject *args) -{ - unsigned long program, version; - int protocol; - unsigned short port; - - if (!PyArg_ParseTuple(args, "llih:set", - &program, &version, &protocol, &port)) - return NULL; - - pmap_unset(program, version); - pmap_set(program, version, protocol, port); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * portmap_unset(PyObject *self, PyObject *args) -{ - unsigned long program, version; - - if (!PyArg_ParseTuple(args, "ll:unset", - &program, &version)) - return NULL; - - pmap_unset(program, version); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef PortmapMethods[] = { - {"set", portmap_set, METH_VARARGS, - "Set an entry in the portmapper."}, - {"unset", portmap_unset, METH_VARARGS, - "Unset an entry in the portmapper."}, - {NULL, NULL, 0, NULL} -}; - -void initportmap(void) -{ - (void) Py_InitModule("portmap", PortmapMethods); -} - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/procmon.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/procmon.py deleted file mode 100644 index 28be909..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/procmon.py +++ /dev/null @@ -1,308 +0,0 @@ -# -*- test-case-name: twisted.runner.test.test_procmon -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for starting, monitoring, and restarting child process. -""" -from twisted.python import log -from twisted.internet import error, protocol, reactor as _reactor -from twisted.application import service -from twisted.protocols import basic - -class DummyTransport: - - disconnecting = 0 - -transport = DummyTransport() - -class LineLogger(basic.LineReceiver): - - tag = None - delimiter = '\n' - - def lineReceived(self, line): - log.msg('[%s] %s' % (self.tag, line)) - - -class LoggingProtocol(protocol.ProcessProtocol): - - service = None - name = None - empty = 1 - - def connectionMade(self): - self.output = LineLogger() - self.output.tag = self.name - self.output.makeConnection(transport) - - - def outReceived(self, data): - self.output.dataReceived(data) - self.empty = data[-1] == '\n' - - errReceived = outReceived - - - def processEnded(self, reason): - if not self.empty: - self.output.dataReceived('\n') - self.service.connectionLost(self.name) - - -class ProcessMonitor(service.Service): - """ - ProcessMonitor runs processes, monitors their progress, and restarts - them when they die. - - The ProcessMonitor will not attempt to restart a process that appears to - die instantly -- with each "instant" death (less than 1 second, by - default), it will delay approximately twice as long before restarting - it. A successful run will reset the counter. - - The primary interface is L{addProcess} and L{removeProcess}. When the - service is running (that is, when the application it is attached to is - running), adding a process automatically starts it. - - Each process has a name. This name string must uniquely identify the - process. In particular, attempting to add two processes with the same - name will result in a C{KeyError}. - - @type threshold: C{float} - @ivar threshold: How long a process has to live before the death is - considered instant, in seconds. The default value is 1 second. - - @type killTime: C{float} - @ivar killTime: How long a process being killed has to get its affairs - in order before it gets killed with an unmaskable signal. The - default value is 5 seconds. - - @type minRestartDelay: C{float} - @ivar minRestartDelay: The minimum time (in seconds) to wait before - attempting to restart a process. Default 1s. - - @type maxRestartDelay: C{float} - @ivar maxRestartDelay: The maximum time (in seconds) to wait before - attempting to restart a process. Default 3600s (1h). - - @type _reactor: L{IReactorProcess} provider - @ivar _reactor: A provider of L{IReactorProcess} and L{IReactorTime} - which will be used to spawn processes and register delayed calls. - - """ - threshold = 1 - killTime = 5 - minRestartDelay = 1 - maxRestartDelay = 3600 - - - def __init__(self, reactor=_reactor): - self._reactor = reactor - - self.processes = {} - self.protocols = {} - self.delay = {} - self.timeStarted = {} - self.murder = {} - self.restart = {} - - - def __getstate__(self): - dct = service.Service.__getstate__(self) - del dct['_reactor'] - dct['protocols'] = {} - dct['delay'] = {} - dct['timeStarted'] = {} - dct['murder'] = {} - dct['restart'] = {} - return dct - - - def addProcess(self, name, args, uid=None, gid=None, env={}): - """ - Add a new monitored process and start it immediately if the - L{ProcessMonitor} service is running. - - Note that args are passed to the system call, not to the shell. If - running the shell is desired, the common idiom is to use - C{ProcessMonitor.addProcess("name", ['/bin/sh', '-c', shell_script])} - - @param name: A name for this process. This value must be - unique across all processes added to this monitor. - @type name: C{str} - @param args: The argv sequence for the process to launch. - @param uid: The user ID to use to run the process. If C{None}, - the current UID is used. - @type uid: C{int} - @param gid: The group ID to use to run the process. If C{None}, - the current GID is used. - @type uid: C{int} - @param env: The environment to give to the launched process. See - L{IReactorProcess.spawnProcess}'s C{env} parameter. - @type env: C{dict} - @raises: C{KeyError} if a process with the given name already - exists - """ - if name in self.processes: - raise KeyError("remove %s first" % (name,)) - self.processes[name] = args, uid, gid, env - self.delay[name] = self.minRestartDelay - if self.running: - self.startProcess(name) - - - def removeProcess(self, name): - """ - Stop the named process and remove it from the list of monitored - processes. - - @type name: C{str} - @param name: A string that uniquely identifies the process. - """ - self.stopProcess(name) - del self.processes[name] - - - def startService(self): - """ - Start all monitored processes. - """ - service.Service.startService(self) - for name in self.processes: - self.startProcess(name) - - - def stopService(self): - """ - Stop all monitored processes and cancel all scheduled process restarts. - """ - service.Service.stopService(self) - - # Cancel any outstanding restarts - for name, delayedCall in self.restart.items(): - if delayedCall.active(): - delayedCall.cancel() - - for name in self.processes: - self.stopProcess(name) - - - def connectionLost(self, name): - """ - Called when a monitored processes exits. If - L{ProcessMonitor.running} is C{True} (ie the service is started), the - process will be restarted. - If the process had been running for more than - L{ProcessMonitor.threshold} seconds it will be restarted immediately. - If the process had been running for less than - L{ProcessMonitor.threshold} seconds, the restart will be delayed and - each time the process dies before the configured threshold, the restart - delay will be doubled - up to a maximum delay of maxRestartDelay sec. - - @type name: C{str} - @param name: A string that uniquely identifies the process - which exited. - """ - # Cancel the scheduled _forceStopProcess function if the process - # dies naturally - if name in self.murder: - if self.murder[name].active(): - self.murder[name].cancel() - del self.murder[name] - - del self.protocols[name] - - if self._reactor.seconds() - self.timeStarted[name] < self.threshold: - # The process died too fast - backoff - nextDelay = self.delay[name] - self.delay[name] = min(self.delay[name] * 2, self.maxRestartDelay) - - else: - # Process had been running for a significant amount of time - # restart immediately - nextDelay = 0 - self.delay[name] = self.minRestartDelay - - # Schedule a process restart if the service is running - if self.running and name in self.processes: - self.restart[name] = self._reactor.callLater(nextDelay, - self.startProcess, - name) - - - def startProcess(self, name): - """ - @param name: The name of the process to be started - """ - # If a protocol instance already exists, it means the process is - # already running - if name in self.protocols: - return - - args, uid, gid, env = self.processes[name] - - proto = LoggingProtocol() - proto.service = self - proto.name = name - self.protocols[name] = proto - self.timeStarted[name] = self._reactor.seconds() - self._reactor.spawnProcess(proto, args[0], args, uid=uid, - gid=gid, env=env) - - - def _forceStopProcess(self, proc): - """ - @param proc: An L{IProcessTransport} provider - """ - try: - proc.signalProcess('KILL') - except error.ProcessExitedAlready: - pass - - - def stopProcess(self, name): - """ - @param name: The name of the process to be stopped - """ - if name not in self.processes: - raise KeyError('Unrecognized process name: %s' % (name,)) - - proto = self.protocols.get(name, None) - if proto is not None: - proc = proto.transport - try: - proc.signalProcess('TERM') - except error.ProcessExitedAlready: - pass - else: - self.murder[name] = self._reactor.callLater( - self.killTime, - self._forceStopProcess, proc) - - - def restartAll(self): - """ - Restart all processes. This is useful for third party management - services to allow a user to restart servers because of an outside change - in circumstances -- for example, a new version of a library is - installed. - """ - for name in self.processes: - self.stopProcess(name) - - - def __repr__(self): - l = [] - for name, proc in self.processes.items(): - uidgid = '' - if proc[1] is not None: - uidgid = str(proc[1]) - if proc[2] is not None: - uidgid += ':'+str(proc[2]) - - if uidgid: - uidgid = '(' + uidgid + ')' - l.append('%r%s: %r' % (name, uidgid, proc[0])) - return ('<' + self.__class__.__name__ + ' ' - + ' '.join(l) - + '>') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/procmontap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/procmontap.py deleted file mode 100644 index c0e72a4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/procmontap.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- test-case-name: twisted.runner.test.test_procmontap -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for creating a service which runs a process monitor. -""" - -from twisted.python import usage -from twisted.runner.procmon import ProcessMonitor - - -class Options(usage.Options): - """ - Define the options accepted by the I{twistd procmon} plugin. - """ - - synopsis = "[procmon options] commandline" - - optParameters = [["threshold", "t", 1, "How long a process has to live " - "before the death is considered instant, in seconds.", - float], - ["killtime", "k", 5, "How long a process being killed " - "has to get its affairs in order before it gets killed " - "with an unmaskable signal.", - float], - ["minrestartdelay", "m", 1, "The minimum time (in " - "seconds) to wait before attempting to restart a " - "process", float], - ["maxrestartdelay", "M", 3600, "The maximum time (in " - "seconds) to wait before attempting to restart a " - "process", float]] - - optFlags = [] - - - longdesc = """\ -procmon runs processes, monitors their progress, and restarts them when they -die. - -procmon will not attempt to restart a process that appears to die instantly; -with each "instant" death (less than 1 second, by default), it will delay -approximately twice as long before restarting it. A successful run will reset -the counter. - -Eg twistd procmon sleep 10""" - - def parseArgs(self, *args): - """ - Grab the command line that is going to be started and monitored - """ - self['args'] = args - - - def postOptions(self): - """ - Check for dependencies. - """ - if len(self["args"]) < 1: - raise usage.UsageError("Please specify a process commandline") - - - -def makeService(config): - s = ProcessMonitor() - - s.threshold = config["threshold"] - s.killTime = config["killtime"] - s.minRestartDelay = config["minrestartdelay"] - s.maxRestartDelay = config["maxrestartdelay"] - - s.addProcess(" ".join(config["args"]), config["args"]) - return s diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/__init__.py deleted file mode 100644 index e6c22ba..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test package for Twisted Runner. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/test_procmon.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/test_procmon.py deleted file mode 100644 index d5217a0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/test_procmon.py +++ /dev/null @@ -1,477 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.runner.procmon}. -""" - -from twisted.trial import unittest -from twisted.runner.procmon import LoggingProtocol, ProcessMonitor -from twisted.internet.error import (ProcessDone, ProcessTerminated, - ProcessExitedAlready) -from twisted.internet.task import Clock -from twisted.python.failure import Failure -from twisted.test.proto_helpers import MemoryReactor - - - -class DummyProcess(object): - """ - An incomplete and fake L{IProcessTransport} implementation for testing how - L{ProcessMonitor} behaves when its monitored processes exit. - - @ivar _terminationDelay: the delay in seconds after which the DummyProcess - will appear to exit when it receives a TERM signal - """ - - pid = 1 - proto = None - - _terminationDelay = 1 - - def __init__(self, reactor, executable, args, environment, path, - proto, uid=None, gid=None, usePTY=0, childFDs=None): - - self.proto = proto - - self._reactor = reactor - self._executable = executable - self._args = args - self._environment = environment - self._path = path - self._uid = uid - self._gid = gid - self._usePTY = usePTY - self._childFDs = childFDs - - - def signalProcess(self, signalID): - """ - A partial implementation of signalProcess which can only handle TERM and - KILL signals. - - When a TERM signal is given, the dummy process will appear to exit - after L{DummyProcess._terminationDelay} seconds with exit code 0 - - When a KILL signal is given, the dummy process will appear to exit - immediately with exit code 1. - - @param signalID: The signal name or number to be issued to the process. - @type signalID: C{str} - """ - params = { - "TERM": (self._terminationDelay, 0), - "KILL": (0, 1) - } - - if self.pid is None: - raise ProcessExitedAlready() - - if signalID in params: - delay, status = params[signalID] - self._signalHandler = self._reactor.callLater( - delay, self.processEnded, status) - - - def processEnded(self, status): - """ - Deliver the process ended event to C{self.proto}. - """ - self.pid = None - statusMap = { - 0: ProcessDone, - 1: ProcessTerminated, - } - self.proto.processEnded(Failure(statusMap[status](status))) - - - -class DummyProcessReactor(MemoryReactor, Clock): - """ - @ivar spawnedProcesses: a list that keeps track of the fake process - instances built by C{spawnProcess}. - @type spawnedProcesses: C{list} - """ - def __init__(self): - MemoryReactor.__init__(self) - Clock.__init__(self) - - self.spawnedProcesses = [] - - - def spawnProcess(self, processProtocol, executable, args=(), env={}, - path=None, uid=None, gid=None, usePTY=0, - childFDs=None): - """ - Fake L{reactor.spawnProcess}, that logs all the process - arguments and returns a L{DummyProcess}. - """ - - proc = DummyProcess(self, executable, args, env, path, - processProtocol, uid, gid, usePTY, childFDs) - processProtocol.makeConnection(proc) - self.spawnedProcesses.append(proc) - return proc - - - -class ProcmonTests(unittest.TestCase): - """ - Tests for L{ProcessMonitor}. - """ - - def setUp(self): - """ - Create an L{ProcessMonitor} wrapped around a fake reactor. - """ - self.reactor = DummyProcessReactor() - self.pm = ProcessMonitor(reactor=self.reactor) - self.pm.minRestartDelay = 2 - self.pm.maxRestartDelay = 10 - self.pm.threshold = 10 - - - def test_getStateIncludesProcesses(self): - """ - The list of monitored processes must be included in the pickle state. - """ - self.pm.addProcess("foo", ["arg1", "arg2"], - uid=1, gid=2, env={}) - self.assertEqual(self.pm.__getstate__()['processes'], - {'foo': (['arg1', 'arg2'], 1, 2, {})}) - - - def test_getStateExcludesReactor(self): - """ - The private L{ProcessMonitor._reactor} instance variable should not be - included in the pickle state. - """ - self.assertNotIn('_reactor', self.pm.__getstate__()) - - - def test_addProcess(self): - """ - L{ProcessMonitor.addProcess} only starts the named program if - L{ProcessMonitor.startService} has been called. - """ - self.pm.addProcess("foo", ["arg1", "arg2"], - uid=1, gid=2, env={}) - self.assertEqual(self.pm.protocols, {}) - self.assertEqual(self.pm.processes, - {"foo": (["arg1", "arg2"], 1, 2, {})}) - self.pm.startService() - self.reactor.advance(0) - self.assertEqual(self.pm.protocols.keys(), ["foo"]) - - - def test_addProcessDuplicateKeyError(self): - """ - L{ProcessMonitor.addProcess} raises a C{KeyError} if a process with the - given name already exists. - """ - self.pm.addProcess("foo", ["arg1", "arg2"], - uid=1, gid=2, env={}) - self.assertRaises(KeyError, self.pm.addProcess, - "foo", ["arg1", "arg2"], uid=1, gid=2, env={}) - - - def test_addProcessEnv(self): - """ - L{ProcessMonitor.addProcess} takes an C{env} parameter that is passed to - L{IReactorProcess.spawnProcess}. - """ - fakeEnv = {"KEY": "value"} - self.pm.startService() - self.pm.addProcess("foo", ["foo"], uid=1, gid=2, env=fakeEnv) - self.reactor.advance(0) - self.assertEqual( - self.reactor.spawnedProcesses[0]._environment, fakeEnv) - - - def test_removeProcess(self): - """ - L{ProcessMonitor.removeProcess} removes the process from the public - processes list. - """ - self.pm.startService() - self.pm.addProcess("foo", ["foo"]) - self.assertEqual(len(self.pm.processes), 1) - self.pm.removeProcess("foo") - self.assertEqual(len(self.pm.processes), 0) - - - def test_removeProcessUnknownKeyError(self): - """ - L{ProcessMonitor.removeProcess} raises a C{KeyError} if the given - process name isn't recognised. - """ - self.pm.startService() - self.assertRaises(KeyError, self.pm.removeProcess, "foo") - - - def test_startProcess(self): - """ - When a process has been started, an instance of L{LoggingProtocol} will - be added to the L{ProcessMonitor.protocols} dict and the start time of - the process will be recorded in the L{ProcessMonitor.timeStarted} - dictionary. - """ - self.pm.addProcess("foo", ["foo"]) - self.pm.startProcess("foo") - self.assertIsInstance(self.pm.protocols["foo"], LoggingProtocol) - self.assertIn("foo", self.pm.timeStarted.keys()) - - - def test_startProcessAlreadyStarted(self): - """ - L{ProcessMonitor.startProcess} silently returns if the named process is - already started. - """ - self.pm.addProcess("foo", ["foo"]) - self.pm.startProcess("foo") - self.assertIdentical(None, self.pm.startProcess("foo")) - - - def test_startProcessUnknownKeyError(self): - """ - L{ProcessMonitor.startProcess} raises a C{KeyError} if the given - process name isn't recognised. - """ - self.assertRaises(KeyError, self.pm.startProcess, "foo") - - - def test_stopProcessNaturalTermination(self): - """ - L{ProcessMonitor.stopProcess} immediately sends a TERM signal to the - named process. - """ - self.pm.startService() - self.pm.addProcess("foo", ["foo"]) - self.assertIn("foo", self.pm.protocols) - - # Configure fake process to die 1 second after receiving term signal - timeToDie = self.pm.protocols["foo"].transport._terminationDelay = 1 - - # Advance the reactor to just before the short lived process threshold - # and leave enough time for the process to die - self.reactor.advance(self.pm.threshold) - # Then signal the process to stop - self.pm.stopProcess("foo") - - # Advance the reactor just enough to give the process time to die and - # verify that the process restarts - self.reactor.advance(timeToDie) - - # We expect it to be restarted immediately - self.assertEqual(self.reactor.seconds(), - self.pm.timeStarted["foo"]) - - - def test_stopProcessForcedKill(self): - """ - L{ProcessMonitor.stopProcess} kills a process which fails to terminate - naturally within L{ProcessMonitor.killTime} seconds. - """ - self.pm.startService() - self.pm.addProcess("foo", ["foo"]) - self.assertIn("foo", self.pm.protocols) - self.reactor.advance(self.pm.threshold) - proc = self.pm.protocols["foo"].transport - # Arrange for the fake process to live longer than the killTime - proc._terminationDelay = self.pm.killTime + 1 - self.pm.stopProcess("foo") - # If process doesn't die before the killTime, procmon should - # terminate it - self.reactor.advance(self.pm.killTime - 1) - self.assertEqual(0.0, self.pm.timeStarted["foo"]) - - self.reactor.advance(1) - # We expect it to be immediately restarted - self.assertEqual(self.reactor.seconds(), self.pm.timeStarted["foo"]) - - - def test_stopProcessUnknownKeyError(self): - """ - L{ProcessMonitor.stopProcess} raises a C{KeyError} if the given process - name isn't recognised. - """ - self.assertRaises(KeyError, self.pm.stopProcess, "foo") - - - def test_stopProcessAlreadyStopped(self): - """ - L{ProcessMonitor.stopProcess} silently returns if the named process - is already stopped. eg Process has crashed and a restart has been - rescheduled, but in the meantime, the service is stopped. - """ - self.pm.addProcess("foo", ["foo"]) - self.assertIdentical(None, self.pm.stopProcess("foo")) - - - def test_connectionLostLongLivedProcess(self): - """ - L{ProcessMonitor.connectionLost} should immediately restart a process - if it has been running longer than L{ProcessMonitor.threshold} seconds. - """ - self.pm.addProcess("foo", ["foo"]) - # Schedule the process to start - self.pm.startService() - # advance the reactor to start the process - self.reactor.advance(0) - self.assertIn("foo", self.pm.protocols) - # Long time passes - self.reactor.advance(self.pm.threshold) - # Process dies after threshold - self.pm.protocols["foo"].processEnded(Failure(ProcessDone(0))) - self.assertNotIn("foo", self.pm.protocols) - # Process should be restarted immediately - self.reactor.advance(0) - self.assertIn("foo", self.pm.protocols) - - - def test_connectionLostMurderCancel(self): - """ - L{ProcessMonitor.connectionLost} cancels a scheduled process killer and - deletes the DelayedCall from the L{ProcessMonitor.murder} list. - """ - self.pm.addProcess("foo", ["foo"]) - # Schedule the process to start - self.pm.startService() - # Advance 1s to start the process then ask ProcMon to stop it - self.reactor.advance(1) - self.pm.stopProcess("foo") - # A process killer has been scheduled, delayedCall is active - self.assertIn("foo", self.pm.murder) - delayedCall = self.pm.murder["foo"] - self.assertTrue(delayedCall.active()) - # Advance to the point at which the dummy process exits - self.reactor.advance( - self.pm.protocols["foo"].transport._terminationDelay) - # Now the delayedCall has been cancelled and deleted - self.assertFalse(delayedCall.active()) - self.assertNotIn("foo", self.pm.murder) - - - def test_connectionLostProtocolDeletion(self): - """ - L{ProcessMonitor.connectionLost} removes the corresponding - ProcessProtocol instance from the L{ProcessMonitor.protocols} list. - """ - self.pm.startService() - self.pm.addProcess("foo", ["foo"]) - self.assertIn("foo", self.pm.protocols) - self.pm.protocols["foo"].transport.signalProcess("KILL") - self.reactor.advance( - self.pm.protocols["foo"].transport._terminationDelay) - self.assertNotIn("foo", self.pm.protocols) - - - def test_connectionLostMinMaxRestartDelay(self): - """ - L{ProcessMonitor.connectionLost} will wait at least minRestartDelay s - and at most maxRestartDelay s - """ - self.pm.minRestartDelay = 2 - self.pm.maxRestartDelay = 3 - - self.pm.startService() - self.pm.addProcess("foo", ["foo"]) - - self.assertEqual(self.pm.delay["foo"], self.pm.minRestartDelay) - self.reactor.advance(self.pm.threshold - 1) - self.pm.protocols["foo"].processEnded(Failure(ProcessDone(0))) - self.assertEqual(self.pm.delay["foo"], self.pm.maxRestartDelay) - - - def test_connectionLostBackoffDelayDoubles(self): - """ - L{ProcessMonitor.connectionLost} doubles the restart delay each time - the process dies too quickly. - """ - self.pm.startService() - self.pm.addProcess("foo", ["foo"]) - self.reactor.advance(self.pm.threshold - 1) #9s - self.assertIn("foo", self.pm.protocols) - self.assertEqual(self.pm.delay["foo"], self.pm.minRestartDelay) - # process dies within the threshold and should not restart immediately - self.pm.protocols["foo"].processEnded(Failure(ProcessDone(0))) - self.assertEqual(self.pm.delay["foo"], self.pm.minRestartDelay * 2) - - - def test_startService(self): - """ - L{ProcessMonitor.startService} starts all monitored processes. - """ - self.pm.addProcess("foo", ["foo"]) - # Schedule the process to start - self.pm.startService() - # advance the reactor to start the process - self.reactor.advance(0) - self.assertTrue("foo" in self.pm.protocols) - - - def test_stopService(self): - """ - L{ProcessMonitor.stopService} should stop all monitored processes. - """ - self.pm.addProcess("foo", ["foo"]) - self.pm.addProcess("bar", ["bar"]) - # Schedule the process to start - self.pm.startService() - # advance the reactor to start the processes - self.reactor.advance(self.pm.threshold) - self.assertIn("foo", self.pm.protocols) - self.assertIn("bar", self.pm.protocols) - - self.reactor.advance(1) - - self.pm.stopService() - # Advance to beyond the killTime - all monitored processes - # should have exited - self.reactor.advance(self.pm.killTime + 1) - # The processes shouldn't be restarted - self.assertEqual({}, self.pm.protocols) - - - def test_stopServiceCancelRestarts(self): - """ - L{ProcessMonitor.stopService} should cancel any scheduled process - restarts. - """ - self.pm.addProcess("foo", ["foo"]) - # Schedule the process to start - self.pm.startService() - # advance the reactor to start the processes - self.reactor.advance(self.pm.threshold) - self.assertIn("foo", self.pm.protocols) - - self.reactor.advance(1) - # Kill the process early - self.pm.protocols["foo"].processEnded(Failure(ProcessDone(0))) - self.assertTrue(self.pm.restart['foo'].active()) - self.pm.stopService() - # Scheduled restart should have been cancelled - self.assertFalse(self.pm.restart['foo'].active()) - - - def test_stopServiceCleanupScheduledRestarts(self): - """ - L{ProcessMonitor.stopService} should cancel all scheduled process - restarts. - """ - self.pm.threshold = 5 - self.pm.minRestartDelay = 5 - # Start service and add a process (started immediately) - self.pm.startService() - self.pm.addProcess("foo", ["foo"]) - # Stop the process after 1s - self.reactor.advance(1) - self.pm.stopProcess("foo") - # Wait 1s for it to exit it will be scheduled to restart 5s later - self.reactor.advance(1) - # Meanwhile stop the service - self.pm.stopService() - # Advance to beyond the process restart time - self.reactor.advance(6) - # The process shouldn't have restarted because stopService has cancelled - # all pending process restarts. - self.assertEqual(self.pm.protocols, {}) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/test_procmontap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/test_procmontap.py deleted file mode 100644 index 6819425..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/test/test_procmontap.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.runner.procmontap}. -""" - -from twisted.python.usage import UsageError -from twisted.trial import unittest -from twisted.runner.procmon import ProcessMonitor -from twisted.runner import procmontap as tap - - -class ProcessMonitorTapTests(unittest.TestCase): - """ - Tests for L{twisted.runner.procmontap}'s option parsing and makeService - method. - """ - - def test_commandLineRequired(self): - """ - The command line arguments must be provided. - """ - opt = tap.Options() - self.assertRaises(UsageError, opt.parseOptions, []) - - - def test_threshold(self): - """ - The threshold option is recognised as a parameter and coerced to - float. - """ - opt = tap.Options() - opt.parseOptions(['--threshold', '7.5', 'foo']) - self.assertEqual(opt['threshold'], 7.5) - - - def test_killTime(self): - """ - The killtime option is recognised as a parameter and coerced to float. - """ - opt = tap.Options() - opt.parseOptions(['--killtime', '7.5', 'foo']) - self.assertEqual(opt['killtime'], 7.5) - - - def test_minRestartDelay(self): - """ - The minrestartdelay option is recognised as a parameter and coerced to - float. - """ - opt = tap.Options() - opt.parseOptions(['--minrestartdelay', '7.5', 'foo']) - self.assertEqual(opt['minrestartdelay'], 7.5) - - - def test_maxRestartDelay(self): - """ - The maxrestartdelay option is recognised as a parameter and coerced to - float. - """ - opt = tap.Options() - opt.parseOptions(['--maxrestartdelay', '7.5', 'foo']) - self.assertEqual(opt['maxrestartdelay'], 7.5) - - - def test_parameterDefaults(self): - """ - The parameters all have default values - """ - opt = tap.Options() - opt.parseOptions(['foo']) - self.assertEqual(opt['threshold'], 1) - self.assertEqual(opt['killtime'], 5) - self.assertEqual(opt['minrestartdelay'], 1) - self.assertEqual(opt['maxrestartdelay'], 3600) - - - def test_makeService(self): - """ - The command line gets added as a process to the ProcessMontor. - """ - opt = tap.Options() - opt.parseOptions(['ping', '-c', '3', '8.8.8.8']) - s = tap.makeService(opt) - self.assertIsInstance(s, ProcessMonitor) - self.assertIn('ping -c 3 8.8.8.8', s.processes) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/NEWS deleted file mode 100644 index 67ffcfb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/NEWS +++ /dev/null @@ -1,185 +0,0 @@ -Ticket numbers in this file can be looked up by visiting -http://twistedmatrix.com/trac/ticket/ - -Twisted Runner 15.2.1 (2015-05-23) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 15.2.0 (2015-05-18) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 15.1.0 (2015-04-02) -================================== - -No significant changes have been made for this release. - -Other ------ - - #7726 - - -Twisted Runner 15.0.0 (2015-01-24) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 14.0.2 (2014-09-18) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 14.0.1 (2014-09-17) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 14.0.0 (2014-05-08) -================================== - -No significant changes have been made for this release. - -Other ------ - - #6992 - - -Twisted Runner 13.2.0 (2013-10-29) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 13.1.0 (2013-06-23) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 13.0.0 (2013-03-19) -================================== - -No significant changes have been made for this release. - -Other ------ - - #5740 - - -Twisted Runner 12.3.0 (2012-12-20) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 12.2.0 (2012-08-26) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 12.1.0 (2012-06-02) -================================== - -Deprecations and Removals -------------------------- - - ProcessMonitor.active, consistencyDelay, and consistency in - twisted.runner.procmon were deprecated since 10.1 have been - removed. (#5517) - - -Twisted Runner 12.0.0 (2012-02-10) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 11.1.0 (2011-11-15) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 11.0.0 (2011-04-01) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 10.2.0 (2010-11-29) -================================== - -No significant changes have been made for this release. - - -Twisted Runner 10.1.0 (2010-06-27) -================================== - -Features --------- - - twistd now has a procmon subcommand plugin - a convenient way to - monitor and automatically restart another process. (#4356) - -Deprecations and Removals -------------------------- - - twisted.runner.procmon.ProcessMonitor's active, consistency, and - consistencyDelay attributes are now deprecated. (#1763) - -Other ------ - - #3775 - - -Twisted Runner 10.0.0 (2010-03-01) -================================== - -Other ------ - - #3961 - - -Twisted Runner 9.0.0 (2009-11-24) -================================= - -Features --------- - - procmon.ProcessMonitor.addProcess now accepts an 'env' parameter which allows - users to specify the environment in which a process will be run (#3691) - -Other ------ - - #3540 - - -Runner 8.2.0 (2008-12-16) -========================= - -No interesting changes since Twisted 8.0. - -8.0.0 (2008-03-17) -================== - -Misc ----- - - Remove all "API Stability" markers (#2847) - - -0.2.0 (2006-05-24) -================== - -Fixes ------ - - Fix a bug that broke inetdtap.RPCServer. - - Misc: #1142 - - -0.1.0 -===== - - Pass *blocking* sockets to subprocesses run by inetd diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/README deleted file mode 100644 index 4aaa19c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/README +++ /dev/null @@ -1,3 +0,0 @@ -Twisted Runner 15.2.1 - -Twisted Runner depends on Twisted. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/setup.py deleted file mode 100644 index 27f65d3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/runner/topfiles/setup.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - from twisted.python.dist import setup, ConditionalExtension as Extension -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -extensions = [ - Extension("twisted.runner.portmap", - ["twisted/runner/portmap.c"], - condition=lambda builder: builder._check_header("rpc/rpc.h")), -] - -if __name__ == '__main__': - setup( - twisted_subproject="runner", - # metadata - name="Twisted Runner", - description="Twisted Runner is a process management library and inetd " - "replacement.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Andrew Bennetts", - url="http://twistedmatrix.com/trac/wiki/TwistedRunner", - license="MIT", - long_description="""\ -Twisted Runner contains code useful for persistent process management -with Python and Twisted, and has an almost full replacement for inetd. -""", - # build stuff - conditionalExtensions=extensions, - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/__init__.py deleted file mode 100644 index 73d90a8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Subpackage containing the modules that implement the command line tools. - -Note that these are imported by top-level scripts which are intended to be -invoked directly from a shell. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/_twistd_unix.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/_twistd_unix.py deleted file mode 100644 index f0a43bc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/_twistd_unix.py +++ /dev/null @@ -1,390 +0,0 @@ -# -*- test-case-name: twisted.test.test_twistd -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -import os, errno, sys - -from twisted.python import log, syslog, logfile, usage -from twisted.python.util import ( - switchUID, uidFromString, gidFromString, untilConcludes) -from twisted.application import app, service -from twisted.internet.interfaces import IReactorDaemonize -from twisted import copyright - - -def _umask(value): - return int(value, 8) - - -class ServerOptions(app.ServerOptions): - synopsis = "Usage: twistd [options]" - - optFlags = [['nodaemon', 'n', "don't daemonize, don't use default umask of 0077"], - ['originalname', None, "Don't try to change the process name"], - ['syslog', None, "Log to syslog, not to file"], - ['euid', '', - "Set only effective user-id rather than real user-id. " - "(This option has no effect unless the server is running as " - "root, in which case it means not to shed all privileges " - "after binding ports, retaining the option to regain " - "privileges in cases such as spawning processes. " - "Use with caution.)"], - ] - - optParameters = [ - ['prefix', None,'twisted', - "use the given prefix when syslogging"], - ['pidfile','','twistd.pid', - "Name of the pidfile"], - ['chroot', None, None, - 'Chroot to a supplied directory before running'], - ['uid', 'u', None, "The uid to run as.", uidFromString], - ['gid', 'g', None, "The gid to run as.", gidFromString], - ['umask', None, None, - "The (octal) file creation mask to apply.", _umask], - ] - - compData = usage.Completions( - optActions={"pidfile": usage.CompleteFiles("*.pid"), - "chroot": usage.CompleteDirs(descr="chroot directory"), - "gid": usage.CompleteGroups(descr="gid to run as"), - "uid": usage.CompleteUsernames(descr="uid to run as"), - "prefix": usage.Completer(descr="syslog prefix"), - }, - ) - - def opt_version(self): - """Print version information and exit. - """ - print 'twistd (the Twisted daemon) %s' % copyright.version - print copyright.copyright - sys.exit() - - - def postOptions(self): - app.ServerOptions.postOptions(self) - if self['pidfile']: - self['pidfile'] = os.path.abspath(self['pidfile']) - - -def checkPID(pidfile): - if not pidfile: - return - if os.path.exists(pidfile): - try: - pid = int(open(pidfile).read()) - except ValueError: - sys.exit('Pidfile %s contains non-numeric value' % pidfile) - try: - os.kill(pid, 0) - except OSError, why: - if why[0] == errno.ESRCH: - # The pid doesn't exists. - log.msg('Removing stale pidfile %s' % pidfile, isError=True) - os.remove(pidfile) - else: - sys.exit("Can't check status of PID %s from pidfile %s: %s" % - (pid, pidfile, why[1])) - else: - sys.exit("""\ -Another twistd server is running, PID %s\n -This could either be a previously started instance of your application or a -different application entirely. To start a new one, either run it in some other -directory, or use the --pidfile and --logfile parameters to avoid clashes. -""" % pid) - - - -class UnixAppLogger(app.AppLogger): - """ - A logger able to log to syslog, to files, and to stdout. - - @ivar _syslog: A flag indicating whether to use syslog instead of file - logging. - @type _syslog: C{bool} - - @ivar _syslogPrefix: If C{sysLog} is C{True}, the string prefix to use for - syslog messages. - @type _syslogPrefix: C{str} - - @ivar _nodaemon: A flag indicating the process will not be daemonizing. - @type _nodaemon: C{bool} - """ - - def __init__(self, options): - app.AppLogger.__init__(self, options) - self._syslog = options.get("syslog", False) - self._syslogPrefix = options.get("prefix", "") - self._nodaemon = options.get("nodaemon", False) - - - def _getLogObserver(self): - """ - Create and return a suitable log observer for the given configuration. - - The observer will go to syslog using the prefix C{_syslogPrefix} if - C{_syslog} is true. Otherwise, it will go to the file named - C{_logfilename} or, if C{_nodaemon} is true and C{_logfilename} is - C{"-"}, to stdout. - - @return: An object suitable to be passed to C{log.addObserver}. - """ - if self._syslog: - return syslog.SyslogObserver(self._syslogPrefix).emit - - if self._logfilename == '-': - if not self._nodaemon: - sys.exit('Daemons cannot log to stdout, exiting!') - logFile = sys.stdout - elif self._nodaemon and not self._logfilename: - logFile = sys.stdout - else: - if not self._logfilename: - self._logfilename = 'twistd.log' - logFile = logfile.LogFile.fromFullPath(self._logfilename) - try: - import signal - except ImportError: - pass - else: - # Override if signal is set to None or SIG_DFL (0) - if not signal.getsignal(signal.SIGUSR1): - def rotateLog(signal, frame): - from twisted.internet import reactor - reactor.callFromThread(logFile.rotate) - signal.signal(signal.SIGUSR1, rotateLog) - return log.FileLogObserver(logFile).emit - - - -def launchWithName(name): - if name and name != sys.argv[0]: - exe = os.path.realpath(sys.executable) - log.msg('Changing process name to ' + name) - os.execv(exe, [name, sys.argv[0], '--originalname'] + sys.argv[1:]) - - - -class UnixApplicationRunner(app.ApplicationRunner): - """ - An ApplicationRunner which does Unix-specific things, like fork, - shed privileges, and maintain a PID file. - """ - loggerFactory = UnixAppLogger - - def preApplication(self): - """ - Do pre-application-creation setup. - """ - checkPID(self.config['pidfile']) - self.config['nodaemon'] = (self.config['nodaemon'] - or self.config['debug']) - self.oldstdout = sys.stdout - self.oldstderr = sys.stderr - - - def postApplication(self): - """ - To be called after the application is created: start the application - and run the reactor. After the reactor stops, clean up PID files and - such. - """ - try: - self.startApplication(self.application) - except Exception as ex: - statusPipe = self.config.get("statusPipe", None) - if statusPipe is not None: - # Limit the total length to the passed string to 100 - strippedError = str(ex)[:98] - untilConcludes(os.write, statusPipe, "1 %s" % (strippedError,)) - untilConcludes(os.close, statusPipe) - self.removePID(self.config['pidfile']) - raise - else: - statusPipe = self.config.get("statusPipe", None) - if statusPipe is not None: - untilConcludes(os.write, statusPipe, "0") - untilConcludes(os.close, statusPipe) - self.startReactor(None, self.oldstdout, self.oldstderr) - self.removePID(self.config['pidfile']) - - - def removePID(self, pidfile): - """ - Remove the specified PID file, if possible. Errors are logged, not - raised. - - @type pidfile: C{str} - @param pidfile: The path to the PID tracking file. - """ - if not pidfile: - return - try: - os.unlink(pidfile) - except OSError, e: - if e.errno == errno.EACCES or e.errno == errno.EPERM: - log.msg("Warning: No permission to delete pid file") - else: - log.err(e, "Failed to unlink PID file:") - except: - log.err(None, "Failed to unlink PID file:") - - - def setupEnvironment(self, chroot, rundir, nodaemon, umask, pidfile): - """ - Set the filesystem root, the working directory, and daemonize. - - @type chroot: C{str} or L{NoneType} - @param chroot: If not None, a path to use as the filesystem root (using - L{os.chroot}). - - @type rundir: C{str} - @param rundir: The path to set as the working directory. - - @type nodaemon: C{bool} - @param nodaemon: A flag which, if set, indicates that daemonization - should not be done. - - @type umask: C{int} or L{NoneType} - @param umask: The value to which to change the process umask. - - @type pidfile: C{str} or L{NoneType} - @param pidfile: If not C{None}, the path to a file into which to put - the PID of this process. - """ - daemon = not nodaemon - - if chroot is not None: - os.chroot(chroot) - if rundir == '.': - rundir = '/' - os.chdir(rundir) - if daemon and umask is None: - umask = 077 - if umask is not None: - os.umask(umask) - if daemon: - from twisted.internet import reactor - self.config["statusPipe"] = self.daemonize(reactor) - if pidfile: - f = open(pidfile, 'wb') - f.write(str(os.getpid())) - f.close() - - - def daemonize(self, reactor): - """ - Daemonizes the application on Unix. This is done by the usual double - forking approach. - - @see: U{http://code.activestate.com/recipes/278731/} - @see: W. Richard Stevens, - "Advanced Programming in the Unix Environment", - 1992, Addison-Wesley, ISBN 0-201-56317-7 - - @param reactor: The reactor in use. If it provides - L{IReactorDaemonize}, its daemonization-related callbacks will be - invoked. - - @return: A writable pipe to be used to report errors. - @rtype: C{int} - """ - # If the reactor requires hooks to be called for daemonization, call - # them. Currently the only reactor which provides/needs that is - # KQueueReactor. - if IReactorDaemonize.providedBy(reactor): - reactor.beforeDaemonize() - r, w = os.pipe() - if os.fork(): # launch child and... - code = self._waitForStart(r) - os.close(r) - os._exit(code) # kill off parent - os.setsid() - if os.fork(): # launch child and... - os._exit(0) # kill off parent again. - null = os.open('/dev/null', os.O_RDWR) - for i in range(3): - try: - os.dup2(null, i) - except OSError as e: - if e.errno != errno.EBADF: - raise - os.close(null) - - if IReactorDaemonize.providedBy(reactor): - reactor.afterDaemonize() - - return w - - - def _waitForStart(self, readPipe): - """ - Wait for the daemonization success. - - @param readPipe: file descriptor to read start information from. - @type readPipe: C{int} - - @return: code to be passed to C{os._exit}: 0 for success, 1 for error. - @rtype: C{int} - """ - data = untilConcludes(os.read, readPipe, 100) - if data != "0": - msg = ("An error has occurred: '%s'\nPlease look at log " - "file for more information.\n" % (data[2:],)) - untilConcludes(sys.__stderr__.write, msg) - return 1 - return 0 - - - def shedPrivileges(self, euid, uid, gid): - """ - Change the UID and GID or the EUID and EGID of this process. - - @type euid: C{bool} - @param euid: A flag which, if set, indicates that only the I{effective} - UID and GID should be set. - - @type uid: C{int} or C{NoneType} - @param uid: If not C{None}, the UID to which to switch. - - @type gid: C{int} or C{NoneType} - @param gid: If not C{None}, the GID to which to switch. - """ - if uid is not None or gid is not None: - extra = euid and 'e' or '' - desc = '%suid/%sgid %s/%s' % (extra, extra, uid, gid) - try: - switchUID(uid, gid, euid) - except OSError: - log.msg('failed to set %s (are you root?) -- exiting.' % desc) - sys.exit(1) - else: - log.msg('set %s' % desc) - - - def startApplication(self, application): - """ - Configure global process state based on the given application and run - the application. - - @param application: An object which can be adapted to - L{service.IProcess} and L{service.IService}. - """ - process = service.IProcess(application) - if not self.config['originalname']: - launchWithName(process.processName) - self.setupEnvironment( - self.config['chroot'], self.config['rundir'], - self.config['nodaemon'], self.config['umask'], - self.config['pidfile']) - - service.IService(application).privilegedStartService() - - uid, gid = self.config['uid'], self.config['gid'] - if uid is None: - uid = process.uid - if gid is None: - gid = process.gid - - self.shedPrivileges(self.config['euid'], uid, gid) - app.startApplication(application, not self.config['no_save']) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/_twistw.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/_twistw.py deleted file mode 100644 index 9bf1348..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/_twistw.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- test-case-name: twisted.test.test_twistd -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.python import log -from twisted.application import app, service, internet -from twisted import copyright -import sys, os - - - -class ServerOptions(app.ServerOptions): - synopsis = "Usage: twistd [options]" - - optFlags = [['nodaemon','n', "(for backwards compatibility)."], - ] - - def opt_version(self): - """Print version information and exit. - """ - print 'twistd (the Twisted Windows runner) %s' % copyright.version - print copyright.copyright - sys.exit() - - - -class WindowsApplicationRunner(app.ApplicationRunner): - """ - An ApplicationRunner which avoids unix-specific things. No - forking, no PID files, no privileges. - """ - - def preApplication(self): - """ - Do pre-application-creation setup. - """ - self.oldstdout = sys.stdout - self.oldstderr = sys.stderr - os.chdir(self.config['rundir']) - - - def postApplication(self): - """ - Start the application and run the reactor. - """ - service.IService(self.application).privilegedStartService() - app.startApplication(self.application, not self.config['no_save']) - app.startApplication(internet.TimerService(0.1, lambda:None), 0) - self.startReactor(None, self.oldstdout, self.oldstderr) - log.msg("Server Shut Down.") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/htmlizer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/htmlizer.py deleted file mode 100644 index 4357809..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/htmlizer.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""HTML pretty-printing for Python source code.""" - -__version__ = '$Revision: 1.8 $'[11:-2] - -from twisted.python import htmlizer, usage -from twisted import copyright - -import os, sys - -header = ''' -%(title)s - -%(alternate)s -%(stylesheet)s - - -''' -footer = """""" - -styleLink = '' -alternateLink = '' - -class Options(usage.Options): - synopsis = """%s [options] source.py - """ % ( - os.path.basename(sys.argv[0]),) - - optParameters = [ - ('stylesheet', 's', None, "URL of stylesheet to link to."), - ] - - compData = usage.Completions( - extraActions=[usage.CompleteFiles('*.py', descr='source python file')] - ) - - def parseArgs(self, filename): - self['filename'] = filename - -def run(): - options = Options() - try: - options.parseOptions() - except usage.UsageError, e: - print str(e) - sys.exit(1) - filename = options['filename'] - if options.get('stylesheet') is not None: - stylesheet = styleLink % (options['stylesheet'],) - else: - stylesheet = '' - - output = open(filename + '.html', 'w') - try: - output.write(header % { - 'title': filename, - 'generator': 'htmlizer/%s' % (copyright.longversion,), - 'alternate': alternateLink % {'source': filename}, - 'stylesheet': stylesheet - }) - htmlizer.filter(open(filename), output, - htmlizer.SmallerHTMLWriter) - output.write(footer) - finally: - output.close() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/manhole.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/manhole.py deleted file mode 100644 index 06adffb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/manhole.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Start a L{twisted.manhole} client. -""" - -import sys - -from twisted.python import usage - -def run(): - config = MyOptions() - try: - config.parseOptions() - except usage.UsageError, e: - print str(e) - print str(config) - sys.exit(1) - - run_gtk2(config) - - from twisted.internet import reactor - reactor.run() - - -def run_gtk2(config): - # Put these off until after we parse options, so we know what reactor - # to load. - from twisted.internet import gtk2reactor - gtk2reactor.install() - - # Put this off until after we parse options, or else gnome eats them. - sys.argv[:] = ['manhole'] - from twisted.manhole.ui import gtk2manhole - - o = config.opts - defaults = { - 'host': o['host'], - 'port': o['port'], - 'identityName': o['user'], - 'password': o['password'], - 'serviceName': o['service'], - 'perspectiveName': o['perspective'] - } - w = gtk2manhole.ManholeWindow() - w.setDefaults(defaults) - w.login() - - -pbportno = 8787 - -class MyOptions(usage.Options): - optParameters=[("user", "u", "guest", "username"), - ("password", "w", "guest"), - ("service", "s", "twisted.manhole", "PB Service"), - ("host", "h", "localhost"), - ("port", "p", str(pbportno)), - ("perspective", "P", "", - "PB Perspective to ask for " - "(if different than username)")] - - compData = usage.Completions( - optActions={"host": usage.CompleteHostnames(), - "user": usage.CompleteUsernames()} - ) - -if __name__ == '__main__': - run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/tap2deb.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/tap2deb.py deleted file mode 100644 index ee6e689..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/tap2deb.py +++ /dev/null @@ -1,304 +0,0 @@ -# -*- test-case-name: twisted.scripts.test.test_tap2deb -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -tap2deb creates Debian packages which wrap .tap files. -""" - -import os -import sys -import shutil -import subprocess -import warnings -from email.utils import formatdate as now - -from twisted.python import usage -from twisted.python.filepath import FilePath - -warnings.warn("tap2deb is deprecated since Twisted 15.2.", - category=DeprecationWarning, stacklevel=2) - - -class MyOptions(usage.Options): - optFlags = [["unsigned", "u"]] - optParameters = [["tapfile", "t", "twistd.tap"], - ["maintainer", "m", "", - "The maintainer's name and email in a specific format: " - "'John Doe '"], - ["protocol", "p", ""], - ["description", "e", ""], - ["long_description", "l", ""], - ["set-version", "V", "1.0"], - ["debfile", "d", None], - ["type", "y", "tap", "Type of configuration: 'tap', 'xml', " - "'source' or 'python' for .tac files"]] - - compData = usage.Completions( - optActions={ - "type": usage.CompleteList(["tap", "xml", "source", "python"]), - "debfile": usage.CompleteFiles("*.deb")} - ) - - def postOptions(self): - if not self["maintainer"]: - raise usage.UsageError("maintainer must be specified.") - - -type_dict = { - 'tap': 'file', - 'python': 'python', - 'source': 'source', - 'xml': 'xml', -} - - - -def run(args=None): - """ - Parses the configuration options in C{args} and runs C{dpkg-buildpackage} - to create a .deb file. - - @param args: List of strings representing the C{tap2deb} configuration - options. - @type args: L{list} - """ - try: - config = MyOptions() - config.parseOptions(args) - except usage.error as ue: - sys.exit("%s: %s" % (sys.argv[0], ue)) - - tapFile = config['tapfile'] - baseTapFile = os.path.basename(config['tapfile']) - protocol = (config['protocol'] or os.path.splitext(baseTapFile)[0]) - debFile = config['debfile'] or 'twisted-' + protocol - version = config['set-version'] - maintainer = config['maintainer'] - description = config['description'] or ( - 'A Twisted-based server for %(protocol)s' % vars()) - longDescription = config['long_description'] or\ - 'Automatically created by tap2deb' - twistdOption = type_dict[config['type']] - date = now() - directory = debFile + '-' + version - pythonVersion = '%s.%s' % sys.version_info[:2] - buildDir = FilePath('.build').child(directory) - - if buildDir.exists(): - buildDir.remove() - - debianDir = buildDir.child('debian') - debianDir.child('source').makedirs() - shutil.copy(tapFile, buildDir.path) - - debianDir.child('README.Debian').setContent( - '''This package was auto-generated by tap2deb\n''') - - debianDir.child('conffiles').setContent( - '''\ -/etc/init.d/%(debFile)s -/etc/default/%(debFile)s -/etc/%(baseTapFile)s -''' % vars()) - - debianDir.child('default').setContent( - '''\ -pidfile=/var/run/%(debFile)s.pid -rundir=/var/lib/%(debFile)s/ -file=/etc/%(tapFile)s -logfile=/var/log/%(debFile)s.log - ''' % vars()) - - debianDir.child('init.d').setContent( - '''\ -#!/bin/sh - -PATH=/sbin:/bin:/usr/sbin:/usr/bin - -pidfile=/var/run/%(debFile)s.pid \ -rundir=/var/lib/%(debFile)s/ \ -file=/etc/%(tapFile)s \ -logfile=/var/log/%(debFile)s.log - -[ -r /etc/default/%(debFile)s ] && . /etc/default/%(debFile)s - -test -x /usr/bin/twistd%(pythonVersion)s || exit 0 -test -r $file || exit 0 -test -r /usr/share/%(debFile)s/package-installed || exit 0 - - -case "$1" in - start) - echo -n "Starting %(debFile)s: twistd" - start-stop-daemon --start --quiet --exec /usr/bin/twistd%(pythonVersion)s -- \ - --pidfile=$pidfile \ - --rundir=$rundir \ - --%(twistdOption)s=$file \ - --logfile=$logfile - echo "." - ;; - - stop) - echo -n "Stopping %(debFile)s: twistd" - start-stop-daemon --stop --quiet \ - --pidfile $pidfile - echo "." - ;; - - restart) - $0 stop - $0 start - ;; - - force-reload) - $0 restart - ;; - - *) - echo "Usage: /etc/init.d/%(debFile)s {start|stop|restart|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 -''' % vars()) - - debianDir.child('init.d').chmod(0755) - - debianDir.child('postinst').setContent( - '''\ -#!/bin/sh -update-rc.d %(debFile)s defaults >/dev/null -invoke-rc.d %(debFile)s start -''' % vars()) - - debianDir.child('prerm').setContent( - '''\ -#!/bin/sh -invoke-rc.d %(debFile)s stop -''' % vars()) - - debianDir.child('postrm').setContent( - '''\ -#!/bin/sh -if [ "$1" = purge ]; then - update-rc.d %(debFile)s remove >/dev/null -fi -''' % vars()) - - debianDir.child('changelog').setContent( - '''\ -%(debFile)s (%(version)s) unstable; urgency=low - - * Created by tap2deb - - -- %(maintainer)s %(date)s - -''' % vars()) - - debianDir.child('control').setContent( - '''\ -Source: %(debFile)s -Section: net -Priority: extra -Maintainer: %(maintainer)s -Build-Depends-Indep: debhelper -Standards-Version: 3.5.6 - -Package: %(debFile)s -Architecture: all -Depends: python%(pythonVersion)s-twisted -Description: %(description)s - %(longDescription)s -''' % vars()) - - debianDir.child('copyright').setContent( - '''\ -This package was auto-debianized by %(maintainer)s on -%(date)s - -It was auto-generated by tap2deb - -Upstream Author(s): -Moshe Zadka -- tap2deb author - -Copyright: - -Insert copyright here. -''' % vars()) - - debianDir.child('dirs').setContent( - '''\ -etc/init.d -etc/default -var/lib/%(debFile)s -usr/share/doc/%(debFile)s -usr/share/%(debFile)s -''' % vars()) - - debianDir.child('rules').setContent( - '''\ -#!/usr/bin/make -f - -export DH_COMPAT=1 - -build: build-stamp -build-stamp: - dh_testdir - touch build-stamp - -clean: - dh_testdir - dh_testroot - rm -f build-stamp install-stamp - dh_clean - -install: install-stamp -install-stamp: build-stamp - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - # Add here commands to install the package into debian/tmp. - cp %(baseTapFile)s debian/tmp/etc/ - cp debian/init.d debian/tmp/etc/init.d/%(debFile)s - cp debian/default debian/tmp/etc/default/%(debFile)s - cp debian/copyright debian/tmp/usr/share/doc/%(debFile)s/ - cp debian/README.Debian debian/tmp/usr/share/doc/%(debFile)s/ - touch debian/tmp/usr/share/%(debFile)s/package-installed - touch install-stamp - -binary-arch: build install - -binary-indep: build install - dh_testdir - dh_testroot - dh_strip - dh_compress - dh_installchangelogs - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -source diff: - @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install -''' % vars()) - - debianDir.child('rules').chmod(0755) - - args = ["dpkg-buildpackage", "-rfakeroot"] - if config['unsigned']: - args = args + ['-uc', '-us'] - - # Build deb - job = subprocess.Popen(args, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, cwd=buildDir.path) - stdout, _ = job.communicate() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/tap2rpm.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/tap2rpm.py deleted file mode 100755 index 0e66932..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/tap2rpm.py +++ /dev/null @@ -1,333 +0,0 @@ -# -*- test-case-name: twisted.scripts.test.test_tap2rpm -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys, os, shutil, time, glob -import subprocess -import tempfile -import tarfile -from StringIO import StringIO -import warnings - -from twisted.python import usage, log, versions, deprecate - -warnings.warn("tap2rpm is deprecated since Twisted 15.2.", - category=DeprecationWarning, stacklevel=2) - -################################# -# data that goes in /etc/inittab -initFileData = '''\ -#!/bin/sh -# -# Startup script for a Twisted service. -# -# chkconfig: - 85 15 -# description: Start-up script for the Twisted service "%(tap_file)s". - -PATH=/usr/bin:/bin:/usr/sbin:/sbin - -pidfile=/var/run/%(rpm_file)s.pid -rundir=/var/lib/twisted-taps/%(rpm_file)s/ -file=/etc/twisted-taps/%(tap_file)s -logfile=/var/log/%(rpm_file)s.log - -# load init function library -. /etc/init.d/functions - -[ -r /etc/default/%(rpm_file)s ] && . /etc/default/%(rpm_file)s - -# check for required files -if [ ! -x /usr/bin/twistd ] -then - echo "$0: Aborting, no /usr/bin/twistd found" - exit 0 -fi -if [ ! -r "$file" ] -then - echo "$0: Aborting, no file $file found." - exit 0 -fi - -# set up run directory if necessary -if [ ! -d "${rundir}" ] -then - mkdir -p "${rundir}" -fi - - -case "$1" in - start) - echo -n "Starting %(rpm_file)s: twistd" - daemon twistd \\ - --pidfile=$pidfile \\ - --rundir=$rundir \\ - --%(twistd_option)s=$file \\ - --logfile=$logfile - status %(rpm_file)s - ;; - - stop) - echo -n "Stopping %(rpm_file)s: twistd" - kill `cat "${pidfile}"` - status %(rpm_file)s - ;; - - restart) - "${0}" stop - "${0}" start - ;; - - *) - echo "Usage: ${0} {start|stop|restart|}" >&2 - exit 1 - ;; -esac - -exit 0 -''' - -####################################### -# the data for creating the spec file -specFileData = '''\ -Summary: %(description)s -Name: %(rpm_file)s -Version: %(version)s -Release: 1 -License: Unknown -Group: Networking/Daemons -Source: %(tarfile_basename)s -BuildRoot: %%{_tmppath}/%%{name}-%%{version}-root -Requires: /usr/bin/twistd -BuildArch: noarch - -%%description -%(long_description)s - -%%prep -%%setup -%%build - -%%install -[ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \ - && rm -rf "$RPM_BUILD_ROOT" -mkdir -p "$RPM_BUILD_ROOT"/etc/twisted-taps -mkdir -p "$RPM_BUILD_ROOT"/etc/init.d -mkdir -p "$RPM_BUILD_ROOT"/var/lib/twisted-taps -cp "%(tap_file)s" "$RPM_BUILD_ROOT"/etc/twisted-taps/ -cp "%(rpm_file)s.init" "$RPM_BUILD_ROOT"/etc/init.d/"%(rpm_file)s" - -%%clean -[ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \ - && rm -rf "$RPM_BUILD_ROOT" - -%%post -/sbin/chkconfig --add %(rpm_file)s -/sbin/chkconfig --level 35 %(rpm_file)s -/etc/init.d/%(rpm_file)s start - -%%preun -/etc/init.d/%(rpm_file)s stop -/sbin/chkconfig --del %(rpm_file)s - -%%files -%%defattr(-,root,root) -%%attr(0755,root,root) /etc/init.d/%(rpm_file)s -%%attr(0660,root,root) /etc/twisted-taps/%(tap_file)s - -%%changelog -* %(date)s %(maintainer)s -- Created by tap2rpm: %(rpm_file)s (%(version)s) -''' - -############################### -class MyOptions(usage.Options): - optFlags = [['quiet', 'q']] - optParameters = [ - ["tapfile", "t", "twistd.tap"], - ["maintainer", "m", "tap2rpm"], - ["protocol", "p", None], - ["description", "e", None], - ["long_description", "l", - "Automatically created by tap2rpm"], - ["set-version", "V", "1.0"], - ["rpmfile", "r", None], - ["type", "y", "tap", "type of configuration: 'tap', 'xml, " - "'source' or 'python'"], - ] - - compData = usage.Completions( - optActions={"type": usage.CompleteList(["tap", "xml", "source", - "python"]), - "rpmfile": usage.CompleteFiles("*.rpm")} - ) - - def postOptions(self): - """ - Calculate the default values for certain command-line options. - """ - # Options whose defaults depend on other parameters. - if self['protocol'] is None: - base_tapfile = os.path.basename(self['tapfile']) - self['protocol'] = os.path.splitext(base_tapfile)[0] - if self['description'] is None: - self['description'] = "A TCP server for %s" % (self['protocol'],) - if self['rpmfile'] is None: - self['rpmfile'] = 'twisted-%s' % (self['protocol'],) - - # Values that aren't options, but are calculated from options and are - # handy to have around. - self['twistd_option'] = type_dict[self['type']] - self['release-name'] = '%s-%s' % (self['rpmfile'], self['set-version']) - - - def opt_unsigned(self): - """ - Generate an unsigned rather than a signed RPM. (DEPRECATED; unsigned - is the default) - """ - msg = deprecate.getDeprecationWarningString( - self.opt_unsigned, versions.Version("Twisted", 12, 1, 0)) - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - - # Maintain the -u short flag - opt_u = opt_unsigned - - -type_dict = { - 'tap': 'file', - 'python': 'python', - 'source': 'source', - 'xml': 'xml', -} - - - -########################## -def makeBuildDir(): - """ - Set up the temporary directory for building RPMs. - - Returns: buildDir, a randomly-named subdirectory of baseDir. - """ - tmpDir = tempfile.mkdtemp() - # set up initial directory contents - os.makedirs(os.path.join(tmpDir, 'RPMS', 'noarch')) - os.makedirs(os.path.join(tmpDir, 'SPECS')) - os.makedirs(os.path.join(tmpDir, 'BUILD')) - os.makedirs(os.path.join(tmpDir, 'SOURCES')) - os.makedirs(os.path.join(tmpDir, 'SRPMS')) - - log.msg(format="Created RPM build structure in %(path)r", - path=tmpDir) - return tmpDir - - - -def setupBuildFiles(buildDir, config): - """ - Create files required to build an RPM in the build directory. - """ - # Create the source tarball in the SOURCES directory. - tarballName = "%s.tar" % (config['release-name'],) - tarballPath = os.path.join(buildDir, "SOURCES", tarballName) - tarballHandle = tarfile.open(tarballPath, "w") - - sourceDirInfo = tarfile.TarInfo(config['release-name']) - sourceDirInfo.type = tarfile.DIRTYPE - sourceDirInfo.mode = 0755 - tarballHandle.addfile(sourceDirInfo) - - tapFileBase = os.path.basename(config['tapfile']) - - initFileInfo = tarfile.TarInfo( - os.path.join( - config['release-name'], - '%s.init' % config['rpmfile'], - ) - ) - initFileInfo.type = tarfile.REGTYPE - initFileInfo.mode = 0755 - initFileRealData = initFileData % { - 'tap_file': tapFileBase, - 'rpm_file': config['release-name'], - 'twistd_option': config['twistd_option'], - } - initFileInfo.size = len(initFileRealData) - tarballHandle.addfile(initFileInfo, StringIO(initFileRealData)) - - tapFileHandle = open(config['tapfile'], 'rb') - tapFileInfo = tarballHandle.gettarinfo( - arcname=os.path.join(config['release-name'], tapFileBase), - fileobj=tapFileHandle, - ) - tapFileInfo.mode = 0644 - tarballHandle.addfile(tapFileInfo, tapFileHandle) - - tarballHandle.close() - - log.msg(format="Created dummy source tarball %(tarballPath)r", - tarballPath=tarballPath) - - # Create the spec file in the SPECS directory. - specName = "%s.spec" % (config['release-name'],) - specPath = os.path.join(buildDir, "SPECS", specName) - specHandle = open(specPath, "w") - specFileRealData = specFileData % { - 'description': config['description'], - 'rpm_file': config['rpmfile'], - 'version': config['set-version'], - 'tarfile_basename': tarballName, - 'tap_file': tapFileBase, - 'date': time.strftime('%a %b %d %Y', time.localtime(time.time())), - 'maintainer': config['maintainer'], - 'long_description': config['long_description'], - } - specHandle.write(specFileRealData) - specHandle.close() - - log.msg(format="Created RPM spec file %(specPath)r", - specPath=specPath) - - return specPath - - - -def run(options=None): - # parse options - try: - config = MyOptions() - config.parseOptions(options) - except usage.error, ue: - sys.exit("%s: %s" % (sys.argv[0], ue)) - - # create RPM build environment - tmpDir = makeBuildDir() - specPath = setupBuildFiles(tmpDir, config) - - # build rpm - job = subprocess.Popen([ - "rpmbuild", - "-vv", - "--define", "_topdir %s" % (tmpDir,), - "-ba", specPath, - ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - stdout, _ = job.communicate() - - # If there was a problem, show people what it was. - if job.returncode != 0: - print stdout - - # copy the RPMs to the local directory - rpmPath = glob.glob(os.path.join(tmpDir, 'RPMS', 'noarch', '*'))[0] - srpmPath = glob.glob(os.path.join(tmpDir, 'SRPMS', '*'))[0] - if not config['quiet']: - print 'Writing "%s"...' % os.path.basename(rpmPath) - shutil.copy(rpmPath, '.') - if not config['quiet']: - print 'Writing "%s"...' % os.path.basename(srpmPath) - shutil.copy(srpmPath, '.') - - # remove the build directory - shutil.rmtree(tmpDir) - - return [os.path.basename(rpmPath), os.path.basename(srpmPath)] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/__init__.py deleted file mode 100644 index c04ed1c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test package for L{twisted.scripts}. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_scripts.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_scripts.py deleted file mode 100644 index 59343e7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_scripts.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for the command-line scripts in the top-level I{bin/} directory. - -Tests for actual functionality belong elsewhere, written in a way that doesn't -involve launching child processes. -""" - -from os import devnull, getcwd, chdir -from sys import executable -from subprocess import PIPE, Popen - -from twisted.trial.unittest import SkipTest, TestCase -from twisted.python import reflect -from twisted.python.modules import getModule -from twisted.python.filepath import FilePath -from twisted.python.test.test_shellcomp import ZshScriptTestMixin - - - -def outputFromPythonScript(script, *args): - """ - Synchronously run a Python script, with the same Python interpreter that - ran the process calling this function, using L{Popen}, using the given - command-line arguments, with standard input and standard error both - redirected to L{os.devnull}, and return its output as a string. - - @param script: The path to the script. - @type script: L{FilePath} - - @param args: The command-line arguments to follow the script in its - invocation (the desired C{sys.argv[1:]}). - @type args: L{tuple} of L{str} - - @return: the output passed to the proces's C{stdout}, without any messages - from C{stderr}. - @rtype: L{bytes} - """ - nullInput = file(devnull, "rb") - nullError = file(devnull, "wb") - stdout = Popen([executable, script.path] + list(args), - stdout=PIPE, stderr=nullError, stdin=nullInput).stdout.read() - nullInput.close() - nullError.close() - return stdout - - - -class ScriptTestsMixin: - """ - Mixin for L{TestCase} subclasses which defines a helper function for testing - a Twisted-using script. - """ - bin = getModule("twisted").pathEntry.filePath.child("bin") - - def scriptTest(self, name): - """ - Verify that the given script runs and uses the version of Twisted - currently being tested. - - This only works when running tests against a vcs checkout of Twisted, - since it relies on the scripts being in the place they are kept in - version control, and exercises their logic for finding the right version - of Twisted to use in that situation. - - @param name: A path fragment, relative to the I{bin} directory of a - Twisted source checkout, identifying a script to test. - @type name: C{str} - - @raise SkipTest: if the script is not where it is expected to be. - """ - script = self.bin.preauthChild(name) - if not script.exists(): - raise SkipTest( - "Script tests do not apply to installed configuration.") - - from twisted.copyright import version - scriptVersion = outputFromPythonScript(script, '--version') - - self.assertIn(str(version), scriptVersion) - - - -class ScriptTests(TestCase, ScriptTestsMixin): - """ - Tests for the core scripts. - """ - def test_twistd(self): - self.scriptTest("twistd") - - - def test_twistdPathInsert(self): - """ - The twistd script adds the current working directory to sys.path so - that it's able to import modules from it. - """ - script = self.bin.child("twistd") - if not script.exists(): - raise SkipTest( - "Script tests do not apply to installed configuration.") - cwd = getcwd() - self.addCleanup(chdir, cwd) - testDir = FilePath(self.mktemp()) - testDir.makedirs() - chdir(testDir.path) - testDir.child("bar.tac").setContent( - "import sys\n" - "print sys.path\n") - output = outputFromPythonScript(script, '-ny', 'bar.tac') - self.assertIn(repr(testDir.path), output) - - - def test_manhole(self): - self.scriptTest("manhole") - - - def test_trial(self): - self.scriptTest("trial") - - - def test_trialPathInsert(self): - """ - The trial script adds the current working directory to sys.path so that - it's able to import modules from it. - """ - script = self.bin.child("trial") - if not script.exists(): - raise SkipTest( - "Script tests do not apply to installed configuration.") - cwd = getcwd() - self.addCleanup(chdir, cwd) - testDir = FilePath(self.mktemp()) - testDir.makedirs() - chdir(testDir.path) - testDir.child("foo.py").setContent("") - output = outputFromPythonScript(script, 'foo') - self.assertIn("PASSED", output) - - - def test_pyhtmlizer(self): - self.scriptTest("pyhtmlizer") - - - def test_tap2rpm(self): - self.scriptTest("tap2rpm") - - - def test_tap2deb(self): - self.scriptTest("tap2deb") - - - -class ZshIntegrationTests(TestCase, ZshScriptTestMixin): - """ - Test that zsh completion functions are generated without error - """ - generateFor = [('twistd', 'twisted.scripts.twistd.ServerOptions'), - ('trial', 'twisted.scripts.trial.Options'), - ('pyhtmlizer', 'twisted.scripts.htmlizer.Options'), - ('tap2rpm', 'twisted.scripts.tap2rpm.MyOptions'), - ('tap2deb', 'twisted.scripts.tap2deb.MyOptions'), - ('manhole', 'twisted.scripts.manhole.MyOptions') - ] - - - -class Tap2DeprecationTests(TestCase): - """ - Contains tests to make sure tap2deb/tap2rpm are marked as deprecated. - """ - def test_tap2debDeprecation(self): - """ - L{twisted.scripts.tap2deb} is deprecated since Twisted 15.2. - """ - reload(reflect.namedAny("twisted.scripts.tap2deb")) - warningsShown = self.flushWarnings() - self.assertEqual(1, len(warningsShown)) - self.assertEqual( - "tap2deb is deprecated since Twisted 15.2.", - warningsShown[0]['message']) - - - def test_tap2rpmDeprecation(self): - """ - L{twisted.scripts.tap2rpm} is deprecated since Twisted 15.2. - """ - reload(reflect.namedAny("twisted.scripts.tap2rpm")) - warningsShown = self.flushWarnings() - self.assertEqual(1, len(warningsShown)) - self.assertEqual( - "tap2rpm is deprecated since Twisted 15.2.", - warningsShown[0]['message']) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_tap2deb.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_tap2deb.py deleted file mode 100644 index 14e79ce..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_tap2deb.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.scripts.tap2deb}. -""" - -from twisted.scripts import tap2deb -from twisted.python import usage, procutils -from twisted.python.filepath import FilePath - -from twisted.trial.unittest import TestCase, SkipTest - - - -class TestTap2DEB(TestCase): - """ - Tests for the L{tap2deb} script. - """ - maintainer = "Jane Doe " - - def test_maintainerOption(self): - """ - The C{--maintainer} option must be specified on the commandline or - passed to L{tap2deb.run}. - """ - config = tap2deb.MyOptions() - self.assertRaises(usage.UsageError, config.parseOptions, []) - self.assertRaises(SystemExit, tap2deb.run, []) - - - def test_optionDefaults(self): - """ - Commandline options default to sensible values. - """ - config = tap2deb.MyOptions() - config.parseOptions(['--maintainer', self.maintainer]) - - self.assertEqual(config['tapfile'], 'twistd.tap') - self.assertEqual(config['maintainer'], self.maintainer) - self.assertEqual(config['protocol'], '') - self.assertEqual(config['description'], '') - self.assertEqual(config['long_description'], '') - self.assertEqual(config['set-version'], '1.0') - self.assertEqual(config['debfile'], None) - self.assertEqual(config['type'], 'tap') - - - def test_missingMaintainer(self): - """ - Omitting the maintainer argument results in L{tap2deb.run} raising - C{SystemExit}. - """ - error = self.assertRaises(SystemExit, tap2deb.run, - ["--tapfile", "foo"]) - self.assertTrue(str(error).endswith('maintainer must be specified.')) - - - def test_basicOperation(self): - """ - Running the L{tap2deb} script produces a bunch of files using - C{dpkg-buildpackage}. - """ - # Skip tests if dpkg-buildpackage is not present - if not procutils.which("dpkg-buildpackage"): - raise SkipTest("dpkg-buildpackage must be present to test tap2deb") - - baseDir = FilePath(self.mktemp()) - baseDir.makedirs() - - # Make a temporary .tap file - version = '1.0' - tapName = 'lemon' - tapFile = baseDir.child("%s.tap" % (tapName,)) - tapFile.setContent("# Dummy .tap file") - - buildDir = FilePath('.build') - outputDir = buildDir.child('twisted-%s-%s' % (tapName, version)) - - # Run - args = ["--tapfile", tapFile.path, "--maintainer", self.maintainer] - tap2deb.run(args) - - # Verify input files were created - self.assertEqual(sorted(outputDir.listdir()), - ['build-stamp', 'debian', 'install-stamp', 'lemon.tap']) - - debianDir = outputDir.child('debian') - for name in ['README.Debian', 'conffiles', 'default', 'init.d', - 'postinst', 'prerm', 'postrm', 'changelog', 'control', - 'copyright', 'dirs', 'rules']: - self.assertTrue(debianDir.child(name).exists()) - - # Verify 4 output files were created - self.assertTrue(buildDir.child('twisted-lemon_1.0_all.deb').exists()) - self.assertTrue(buildDir.child('twisted-lemon_1.0.tar.gz').exists()) - self.assertTrue(buildDir.child('twisted-lemon_1.0.dsc').exists()) - self.assertEqual( - len(buildDir.globChildren('twisted-lemon_1.0_*.changes')), 1) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_tap2rpm.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_tap2rpm.py deleted file mode 100644 index 509e69c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/test/test_tap2rpm.py +++ /dev/null @@ -1,399 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.scripts.tap2rpm}. -""" -import os - -from twisted.trial.unittest import TestCase, SkipTest -from twisted.python import procutils -from twisted.python import versions -from twisted.python import deprecate -from twisted.python.failure import Failure -from twisted.internet import utils -from twisted.scripts import tap2rpm - -# When we query the RPM metadata, we get back a string we'll have to parse, so -# we'll use suitably rare delimiter characters to split on. Luckily, ASCII -# defines some for us! -RECORD_SEPARATOR = "\x1E" -UNIT_SEPARATOR = "\x1F" - - - -def _makeRPMs(tapfile=None, maintainer=None, protocol=None, description=None, - longDescription=None, setVersion=None, rpmfile=None, type_=None): - """ - Helper function to invoke tap2rpm with the given parameters. - """ - args = [] - - if not tapfile: - tapfile = "dummy-tap-file" - handle = open(tapfile, "w") - handle.write("# Dummy TAP file\n") - handle.close() - - args.extend(["--quiet", "--tapfile", tapfile]) - - if maintainer: - args.extend(["--maintainer", maintainer]) - if protocol: - args.extend(["--protocol", protocol]) - if description: - args.extend(["--description", description]) - if longDescription: - args.extend(["--long_description", longDescription]) - if setVersion: - args.extend(["--set-version", setVersion]) - if rpmfile: - args.extend(["--rpmfile", rpmfile]) - if type_: - args.extend(["--type", type_]) - - return tap2rpm.run(args) - - - -def _queryRPMTags(rpmfile, taglist): - """ - Helper function to read the given header tags from the given RPM file. - - Returns a Deferred that fires with dictionary mapping a tag name to a list - of the associated values in the RPM header. If a tag has only a single - value in the header (like NAME or VERSION), it will be returned as a 1-item - list. - - Run "rpm --querytags" to see what tags can be queried. - """ - - # Build a query format string that will return appropriately delimited - # results. Every field is treated as an array field, so single-value tags - # like VERSION will be returned as 1-item lists. - queryFormat = RECORD_SEPARATOR.join([ - "[%%{%s}%s]" % (tag, UNIT_SEPARATOR) for tag in taglist - ]) - - def parseTagValues(output): - res = {} - - for tag, values in zip(taglist, output.split(RECORD_SEPARATOR)): - values = values.strip(UNIT_SEPARATOR).split(UNIT_SEPARATOR) - res[tag] = values - - return res - - def checkErrorResult(failure): - # The current rpm packages on Debian and Ubuntu don't properly set up - # the RPM database, which causes rpm to print a harmless warning to - # stderr. Unfortunately, .getProcessOutput() assumes all warnings are - # catastrophic and panics whenever it sees one. - # - # See also: - # http://twistedmatrix.com/trac/ticket/3292#comment:42 - # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=551669 - # http://rpm.org/ticket/106 - - failure.trap(IOError) - - # Depending on kernel scheduling, we might read the whole error - # message, or only the first few bytes. - if str(failure.value).startswith("got stderr: 'error: "): - newFailure = Failure(SkipTest("rpm is missing its package " - "database. Run 'sudo rpm -qa > /dev/null' to create one.")) - else: - # Not the exception we were looking for; we should report the - # original failure. - newFailure = failure - - # We don't want to raise the exception right away; we want to wait for - # the process to exit, otherwise we'll get extra useless errors - # reported. - d = failure.value.processEnded - d.addBoth(lambda _: newFailure) - return d - - d = utils.getProcessOutput("rpm", - ("-q", "--queryformat", queryFormat, "-p", rpmfile)) - d.addCallbacks(parseTagValues, checkErrorResult) - return d - - - -class TestTap2RPM(TestCase): - - - def setUp(self): - return self._checkForRpmbuild() - - - def _checkForRpmbuild(self): - """ - tap2rpm requires rpmbuild; skip tests if rpmbuild is not present. - """ - if not procutils.which("rpmbuild"): - raise SkipTest("rpmbuild must be present to test tap2rpm") - - - def _makeTapFile(self, basename="dummy"): - """ - Make a temporary .tap file and returns the absolute path. - """ - path = basename + ".tap" - handle = open(path, "w") - handle.write("# Dummy .tap file") - handle.close() - return path - - - def _verifyRPMTags(self, rpmfile, **tags): - """ - Check the given file has the given tags set to the given values. - """ - - d = _queryRPMTags(rpmfile, tags.keys()) - d.addCallback(self.assertEqual, tags) - return d - - - def test_optionDefaults(self): - """ - Commandline options should default to sensible values. - - "sensible" here is defined as "the same values that previous versions - defaulted to". - """ - config = tap2rpm.MyOptions() - config.parseOptions([]) - - self.assertEqual(config['tapfile'], 'twistd.tap') - self.assertEqual(config['maintainer'], 'tap2rpm') - self.assertEqual(config['protocol'], 'twistd') - self.assertEqual(config['description'], 'A TCP server for twistd') - self.assertEqual(config['long_description'], - 'Automatically created by tap2rpm') - self.assertEqual(config['set-version'], '1.0') - self.assertEqual(config['rpmfile'], 'twisted-twistd') - self.assertEqual(config['type'], 'tap') - self.assertEqual(config['quiet'], False) - self.assertEqual(config['twistd_option'], 'file') - self.assertEqual(config['release-name'], 'twisted-twistd-1.0') - - - def test_protocolCalculatedFromTapFile(self): - """ - The protocol name defaults to a value based on the tapfile value. - """ - config = tap2rpm.MyOptions() - config.parseOptions(['--tapfile', 'pancakes.tap']) - - self.assertEqual(config['tapfile'], 'pancakes.tap') - self.assertEqual(config['protocol'], 'pancakes') - - - def test_optionsDefaultToProtocolValue(self): - """ - Many options default to a value calculated from the protocol name. - """ - config = tap2rpm.MyOptions() - config.parseOptions([ - '--tapfile', 'sausages.tap', - '--protocol', 'eggs', - ]) - - self.assertEqual(config['tapfile'], 'sausages.tap') - self.assertEqual(config['maintainer'], 'tap2rpm') - self.assertEqual(config['protocol'], 'eggs') - self.assertEqual(config['description'], 'A TCP server for eggs') - self.assertEqual(config['long_description'], - 'Automatically created by tap2rpm') - self.assertEqual(config['set-version'], '1.0') - self.assertEqual(config['rpmfile'], 'twisted-eggs') - self.assertEqual(config['type'], 'tap') - self.assertEqual(config['quiet'], False) - self.assertEqual(config['twistd_option'], 'file') - self.assertEqual(config['release-name'], 'twisted-eggs-1.0') - - - def test_releaseNameDefaultsToRpmfileValue(self): - """ - The release-name option is calculated from rpmfile and set-version. - """ - config = tap2rpm.MyOptions() - config.parseOptions([ - "--rpmfile", "beans", - "--set-version", "1.2.3", - ]) - - self.assertEqual(config['release-name'], 'beans-1.2.3') - - - def test_basicOperation(self): - """ - Calling tap2rpm should produce an RPM and SRPM with default metadata. - """ - basename = "frenchtoast" - - # Create RPMs based on a TAP file with this name. - rpm, srpm = _makeRPMs(tapfile=self._makeTapFile(basename)) - - # Verify the resulting RPMs have the correct tags. - d = self._verifyRPMTags(rpm, - NAME=["twisted-%s" % (basename,)], - VERSION=["1.0"], - RELEASE=["1"], - SUMMARY=["A TCP server for %s" % (basename,)], - DESCRIPTION=["Automatically created by tap2rpm"], - ) - d.addCallback(lambda _: self._verifyRPMTags(srpm, - NAME=["twisted-%s" % (basename,)], - VERSION=["1.0"], - RELEASE=["1"], - SUMMARY=["A TCP server for %s" % (basename,)], - DESCRIPTION=["Automatically created by tap2rpm"], - )) - - return d - - - def test_protocolOverride(self): - """ - Setting 'protocol' should change the name of the resulting package. - """ - basename = "acorn" - protocol = "banana" - - # Create RPMs based on a TAP file with this name. - rpm, srpm = _makeRPMs(tapfile=self._makeTapFile(basename), - protocol=protocol) - - # Verify the resulting RPMs have the correct tags. - d = self._verifyRPMTags(rpm, - NAME=["twisted-%s" % (protocol,)], - SUMMARY=["A TCP server for %s" % (protocol,)], - ) - d.addCallback(lambda _: self._verifyRPMTags(srpm, - NAME=["twisted-%s" % (protocol,)], - SUMMARY=["A TCP server for %s" % (protocol,)], - )) - - return d - - - def test_rpmfileOverride(self): - """ - Setting 'rpmfile' should change the name of the resulting package. - """ - basename = "cherry" - rpmfile = "donut" - - # Create RPMs based on a TAP file with this name. - rpm, srpm = _makeRPMs(tapfile=self._makeTapFile(basename), - rpmfile=rpmfile) - - # Verify the resulting RPMs have the correct tags. - d = self._verifyRPMTags(rpm, - NAME=[rpmfile], - SUMMARY=["A TCP server for %s" % (basename,)], - ) - d.addCallback(lambda _: self._verifyRPMTags(srpm, - NAME=[rpmfile], - SUMMARY=["A TCP server for %s" % (basename,)], - )) - - return d - - - def test_descriptionOverride(self): - """ - Setting 'description' should change the SUMMARY tag. - """ - description = "eggplant" - - # Create RPMs based on a TAP file with this name. - rpm, srpm = _makeRPMs(tapfile=self._makeTapFile(), - description=description) - - # Verify the resulting RPMs have the correct tags. - d = self._verifyRPMTags(rpm, - SUMMARY=[description], - ) - d.addCallback(lambda _: self._verifyRPMTags(srpm, - SUMMARY=[description], - )) - - return d - - - def test_longDescriptionOverride(self): - """ - Setting 'longDescription' should change the DESCRIPTION tag. - """ - longDescription = "fig" - - # Create RPMs based on a TAP file with this name. - rpm, srpm = _makeRPMs(tapfile=self._makeTapFile(), - longDescription=longDescription) - - # Verify the resulting RPMs have the correct tags. - d = self._verifyRPMTags(rpm, - DESCRIPTION=[longDescription], - ) - d.addCallback(lambda _: self._verifyRPMTags(srpm, - DESCRIPTION=[longDescription], - )) - - return d - - - def test_setVersionOverride(self): - """ - Setting 'setVersion' should change the RPM's version info. - """ - version = "123.456" - - # Create RPMs based on a TAP file with this name. - rpm, srpm = _makeRPMs(tapfile=self._makeTapFile(), - setVersion=version) - - # Verify the resulting RPMs have the correct tags. - d = self._verifyRPMTags(rpm, - VERSION=["123.456"], - RELEASE=["1"], - ) - d.addCallback(lambda _: self._verifyRPMTags(srpm, - VERSION=["123.456"], - RELEASE=["1"], - )) - - return d - - - def test_tapInOtherDirectory(self): - """ - tap2rpm handles tapfiles outside the current directory. - """ - # Make a tapfile outside the current directory. - tempdir = self.mktemp() - os.mkdir(tempdir) - tapfile = self._makeTapFile(os.path.join(tempdir, "bacon")) - - # Try and make an RPM from that tapfile. - _makeRPMs(tapfile=tapfile) - - - def test_unsignedFlagDeprecationWarning(self): - """ - The 'unsigned' flag in tap2rpm should be deprecated, and its use - should raise a warning as such. - """ - config = tap2rpm.MyOptions() - config.parseOptions(['--unsigned']) - warnings = self.flushWarnings() - self.assertEqual(DeprecationWarning, warnings[0]['category']) - self.assertEqual( - deprecate.getDeprecationWarningString( - config.opt_unsigned, versions.Version("Twisted", 12, 1, 0)), - warnings[0]['message']) - self.assertEqual(1, len(warnings)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/trial.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/trial.py deleted file mode 100644 index 0609084..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/trial.py +++ /dev/null @@ -1,622 +0,0 @@ -# -*- test-case-name: twisted.trial.test.test_script -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import print_function -import gc -import inspect -import os -import pdb -import random -import sys -import time -import warnings - -from twisted.internet import defer -from twisted.application import app -from twisted.python import usage, reflect, failure -from twisted.python.filepath import FilePath -from twisted.python.reflect import namedModule -from twisted import plugin -from twisted.python.util import spewer -from twisted.trial import runner, itrial, reporter - - -# Yea, this is stupid. Leave it for command-line compatibility for a -# while, though. -TBFORMAT_MAP = { - 'plain': 'default', - 'default': 'default', - 'emacs': 'brief', - 'brief': 'brief', - 'cgitb': 'verbose', - 'verbose': 'verbose' - } - - -def _parseLocalVariables(line): - """ - Accepts a single line in Emacs local variable declaration format and - returns a dict of all the variables {name: value}. - Raises ValueError if 'line' is in the wrong format. - - See http://www.gnu.org/software/emacs/manual/html_node/File-Variables.html - """ - paren = '-*-' - start = line.find(paren) + len(paren) - end = line.rfind(paren) - if start == -1 or end == -1: - raise ValueError("%r not a valid local variable declaration" % (line,)) - items = line[start:end].split(';') - localVars = {} - for item in items: - if len(item.strip()) == 0: - continue - split = item.split(':') - if len(split) != 2: - raise ValueError("%r contains invalid declaration %r" - % (line, item)) - localVars[split[0].strip()] = split[1].strip() - return localVars - - -def loadLocalVariables(filename): - """ - Accepts a filename and attempts to load the Emacs variable declarations - from that file, simulating what Emacs does. - - See http://www.gnu.org/software/emacs/manual/html_node/File-Variables.html - """ - f = file(filename, "r") - lines = [f.readline(), f.readline()] - f.close() - for line in lines: - try: - return _parseLocalVariables(line) - except ValueError: - pass - return {} - - -def getTestModules(filename): - testCaseVar = loadLocalVariables(filename).get('test-case-name', None) - if testCaseVar is None: - return [] - return testCaseVar.split(',') - - -def isTestFile(filename): - """ - Returns true if 'filename' looks like a file containing unit tests. - False otherwise. Doesn't care whether filename exists. - """ - basename = os.path.basename(filename) - return (basename.startswith('test_') - and os.path.splitext(basename)[1] == ('.py')) - - -def _reporterAction(): - return usage.CompleteList([p.longOpt for p in - plugin.getPlugins(itrial.IReporter)]) - - -def _maybeFindSourceLine(testThing): - """ - Try to find the source line of the given test thing. - - @param testThing: the test item to attempt to inspect - @type testThing: an L{TestCase}, test method, or module, though only the - former two have a chance to succeed - @rtype: int - @return: the starting source line, or -1 if one couldn't be found - """ - - # an instance of L{TestCase} -- locate the test it will run - method = getattr(testThing, "_testMethodName", None) - if method is not None: - testThing = getattr(testThing, method) - - # If it's a function, we can get the line number even if the source file no - # longer exists - code = getattr(testThing, "__code__", None) - if code is not None: - return code.co_firstlineno - - try: - return inspect.getsourcelines(testThing)[1] - except (IOError, TypeError): - # either testThing is a module, which raised a TypeError, or the file - # couldn't be read - return -1 - - -# orders which can be passed to trial --order -_runOrders = { - "alphabetical" : ( - "alphabetical order for test methods, arbitrary order for test cases", - runner.name), - "toptobottom" : ( - "attempt to run test cases and methods in the order they were defined", - _maybeFindSourceLine), -} - - -def _checkKnownRunOrder(order): - """ - Check that the given order is a known test running order. - - Does nothing else, since looking up the appropriate callable to sort the - tests should be done when it actually will be used, as the default argument - will not be coerced by this function. - - @param order: one of the known orders in C{_runOrders} - @return: the order unmodified - """ - if order not in _runOrders: - raise usage.UsageError( - "--order must be one of: %s. See --help-orders for details" % - (", ".join(repr(order) for order in _runOrders),)) - return order - - - -class _BasicOptions(object): - """ - Basic options shared between trial and its local workers. - """ - synopsis = """%s [options] [[file|package|module|TestCase|testmethod]...] - """ % (os.path.basename(sys.argv[0]),) - - longdesc = ("trial loads and executes a suite of unit tests, obtained " - "from modules, packages and files listed on the command line.") - - optFlags = [["help", "h"], - ["no-recurse", "N", "Don't recurse into packages"], - ['help-orders', None, "Help on available test running orders"], - ['help-reporters', None, - "Help on available output plugins (reporters)"], - ["rterrors", "e", "realtime errors, print out tracebacks as " - "soon as they occur"], - ["unclean-warnings", None, - "Turn dirty reactor errors into warnings"], - ["force-gc", None, "Have Trial run gc.collect() before and " - "after each test case."], - ["exitfirst", "x", - "Exit after the first non-successful result (cannot be " - "specified along with --jobs)."], - ] - - optParameters = [ - ["order", "o", None, - "Specify what order to run test cases and methods. " - "See --help-orders for more info.", _checkKnownRunOrder], - ["random", "z", None, - "Run tests in random order using the specified seed"], - ['temp-directory', None, '_trial_temp', - 'Path to use as working directory for tests.'], - ['reporter', None, 'verbose', - 'The reporter to use for this test run. See --help-reporters for ' - 'more info.']] - - compData = usage.Completions( - optActions={"order": usage.CompleteList(_runOrders), - "reporter": _reporterAction, - "logfile": usage.CompleteFiles(descr="log file name"), - "random": usage.Completer(descr="random seed")}, - extraActions=[usage.CompleteFiles( - "*.py", descr="file | module | package | TestCase | testMethod", - repeat=True)], - ) - - fallbackReporter = reporter.TreeReporter - tracer = None - - def __init__(self): - self['tests'] = [] - usage.Options.__init__(self) - - - def coverdir(self): - """ - Return a L{FilePath} representing the directory into which coverage - results should be written. - """ - coverdir = 'coverage' - result = FilePath(self['temp-directory']).child(coverdir) - print("Setting coverage directory to %s." % (result.path,)) - return result - - - # TODO: Some of the opt_* methods on this class have docstrings and some do - # not. This is mostly because usage.Options's currently will replace - # any intended output in optFlags and optParameters with the - # docstring. See #6427. When that is fixed, all methods should be - # given docstrings (and it should be verified that those with - # docstrings already have content suitable for printing as usage - # information). - - def opt_coverage(self): - """ - Generate coverage information in the coverage file in the - directory specified by the temp-directory option. - """ - import trace - self.tracer = trace.Trace(count=1, trace=0) - sys.settrace(self.tracer.globaltrace) - self['coverage'] = True - - - def opt_testmodule(self, filename): - """ - Filename to grep for test cases (-*- test-case-name). - """ - # If the filename passed to this parameter looks like a test module - # we just add that to the test suite. - # - # If not, we inspect it for an Emacs buffer local variable called - # 'test-case-name'. If that variable is declared, we try to add its - # value to the test suite as a module. - # - # This parameter allows automated processes (like Buildbot) to pass - # a list of files to Trial with the general expectation of "these files, - # whatever they are, will get tested" - if not os.path.isfile(filename): - sys.stderr.write("File %r doesn't exist\n" % (filename,)) - return - filename = os.path.abspath(filename) - if isTestFile(filename): - self['tests'].append(filename) - else: - self['tests'].extend(getTestModules(filename)) - - - def opt_spew(self): - """ - Print an insanely verbose log of everything that happens. Useful - when debugging freezes or locks in complex code. - """ - sys.settrace(spewer) - - - def opt_help_orders(self): - synopsis = ("Trial can attempt to run test cases and their methods in " - "a few different orders. You can select any of the " - "following options using --order=.\n") - - print(synopsis) - for name, (description, _) in sorted(_runOrders.items()): - print(' ', name, '\t', description) - sys.exit(0) - - - def opt_help_reporters(self): - synopsis = ("Trial's output can be customized using plugins called " - "Reporters. You can\nselect any of the following " - "reporters using --reporter=\n") - print(synopsis) - for p in plugin.getPlugins(itrial.IReporter): - print(' ', p.longOpt, '\t', p.description) - sys.exit(0) - - - def opt_disablegc(self): - """ - Disable the garbage collector - """ - self["disablegc"] = True - gc.disable() - - - def opt_tbformat(self, opt): - """ - Specify the format to display tracebacks with. Valid formats are - 'plain', 'emacs', and 'cgitb' which uses the nicely verbose stdlib - cgitb.text function - """ - try: - self['tbformat'] = TBFORMAT_MAP[opt] - except KeyError: - raise usage.UsageError( - "tbformat must be 'plain', 'emacs', or 'cgitb'.") - - - def opt_recursionlimit(self, arg): - """ - see sys.setrecursionlimit() - """ - try: - sys.setrecursionlimit(int(arg)) - except (TypeError, ValueError): - raise usage.UsageError( - "argument to recursionlimit must be an integer") - else: - self["recursionlimit"] = int(arg) - - - def opt_random(self, option): - try: - self['random'] = long(option) - except ValueError: - raise usage.UsageError( - "Argument to --random must be a positive integer") - else: - if self['random'] < 0: - raise usage.UsageError( - "Argument to --random must be a positive integer") - elif self['random'] == 0: - self['random'] = long(time.time() * 100) - - - def opt_without_module(self, option): - """ - Fake the lack of the specified modules, separated with commas. - """ - self["without-module"] = option - for module in option.split(","): - if module in sys.modules: - warnings.warn("Module '%s' already imported, " - "disabling anyway." % (module,), - category=RuntimeWarning) - sys.modules[module] = None - - - def parseArgs(self, *args): - self['tests'].extend(args) - - - def _loadReporterByName(self, name): - for p in plugin.getPlugins(itrial.IReporter): - qual = "%s.%s" % (p.module, p.klass) - if p.longOpt == name: - return reflect.namedAny(qual) - raise usage.UsageError("Only pass names of Reporter plugins to " - "--reporter. See --help-reporters for " - "more info.") - - - def postOptions(self): - # Only load reporters now, as opposed to any earlier, to avoid letting - # application-defined plugins muck up reactor selecting by importing - # t.i.reactor and causing the default to be installed. - self['reporter'] = self._loadReporterByName(self['reporter']) - if 'tbformat' not in self: - self['tbformat'] = 'default' - if self['order'] is not None and self['random'] is not None: - raise usage.UsageError( - "You can't specify --random when using --order") - - - -class Options(_BasicOptions, usage.Options, app.ReactorSelectionMixin): - """ - Options to the trial command line tool. - - @ivar _workerFlags: List of flags which are accepted by trial distributed - workers. This is used by C{_getWorkerArguments} to build the command - line arguments. - @type _workerFlags: C{list} - - @ivar _workerParameters: List of parameter which are accepted by trial - distrubuted workers. This is used by C{_getWorkerArguments} to build - the command line arguments. - @type _workerParameters: C{list} - """ - - optFlags = [ - ["debug", "b", "Run tests in a debugger. If that debugger is " - "pdb, will load '.pdbrc' from current directory if it exists." - ], - ["debug-stacktraces", "B", "Report Deferred creation and " - "callback stack traces"], - ["nopm", None, "don't automatically jump into debugger for " - "postmorteming of exceptions"], - ["dry-run", 'n', "do everything but run the tests"], - ["profile", None, "Run tests under the Python profiler"], - ["until-failure", "u", "Repeat test until it fails"], - ] - - optParameters = [ - ["debugger", None, "pdb", "the fully qualified name of a debugger to " - "use if --debug is passed"], - ["logfile", "l", "test.log", "log file name"], - ["jobs", "j", None, "Number of local workers to run"] - ] - - compData = usage.Completions( - optActions = { - "tbformat": usage.CompleteList(["plain", "emacs", "cgitb"]), - "reporter": _reporterAction, - }, - ) - - _workerFlags = ["disablegc", "force-gc", "coverage"] - _workerParameters = ["recursionlimit", "reactor", "without-module"] - - fallbackReporter = reporter.TreeReporter - extra = None - tracer = None - - - def opt_jobs(self, number): - """ - Number of local workers to run, a strictly positive integer. - """ - try: - number = int(number) - except ValueError: - raise usage.UsageError( - "Expecting integer argument to jobs, got '%s'" % number) - if number <= 0: - raise usage.UsageError( - "Argument to jobs must be a strictly positive integer") - self["jobs"] = number - - - def _getWorkerArguments(self): - """ - Return a list of options to pass to distributed workers. - """ - args = [] - for option in self._workerFlags: - if self.get(option) is not None: - if self[option]: - args.append("--%s" % (option,)) - for option in self._workerParameters: - if self.get(option) is not None: - args.extend(["--%s" % (option,), str(self[option])]) - return args - - - def postOptions(self): - _BasicOptions.postOptions(self) - if self['jobs']: - conflicts = ['debug', 'profile', 'debug-stacktraces', 'exitfirst'] - for option in conflicts: - if self[option]: - raise usage.UsageError( - "You can't specify --%s when using --jobs" % option) - if self['nopm']: - if not self['debug']: - raise usage.UsageError("You must specify --debug when using " - "--nopm ") - failure.DO_POST_MORTEM = False - - - -def _initialDebugSetup(config): - # do this part of debug setup first for easy debugging of import failures - if config['debug']: - failure.startDebugMode() - if config['debug'] or config['debug-stacktraces']: - defer.setDebugging(True) - - - -def _getSuite(config): - loader = _getLoader(config) - recurse = not config['no-recurse'] - return loader.loadByNames(config['tests'], recurse) - - - -def _getLoader(config): - loader = runner.TestLoader() - if config['random']: - randomer = random.Random() - randomer.seed(config['random']) - loader.sorter = lambda x : randomer.random() - print('Running tests shuffled with seed %d\n' % config['random']) - elif config['order']: - _, sorter = _runOrders[config['order']] - loader.sorter = sorter - if not config['until-failure']: - loader.suiteFactory = runner.DestructiveTestSuite - return loader - - -def _wrappedPdb(): - """ - Wrap an instance of C{pdb.Pdb} with readline support and load any .rcs. - - """ - - dbg = pdb.Pdb() - try: - namedModule('readline') - except ImportError: - print("readline module not available") - sys.exc_clear() - for path in ('.pdbrc', 'pdbrc'): - if os.path.exists(path): - try: - rcFile = file(path, 'r') - except IOError: - sys.exc_clear() - else: - dbg.rcLines.extend(rcFile.readlines()) - return dbg - - -class _DebuggerNotFound(Exception): - """ - A debugger import failed. - - Used to allow translating these errors into usage error messages. - - """ - - - -def _makeRunner(config): - """ - Return a trial runner class set up with the parameters extracted from - C{config}. - - @return: A trial runner instance. - @rtype: L{runner.TrialRunner} or C{DistTrialRunner} depending on the - configuration. - """ - cls = runner.TrialRunner - args = {'reporterFactory': config['reporter'], - 'tracebackFormat': config['tbformat'], - 'realTimeErrors': config['rterrors'], - 'uncleanWarnings': config['unclean-warnings'], - 'logfile': config['logfile'], - 'workingDirectory': config['temp-directory']} - if config['dry-run']: - args['mode'] = runner.TrialRunner.DRY_RUN - elif config['jobs']: - from twisted.trial._dist.disttrial import DistTrialRunner - cls = DistTrialRunner - args['workerNumber'] = config['jobs'] - args['workerArguments'] = config._getWorkerArguments() - else: - if config['debug']: - args['mode'] = runner.TrialRunner.DEBUG - debugger = config['debugger'] - - if debugger != 'pdb': - try: - args['debugger'] = reflect.namedAny(debugger) - except reflect.ModuleNotFound: - raise _DebuggerNotFound( - '%r debugger could not be found.' % (debugger,)) - else: - args['debugger'] = _wrappedPdb() - - args['exitFirst'] = config['exitfirst'] - args['profile'] = config['profile'] - args['forceGarbageCollection'] = config['force-gc'] - - return cls(**args) - - - -def run(): - if len(sys.argv) == 1: - sys.argv.append("--help") - config = Options() - try: - config.parseOptions() - except usage.error as ue: - raise SystemExit("%s: %s" % (sys.argv[0], ue)) - _initialDebugSetup(config) - - try: - trialRunner = _makeRunner(config) - except _DebuggerNotFound as e: - raise SystemExit('%s: %s' % (sys.argv[0], str(e))) - - suite = _getSuite(config) - if config['until-failure']: - test_result = trialRunner.runUntilFailure(suite) - else: - test_result = trialRunner.run(suite) - if config.tracer: - sys.settrace(None) - results = config.tracer.results() - results.write_results(show_missing=1, summary=False, - coverdir=config.coverdir().path) - sys.exit(not test_result.wasSuccessful()) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/twistd.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/twistd.py deleted file mode 100644 index c2b53c7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/scripts/twistd.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- test-case-name: twisted.test.test_twistd -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -The Twisted Daemon: platform-independent interface. - -@author: Christopher Armstrong -""" - -from twisted.application import app - -from twisted.python.runtime import platformType -if platformType == "win32": - from twisted.scripts._twistw import ServerOptions, \ - WindowsApplicationRunner as _SomeApplicationRunner -else: - from twisted.scripts._twistd_unix import ServerOptions, \ - UnixApplicationRunner as _SomeApplicationRunner - - -def runApp(config): - _SomeApplicationRunner(config).run() - - -def run(): - app.run(runApp, ServerOptions) - - -__all__ = ['run', 'runApp'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/__init__.py deleted file mode 100644 index ab38810..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Spread: Spreadable (Distributed) Computing. - -@author: Glyph Lefkowitz -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/banana.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/banana.py deleted file mode 100644 index 7dc2259..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/banana.py +++ /dev/null @@ -1,389 +0,0 @@ -# -*- test-case-name: twisted.test.test_banana -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Banana -- s-exp based protocol. - -Future Plans: This module is almost entirely stable. The same caveat applies -to it as applies to L{twisted.spread.jelly}, however. Read its future plans -for more details. - -@author: Glyph Lefkowitz -""" - -import copy, cStringIO, struct - -from twisted.internet import protocol -from twisted.persisted import styles -from twisted.python import log -from twisted.python.reflect import fullyQualifiedName - -class BananaError(Exception): - pass - -def int2b128(integer, stream): - if integer == 0: - stream(chr(0)) - return - assert integer > 0, "can only encode positive integers" - while integer: - stream(chr(integer & 0x7f)) - integer = integer >> 7 - - -def b1282int(st): - """ - Convert an integer represented as a base 128 string into an C{int} or - C{long}. - - @param st: The integer encoded in a string. - @type st: C{str} - - @return: The integer value extracted from the string. - @rtype: C{int} or C{long} - """ - e = 1 - i = 0 - for char in st: - n = ord(char) - i += (n * e) - e <<= 7 - return i - - -# delimiter characters. -LIST = chr(0x80) -INT = chr(0x81) -STRING = chr(0x82) -NEG = chr(0x83) -FLOAT = chr(0x84) -# "optional" -- these might be refused by a low-level implementation. -LONGINT = chr(0x85) -LONGNEG = chr(0x86) -# really optional; this is part of the 'pb' vocabulary -VOCAB = chr(0x87) - -HIGH_BIT_SET = chr(0x80) - -def setPrefixLimit(limit): - """ - Set the limit on the prefix length for all Banana connections - established after this call. - - The prefix length limit determines how many bytes of prefix a banana - decoder will allow before rejecting a potential object as too large. - - @type limit: C{int} - @param limit: The number of bytes of prefix for banana to allow when - decoding. - """ - global _PREFIX_LIMIT - _PREFIX_LIMIT = limit - -_PREFIX_LIMIT = None -setPrefixLimit(64) - -SIZE_LIMIT = 640 * 1024 # 640k is all you'll ever need :-) - -class Banana(protocol.Protocol, styles.Ephemeral): - """ - L{Banana} implements the I{Banana} s-expression protocol, client and - server. - - @ivar knownDialects: These are the profiles supported by this Banana - implementation. - @type knownDialects: L{list} of L{bytes} - """ - - # The specification calls these profiles but this implementation calls them - # dialects instead. - knownDialects = ["pb", "none"] - - prefixLimit = None - sizeLimit = SIZE_LIMIT - - def setPrefixLimit(self, limit): - """ - Set the prefix limit for decoding done by this protocol instance. - - @see: L{setPrefixLimit} - """ - self.prefixLimit = limit - self._smallestLongInt = -2 ** (limit * 7) + 1 - self._smallestInt = -2 ** 31 - self._largestInt = 2 ** 31 - 1 - self._largestLongInt = 2 ** (limit * 7) - 1 - - - def connectionReady(self): - """Surrogate for connectionMade - Called after protocol negotiation. - """ - - def _selectDialect(self, dialect): - self.currentDialect = dialect - self.connectionReady() - - def callExpressionReceived(self, obj): - if self.currentDialect: - self.expressionReceived(obj) - else: - # this is the first message we've received - if self.isClient: - # if I'm a client I have to respond - for serverVer in obj: - if serverVer in self.knownDialects: - self.sendEncoded(serverVer) - self._selectDialect(serverVer) - break - else: - # I can't speak any of those dialects. - log.msg("The client doesn't speak any of the protocols " - "offered by the server: disconnecting.") - self.transport.loseConnection() - else: - if obj in self.knownDialects: - self._selectDialect(obj) - else: - # the client just selected a protocol that I did not suggest. - log.msg("The client selected a protocol the server didn't " - "suggest and doesn't know: disconnecting.") - self.transport.loseConnection() - - - def connectionMade(self): - self.setPrefixLimit(_PREFIX_LIMIT) - self.currentDialect = None - if not self.isClient: - self.sendEncoded(self.knownDialects) - - - def gotItem(self, item): - l = self.listStack - if l: - l[-1][1].append(item) - else: - self.callExpressionReceived(item) - - buffer = '' - - def dataReceived(self, chunk): - buffer = self.buffer + chunk - listStack = self.listStack - gotItem = self.gotItem - while buffer: - assert self.buffer != buffer, "This ain't right: %s %s" % (repr(self.buffer), repr(buffer)) - self.buffer = buffer - pos = 0 - for ch in buffer: - if ch >= HIGH_BIT_SET: - break - pos = pos + 1 - else: - if pos > self.prefixLimit: - raise BananaError("Security precaution: more than %d bytes of prefix" % (self.prefixLimit,)) - return - num = buffer[:pos] - typebyte = buffer[pos] - rest = buffer[pos+1:] - if len(num) > self.prefixLimit: - raise BananaError("Security precaution: longer than %d bytes worth of prefix" % (self.prefixLimit,)) - if typebyte == LIST: - num = b1282int(num) - if num > SIZE_LIMIT: - raise BananaError("Security precaution: List too long.") - listStack.append((num, [])) - buffer = rest - elif typebyte == STRING: - num = b1282int(num) - if num > SIZE_LIMIT: - raise BananaError("Security precaution: String too long.") - if len(rest) >= num: - buffer = rest[num:] - gotItem(rest[:num]) - else: - return - elif typebyte == INT: - buffer = rest - num = b1282int(num) - gotItem(num) - elif typebyte == LONGINT: - buffer = rest - num = b1282int(num) - gotItem(num) - elif typebyte == LONGNEG: - buffer = rest - num = b1282int(num) - gotItem(-num) - elif typebyte == NEG: - buffer = rest - num = -b1282int(num) - gotItem(num) - elif typebyte == VOCAB: - buffer = rest - num = b1282int(num) - item = self.incomingVocabulary[num] - if self.currentDialect == b'pb': - # the sender issues VOCAB only for dialect pb - gotItem(item) - else: - raise NotImplementedError( - "Invalid item for pb protocol {0!r}".format(item)) - elif typebyte == FLOAT: - if len(rest) >= 8: - buffer = rest[8:] - gotItem(struct.unpack("!d", rest[:8])[0]) - else: - return - else: - raise NotImplementedError(("Invalid Type Byte %r" % (typebyte,))) - while listStack and (len(listStack[-1][1]) == listStack[-1][0]): - item = listStack.pop()[1] - gotItem(item) - self.buffer = '' - - - def expressionReceived(self, lst): - """Called when an expression (list, string, or int) is received. - """ - raise NotImplementedError() - - - outgoingVocabulary = { - # Jelly Data Types - 'None' : 1, - 'class' : 2, - 'dereference' : 3, - 'reference' : 4, - 'dictionary' : 5, - 'function' : 6, - 'instance' : 7, - 'list' : 8, - 'module' : 9, - 'persistent' : 10, - 'tuple' : 11, - 'unpersistable' : 12, - - # PB Data Types - 'copy' : 13, - 'cache' : 14, - 'cached' : 15, - 'remote' : 16, - 'local' : 17, - 'lcache' : 18, - - # PB Protocol Messages - 'version' : 19, - 'login' : 20, - 'password' : 21, - 'challenge' : 22, - 'logged_in' : 23, - 'not_logged_in' : 24, - 'cachemessage' : 25, - 'message' : 26, - 'answer' : 27, - 'error' : 28, - 'decref' : 29, - 'decache' : 30, - 'uncache' : 31, - } - - incomingVocabulary = {} - for k, v in outgoingVocabulary.items(): - incomingVocabulary[v] = k - - def __init__(self, isClient=1): - self.listStack = [] - self.outgoingSymbols = copy.copy(self.outgoingVocabulary) - self.outgoingSymbolCount = 0 - self.isClient = isClient - - def sendEncoded(self, obj): - """ - Send the encoded representation of the given object: - - @param obj: An object to encode and send. - - @raise BananaError: If the given object is not an instance of one of - the types supported by Banana. - - @return: C{None} - """ - io = cStringIO.StringIO() - self._encode(obj, io.write) - value = io.getvalue() - self.transport.write(value) - - def _encode(self, obj, write): - if isinstance(obj, (list, tuple)): - if len(obj) > SIZE_LIMIT: - raise BananaError( - "list/tuple is too long to send (%d)" % (len(obj),)) - int2b128(len(obj), write) - write(LIST) - for elem in obj: - self._encode(elem, write) - elif isinstance(obj, (int, long)): - if obj < self._smallestLongInt or obj > self._largestLongInt: - raise BananaError( - "int/long is too large to send (%d)" % (obj,)) - if obj < self._smallestInt: - int2b128(-obj, write) - write(LONGNEG) - elif obj < 0: - int2b128(-obj, write) - write(NEG) - elif obj <= self._largestInt: - int2b128(obj, write) - write(INT) - else: - int2b128(obj, write) - write(LONGINT) - elif isinstance(obj, float): - write(FLOAT) - write(struct.pack("!d", obj)) - elif isinstance(obj, str): - # TODO: an API for extending banana... - if self.currentDialect == "pb" and obj in self.outgoingSymbols: - symbolID = self.outgoingSymbols[obj] - int2b128(symbolID, write) - write(VOCAB) - else: - if len(obj) > SIZE_LIMIT: - raise BananaError( - "string is too long to send (%d)" % (len(obj),)) - int2b128(len(obj), write) - write(STRING) - write(obj) - else: - raise BananaError("Banana cannot send {0} objects: {1!r}".format( - fullyQualifiedName(type(obj)), obj)) - - -# For use from the interactive interpreter -_i = Banana() -_i.connectionMade() -_i._selectDialect("none") - - -def encode(lst): - """Encode a list s-expression.""" - io = cStringIO.StringIO() - _i.transport = io - _i.sendEncoded(lst) - return io.getvalue() - - -def decode(st): - """ - Decode a banana-encoded string. - """ - l = [] - _i.expressionReceived = l.append - try: - _i.dataReceived(st) - finally: - _i.buffer = '' - del _i.expressionReceived - return l[0] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/flavors.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/flavors.py deleted file mode 100644 index c3156b1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/flavors.py +++ /dev/null @@ -1,589 +0,0 @@ -# -*- test-case-name: twisted.test.test_pb -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module represents flavors of remotely accessible objects. - -Currently this is only objects accessible through Perspective Broker, but will -hopefully encompass all forms of remote access which can emulate subsets of PB -(such as XMLRPC or SOAP). - -Future Plans: Optimization. Exploitation of new-style object model. -Optimizations to this module should not affect external-use semantics at all, -but may have a small impact on users who subclass and override methods. - -@author: Glyph Lefkowitz -""" - -# NOTE: this module should NOT import pb; it is supposed to be a module which -# abstractly defines remotely accessible types. Many of these types expect to -# be serialized by Jelly, but they ought to be accessible through other -# mechanisms (like XMLRPC) - -# system imports -import sys -from zope.interface import implementer, Interface - -# twisted imports -from twisted.python import log, reflect - -# sibling imports -from jelly import setUnjellyableForClass, setUnjellyableForClassTree, setUnjellyableFactoryForClass, unjellyableRegistry -from jelly import Jellyable, Unjellyable, _newDummyLike -from jelly import setInstanceState, getInstanceState - -# compatibility -setCopierForClass = setUnjellyableForClass -setCopierForClassTree = setUnjellyableForClassTree -setFactoryForClass = setUnjellyableFactoryForClass -copyTags = unjellyableRegistry - -copy_atom = "copy" -cache_atom = "cache" -cached_atom = "cached" -remote_atom = "remote" - - -class NoSuchMethod(AttributeError): - """Raised if there is no such remote method""" - - -class IPBRoot(Interface): - """Factory for root Referenceable objects for PB servers.""" - - def rootObject(broker): - """Return root Referenceable for broker.""" - - -class Serializable(Jellyable): - """An object that can be passed remotely. - - I am a style of object which can be serialized by Perspective - Broker. Objects which wish to be referenceable or copied remotely - have to subclass Serializable. However, clients of Perspective - Broker will probably not want to directly subclass Serializable; the - Flavors of transferable objects are listed below. - - What it means to be \"Serializable\" is that an object can be - passed to or returned from a remote method. Certain basic types - (dictionaries, lists, tuples, numbers, strings) are serializable by - default; however, classes need to choose a specific serialization - style: L{Referenceable}, L{Viewable}, L{Copyable} or L{Cacheable}. - - You may also pass C{[lists, dictionaries, tuples]} of L{Serializable} - instances to or return them from remote methods, as many levels deep - as you like. - """ - - def processUniqueID(self): - """Return an ID which uniquely represents this object for this process. - - By default, this uses the 'id' builtin, but can be overridden to - indicate that two values are identity-equivalent (such as proxies - for the same object). - """ - - return id(self) - -class Referenceable(Serializable): - perspective = None - """I am an object sent remotely as a direct reference. - - When one of my subclasses is sent as an argument to or returned - from a remote method call, I will be serialized by default as a - direct reference. - - This means that the peer will be able to call methods on me; - a method call xxx() from my peer will be resolved to methods - of the name remote_xxx. - """ - - def remoteMessageReceived(self, broker, message, args, kw): - """A remote message has been received. Dispatch it appropriately. - - The default implementation is to dispatch to a method called - 'remote_messagename' and call it with the same arguments. - """ - args = broker.unserialize(args) - kw = broker.unserialize(kw) - method = getattr(self, "remote_%s" % message, None) - if method is None: - raise NoSuchMethod("No such method: remote_%s" % (message,)) - try: - state = method(*args, **kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - return broker.serialize(state, self.perspective) - - def jellyFor(self, jellier): - """(internal) - - Return a tuple which will be used as the s-expression to - serialize this to a peer. - """ - - return ["remote", jellier.invoker.registerReference(self)] - - -@implementer(IPBRoot) -class Root(Referenceable): - """I provide a root object to L{pb.Broker}s for a L{pb.BrokerFactory}. - - When a L{pb.BrokerFactory} produces a L{pb.Broker}, it supplies that - L{pb.Broker} with an object named \"root\". That object is obtained - by calling my rootObject method. - """ - - def rootObject(self, broker): - """A L{pb.BrokerFactory} is requesting to publish me as a root object. - - When a L{pb.BrokerFactory} is sending me as the root object, this - method will be invoked to allow per-broker versions of an - object. By default I return myself. - """ - return self - - -class ViewPoint(Referenceable): - """ - I act as an indirect reference to an object accessed through a - L{pb.Perspective}. - - Simply put, I combine an object with a perspective so that when a - peer calls methods on the object I refer to, the method will be - invoked with that perspective as a first argument, so that it can - know who is calling it. - - While L{Viewable} objects will be converted to ViewPoints by default - when they are returned from or sent as arguments to a remote - method, any object may be manually proxied as well. (XXX: Now that - this class is no longer named C{Proxy}, this is the only occourance - of the term 'proxied' in this docstring, and may be unclear.) - - This can be useful when dealing with L{pb.Perspective}s, L{Copyable}s, - and L{Cacheable}s. It is legal to implement a method as such on - a perspective:: - - | def perspective_getViewPointForOther(self, name): - | defr = self.service.getPerspectiveRequest(name) - | defr.addCallbacks(lambda x, self=self: ViewPoint(self, x), log.msg) - | return defr - - This will allow you to have references to Perspective objects in two - different ways. One is through the initial 'attach' call -- each - peer will have a L{pb.RemoteReference} to their perspective directly. The - other is through this method; each peer can get a L{pb.RemoteReference} to - all other perspectives in the service; but that L{pb.RemoteReference} will - be to a L{ViewPoint}, not directly to the object. - - The practical offshoot of this is that you can implement 2 varieties - of remotely callable methods on this Perspective; view_xxx and - C{perspective_xxx}. C{view_xxx} methods will follow the rules for - ViewPoint methods (see ViewPoint.L{remoteMessageReceived}), and - C{perspective_xxx} methods will follow the rules for Perspective - methods. - """ - - def __init__(self, perspective, object): - """Initialize me with a Perspective and an Object. - """ - self.perspective = perspective - self.object = object - - def processUniqueID(self): - """Return an ID unique to a proxy for this perspective+object combination. - """ - return (id(self.perspective), id(self.object)) - - def remoteMessageReceived(self, broker, message, args, kw): - """A remote message has been received. Dispatch it appropriately. - - The default implementation is to dispatch to a method called - 'C{view_messagename}' to my Object and call it on my object with - the same arguments, modified by inserting my Perspective as - the first argument. - """ - args = broker.unserialize(args, self.perspective) - kw = broker.unserialize(kw, self.perspective) - method = getattr(self.object, "view_%s" % message) - try: - state = method(*(self.perspective,)+args, **kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - rv = broker.serialize(state, self.perspective, method, args, kw) - return rv - - -class Viewable(Serializable): - """I will be converted to a L{ViewPoint} when passed to or returned from a remote method. - - The beginning of a peer's interaction with a PB Service is always - through a perspective. However, if a C{perspective_xxx} method returns - a Viewable, it will be serialized to the peer as a response to that - method. - """ - - def jellyFor(self, jellier): - """Serialize a L{ViewPoint} for me and the perspective of the given broker. - """ - return ViewPoint(jellier.invoker.serializingPerspective, self).jellyFor(jellier) - - - -class Copyable(Serializable): - """Subclass me to get copied each time you are returned from or passed to a remote method. - - When I am returned from or passed to a remote method call, I will be - converted into data via a set of callbacks (see my methods for more - info). That data will then be serialized using Jelly, and sent to - the peer. - - The peer will then look up the type to represent this with; see - L{RemoteCopy} for details. - """ - - def getStateToCopy(self): - """Gather state to send when I am serialized for a peer. - - I will default to returning self.__dict__. Override this to - customize this behavior. - """ - - return self.__dict__ - - def getStateToCopyFor(self, perspective): - """ - Gather state to send when I am serialized for a particular - perspective. - - I will default to calling L{getStateToCopy}. Override this to - customize this behavior. - """ - - return self.getStateToCopy() - - def getTypeToCopy(self): - """Determine what type tag to send for me. - - By default, send the string representation of my class - (package.module.Class); normally this is adequate, but - you may override this to change it. - """ - - return reflect.qual(self.__class__) - - def getTypeToCopyFor(self, perspective): - """Determine what type tag to send for me. - - By default, defer to self.L{getTypeToCopy}() normally this is - adequate, but you may override this to change it. - """ - - return self.getTypeToCopy() - - def jellyFor(self, jellier): - """Assemble type tag and state to copy for this broker. - - This will call L{getTypeToCopyFor} and L{getStateToCopy}, and - return an appropriate s-expression to represent me. - """ - - if jellier.invoker is None: - return getInstanceState(self, jellier) - p = jellier.invoker.serializingPerspective - t = self.getTypeToCopyFor(p) - state = self.getStateToCopyFor(p) - sxp = jellier.prepare(self) - sxp.extend([t, jellier.jelly(state)]) - return jellier.preserve(self, sxp) - - -class Cacheable(Copyable): - """A cached instance. - - This means that it's copied; but there is some logic to make sure - that it's only copied once. Additionally, when state is retrieved, - it is passed a "proto-reference" to the state as it will exist on - the client. - - XXX: The documentation for this class needs work, but it's the most - complex part of PB and it is inherently difficult to explain. - """ - - def getStateToCacheAndObserveFor(self, perspective, observer): - """ - Get state to cache on the client and client-cache reference - to observe locally. - - This is similiar to getStateToCopyFor, but it additionally - passes in a reference to the client-side RemoteCache instance - that will be created when it is unserialized. This allows - Cacheable instances to keep their RemoteCaches up to date when - they change, such that no changes can occur between the point - at which the state is initially copied and the client receives - it that are not propagated. - """ - - return self.getStateToCopyFor(perspective) - - def jellyFor(self, jellier): - """Return an appropriate tuple to serialize me. - - Depending on whether this broker has cached me or not, this may - return either a full state or a reference to an existing cache. - """ - if jellier.invoker is None: - return getInstanceState(self, jellier) - luid = jellier.invoker.cachedRemotelyAs(self, 1) - if luid is None: - luid = jellier.invoker.cacheRemotely(self) - p = jellier.invoker.serializingPerspective - type_ = self.getTypeToCopyFor(p) - observer = RemoteCacheObserver(jellier.invoker, self, p) - state = self.getStateToCacheAndObserveFor(p, observer) - l = jellier.prepare(self) - jstate = jellier.jelly(state) - l.extend([type_, luid, jstate]) - return jellier.preserve(self, l) - else: - return cached_atom, luid - - def stoppedObserving(self, perspective, observer): - """This method is called when a client has stopped observing me. - - The 'observer' argument is the same as that passed in to - getStateToCacheAndObserveFor. - """ - - - -class RemoteCopy(Unjellyable): - """I am a remote copy of a Copyable object. - - When the state from a L{Copyable} object is received, an instance will - be created based on the copy tags table (see setUnjellyableForClass) and - sent the L{setCopyableState} message. I provide a reasonable default - implementation of that message; subclass me if you wish to serve as - a copier for remote data. - - NOTE: copiers are invoked with no arguments. Do not implement a - constructor which requires args in a subclass of L{RemoteCopy}! - """ - - def setCopyableState(self, state): - """I will be invoked with the state to copy locally. - - 'state' is the data returned from the remote object's - 'getStateToCopyFor' method, which will often be the remote - object's dictionary (or a filtered approximation of it depending - on my peer's perspective). - """ - - self.__dict__ = state - - def unjellyFor(self, unjellier, jellyList): - if unjellier.invoker is None: - return setInstanceState(self, unjellier, jellyList) - self.setCopyableState(unjellier.unjelly(jellyList[1])) - return self - - - -class RemoteCache(RemoteCopy, Serializable): - """A cache is a local representation of a remote L{Cacheable} object. - - This represents the last known state of this object. It may - also have methods invoked on it -- in order to update caches, - the cached class generates a L{pb.RemoteReference} to this object as - it is originally sent. - - Much like copy, I will be invoked with no arguments. Do not - implement a constructor that requires arguments in one of my - subclasses. - """ - - def remoteMessageReceived(self, broker, message, args, kw): - """A remote message has been received. Dispatch it appropriately. - - The default implementation is to dispatch to a method called - 'C{observe_messagename}' and call it on my with the same arguments. - """ - - args = broker.unserialize(args) - kw = broker.unserialize(kw) - method = getattr(self, "observe_%s" % message) - try: - state = method(*args, **kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - return broker.serialize(state, None, method, args, kw) - - def jellyFor(self, jellier): - """serialize me (only for the broker I'm for) as the original cached reference - """ - if jellier.invoker is None: - return getInstanceState(self, jellier) - assert jellier.invoker is self.broker, "You cannot exchange cached proxies between brokers." - return 'lcache', self.luid - - - def unjellyFor(self, unjellier, jellyList): - if unjellier.invoker is None: - return setInstanceState(self, unjellier, jellyList) - self.broker = unjellier.invoker - self.luid = jellyList[1] - cProxy = _newDummyLike(self) - # XXX questionable whether this was a good design idea... - init = getattr(cProxy, "__init__", None) - if init: - init() - unjellier.invoker.cacheLocally(jellyList[1], self) - cProxy.setCopyableState(unjellier.unjelly(jellyList[2])) - # Might have changed due to setCopyableState method; we'll assume that - # it's bad form to do so afterwards. - self.__dict__ = cProxy.__dict__ - # chomp, chomp -- some existing code uses "self.__dict__ =", some uses - # "__dict__.update". This is here in order to handle both cases. - self.broker = unjellier.invoker - self.luid = jellyList[1] - return cProxy - -## def __really_del__(self): -## """Final finalization call, made after all remote references have been lost. -## """ - - def __cmp__(self, other): - """Compare me [to another RemoteCache. - """ - if isinstance(other, self.__class__): - return cmp(id(self.__dict__), id(other.__dict__)) - else: - return cmp(id(self.__dict__), other) - - def __hash__(self): - """Hash me. - """ - return int(id(self.__dict__) % sys.maxint) - - broker = None - luid = None - - def __del__(self): - """Do distributed reference counting on finalize. - """ - try: - # log.msg( ' --- decache: %s %s' % (self, self.luid) ) - if self.broker: - self.broker.decCacheRef(self.luid) - except: - log.deferr() - -def unjellyCached(unjellier, unjellyList): - luid = unjellyList[1] - cNotProxy = unjellier.invoker.cachedLocallyAs(luid) - cProxy = _newDummyLike(cNotProxy) - return cProxy - -setUnjellyableForClass("cached", unjellyCached) - -def unjellyLCache(unjellier, unjellyList): - luid = unjellyList[1] - obj = unjellier.invoker.remotelyCachedForLUID(luid) - return obj - -setUnjellyableForClass("lcache", unjellyLCache) - -def unjellyLocal(unjellier, unjellyList): - obj = unjellier.invoker.localObjectForID(unjellyList[1]) - return obj - -setUnjellyableForClass("local", unjellyLocal) - -class RemoteCacheMethod: - """A method on a reference to a L{RemoteCache}. - """ - - def __init__(self, name, broker, cached, perspective): - """(internal) initialize. - """ - self.name = name - self.broker = broker - self.perspective = perspective - self.cached = cached - - def __cmp__(self, other): - return cmp((self.name, self.broker, self.perspective, self.cached), other) - - def __hash__(self): - return hash((self.name, self.broker, self.perspective, self.cached)) - - def __call__(self, *args, **kw): - """(internal) action method. - """ - cacheID = self.broker.cachedRemotelyAs(self.cached) - if cacheID is None: - from pb import ProtocolError - raise ProtocolError("You can't call a cached method when the object hasn't been given to the peer yet.") - return self.broker._sendMessage('cache', self.perspective, cacheID, self.name, args, kw) - -class RemoteCacheObserver: - """I am a reverse-reference to the peer's L{RemoteCache}. - - I am generated automatically when a cache is serialized. I - represent a reference to the client's L{RemoteCache} object that - will represent a particular L{Cacheable}; I am the additional - object passed to getStateToCacheAndObserveFor. - """ - - def __init__(self, broker, cached, perspective): - """(internal) Initialize me. - - @param broker: a L{pb.Broker} instance. - - @param cached: a L{Cacheable} instance that this L{RemoteCacheObserver} - corresponds to. - - @param perspective: a reference to the perspective who is observing this. - """ - - self.broker = broker - self.cached = cached - self.perspective = perspective - - def __repr__(self): - return "" % ( - self.broker, self.cached, self.perspective, id(self)) - - def __hash__(self): - """Generate a hash unique to all L{RemoteCacheObserver}s for this broker/perspective/cached triplet - """ - - return ( (hash(self.broker) % 2**10) - + (hash(self.perspective) % 2**10) - + (hash(self.cached) % 2**10)) - - def __cmp__(self, other): - """Compare me to another L{RemoteCacheObserver}. - """ - - return cmp((self.broker, self.perspective, self.cached), other) - - def callRemote(self, _name, *args, **kw): - """(internal) action method. - """ - cacheID = self.broker.cachedRemotelyAs(self.cached) - if cacheID is None: - from pb import ProtocolError - raise ProtocolError("You can't call a cached method when the " - "object hasn't been given to the peer yet.") - return self.broker._sendMessage('cache', self.perspective, cacheID, - _name, args, kw) - - def remoteMethod(self, key): - """Get a L{pb.RemoteMethod} for this key. - """ - return RemoteCacheMethod(key, self.broker, self.cached, self.perspective) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/interfaces.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/interfaces.py deleted file mode 100644 index a7db3ff..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/interfaces.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Spread Interfaces. -""" - -from zope.interface import Interface - - -class IJellyable(Interface): - def jellyFor(jellier): - """ - Jelly myself for jellier. - """ - - - -class IUnjellyable(Interface): - def unjellyFor(jellier, jellyList): - """ - Unjelly myself for the jellier. - - @param jellier: A stateful object which exists for the lifetime of a - single call to L{unjelly}. - - @param jellyList: The C{list} which represents the jellied state of the - object to be unjellied. - - @return: The object which results from unjellying. - """ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/jelly.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/jelly.py deleted file mode 100644 index ec32903..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/jelly.py +++ /dev/null @@ -1,1142 +0,0 @@ -# -*- test-case-name: twisted.test.test_jelly -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -S-expression-based persistence of python objects. - -It does something very much like L{Pickle}; however, pickle's main goal -seems to be efficiency (both in space and time); jelly's main goals are -security, human readability, and portability to other environments. - -This is how Jelly converts various objects to s-expressions. - -Boolean:: - True --> ['boolean', 'true'] - -Integer:: - 1 --> 1 - -List:: - [1, 2] --> ['list', 1, 2] - -String:: - \"hello\" --> \"hello\" - -Float:: - 2.3 --> 2.3 - -Dictionary:: - {'a': 1, 'b': 'c'} --> ['dictionary', ['b', 'c'], ['a', 1]] - -Module:: - UserString --> ['module', 'UserString'] - -Class:: - UserString.UserString --> ['class', ['module', 'UserString'], 'UserString'] - -Function:: - string.join --> ['function', 'join', ['module', 'string']] - -Instance: s is an instance of UserString.UserString, with a __dict__ -{'data': 'hello'}:: - [\"UserString.UserString\", ['dictionary', ['data', 'hello']]] - -Class Method: UserString.UserString.center:: - ['method', 'center', ['None'], ['class', ['module', 'UserString'], - 'UserString']] - -Instance Method: s.center, where s is an instance of UserString.UserString:: - ['method', 'center', ['instance', ['reference', 1, ['class', - ['module', 'UserString'], 'UserString']], ['dictionary', ['data', 'd']]], - ['dereference', 1]] - -The C{set} builtin and the C{sets.Set} class are serialized to the same -thing, and unserialized to C{set} if available, else to C{sets.Set}. It means -that there's a possibility of type switching in the serialization process. The -solution is to always use C{set}. - -The same rule applies for C{frozenset} and C{sets.ImmutableSet}. - -@author: Glyph Lefkowitz -""" - -# System Imports -import pickle -import types -import warnings -import decimal -from functools import reduce -from types import StringType -from types import IntType -from types import TupleType -from types import ListType -from types import LongType -from types import FloatType -from types import FunctionType -from types import MethodType -from types import ModuleType -from types import DictionaryType -from types import InstanceType -from types import NoneType -from types import ClassType -import copy - -import datetime -from types import BooleanType - -try: - # Filter out deprecation warning for Python >= 2.6 - warnings.filterwarnings("ignore", category=DeprecationWarning, - message="the sets module is deprecated", append=True) - import sets as _sets -finally: - warnings.filters.pop() - - -from zope.interface import implementer - -# Twisted Imports -from twisted.python.compat import unicode -from twisted.python.reflect import namedObject, qual -from twisted.persisted.crefutil import NotKnown, _Tuple, _InstanceMethod -from twisted.persisted.crefutil import _DictKeyAndValue, _Dereference -from twisted.persisted.crefutil import _Container - -from twisted.spread.interfaces import IJellyable, IUnjellyable - -from twisted.python.deprecate import deprecatedModuleAttribute -from twisted.python.versions import Version - -DictTypes = (DictionaryType,) - -None_atom = "None" # N -# code -class_atom = "class" # c -module_atom = "module" # m -function_atom = "function" # f - -# references -dereference_atom = 'dereference' # D -persistent_atom = 'persistent' # p -reference_atom = 'reference' # r - -# mutable collections -dictionary_atom = "dictionary" # d -list_atom = 'list' # l -set_atom = 'set' - -# immutable collections -# (assignment to __dict__ and __class__ still might go away!) -tuple_atom = "tuple" # t -instance_atom = 'instance' # i -frozenset_atom = 'frozenset' - - -deprecatedModuleAttribute( - Version("Twisted", 15, 0, 0), - "instance_atom is unused within Twisted.", - "twisted.spread.jelly", "instance_atom") - -# errors -unpersistable_atom = "unpersistable"# u -unjellyableRegistry = {} -unjellyableFactoryRegistry = {} - -_NO_STATE = object() - -def _newInstance(cls, state=_NO_STATE): - """ - Make a new instance of a class without calling its __init__ method. - Supports both new- and old-style classes. - - @param state: A C{dict} used to update C{inst.__dict__} or C{_NO_STATE} - to skip this part of initialization. - - @return: A new instance of C{cls}. - """ - if not isinstance(cls, types.ClassType): - # new-style - inst = cls.__new__(cls) - - if state is not _NO_STATE: - inst.__dict__.update(state) # Copy 'instance' behaviour - else: - if state is not _NO_STATE: - inst = InstanceType(cls, state) - else: - inst = InstanceType(cls) - return inst - - - -def _maybeClass(classnamep): - try: - object - except NameError: - isObject = 0 - else: - isObject = isinstance(classnamep, type) - if isinstance(classnamep, ClassType) or isObject: - return qual(classnamep) - return classnamep - - - -def setUnjellyableForClass(classname, unjellyable): - """ - Set which local class will represent a remote type. - - If you have written a Copyable class that you expect your client to be - receiving, write a local "copy" class to represent it, then call:: - - jellier.setUnjellyableForClass('module.package.Class', MyCopier). - - Call this at the module level immediately after its class - definition. MyCopier should be a subclass of RemoteCopy. - - The classname may be a special tag returned by - 'Copyable.getTypeToCopyFor' rather than an actual classname. - - This call is also for cached classes, since there will be no - overlap. The rules are the same. - """ - - global unjellyableRegistry - classname = _maybeClass(classname) - unjellyableRegistry[classname] = unjellyable - globalSecurity.allowTypes(classname) - - - -def setUnjellyableFactoryForClass(classname, copyFactory): - """ - Set the factory to construct a remote instance of a type:: - - jellier.setUnjellyableFactoryForClass('module.package.Class', MyFactory) - - Call this at the module level immediately after its class definition. - C{copyFactory} should return an instance or subclass of - L{RemoteCopy}. - - Similar to L{setUnjellyableForClass} except it uses a factory instead - of creating an instance. - """ - - global unjellyableFactoryRegistry - classname = _maybeClass(classname) - unjellyableFactoryRegistry[classname] = copyFactory - globalSecurity.allowTypes(classname) - - - -def setUnjellyableForClassTree(module, baseClass, prefix=None): - """ - Set all classes in a module derived from C{baseClass} as copiers for - a corresponding remote class. - - When you have a heirarchy of Copyable (or Cacheable) classes on one - side, and a mirror structure of Copied (or RemoteCache) classes on the - other, use this to setUnjellyableForClass all your Copieds for the - Copyables. - - Each copyTag (the \"classname\" argument to getTypeToCopyFor, and - what the Copyable's getTypeToCopyFor returns) is formed from - adding a prefix to the Copied's class name. The prefix defaults - to module.__name__. If you wish the copy tag to consist of solely - the classname, pass the empty string \'\'. - - @param module: a module object from which to pull the Copied classes. - (passing sys.modules[__name__] might be useful) - - @param baseClass: the base class from which all your Copied classes derive. - - @param prefix: the string prefixed to classnames to form the - unjellyableRegistry. - """ - if prefix is None: - prefix = module.__name__ - - if prefix: - prefix = "%s." % prefix - - for i in dir(module): - i_ = getattr(module, i) - if type(i_) == types.ClassType: - if issubclass(i_, baseClass): - setUnjellyableForClass('%s%s' % (prefix, i), i_) - - - -def getInstanceState(inst, jellier): - """ - Utility method to default to 'normal' state rules in serialization. - """ - if hasattr(inst, "__getstate__"): - state = inst.__getstate__() - else: - state = inst.__dict__ - sxp = jellier.prepare(inst) - sxp.extend([qual(inst.__class__), jellier.jelly(state)]) - return jellier.preserve(inst, sxp) - - - -def setInstanceState(inst, unjellier, jellyList): - """ - Utility method to default to 'normal' state rules in unserialization. - """ - state = unjellier.unjelly(jellyList[1]) - if hasattr(inst, "__setstate__"): - inst.__setstate__(state) - else: - inst.__dict__ = state - return inst - - - -class Unpersistable: - """ - This is an instance of a class that comes back when something couldn't be - unpersisted. - """ - - def __init__(self, reason): - """ - Initialize an unpersistable object with a descriptive C{reason} string. - """ - self.reason = reason - - - def __repr__(self): - return "Unpersistable(%s)" % repr(self.reason) - - - -@implementer(IJellyable) -class Jellyable: - """ - Inherit from me to Jelly yourself directly with the `getStateFor' - convenience method. - """ - - def getStateFor(self, jellier): - return self.__dict__ - - - def jellyFor(self, jellier): - """ - @see: L{twisted.spread.interfaces.IJellyable.jellyFor} - """ - sxp = jellier.prepare(self) - sxp.extend([ - qual(self.__class__), - jellier.jelly(self.getStateFor(jellier))]) - return jellier.preserve(self, sxp) - - - -@implementer(IUnjellyable) -class Unjellyable: - """ - Inherit from me to Unjelly yourself directly with the - C{setStateFor} convenience method. - """ - - def setStateFor(self, unjellier, state): - self.__dict__ = state - - - def unjellyFor(self, unjellier, jellyList): - """ - Perform the inverse operation of L{Jellyable.jellyFor}. - - @see: L{twisted.spread.interfaces.IUnjellyable.unjellyFor} - """ - state = unjellier.unjelly(jellyList[1]) - self.setStateFor(unjellier, state) - return self - - - -class _Jellier: - """ - (Internal) This class manages state for a call to jelly() - """ - - def __init__(self, taster, persistentStore, invoker): - """ - Initialize. - """ - self.taster = taster - # `preserved' is a dict of previously seen instances. - self.preserved = {} - # `cooked' is a dict of previously backreferenced instances to their - # `ref' lists. - self.cooked = {} - self.cooker = {} - self._ref_id = 1 - self.persistentStore = persistentStore - self.invoker = invoker - - - def _cook(self, object): - """ - (internal) Backreference an object. - - Notes on this method for the hapless future maintainer: If I've already - gone through the prepare/preserve cycle on the specified object (it is - being referenced after the serializer is \"done with\" it, e.g. this - reference is NOT circular), the copy-in-place of aList is relevant, - since the list being modified is the actual, pre-existing jelly - expression that was returned for that object. If not, it's technically - superfluous, since the value in self.preserved didn't need to be set, - but the invariant that self.preserved[id(object)] is a list is - convenient because that means we don't have to test and create it or - not create it here, creating fewer code-paths. that's why - self.preserved is always set to a list. - - Sorry that this code is so hard to follow, but Python objects are - tricky to persist correctly. -glyph - """ - aList = self.preserved[id(object)] - newList = copy.copy(aList) - # make a new reference ID - refid = self._ref_id - self._ref_id = self._ref_id + 1 - # replace the old list in-place, so that we don't have to track the - # previous reference to it. - aList[:] = [reference_atom, refid, newList] - self.cooked[id(object)] = [dereference_atom, refid] - return aList - - - def prepare(self, object): - """ - (internal) Create a list for persisting an object to. This will allow - backreferences to be made internal to the object. (circular - references). - - The reason this needs to happen is that we don't generate an ID for - every object, so we won't necessarily know which ID the object will - have in the future. When it is 'cooked' ( see _cook ), it will be - assigned an ID, and the temporary placeholder list created here will be - modified in-place to create an expression that gives this object an ID: - [reference id# [object-jelly]]. - """ - - # create a placeholder list to be preserved - self.preserved[id(object)] = [] - # keep a reference to this object around, so it doesn't disappear! - # (This isn't always necessary, but for cases where the objects are - # dynamically generated by __getstate__ or getStateToCopyFor calls, it - # is; id() will return the same value for a different object if it gets - # garbage collected. This may be optimized later.) - self.cooker[id(object)] = object - return [] - - - def preserve(self, object, sexp): - """ - (internal) Mark an object's persistent list for later referral. - """ - # if I've been cooked in the meanwhile, - if id(object) in self.cooked: - # replace the placeholder empty list with the real one - self.preserved[id(object)][2] = sexp - # but give this one back. - sexp = self.preserved[id(object)] - else: - self.preserved[id(object)] = sexp - return sexp - - constantTypes = {types.StringType : 1, types.IntType : 1, - types.FloatType : 1, types.LongType : 1} - - - def _checkMutable(self,obj): - objId = id(obj) - if objId in self.cooked: - return self.cooked[objId] - if objId in self.preserved: - self._cook(obj) - return self.cooked[objId] - - - def jelly(self, obj): - if isinstance(obj, Jellyable): - preRef = self._checkMutable(obj) - if preRef: - return preRef - return obj.jellyFor(self) - objType = type(obj) - if self.taster.isTypeAllowed(qual(objType)): - # "Immutable" Types - if ((objType is StringType) or - (objType is IntType) or - (objType is LongType) or - (objType is FloatType)): - return obj - elif objType is MethodType: - return ["method", - obj.im_func.__name__, - self.jelly(obj.im_self), - self.jelly(obj.im_class)] - - elif objType is unicode: - return ['unicode', obj.encode('UTF-8')] - elif objType is NoneType: - return ['None'] - elif objType is FunctionType: - name = obj.__name__ - return ['function', str(pickle.whichmodule(obj, obj.__name__)) - + '.' + - name] - elif objType is ModuleType: - return ['module', obj.__name__] - elif objType is BooleanType: - return ['boolean', obj and 'true' or 'false'] - elif objType is datetime.datetime: - if obj.tzinfo: - raise NotImplementedError( - "Currently can't jelly datetime objects with tzinfo") - return ['datetime', '%s %s %s %s %s %s %s' % ( - obj.year, obj.month, obj.day, obj.hour, - obj.minute, obj.second, obj.microsecond)] - elif objType is datetime.time: - if obj.tzinfo: - raise NotImplementedError( - "Currently can't jelly datetime objects with tzinfo") - return ['time', '%s %s %s %s' % (obj.hour, obj.minute, - obj.second, obj.microsecond)] - elif objType is datetime.date: - return ['date', '%s %s %s' % (obj.year, obj.month, obj.day)] - elif objType is datetime.timedelta: - return ['timedelta', '%s %s %s' % (obj.days, obj.seconds, - obj.microseconds)] - elif objType is ClassType or issubclass(objType, type): - return ['class', qual(obj)] - elif objType is decimal.Decimal: - return self.jelly_decimal(obj) - else: - preRef = self._checkMutable(obj) - if preRef: - return preRef - # "Mutable" Types - sxp = self.prepare(obj) - if objType is ListType: - sxp.extend(self._jellyIterable(list_atom, obj)) - elif objType is TupleType: - sxp.extend(self._jellyIterable(tuple_atom, obj)) - elif objType in DictTypes: - sxp.append(dictionary_atom) - for key, val in obj.items(): - sxp.append([self.jelly(key), self.jelly(val)]) - elif objType is set or objType is _sets.Set: - sxp.extend(self._jellyIterable(set_atom, obj)) - elif objType is frozenset or objType is _sets.ImmutableSet: - sxp.extend(self._jellyIterable(frozenset_atom, obj)) - else: - className = qual(obj.__class__) - persistent = None - if self.persistentStore: - persistent = self.persistentStore(obj, self) - if persistent is not None: - sxp.append(persistent_atom) - sxp.append(persistent) - elif self.taster.isClassAllowed(obj.__class__): - sxp.append(className) - if hasattr(obj, "__getstate__"): - state = obj.__getstate__() - else: - state = obj.__dict__ - sxp.append(self.jelly(state)) - else: - self.unpersistable( - "instance of class %s deemed insecure" % - qual(obj.__class__), sxp) - return self.preserve(obj, sxp) - else: - if objType is InstanceType: - raise InsecureJelly("Class not allowed for instance: %s %s" % - (obj.__class__, obj)) - raise InsecureJelly("Type not allowed for object: %s %s" % - (objType, obj)) - - - def _jellyIterable(self, atom, obj): - """ - Jelly an iterable object. - - @param atom: the identifier atom of the object. - @type atom: C{str} - - @param obj: any iterable object. - @type obj: C{iterable} - - @return: a generator of jellied data. - @rtype: C{generator} - """ - yield atom - for item in obj: - yield self.jelly(item) - - - def jelly_decimal(self, d): - """ - Jelly a decimal object. - - @param d: a decimal object to serialize. - @type d: C{decimal.Decimal} - - @return: jelly for the decimal object. - @rtype: C{list} - """ - sign, guts, exponent = d.as_tuple() - value = reduce(lambda left, right: left * 10 + right, guts) - if sign: - value = -value - return ['decimal', value, exponent] - - - def unpersistable(self, reason, sxp=None): - """ - (internal) Returns an sexp: (unpersistable "reason"). Utility method - for making note that a particular object could not be serialized. - """ - if sxp is None: - sxp = [] - sxp.append(unpersistable_atom) - sxp.append(reason) - return sxp - - - -class _Unjellier: - - def __init__(self, taster, persistentLoad, invoker): - self.taster = taster - self.persistentLoad = persistentLoad - self.references = {} - self.postCallbacks = [] - self.invoker = invoker - - - def unjellyFull(self, obj): - o = self.unjelly(obj) - for m in self.postCallbacks: - m() - return o - - - def unjelly(self, obj): - if type(obj) is not types.ListType: - return obj - jelType = obj[0] - if not self.taster.isTypeAllowed(jelType): - raise InsecureJelly(jelType) - regClass = unjellyableRegistry.get(jelType) - if regClass is not None: - if isinstance(regClass, ClassType): - inst = _Dummy() # XXX chomp, chomp - inst.__class__ = regClass - method = inst.unjellyFor - elif isinstance(regClass, type): - # regClass.__new__ does not call regClass.__init__ - inst = regClass.__new__(regClass) - method = inst.unjellyFor - else: - method = regClass # this is how it ought to be done - val = method(self, obj) - if hasattr(val, 'postUnjelly'): - self.postCallbacks.append(inst.postUnjelly) - return val - regFactory = unjellyableFactoryRegistry.get(jelType) - if regFactory is not None: - state = self.unjelly(obj[1]) - inst = regFactory(state) - if hasattr(inst, 'postUnjelly'): - self.postCallbacks.append(inst.postUnjelly) - return inst - thunk = getattr(self, '_unjelly_%s'%jelType, None) - if thunk is not None: - ret = thunk(obj[1:]) - else: - nameSplit = jelType.split('.') - modName = '.'.join(nameSplit[:-1]) - if not self.taster.isModuleAllowed(modName): - raise InsecureJelly( - "Module %s not allowed (in type %s)." % (modName, jelType)) - clz = namedObject(jelType) - if not self.taster.isClassAllowed(clz): - raise InsecureJelly("Class %s not allowed." % jelType) - if hasattr(clz, "__setstate__"): - ret = _newInstance(clz) - state = self.unjelly(obj[1]) - ret.__setstate__(state) - else: - state = self.unjelly(obj[1]) - ret = _newInstance(clz, state) - if hasattr(clz, 'postUnjelly'): - self.postCallbacks.append(ret.postUnjelly) - return ret - - - def _unjelly_None(self, exp): - return None - - - def _unjelly_unicode(self, exp): - return unicode(exp[0], "UTF-8") - - - def _unjelly_decimal(self, exp): - """ - Unjelly decimal objects. - """ - value = exp[0] - exponent = exp[1] - if value < 0: - sign = 1 - else: - sign = 0 - guts = decimal.Decimal(value).as_tuple()[1] - return decimal.Decimal((sign, guts, exponent)) - - - def _unjelly_boolean(self, exp): - if BooleanType: - assert exp[0] in ('true', 'false') - return exp[0] == 'true' - else: - return Unpersistable("Could not unpersist boolean: %s" % (exp[0],)) - - - def _unjelly_datetime(self, exp): - return datetime.datetime(*map(int, exp[0].split())) - - - def _unjelly_date(self, exp): - return datetime.date(*map(int, exp[0].split())) - - - def _unjelly_time(self, exp): - return datetime.time(*map(int, exp[0].split())) - - - def _unjelly_timedelta(self, exp): - days, seconds, microseconds = map(int, exp[0].split()) - return datetime.timedelta( - days=days, seconds=seconds, microseconds=microseconds) - - - def unjellyInto(self, obj, loc, jel): - o = self.unjelly(jel) - if isinstance(o, NotKnown): - o.addDependant(obj, loc) - obj[loc] = o - return o - - - def _unjelly_dereference(self, lst): - refid = lst[0] - x = self.references.get(refid) - if x is not None: - return x - der = _Dereference(refid) - self.references[refid] = der - return der - - - def _unjelly_reference(self, lst): - refid = lst[0] - exp = lst[1] - o = self.unjelly(exp) - ref = self.references.get(refid) - if (ref is None): - self.references[refid] = o - elif isinstance(ref, NotKnown): - ref.resolveDependants(o) - self.references[refid] = o - else: - assert 0, "Multiple references with same ID!" - return o - - - def _unjelly_tuple(self, lst): - l = range(len(lst)) - finished = 1 - for elem in l: - if isinstance(self.unjellyInto(l, elem, lst[elem]), NotKnown): - finished = 0 - if finished: - return tuple(l) - else: - return _Tuple(l) - - - def _unjelly_list(self, lst): - l = range(len(lst)) - for elem in l: - self.unjellyInto(l, elem, lst[elem]) - return l - - - def _unjellySetOrFrozenset(self, lst, containerType): - """ - Helper method to unjelly set or frozenset. - - @param lst: the content of the set. - @type lst: C{list} - - @param containerType: the type of C{set} to use. - """ - l = range(len(lst)) - finished = True - for elem in l: - data = self.unjellyInto(l, elem, lst[elem]) - if isinstance(data, NotKnown): - finished = False - if not finished: - return _Container(l, containerType) - else: - return containerType(l) - - - def _unjelly_set(self, lst): - """ - Unjelly set using the C{set} builtin. - """ - return self._unjellySetOrFrozenset(lst, set) - - - def _unjelly_frozenset(self, lst): - """ - Unjelly frozenset using the C{frozenset} builtin. - """ - return self._unjellySetOrFrozenset(lst, frozenset) - - - def _unjelly_dictionary(self, lst): - d = {} - for k, v in lst: - kvd = _DictKeyAndValue(d) - self.unjellyInto(kvd, 0, k) - self.unjellyInto(kvd, 1, v) - return d - - - def _unjelly_module(self, rest): - moduleName = rest[0] - if type(moduleName) != types.StringType: - raise InsecureJelly( - "Attempted to unjelly a module with a non-string name.") - if not self.taster.isModuleAllowed(moduleName): - raise InsecureJelly( - "Attempted to unjelly module named %r" % (moduleName,)) - mod = __import__(moduleName, {}, {},"x") - return mod - - - def _unjelly_class(self, rest): - clist = rest[0].split('.') - modName = '.'.join(clist[:-1]) - if not self.taster.isModuleAllowed(modName): - raise InsecureJelly("module %s not allowed" % modName) - klaus = namedObject(rest[0]) - objType = type(klaus) - if objType not in (types.ClassType, types.TypeType): - raise InsecureJelly( - "class %r unjellied to something that isn't a class: %r" % ( - rest[0], klaus)) - if not self.taster.isClassAllowed(klaus): - raise InsecureJelly("class not allowed: %s" % qual(klaus)) - return klaus - - - def _unjelly_function(self, rest): - modSplit = rest[0].split('.') - modName = '.'.join(modSplit[:-1]) - if not self.taster.isModuleAllowed(modName): - raise InsecureJelly("Module not allowed: %s"% modName) - # XXX do I need an isFunctionAllowed? - function = namedObject(rest[0]) - return function - - - def _unjelly_persistent(self, rest): - if self.persistentLoad: - pload = self.persistentLoad(rest[0], self) - return pload - else: - return Unpersistable("Persistent callback not found") - - - def _unjelly_instance(self, rest): - """ - (internal) Unjelly an instance. - - Called to handle the deprecated I{instance} token. - - @param rest: The s-expression representing the instance. - - @return: The unjellied instance. - """ - warnings.warn_explicit( - "Unjelly support for the instance atom is deprecated since " - "Twisted 15.0.0. Upgrade peer for modern instance support.", - category=DeprecationWarning, filename="", lineno=0) - - clz = self.unjelly(rest[0]) - if type(clz) is not types.ClassType: - raise InsecureJelly("Instance found with non-class class.") - if hasattr(clz, "__setstate__"): - inst = _newInstance(clz, {}) - state = self.unjelly(rest[1]) - inst.__setstate__(state) - else: - state = self.unjelly(rest[1]) - inst = _newInstance(clz, state) - if hasattr(clz, 'postUnjelly'): - self.postCallbacks.append(inst.postUnjelly) - return inst - - - def _unjelly_unpersistable(self, rest): - return Unpersistable("Unpersistable data: %s" % (rest[0],)) - - - def _unjelly_method(self, rest): - """ - (internal) Unjelly a method. - """ - im_name = rest[0] - im_self = self.unjelly(rest[1]) - im_class = self.unjelly(rest[2]) - if type(im_class) is not types.ClassType: - raise InsecureJelly("Method found with non-class class.") - if im_name in im_class.__dict__: - if im_self is None: - im = getattr(im_class, im_name) - elif isinstance(im_self, NotKnown): - im = _InstanceMethod(im_name, im_self, im_class) - else: - im = MethodType(im_class.__dict__[im_name], im_self, im_class) - else: - raise TypeError('instance method changed') - return im - - - -class _Dummy: - """ - (Internal) Dummy class, used for unserializing instances. - """ - - - -class _DummyNewStyle(object): - """ - (Internal) Dummy class, used for unserializing instances of new-style - classes. - """ - - -def _newDummyLike(instance): - """ - Create a new instance like C{instance}. - - The new instance has the same class and instance dictionary as the given - instance. - - @return: The new instance. - """ - if isinstance(instance.__class__, type): - # New-style class - dummy = _DummyNewStyle() - else: - # Classic class - dummy = _Dummy() - dummy.__class__ = instance.__class__ - dummy.__dict__ = instance.__dict__ - return dummy - - -#### Published Interface. - - -class InsecureJelly(Exception): - """ - This exception will be raised when a jelly is deemed `insecure'; e.g. it - contains a type, class, or module disallowed by the specified `taster' - """ - - - -class DummySecurityOptions: - """ - DummySecurityOptions() -> insecure security options - Dummy security options -- this class will allow anything. - """ - - def isModuleAllowed(self, moduleName): - """ - DummySecurityOptions.isModuleAllowed(moduleName) -> boolean - returns 1 if a module by that name is allowed, 0 otherwise - """ - return 1 - - - def isClassAllowed(self, klass): - """ - DummySecurityOptions.isClassAllowed(class) -> boolean - Assumes the module has already been allowed. Returns 1 if the given - class is allowed, 0 otherwise. - """ - return 1 - - - def isTypeAllowed(self, typeName): - """ - DummySecurityOptions.isTypeAllowed(typeName) -> boolean - Returns 1 if the given type is allowed, 0 otherwise. - """ - return 1 - - - -class SecurityOptions: - """ - This will by default disallow everything, except for 'none'. - """ - - basicTypes = ["dictionary", "list", "tuple", - "reference", "dereference", "unpersistable", - "persistent", "long_int", "long", "dict"] - - def __init__(self): - """ - SecurityOptions() initialize. - """ - # I don't believe any of these types can ever pose a security hazard, - # except perhaps "reference"... - self.allowedTypes = {"None": 1, - "bool": 1, - "boolean": 1, - "string": 1, - "str": 1, - "int": 1, - "float": 1, - "datetime": 1, - "time": 1, - "date": 1, - "timedelta": 1, - "NoneType": 1} - self.allowedTypes['unicode'] = 1 - self.allowedTypes['decimal'] = 1 - self.allowedTypes['set'] = 1 - self.allowedTypes['frozenset'] = 1 - self.allowedModules = {} - self.allowedClasses = {} - - - def allowBasicTypes(self): - """ - Allow all `basic' types. (Dictionary and list. Int, string, and float - are implicitly allowed.) - """ - self.allowTypes(*self.basicTypes) - - - def allowTypes(self, *types): - """ - SecurityOptions.allowTypes(typeString): Allow a particular type, by its - name. - """ - for typ in types: - if not isinstance(typ, str): - typ = qual(typ) - self.allowedTypes[typ] = 1 - - - def allowInstancesOf(self, *classes): - """ - SecurityOptions.allowInstances(klass, klass, ...): allow instances - of the specified classes - - This will also allow the 'instance', 'class' (renamed 'classobj' in - Python 2.3), and 'module' types, as well as basic types. - """ - self.allowBasicTypes() - self.allowTypes("instance", "class", "classobj", "module") - for klass in classes: - self.allowTypes(qual(klass)) - self.allowModules(klass.__module__) - self.allowedClasses[klass] = 1 - - - def allowModules(self, *modules): - """ - SecurityOptions.allowModules(module, module, ...): allow modules by - name. This will also allow the 'module' type. - """ - for module in modules: - if type(module) == types.ModuleType: - module = module.__name__ - self.allowedModules[module] = 1 - - - def isModuleAllowed(self, moduleName): - """ - SecurityOptions.isModuleAllowed(moduleName) -> boolean - returns 1 if a module by that name is allowed, 0 otherwise - """ - return moduleName in self.allowedModules - - - def isClassAllowed(self, klass): - """ - SecurityOptions.isClassAllowed(class) -> boolean - Assumes the module has already been allowed. Returns 1 if the given - class is allowed, 0 otherwise. - """ - return klass in self.allowedClasses - - - def isTypeAllowed(self, typeName): - """ - SecurityOptions.isTypeAllowed(typeName) -> boolean - Returns 1 if the given type is allowed, 0 otherwise. - """ - return (typeName in self.allowedTypes or '.' in typeName) - - -globalSecurity = SecurityOptions() -globalSecurity.allowBasicTypes() - - - -def jelly(object, taster=DummySecurityOptions(), persistentStore=None, - invoker=None): - """ - Serialize to s-expression. - - Returns a list which is the serialized representation of an object. An - optional 'taster' argument takes a SecurityOptions and will mark any - insecure objects as unpersistable rather than serializing them. - """ - return _Jellier(taster, persistentStore, invoker).jelly(object) - - - -def unjelly(sexp, taster=DummySecurityOptions(), persistentLoad=None, - invoker=None): - """ - Unserialize from s-expression. - - Takes an list that was the result from a call to jelly() and unserializes - an arbitrary object from it. The optional 'taster' argument, an instance - of SecurityOptions, will cause an InsecureJelly exception to be raised if a - disallowed type, module, or class attempted to unserialize. - """ - return _Unjellier(taster, persistentLoad, invoker).unjellyFull(sexp) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/pb.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/pb.py deleted file mode 100644 index 548c6a7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/pb.py +++ /dev/null @@ -1,1430 +0,0 @@ -# -*- test-case-name: twisted.test.test_pb -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Perspective Broker - -\"This isn\'t a professional opinion, but it's probably got enough -internet to kill you.\" --glyph - -Introduction -============ - -This is a broker for proxies for and copies of objects. It provides a -translucent interface layer to those proxies. - -The protocol is not opaque, because it provides objects which represent the -remote proxies and require no context (server references, IDs) to operate on. - -It is not transparent because it does I{not} attempt to make remote objects -behave identically, or even similarly, to local objects. Method calls are -invoked asynchronously, and specific rules are applied when serializing -arguments. - -To get started, begin with L{PBClientFactory} and L{PBServerFactory}. - -@author: Glyph Lefkowitz -""" - -import random -import types -from hashlib import md5 - -from zope.interface import implementer, Interface - -# Twisted Imports -from twisted.python import log, failure, reflect -from twisted.internet import defer, protocol -from twisted.cred.portal import Portal -from twisted.cred.credentials import IAnonymous, ICredentials -from twisted.cred.credentials import IUsernameHashedPassword, Anonymous -from twisted.persisted import styles -from twisted.python.components import registerAdapter - -from twisted.spread.interfaces import IJellyable, IUnjellyable -from twisted.spread.jelly import jelly, unjelly, globalSecurity -from twisted.spread import banana - -from twisted.spread.flavors import Serializable -from twisted.spread.flavors import Referenceable, NoSuchMethod -from twisted.spread.flavors import Root, IPBRoot -from twisted.spread.flavors import ViewPoint -from twisted.spread.flavors import Viewable -from twisted.spread.flavors import Copyable -from twisted.spread.flavors import Jellyable -from twisted.spread.flavors import Cacheable -from twisted.spread.flavors import RemoteCopy -from twisted.spread.flavors import RemoteCache -from twisted.spread.flavors import RemoteCacheObserver -from twisted.spread.flavors import copyTags - -from twisted.spread.flavors import setUnjellyableForClass -from twisted.spread.flavors import setUnjellyableFactoryForClass -from twisted.spread.flavors import setUnjellyableForClassTree -# These three are backwards compatibility aliases for the previous three. -# Ultimately they should be deprecated. -exarkun -from twisted.spread.flavors import setCopierForClass -from twisted.spread.flavors import setFactoryForClass -from twisted.spread.flavors import setCopierForClassTree - - -MAX_BROKER_REFS = 1024 - -portno = 8787 - - - -class ProtocolError(Exception): - """ - This error is raised when an invalid protocol statement is received. - """ - - - -class DeadReferenceError(ProtocolError): - """ - This error is raised when a method is called on a dead reference (one whose - broker has been disconnected). - """ - - - -class Error(Exception): - """ - This error can be raised to generate known error conditions. - - When a PB callable method (perspective_, remote_, view_) raises - this error, it indicates that a traceback should not be printed, - but instead, the string representation of the exception should be - sent. - """ - - - -class RemoteError(Exception): - """ - This class is used to wrap a string-ified exception from the remote side to - be able to reraise it. (Raising string exceptions is no longer possible in - Python 2.6+) - - The value of this exception will be a str() representation of the remote - value. - - @ivar remoteType: The full import path of the exception class which was - raised on the remote end. - @type remoteType: C{str} - - @ivar remoteTraceback: The remote traceback. - @type remoteTraceback: C{str} - - @note: It's not possible to include the remoteTraceback if this exception is - thrown into a generator. It must be accessed as an attribute. - """ - def __init__(self, remoteType, value, remoteTraceback): - Exception.__init__(self, value) - self.remoteType = remoteType - self.remoteTraceback = remoteTraceback - - - -class RemoteMethod: - """ - This is a translucent reference to a remote message. - """ - def __init__(self, obj, name): - """ - Initialize with a L{RemoteReference} and the name of this message. - """ - self.obj = obj - self.name = name - - - def __cmp__(self, other): - return cmp((self.obj, self.name), other) - - - def __hash__(self): - return hash((self.obj, self.name)) - - - def __call__(self, *args, **kw): - """ - Asynchronously invoke a remote method. - """ - return self.obj.broker._sendMessage('',self.obj.perspective, - self.obj.luid, self.name, args, kw) - - - -class PBConnectionLost(Exception): - pass - - - -class IPerspective(Interface): - """ - per*spec*tive, n. : The relationship of aspects of a subject to each - other and to a whole: 'a perspective of history'; 'a need to view - the problem in the proper perspective'. - - This is a Perspective Broker-specific wrapper for an avatar. That - is to say, a PB-published view on to the business logic for the - system's concept of a 'user'. - - The concept of attached/detached is no longer implemented by the - framework. The realm is expected to implement such semantics if - needed. - """ - - def perspectiveMessageReceived(broker, message, args, kwargs): - """ - This method is called when a network message is received. - - @arg broker: The Perspective Broker. - - @type message: str - @arg message: The name of the method called by the other end. - - @type args: list in jelly format - @arg args: The arguments that were passed by the other end. It - is recommend that you use the `unserialize' method of the - broker to decode this. - - @type kwargs: dict in jelly format - @arg kwargs: The keyword arguments that were passed by the - other end. It is recommended that you use the - `unserialize' method of the broker to decode this. - - @rtype: A jelly list. - @return: It is recommended that you use the `serialize' method - of the broker on whatever object you need to return to - generate the return value. - """ - - - -@implementer(IPerspective) -class Avatar: - """ - A default IPerspective implementor. - - This class is intended to be subclassed, and a realm should return - an instance of such a subclass when IPerspective is requested of - it. - - A peer requesting a perspective will receive only a - L{RemoteReference} to a pb.Avatar. When a method is called on - that L{RemoteReference}, it will translate to a method on the - remote perspective named 'perspective_methodname'. (For more - information on invoking methods on other objects, see - L{flavors.ViewPoint}.) - """ - - def perspectiveMessageReceived(self, broker, message, args, kw): - """ - This method is called when a network message is received. - - This will call:: - - self.perspective_%(message)s(*broker.unserialize(args), - **broker.unserialize(kw)) - - to handle the method; subclasses of Avatar are expected to - implement methods using this naming convention. - """ - - args = broker.unserialize(args, self) - kw = broker.unserialize(kw, self) - method = getattr(self, "perspective_%s" % message) - try: - state = method(*args, **kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - return broker.serialize(state, self, method, args, kw) - - - -class AsReferenceable(Referenceable): - """ - A reference directed towards another object. - """ - - def __init__(self, object, messageType="remote"): - self.remoteMessageReceived = getattr( - object, messageType + "MessageReceived") - - - -@implementer(IUnjellyable) -class RemoteReference(Serializable, styles.Ephemeral): - """ - A translucent reference to a remote object. - - I may be a reference to a L{flavors.ViewPoint}, a - L{flavors.Referenceable}, or an L{IPerspective} implementer (e.g., - pb.Avatar). From the client's perspective, it is not possible to - tell which except by convention. - - I am a \"translucent\" reference because although no additional - bookkeeping overhead is given to the application programmer for - manipulating a reference, return values are asynchronous. - - See also L{twisted.internet.defer}. - - @ivar broker: The broker I am obtained through. - @type broker: L{Broker} - """ - - def __init__(self, perspective, broker, luid, doRefCount): - """(internal) Initialize me with a broker and a locally-unique ID. - - The ID is unique only to the particular Perspective Broker - instance. - """ - self.luid = luid - self.broker = broker - self.doRefCount = doRefCount - self.perspective = perspective - self.disconnectCallbacks = [] - - def notifyOnDisconnect(self, callback): - """Register a callback to be called if our broker gets disconnected. - - This callback will be called with one argument, this instance. - """ - assert callable(callback) - self.disconnectCallbacks.append(callback) - if len(self.disconnectCallbacks) == 1: - self.broker.notifyOnDisconnect(self._disconnected) - - def dontNotifyOnDisconnect(self, callback): - """Remove a callback that was registered with notifyOnDisconnect.""" - self.disconnectCallbacks.remove(callback) - if not self.disconnectCallbacks: - self.broker.dontNotifyOnDisconnect(self._disconnected) - - def _disconnected(self): - """Called if we are disconnected and have callbacks registered.""" - for callback in self.disconnectCallbacks: - callback(self) - self.disconnectCallbacks = None - - def jellyFor(self, jellier): - """If I am being sent back to where I came from, serialize as a local backreference. - """ - if jellier.invoker: - assert self.broker == jellier.invoker, "Can't send references to brokers other than their own." - return "local", self.luid - else: - return "unpersistable", "References cannot be serialized" - - def unjellyFor(self, unjellier, unjellyList): - self.__init__(unjellier.invoker.unserializingPerspective, unjellier.invoker, unjellyList[1], 1) - return self - - def callRemote(self, _name, *args, **kw): - """Asynchronously invoke a remote method. - - @type _name: C{str} - @param _name: the name of the remote method to invoke - @param args: arguments to serialize for the remote function - @param kw: keyword arguments to serialize for the remote function. - @rtype: L{twisted.internet.defer.Deferred} - @returns: a Deferred which will be fired when the result of - this remote call is received. - """ - # note that we use '_name' instead of 'name' so the user can call - # remote methods with 'name' as a keyword parameter, like this: - # ref.callRemote("getPeopleNamed", count=12, name="Bob") - - return self.broker._sendMessage('',self.perspective, self.luid, - _name, args, kw) - - def remoteMethod(self, key): - """Get a L{RemoteMethod} for this key. - """ - return RemoteMethod(self, key) - - def __cmp__(self,other): - """Compare me [to another L{RemoteReference}]. - """ - if isinstance(other, RemoteReference): - if other.broker == self.broker: - return cmp(self.luid, other.luid) - return cmp(self.broker, other) - - def __hash__(self): - """Hash me. - """ - return self.luid - - def __del__(self): - """Do distributed reference counting on finalization. - """ - if self.doRefCount: - self.broker.sendDecRef(self.luid) - -setUnjellyableForClass("remote", RemoteReference) - -class Local: - """(internal) A reference to a local object. - """ - - def __init__(self, object, perspective=None): - """Initialize. - """ - self.object = object - self.perspective = perspective - self.refcount = 1 - - def __repr__(self): - return "" % (self.object, self.refcount) - - def incref(self): - """Increment and return my reference count. - """ - self.refcount = self.refcount + 1 - return self.refcount - - def decref(self): - """Decrement and return my reference count. - """ - self.refcount = self.refcount - 1 - return self.refcount - - -## -# Failure -## - -class CopyableFailure(failure.Failure, Copyable): - """ - A L{flavors.RemoteCopy} and L{flavors.Copyable} version of - L{twisted.python.failure.Failure} for serialization. - """ - - unsafeTracebacks = 0 - - def getStateToCopy(self): - """ - Collect state related to the exception which occurred, discarding - state which cannot reasonably be serialized. - """ - state = self.__dict__.copy() - state['tb'] = None - state['frames'] = [] - state['stack'] = [] - state['value'] = str(self.value) # Exception instance - if isinstance(self.type, str): - state['type'] = self.type - else: - state['type'] = reflect.qual(self.type) # Exception class - if self.unsafeTracebacks: - state['traceback'] = self.getTraceback() - else: - state['traceback'] = 'Traceback unavailable\n' - return state - - - -class CopiedFailure(RemoteCopy, failure.Failure): - """ - A L{CopiedFailure} is a L{pb.RemoteCopy} of a L{failure.Failure} - transferred via PB. - - @ivar type: The full import path of the exception class which was raised on - the remote end. - @type type: C{str} - - @ivar value: A str() representation of the remote value. - @type value: L{CopiedFailure} or C{str} - - @ivar traceback: The remote traceback. - @type traceback: C{str} - """ - - def printTraceback(self, file=None, elideFrameworkCode=0, detail='default'): - if file is None: - file = log.logfile - file.write("Traceback from remote host -- ") - file.write(self.traceback) - file.write(self.type + ": " + self.value) - file.write('\n') - - - def throwExceptionIntoGenerator(self, g): - """ - Throw the original exception into the given generator, preserving - traceback information if available. In the case of a L{CopiedFailure} - where the exception type is a string, a L{pb.RemoteError} is thrown - instead. - - @return: The next value yielded from the generator. - @raise StopIteration: If there are no more values in the generator. - @raise RemoteError: The wrapped remote exception. - """ - return g.throw(RemoteError(self.type, self.value, self.traceback)) - - printBriefTraceback = printTraceback - printDetailedTraceback = printTraceback - -setUnjellyableForClass(CopyableFailure, CopiedFailure) - - - -def failure2Copyable(fail, unsafeTracebacks=0): - f = types.InstanceType(CopyableFailure, fail.__dict__) - f.unsafeTracebacks = unsafeTracebacks - return f - - - -class Broker(banana.Banana): - """I am a broker for objects. - """ - - version = 6 - username = None - factory = None - - def __init__(self, isClient=1, security=globalSecurity): - banana.Banana.__init__(self, isClient) - self.disconnected = 0 - self.disconnects = [] - self.failures = [] - self.connects = [] - self.localObjects = {} - self.security = security - self.pageProducers = [] - self.currentRequestID = 0 - self.currentLocalID = 0 - self.unserializingPerspective = None - # Some terms: - # PUID: process unique ID; return value of id() function. type "int". - # LUID: locally unique ID; an ID unique to an object mapped over this - # connection. type "int" - # GUID: (not used yet) globally unique ID; an ID for an object which - # may be on a redirected or meta server. Type as yet undecided. - # Dictionary mapping LUIDs to local objects. - # set above to allow root object to be assigned before connection is made - # self.localObjects = {} - # Dictionary mapping PUIDs to LUIDs. - self.luids = {} - # Dictionary mapping LUIDs to local (remotely cached) objects. Remotely - # cached means that they're objects which originate here, and were - # copied remotely. - self.remotelyCachedObjects = {} - # Dictionary mapping PUIDs to (cached) LUIDs - self.remotelyCachedLUIDs = {} - # Dictionary mapping (remote) LUIDs to (locally cached) objects. - self.locallyCachedObjects = {} - self.waitingForAnswers = {} - - # Mapping from LUIDs to weakref objects with callbacks for performing - # any local cleanup which may be necessary for the corresponding - # object once it no longer exists. - self._localCleanup = {} - - - def resumeProducing(self): - """Called when the consumer attached to me runs out of buffer. - """ - # Go backwards over the list so we can remove indexes from it as we go - for pageridx in xrange(len(self.pageProducers)-1, -1, -1): - pager = self.pageProducers[pageridx] - pager.sendNextPage() - if not pager.stillPaging(): - del self.pageProducers[pageridx] - if not self.pageProducers: - self.transport.unregisterProducer() - - # Streaming producer methods; not necessary to implement. - def pauseProducing(self): - pass - - def stopProducing(self): - pass - - def registerPageProducer(self, pager): - self.pageProducers.append(pager) - if len(self.pageProducers) == 1: - self.transport.registerProducer(self, 0) - - def expressionReceived(self, sexp): - """Evaluate an expression as it's received. - """ - if isinstance(sexp, types.ListType): - command = sexp[0] - methodName = "proto_%s" % command - method = getattr(self, methodName, None) - if method: - method(*sexp[1:]) - else: - self.sendCall("didNotUnderstand", command) - else: - raise ProtocolError("Non-list expression received.") - - - def proto_version(self, vnum): - """Protocol message: (version version-number) - - Check to make sure that both ends of the protocol are speaking - the same version dialect. - """ - - if vnum != self.version: - raise ProtocolError("Version Incompatibility: %s %s" % (self.version, vnum)) - - - def sendCall(self, *exp): - """Utility method to send an expression to the other side of the connection. - """ - self.sendEncoded(exp) - - def proto_didNotUnderstand(self, command): - """Respond to stock 'C{didNotUnderstand}' message. - - Log the command that was not understood and continue. (Note: - this will probably be changed to close the connection or raise - an exception in the future.) - """ - log.msg("Didn't understand command: %r" % command) - - def connectionReady(self): - """Initialize. Called after Banana negotiation is done. - """ - self.sendCall("version", self.version) - for notifier in self.connects: - try: - notifier() - except: - log.deferr() - self.connects = None - if self.factory: # in tests we won't have factory - self.factory.clientConnectionMade(self) - - def connectionFailed(self): - # XXX should never get called anymore? check! - for notifier in self.failures: - try: - notifier() - except: - log.deferr() - self.failures = None - - waitingForAnswers = None - - def connectionLost(self, reason): - """The connection was lost. - """ - self.disconnected = 1 - # nuke potential circular references. - self.luids = None - if self.waitingForAnswers: - for d in self.waitingForAnswers.values(): - try: - d.errback(failure.Failure(PBConnectionLost(reason))) - except: - log.deferr() - # Assure all Cacheable.stoppedObserving are called - for lobj in self.remotelyCachedObjects.values(): - cacheable = lobj.object - perspective = lobj.perspective - try: - cacheable.stoppedObserving(perspective, RemoteCacheObserver(self, cacheable, perspective)) - except: - log.deferr() - # Loop on a copy to prevent notifiers to mixup - # the list by calling dontNotifyOnDisconnect - for notifier in self.disconnects[:]: - try: - notifier() - except: - log.deferr() - self.disconnects = None - self.waitingForAnswers = None - self.localSecurity = None - self.remoteSecurity = None - self.remotelyCachedObjects = None - self.remotelyCachedLUIDs = None - self.locallyCachedObjects = None - self.localObjects = None - - def notifyOnDisconnect(self, notifier): - """Call the given callback when the Broker disconnects.""" - assert callable(notifier) - self.disconnects.append(notifier) - - def notifyOnFail(self, notifier): - """Call the given callback if the Broker fails to connect.""" - assert callable(notifier) - self.failures.append(notifier) - - def notifyOnConnect(self, notifier): - """Call the given callback when the Broker connects.""" - assert callable(notifier) - if self.connects is None: - try: - notifier() - except: - log.err() - else: - self.connects.append(notifier) - - def dontNotifyOnDisconnect(self, notifier): - """Remove a callback from list of disconnect callbacks.""" - try: - self.disconnects.remove(notifier) - except ValueError: - pass - - def localObjectForID(self, luid): - """ - Get a local object for a locally unique ID. - - @return: An object previously stored with L{registerReference} or - C{None} if there is no object which corresponds to the given - identifier. - """ - lob = self.localObjects.get(luid) - if lob is None: - return - return lob.object - - maxBrokerRefsViolations = 0 - - def registerReference(self, object): - """Get an ID for a local object. - - Store a persistent reference to a local object and map its id() - to a generated, session-unique ID and return that ID. - """ - - assert object is not None - puid = object.processUniqueID() - luid = self.luids.get(puid) - if luid is None: - if len(self.localObjects) > MAX_BROKER_REFS: - self.maxBrokerRefsViolations = self.maxBrokerRefsViolations + 1 - if self.maxBrokerRefsViolations > 3: - self.transport.loseConnection() - raise Error("Maximum PB reference count exceeded. " - "Goodbye.") - raise Error("Maximum PB reference count exceeded.") - - luid = self.newLocalID() - self.localObjects[luid] = Local(object) - self.luids[puid] = luid - else: - self.localObjects[luid].incref() - return luid - - def setNameForLocal(self, name, object): - """Store a special (string) ID for this object. - - This is how you specify a 'base' set of objects that the remote - protocol can connect to. - """ - assert object is not None - self.localObjects[name] = Local(object) - - def remoteForName(self, name): - """Returns an object from the remote name mapping. - - Note that this does not check the validity of the name, only - creates a translucent reference for it. - """ - return RemoteReference(None, self, name, 0) - - def cachedRemotelyAs(self, instance, incref=0): - """Returns an ID that says what this instance is cached as remotely, or C{None} if it's not. - """ - - puid = instance.processUniqueID() - luid = self.remotelyCachedLUIDs.get(puid) - if (luid is not None) and (incref): - self.remotelyCachedObjects[luid].incref() - return luid - - def remotelyCachedForLUID(self, luid): - """Returns an instance which is cached remotely, with this LUID. - """ - return self.remotelyCachedObjects[luid].object - - def cacheRemotely(self, instance): - """ - XXX""" - puid = instance.processUniqueID() - luid = self.newLocalID() - if len(self.remotelyCachedObjects) > MAX_BROKER_REFS: - self.maxBrokerRefsViolations = self.maxBrokerRefsViolations + 1 - if self.maxBrokerRefsViolations > 3: - self.transport.loseConnection() - raise Error("Maximum PB cache count exceeded. " - "Goodbye.") - raise Error("Maximum PB cache count exceeded.") - - self.remotelyCachedLUIDs[puid] = luid - # This table may not be necessary -- for now, it's to make sure that no - # monkey business happens with id(instance) - self.remotelyCachedObjects[luid] = Local(instance, self.serializingPerspective) - return luid - - def cacheLocally(self, cid, instance): - """(internal) - - Store a non-filled-out cached instance locally. - """ - self.locallyCachedObjects[cid] = instance - - def cachedLocallyAs(self, cid): - instance = self.locallyCachedObjects[cid] - return instance - - def serialize(self, object, perspective=None, method=None, args=None, kw=None): - """Jelly an object according to the remote security rules for this broker. - """ - - if isinstance(object, defer.Deferred): - object.addCallbacks(self.serialize, lambda x: x, - callbackKeywords={ - 'perspective': perspective, - 'method': method, - 'args': args, - 'kw': kw - }) - return object - - # XXX This call is NOT REENTRANT and testing for reentrancy is just - # crazy, so it likely won't be. Don't ever write methods that call the - # broker's serialize() method recursively (e.g. sending a method call - # from within a getState (this causes concurrency problems anyway so - # you really, really shouldn't do it)) - - # self.jellier = _NetJellier(self) - self.serializingPerspective = perspective - self.jellyMethod = method - self.jellyArgs = args - self.jellyKw = kw - try: - return jelly(object, self.security, None, self) - finally: - self.serializingPerspective = None - self.jellyMethod = None - self.jellyArgs = None - self.jellyKw = None - - def unserialize(self, sexp, perspective = None): - """Unjelly an sexp according to the local security rules for this broker. - """ - - self.unserializingPerspective = perspective - try: - return unjelly(sexp, self.security, None, self) - finally: - self.unserializingPerspective = None - - def newLocalID(self): - """Generate a new LUID. - """ - self.currentLocalID = self.currentLocalID + 1 - return self.currentLocalID - - def newRequestID(self): - """Generate a new request ID. - """ - self.currentRequestID = self.currentRequestID + 1 - return self.currentRequestID - - def _sendMessage(self, prefix, perspective, objectID, message, args, kw): - pbc = None - pbe = None - answerRequired = 1 - if 'pbcallback' in kw: - pbc = kw['pbcallback'] - del kw['pbcallback'] - if 'pberrback' in kw: - pbe = kw['pberrback'] - del kw['pberrback'] - if 'pbanswer' in kw: - assert (not pbe) and (not pbc), "You can't specify a no-answer requirement." - answerRequired = kw['pbanswer'] - del kw['pbanswer'] - if self.disconnected: - raise DeadReferenceError("Calling Stale Broker") - try: - netArgs = self.serialize(args, perspective=perspective, method=message) - netKw = self.serialize(kw, perspective=perspective, method=message) - except: - return defer.fail(failure.Failure()) - requestID = self.newRequestID() - if answerRequired: - rval = defer.Deferred() - self.waitingForAnswers[requestID] = rval - if pbc or pbe: - log.msg('warning! using deprecated "pbcallback"') - rval.addCallbacks(pbc, pbe) - else: - rval = None - self.sendCall(prefix+"message", requestID, objectID, message, answerRequired, netArgs, netKw) - return rval - - def proto_message(self, requestID, objectID, message, answerRequired, netArgs, netKw): - self._recvMessage(self.localObjectForID, requestID, objectID, message, answerRequired, netArgs, netKw) - def proto_cachemessage(self, requestID, objectID, message, answerRequired, netArgs, netKw): - self._recvMessage(self.cachedLocallyAs, requestID, objectID, message, answerRequired, netArgs, netKw) - - def _recvMessage(self, findObjMethod, requestID, objectID, message, answerRequired, netArgs, netKw): - """Received a message-send. - - Look up message based on object, unserialize the arguments, and - invoke it with args, and send an 'answer' or 'error' response. - """ - try: - object = findObjMethod(objectID) - if object is None: - raise Error("Invalid Object ID") - netResult = object.remoteMessageReceived(self, message, netArgs, netKw) - except Error, e: - if answerRequired: - # If the error is Jellyable or explicitly allowed via our - # security options, send it back and let the code on the - # other end deal with unjellying. If it isn't Jellyable, - # wrap it in a CopyableFailure, which ensures it can be - # unjellied on the other end. We have to do this because - # all errors must be sent back. - if isinstance(e, Jellyable) or self.security.isClassAllowed(e.__class__): - self._sendError(e, requestID) - else: - self._sendError(CopyableFailure(e), requestID) - except: - if answerRequired: - log.msg("Peer will receive following PB traceback:", isError=True) - f = CopyableFailure() - self._sendError(f, requestID) - log.err() - else: - if answerRequired: - if isinstance(netResult, defer.Deferred): - args = (requestID,) - netResult.addCallbacks(self._sendAnswer, self._sendFailureOrError, - callbackArgs=args, errbackArgs=args) - # XXX Should this be done somewhere else? - else: - self._sendAnswer(netResult, requestID) - ## - # success - ## - - def _sendAnswer(self, netResult, requestID): - """(internal) Send an answer to a previously sent message. - """ - self.sendCall("answer", requestID, netResult) - - def proto_answer(self, requestID, netResult): - """(internal) Got an answer to a previously sent message. - - Look up the appropriate callback and call it. - """ - d = self.waitingForAnswers[requestID] - del self.waitingForAnswers[requestID] - d.callback(self.unserialize(netResult)) - - ## - # failure - ## - def _sendFailureOrError(self, fail, requestID): - """ - Call L{_sendError} or L{_sendFailure}, depending on whether C{fail} - represents an L{Error} subclass or not. - """ - if fail.check(Error) is None: - self._sendFailure(fail, requestID) - else: - self._sendError(fail, requestID) - - - def _sendFailure(self, fail, requestID): - """Log error and then send it.""" - log.msg("Peer will receive following PB traceback:") - log.err(fail) - self._sendError(fail, requestID) - - def _sendError(self, fail, requestID): - """(internal) Send an error for a previously sent message. - """ - if isinstance(fail, failure.Failure): - # If the failures value is jellyable or allowed through security, - # send the value - if (isinstance(fail.value, Jellyable) or - self.security.isClassAllowed(fail.value.__class__)): - fail = fail.value - elif not isinstance(fail, CopyableFailure): - fail = failure2Copyable(fail, self.factory.unsafeTracebacks) - if isinstance(fail, CopyableFailure): - fail.unsafeTracebacks = self.factory.unsafeTracebacks - self.sendCall("error", requestID, self.serialize(fail)) - - def proto_error(self, requestID, fail): - """(internal) Deal with an error. - """ - d = self.waitingForAnswers[requestID] - del self.waitingForAnswers[requestID] - d.errback(self.unserialize(fail)) - - ## - # refcounts - ## - - def sendDecRef(self, objectID): - """(internal) Send a DECREF directive. - """ - self.sendCall("decref", objectID) - - def proto_decref(self, objectID): - """(internal) Decrement the reference count of an object. - - If the reference count is zero, it will free the reference to this - object. - """ - refs = self.localObjects[objectID].decref() - if refs == 0: - puid = self.localObjects[objectID].object.processUniqueID() - del self.luids[puid] - del self.localObjects[objectID] - self._localCleanup.pop(puid, lambda: None)() - - ## - # caching - ## - - def decCacheRef(self, objectID): - """(internal) Send a DECACHE directive. - """ - self.sendCall("decache", objectID) - - def proto_decache(self, objectID): - """(internal) Decrement the reference count of a cached object. - - If the reference count is zero, free the reference, then send an - 'uncached' directive. - """ - refs = self.remotelyCachedObjects[objectID].decref() - # log.msg('decaching: %s #refs: %s' % (objectID, refs)) - if refs == 0: - lobj = self.remotelyCachedObjects[objectID] - cacheable = lobj.object - perspective = lobj.perspective - # TODO: force_decache needs to be able to force-invalidate a - # cacheable reference. - try: - cacheable.stoppedObserving(perspective, RemoteCacheObserver(self, cacheable, perspective)) - except: - log.deferr() - puid = cacheable.processUniqueID() - del self.remotelyCachedLUIDs[puid] - del self.remotelyCachedObjects[objectID] - self.sendCall("uncache", objectID) - - def proto_uncache(self, objectID): - """(internal) Tell the client it is now OK to uncache an object. - """ - # log.msg("uncaching locally %d" % objectID) - obj = self.locallyCachedObjects[objectID] - obj.broker = None -## def reallyDel(obj=obj): -## obj.__really_del__() -## obj.__del__ = reallyDel - del self.locallyCachedObjects[objectID] - - - -def respond(challenge, password): - """Respond to a challenge. - - This is useful for challenge/response authentication. - """ - m = md5() - m.update(password) - hashedPassword = m.digest() - m = md5() - m.update(hashedPassword) - m.update(challenge) - doubleHashedPassword = m.digest() - return doubleHashedPassword - -def challenge(): - """I return some random data.""" - crap = '' - for x in range(random.randrange(15,25)): - crap = crap + chr(random.randint(65,90)) - crap = md5(crap).digest() - return crap - - -class PBClientFactory(protocol.ClientFactory): - """ - Client factory for PB brokers. - - As with all client factories, use with reactor.connectTCP/SSL/etc.. - getPerspective and getRootObject can be called either before or - after the connect. - """ - - protocol = Broker - unsafeTracebacks = False - - def __init__(self, unsafeTracebacks=False, security=globalSecurity): - """ - @param unsafeTracebacks: if set, tracebacks for exceptions will be sent - over the wire. - @type unsafeTracebacks: C{bool} - - @param security: security options used by the broker, default to - C{globalSecurity}. - @type security: L{twisted.spread.jelly.SecurityOptions} - """ - self.unsafeTracebacks = unsafeTracebacks - self.security = security - self._reset() - - - def buildProtocol(self, addr): - """ - Build the broker instance, passing the security options to it. - """ - p = self.protocol(isClient=True, security=self.security) - p.factory = self - return p - - - def _reset(self): - self.rootObjectRequests = [] # list of deferred - self._broker = None - self._root = None - - def _failAll(self, reason): - deferreds = self.rootObjectRequests - self._reset() - for d in deferreds: - d.errback(reason) - - def clientConnectionFailed(self, connector, reason): - self._failAll(reason) - - def clientConnectionLost(self, connector, reason, reconnecting=0): - """Reconnecting subclasses should call with reconnecting=1.""" - if reconnecting: - # any pending requests will go to next connection attempt - # so we don't fail them. - self._broker = None - self._root = None - else: - self._failAll(reason) - - def clientConnectionMade(self, broker): - self._broker = broker - self._root = broker.remoteForName("root") - ds = self.rootObjectRequests - self.rootObjectRequests = [] - for d in ds: - d.callback(self._root) - - def getRootObject(self): - """Get root object of remote PB server. - - @return: Deferred of the root object. - """ - if self._broker and not self._broker.disconnected: - return defer.succeed(self._root) - d = defer.Deferred() - self.rootObjectRequests.append(d) - return d - - def disconnect(self): - """If the factory is connected, close the connection. - - Note that if you set up the factory to reconnect, you will need to - implement extra logic to prevent automatic reconnection after this - is called. - """ - if self._broker: - self._broker.transport.loseConnection() - - def _cbSendUsername(self, root, username, password, client): - return root.callRemote("login", username).addCallback( - self._cbResponse, password, client) - - def _cbResponse(self, (challenge, challenger), password, client): - return challenger.callRemote("respond", respond(challenge, password), client) - - - def _cbLoginAnonymous(self, root, client): - """ - Attempt an anonymous login on the given remote root object. - - @type root: L{RemoteReference} - @param root: The object on which to attempt the login, most likely - returned by a call to L{PBClientFactory.getRootObject}. - - @param client: A jellyable object which will be used as the I{mind} - parameter for the login attempt. - - @rtype: L{Deferred} - @return: A L{Deferred} which will be called back with a - L{RemoteReference} to an avatar when anonymous login succeeds, or - which will errback if anonymous login fails. - """ - return root.callRemote("loginAnonymous", client) - - - def login(self, credentials, client=None): - """ - Login and get perspective from remote PB server. - - Currently the following credentials are supported:: - - L{twisted.cred.credentials.IUsernamePassword} - L{twisted.cred.credentials.IAnonymous} - - @rtype: L{Deferred} - @return: A L{Deferred} which will be called back with a - L{RemoteReference} for the avatar logged in to, or which will - errback if login fails. - """ - d = self.getRootObject() - - if IAnonymous.providedBy(credentials): - d.addCallback(self._cbLoginAnonymous, client) - else: - d.addCallback( - self._cbSendUsername, credentials.username, - credentials.password, client) - return d - - - -class PBServerFactory(protocol.ServerFactory): - """ - Server factory for perspective broker. - - Login is done using a Portal object, whose realm is expected to return - avatars implementing IPerspective. The credential checkers in the portal - should accept IUsernameHashedPassword or IUsernameMD5Password. - - Alternatively, any object providing or adaptable to L{IPBRoot} can be - used instead of a portal to provide the root object of the PB server. - """ - - unsafeTracebacks = False - - # object broker factory - protocol = Broker - - def __init__(self, root, unsafeTracebacks=False, security=globalSecurity): - """ - @param root: factory providing the root Referenceable used by the broker. - @type root: object providing or adaptable to L{IPBRoot}. - - @param unsafeTracebacks: if set, tracebacks for exceptions will be sent - over the wire. - @type unsafeTracebacks: C{bool} - - @param security: security options used by the broker, default to - C{globalSecurity}. - @type security: L{twisted.spread.jelly.SecurityOptions} - """ - self.root = IPBRoot(root) - self.unsafeTracebacks = unsafeTracebacks - self.security = security - - - def buildProtocol(self, addr): - """ - Return a Broker attached to the factory (as the service provider). - """ - proto = self.protocol(isClient=False, security=self.security) - proto.factory = self - proto.setNameForLocal("root", self.root.rootObject(proto)) - return proto - - def clientConnectionMade(self, protocol): - # XXX does this method make any sense? - pass - - -class IUsernameMD5Password(ICredentials): - """ - I encapsulate a username and a hashed password. - - This credential is used for username/password over PB. CredentialCheckers - which check this kind of credential must store the passwords in plaintext - form or as a MD5 digest. - - @type username: C{str} or C{Deferred} - @ivar username: The username associated with these credentials. - """ - - def checkPassword(password): - """ - Validate these credentials against the correct password. - - @type password: C{str} - @param password: The correct, plaintext password against which to - check. - - @rtype: C{bool} or L{Deferred} - @return: C{True} if the credentials represented by this object match the - given password, C{False} if they do not, or a L{Deferred} which will - be called back with one of these values. - """ - - def checkMD5Password(password): - """ - Validate these credentials against the correct MD5 digest of the - password. - - @type password: C{str} - @param password: The correct MD5 digest of a password against which to - check. - - @rtype: C{bool} or L{Deferred} - @return: C{True} if the credentials represented by this object match the - given digest, C{False} if they do not, or a L{Deferred} which will - be called back with one of these values. - """ - - -@implementer(IPBRoot) -class _PortalRoot: - """Root object, used to login to portal.""" - - def __init__(self, portal): - self.portal = portal - - def rootObject(self, broker): - return _PortalWrapper(self.portal, broker) - -registerAdapter(_PortalRoot, Portal, IPBRoot) - - - -class _JellyableAvatarMixin: - """ - Helper class for code which deals with avatars which PB must be capable of - sending to a peer. - """ - def _cbLogin(self, (interface, avatar, logout)): - """ - Ensure that the avatar to be returned to the client is jellyable and - set up disconnection notification to call the realm's logout object. - """ - if not IJellyable.providedBy(avatar): - avatar = AsReferenceable(avatar, "perspective") - - puid = avatar.processUniqueID() - - # only call logout once, whether the connection is dropped (disconnect) - # or a logout occurs (cleanup), and be careful to drop the reference to - # it in either case - logout = [ logout ] - def maybeLogout(): - if not logout: - return - fn = logout[0] - del logout[0] - fn() - self.broker._localCleanup[puid] = maybeLogout - self.broker.notifyOnDisconnect(maybeLogout) - - return avatar - - - -class _PortalWrapper(Referenceable, _JellyableAvatarMixin): - """ - Root Referenceable object, used to login to portal. - """ - - def __init__(self, portal, broker): - self.portal = portal - self.broker = broker - - - def remote_login(self, username): - """ - Start of username/password login. - """ - c = challenge() - return c, _PortalAuthChallenger(self.portal, self.broker, username, c) - - - def remote_loginAnonymous(self, mind): - """ - Attempt an anonymous login. - - @param mind: An object to use as the mind parameter to the portal login - call (possibly None). - - @rtype: L{Deferred} - @return: A Deferred which will be called back with an avatar when login - succeeds or which will be errbacked if login fails somehow. - """ - d = self.portal.login(Anonymous(), mind, IPerspective) - d.addCallback(self._cbLogin) - return d - - - -@implementer(IUsernameHashedPassword, IUsernameMD5Password) -class _PortalAuthChallenger(Referenceable, _JellyableAvatarMixin): - """ - Called with response to password challenge. - """ - def __init__(self, portal, broker, username, challenge): - self.portal = portal - self.broker = broker - self.username = username - self.challenge = challenge - - - def remote_respond(self, response, mind): - self.response = response - d = self.portal.login(self, mind, IPerspective) - d.addCallback(self._cbLogin) - return d - - - # IUsernameHashedPassword: - def checkPassword(self, password): - return self.checkMD5Password(md5(password).digest()) - - - # IUsernameMD5Password - def checkMD5Password(self, md5Password): - md = md5() - md.update(md5Password) - md.update(self.challenge) - correct = md.digest() - return self.response == correct - - -__all__ = [ - # Everything from flavors is exposed publically here. - 'IPBRoot', 'Serializable', 'Referenceable', 'NoSuchMethod', 'Root', - 'ViewPoint', 'Viewable', 'Copyable', 'Jellyable', 'Cacheable', - 'RemoteCopy', 'RemoteCache', 'RemoteCacheObserver', 'copyTags', - 'setUnjellyableForClass', 'setUnjellyableFactoryForClass', - 'setUnjellyableForClassTree', - 'setCopierForClass', 'setFactoryForClass', 'setCopierForClassTree', - - 'MAX_BROKER_REFS', 'portno', - - 'ProtocolError', 'DeadReferenceError', 'Error', 'PBConnectionLost', - 'RemoteMethod', 'IPerspective', 'Avatar', 'AsReferenceable', - 'RemoteReference', 'CopyableFailure', 'CopiedFailure', 'failure2Copyable', - 'Broker', 'respond', 'challenge', 'PBClientFactory', 'PBServerFactory', - 'IUsernameMD5Password', - ] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/publish.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/publish.py deleted file mode 100644 index 5bc1868..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/publish.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- test-case-name: twisted.test.test_pb -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Persistently cached objects for PB. - -Maintainer: Glyph Lefkowitz - -Future Plans: None known. -""" - -import time - -from twisted.internet import defer -from twisted.spread import banana, jelly, flavors - - -class Publishable(flavors.Cacheable): - """An object whose cached state persists across sessions. - """ - def __init__(self, publishedID): - self.republish() - self.publishedID = publishedID - - def republish(self): - """Set the timestamp to current and (TODO) update all observers. - """ - self.timestamp = time.time() - - def view_getStateToPublish(self, perspective): - '(internal)' - return self.getStateToPublishFor(perspective) - - def getStateToPublishFor(self, perspective): - """Implement me to special-case your state for a perspective. - """ - return self.getStateToPublish() - - def getStateToPublish(self): - """Implement me to return state to copy as part of the publish phase. - """ - raise NotImplementedError("%s.getStateToPublishFor" % self.__class__) - - def getStateToCacheAndObserveFor(self, perspective, observer): - """Get all necessary metadata to keep a clientside cache. - """ - if perspective: - pname = perspective.perspectiveName - sname = perspective.getService().serviceName - else: - pname = "None" - sname = "None" - - return {"remote": flavors.ViewPoint(perspective, self), - "publishedID": self.publishedID, - "perspective": pname, - "service": sname, - "timestamp": self.timestamp} - -class RemotePublished(flavors.RemoteCache): - """The local representation of remote Publishable object. - """ - isActivated = 0 - _wasCleanWhenLoaded = 0 - def getFileName(self, ext='pub'): - return ("%s-%s-%s.%s" % - (self.service, self.perspective, str(self.publishedID), ext)) - - def setCopyableState(self, state): - self.__dict__.update(state) - self._activationListeners = [] - try: - dataFile = file(self.getFileName(), "rb") - data = dataFile.read() - dataFile.close() - except IOError: - recent = 0 - else: - newself = jelly.unjelly(banana.decode(data)) - recent = (newself.timestamp == self.timestamp) - if recent: - self._cbGotUpdate(newself.__dict__) - self._wasCleanWhenLoaded = 1 - else: - self.remote.callRemote('getStateToPublish').addCallbacks(self._cbGotUpdate) - - def __getstate__(self): - other = self.__dict__.copy() - # Remove PB-specific attributes - del other['broker'] - del other['remote'] - del other['luid'] - # remove my own runtime-tracking stuff - del other['_activationListeners'] - del other['isActivated'] - return other - - def _cbGotUpdate(self, newState): - self.__dict__.update(newState) - self.isActivated = 1 - # send out notifications - for listener in self._activationListeners: - listener(self) - self._activationListeners = [] - self.activated() - dataFile = file(self.getFileName(), "wb") - dataFile.write(banana.encode(jelly.jelly(self))) - dataFile.close() - - - def activated(self): - """Implement this method if you want to be notified when your - publishable subclass is activated. - """ - - def callWhenActivated(self, callback): - """Externally register for notification when this publishable has received all relevant data. - """ - if self.isActivated: - callback(self) - else: - self._activationListeners.append(callback) - -def whenReady(d): - """ - Wrap a deferred returned from a pb method in another deferred that - expects a RemotePublished as a result. This will allow you to wait until - the result is really available. - - Idiomatic usage would look like:: - - publish.whenReady(serverObject.getMeAPublishable()).addCallback(lookAtThePublishable) - """ - d2 = defer.Deferred() - d.addCallbacks(_pubReady, d2.errback, - callbackArgs=(d2,)) - return d2 - -def _pubReady(result, d2): - '(internal)' - result.callWhenActivated(d2.callback) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/__init__.py deleted file mode 100644 index 56bf766..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Spread UI: UI utilities for various toolkits connecting to PB. -""" - -# Undeprecating this until someone figures out a real plan for alternatives to spread.ui. -##import warnings -##warnings.warn("twisted.spread.ui is deprecated. Please do not use.", DeprecationWarning) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/gtk2util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/gtk2util.py deleted file mode 100644 index a576388..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/gtk2util.py +++ /dev/null @@ -1,218 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -import gtk - -from twisted import copyright -from twisted.internet import defer -from twisted.python import failure, log, util -from twisted.spread import pb -from twisted.cred.credentials import UsernamePassword - -from twisted.internet import error as netError - -def login(client=None, **defaults): - """ - @param host: - @param port: - @param identityName: - @param password: - @param serviceName: - @param perspectiveName: - - @returntype: Deferred RemoteReference of Perspective - """ - d = defer.Deferred() - LoginDialog(client, d, defaults) - return d - -class GladeKeeper: - """ - @cvar gladefile: The file in which the glade GUI definition is kept. - @type gladefile: str - - @cvar _widgets: Widgets that should be attached to me as attributes. - @type _widgets: list of strings - """ - - gladefile = None - _widgets = () - - def __init__(self): - from gtk import glade - self.glade = glade.XML(self.gladefile) - - # mold can go away when we get a newer pygtk (post 1.99.14) - mold = {} - for k in dir(self): - mold[k] = getattr(self, k) - self.glade.signal_autoconnect(mold) - self._setWidgets() - - def _setWidgets(self): - get_widget = self.glade.get_widget - for widgetName in self._widgets: - setattr(self, "_" + widgetName, get_widget(widgetName)) - - -class LoginDialog(GladeKeeper): - # IdentityConnector host port identityName password - # requestLogin -> identityWrapper or login failure - # requestService serviceName perspectiveName client - - # window killed - # cancel button pressed - # login button activated - - fields = ['host','port','identityName','password', - 'perspectiveName'] - - _widgets = ("hostEntry", "portEntry", "identityNameEntry", "passwordEntry", - "perspectiveNameEntry", "statusBar", - "loginDialog") - - _advancedControls = ['perspectiveLabel', 'perspectiveNameEntry', - 'protocolLabel', 'versionLabel'] - - gladefile = util.sibpath(__file__, "login2.glade") - - _timeoutID = None - - def __init__(self, client, deferred, defaults): - self.client = client - self.deferredResult = deferred - - GladeKeeper.__init__(self) - - self.setDefaults(defaults) - self._loginDialog.show() - - - def setDefaults(self, defaults): - if not defaults.has_key('port'): - defaults['port'] = str(pb.portno) - elif isinstance(defaults['port'], (int, long)): - defaults['port'] = str(defaults['port']) - - for k, v in defaults.iteritems(): - if k in self.fields: - widget = getattr(self, "_%sEntry" % (k,)) - widget.set_text(v) - - def _setWidgets(self): - GladeKeeper._setWidgets(self) - self._statusContext = self._statusBar.get_context_id("Login dialog.") - get_widget = self.glade.get_widget - get_widget("versionLabel").set_text(copyright.longversion) - get_widget("protocolLabel").set_text("Protocol PB-%s" % - (pb.Broker.version,)) - - def _on_loginDialog_response(self, widget, response): - handlers = {gtk.RESPONSE_NONE: self._windowClosed, - gtk.RESPONSE_DELETE_EVENT: self._windowClosed, - gtk.RESPONSE_OK: self._doLogin, - gtk.RESPONSE_CANCEL: self._cancelled} - handler = handlers.get(response) - if handler is not None: - handler() - else: - log.msg("Unexpected dialog response %r from %s" % (response, - widget)) - - def _on_loginDialog_close(self, widget, userdata=None): - self._windowClosed() - - def _on_loginDialog_destroy_event(self, widget, userdata=None): - self._windowClosed() - - def _cancelled(self): - if not self.deferredResult.called: - self.deferredResult.errback(netError.UserError("User hit Cancel.")) - self._loginDialog.destroy() - - def _windowClosed(self, reason=None): - if not self.deferredResult.called: - self.deferredResult.errback(netError.UserError("Window closed.")) - - def _doLogin(self): - idParams = {} - - idParams['host'] = self._hostEntry.get_text() - idParams['port'] = self._portEntry.get_text() - idParams['identityName'] = self._identityNameEntry.get_text() - idParams['password'] = self._passwordEntry.get_text() - - try: - idParams['port'] = int(idParams['port']) - except ValueError: - pass - - f = pb.PBClientFactory() - from twisted.internet import reactor - reactor.connectTCP(idParams['host'], idParams['port'], f) - creds = UsernamePassword(idParams['identityName'], idParams['password']) - d = f.login(creds, self.client) - def _timeoutLogin(): - self._timeoutID = None - d.errback(failure.Failure(defer.TimeoutError("Login timed out."))) - self._timeoutID = reactor.callLater(30, _timeoutLogin) - d.addCallbacks(self._cbGotPerspective, self._ebFailedLogin) - self.statusMsg("Contacting server...") - - # serviceName = self._serviceNameEntry.get_text() - # perspectiveName = self._perspectiveNameEntry.get_text() - # if not perspectiveName: - # perspectiveName = idParams['identityName'] - - # d = _identityConnector.requestService(serviceName, perspectiveName, - # self.client) - # d.addCallbacks(self._cbGotPerspective, self._ebFailedLogin) - # setCursor to waiting - - def _cbGotPerspective(self, perspective): - self.statusMsg("Connected to server.") - if self._timeoutID is not None: - self._timeoutID.cancel() - self._timeoutID = None - self.deferredResult.callback(perspective) - # clear waiting cursor - self._loginDialog.destroy() - - def _ebFailedLogin(self, reason): - if isinstance(reason, failure.Failure): - reason = reason.value - self.statusMsg(reason) - if isinstance(reason, (unicode, str)): - text = reason - else: - text = unicode(reason) - msg = gtk.MessageDialog(self._loginDialog, - gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_ERROR, - gtk.BUTTONS_CLOSE, - text) - msg.show_all() - msg.connect("response", lambda *a: msg.destroy()) - - # hostname not found - # host unreachable - # connection refused - # authentication failed - # no such service - # no such perspective - # internal server error - - def _on_advancedButton_toggled(self, widget, userdata=None): - active = widget.get_active() - if active: - op = "show" - else: - op = "hide" - for widgetName in self._advancedControls: - widget = self.glade.get_widget(widgetName) - getattr(widget, op)() - - def statusMsg(self, text): - if not isinstance(text, (unicode, str)): - text = unicode(text) - return self._statusBar.push(self._statusContext, text) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/login2.glade b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/login2.glade deleted file mode 100644 index af8c53d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/login2.glade +++ /dev/null @@ -1,461 +0,0 @@ - - - - - - - Login - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - True - True - - - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - -6 - - - - - - True - True - True - True - GTK_RELIEF_NORMAL - -5 - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-ok - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - _Login - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - False - - - 0 - False - False - GTK_PACK_END - - - - - - True - 6 - 2 - False - 2 - 0 - - - - True - _Host: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - hostEntry - - - - - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - False - 0 - - - - True - The name of a host to connect to. - True - True - True - True - 0 - localhost - True - * - True - - - - - - 0 - True - True - - - - - - True - The number of a port to connect on. - True - True - True - 0 - 8787 - True - * - True - 5 - - - 0 - False - True - - - - - 1 - 2 - 0 - 1 - fill - - - - - - True - _Name: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - identityNameEntry - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - An identity to log in as. - True - True - True - 0 - - True - * - True - - - 1 - 2 - 1 - 2 - - - - - - - True - The Identity's log-in password. - True - True - False - 0 - - True - * - True - - - 1 - 2 - 2 - 3 - - - - - - - True - _Password: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - passwordEntry - - - 0 - 1 - 2 - 3 - fill - - - - - - - Perspective: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - - - 0 - 1 - 5 - 6 - fill - - - - - - - The name of a Perspective to request. - True - True - True - 0 - - True - * - False - - - 1 - 2 - 5 - 6 - - - - - - - True - False - 0 - - - - Insert Protocol Version Here - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - Insert Twisted Version Here - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - 0 - 2 - 4 - 5 - fill - fill - - - - - - True - 1 - 0.5 - 0 - 1 - - - - True - Advanced options. - True - Advanced >> - True - GTK_RELIEF_NORMAL - False - False - - - - - - 0 - 2 - 3 - 4 - - - - - - 0 - False - False - - - - - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/tktree.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/tktree.py deleted file mode 100644 index 707bfcf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/tktree.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -What I want it to look like: - -+- One -| \- Two -| |- Three -| |- Four -| +- Five -| | \- Six -| |- Seven -+- Eight -| \- Nine -""" - -import os -from Tkinter import END, Listbox, Tk, Scrollbar, LEFT, BOTH, RIGHT, Y - -class Node: - def __init__(self): - """ - Do whatever you want here. - """ - self.item=None - def getName(self): - """ - Return the name of this node in the tree. - """ - pass - def isExpandable(self): - """ - Return true if this node is expandable. - """ - return len(self.getSubNodes())>0 - def getSubNodes(self): - """ - Return the sub nodes of this node. - """ - return [] - def gotDoubleClick(self): - """ - Called when we are double clicked. - """ - pass - def updateMe(self): - """ - Call me when something about me changes, so that my representation - changes. - """ - if self.item: - self.item.update() - -class FileNode(Node): - def __init__(self,name): - Node.__init__(self) - self.name=name - def getName(self): - return os.path.basename(self.name) - def isExpandable(self): - return os.path.isdir(self.name) - def getSubNodes(self): - names=map(lambda x,n=self.name:os.path.join(n,x),os.listdir(self.name)) - return map(FileNode,names) - -class TreeItem: - def __init__(self,widget,parent,node): - self.widget=widget - self.node=node - node.item=self - if self.node.isExpandable(): - self.expand=0 - else: - self.expand=None - self.parent=parent - if parent: - self.level=self.parent.level+1 - else: - self.level=0 - self.first=0 # gets set in Tree.expand() - self.subitems=[] - def __del__(self): - del self.node - del self.widget - def __repr__(self): - return ""%(self.node.getName(),self.level) - def render(self): - """ - Override in a subclass. - """ - raise NotImplementedError - def update(self): - self.widget.update(self) - -class ListboxTreeItem(TreeItem): - def render(self): - start=self.level*"| " - if self.expand==None and not self.first: - start=start+"|" - elif self.expand==0: - start=start+"L" - elif self.expand==1: - start=start+"+" - else: - start=start+"\\" - r=[start+"- "+self.node.getName()] - if self.expand: - for i in self.subitems: - r.extend(i.render()) - return r - -class ListboxTree: - def __init__(self,parent=None,**options): - self.box=apply(Listbox,[parent],options) - self.box.bind("",self.flip) - self.roots=[] - self.items=[] - def pack(self,*args,**kw): - """ - for packing. - """ - apply(self.box.pack,args,kw) - def grid(self,*args,**kw): - """ - for gridding. - """ - apply(self.box.grid,args,kw) - def yview(self,*args,**kw): - """ - for scrolling. - """ - apply(self.box.yview,args,kw) - def addRoot(self,node): - r=ListboxTreeItem(self,None,node) - self.roots.append(r) - self.items.append(r) - self.box.insert(END,r.render()[0]) - return r - def curselection(self): - c=self.box.curselection() - if not c: return - return self.items[int(c[0])] - def flip(self,*foo): - if not self.box.curselection(): return - item=self.items[int(self.box.curselection()[0])] - if item.expand==None: return - if not item.expand: - self.expand(item) - else: - self.close(item) - item.node.gotDoubleClick() - def expand(self,item): - if item.expand or item.expand==None: return - item.expand=1 - item.subitems=map(lambda x,i=item,s=self:ListboxTreeItem(s,i,x),item.node.getSubNodes()) - if item.subitems: - item.subitems[0].first=1 - i=self.items.index(item) - self.items,after=self.items[:i+1],self.items[i+1:] - self.items=self.items+item.subitems+after - c=self.items.index(item) - self.box.delete(c) - r=item.render() - for i in r: - self.box.insert(c,i) - c=c+1 - def close(self,item): - if not item.expand: return - item.expand=0 - length=len(item.subitems) - for i in item.subitems: - self.close(i) - c=self.items.index(item) - del self.items[c+1:c+1+length] - for i in range(length+1): - self.box.delete(c) - self.box.insert(c,item.render()[0]) - def remove(self,item): - if item.expand: - self.close(item) - c=self.items.index(item) - del self.items[c] - if item.parent: - item.parent.subitems.remove(item) - self.box.delete(c) - def update(self,item): - if item.expand==None: - c=self.items.index(item) - self.box.delete(c) - self.box.insert(c,item.render()[0]) - elif item.expand: - self.close(item) - self.expand(item) - -if __name__=="__main__": - tk=Tk() - s=Scrollbar() - t=ListboxTree(tk,yscrollcommand=s.set) - t.pack(side=LEFT,fill=BOTH) - s.config(command=t.yview) - s.pack(side=RIGHT,fill=Y) - t.addRoot(FileNode("C:/")) - #mainloop() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/tkutil.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/tkutil.py deleted file mode 100644 index 16f4c1d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/ui/tkutil.py +++ /dev/null @@ -1,397 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Utilities for building L{PB} clients with L{Tkinter}. -""" -from Tkinter import ( - ACTIVE, Button, Canvas, E, END, Entry, Frame, Label, LEFT, Listbox, - mainloop, N, S, StringVar, Toplevel, Tk, W) -from tkSimpleDialog import _QueryString -from tkFileDialog import _Dialog -from twisted.spread import pb -from twisted import copyright - -import string - -#normalFont = Font("-adobe-courier-medium-r-normal-*-*-120-*-*-m-*-iso8859-1") -#boldFont = Font("-adobe-courier-bold-r-normal-*-*-120-*-*-m-*-iso8859-1") -#errorFont = Font("-adobe-courier-medium-o-normal-*-*-120-*-*-m-*-iso8859-1") - -class _QueryPassword(_QueryString): - def body(self, master): - - w = Label(master, text=self.prompt, justify=LEFT) - w.grid(row=0, padx=5, sticky=W) - - self.entry = Entry(master, name="entry",show="*") - self.entry.grid(row=1, padx=5, sticky=W+E) - - if self.initialvalue: - self.entry.insert(0, self.initialvalue) - self.entry.select_range(0, END) - - return self.entry - -def askpassword(title, prompt, **kw): - '''get a password from the user - - @param title: the dialog title - @param prompt: the label text - @param **kw: see L{SimpleDialog} class - - @returns: a string - ''' - d = apply(_QueryPassword, (title, prompt), kw) - return d.result - -def grid_setexpand(widget): - cols,rows=widget.grid_size() - for i in range(cols): - widget.columnconfigure(i,weight=1) - for i in range(rows): - widget.rowconfigure(i,weight=1) - -class CList(Frame): - def __init__(self,parent,labels,disablesorting=0,**kw): - Frame.__init__(self,parent) - self.labels=labels - self.lists=[] - self.disablesorting=disablesorting - kw["exportselection"]=0 - for i in range(len(labels)): - b=Button(self,text=labels[i],anchor=W,height=1,pady=0) - b.config(command=lambda s=self,i=i:s.setSort(i)) - b.grid(column=i,row=0,sticky=N+E+W) - box=apply(Listbox,(self,),kw) - box.grid(column=i,row=1,sticky=N+E+S+W) - self.lists.append(box) - grid_setexpand(self) - self.rowconfigure(0,weight=0) - self._callall("bind",'',self.Button1) - self._callall("bind",'',self.Button1) - self.bind('',self.UpKey) - self.bind('',self.DownKey) - self.sort=None - - def _callall(self,funcname,*args,**kw): - rets=[] - for l in self.lists: - func=getattr(l,funcname) - ret=apply(func,args,kw) - if ret!=None: rets.append(ret) - if rets: return rets - - def Button1(self,e): - index=self.nearest(e.y) - self.select_clear(0,END) - self.select_set(index) - self.activate(index) - return "break" - - def UpKey(self,e): - index=self.index(ACTIVE) - if index: - self.select_clear(0,END) - self.select_set(index-1) - return "break" - - def DownKey(self,e): - index=self.index(ACTIVE) - if index!=self.size()-1: - self.select_clear(0,END) - self.select_set(index+1) - return "break" - - def setSort(self,index): - if self.sort==None: - self.sort=[index,1] - elif self.sort[0]==index: - self.sort[1]=-self.sort[1] - else: - self.sort=[index,1] - self._sort() - - def _sort(self): - if self.disablesorting: - return - if self.sort==None: - return - ind,direc=self.sort - li=list(self.get(0,END)) - li.sort(lambda x,y,i=ind,d=direc:d*cmp(x[i],y[i])) - self.delete(0,END) - for l in li: - self._insert(END,l) - def activate(self,index): - self._callall("activate",index) - - # def bbox(self,index): - # return self._callall("bbox",index) - - def curselection(self): - return self.lists[0].curselection() - - def delete(self,*args): - apply(self._callall,("delete",)+args) - - def get(self,*args): - bad=apply(self._callall,("get",)+args) - if len(args)==1: - return bad - ret=[] - for i in range(len(bad[0])): - r=[] - for j in range(len(bad)): - r.append(bad[j][i]) - ret.append(r) - return ret - - def index(self,index): - return self.lists[0].index(index) - - def insert(self,index,items): - self._insert(index,items) - self._sort() - - def _insert(self,index,items): - for i in range(len(items)): - self.lists[i].insert(index,items[i]) - - def nearest(self,y): - return self.lists[0].nearest(y) - - def see(self,index): - self._callall("see",index) - - def size(self): - return self.lists[0].size() - - def selection_anchor(self,index): - self._callall("selection_anchor",index) - - select_anchor=selection_anchor - - def selection_clear(self,*args): - apply(self._callall,("selection_clear",)+args) - - select_clear=selection_clear - - def selection_includes(self,index): - return self.lists[0].select_includes(index) - - select_includes=selection_includes - - def selection_set(self,*args): - apply(self._callall,("selection_set",)+args) - - select_set=selection_set - - def xview(self,*args): - if not args: return self.lists[0].xview() - apply(self._callall,("xview",)+args) - - def yview(self,*args): - if not args: return self.lists[0].yview() - apply(self._callall,("yview",)+args) - -class ProgressBar: - def __init__(self, master=None, orientation="horizontal", - min=0, max=100, width=100, height=18, - doLabel=1, appearance="sunken", - fillColor="blue", background="gray", - labelColor="yellow", labelFont="Verdana", - labelText="", labelFormat="%d%%", - value=0, bd=2): - # preserve various values - self.master=master - self.orientation=orientation - self.min=min - self.max=max - self.width=width - self.height=height - self.doLabel=doLabel - self.fillColor=fillColor - self.labelFont= labelFont - self.labelColor=labelColor - self.background=background - self.labelText=labelText - self.labelFormat=labelFormat - self.value=value - self.frame=Frame(master, relief=appearance, bd=bd) - self.canvas=Canvas(self.frame, height=height, width=width, bd=0, - highlightthickness=0, background=background) - self.scale=self.canvas.create_rectangle(0, 0, width, height, - fill=fillColor) - self.label=self.canvas.create_text(self.canvas.winfo_reqwidth() / 2, - height / 2, text=labelText, - anchor="c", fill=labelColor, - font=self.labelFont) - self.update() - self.canvas.pack(side='top', fill='x', expand='no') - - def updateProgress(self, newValue, newMax=None): - if newMax: - self.max = newMax - self.value = newValue - self.update() - - def update(self): - # Trim the values to be between min and max - value=self.value - if value > self.max: - value = self.max - if value < self.min: - value = self.min - # Adjust the rectangle - if self.orientation == "horizontal": - self.canvas.coords(self.scale, 0, 0, - float(value) / self.max * self.width, self.height) - else: - self.canvas.coords(self.scale, 0, - self.height - (float(value) / - self.max*self.height), - self.width, self.height) - # Now update the colors - self.canvas.itemconfig(self.scale, fill=self.fillColor) - self.canvas.itemconfig(self.label, fill=self.labelColor) - # And update the label - if self.doLabel: - if value: - if value >= 0: - pvalue = int((float(value) / float(self.max)) * - 100.0) - else: - pvalue = 0 - self.canvas.itemconfig(self.label, text=self.labelFormat - % pvalue) - else: - self.canvas.itemconfig(self.label, text='') - else: - self.canvas.itemconfig(self.label, text=self.labelFormat % - self.labelText) - self.canvas.update_idletasks() - -class DirectoryBrowser(_Dialog): - command = "tk_chooseDirectory" - -def askdirectory(**options): - "Ask for a directory to save to." - - return apply(DirectoryBrowser, (), options).show() - -class GenericLogin(Toplevel): - def __init__(self,callback,buttons): - Toplevel.__init__(self) - self.callback=callback - Label(self,text="Twisted v%s"%copyright.version).grid(column=0,row=0,columnspan=2) - self.entries={} - row=1 - for stuff in buttons: - label,value=stuff[:2] - if len(stuff)==3: - dict=stuff[2] - else: dict={} - Label(self,text=label+": ").grid(column=0,row=row) - e=apply(Entry,(self,),dict) - e.grid(column=1,row=row) - e.insert(0,value) - self.entries[label]=e - row=row+1 - Button(self,text="Login",command=self.doLogin).grid(column=0,row=row) - Button(self,text="Cancel",command=self.close).grid(column=1,row=row) - self.protocol('WM_DELETE_WINDOW',self.close) - - def close(self): - self.tk.quit() - self.destroy() - - def doLogin(self): - values={} - for k in self.entries.keys(): - values[string.lower(k)]=self.entries[k].get() - self.callback(values) - self.destroy() - -class Login(Toplevel): - def __init__(self, - callback, - referenced = None, - initialUser = "guest", - initialPassword = "guest", - initialHostname = "localhost", - initialService = "", - initialPortno = pb.portno): - Toplevel.__init__(self) - version_label = Label(self,text="Twisted v%s" % copyright.version) - self.pbReferenceable = referenced - self.pbCallback = callback - # version_label.show() - self.username = Entry(self) - self.password = Entry(self,show='*') - self.hostname = Entry(self) - self.service = Entry(self) - self.port = Entry(self) - - self.username.insert(0,initialUser) - self.password.insert(0,initialPassword) - self.service.insert(0,initialService) - self.hostname.insert(0,initialHostname) - self.port.insert(0,str(initialPortno)) - - userlbl=Label(self,text="Username:") - passlbl=Label(self,text="Password:") - servicelbl=Label(self,text="Service:") - hostlbl=Label(self,text="Hostname:") - portlbl=Label(self,text="Port #:") - self.logvar=StringVar() - self.logvar.set("Protocol PB-%s"%pb.Broker.version) - self.logstat = Label(self,textvariable=self.logvar) - self.okbutton = Button(self,text="Log In", command=self.login) - - version_label.grid(column=0,row=0,columnspan=2) - z=0 - for i in [[userlbl,self.username], - [passlbl,self.password], - [hostlbl,self.hostname], - [servicelbl,self.service], - [portlbl,self.port]]: - i[0].grid(column=0,row=z+1) - i[1].grid(column=1,row=z+1) - z = z+1 - - self.logstat.grid(column=0,row=6,columnspan=2) - self.okbutton.grid(column=0,row=7,columnspan=2) - - self.protocol('WM_DELETE_WINDOW',self.tk.quit) - - def loginReset(self): - self.logvar.set("Idle.") - - def loginReport(self, txt): - self.logvar.set(txt) - self.after(30000, self.loginReset) - - def login(self): - host = self.hostname.get() - port = self.port.get() - service = self.service.get() - try: - port = int(port) - except: - pass - user = self.username.get() - pswd = self.password.get() - pb.connect(host, port, user, pswd, service, - client=self.pbReferenceable).addCallback(self.pbCallback).addErrback( - self.couldNotConnect) - - def couldNotConnect(self,f): - self.loginReport("could not connect:"+f.getErrorMessage()) - -if __name__=="__main__": - root=Tk() - o=CList(root,["Username","Online","Auto-Logon","Gateway"]) - o.pack() - for i in range(0,16,4): - o.insert(END,[i,i+1,i+2,i+3]) - mainloop() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/util.py deleted file mode 100644 index 21db080..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/spread/util.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- test-case-name: twisted.test.test_pb -*- - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Utility classes for spread. -""" - -from twisted.internet import defer -from twisted.python.failure import Failure -from twisted.spread import pb -from twisted.protocols import basic -from twisted.internet import interfaces - -from zope.interface import implementer - - -class LocalMethod: - def __init__(self, local, name): - self.local = local - self.name = name - - def __call__(self, *args, **kw): - return self.local.callRemote(self.name, *args, **kw) - - -class LocalAsRemote: - """ - A class useful for emulating the effects of remote behavior locally. - """ - reportAllTracebacks = 1 - - def callRemote(self, name, *args, **kw): - """ - Call a specially-designated local method. - - self.callRemote('x') will first try to invoke a method named - sync_x and return its result (which should probably be a - Deferred). Second, it will look for a method called async_x, - which will be called and then have its result (or Failure) - automatically wrapped in a Deferred. - """ - if hasattr(self, 'sync_'+name): - return getattr(self, 'sync_'+name)(*args, **kw) - try: - method = getattr(self, "async_" + name) - return defer.succeed(method(*args, **kw)) - except: - f = Failure() - if self.reportAllTracebacks: - f.printTraceback() - return defer.fail(f) - - def remoteMethod(self, name): - return LocalMethod(self, name) - - -class LocalAsyncForwarder: - """ - A class useful for forwarding a locally-defined interface. - """ - - def __init__(self, forwarded, interfaceClass, failWhenNotImplemented=0): - assert interfaceClass.providedBy(forwarded) - self.forwarded = forwarded - self.interfaceClass = interfaceClass - self.failWhenNotImplemented = failWhenNotImplemented - - def _callMethod(self, method, *args, **kw): - return getattr(self.forwarded, method)(*args, **kw) - - def callRemote(self, method, *args, **kw): - if self.interfaceClass.queryDescriptionFor(method): - result = defer.maybeDeferred(self._callMethod, method, *args, **kw) - return result - elif self.failWhenNotImplemented: - return defer.fail( - Failure(NotImplementedError, - "No Such Method in Interface: %s" % method)) - else: - return defer.succeed(None) - - -class Pager: - """ - I am an object which pages out information. - """ - def __init__(self, collector, callback=None, *args, **kw): - """ - Create a pager with a Reference to a remote collector and - an optional callable to invoke upon completion. - """ - if callable(callback): - self.callback = callback - self.callbackArgs = args - self.callbackKeyword = kw - else: - self.callback = None - self._stillPaging = 1 - self.collector = collector - collector.broker.registerPageProducer(self) - - def stillPaging(self): - """ - (internal) Method called by Broker. - """ - if not self._stillPaging: - self.collector.callRemote("endedPaging") - if self.callback is not None: - self.callback(*self.callbackArgs, **self.callbackKeyword) - return self._stillPaging - - def sendNextPage(self): - """ - (internal) Method called by Broker. - """ - self.collector.callRemote("gotPage", self.nextPage()) - - def nextPage(self): - """ - Override this to return an object to be sent to my collector. - """ - raise NotImplementedError() - - def stopPaging(self): - """ - Call this when you're done paging. - """ - self._stillPaging = 0 - - -class StringPager(Pager): - """ - A simple pager that splits a string into chunks. - """ - def __init__(self, collector, st, chunkSize=8192, callback=None, *args, **kw): - self.string = st - self.pointer = 0 - self.chunkSize = chunkSize - Pager.__init__(self, collector, callback, *args, **kw) - - def nextPage(self): - val = self.string[self.pointer:self.pointer+self.chunkSize] - self.pointer += self.chunkSize - if self.pointer >= len(self.string): - self.stopPaging() - return val - - -@implementer(interfaces.IConsumer) -class FilePager(Pager): - """ - Reads a file in chunks and sends the chunks as they come. - """ - - def __init__(self, collector, fd, callback=None, *args, **kw): - self.chunks = [] - Pager.__init__(self, collector, callback, *args, **kw) - self.startProducing(fd) - - def startProducing(self, fd): - self.deferred = basic.FileSender().beginFileTransfer(fd, self) - self.deferred.addBoth(lambda x : self.stopPaging()) - - def registerProducer(self, producer, streaming): - self.producer = producer - if not streaming: - self.producer.resumeProducing() - - def unregisterProducer(self): - self.producer = None - - def write(self, chunk): - self.chunks.append(chunk) - - def sendNextPage(self): - """ - Get the first chunk read and send it to collector. - """ - if not self.chunks: - return - val = self.chunks.pop(0) - self.producer.resumeProducing() - self.collector.callRemote("gotPage", val) - - -# Utility paging stuff. -class CallbackPageCollector(pb.Referenceable): - """ - I receive pages from the peer. You may instantiate a Pager with a - remote reference to me. I will call the callback with a list of pages - once they are all received. - """ - def __init__(self, callback): - self.pages = [] - self.callback = callback - - def remote_gotPage(self, page): - self.pages.append(page) - - def remote_endedPaging(self): - self.callback(self.pages) - - -def getAllPages(referenceable, methodName, *args, **kw): - """ - A utility method that will call a remote method which expects a - PageCollector as the first argument. - """ - d = defer.Deferred() - referenceable.callRemote(methodName, CallbackPageCollector(d.callback), *args, **kw) - return d - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/__init__.py deleted file mode 100644 index cdc430f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted TAP: Twisted Application Persistence builders for other Twisted servers. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/ftp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/ftp.py deleted file mode 100644 index 735ab4b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/ftp.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- test-case-name: twisted.test.test_ftp_options -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I am the support module for making a ftp server with twistd. -""" - -from twisted.application import internet -from twisted.cred import portal, checkers, strcred -from twisted.protocols import ftp - -from twisted.python import usage, deprecate, versions - -import warnings - - - -class Options(usage.Options, strcred.AuthOptionMixin): - synopsis = """[options]. - WARNING: This FTP server is probably INSECURE do not use it. - """ - optParameters = [ - ["port", "p", "2121", "set the port number"], - ["root", "r", "/usr/local/ftp", "define the root of the ftp-site."], - ["userAnonymous", "", "anonymous", "Name of the anonymous user."] - ] - - compData = usage.Completions( - optActions={"root": usage.CompleteDirs(descr="root of the ftp site")} - ) - - longdesc = '' - - def __init__(self, *a, **kw): - usage.Options.__init__(self, *a, **kw) - self.addChecker(checkers.AllowAnonymousAccess()) - - - def opt_password_file(self, filename): - """ - Specify a file containing username:password login info for - authenticated connections. (DEPRECATED; see --help-auth instead) - """ - self['password-file'] = filename - msg = deprecate.getDeprecationWarningString( - self.opt_password_file, versions.Version('Twisted', 11, 1, 0)) - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - self.addChecker(checkers.FilePasswordDB(filename, cache=True)) - - - -def makeService(config): - f = ftp.FTPFactory() - - r = ftp.FTPRealm(config['root']) - p = portal.Portal(r, config.get('credCheckers', [])) - - f.tld = config['root'] - f.userAnonymous = config['userAnonymous'] - f.portal = p - f.protocol = ftp.FTP - - try: - portno = int(config['port']) - except KeyError: - portno = 2121 - return internet.TCPServer(portno, f) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/manhole.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/manhole.py deleted file mode 100644 index d3d4f32..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/manhole.py +++ /dev/null @@ -1,54 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I am the support module for making a manhole server with twistd. -""" - -from twisted.manhole import service -from twisted.spread import pb -from twisted.python import usage, util -from twisted.cred import portal, checkers -from twisted.application import strports - - -class Options(usage.Options): - synopsis = "[options]" - optParameters = [ - ["user", "u", "admin", "Name of user to allow to log in"], - ["port", "p", str(pb.portno), "Port to listen on"], - ] - - optFlags = [ - ["tracebacks", "T", "Allow tracebacks to be sent over the network"], - ] - - compData = usage.Completions( - optActions={"user": usage.CompleteUsernames()} - ) - - def opt_password(self, password): - """Required. '-' will prompt or read a password from stdin. - """ - # If standard input is a terminal, I prompt for a password and - # confirm it. Otherwise, I use the first line from standard - # input, stripping off a trailing newline if there is one. - if password in ('', '-'): - self['password'] = util.getPassword(confirm=1) - else: - self['password'] = password - opt_w = opt_password - - def postOptions(self): - if not self.has_key('password'): - self.opt_password('-') - -def makeService(config): - port, user, password = config['port'], config['user'], config['password'] - p = portal.Portal( - service.Realm(service.Service(config["tracebacks"], config.get('namespace'))), - [checkers.InMemoryUsernamePasswordDatabaseDontUse(**{user: password})] - ) - return strports.service(port, pb.PBServerFactory(p, config["tracebacks"])) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/portforward.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/portforward.py deleted file mode 100644 index 2ad3f36..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/portforward.py +++ /dev/null @@ -1,27 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support module for making a port forwarder with twistd. -""" -from twisted.protocols import portforward -from twisted.python import usage -from twisted.application import strports - -class Options(usage.Options): - synopsis = "[options]" - longdesc = 'Port Forwarder.' - optParameters = [ - ["port", "p", "6666","Set the port number."], - ["host", "h", "localhost","Set the host."], - ["dest_port", "d", 6665,"Set the destination port."], - ] - - compData = usage.Completions( - optActions={"host": usage.CompleteHostnames()} - ) - -def makeService(config): - f = portforward.ProxyFactory(config['host'], int(config['dest_port'])) - return strports.service(config['port'], f) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/socks.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/socks.py deleted file mode 100644 index a418f0c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/socks.py +++ /dev/null @@ -1,38 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I am a support module for making SOCKSv4 servers with twistd. -""" - -from twisted.protocols import socks -from twisted.python import usage -from twisted.application import internet - - -class Options(usage.Options): - synopsis = "[-i ] [-p ] [-l ]" - optParameters = [["interface", "i", "127.0.0.1", "local interface to which we listen"], - ["port", "p", 1080, "Port on which to listen"], - ["log", "l", None, "file to log connection data to"]] - - compData = usage.Completions( - optActions={"log": usage.CompleteFiles("*.log"), - "interface": usage.CompleteNetInterfaces()} - ) - - longdesc = "Makes a SOCKSv4 server." - -def makeService(config): - if config["interface"] != "127.0.0.1": - print - print "WARNING:" - print " You have chosen to listen on a non-local interface." - print " This may allow intruders to access your local network" - print " if you run this on a firewall." - print - t = socks.SOCKSv4Factory(config['log']) - portno = int(config['port']) - return internet.TCPServer(portno, t, interface=config['interface']) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/telnet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/telnet.py deleted file mode 100644 index bc0c802..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/tap/telnet.py +++ /dev/null @@ -1,32 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support module for making a telnet server with twistd. -""" - -from twisted.manhole import telnet -from twisted.python import usage -from twisted.application import strports - -class Options(usage.Options): - synopsis = "[options]" - longdesc = "Makes a telnet server to a Python shell." - optParameters = [ - ["username", "u", "admin","set the login username"], - ["password", "w", "changeme","set the password"], - ["port", "p", "4040", "port to listen on"], - ] - - compData = usage.Completions( - optActions={"username": usage.CompleteUsernames()} - ) - -def makeService(config): - t = telnet.ShellFactory() - t.username, t.password = config['username'], config['password'] - s = strports.service(config['port'], t) - t.setService(s) - return s diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/__init__.py deleted file mode 100644 index dd5a58d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted's unit tests. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/_preamble.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/_preamble.py deleted file mode 100644 index e3e794e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/_preamble.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This makes sure Twisted-using child processes used in the test suite import -# the correct version of Twisted (ie, the version of Twisted under test). - -# This is a copy of the bin/_preamble.py script because it's not clear how to -# use the functionality for both things without having a copy. - -import sys, os - -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.exists(os.path.join(path, 'twisted', '__init__.py')): - sys.path.insert(0, path) - break - path = os.path.dirname(path) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/crash_test_dummy.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/crash_test_dummy.py deleted file mode 100644 index 5a30bd4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/crash_test_dummy.py +++ /dev/null @@ -1,34 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.python import components -from zope.interface import implements, Interface - -def foo(): - return 2 - -class X: - def __init__(self, x): - self.x = x - - def do(self): - #print 'X',self.x,'doing!' - pass - - -class XComponent(components.Componentized): - pass - -class IX(Interface): - pass - -class XA(components.Adapter): - implements(IX) - - def method(self): - # Kick start :( - pass - -components.registerAdapter(XA, X, IX) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/iosim.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/iosim.py deleted file mode 100644 index 1fcfd48..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/iosim.py +++ /dev/null @@ -1,407 +0,0 @@ -# -*- test-case-name: twisted.test.test_amp.TLSTests,twisted.test.test_iosim -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Utilities and helpers for simulating a network -""" - -from __future__ import print_function - -import itertools - -try: - from OpenSSL.SSL import Error as NativeOpenSSLError -except ImportError: - pass - -from zope.interface import implementer, directlyProvides - -from twisted.python.failure import Failure -from twisted.internet import error -from twisted.internet import interfaces - -class TLSNegotiation: - def __init__(self, obj, connectState): - self.obj = obj - self.connectState = connectState - self.sent = False - self.readyToSend = connectState - - def __repr__(self): - return 'TLSNegotiation(%r)' % (self.obj,) - - def pretendToVerify(self, other, tpt): - # Set the transport problems list here? disconnections? - # hmmmmm... need some negative path tests. - - if not self.obj.iosimVerify(other.obj): - tpt.disconnectReason = NativeOpenSSLError() - tpt.loseConnection() - - - -implementer(interfaces.IAddress) -class FakeAddress(object): - """ - The default address type for the host and peer of L{FakeTransport} - connections. - """ - - - -@implementer(interfaces.ITransport, - interfaces.ITLSTransport) -class FakeTransport: - """ - A wrapper around a file-like object to make it behave as a Transport. - - This doesn't actually stream the file to the attached protocol, - and is thus useful mainly as a utility for debugging protocols. - """ - - _nextserial = staticmethod(lambda counter=itertools.count(): next(counter)) - closed = 0 - disconnecting = 0 - disconnected = 0 - disconnectReason = error.ConnectionDone("Connection done") - producer = None - streamingProducer = 0 - tls = None - - def __init__(self, protocol, isServer, hostAddress=None, peerAddress=None): - """ - @param protocol: This transport will deliver bytes to this protocol. - @type protocol: L{IProtocol} provider - - @param isServer: C{True} if this is the accepting side of the - connection, C{False} if it is the connecting side. - @type isServer: L{bool} - - @param hostAddress: The value to return from C{getHost}. C{None} - results in a new L{FakeAddress} being created to use as the value. - @type hostAddress: L{IAddress} provider or L{NoneType} - - @param peerAddress: The value to return from C{getPeer}. C{None} - results in a new L{FakeAddress} being created to use as the value. - @type peerAddress: L{IAddress} provider or L{NoneType} - """ - self.protocol = protocol - self.isServer = isServer - self.stream = [] - self.serial = self._nextserial() - if hostAddress is None: - hostAddress = FakeAddress() - self.hostAddress = hostAddress - if peerAddress is None: - peerAddress = FakeAddress() - self.peerAddress = peerAddress - - - def __repr__(self): - return 'FakeTransport<%s,%s,%s>' % ( - self.isServer and 'S' or 'C', self.serial, - self.protocol.__class__.__name__) - - - def write(self, data): - if self.tls is not None: - self.tlsbuf.append(data) - else: - self.stream.append(data) - - def _checkProducer(self): - # Cheating; this is called at "idle" times to allow producers to be - # found and dealt with - if self.producer: - self.producer.resumeProducing() - - def registerProducer(self, producer, streaming): - """From abstract.FileDescriptor - """ - self.producer = producer - self.streamingProducer = streaming - if not streaming: - producer.resumeProducing() - - def unregisterProducer(self): - self.producer = None - - def stopConsuming(self): - self.unregisterProducer() - self.loseConnection() - - def writeSequence(self, iovec): - self.write("".join(iovec)) - - def loseConnection(self): - self.disconnecting = True - - - def abortConnection(self): - """ - For the time being, this is the same as loseConnection; no buffered - data will be lost. - """ - self.disconnecting = True - - - def reportDisconnect(self): - if self.tls is not None: - # We were in the middle of negotiating! Must have been a TLS problem. - err = NativeOpenSSLError() - else: - err = self.disconnectReason - self.protocol.connectionLost(Failure(err)) - - def logPrefix(self): - """ - Identify this transport/event source to the logging system. - """ - return "iosim" - - def getPeer(self): - return self.peerAddress - - def getHost(self): - return self.hostAddress - - def resumeProducing(self): - # Never sends data anyways - pass - - def pauseProducing(self): - # Never sends data anyways - pass - - def stopProducing(self): - self.loseConnection() - - def startTLS(self, contextFactory, beNormal=True): - # Nothing's using this feature yet, but startTLS has an undocumented - # second argument which defaults to true; if set to False, servers will - # behave like clients and clients will behave like servers. - connectState = self.isServer ^ beNormal - self.tls = TLSNegotiation(contextFactory, connectState) - self.tlsbuf = [] - - - def getOutBuffer(self): - """ - Get the pending writes from this transport, clearing them from the - pending buffer. - - @return: the bytes written with C{transport.write} - @rtype: L{bytes} - """ - S = self.stream - if S: - self.stream = [] - return b''.join(S) - elif self.tls is not None: - if self.tls.readyToSend: - # Only _send_ the TLS negotiation "packet" if I'm ready to. - self.tls.sent = True - return self.tls - else: - return None - else: - return None - - - def bufferReceived(self, buf): - if isinstance(buf, TLSNegotiation): - assert self.tls is not None # By the time you're receiving a - # negotiation, you have to have called - # startTLS already. - if self.tls.sent: - self.tls.pretendToVerify(buf, self) - self.tls = None # we're done with the handshake if we've gotten - # this far... although maybe it failed...? - # TLS started! Unbuffer... - b, self.tlsbuf = self.tlsbuf, None - self.writeSequence(b) - directlyProvides(self, interfaces.ISSLTransport) - else: - # We haven't sent our own TLS negotiation: time to do that! - self.tls.readyToSend = True - else: - self.protocol.dataReceived(buf) - - - -def makeFakeClient(clientProtocol): - """ - Create and return a new in-memory transport hooked up to the given protocol. - - @param clientProtocol: The client protocol to use. - @type clientProtocol: L{IProtocol} provider - - @return: The transport. - @rtype: L{FakeTransport} - """ - return FakeTransport(clientProtocol, isServer=False) - - - -def makeFakeServer(serverProtocol): - """ - Create and return a new in-memory transport hooked up to the given protocol. - - @param serverProtocol: The server protocol to use. - @type serverProtocol: L{IProtocol} provider - - @return: The transport. - @rtype: L{FakeTransport} - """ - return FakeTransport(serverProtocol, isServer=True) - - - -class IOPump: - """Utility to pump data between clients and servers for protocol testing. - - Perhaps this is a utility worthy of being in protocol.py? - """ - def __init__(self, client, server, clientIO, serverIO, debug): - self.client = client - self.server = server - self.clientIO = clientIO - self.serverIO = serverIO - self.debug = debug - - def flush(self, debug=False): - """Pump until there is no more input or output. - - Returns whether any data was moved. - """ - result = False - for x in range(1000): - if self.pump(debug): - result = True - else: - break - else: - assert 0, "Too long" - return result - - - def pump(self, debug=False): - """Move data back and forth. - - Returns whether any data was moved. - """ - if self.debug or debug: - print('-- GLUG --') - sData = self.serverIO.getOutBuffer() - cData = self.clientIO.getOutBuffer() - self.clientIO._checkProducer() - self.serverIO._checkProducer() - if self.debug or debug: - print('.') - # XXX slightly buggy in the face of incremental output - if cData: - print('C: ' + repr(cData)) - if sData: - print('S: ' + repr(sData)) - if cData: - self.serverIO.bufferReceived(cData) - if sData: - self.clientIO.bufferReceived(sData) - if cData or sData: - return True - if (self.serverIO.disconnecting and - not self.serverIO.disconnected): - if self.debug or debug: - print('* C') - self.serverIO.disconnected = True - self.clientIO.disconnecting = True - self.clientIO.reportDisconnect() - return True - if self.clientIO.disconnecting and not self.clientIO.disconnected: - if self.debug or debug: - print('* S') - self.clientIO.disconnected = True - self.serverIO.disconnecting = True - self.serverIO.reportDisconnect() - return True - return False - - - -def connect(serverProtocol, serverTransport, - clientProtocol, clientTransport, debug=False): - """ - Create a new L{IOPump} connecting two protocols. - - @param serverProtocol: The protocol to use on the accepting side of the - connection. - @type serverProtocol: L{IProtocol} provider - - @param serverTransport: The transport to associate with C{serverProtocol}. - @type serverTransport: L{FakeTransport} - - @param clientProtocol: The protocol to use on the initiating side of the - connection. - @type clientProtocol: L{IProtocol} provider - - @param clientTransport: The transport to associate with C{clientProtocol}. - @type clientTransport: L{FakeTransport} - - @param debug: A flag indicating whether to log information about what the - L{IOPump} is doing. - @type debug: L{bool} - - @return: An L{IOPump} which connects C{serverProtocol} and - C{clientProtocol} and delivers bytes between them when it is pumped. - @rtype: L{IOPump} - """ - serverProtocol.makeConnection(serverTransport) - clientProtocol.makeConnection(clientTransport) - pump = IOPump( - clientProtocol, serverProtocol, clientTransport, serverTransport, debug - ) - # kick off server greeting, etc - pump.flush() - return pump - - - -def connectedServerAndClient(ServerClass, ClientClass, - clientTransportFactory=makeFakeClient, - serverTransportFactory=makeFakeServer, - debug=False): - """ - Connect a given server and client class to each other. - - @param ServerClass: a callable that produces the server-side protocol. - @type ServerClass: 0-argument callable returning L{IProtocol} provider. - - @param ClientClass: like C{ServerClass} but for the other side of the - connection. - @type ClientClass: 0-argument callable returning L{IProtocol} provider. - - @param clientTransportFactory: a callable that produces the transport which - will be attached to the protocol returned from C{ClientClass}. - @type clientTransportFactory: callable taking (L{IProtocol}) and returning - L{FakeTransport} - - @param serverTransportFactory: a callable that produces the transport which - will be attached to the protocol returned from C{ServerClass}. - @type serverTransportFactory: callable taking (L{IProtocol}) and returning - L{FakeTransport} - - @param debug: Should this dump an escaped version of all traffic on this - connection to stdout for inspection? - @type debug: L{bool} - - @return: the client protocol, the server protocol, and an L{IOPump} which, - when its C{pump} and C{flush} methods are called, will move data - between the created client and server protocol instances. - @rtype: 3-L{tuple} of L{IProtocol}, L{IProtocol}, L{IOPump} - """ - c = ClientClass() - s = ServerClass() - cio = clientTransportFactory(c) - sio = serverTransportFactory(s) - return c, s, connect(s, sio, c, cio, debug) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/mock_win32process.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/mock_win32process.py deleted file mode 100644 index b70bdca..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/mock_win32process.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This is a mock win32process module. - -The purpose of this module is mock process creation for the PID test. - -CreateProcess(...) will spawn a process, and always return a PID of 42. -""" - -import win32process -GetExitCodeProcess = win32process.GetExitCodeProcess -STARTUPINFO = win32process.STARTUPINFO - -STARTF_USESTDHANDLES = win32process.STARTF_USESTDHANDLES - - -def CreateProcess(appName, - cmdline, - procSecurity, - threadSecurity, - inheritHandles, - newEnvironment, - env, - workingDir, - startupInfo): - """ - This function mocks the generated pid aspect of the win32.CreateProcess - function. - - the true win32process.CreateProcess is called - - return values are harvested in a tuple. - - all return values from createProcess are passed back to the calling - function except for the pid, the returned pid is hardcoded to 42 - """ - - hProcess, hThread, dwPid, dwTid = win32process.CreateProcess( - appName, - cmdline, - procSecurity, - threadSecurity, - inheritHandles, - newEnvironment, - env, - workingDir, - startupInfo) - dwPid = 42 - return (hProcess, hThread, dwPid, dwTid) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/myrebuilder1.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/myrebuilder1.py deleted file mode 100644 index f53e8c7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/myrebuilder1.py +++ /dev/null @@ -1,15 +0,0 @@ - -class A: - def a(self): - return 'a' -try: - object -except NameError: - pass -else: - class B(object, A): - def b(self): - return 'b' -class Inherit(A): - def a(self): - return 'c' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/myrebuilder2.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/myrebuilder2.py deleted file mode 100644 index d2a0d10..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/myrebuilder2.py +++ /dev/null @@ -1,16 +0,0 @@ - -class A: - def a(self): - return 'b' -try: - object -except NameError: - pass -else: - class B(A, object): - def b(self): - return 'c' - -class Inherit(A): - def a(self): - return 'd' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_basic.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_basic.py deleted file mode 100644 index a4c297b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_basic.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# Don't change the docstring, it's part of the tests -""" -I'm a test drop-in. The plugin system's unit tests use me. No one -else should. -""" - -from zope.interface import classProvides - -from twisted.plugin import IPlugin -from twisted.test.test_plugin import ITestPlugin, ITestPlugin2 - - - -class TestPlugin: - """ - A plugin used solely for testing purposes. - """ - - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) - - - -class AnotherTestPlugin: - """ - Another plugin used solely for testing purposes. - """ - - classProvides(ITestPlugin2, - IPlugin) - - def test(): - pass - test = staticmethod(test) - - - -class ThirdTestPlugin: - """ - Another plugin used solely for testing purposes. - """ - - classProvides(ITestPlugin2, - IPlugin) - - def test(): - pass - test = staticmethod(test) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_extra1.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_extra1.py deleted file mode 100644 index 9e4c8d4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_extra1.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test plugin used in L{twisted.test.test_plugin}. -""" - -from zope.interface import classProvides - -from twisted.plugin import IPlugin -from twisted.test.test_plugin import ITestPlugin - - - -class FourthTestPlugin: - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_extra2.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_extra2.py deleted file mode 100644 index a6b3f09..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/plugin_extra2.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test plugin used in L{twisted.test.test_plugin}. -""" - -from zope.interface import classProvides - -from twisted.plugin import IPlugin -from twisted.test.test_plugin import ITestPlugin - - - -class FourthTestPlugin: - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) - - - -class FifthTestPlugin: - """ - More documentation: I hate you. - """ - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_cmdline.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_cmdline.py deleted file mode 100644 index a0bbdb3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_cmdline.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -Write to stdout the command line args it received, one per line. -""" - -from __future__ import print_function - -import sys - - -for x in sys.argv[1:]: - print(x) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_echoer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_echoer.py deleted file mode 100644 index 8a7bf6d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_echoer.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Write back all data it receives.""" - -import sys - -data = sys.stdin.read(1) -while data: - sys.stdout.write(data) - sys.stdout.flush() - data = sys.stdin.read(1) -sys.stderr.write("byebye") -sys.stderr.flush() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_fds.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_fds.py deleted file mode 100644 index 51e90d8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_fds.py +++ /dev/null @@ -1,41 +0,0 @@ - -"""Write to a handful of file descriptors, to test the childFDs= argument of -reactor.spawnProcess() -""" - -from __future__ import print_function - -import os, sys - -debug = 0 - -if debug: stderr = os.fdopen(2, "w") - -if debug: print("this is stderr", file=stderr) - -abcd = os.read(0, 4) -if debug: print("read(0):", abcd, file=stderr) -if abcd != b"abcd": - sys.exit(1) - -if debug: print("os.write(1, righto)", file=stderr) -os.write(1, b"righto") - -efgh = os.read(3, 4) -if debug: print("read(3):", file=stderr) -if efgh != b"efgh": - sys.exit(2) - -if debug: print("os.close(4)", file=stderr) -os.close(4) - -eof = os.read(5, 4) -if debug: print("read(5):", eof, file=stderr) -if eof != b"": - sys.exit(3) - -if debug: print("os.write(1, closed)", file=stderr) -os.write(1, b"closed") - -if debug: print("sys.exit(0)", file=stderr) -sys.exit(0) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_linger.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_linger.py deleted file mode 100644 index b78e11a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_linger.py +++ /dev/null @@ -1,16 +0,0 @@ - -"""Write to a file descriptor and then close it, waiting a few seconds before -quitting. This serves to make sure SIGCHLD is actually being noticed. -""" - -import os, sys, time - -print("here is some text") -time.sleep(1) -print("goodbye") -os.close(1) -os.close(2) - -time.sleep(2) - -sys.exit(0) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_reader.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_reader.py deleted file mode 100644 index be37a7c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_reader.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Script used by test_process.TestTwoProcesses""" - -# run until stdin is closed, then quit - -import sys - -while 1: - d = sys.stdin.read() - if len(d) == 0: - sys.exit(0) - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_signal.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_signal.py deleted file mode 100644 index d3e20cd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_signal.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys, signal - -signal.signal(signal.SIGINT, signal.SIG_DFL) -if getattr(signal, "SIGHUP", None) is not None: - signal.signal(signal.SIGHUP, signal.SIG_DFL) -print('ok, signal us') -sys.stdin.read() -sys.exit(1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_stdinreader.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_stdinreader.py deleted file mode 100644 index b8ff0bc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_stdinreader.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Script used by twisted.test.test_process on win32.""" - -import sys, os, msvcrt -msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) -msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) - - -sys.stdout.write("out\n") -sys.stdout.flush() -sys.stderr.write("err\n") -sys.stderr.flush() - -data = sys.stdin.read() - -sys.stdout.write(data) -sys.stdout.write("\nout\n") -sys.stderr.write("err\n") - -sys.stdout.flush() -sys.stderr.flush() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_tester.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_tester.py deleted file mode 100644 index 146ffcc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_tester.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Test program for processes.""" - -import sys, os - -# Twisted is unimportable from this file, so just do the PY3 check manually -if sys.version_info < (3, 0): - _PY3 = False -else: - _PY3 = True - -test_file_match = "process_test.log.*" -test_file = "process_test.log.%d" % os.getpid() - -def main(): - f = open(test_file, 'wb') - - if _PY3: - stdin = sys.stdin.buffer - stderr = sys.stderr.buffer - stdout = sys.stdout.buffer - else: - stdin = sys.stdin - stdout = sys.stdout - stderr = sys.stderr - - # stage 1 - b = stdin.read(4) - f.write(b"one: " + b + b"\n") - - # stage 2 - stdout.write(b) - stdout.flush() - os.close(sys.stdout.fileno()) - - # and a one, and a two, and a... - b = stdin.read(4) - f.write(b"two: " + b + b"\n") - - # stage 3 - stderr.write(b) - stderr.flush() - os.close(stderr.fileno()) - - # stage 4 - b = stdin.read(4) - f.write(b"three: " + b + b"\n") - - # exit with status code 23 - sys.exit(23) - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_tty.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_tty.py deleted file mode 100644 index f36d8cb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_tty.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Test to make sure we can open /dev/tty""" - -f = open("/dev/tty", "rb+", buffering=0) -a = f.readline() -f.write(a) -f.close() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_twisted.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_twisted.py deleted file mode 100644 index 5704a4f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/process_twisted.py +++ /dev/null @@ -1,45 +0,0 @@ -"""A process that reads from stdin and out using Twisted.""" - -from __future__ import division, absolute_import - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -pos = os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') -if pos != -1: - sys.path.insert(0, os.path.abspath(sys.argv[0])[:pos+8]) -sys.path.insert(0, os.curdir) -### end of preamble - - -from twisted.python import log -from zope.interface import implementer -from twisted.internet import interfaces - -log.startLogging(sys.stderr) - -from twisted.internet import protocol, reactor, stdio - - -@implementer(interfaces.IHalfCloseableProtocol) -class Echo(protocol.Protocol): - - def connectionMade(self): - print("connection made") - - def dataReceived(self, data): - self.transport.write(data) - - def readConnectionLost(self): - print("readConnectionLost") - self.transport.loseConnection() - def writeConnectionLost(self): - print("writeConnectionLost") - - def connectionLost(self, reason): - print("connectionLost", reason) - reactor.stop() - -stdio.StandardIO(Echo()) -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/proto_helpers.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/proto_helpers.py deleted file mode 100644 index 3b0d27f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/proto_helpers.py +++ /dev/null @@ -1,690 +0,0 @@ -# -*- test-case-name: twisted.test.test_stringtransport -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Assorted functionality which is commonly useful when writing unit tests. -""" - -from __future__ import division, absolute_import - -from socket import AF_INET, AF_INET6 -from io import BytesIO - -from zope.interface import implementer, implementedBy -from zope.interface.verify import verifyClass - -from twisted.python import failure -from twisted.python.compat import unicode -from twisted.internet.interfaces import ( - ITransport, IConsumer, IPushProducer, IConnector, IReactorTCP, IReactorSSL, - IReactorUNIX, IReactorSocket, IListeningPort, IReactorFDSet -) -from twisted.internet.abstract import isIPv6Address -from twisted.internet.error import UnsupportedAddressFamily -from twisted.protocols import basic -from twisted.internet import protocol, error, address - -from twisted.internet.task import Clock -from twisted.internet.address import IPv4Address, UNIXAddress, IPv6Address - - -class AccumulatingProtocol(protocol.Protocol): - """ - L{AccumulatingProtocol} is an L{IProtocol} implementation which collects - the data delivered to it and can fire a Deferred when it is connected or - disconnected. - - @ivar made: A flag indicating whether C{connectionMade} has been called. - @ivar data: Bytes giving all the data passed to C{dataReceived}. - @ivar closed: A flag indicated whether C{connectionLost} has been called. - @ivar closedReason: The value of the I{reason} parameter passed to - C{connectionLost}. - @ivar closedDeferred: If set to a L{Deferred}, this will be fired when - C{connectionLost} is called. - """ - made = closed = 0 - closedReason = None - - closedDeferred = None - - data = b"" - - factory = None - - def connectionMade(self): - self.made = 1 - if (self.factory is not None and - self.factory.protocolConnectionMade is not None): - d = self.factory.protocolConnectionMade - self.factory.protocolConnectionMade = None - d.callback(self) - - def dataReceived(self, data): - self.data += data - - def connectionLost(self, reason): - self.closed = 1 - self.closedReason = reason - if self.closedDeferred is not None: - d, self.closedDeferred = self.closedDeferred, None - d.callback(None) - - -class LineSendingProtocol(basic.LineReceiver): - lostConn = False - - def __init__(self, lines, start = True): - self.lines = lines[:] - self.response = [] - self.start = start - - def connectionMade(self): - if self.start: - for line in self.lines: - self.sendLine(line) - - def lineReceived(self, line): - if not self.start: - for line in self.lines: - self.sendLine(line) - self.lines = [] - self.response.append(line) - - def connectionLost(self, reason): - self.lostConn = True - - -class FakeDatagramTransport: - noAddr = object() - - def __init__(self): - self.written = [] - - def write(self, packet, addr=noAddr): - self.written.append((packet, addr)) - - - -@implementer(ITransport, IConsumer, IPushProducer) -class StringTransport: - """ - A transport implementation which buffers data in memory and keeps track of - its other state without providing any behavior. - - L{StringTransport} has a number of attributes which are not part of any of - the interfaces it claims to implement. These attributes are provided for - testing purposes. Implementation code should not use any of these - attributes; they are not provided by other transports. - - @ivar disconnecting: A C{bool} which is C{False} until L{loseConnection} is - called, then C{True}. - - @ivar producer: If a producer is currently registered, C{producer} is a - reference to it. Otherwise, C{None}. - - @ivar streaming: If a producer is currently registered, C{streaming} refers - to the value of the second parameter passed to C{registerProducer}. - - @ivar hostAddr: C{None} or an object which will be returned as the host - address of this transport. If C{None}, a nasty tuple will be returned - instead. - - @ivar peerAddr: C{None} or an object which will be returned as the peer - address of this transport. If C{None}, a nasty tuple will be returned - instead. - - @ivar producerState: The state of this L{StringTransport} in its capacity - as an L{IPushProducer}. One of C{'producing'}, C{'paused'}, or - C{'stopped'}. - - @ivar io: A L{BytesIO} which holds the data which has been written to this - transport since the last call to L{clear}. Use L{value} instead of - accessing this directly. - """ - - disconnecting = False - - producer = None - streaming = None - - hostAddr = None - peerAddr = None - - producerState = 'producing' - - def __init__(self, hostAddress=None, peerAddress=None): - self.clear() - if hostAddress is not None: - self.hostAddr = hostAddress - if peerAddress is not None: - self.peerAddr = peerAddress - self.connected = True - - def clear(self): - """ - Discard all data written to this transport so far. - - This is not a transport method. It is intended for tests. Do not use - it in implementation code. - """ - self.io = BytesIO() - - - def value(self): - """ - Retrieve all data which has been buffered by this transport. - - This is not a transport method. It is intended for tests. Do not use - it in implementation code. - - @return: A C{bytes} giving all data written to this transport since the - last call to L{clear}. - @rtype: C{bytes} - """ - return self.io.getvalue() - - - # ITransport - def write(self, data): - if isinstance(data, unicode): # no, really, I mean it - raise TypeError("Data must not be unicode") - self.io.write(data) - - - def writeSequence(self, data): - self.io.write(b''.join(data)) - - - def loseConnection(self): - """ - Close the connection. Does nothing besides toggle the C{disconnecting} - instance variable to C{True}. - """ - self.disconnecting = True - - - def getPeer(self): - if self.peerAddr is None: - return address.IPv4Address('TCP', '192.168.1.1', 54321) - return self.peerAddr - - - def getHost(self): - if self.hostAddr is None: - return address.IPv4Address('TCP', '10.0.0.1', 12345) - return self.hostAddr - - - # IConsumer - def registerProducer(self, producer, streaming): - if self.producer is not None: - raise RuntimeError("Cannot register two producers") - self.producer = producer - self.streaming = streaming - - - def unregisterProducer(self): - if self.producer is None: - raise RuntimeError( - "Cannot unregister a producer unless one is registered") - self.producer = None - self.streaming = None - - - # IPushProducer - def _checkState(self): - if self.disconnecting: - raise RuntimeError( - "Cannot resume producing after loseConnection") - if self.producerState == 'stopped': - raise RuntimeError("Cannot resume a stopped producer") - - - def pauseProducing(self): - self._checkState() - self.producerState = 'paused' - - - def stopProducing(self): - self.producerState = 'stopped' - - - def resumeProducing(self): - self._checkState() - self.producerState = 'producing' - - - -class StringTransportWithDisconnection(StringTransport): - """ - A L{StringTransport} which can be disconnected. - """ - - def loseConnection(self): - if self.connected: - self.connected = False - self.protocol.connectionLost( - failure.Failure(error.ConnectionDone("Bye."))) - - - -class StringIOWithoutClosing(BytesIO): - """ - A BytesIO that can't be closed. - """ - def close(self): - """ - Do nothing. - """ - - - -@implementer(IListeningPort) -class _FakePort(object): - """ - A fake L{IListeningPort} to be used in tests. - - @ivar _hostAddress: The L{IAddress} this L{IListeningPort} is pretending - to be listening on. - """ - - def __init__(self, hostAddress): - """ - @param hostAddress: An L{IAddress} this L{IListeningPort} should - pretend to be listening on. - """ - self._hostAddress = hostAddress - - - def startListening(self): - """ - Fake L{IListeningPort.startListening} that doesn't do anything. - """ - - - def stopListening(self): - """ - Fake L{IListeningPort.stopListening} that doesn't do anything. - """ - - - def getHost(self): - """ - Fake L{IListeningPort.getHost} that returns our L{IAddress}. - """ - return self._hostAddress - - - -@implementer(IConnector) -class _FakeConnector(object): - """ - A fake L{IConnector} that allows us to inspect if it has been told to stop - connecting. - - @ivar stoppedConnecting: has this connector's - L{FakeConnector.stopConnecting} method been invoked yet? - - @ivar _address: An L{IAddress} provider that represents our destination. - """ - _disconnected = False - stoppedConnecting = False - - def __init__(self, address): - """ - @param address: An L{IAddress} provider that represents this - connector's destination. - """ - self._address = address - - - def stopConnecting(self): - """ - Implement L{IConnector.stopConnecting} and set - L{FakeConnector.stoppedConnecting} to C{True} - """ - self.stoppedConnecting = True - - - def disconnect(self): - """ - Implement L{IConnector.disconnect} as a no-op. - """ - self._disconnected = True - - - def connect(self): - """ - Implement L{IConnector.connect} as a no-op. - """ - - - def getDestination(self): - """ - Implement L{IConnector.getDestination} to return the C{address} passed - to C{__init__}. - """ - return self._address - - - -@implementer( - IReactorTCP, IReactorSSL, IReactorUNIX, IReactorSocket, IReactorFDSet -) -class MemoryReactor(object): - """ - A fake reactor to be used in tests. This reactor doesn't actually do - much that's useful yet. It accepts TCP connection setup attempts, but - they will never succeed. - - @ivar tcpClients: a list that keeps track of connection attempts (ie, calls - to C{connectTCP}). - @type tcpClients: C{list} - - @ivar tcpServers: a list that keeps track of server listen attempts (ie, calls - to C{listenTCP}). - @type tcpServers: C{list} - - @ivar sslClients: a list that keeps track of connection attempts (ie, - calls to C{connectSSL}). - @type sslClients: C{list} - - @ivar sslServers: a list that keeps track of server listen attempts (ie, - calls to C{listenSSL}). - @type sslServers: C{list} - - @ivar unixClients: a list that keeps track of connection attempts (ie, - calls to C{connectUNIX}). - @type unixClients: C{list} - - @ivar unixServers: a list that keeps track of server listen attempts (ie, - calls to C{listenUNIX}). - @type unixServers: C{list} - - @ivar adoptedPorts: a list that keeps track of server listen attempts (ie, - calls to C{adoptStreamPort}). - - @ivar adoptedStreamConnections: a list that keeps track of stream-oriented - connections added using C{adoptStreamConnection}. - """ - - def __init__(self): - """ - Initialize the tracking lists. - """ - self.tcpClients = [] - self.tcpServers = [] - self.sslClients = [] - self.sslServers = [] - self.unixClients = [] - self.unixServers = [] - self.adoptedPorts = [] - self.adoptedStreamConnections = [] - self.connectors = [] - - self.readers = set() - self.writers = set() - - - def adoptStreamPort(self, fileno, addressFamily, factory): - """ - Fake L{IReactorSocket.adoptStreamPort}, that logs the call and returns - an L{IListeningPort}. - """ - if addressFamily == AF_INET: - addr = IPv4Address('TCP', '0.0.0.0', 1234) - elif addressFamily == AF_INET6: - addr = IPv6Address('TCP', '::', 1234) - else: - raise UnsupportedAddressFamily() - - self.adoptedPorts.append((fileno, addressFamily, factory)) - return _FakePort(addr) - - - def adoptStreamConnection(self, fileDescriptor, addressFamily, factory): - """ - Record the given stream connection in C{adoptedStreamConnections}. - - @see: L{twisted.internet.interfaces.IReactorSocket.adoptStreamConnection} - """ - self.adoptedStreamConnections.append(( - fileDescriptor, addressFamily, factory)) - - - def adoptDatagramPort(self, fileno, addressFamily, protocol, - maxPacketSize=8192): - """ - Fake L{IReactorSocket.adoptDatagramPort}, that logs the call and returns - a fake L{IListeningPort}. - - @see: L{twisted.internet.interfaces.IReactorSocket.adoptDatagramPort} - """ - if addressFamily == AF_INET: - addr = IPv4Address('UDP', '0.0.0.0', 1234) - elif addressFamily == AF_INET6: - addr = IPv6Address('UDP', '::', 1234) - else: - raise UnsupportedAddressFamily() - - self.adoptedPorts.append( - (fileno, addressFamily, protocol, maxPacketSize)) - return _FakePort(addr) - - - def listenTCP(self, port, factory, backlog=50, interface=''): - """ - Fake L{reactor.listenTCP}, that logs the call and returns an - L{IListeningPort}. - """ - self.tcpServers.append((port, factory, backlog, interface)) - if isIPv6Address(interface): - address = IPv6Address('TCP', interface, port) - else: - address = IPv4Address('TCP', '0.0.0.0', port) - return _FakePort(address) - - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - """ - Fake L{reactor.connectTCP}, that logs the call and returns an - L{IConnector}. - """ - self.tcpClients.append((host, port, factory, timeout, bindAddress)) - if isIPv6Address(host): - conn = _FakeConnector(IPv6Address('TCP', host, port)) - else: - conn = _FakeConnector(IPv4Address('TCP', host, port)) - factory.startedConnecting(conn) - self.connectors.append(conn) - return conn - - - def listenSSL(self, port, factory, contextFactory, - backlog=50, interface=''): - """ - Fake L{reactor.listenSSL}, that logs the call and returns an - L{IListeningPort}. - """ - self.sslServers.append((port, factory, contextFactory, - backlog, interface)) - return _FakePort(IPv4Address('TCP', '0.0.0.0', port)) - - - def connectSSL(self, host, port, factory, contextFactory, - timeout=30, bindAddress=None): - """ - Fake L{reactor.connectSSL}, that logs the call and returns an - L{IConnector}. - """ - self.sslClients.append((host, port, factory, contextFactory, - timeout, bindAddress)) - conn = _FakeConnector(IPv4Address('TCP', host, port)) - factory.startedConnecting(conn) - self.connectors.append(conn) - return conn - - - def listenUNIX(self, address, factory, - backlog=50, mode=0o666, wantPID=0): - """ - Fake L{reactor.listenUNIX}, that logs the call and returns an - L{IListeningPort}. - """ - self.unixServers.append((address, factory, backlog, mode, wantPID)) - return _FakePort(UNIXAddress(address)) - - - def connectUNIX(self, address, factory, timeout=30, checkPID=0): - """ - Fake L{reactor.connectUNIX}, that logs the call and returns an - L{IConnector}. - """ - self.unixClients.append((address, factory, timeout, checkPID)) - conn = _FakeConnector(UNIXAddress(address)) - factory.startedConnecting(conn) - self.connectors.append(conn) - return conn - - - def addReader(self, reader): - """ - Fake L{IReactorFDSet.addReader} which adds the reader to a local set. - """ - self.readers.add(reader) - - - def removeReader(self, reader): - """ - Fake L{IReactorFDSet.removeReader} which removes the reader from a - local set. - """ - self.readers.discard(reader) - - - def addWriter(self, writer): - """ - Fake L{IReactorFDSet.addWriter} which adds the writer to a local set. - """ - self.writers.add(writer) - - - def removeWriter(self, writer): - """ - Fake L{IReactorFDSet.removeWriter} which removes the writer from a - local set. - """ - self.writers.discard(writer) - - - def getReaders(self): - """ - Fake L{IReactorFDSet.getReaders} which returns a list of readers from - the local set. - """ - return list(self.readers) - - - def getWriters(self): - """ - Fake L{IReactorFDSet.getWriters} which returns a list of writers from - the local set. - """ - return list(self.writers) - - - def removeAll(self): - """ - Fake L{IReactorFDSet.removeAll} which removed all readers and writers - from the local sets. - """ - self.readers.clear() - self.writers.clear() - - -for iface in implementedBy(MemoryReactor): - verifyClass(iface, MemoryReactor) - - - -class MemoryReactorClock(MemoryReactor, Clock): - def __init__(self): - MemoryReactor.__init__(self) - Clock.__init__(self) - - - -@implementer(IReactorTCP, IReactorSSL, IReactorUNIX, IReactorSocket) -class RaisingMemoryReactor(object): - """ - A fake reactor to be used in tests. It accepts TCP connection setup - attempts, but they will fail. - - @ivar _listenException: An instance of an L{Exception} - @ivar _connectException: An instance of an L{Exception} - """ - - def __init__(self, listenException=None, connectException=None): - """ - @param listenException: An instance of an L{Exception} to raise when any - C{listen} method is called. - - @param connectException: An instance of an L{Exception} to raise when - any C{connect} method is called. - """ - self._listenException = listenException - self._connectException = connectException - - - def adoptStreamPort(self, fileno, addressFamily, factory): - """ - Fake L{IReactorSocket.adoptStreamPort}, that raises - L{self._listenException}. - """ - raise self._listenException - - - def listenTCP(self, port, factory, backlog=50, interface=''): - """ - Fake L{reactor.listenTCP}, that raises L{self._listenException}. - """ - raise self._listenException - - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - """ - Fake L{reactor.connectTCP}, that raises L{self._connectException}. - """ - raise self._connectException - - - def listenSSL(self, port, factory, contextFactory, - backlog=50, interface=''): - """ - Fake L{reactor.listenSSL}, that raises L{self._listenException}. - """ - raise self._listenException - - - def connectSSL(self, host, port, factory, contextFactory, - timeout=30, bindAddress=None): - """ - Fake L{reactor.connectSSL}, that raises L{self._connectException}. - """ - raise self._connectException - - - def listenUNIX(self, address, factory, - backlog=50, mode=0o666, wantPID=0): - """ - Fake L{reactor.listenUNIX}, that raises L{self._listenException}. - """ - raise self._listenException - - - def connectUNIX(self, address, factory, timeout=30, checkPID=0): - """ - Fake L{reactor.connectUNIX}, that raises L{self._connectException}. - """ - raise self._connectException diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/raiser.c b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/raiser.c deleted file mode 100644 index b9ba176..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/raiser.c +++ /dev/null @@ -1,1443 +0,0 @@ -/* Generated by Cython 0.14.1 on Tue Mar 8 19:41:56 2011 */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" -#ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. -#else - -#include /* For offsetof */ -#ifndef offsetof -#define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) -#endif - -#if !defined(WIN32) && !defined(MS_WINDOWS) - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __fastcall - #define __fastcall - #endif -#endif - -#ifndef DL_IMPORT - #define DL_IMPORT(t) t -#endif -#ifndef DL_EXPORT - #define DL_EXPORT(t) t -#endif - -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif - -#if PY_VERSION_HEX < 0x02040000 - #define METH_COEXIST 0 - #define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type) - #define PyDict_Contains(d,o) PySequence_Contains(d,o) -#endif - -#if PY_VERSION_HEX < 0x02050000 - typedef int Py_ssize_t; - #define PY_SSIZE_T_MAX INT_MAX - #define PY_SSIZE_T_MIN INT_MIN - #define PY_FORMAT_SIZE_T "" - #define PyInt_FromSsize_t(z) PyInt_FromLong(z) - #define PyInt_AsSsize_t(o) PyInt_AsLong(o) - #define PyNumber_Index(o) PyNumber_Int(o) - #define PyIndex_Check(o) PyNumber_Check(o) - #define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message) -#endif - -#if PY_VERSION_HEX < 0x02060000 - #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) - #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) - #define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) - #define PyVarObject_HEAD_INIT(type, size) \ - PyObject_HEAD_INIT(type) size, - #define PyType_Modified(t) - - typedef struct { - void *buf; - PyObject *obj; - Py_ssize_t len; - Py_ssize_t itemsize; - int readonly; - int ndim; - char *format; - Py_ssize_t *shape; - Py_ssize_t *strides; - Py_ssize_t *suboffsets; - void *internal; - } Py_buffer; - - #define PyBUF_SIMPLE 0 - #define PyBUF_WRITABLE 0x0001 - #define PyBUF_FORMAT 0x0004 - #define PyBUF_ND 0x0008 - #define PyBUF_STRIDES (0x0010 | PyBUF_ND) - #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) - #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) - #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) - #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) - -#endif - -#if PY_MAJOR_VERSION < 3 - #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" -#else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" -#endif - -#if PY_MAJOR_VERSION >= 3 - #define Py_TPFLAGS_CHECKTYPES 0 - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif - -#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3) - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif - -#if PY_MAJOR_VERSION >= 3 - #define PyBaseString_Type PyUnicode_Type - #define PyStringObject PyUnicodeObject - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -#endif - -#if PY_VERSION_HEX < 0x02060000 - #define PyBytesObject PyStringObject - #define PyBytes_Type PyString_Type - #define PyBytes_Check PyString_Check - #define PyBytes_CheckExact PyString_CheckExact - #define PyBytes_FromString PyString_FromString - #define PyBytes_FromStringAndSize PyString_FromStringAndSize - #define PyBytes_FromFormat PyString_FromFormat - #define PyBytes_DecodeEscape PyString_DecodeEscape - #define PyBytes_AsString PyString_AsString - #define PyBytes_AsStringAndSize PyString_AsStringAndSize - #define PyBytes_Size PyString_Size - #define PyBytes_AS_STRING PyString_AS_STRING - #define PyBytes_GET_SIZE PyString_GET_SIZE - #define PyBytes_Repr PyString_Repr - #define PyBytes_Concat PyString_Concat - #define PyBytes_ConcatAndDel PyString_ConcatAndDel -#endif - -#if PY_VERSION_HEX < 0x02060000 - #define PySet_Check(obj) PyObject_TypeCheck(obj, &PySet_Type) - #define PyFrozenSet_Check(obj) PyObject_TypeCheck(obj, &PyFrozenSet_Type) -#endif -#ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) -#endif - -#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) - -#if PY_MAJOR_VERSION >= 3 - #define PyIntObject PyLongObject - #define PyInt_Type PyLong_Type - #define PyInt_Check(op) PyLong_Check(op) - #define PyInt_CheckExact(op) PyLong_CheckExact(op) - #define PyInt_FromString PyLong_FromString - #define PyInt_FromUnicode PyLong_FromUnicode - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t - #define PyInt_FromSsize_t PyLong_FromSsize_t - #define PyInt_AsLong PyLong_AsLong - #define PyInt_AS_LONG PyLong_AS_LONG - #define PyInt_AsSsize_t PyLong_AsSsize_t - #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask - #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask -#endif - -#if PY_MAJOR_VERSION >= 3 - #define PyBoolObject PyLongObject -#endif - - -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) -#else - #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) -#endif - -#if (PY_MAJOR_VERSION < 3) || (PY_VERSION_HEX >= 0x03010300) - #define __Pyx_PySequence_GetSlice(obj, a, b) PySequence_GetSlice(obj, a, b) - #define __Pyx_PySequence_SetSlice(obj, a, b, value) PySequence_SetSlice(obj, a, b, value) - #define __Pyx_PySequence_DelSlice(obj, a, b) PySequence_DelSlice(obj, a, b) -#else - #define __Pyx_PySequence_GetSlice(obj, a, b) (unlikely(!(obj)) ? \ - (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), (PyObject*)0) : \ - (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_GetSlice(obj, a, b)) : \ - (PyErr_Format(PyExc_TypeError, "'%.200s' object is unsliceable", (obj)->ob_type->tp_name), (PyObject*)0))) - #define __Pyx_PySequence_SetSlice(obj, a, b, value) (unlikely(!(obj)) ? \ - (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \ - (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_SetSlice(obj, a, b, value)) : \ - (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice assignment", (obj)->ob_type->tp_name), -1))) - #define __Pyx_PySequence_DelSlice(obj, a, b) (unlikely(!(obj)) ? \ - (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \ - (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_DelSlice(obj, a, b)) : \ - (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice deletion", (obj)->ob_type->tp_name), -1))) -#endif - -#if PY_MAJOR_VERSION >= 3 - #define PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func)) -#endif - -#if PY_VERSION_HEX < 0x02050000 - #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),((char *)(n))) - #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a)) - #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),((char *)(n))) -#else - #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),(n)) - #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a)) - #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),(n)) -#endif - -#if PY_VERSION_HEX < 0x02050000 - #define __Pyx_NAMESTR(n) ((char *)(n)) - #define __Pyx_DOCSTR(n) ((char *)(n)) -#else - #define __Pyx_NAMESTR(n) (n) - #define __Pyx_DOCSTR(n) (n) -#endif - -#ifdef __cplusplus -#define __PYX_EXTERN_C extern "C" -#else -#define __PYX_EXTERN_C extern -#endif - -#if defined(WIN32) || defined(MS_WINDOWS) -#define _USE_MATH_DEFINES -#endif -#include -#define __PYX_HAVE_API__twisted__test__raiser - -#ifdef PYREX_WITHOUT_ASSERTIONS -#define CYTHON_WITHOUT_ASSERTIONS -#endif - - -/* inline attribute */ -#ifndef CYTHON_INLINE - #if defined(__GNUC__) - #define CYTHON_INLINE __inline__ - #elif defined(_MSC_VER) - #define CYTHON_INLINE __inline - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_INLINE inline - #else - #define CYTHON_INLINE - #endif -#endif - -/* unused attribute */ -#ifndef CYTHON_UNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -# elif defined(__ICC) || defined(__INTEL_COMPILER) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -#endif - -typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/ - - -/* Type Conversion Predeclarations */ - -#define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s) -#define __Pyx_PyBytes_AsUString(s) ((unsigned char*) PyBytes_AsString(s)) - -#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); - -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); -static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*); - -#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - - -#ifdef __GNUC__ -/* Test for GCC > 2.95 */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#else /* __GNUC__ > 2 ... */ -#define likely(x) (x) -#define unlikely(x) (x) -#endif /* __GNUC__ > 2 ... */ -#else /* __GNUC__ */ -#define likely(x) (x) -#define unlikely(x) (x) -#endif /* __GNUC__ */ - -static PyObject *__pyx_m; -static PyObject *__pyx_b; -static PyObject *__pyx_empty_tuple; -static PyObject *__pyx_empty_bytes; -static int __pyx_lineno; -static int __pyx_clineno = 0; -static const char * __pyx_cfilenm= __FILE__; -static const char *__pyx_filename; - - -static const char *__pyx_f[] = { - "raiser.pyx", -}; - -/* Type declarations */ - -#ifndef CYTHON_REFNANNY - #define CYTHON_REFNANNY 0 -#endif - -#if CYTHON_REFNANNY - typedef struct { - void (*INCREF)(void*, PyObject*, int); - void (*DECREF)(void*, PyObject*, int); - void (*GOTREF)(void*, PyObject*, int); - void (*GIVEREF)(void*, PyObject*, int); - void* (*SetupContext)(const char*, int, const char*); - void (*FinishContext)(void**); - } __Pyx_RefNannyAPIStruct; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule((char *)modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); - end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; - } - #define __Pyx_RefNannySetupContext(name) void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) - #define __Pyx_RefNannyFinishContext() __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0) -#else - #define __Pyx_RefNannySetupContext(name) - #define __Pyx_RefNannyFinishContext() - #define __Pyx_INCREF(r) Py_INCREF(r) - #define __Pyx_DECREF(r) Py_DECREF(r) - #define __Pyx_GOTREF(r) - #define __Pyx_GIVEREF(r) - #define __Pyx_XDECREF(r) Py_XDECREF(r) -#endif /* CYTHON_REFNANNY */ -#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0) -#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0) - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ - -static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ -static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ - -static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases); /*proto*/ - -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, - PyObject *modname); /*proto*/ - -static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *); - -static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *); - -static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject *); - -static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject *); - -static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject *); - -static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject *); - -static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject *); - -static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject *); - -static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject *); - -static CYTHON_INLINE int __Pyx_PyInt_AsLongDouble(PyObject *); - -static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject *); - -static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject *); - -static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject *); - -static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject *); - -static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject *); - -static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject *); - -static void __Pyx_AddTraceback(const char *funcname); /*proto*/ - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ -/* Module declarations from twisted.test.raiser */ - -#define __Pyx_MODULE_NAME "twisted.test.raiser" -static int __pyx_module_is_main_twisted__test__raiser = 0; - -/* Implementation of twisted.test.raiser */ -static PyObject *__pyx_builtin_Exception; -static char __pyx_k_1[] = "This function is intentionally broken"; -static char __pyx_k_3[] = "\nA trivial extension that just raises an exception.\nSee L{twisted.test.test_failure.test_failureConstructionWithMungedStackSucceeds}.\n"; -static char __pyx_k_4[] = "\n A speficic exception only used to be identified in tests.\n "; -static char __pyx_k_5[] = "twisted.test.raiser"; -static char __pyx_k____main__[] = "__main__"; -static char __pyx_k____test__[] = "__test__"; -static char __pyx_k__Exception[] = "Exception"; -static char __pyx_k__raiseException[] = "raiseException"; -static char __pyx_k__RaiserException[] = "RaiserException"; -static PyObject *__pyx_kp_s_1; -static PyObject *__pyx_kp_s_4; -static PyObject *__pyx_n_s_5; -static PyObject *__pyx_n_s__Exception; -static PyObject *__pyx_n_s__RaiserException; -static PyObject *__pyx_n_s____main__; -static PyObject *__pyx_n_s____test__; -static PyObject *__pyx_n_s__raiseException; -static PyObject *__pyx_k_tuple_2; - -/* "twisted/test/raiser.pyx":17 - * - * - * def raiseException(): # <<<<<<<<<<<<<< - * """ - * Raise L{RaiserException}. - */ - -static PyObject *__pyx_pf_7twisted_4test_6raiser_raiseException(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ -static char __pyx_doc_7twisted_4test_6raiser_raiseException[] = "\n Raise L{RaiserException}.\n "; -static PyMethodDef __pyx_mdef_7twisted_4test_6raiser_raiseException = {__Pyx_NAMESTR("raiseException"), (PyCFunction)__pyx_pf_7twisted_4test_6raiser_raiseException, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_7twisted_4test_6raiser_raiseException)}; -static PyObject *__pyx_pf_7twisted_4test_6raiser_raiseException(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) { - PyObject *__pyx_r = NULL; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - __Pyx_RefNannySetupContext("raiseException"); - __pyx_self = __pyx_self; - - /* "twisted/test/raiser.pyx":21 - * Raise L{RaiserException}. - * """ - * raise RaiserException("This function is intentionally broken") # <<<<<<<<<<<<<< - */ - __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__RaiserException); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_2), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_Raise(__pyx_t_2, 0, 0); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_AddTraceback("twisted.test.raiser.raiseException"); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef __pyx_moduledef = { - PyModuleDef_HEAD_INIT, - __Pyx_NAMESTR("raiser"), - __Pyx_DOCSTR(__pyx_k_3), /* m_doc */ - -1, /* m_size */ - __pyx_methods /* m_methods */, - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ -}; -#endif - -static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 0}, - {&__pyx_kp_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 0}, - {&__pyx_n_s_5, __pyx_k_5, sizeof(__pyx_k_5), 0, 0, 1, 1}, - {&__pyx_n_s__Exception, __pyx_k__Exception, sizeof(__pyx_k__Exception), 0, 0, 1, 1}, - {&__pyx_n_s__RaiserException, __pyx_k__RaiserException, sizeof(__pyx_k__RaiserException), 0, 0, 1, 1}, - {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1}, - {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1}, - {&__pyx_n_s__raiseException, __pyx_k__raiseException, sizeof(__pyx_k__raiseException), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} -}; -static int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - return 0; - __pyx_L1_error:; - return -1; -} - -static int __Pyx_InitCachedConstants(void) { - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants"); - - /* "twisted/test/raiser.pyx":21 - * Raise L{RaiserException}. - * """ - * raise RaiserException("This function is intentionally broken") # <<<<<<<<<<<<<< - */ - __pyx_k_tuple_2 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_k_tuple_2)); - __Pyx_INCREF(((PyObject *)__pyx_kp_s_1)); - PyTuple_SET_ITEM(__pyx_k_tuple_2, 0, ((PyObject *)__pyx_kp_s_1)); - __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_1)); - __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_2)); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; - __Pyx_RefNannyFinishContext(); - return -1; -} - -static int __Pyx_InitGlobals(void) { - if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - return 0; - __pyx_L1_error:; - return -1; -} - -#if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC initraiser(void); /*proto*/ -PyMODINIT_FUNC initraiser(void) -#else -PyMODINIT_FUNC PyInit_raiser(void); /*proto*/ -PyMODINIT_FUNC PyInit_raiser(void) -#endif -{ - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - #if CYTHON_REFNANNY - void* __pyx_refnanny = NULL; - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); - if (!__Pyx_RefNanny) { - PyErr_Clear(); - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); - if (!__Pyx_RefNanny) - Py_FatalError("failed to import 'refnanny' module"); - } - __pyx_refnanny = __Pyx_RefNanny->SetupContext("PyMODINIT_FUNC PyInit_raiser(void)", __LINE__, __FILE__); - #endif - __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #ifdef __pyx_binding_PyCFunctionType_USED - if (__pyx_binding_PyCFunctionType_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ - #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - #ifdef WITH_THREAD /* Python build with threading support? */ - PyEval_InitThreads(); - #endif - #endif - /*--- Module creation code ---*/ - #if PY_MAJOR_VERSION < 3 - __pyx_m = Py_InitModule4(__Pyx_NAMESTR("raiser"), __pyx_methods, __Pyx_DOCSTR(__pyx_k_3), 0, PYTHON_API_VERSION); - #else - __pyx_m = PyModule_Create(&__pyx_moduledef); - #endif - if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - #if PY_MAJOR_VERSION < 3 - Py_INCREF(__pyx_m); - #endif - __pyx_b = PyImport_AddModule(__Pyx_NAMESTR(__Pyx_BUILTIN_MODULE_NAME)); - if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - if (__Pyx_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - /*--- Initialize various global constants etc. ---*/ - if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__pyx_module_is_main_twisted__test__raiser) { - if (__Pyx_SetAttrString(__pyx_m, "__name__", __pyx_n_s____main__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - } - /*--- Builtin init code ---*/ - if (unlikely(__Pyx_InitCachedBuiltins() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /*--- Constants init code ---*/ - if (unlikely(__Pyx_InitCachedConstants() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /*--- Global init code ---*/ - /*--- Function export code ---*/ - /*--- Type init code ---*/ - /*--- Type import code ---*/ - /*--- Function import code ---*/ - /*--- Execution code ---*/ - - /* "twisted/test/raiser.pyx":11 - * - * - * class RaiserException(Exception): # <<<<<<<<<<<<<< - * """ - * A speficic exception only used to be identified in tests. - */ - __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_1)); - __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - __Pyx_INCREF(__pyx_builtin_Exception); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_builtin_Exception); - __Pyx_GIVEREF(__pyx_builtin_Exception); - if (PyDict_SetItemString(((PyObject *)__pyx_t_1), "__doc__", ((PyObject *)__pyx_kp_s_4)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_3 = __Pyx_CreateClass(((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1), __pyx_n_s__RaiserException, __pyx_n_s_5); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__RaiserException, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; - - /* "twisted/test/raiser.pyx":17 - * - * - * def raiseException(): # <<<<<<<<<<<<<< - * """ - * Raise L{RaiserException}. - */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_7twisted_4test_6raiser_raiseException, NULL, __pyx_n_s_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__raiseException, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "twisted/test/raiser.pyx":1 - * # Copyright (c) Twisted Matrix Laboratories. # <<<<<<<<<<<<<< - * # See LICENSE for details. - * - */ - __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_1)); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s____test__, ((PyObject *)__pyx_t_1)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - if (__pyx_m) { - __Pyx_AddTraceback("init twisted.test.raiser"); - Py_DECREF(__pyx_m); __pyx_m = 0; - } else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ImportError, "init twisted.test.raiser"); - } - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - #if PY_MAJOR_VERSION < 3 - return; - #else - return __pyx_m; - #endif -} - -/* Runtime support code */ - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { - PyObject *result; - result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); - return result; -} - -static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) { - PyObject *tmp_type, *tmp_value, *tmp_tb; - PyThreadState *tstate = PyThreadState_GET(); - - tmp_type = tstate->curexc_type; - tmp_value = tstate->curexc_value; - tmp_tb = tstate->curexc_traceback; - tstate->curexc_type = type; - tstate->curexc_value = value; - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -} - -static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) { - PyThreadState *tstate = PyThreadState_GET(); - *type = tstate->curexc_type; - *value = tstate->curexc_value; - *tb = tstate->curexc_traceback; - - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; -} - - -#if PY_MAJOR_VERSION < 3 -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - /* First, check the traceback argument, replacing None with NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = 0; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - #if PY_VERSION_HEX < 0x02050000 - if (!PyClass_Check(type)) - #else - if (!PyType_Check(type)) - #endif - { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - #if PY_VERSION_HEX < 0x02050000 - if (PyInstance_Check(type)) { - type = (PyObject*) ((PyInstanceObject*)type)->in_class; - Py_INCREF(type); - } - else { - type = 0; - PyErr_SetString(PyExc_TypeError, - "raise: exception must be an old-style class or instance"); - goto raise_error; - } - #else - type = (PyObject*) Py_TYPE(type); - Py_INCREF(type); - if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto raise_error; - } - #endif - } - - __Pyx_ErrRestore(type, value, tb); - return; -raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return; -} - -#else /* Python 3+ */ - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - if (tb == Py_None) { - tb = 0; - } else if (tb && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto bad; - } - if (value == Py_None) - value = 0; - - if (PyExceptionInstance_Check(type)) { - if (value) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto bad; - } - value = type; - type = (PyObject*) Py_TYPE(value); - } else if (!PyExceptionClass_Check(type)) { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto bad; - } - - PyErr_SetObject(type, value); - - if (tb) { - PyThreadState *tstate = PyThreadState_GET(); - PyObject* tmp_tb = tstate->curexc_traceback; - if (tb != tmp_tb) { - Py_INCREF(tb); - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_tb); - } - } - -bad: - return; -} -#endif - -static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases) { - PyObject *metaclass; - /* Default metaclass */ -#if PY_MAJOR_VERSION < 3 - if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { - PyObject *base = PyTuple_GET_ITEM(bases, 0); - metaclass = PyObject_GetAttrString(base, "__class__"); - if (!metaclass) { - PyErr_Clear(); - metaclass = (PyObject*) Py_TYPE(base); - } - } else { - metaclass = (PyObject *) &PyClass_Type; - } -#else - if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { - PyObject *base = PyTuple_GET_ITEM(bases, 0); - metaclass = (PyObject*) Py_TYPE(base); - } else { - metaclass = (PyObject *) &PyType_Type; - } -#endif - Py_INCREF(metaclass); - return metaclass; -} - -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, - PyObject *modname) { - PyObject *result; - PyObject *metaclass; - - if (PyDict_SetItemString(dict, "__module__", modname) < 0) - return NULL; - - /* Python2 __metaclass__ */ - metaclass = PyDict_GetItemString(dict, "__metaclass__"); - if (metaclass) { - Py_INCREF(metaclass); - } else { - metaclass = __Pyx_FindPy2Metaclass(bases); - } - result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL); - Py_DECREF(metaclass); - return result; -} - -static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject* x) { - const unsigned char neg_one = (unsigned char)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(unsigned char) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(unsigned char)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to unsigned char" : - "value too large to convert to unsigned char"); - } - return (unsigned char)-1; - } - return (unsigned char)val; - } - return (unsigned char)__Pyx_PyInt_AsUnsignedLong(x); -} - -static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject* x) { - const unsigned short neg_one = (unsigned short)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(unsigned short) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(unsigned short)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to unsigned short" : - "value too large to convert to unsigned short"); - } - return (unsigned short)-1; - } - return (unsigned short)val; - } - return (unsigned short)__Pyx_PyInt_AsUnsignedLong(x); -} - -static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject* x) { - const unsigned int neg_one = (unsigned int)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(unsigned int) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(unsigned int)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to unsigned int" : - "value too large to convert to unsigned int"); - } - return (unsigned int)-1; - } - return (unsigned int)val; - } - return (unsigned int)__Pyx_PyInt_AsUnsignedLong(x); -} - -static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject* x) { - const char neg_one = (char)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(char) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(char)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to char" : - "value too large to convert to char"); - } - return (char)-1; - } - return (char)val; - } - return (char)__Pyx_PyInt_AsLong(x); -} - -static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject* x) { - const short neg_one = (short)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(short) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(short)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to short" : - "value too large to convert to short"); - } - return (short)-1; - } - return (short)val; - } - return (short)__Pyx_PyInt_AsLong(x); -} - -static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject* x) { - const int neg_one = (int)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(int) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(int)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to int" : - "value too large to convert to int"); - } - return (int)-1; - } - return (int)val; - } - return (int)__Pyx_PyInt_AsLong(x); -} - -static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject* x) { - const signed char neg_one = (signed char)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(signed char) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(signed char)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to signed char" : - "value too large to convert to signed char"); - } - return (signed char)-1; - } - return (signed char)val; - } - return (signed char)__Pyx_PyInt_AsSignedLong(x); -} - -static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject* x) { - const signed short neg_one = (signed short)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(signed short) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(signed short)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to signed short" : - "value too large to convert to signed short"); - } - return (signed short)-1; - } - return (signed short)val; - } - return (signed short)__Pyx_PyInt_AsSignedLong(x); -} - -static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject* x) { - const signed int neg_one = (signed int)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(signed int) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(signed int)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to signed int" : - "value too large to convert to signed int"); - } - return (signed int)-1; - } - return (signed int)val; - } - return (signed int)__Pyx_PyInt_AsSignedLong(x); -} - -static CYTHON_INLINE int __Pyx_PyInt_AsLongDouble(PyObject* x) { - const int neg_one = (int)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(int) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(int)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to int" : - "value too large to convert to int"); - } - return (int)-1; - } - return (int)val; - } - return (int)__Pyx_PyInt_AsLong(x); -} - -static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject* x) { - const unsigned long neg_one = (unsigned long)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned long"); - return (unsigned long)-1; - } - return (unsigned long)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned long"); - return (unsigned long)-1; - } - return PyLong_AsUnsignedLong(x); - } else { - return PyLong_AsLong(x); - } - } else { - unsigned long val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (unsigned long)-1; - val = __Pyx_PyInt_AsUnsignedLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject* x) { - const unsigned PY_LONG_LONG neg_one = (unsigned PY_LONG_LONG)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned PY_LONG_LONG"); - return (unsigned PY_LONG_LONG)-1; - } - return (unsigned PY_LONG_LONG)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned PY_LONG_LONG"); - return (unsigned PY_LONG_LONG)-1; - } - return PyLong_AsUnsignedLongLong(x); - } else { - return PyLong_AsLongLong(x); - } - } else { - unsigned PY_LONG_LONG val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (unsigned PY_LONG_LONG)-1; - val = __Pyx_PyInt_AsUnsignedLongLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject* x) { - const long neg_one = (long)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long)-1; - } - return (long)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long)-1; - } - return PyLong_AsUnsignedLong(x); - } else { - return PyLong_AsLong(x); - } - } else { - long val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (long)-1; - val = __Pyx_PyInt_AsLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject* x) { - const PY_LONG_LONG neg_one = (PY_LONG_LONG)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to PY_LONG_LONG"); - return (PY_LONG_LONG)-1; - } - return (PY_LONG_LONG)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to PY_LONG_LONG"); - return (PY_LONG_LONG)-1; - } - return PyLong_AsUnsignedLongLong(x); - } else { - return PyLong_AsLongLong(x); - } - } else { - PY_LONG_LONG val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (PY_LONG_LONG)-1; - val = __Pyx_PyInt_AsLongLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject* x) { - const signed long neg_one = (signed long)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed long"); - return (signed long)-1; - } - return (signed long)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed long"); - return (signed long)-1; - } - return PyLong_AsUnsignedLong(x); - } else { - return PyLong_AsLong(x); - } - } else { - signed long val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (signed long)-1; - val = __Pyx_PyInt_AsSignedLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject* x) { - const signed PY_LONG_LONG neg_one = (signed PY_LONG_LONG)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed PY_LONG_LONG"); - return (signed PY_LONG_LONG)-1; - } - return (signed PY_LONG_LONG)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed PY_LONG_LONG"); - return (signed PY_LONG_LONG)-1; - } - return PyLong_AsUnsignedLongLong(x); - } else { - return PyLong_AsLongLong(x); - } - } else { - signed PY_LONG_LONG val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (signed PY_LONG_LONG)-1; - val = __Pyx_PyInt_AsSignedLongLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" - -static void __Pyx_AddTraceback(const char *funcname) { - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - PyObject *py_globals = 0; - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - - #if PY_MAJOR_VERSION < 3 - py_srcfile = PyString_FromString(__pyx_filename); - #else - py_srcfile = PyUnicode_FromString(__pyx_filename); - #endif - if (!py_srcfile) goto bad; - if (__pyx_clineno) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno); - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno); - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); - #else - py_funcname = PyUnicode_FromString(funcname); - #endif - } - if (!py_funcname) goto bad; - py_globals = PyModule_GetDict(__pyx_m); - if (!py_globals) goto bad; - py_code = PyCode_New( - 0, /*int argcount,*/ - #if PY_MAJOR_VERSION >= 3 - 0, /*int kwonlyargcount,*/ - #endif - 0, /*int nlocals,*/ - 0, /*int stacksize,*/ - 0, /*int flags,*/ - __pyx_empty_bytes, /*PyObject *code,*/ - __pyx_empty_tuple, /*PyObject *consts,*/ - __pyx_empty_tuple, /*PyObject *names,*/ - __pyx_empty_tuple, /*PyObject *varnames,*/ - __pyx_empty_tuple, /*PyObject *freevars,*/ - __pyx_empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - __pyx_lineno, /*int firstlineno,*/ - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - if (!py_code) goto bad; - py_frame = PyFrame_New( - PyThreadState_GET(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - py_globals, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = __pyx_lineno; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { - while (t->p) { - #if PY_MAJOR_VERSION < 3 - if (t->is_unicode) { - *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); - } else if (t->intern) { - *t->p = PyString_InternFromString(t->s); - } else { - *t->p = PyString_FromStringAndSize(t->s, t->n - 1); - } - #else /* Python 3+ has unicode identifiers */ - if (t->is_unicode | t->is_str) { - if (t->intern) { - *t->p = PyUnicode_InternFromString(t->s); - } else if (t->encoding) { - *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); - } else { - *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); - } - } else { - *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); - } - #endif - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -/* Type Conversion Functions */ - -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - int is_true = x == Py_True; - if (is_true | (x == Py_False) | (x == Py_None)) return is_true; - else return PyObject_IsTrue(x); -} - -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { - PyNumberMethods *m; - const char *name = NULL; - PyObject *res = NULL; -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(x) || PyLong_Check(x)) -#else - if (PyLong_Check(x)) -#endif - return Py_INCREF(x), x; - m = Py_TYPE(x)->tp_as_number; -#if PY_VERSION_HEX < 0x03000000 - if (m && m->nb_int) { - name = "int"; - res = PyNumber_Int(x); - } - else if (m && m->nb_long) { - name = "long"; - res = PyNumber_Long(x); - } -#else - if (m && m->nb_int) { - name = "int"; - res = PyNumber_Long(x); - } -#endif - if (res) { -#if PY_VERSION_HEX < 0x03000000 - if (!PyInt_Check(res) && !PyLong_Check(res)) { -#else - if (!PyLong_Check(res)) { -#endif - PyErr_Format(PyExc_TypeError, - "__%s__ returned non-%s (type %.200s)", - name, name, Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } - } - else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "an integer is required"); - } - return res; -} - -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject* x = PyNumber_Index(b); - if (!x) return -1; - ival = PyInt_AsSsize_t(x); - Py_DECREF(x); - return ival; -} - -static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { -#if PY_VERSION_HEX < 0x02050000 - if (ival <= LONG_MAX) - return PyInt_FromLong((long)ival); - else { - unsigned char *bytes = (unsigned char *) &ival; - int one = 1; int little = (int)*(unsigned char*)&one; - return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0); - } -#else - return PyInt_FromSize_t(ival); -#endif -} - -static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) { - unsigned PY_LONG_LONG val = __Pyx_PyInt_AsUnsignedLongLong(x); - if (unlikely(val == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())) { - return (size_t)-1; - } else if (unlikely(val != (unsigned PY_LONG_LONG)(size_t)val)) { - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to size_t"); - return (size_t)-1; - } - return (size_t)val; -} - - -#endif /* Py_PYTHON_H */ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/raiser.pyx b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/raiser.pyx deleted file mode 100644 index 820540e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/raiser.pyx +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A trivial extension that just raises an exception. -See L{twisted.test.test_failure.test_failureConstructionWithMungedStackSucceeds}. -""" - - - -class RaiserException(Exception): - """ - A speficic exception only used to be identified in tests. - """ - - -def raiseException(): - """ - Raise L{RaiserException}. - """ - raise RaiserException("This function is intentionally broken") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_IE.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_IE.py deleted file mode 100644 index aa9b789..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_IE.py +++ /dev/null @@ -1,4 +0,0 @@ - -# Helper for a test_reflect test - -__import__('idonotexist') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_VE.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_VE.py deleted file mode 100644 index e19507f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_VE.py +++ /dev/null @@ -1,4 +0,0 @@ - -# Helper for a test_reflect test - -raise ValueError("Stuff is broken and things") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_ZDE.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_ZDE.py deleted file mode 100644 index 0c53583..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/reflect_helper_ZDE.py +++ /dev/null @@ -1,4 +0,0 @@ - -# Helper module for a test_reflect test - -1//0 diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/server.pem b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/server.pem deleted file mode 100644 index 56af8a3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/server.pem +++ /dev/null @@ -1,94 +0,0 @@ -# coding: utf-8 - -from inspect import getsource -from datetime import datetime - -from OpenSSL.crypto import FILETYPE_PEM, TYPE_RSA, X509, PKey, dump_privatekey, dump_certificate - -key = PKey() -key.generate_key(TYPE_RSA, 2048) - -cert = X509() -issuer = cert.get_issuer() -subject = cert.get_subject() - -for dn in [issuer, subject]: - dn.C = b"TR" - dn.ST = b"Çorum" - dn.L = b"Başmakçı" - dn.CN = b"localhost" - dn.O = b"Twisted Matrix Labs" - dn.OU = b"Automated Testing Authority" - dn.emailAddress = b"security@twistedmatrix.com" - -cert.set_serial_number(datetime.now().toordinal()) -cert.gmtime_adj_notBefore(0) -cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 100) - -cert.set_pubkey(key) -cert.sign(key, b"sha1") - -import __main__ -source = getsource(__main__) -source = source.split(b"\n" + b"-" * 5)[0].rsplit(b"\n", 1)[0] -with open(b"server.pem", "wb") as fObj: - fObj.write(source) - fObj.write(b"\n") - fObj.write(b"'''\n") - fObj.write(dump_privatekey(FILETYPE_PEM, key)) - fObj.write(dump_certificate(FILETYPE_PEM, cert)) - fObj.write(b"'''\n") -''' ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGnXh/GMCLpNNI -AIvfBWlPrRCLFWxd2ICLYSUq3/jwh31CppGKlfaSmUYnrMxnT4hg2f6gBqlmq1gK -jQqDkqQQtHsSljRQF58NRFtz99w45jRmrGs+F5zoggJuyv7/lKXy/BXOc40NodIl -qRuo/uhoPjeXaUNziwpRj4rByRdLwQ6MfRcfdZ0TpVJ4J7apJ66pZt85L63u8TZi -AZdBgcowX6giola7kUUMG66bSi2X6sIFxdXHwzrWlFNnSbKqOqKlGrjmBHUYqRFr -gLALKkaMpF30olHn7QLqJ2592hMFVkOQAzNr8Xb15mF27BuWFYd7P6TirsxCEd+9 -BFFbhl0vAgMBAAECggEAf1ndN3GBlIi9SL/A7+GiYwpPPz8fWxVFZxmFIXa3QlM+ -CAyR6dC6Z8mL6EiuT9f5VFCzKZzb5g8bxrgk87SFKojvGT3ikTB0NaeNFFDrjjhd -hTAtG4U8gQFL2gqjcvG3bpQgz13cJc+K1ccXC0dXce/i6Vz/eQjANwfZKuRr4Y/p -Ml3ZtkarT7cZ2TZRDYd643U2nfrNmeLA9wwwO5mgNYu7HSpI4idpVM+rzoS9ZbU1 -Jxhrdq7GELvnd+Ko3WHTSrkQyb53GtJaLFOSAMxQlZAbRGJMv2VtXSPe+NyA0kxO -V4O9CJ2QL1Bxqk4MQicKGtGoIsFbfR/qYQZgNEuHoQKBgQDlqEYSGpEcyKNvCjZ+ -Dv5hFUT7GZ24MNRvMBdMHPJEkmxvNpwaNkOGXL6zmhDk5Y0HOrzNv64Llmg623y0 -pn9Vh3CvMKDlq5t8910BJhXzZAM9/E9ui/YuQsFwCdWJQFYVMZUIAdylxbDkg6Mf -WzHkx82edwWgb7hOFJhEW3h51wKBgQDdZaofTKeSLUmxIbF1yqm4iX67wyhHFFZL -RZLEcu35ZTJqz3TRpr9KpHCtq9J2gZbqo2Dvqznwfk+yUqT2gkibtk3qvmv/qHQt -FGX5joWLD2E22UgGc4bzonTSQcxPfPYjNZa6Iv7koPgJqO1k3aYLG3mDMgI/Yurz -3j8udCI8aQKBgQCe8uNkfky3PkqXfNsQTnJTYTQ4EpettuYg+oj1Xgdz3F/+bS6H -mc0Mfr5ichyFQDdmrImmYaclT/ld2zGpmp8A5FfieOazbx2T1WTieaixpyPzT+Du -IyLFC+D0GWpYr1WlH4cFXryHY5c14cIR3r1emcc/iSM00n4eVHS6wxBUSwKBgQCQ -fTAI20slgD7uxjF90XTwhXNbcONReDlVSKOfZ+5dbCj6QkhYJv4C5czP2yowwyRO -H7A82j+m75htpbgZVS+zx8eUIxByumqPnRdsRhJrje8BD88MvsrdKDIbomuHmOM+ -WVP0SLCXX2JhU4kS4gDikNy9vZ5v5cu2ul37oDlTuQKBgBl4Qs6Q0xUotlvy/fMf -L3c6GUIeRsLyQCKFfKYiUNLHqqutBSYmsAlx3XOhcK4DZ7/gFAXO6mpYJlwXOdrI -IMcSXuJvZDPAYMXOyZUTgNjPcbQ8t0by+EKPwnTReIBf1Y17vPDfisf5IEKZEWvM -YDXg6cfx9R5QePjvZohlItOu ------END PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIID8DCCAtgCAws5AzANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCVFIxDjAM -BgNVBAgUBcdvcnVtMRkwFwYDVQQHHhAAQgBhAV8AbQBhAGsA5wExMRIwEAYDVQQD -Ewlsb2NhbGhvc3QxHDAaBgNVBAoTE1R3aXN0ZWQgTWF0cml4IExhYnMxJDAiBgNV -BAsTG0F1dG9tYXRlZCBUZXN0aW5nIEF1dGhvcml0eTEpMCcGCSqGSIb3DQEJARYa -c2VjdXJpdHlAdHdpc3RlZG1hdHJpeC5jb20wIBcNMTQwOTE2MDE0MjQ2WhgPMjEx -NDA4MjMwMTQyNDZaMIG7MQswCQYDVQQGEwJUUjEOMAwGA1UECBQFx29ydW0xGTAX -BgNVBAceEABCAGEBXwBtAGEAawDnATExEjAQBgNVBAMTCWxvY2FsaG9zdDEcMBoG -A1UEChMTVHdpc3RlZCBNYXRyaXggTGFiczEkMCIGA1UECxMbQXV0b21hdGVkIFRl -c3RpbmcgQXV0aG9yaXR5MSkwJwYJKoZIhvcNAQkBFhpzZWN1cml0eUB0d2lzdGVk -bWF0cml4LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMadeH8Y -wIuk00gAi98FaU+tEIsVbF3YgIthJSrf+PCHfUKmkYqV9pKZRieszGdPiGDZ/qAG -qWarWAqNCoOSpBC0exKWNFAXnw1EW3P33DjmNGasaz4XnOiCAm7K/v+UpfL8Fc5z -jQ2h0iWpG6j+6Gg+N5dpQ3OLClGPisHJF0vBDox9Fx91nROlUngntqknrqlm3zkv -re7xNmIBl0GByjBfqCKiVruRRQwbrptKLZfqwgXF1cfDOtaUU2dJsqo6oqUauOYE -dRipEWuAsAsqRoykXfSiUeftAuonbn3aEwVWQ5ADM2vxdvXmYXbsG5YVh3s/pOKu -zEIR370EUVuGXS8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAK+HqbIUN6qHYYQZw -7qqsTJWni8NOfK3aguyKAPcdCPP2DCZ6zlxxkUWL57gvsohyDu8Nr9iSI6wePjmI -cN9eCZdc6mD9kYW4qBYhh2T48TOhEEW7zO6bWQUqWohHW+bG+GfrHnvxIx56OC2B -eDS2djvvScYm45etlHprfrVEDIssh956O6qJCySax3D2w+i8YanXji1EbS61XTDw -CMxDdWYmd2MDARRwlMcfcUIfKZUGl5NmqpnOx+H5MyAGwt86s647GMYZborQh+Mj -tNHVpyKf/a8/HjqP1sCOrjCPZIjP6Qp5j4gifAjUStNmCgaBe7CpFtBSLnHqb4o/ -gU7u1w== ------END CERTIFICATE----- -''' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/ssl_helpers.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/ssl_helpers.py deleted file mode 100644 index 04a55d7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/ssl_helpers.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Helper classes for twisted.test.test_ssl. - -They are in a separate module so they will not prevent test_ssl importing if -pyOpenSSL is unavailable. -""" -from __future__ import division, absolute_import - -from twisted.python.compat import nativeString -from twisted.internet import ssl -from twisted.python.filepath import FilePath - -from OpenSSL import SSL - -certPath = nativeString(FilePath(__file__.encode("utf-8") - ).sibling(b"server.pem").path) - - -class ClientTLSContext(ssl.ClientContextFactory): - isClient = 1 - def getContext(self): - return SSL.Context(SSL.TLSv1_METHOD) - -class ServerTLSContext: - isClient = 0 - - def __init__(self, filename=certPath): - self.filename = filename - - def getContext(self): - ctx = SSL.Context(SSL.TLSv1_METHOD) - ctx.use_certificate_file(self.filename) - ctx.use_privatekey_file(self.filename) - return ctx diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_consumer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_consumer.py deleted file mode 100644 index 6d7d4cb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_consumer.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_consumer -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_consumer} to test -that process transports implement IConsumer properly. -""" - -__import__('_preamble') -import sys - -from twisted.python import log, reflect -from twisted.internet import stdio, protocol -from twisted.protocols import basic - -def failed(err): - log.startLogging(sys.stderr) - log.err(err) - -class ConsumerChild(protocol.Protocol): - def __init__(self, junkPath): - self.junkPath = junkPath - - def connectionMade(self): - d = basic.FileSender().beginFileTransfer(file(self.junkPath), self.transport) - d.addErrback(failed) - d.addCallback(lambda ign: self.transport.loseConnection()) - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(ConsumerChild(sys.argv[2])) - reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_halfclose.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_halfclose.py deleted file mode 100644 index 13f89d7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_halfclose.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_readConnectionLost -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_readConnectionLost} -to test that IHalfCloseableProtocol.readConnectionLost works for process -transports. -""" - -__import__('_preamble') -import sys - -from zope.interface import implements - -from twisted.internet.interfaces import IHalfCloseableProtocol -from twisted.internet import stdio, protocol -from twisted.python import reflect, log - - -class HalfCloseProtocol(protocol.Protocol): - """ - A protocol to hook up to stdio and observe its transport being - half-closed. If all goes as expected, C{exitCode} will be set to C{0}; - otherwise it will be set to C{1} to indicate failure. - """ - implements(IHalfCloseableProtocol) - - exitCode = None - - def connectionMade(self): - """ - Signal the parent process that we're ready. - """ - self.transport.write("x") - - - def readConnectionLost(self): - """ - This is the desired event. Once it has happened, stop the reactor so - the process will exit. - """ - self.exitCode = 0 - reactor.stop() - - - def connectionLost(self, reason): - """ - This may only be invoked after C{readConnectionLost}. If it happens - otherwise, mark it as an error and shut down. - """ - if self.exitCode is None: - self.exitCode = 1 - log.err(reason, "Unexpected call to connectionLost") - reactor.stop() - - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - log.startLogging(file(sys.argv[2], 'w')) - from twisted.internet import reactor - protocol = HalfCloseProtocol() - stdio.StandardIO(protocol) - reactor.run() - sys.exit(protocol.exitCode) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_hostpeer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_hostpeer.py deleted file mode 100644 index 707e05b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_hostpeer.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_hostAndPeer -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_hostAndPeer} to test -that ITransport.getHost() and ITransport.getPeer() work for process transports. -""" - -__import__('_preamble') -import sys - -from twisted.internet import stdio, protocol -from twisted.python import reflect - -class HostPeerChild(protocol.Protocol): - def connectionMade(self): - self.transport.write('\n'.join([ - str(self.transport.getHost()), - str(self.transport.getPeer())])) - self.transport.loseConnection() - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(HostPeerChild()) - reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_lastwrite.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_lastwrite.py deleted file mode 100644 index 1449cac..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_lastwrite.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_lastWriteReceived -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_lastWriteReceived} -to test that L{os.write} can be reliably used after -L{twisted.internet.stdio.StandardIO} has finished. -""" - -__import__('_preamble') -import sys - -from twisted.internet.protocol import Protocol -from twisted.internet.stdio import StandardIO -from twisted.python.reflect import namedAny - - -class LastWriteChild(Protocol): - def __init__(self, reactor, magicString): - self.reactor = reactor - self.magicString = magicString - - - def connectionMade(self): - self.transport.write(self.magicString) - self.transport.loseConnection() - - - def connectionLost(self, reason): - self.reactor.stop() - - - -def main(reactor, magicString): - p = LastWriteChild(reactor, magicString) - StandardIO(p) - reactor.run() - - - -if __name__ == '__main__': - namedAny(sys.argv[1]).install() - from twisted.internet import reactor - main(reactor, sys.argv[2]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_loseconn.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_loseconn.py deleted file mode 100644 index c9fa2d0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_loseconn.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_loseConnection -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_loseConnection} to -test that ITransport.loseConnection() works for process transports. -""" - -__import__('_preamble') -import sys - -from twisted.internet.error import ConnectionDone -from twisted.internet import stdio, protocol -from twisted.python import reflect, log - -class LoseConnChild(protocol.Protocol): - exitCode = 0 - - def connectionMade(self): - self.transport.loseConnection() - - - def connectionLost(self, reason): - """ - Check that C{reason} is a L{Failure} wrapping a L{ConnectionDone} - instance and stop the reactor. If C{reason} is wrong for some reason, - log something about that in C{self.errorLogFile} and make sure the - process exits with a non-zero status. - """ - try: - try: - reason.trap(ConnectionDone) - except: - log.err(None, "Problem with reason passed to connectionLost") - self.exitCode = 1 - finally: - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - log.startLogging(file(sys.argv[2], 'w')) - from twisted.internet import reactor - protocol = LoseConnChild() - stdio.StandardIO(protocol) - reactor.run() - sys.exit(protocol.exitCode) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_producer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_producer.py deleted file mode 100644 index 6160772..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_producer.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_producer -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_producer} to test -that process transports implement IProducer properly. -""" - -__import__('_preamble') -import sys - -from twisted.internet import stdio, protocol -from twisted.python import log, reflect - -class ProducerChild(protocol.Protocol): - _paused = False - buf = '' - - def connectionLost(self, reason): - log.msg("*****OVER*****") - reactor.callLater(1, reactor.stop) - # reactor.stop() - - - def dataReceived(self, bytes): - self.buf += bytes - if self._paused: - log.startLogging(sys.stderr) - log.msg("dataReceived while transport paused!") - self.transport.loseConnection() - else: - self.transport.write(bytes) - if self.buf.endswith('\n0\n'): - self.transport.loseConnection() - else: - self.pause() - - - def pause(self): - self._paused = True - self.transport.pauseProducing() - reactor.callLater(0.01, self.unpause) - - - def unpause(self): - self._paused = False - self.transport.resumeProducing() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(ProducerChild()) - reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_write.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_write.py deleted file mode 100644 index b502452..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_write.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_write -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_write} to test that -ITransport.write() works for process transports. -""" - -__import__('_preamble') -import sys - -from twisted.internet import stdio, protocol -from twisted.python import reflect - -class WriteChild(protocol.Protocol): - def connectionMade(self): - for ch in 'ok!': - self.transport.write(ch) - self.transport.loseConnection() - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(WriteChild()) - reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_writeseq.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_writeseq.py deleted file mode 100644 index 6a92e9b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/stdio_test_writeseq.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTests.test_writeSequence -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTests.test_writeSequence} to test that -ITransport.writeSequence() works for process transports. -""" - -__import__('_preamble') -import sys - -from twisted.internet import stdio, protocol -from twisted.python import reflect - -class WriteSequenceChild(protocol.Protocol): - def connectionMade(self): - self.transport.writeSequence(list('ok!')) - self.transport.loseConnection() - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(WriteSequenceChild()) - reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_abstract.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_abstract.py deleted file mode 100644 index eb1d05a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_abstract.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for generic file descriptor based reactor support code. -""" - -from __future__ import division, absolute_import - -from twisted.trial.unittest import TestCase - -from twisted.internet.abstract import isIPAddress - - -class AddressTests(TestCase): - """ - Tests for address-related functionality. - """ - def test_decimalDotted(self): - """ - L{isIPAddress} should return C{True} for any decimal dotted - representation of an IPv4 address. - """ - self.assertTrue(isIPAddress('0.1.2.3')) - self.assertTrue(isIPAddress('252.253.254.255')) - - - def test_shortDecimalDotted(self): - """ - L{isIPAddress} should return C{False} for a dotted decimal - representation with fewer or more than four octets. - """ - self.assertFalse(isIPAddress('0')) - self.assertFalse(isIPAddress('0.1')) - self.assertFalse(isIPAddress('0.1.2')) - self.assertFalse(isIPAddress('0.1.2.3.4')) - - - def test_invalidLetters(self): - """ - L{isIPAddress} should return C{False} for any non-decimal dotted - representation including letters. - """ - self.assertFalse(isIPAddress('a.2.3.4')) - self.assertFalse(isIPAddress('1.b.3.4')) - - - def test_invalidPunctuation(self): - """ - L{isIPAddress} should return C{False} for a string containing - strange punctuation. - """ - self.assertFalse(isIPAddress(',')) - self.assertFalse(isIPAddress('1,2')) - self.assertFalse(isIPAddress('1,2,3')) - self.assertFalse(isIPAddress('1.,.3,4')) - - - def test_emptyString(self): - """ - L{isIPAddress} should return C{False} for the empty string. - """ - self.assertFalse(isIPAddress('')) - - - def test_invalidNegative(self): - """ - L{isIPAddress} should return C{False} for negative decimal values. - """ - self.assertFalse(isIPAddress('-1')) - self.assertFalse(isIPAddress('1.-2')) - self.assertFalse(isIPAddress('1.2.-3')) - self.assertFalse(isIPAddress('1.2.-3.4')) - - - def test_invalidPositive(self): - """ - L{isIPAddress} should return C{False} for a string containing - positive decimal values greater than 255. - """ - self.assertFalse(isIPAddress('256.0.0.0')) - self.assertFalse(isIPAddress('0.256.0.0')) - self.assertFalse(isIPAddress('0.0.256.0')) - self.assertFalse(isIPAddress('0.0.0.256')) - self.assertFalse(isIPAddress('256.256.256.256')) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_adbapi.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_adbapi.py deleted file mode 100644 index 843fa8e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_adbapi.py +++ /dev/null @@ -1,821 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for twisted.enterprise.adbapi. -""" - -from twisted.trial import unittest - -import os, stat -import types - -from twisted.enterprise.adbapi import ConnectionPool, ConnectionLost -from twisted.enterprise.adbapi import Connection, Transaction -from twisted.internet import reactor, defer, interfaces -from twisted.python.failure import Failure -from twisted.python.reflect import requireModule - -simple_table_schema = """ -CREATE TABLE simple ( - x integer -) -""" - - - -class ADBAPITestBase: - """Test the asynchronous DB-API code.""" - - openfun_called = {} - - if interfaces.IReactorThreads(reactor, None) is None: - skip = "ADB-API requires threads, no way to test without them" - - def extraSetUp(self): - """ - Set up the database and create a connection pool pointing at it. - """ - self.startDB() - self.dbpool = self.makePool(cp_openfun=self.openfun) - self.dbpool.start() - - - def tearDown(self): - d = self.dbpool.runOperation('DROP TABLE simple') - d.addCallback(lambda res: self.dbpool.close()) - d.addCallback(lambda res: self.stopDB()) - return d - - def openfun(self, conn): - self.openfun_called[conn] = True - - def checkOpenfunCalled(self, conn=None): - if not conn: - self.failUnless(self.openfun_called) - else: - self.failUnless(self.openfun_called.has_key(conn)) - - def testPool(self): - d = self.dbpool.runOperation(simple_table_schema) - if self.test_failures: - d.addCallback(self._testPool_1_1) - d.addCallback(self._testPool_1_2) - d.addCallback(self._testPool_1_3) - d.addCallback(self._testPool_1_4) - d.addCallback(lambda res: self.flushLoggedErrors()) - d.addCallback(self._testPool_2) - d.addCallback(self._testPool_3) - d.addCallback(self._testPool_4) - d.addCallback(self._testPool_5) - d.addCallback(self._testPool_6) - d.addCallback(self._testPool_7) - d.addCallback(self._testPool_8) - d.addCallback(self._testPool_9) - return d - - def _testPool_1_1(self, res): - d = defer.maybeDeferred(self.dbpool.runQuery, "select * from NOTABLE") - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_1_2(self, res): - d = defer.maybeDeferred(self.dbpool.runOperation, - "deletexxx from NOTABLE") - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_1_3(self, res): - d = defer.maybeDeferred(self.dbpool.runInteraction, - self.bad_interaction) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_1_4(self, res): - d = defer.maybeDeferred(self.dbpool.runWithConnection, - self.bad_withConnection) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_2(self, res): - # verify simple table is empty - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, "Interaction not rolled back") - self.checkOpenfunCalled() - d.addCallback(_check) - return d - - def _testPool_3(self, res): - sql = "select count(1) from simple" - inserts = [] - # add some rows to simple table (runOperation) - for i in range(self.num_iterations): - sql = "insert into simple(x) values(%d)" % i - inserts.append(self.dbpool.runOperation(sql)) - d = defer.gatherResults(inserts) - - def _select(res): - # make sure they were added (runQuery) - sql = "select x from simple order by x"; - d = self.dbpool.runQuery(sql) - return d - d.addCallback(_select) - - def _check(rows): - self.failUnless(len(rows) == self.num_iterations, - "Wrong number of rows") - for i in range(self.num_iterations): - self.failUnless(len(rows[i]) == 1, "Wrong size row") - self.failUnless(rows[i][0] == i, "Values not returned.") - d.addCallback(_check) - - return d - - def _testPool_4(self, res): - # runInteraction - d = self.dbpool.runInteraction(self.interaction) - d.addCallback(lambda res: self.assertEqual(res, "done")) - return d - - def _testPool_5(self, res): - # withConnection - d = self.dbpool.runWithConnection(self.withConnection) - d.addCallback(lambda res: self.assertEqual(res, "done")) - return d - - def _testPool_6(self, res): - # Test a withConnection cannot be closed - d = self.dbpool.runWithConnection(self.close_withConnection) - return d - - def _testPool_7(self, res): - # give the pool a workout - ds = [] - for i in range(self.num_iterations): - sql = "select x from simple where x = %d" % i - ds.append(self.dbpool.runQuery(sql)) - dlist = defer.DeferredList(ds, fireOnOneErrback=True) - def _check(result): - for i in range(self.num_iterations): - self.failUnless(result[i][1][0][0] == i, "Value not returned") - dlist.addCallback(_check) - return dlist - - def _testPool_8(self, res): - # now delete everything - ds = [] - for i in range(self.num_iterations): - sql = "delete from simple where x = %d" % i - ds.append(self.dbpool.runOperation(sql)) - dlist = defer.DeferredList(ds, fireOnOneErrback=True) - return dlist - - def _testPool_9(self, res): - # verify simple table is empty - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, - "Didn't successfully delete table contents") - self.checkConnect() - d.addCallback(_check) - return d - - def checkConnect(self): - """Check the connect/disconnect synchronous calls.""" - conn = self.dbpool.connect() - self.checkOpenfunCalled(conn) - curs = conn.cursor() - curs.execute("insert into simple(x) values(1)") - curs.execute("select x from simple") - res = curs.fetchall() - self.assertEqual(len(res), 1) - self.assertEqual(len(res[0]), 1) - self.assertEqual(res[0][0], 1) - curs.execute("delete from simple") - curs.execute("select x from simple") - self.assertEqual(len(curs.fetchall()), 0) - curs.close() - self.dbpool.disconnect(conn) - - def interaction(self, transaction): - transaction.execute("select x from simple order by x") - for i in range(self.num_iterations): - row = transaction.fetchone() - self.failUnless(len(row) == 1, "Wrong size row") - self.failUnless(row[0] == i, "Value not returned.") - # should test this, but gadfly throws an exception instead - #self.failUnless(transaction.fetchone() is None, "Too many rows") - return "done" - - def bad_interaction(self, transaction): - if self.can_rollback: - transaction.execute("insert into simple(x) values(0)") - - transaction.execute("select * from NOTABLE") - - def withConnection(self, conn): - curs = conn.cursor() - try: - curs.execute("select x from simple order by x") - for i in range(self.num_iterations): - row = curs.fetchone() - self.failUnless(len(row) == 1, "Wrong size row") - self.failUnless(row[0] == i, "Value not returned.") - # should test this, but gadfly throws an exception instead - #self.failUnless(transaction.fetchone() is None, "Too many rows") - finally: - curs.close() - return "done" - - def close_withConnection(self, conn): - conn.close() - - def bad_withConnection(self, conn): - curs = conn.cursor() - try: - curs.execute("select * from NOTABLE") - finally: - curs.close() - - -class ReconnectTestBase: - """Test the asynchronous DB-API code with reconnect.""" - - if interfaces.IReactorThreads(reactor, None) is None: - skip = "ADB-API requires threads, no way to test without them" - - def extraSetUp(self): - """ - Skip the test if C{good_sql} is unavailable. Otherwise, set up the - database, create a connection pool pointed at it, and set up a simple - schema in it. - """ - if self.good_sql is None: - raise unittest.SkipTest('no good sql for reconnect test') - self.startDB() - self.dbpool = self.makePool(cp_max=1, cp_reconnect=True, - cp_good_sql=self.good_sql) - self.dbpool.start() - return self.dbpool.runOperation(simple_table_schema) - - - def tearDown(self): - d = self.dbpool.runOperation('DROP TABLE simple') - d.addCallback(lambda res: self.dbpool.close()) - d.addCallback(lambda res: self.stopDB()) - return d - - def testPool(self): - d = defer.succeed(None) - d.addCallback(self._testPool_1) - d.addCallback(self._testPool_2) - if not self.early_reconnect: - d.addCallback(self._testPool_3) - d.addCallback(self._testPool_4) - d.addCallback(self._testPool_5) - return d - - def _testPool_1(self, res): - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, "Table not empty") - d.addCallback(_check) - return d - - def _testPool_2(self, res): - # reach in and close the connection manually - self.dbpool.connections.values()[0].close() - - def _testPool_3(self, res): - sql = "select count(1) from simple" - d = defer.maybeDeferred(self.dbpool.runQuery, sql) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_4(self, res): - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, "Table not empty") - d.addCallback(_check) - return d - - def _testPool_5(self, res): - self.flushLoggedErrors() - sql = "select * from NOTABLE" # bad sql - d = defer.maybeDeferred(self.dbpool.runQuery, sql) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: self.failIf(f.check(ConnectionLost))) - return d - - -class DBTestConnector: - """A class which knows how to test for the presence of - and establish a connection to a relational database. - - To enable test cases which use a central, system database, - you must create a database named DB_NAME with a user DB_USER - and password DB_PASS with full access rights to database DB_NAME. - """ - - TEST_PREFIX = None # used for creating new test cases - - DB_NAME = "twisted_test" - DB_USER = 'twisted_test' - DB_PASS = 'twisted_test' - - DB_DIR = None # directory for database storage - - nulls_ok = True # nulls supported - trailing_spaces_ok = True # trailing spaces in strings preserved - can_rollback = True # rollback supported - test_failures = True # test bad sql? - escape_slashes = True # escape \ in sql? - good_sql = ConnectionPool.good_sql - early_reconnect = True # cursor() will fail on closed connection - can_clear = True # can try to clear out tables when starting - - num_iterations = 50 # number of iterations for test loops - # (lower this for slow db's) - - def setUp(self): - self.DB_DIR = self.mktemp() - os.mkdir(self.DB_DIR) - if not self.can_connect(): - raise unittest.SkipTest('%s: Cannot access db' % self.TEST_PREFIX) - return self.extraSetUp() - - def can_connect(self): - """Return true if this database is present on the system - and can be used in a test.""" - raise NotImplementedError() - - def startDB(self): - """Take any steps needed to bring database up.""" - pass - - def stopDB(self): - """Bring database down, if needed.""" - pass - - def makePool(self, **newkw): - """Create a connection pool with additional keyword arguments.""" - args, kw = self.getPoolArgs() - kw = kw.copy() - kw.update(newkw) - return ConnectionPool(*args, **kw) - - def getPoolArgs(self): - """Return a tuple (args, kw) of list and keyword arguments - that need to be passed to ConnectionPool to create a connection - to this database.""" - raise NotImplementedError() - -class GadflyConnector(DBTestConnector): - TEST_PREFIX = 'Gadfly' - - nulls_ok = False - can_rollback = False - escape_slashes = False - good_sql = 'select * from simple where 1=0' - - num_iterations = 1 # slow - - def can_connect(self): - try: import gadfly - except: return False - if not getattr(gadfly, 'connect', None): - gadfly.connect = gadfly.gadfly - return True - - def startDB(self): - import gadfly - conn = gadfly.gadfly() - conn.startup(self.DB_NAME, self.DB_DIR) - - # gadfly seems to want us to create something to get the db going - cursor = conn.cursor() - cursor.execute("create table x (x integer)") - conn.commit() - conn.close() - - def getPoolArgs(self): - args = ('gadfly', self.DB_NAME, self.DB_DIR) - kw = {'cp_max': 1} - return args, kw - -class SQLiteConnector(DBTestConnector): - TEST_PREFIX = 'SQLite' - - escape_slashes = False - - num_iterations = 1 # slow - - def can_connect(self): - if requireModule('sqlite') is None: - return False - else: - return True - - def startDB(self): - self.database = os.path.join(self.DB_DIR, self.DB_NAME) - if os.path.exists(self.database): - os.unlink(self.database) - - def getPoolArgs(self): - args = ('sqlite',) - kw = {'database': self.database, 'cp_max': 1} - return args, kw - -class PyPgSQLConnector(DBTestConnector): - TEST_PREFIX = "PyPgSQL" - - def can_connect(self): - try: from pyPgSQL import PgSQL - except: return False - try: - conn = PgSQL.connect(database=self.DB_NAME, user=self.DB_USER, - password=self.DB_PASS) - conn.close() - return True - except: - return False - - def getPoolArgs(self): - args = ('pyPgSQL.PgSQL',) - kw = {'database': self.DB_NAME, 'user': self.DB_USER, - 'password': self.DB_PASS, 'cp_min': 0} - return args, kw - -class PsycopgConnector(DBTestConnector): - TEST_PREFIX = 'Psycopg' - - def can_connect(self): - try: import psycopg - except: return False - try: - conn = psycopg.connect(database=self.DB_NAME, user=self.DB_USER, - password=self.DB_PASS) - conn.close() - return True - except: - return False - - def getPoolArgs(self): - args = ('psycopg',) - kw = {'database': self.DB_NAME, 'user': self.DB_USER, - 'password': self.DB_PASS, 'cp_min': 0} - return args, kw - -class MySQLConnector(DBTestConnector): - TEST_PREFIX = 'MySQL' - - trailing_spaces_ok = False - can_rollback = False - early_reconnect = False - - def can_connect(self): - try: import MySQLdb - except: return False - try: - conn = MySQLdb.connect(db=self.DB_NAME, user=self.DB_USER, - passwd=self.DB_PASS) - conn.close() - return True - except: - return False - - def getPoolArgs(self): - args = ('MySQLdb',) - kw = {'db': self.DB_NAME, 'user': self.DB_USER, 'passwd': self.DB_PASS} - return args, kw - -class FirebirdConnector(DBTestConnector): - TEST_PREFIX = 'Firebird' - - test_failures = False # failure testing causes problems - escape_slashes = False - good_sql = None # firebird doesn't handle failed sql well - can_clear = False # firebird is not so good - - num_iterations = 5 # slow - - - def can_connect(self): - if requireModule('kinterbasdb') is None: - return False - try: - self.startDB() - self.stopDB() - return True - except: - return False - - - def startDB(self): - import kinterbasdb - self.DB_NAME = os.path.join(self.DB_DIR, DBTestConnector.DB_NAME) - os.chmod(self.DB_DIR, stat.S_IRWXU + stat.S_IRWXG + stat.S_IRWXO) - sql = 'create database "%s" user "%s" password "%s"' - sql %= (self.DB_NAME, self.DB_USER, self.DB_PASS); - conn = kinterbasdb.create_database(sql) - conn.close() - - - def getPoolArgs(self): - args = ('kinterbasdb',) - kw = {'database': self.DB_NAME, 'host': '127.0.0.1', - 'user': self.DB_USER, 'password': self.DB_PASS} - return args, kw - - def stopDB(self): - import kinterbasdb - conn = kinterbasdb.connect(database=self.DB_NAME, - host='127.0.0.1', user=self.DB_USER, - password=self.DB_PASS) - conn.drop_database() - -def makeSQLTests(base, suffix, globals): - """ - Make a test case for every db connector which can connect. - - @param base: Base class for test case. Additional base classes - will be a DBConnector subclass and unittest.TestCase - @param suffix: A suffix used to create test case names. Prefixes - are defined in the DBConnector subclasses. - """ - connectors = [GadflyConnector, SQLiteConnector, PyPgSQLConnector, - PsycopgConnector, MySQLConnector, FirebirdConnector] - for connclass in connectors: - name = connclass.TEST_PREFIX + suffix - klass = types.ClassType(name, (connclass, base, unittest.TestCase), - base.__dict__) - globals[name] = klass - -# GadflyADBAPITests SQLiteADBAPITests PyPgSQLADBAPITests -# PsycopgADBAPITests MySQLADBAPITests FirebirdADBAPITests -makeSQLTests(ADBAPITestBase, 'ADBAPITests', globals()) - -# GadflyReconnectTests SQLiteReconnectTests PyPgSQLReconnectTests -# PsycopgReconnectTests MySQLReconnectTests FirebirdReconnectTests -makeSQLTests(ReconnectTestBase, 'ReconnectTests', globals()) - - - -class FakePool(object): - """ - A fake L{ConnectionPool} for tests. - - @ivar connectionFactory: factory for making connections returned by the - C{connect} method. - @type connectionFactory: any callable - """ - reconnect = True - noisy = True - - def __init__(self, connectionFactory): - self.connectionFactory = connectionFactory - - - def connect(self): - """ - Return an instance of C{self.connectionFactory}. - """ - return self.connectionFactory() - - - def disconnect(self, connection): - """ - Do nothing. - """ - - - -class ConnectionTests(unittest.TestCase): - """ - Tests for the L{Connection} class. - """ - - def test_rollbackErrorLogged(self): - """ - If an error happens during rollback, L{ConnectionLost} is raised but - the original error is logged. - """ - class ConnectionRollbackRaise(object): - def rollback(self): - raise RuntimeError("problem!") - - pool = FakePool(ConnectionRollbackRaise) - connection = Connection(pool) - self.assertRaises(ConnectionLost, connection.rollback) - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0].value.args[0], "problem!") - - - -class TransactionTests(unittest.TestCase): - """ - Tests for the L{Transaction} class. - """ - - def test_reopenLogErrorIfReconnect(self): - """ - If the cursor creation raises an error in L{Transaction.reopen}, it - reconnects but log the error occurred. - """ - class ConnectionCursorRaise(object): - count = 0 - - def reconnect(self): - pass - - def cursor(self): - if self.count == 0: - self.count += 1 - raise RuntimeError("problem!") - - pool = FakePool(None) - transaction = Transaction(pool, ConnectionCursorRaise()) - transaction.reopen() - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0].value.args[0], "problem!") - - - -class NonThreadPool(object): - def callInThreadWithCallback(self, onResult, f, *a, **kw): - success = True - try: - result = f(*a, **kw) - except Exception: - success = False - result = Failure() - onResult(success, result) - - - -class DummyConnectionPool(ConnectionPool): - """ - A testable L{ConnectionPool}; - """ - threadpool = NonThreadPool() - - def __init__(self): - """ - Don't forward init call. - """ - self.reactor = reactor - - - -class EventReactor(object): - """ - Partial L{IReactorCore} implementation with simple event-related - methods. - - @ivar _running: A C{bool} indicating whether the reactor is pretending - to have been started already or not. - - @ivar triggers: A C{list} of pending system event triggers. - """ - def __init__(self, running): - self._running = running - self.triggers = [] - - - def callWhenRunning(self, function): - if self._running: - function() - else: - return self.addSystemEventTrigger('after', 'startup', function) - - - def addSystemEventTrigger(self, phase, event, trigger): - handle = (phase, event, trigger) - self.triggers.append(handle) - return handle - - - def removeSystemEventTrigger(self, handle): - self.triggers.remove(handle) - - - -class ConnectionPoolTests(unittest.TestCase): - """ - Unit tests for L{ConnectionPool}. - """ - - def test_runWithConnectionRaiseOriginalError(self): - """ - If rollback fails, L{ConnectionPool.runWithConnection} raises the - original exception and log the error of the rollback. - """ - class ConnectionRollbackRaise(object): - def __init__(self, pool): - pass - - def rollback(self): - raise RuntimeError("problem!") - - def raisingFunction(connection): - raise ValueError("foo") - - pool = DummyConnectionPool() - pool.connectionFactory = ConnectionRollbackRaise - d = pool.runWithConnection(raisingFunction) - d = self.assertFailure(d, ValueError) - def cbFailed(ignored): - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0].value.args[0], "problem!") - d.addCallback(cbFailed) - return d - - - def test_closeLogError(self): - """ - L{ConnectionPool._close} logs exceptions. - """ - class ConnectionCloseRaise(object): - def close(self): - raise RuntimeError("problem!") - - pool = DummyConnectionPool() - pool._close(ConnectionCloseRaise()) - - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0].value.args[0], "problem!") - - - def test_runWithInteractionRaiseOriginalError(self): - """ - If rollback fails, L{ConnectionPool.runInteraction} raises the - original exception and log the error of the rollback. - """ - class ConnectionRollbackRaise(object): - def __init__(self, pool): - pass - - def rollback(self): - raise RuntimeError("problem!") - - class DummyTransaction(object): - def __init__(self, pool, connection): - pass - - def raisingFunction(transaction): - raise ValueError("foo") - - pool = DummyConnectionPool() - pool.connectionFactory = ConnectionRollbackRaise - pool.transactionFactory = DummyTransaction - - d = pool.runInteraction(raisingFunction) - d = self.assertFailure(d, ValueError) - def cbFailed(ignored): - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0].value.args[0], "problem!") - d.addCallback(cbFailed) - return d - - - def test_unstartedClose(self): - """ - If L{ConnectionPool.close} is called without L{ConnectionPool.start} - having been called, the pool's startup event is cancelled. - """ - reactor = EventReactor(False) - pool = ConnectionPool('twisted.test.test_adbapi', cp_reactor=reactor) - # There should be a startup trigger waiting. - self.assertEqual(reactor.triggers, [('after', 'startup', pool._start)]) - pool.close() - # But not anymore. - self.assertFalse(reactor.triggers) - - - def test_startedClose(self): - """ - If L{ConnectionPool.close} is called after it has been started, but - not by its shutdown trigger, the shutdown trigger is cancelled. - """ - reactor = EventReactor(True) - pool = ConnectionPool('twisted.test.test_adbapi', cp_reactor=reactor) - # There should be a shutdown trigger waiting. - self.assertEqual(reactor.triggers, [('during', 'shutdown', pool.finalClose)]) - pool.close() - # But not anymore. - self.assertFalse(reactor.triggers) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_amp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_amp.py deleted file mode 100644 index 05a2093..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_amp.py +++ /dev/null @@ -1,3170 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.protocols.amp}. -""" - -import datetime -import decimal - -from zope.interface import implements -from zope.interface.verify import verifyClass, verifyObject - -from twisted.python import filepath -from twisted.python.failure import Failure -from twisted.protocols import amp -from twisted.trial import unittest -from twisted.internet import ( - address, protocol, defer, error, reactor, interfaces) -from twisted.test import iosim -from twisted.test.proto_helpers import StringTransport - -ssl = None -try: - from twisted.internet import ssl -except ImportError: - pass - -if ssl and not ssl.supported: - ssl = None - -if ssl is None: - skipSSL = "SSL not available" -else: - skipSSL = None - - - -tz = amp._FixedOffsetTZInfo.fromSignHoursMinutes - - - -class TestProto(protocol.Protocol): - """ - A trivial protocol for use in testing where a L{Protocol} is expected. - - @ivar instanceId: the id of this instance - @ivar onConnLost: deferred that will fired when the connection is lost - @ivar dataToSend: data to send on the protocol - """ - - instanceCount = 0 - - def __init__(self, onConnLost, dataToSend): - self.onConnLost = onConnLost - self.dataToSend = dataToSend - self.instanceId = TestProto.instanceCount - TestProto.instanceCount = TestProto.instanceCount + 1 - - - def connectionMade(self): - self.data = [] - self.transport.write(self.dataToSend) - - - def dataReceived(self, bytes): - self.data.append(bytes) - - - def connectionLost(self, reason): - self.onConnLost.callback(self.data) - - - def __repr__(self): - """ - Custom repr for testing to avoid coupling amp tests with repr from - L{Protocol} - - Returns a string which contains a unique identifier that can be looked - up using the instanceId property:: - - - """ - return "" % (self.instanceId,) - - - -class SimpleSymmetricProtocol(amp.AMP): - - def sendHello(self, text): - return self.callRemoteString( - "hello", - hello=text) - - def amp_HELLO(self, box): - return amp.Box(hello=box['hello']) - - def amp_HOWDOYOUDO(self, box): - return amp.QuitBox(howdoyoudo='world') - - - -class UnfriendlyGreeting(Exception): - """Greeting was insufficiently kind. - """ - -class DeathThreat(Exception): - """Greeting was insufficiently kind. - """ - -class UnknownProtocol(Exception): - """Asked to switch to the wrong protocol. - """ - - -class TransportPeer(amp.Argument): - # this serves as some informal documentation for how to get variables from - # the protocol or your environment and pass them to methods as arguments. - def retrieve(self, d, name, proto): - return '' - - def fromStringProto(self, notAString, proto): - return proto.transport.getPeer() - - def toBox(self, name, strings, objects, proto): - return - - - -class Hello(amp.Command): - - commandName = 'hello' - - arguments = [('hello', amp.String()), - ('optional', amp.Boolean(optional=True)), - ('print', amp.Unicode(optional=True)), - ('from', TransportPeer(optional=True)), - ('mixedCase', amp.String(optional=True)), - ('dash-arg', amp.String(optional=True)), - ('underscore_arg', amp.String(optional=True))] - - response = [('hello', amp.String()), - ('print', amp.Unicode(optional=True))] - - errors = {UnfriendlyGreeting: 'UNFRIENDLY'} - - fatalErrors = {DeathThreat: 'DEAD'} - -class NoAnswerHello(Hello): - commandName = Hello.commandName - requiresAnswer = False - -class FutureHello(amp.Command): - commandName = 'hello' - - arguments = [('hello', amp.String()), - ('optional', amp.Boolean(optional=True)), - ('print', amp.Unicode(optional=True)), - ('from', TransportPeer(optional=True)), - ('bonus', amp.String(optional=True)), # addt'l arguments - # should generally be - # added at the end, and - # be optional... - ] - - response = [('hello', amp.String()), - ('print', amp.Unicode(optional=True))] - - errors = {UnfriendlyGreeting: 'UNFRIENDLY'} - -class WTF(amp.Command): - """ - An example of an invalid command. - """ - - -class BrokenReturn(amp.Command): - """ An example of a perfectly good command, but the handler is going to return - None... - """ - - commandName = 'broken_return' - -class Goodbye(amp.Command): - # commandName left blank on purpose: this tests implicit command names. - response = [('goodbye', amp.String())] - responseType = amp.QuitBox - -class Howdoyoudo(amp.Command): - commandName = 'howdoyoudo' - # responseType = amp.QuitBox - -class WaitForever(amp.Command): - commandName = 'wait_forever' - -class GetList(amp.Command): - commandName = 'getlist' - arguments = [('length', amp.Integer())] - response = [('body', amp.AmpList([('x', amp.Integer())]))] - -class DontRejectMe(amp.Command): - commandName = 'dontrejectme' - arguments = [ - ('magicWord', amp.Unicode()), - ('list', amp.AmpList([('name', amp.Unicode())], optional=True)), - ] - response = [('response', amp.Unicode())] - -class SecuredPing(amp.Command): - # XXX TODO: actually make this refuse to send over an insecure connection - response = [('pinged', amp.Boolean())] - -class TestSwitchProto(amp.ProtocolSwitchCommand): - commandName = 'Switch-Proto' - - arguments = [ - ('name', amp.String()), - ] - errors = {UnknownProtocol: 'UNKNOWN'} - -class SingleUseFactory(protocol.ClientFactory): - def __init__(self, proto): - self.proto = proto - self.proto.factory = self - - def buildProtocol(self, addr): - p, self.proto = self.proto, None - return p - - reasonFailed = None - - def clientConnectionFailed(self, connector, reason): - self.reasonFailed = reason - return - -THING_I_DONT_UNDERSTAND = 'gwebol nargo' -class ThingIDontUnderstandError(Exception): - pass - -class FactoryNotifier(amp.AMP): - factory = None - def connectionMade(self): - if self.factory is not None: - self.factory.theProto = self - if hasattr(self.factory, 'onMade'): - self.factory.onMade.callback(None) - - def emitpong(self): - from twisted.internet.interfaces import ISSLTransport - if not ISSLTransport.providedBy(self.transport): - raise DeathThreat("only send secure pings over secure channels") - return {'pinged': True} - SecuredPing.responder(emitpong) - - -class SimpleSymmetricCommandProtocol(FactoryNotifier): - maybeLater = None - def __init__(self, onConnLost=None): - amp.AMP.__init__(self) - self.onConnLost = onConnLost - - def sendHello(self, text): - return self.callRemote(Hello, hello=text) - - def sendUnicodeHello(self, text, translation): - return self.callRemote(Hello, hello=text, Print=translation) - - greeted = False - - def cmdHello(self, hello, From, optional=None, Print=None, - mixedCase=None, dash_arg=None, underscore_arg=None): - assert From == self.transport.getPeer() - if hello == THING_I_DONT_UNDERSTAND: - raise ThingIDontUnderstandError() - if hello.startswith('fuck'): - raise UnfriendlyGreeting("Don't be a dick.") - if hello == 'die': - raise DeathThreat("aieeeeeeeee") - result = dict(hello=hello) - if Print is not None: - result.update(dict(Print=Print)) - self.greeted = True - return result - Hello.responder(cmdHello) - - def cmdGetlist(self, length): - return {'body': [dict(x=1)] * length} - GetList.responder(cmdGetlist) - - def okiwont(self, magicWord, list=None): - if list is None: - response = u'list omitted' - else: - response = u'%s accepted' % (list[0]['name']) - return dict(response=response) - DontRejectMe.responder(okiwont) - - def waitforit(self): - self.waiting = defer.Deferred() - return self.waiting - WaitForever.responder(waitforit) - - def howdo(self): - return dict(howdoyoudo='world') - Howdoyoudo.responder(howdo) - - def saybye(self): - return dict(goodbye="everyone") - Goodbye.responder(saybye) - - def switchToTestProtocol(self, fail=False): - if fail: - name = 'no-proto' - else: - name = 'test-proto' - p = TestProto(self.onConnLost, SWITCH_CLIENT_DATA) - return self.callRemote( - TestSwitchProto, - SingleUseFactory(p), name=name).addCallback(lambda ign: p) - - def switchit(self, name): - if name == 'test-proto': - return TestProto(self.onConnLost, SWITCH_SERVER_DATA) - raise UnknownProtocol(name) - TestSwitchProto.responder(switchit) - - def donothing(self): - return None - BrokenReturn.responder(donothing) - - -class DeferredSymmetricCommandProtocol(SimpleSymmetricCommandProtocol): - def switchit(self, name): - if name == 'test-proto': - self.maybeLaterProto = TestProto(self.onConnLost, SWITCH_SERVER_DATA) - self.maybeLater = defer.Deferred() - return self.maybeLater - raise UnknownProtocol(name) - TestSwitchProto.responder(switchit) - -class BadNoAnswerCommandProtocol(SimpleSymmetricCommandProtocol): - def badResponder(self, hello, From, optional=None, Print=None, - mixedCase=None, dash_arg=None, underscore_arg=None): - """ - This responder does nothing and forgets to return a dictionary. - """ - NoAnswerHello.responder(badResponder) - -class NoAnswerCommandProtocol(SimpleSymmetricCommandProtocol): - def goodNoAnswerResponder(self, hello, From, optional=None, Print=None, - mixedCase=None, dash_arg=None, underscore_arg=None): - return dict(hello=hello+"-noanswer") - NoAnswerHello.responder(goodNoAnswerResponder) - -def connectedServerAndClient(ServerClass=SimpleSymmetricProtocol, - ClientClass=SimpleSymmetricProtocol, - *a, **kw): - """Returns a 3-tuple: (client, server, pump) - """ - return iosim.connectedServerAndClient( - ServerClass, ClientClass, - *a, **kw) - -class TotallyDumbProtocol(protocol.Protocol): - buf = '' - def dataReceived(self, data): - self.buf += data - -class LiteralAmp(amp.AMP): - def __init__(self): - self.boxes = [] - - def ampBoxReceived(self, box): - self.boxes.append(box) - return - - - -class AmpBoxTests(unittest.TestCase): - """ - Test a few essential properties of AMP boxes, mostly with respect to - serialization correctness. - """ - - def test_serializeStr(self): - """ - Make sure that strs serialize to strs. - """ - a = amp.AmpBox(key='value') - self.assertEqual(type(a.serialize()), str) - - def test_serializeUnicodeKeyRaises(self): - """ - Verify that TypeError is raised when trying to serialize Unicode keys. - """ - a = amp.AmpBox(**{u'key': 'value'}) - self.assertRaises(TypeError, a.serialize) - - def test_serializeUnicodeValueRaises(self): - """ - Verify that TypeError is raised when trying to serialize Unicode - values. - """ - a = amp.AmpBox(key=u'value') - self.assertRaises(TypeError, a.serialize) - - - -class ParsingTests(unittest.TestCase): - - def test_booleanValues(self): - """ - Verify that the Boolean parser parses 'True' and 'False', but nothing - else. - """ - b = amp.Boolean() - self.assertEqual(b.fromString("True"), True) - self.assertEqual(b.fromString("False"), False) - self.assertRaises(TypeError, b.fromString, "ninja") - self.assertRaises(TypeError, b.fromString, "true") - self.assertRaises(TypeError, b.fromString, "TRUE") - self.assertEqual(b.toString(True), 'True') - self.assertEqual(b.toString(False), 'False') - - def test_pathValueRoundTrip(self): - """ - Verify the 'Path' argument can parse and emit a file path. - """ - fp = filepath.FilePath(self.mktemp()) - p = amp.Path() - s = p.toString(fp) - v = p.fromString(s) - self.assertNotIdentical(fp, v) # sanity check - self.assertEqual(fp, v) - - - def test_sillyEmptyThing(self): - """ - Test that empty boxes raise an error; they aren't supposed to be sent - on purpose. - """ - a = amp.AMP() - return self.assertRaises(amp.NoEmptyBoxes, a.ampBoxReceived, amp.Box()) - - - def test_ParsingRoundTrip(self): - """ - Verify that various kinds of data make it through the encode/parse - round-trip unharmed. - """ - c, s, p = connectedServerAndClient(ClientClass=LiteralAmp, - ServerClass=LiteralAmp) - - SIMPLE = ('simple', 'test') - CE = ('ceq', ': ') - CR = ('crtest', 'test\r') - LF = ('lftest', 'hello\n') - NEWLINE = ('newline', 'test\r\none\r\ntwo') - NEWLINE2 = ('newline2', 'test\r\none\r\n two') - BODYTEST = ('body', 'blah\r\n\r\ntesttest') - - testData = [ - [SIMPLE], - [SIMPLE, BODYTEST], - [SIMPLE, CE], - [SIMPLE, CR], - [SIMPLE, CE, CR, LF], - [CE, CR, LF], - [SIMPLE, NEWLINE, CE, NEWLINE2], - [BODYTEST, SIMPLE, NEWLINE] - ] - - for test in testData: - jb = amp.Box() - jb.update(dict(test)) - jb._sendTo(c) - p.flush() - self.assertEqual(s.boxes[-1], jb) - - - -class FakeLocator(object): - """ - This is a fake implementation of the interface implied by - L{CommandLocator}. - """ - def __init__(self): - """ - Remember the given keyword arguments as a set of responders. - """ - self.commands = {} - - - def locateResponder(self, commandName): - """ - Look up and return a function passed as a keyword argument of the given - name to the constructor. - """ - return self.commands[commandName] - - -class FakeSender: - """ - This is a fake implementation of the 'box sender' interface implied by - L{AMP}. - """ - def __init__(self): - """ - Create a fake sender and initialize the list of received boxes and - unhandled errors. - """ - self.sentBoxes = [] - self.unhandledErrors = [] - self.expectedErrors = 0 - - - def expectError(self): - """ - Expect one error, so that the test doesn't fail. - """ - self.expectedErrors += 1 - - - def sendBox(self, box): - """ - Accept a box, but don't do anything. - """ - self.sentBoxes.append(box) - - - def unhandledError(self, failure): - """ - Deal with failures by instantly re-raising them for easier debugging. - """ - self.expectedErrors -= 1 - if self.expectedErrors < 0: - failure.raiseException() - else: - self.unhandledErrors.append(failure) - - - -class CommandDispatchTests(unittest.TestCase): - """ - The AMP CommandDispatcher class dispatches converts AMP boxes into commands - and responses using Command.responder decorator. - - Note: Originally, AMP's factoring was such that many tests for this - functionality are now implemented as full round-trip tests in L{AMPTests}. - Future tests should be written at this level instead, to ensure API - compatibility and to provide more granular, readable units of test - coverage. - """ - - def setUp(self): - """ - Create a dispatcher to use. - """ - self.locator = FakeLocator() - self.sender = FakeSender() - self.dispatcher = amp.BoxDispatcher(self.locator) - self.dispatcher.startReceivingBoxes(self.sender) - - - def test_receivedAsk(self): - """ - L{CommandDispatcher.ampBoxReceived} should locate the appropriate - command in its responder lookup, based on the '_ask' key. - """ - received = [] - def thunk(box): - received.append(box) - return amp.Box({"hello": "goodbye"}) - input = amp.Box(_command="hello", - _ask="test-command-id", - hello="world") - self.locator.commands['hello'] = thunk - self.dispatcher.ampBoxReceived(input) - self.assertEqual(received, [input]) - - - def test_sendUnhandledError(self): - """ - L{CommandDispatcher} should relay its unhandled errors in responding to - boxes to its boxSender. - """ - err = RuntimeError("something went wrong, oh no") - self.sender.expectError() - self.dispatcher.unhandledError(Failure(err)) - self.assertEqual(len(self.sender.unhandledErrors), 1) - self.assertEqual(self.sender.unhandledErrors[0].value, err) - - - def test_unhandledSerializationError(self): - """ - Errors during serialization ought to be relayed to the sender's - unhandledError method. - """ - err = RuntimeError("something undefined went wrong") - def thunk(result): - class BrokenBox(amp.Box): - def _sendTo(self, proto): - raise err - return BrokenBox() - self.locator.commands['hello'] = thunk - input = amp.Box(_command="hello", - _ask="test-command-id", - hello="world") - self.sender.expectError() - self.dispatcher.ampBoxReceived(input) - self.assertEqual(len(self.sender.unhandledErrors), 1) - self.assertEqual(self.sender.unhandledErrors[0].value, err) - - - def test_callRemote(self): - """ - L{CommandDispatcher.callRemote} should emit a properly formatted '_ask' - box to its boxSender and record an outstanding L{Deferred}. When a - corresponding '_answer' packet is received, the L{Deferred} should be - fired, and the results translated via the given L{Command}'s response - de-serialization. - """ - D = self.dispatcher.callRemote(Hello, hello='world') - self.assertEqual(self.sender.sentBoxes, - [amp.AmpBox(_command="hello", - _ask="1", - hello="world")]) - answers = [] - D.addCallback(answers.append) - self.assertEqual(answers, []) - self.dispatcher.ampBoxReceived(amp.AmpBox({'hello': "yay", - 'print': "ignored", - '_answer': "1"})) - self.assertEqual(answers, [dict(hello="yay", - Print=u"ignored")]) - - - def _localCallbackErrorLoggingTest(self, callResult): - """ - Verify that C{callResult} completes with a C{None} result and that an - unhandled error has been logged. - """ - finalResult = [] - callResult.addBoth(finalResult.append) - - self.assertEqual(1, len(self.sender.unhandledErrors)) - self.assertIsInstance( - self.sender.unhandledErrors[0].value, ZeroDivisionError) - - self.assertEqual([None], finalResult) - - - def test_callRemoteSuccessLocalCallbackErrorLogging(self): - """ - If the last callback on the L{Deferred} returned by C{callRemote} (added - by application code calling C{callRemote}) fails, the failure is passed - to the sender's C{unhandledError} method. - """ - self.sender.expectError() - - callResult = self.dispatcher.callRemote(Hello, hello='world') - callResult.addCallback(lambda result: 1 // 0) - - self.dispatcher.ampBoxReceived(amp.AmpBox({ - 'hello': "yay", 'print': "ignored", '_answer': "1"})) - - self._localCallbackErrorLoggingTest(callResult) - - - def test_callRemoteErrorLocalCallbackErrorLogging(self): - """ - Like L{test_callRemoteSuccessLocalCallbackErrorLogging}, but for the - case where the L{Deferred} returned by C{callRemote} fails. - """ - self.sender.expectError() - - callResult = self.dispatcher.callRemote(Hello, hello='world') - callResult.addErrback(lambda result: 1 // 0) - - self.dispatcher.ampBoxReceived(amp.AmpBox({ - '_error': '1', '_error_code': 'bugs', - '_error_description': 'stuff'})) - - self._localCallbackErrorLoggingTest(callResult) - - - -class SimpleGreeting(amp.Command): - """ - A very simple greeting command that uses a few basic argument types. - """ - commandName = 'simple' - arguments = [('greeting', amp.Unicode()), - ('cookie', amp.Integer())] - response = [('cookieplus', amp.Integer())] - - - -class TestLocator(amp.CommandLocator): - """ - A locator which implements a responder to the 'simple' command. - """ - def __init__(self): - self.greetings = [] - - - def greetingResponder(self, greeting, cookie): - self.greetings.append((greeting, cookie)) - return dict(cookieplus=cookie + 3) - greetingResponder = SimpleGreeting.responder(greetingResponder) - - - -class OverridingLocator(TestLocator): - """ - A locator which overrides the responder to the 'simple' command. - """ - - def greetingResponder(self, greeting, cookie): - """ - Return a different cookieplus than L{TestLocator.greetingResponder}. - """ - self.greetings.append((greeting, cookie)) - return dict(cookieplus=cookie + 4) - greetingResponder = SimpleGreeting.responder(greetingResponder) - - - -class InheritingLocator(OverridingLocator): - """ - This locator should inherit the responder from L{OverridingLocator}. - """ - - - -class OverrideLocatorAMP(amp.AMP): - def __init__(self): - amp.AMP.__init__(self) - self.customResponder = object() - self.expectations = {"custom": self.customResponder} - self.greetings = [] - - - def lookupFunction(self, name): - """ - Override the deprecated lookupFunction function. - """ - if name in self.expectations: - result = self.expectations[name] - return result - else: - return super(OverrideLocatorAMP, self).lookupFunction(name) - - - def greetingResponder(self, greeting, cookie): - self.greetings.append((greeting, cookie)) - return dict(cookieplus=cookie + 3) - greetingResponder = SimpleGreeting.responder(greetingResponder) - - - - -class CommandLocatorTests(unittest.TestCase): - """ - The CommandLocator should enable users to specify responders to commands as - functions that take structured objects, annotated with metadata. - """ - - def _checkSimpleGreeting(self, locatorClass, expected): - """ - Check that a locator of type C{locatorClass} finds a responder - for command named I{simple} and that the found responder answers - with the C{expected} result to a C{SimpleGreeting<"ni hao", 5>} - command. - """ - locator = locatorClass() - responderCallable = locator.locateResponder("simple") - result = responderCallable(amp.Box(greeting="ni hao", cookie="5")) - def done(values): - self.assertEqual(values, amp.AmpBox(cookieplus=str(expected))) - return result.addCallback(done) - - - def test_responderDecorator(self): - """ - A method on a L{CommandLocator} subclass decorated with a L{Command} - subclass's L{responder} decorator should be returned from - locateResponder, wrapped in logic to serialize and deserialize its - arguments. - """ - return self._checkSimpleGreeting(TestLocator, 8) - - - def test_responderOverriding(self): - """ - L{CommandLocator} subclasses can override a responder inherited from - a base class by using the L{Command.responder} decorator to register - a new responder method. - """ - return self._checkSimpleGreeting(OverridingLocator, 9) - - - def test_responderInheritance(self): - """ - Responder lookup follows the same rules as normal method lookup - rules, particularly with respect to inheritance. - """ - return self._checkSimpleGreeting(InheritingLocator, 9) - - - def test_lookupFunctionDeprecatedOverride(self): - """ - Subclasses which override locateResponder under its old name, - lookupFunction, should have the override invoked instead. (This tests - an AMP subclass, because in the version of the code that could invoke - this deprecated code path, there was no L{CommandLocator}.) - """ - locator = OverrideLocatorAMP() - customResponderObject = self.assertWarns( - PendingDeprecationWarning, - "Override locateResponder, not lookupFunction.", - __file__, lambda : locator.locateResponder("custom")) - self.assertEqual(locator.customResponder, customResponderObject) - # Make sure upcalling works too - normalResponderObject = self.assertWarns( - PendingDeprecationWarning, - "Override locateResponder, not lookupFunction.", - __file__, lambda : locator.locateResponder("simple")) - result = normalResponderObject(amp.Box(greeting="ni hao", cookie="5")) - def done(values): - self.assertEqual(values, amp.AmpBox(cookieplus='8')) - return result.addCallback(done) - - - def test_lookupFunctionDeprecatedInvoke(self): - """ - Invoking locateResponder under its old name, lookupFunction, should - emit a deprecation warning, but do the same thing. - """ - locator = TestLocator() - responderCallable = self.assertWarns( - PendingDeprecationWarning, - "Call locateResponder, not lookupFunction.", __file__, - lambda : locator.lookupFunction("simple")) - result = responderCallable(amp.Box(greeting="ni hao", cookie="5")) - def done(values): - self.assertEqual(values, amp.AmpBox(cookieplus='8')) - return result.addCallback(done) - - - -SWITCH_CLIENT_DATA = 'Success!' -SWITCH_SERVER_DATA = 'No, really. Success.' - - -class BinaryProtocolTests(unittest.TestCase): - """ - Tests for L{amp.BinaryBoxProtocol}. - - @ivar _boxSender: After C{startReceivingBoxes} is called, the L{IBoxSender} - which was passed to it. - """ - - def setUp(self): - """ - Keep track of all boxes received by this test in its capacity as an - L{IBoxReceiver} implementor. - """ - self.boxes = [] - self.data = [] - - - def startReceivingBoxes(self, sender): - """ - Implement L{IBoxReceiver.startReceivingBoxes} to just remember the - value passed in. - """ - self._boxSender = sender - - - def ampBoxReceived(self, box): - """ - A box was received by the protocol. - """ - self.boxes.append(box) - - stopReason = None - def stopReceivingBoxes(self, reason): - """ - Record the reason that we stopped receiving boxes. - """ - self.stopReason = reason - - - # fake ITransport - def getPeer(self): - return 'no peer' - - - def getHost(self): - return 'no host' - - - def write(self, data): - self.data.append(data) - - - def test_startReceivingBoxes(self): - """ - When L{amp.BinaryBoxProtocol} is connected to a transport, it calls - C{startReceivingBoxes} on its L{IBoxReceiver} with itself as the - L{IBoxSender} parameter. - """ - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(None) - self.assertIdentical(self._boxSender, protocol) - - - def test_sendBoxInStartReceivingBoxes(self): - """ - The L{IBoxReceiver} which is started when L{amp.BinaryBoxProtocol} is - connected to a transport can call C{sendBox} on the L{IBoxSender} - passed to it before C{startReceivingBoxes} returns and have that box - sent. - """ - class SynchronouslySendingReceiver: - def startReceivingBoxes(self, sender): - sender.sendBox(amp.Box({'foo': 'bar'})) - - transport = StringTransport() - protocol = amp.BinaryBoxProtocol(SynchronouslySendingReceiver()) - protocol.makeConnection(transport) - self.assertEqual( - transport.value(), - '\x00\x03foo\x00\x03bar\x00\x00') - - - def test_receiveBoxStateMachine(self): - """ - When a binary box protocol receives: - * a key - * a value - * an empty string - it should emit a box and send it to its boxReceiver. - """ - a = amp.BinaryBoxProtocol(self) - a.stringReceived("hello") - a.stringReceived("world") - a.stringReceived("") - self.assertEqual(self.boxes, [amp.AmpBox(hello="world")]) - - - def test_firstBoxFirstKeyExcessiveLength(self): - """ - L{amp.BinaryBoxProtocol} drops its connection if the length prefix for - the first a key it receives is larger than 255. - """ - transport = StringTransport() - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(transport) - protocol.dataReceived('\x01\x00') - self.assertTrue(transport.disconnecting) - - - def test_firstBoxSubsequentKeyExcessiveLength(self): - """ - L{amp.BinaryBoxProtocol} drops its connection if the length prefix for - a subsequent key in the first box it receives is larger than 255. - """ - transport = StringTransport() - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(transport) - protocol.dataReceived('\x00\x01k\x00\x01v') - self.assertFalse(transport.disconnecting) - protocol.dataReceived('\x01\x00') - self.assertTrue(transport.disconnecting) - - - def test_subsequentBoxFirstKeyExcessiveLength(self): - """ - L{amp.BinaryBoxProtocol} drops its connection if the length prefix for - the first key in a subsequent box it receives is larger than 255. - """ - transport = StringTransport() - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(transport) - protocol.dataReceived('\x00\x01k\x00\x01v\x00\x00') - self.assertFalse(transport.disconnecting) - protocol.dataReceived('\x01\x00') - self.assertTrue(transport.disconnecting) - - - def test_excessiveKeyFailure(self): - """ - If L{amp.BinaryBoxProtocol} disconnects because it received a key - length prefix which was too large, the L{IBoxReceiver}'s - C{stopReceivingBoxes} method is called with a L{TooLong} failure. - """ - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(StringTransport()) - protocol.dataReceived('\x01\x00') - protocol.connectionLost( - Failure(error.ConnectionDone("simulated connection done"))) - self.stopReason.trap(amp.TooLong) - self.assertTrue(self.stopReason.value.isKey) - self.assertFalse(self.stopReason.value.isLocal) - self.assertIdentical(self.stopReason.value.value, None) - self.assertIdentical(self.stopReason.value.keyName, None) - - - def test_unhandledErrorWithTransport(self): - """ - L{amp.BinaryBoxProtocol.unhandledError} logs the failure passed to it - and disconnects its transport. - """ - transport = StringTransport() - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(transport) - protocol.unhandledError(Failure(RuntimeError("Fake error"))) - self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError))) - self.assertTrue(transport.disconnecting) - - - def test_unhandledErrorWithoutTransport(self): - """ - L{amp.BinaryBoxProtocol.unhandledError} completes without error when - there is no associated transport. - """ - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(StringTransport()) - protocol.connectionLost(Failure(Exception("Simulated"))) - protocol.unhandledError(Failure(RuntimeError("Fake error"))) - self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError))) - - - def test_receiveBoxData(self): - """ - When a binary box protocol receives the serialized form of an AMP box, - it should emit a similar box to its boxReceiver. - """ - a = amp.BinaryBoxProtocol(self) - a.dataReceived(amp.Box({"testKey": "valueTest", - "anotherKey": "anotherValue"}).serialize()) - self.assertEqual(self.boxes, - [amp.Box({"testKey": "valueTest", - "anotherKey": "anotherValue"})]) - - - def test_receiveLongerBoxData(self): - """ - An L{amp.BinaryBoxProtocol} can receive serialized AMP boxes with - values of up to (2 ** 16 - 1) bytes. - """ - length = (2 ** 16 - 1) - value = 'x' * length - transport = StringTransport() - protocol = amp.BinaryBoxProtocol(self) - protocol.makeConnection(transport) - protocol.dataReceived(amp.Box({'k': value}).serialize()) - self.assertEqual(self.boxes, [amp.Box({'k': value})]) - self.assertFalse(transport.disconnecting) - - - def test_sendBox(self): - """ - When a binary box protocol sends a box, it should emit the serialized - bytes of that box to its transport. - """ - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - aBox = amp.Box({"testKey": "valueTest", - "someData": "hello"}) - a.makeConnection(self) - a.sendBox(aBox) - self.assertEqual(''.join(self.data), aBox.serialize()) - - - def test_connectionLostStopSendingBoxes(self): - """ - When a binary box protocol loses its connection, it should notify its - box receiver that it has stopped receiving boxes. - """ - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - connectionFailure = Failure(RuntimeError()) - a.connectionLost(connectionFailure) - self.assertIdentical(self.stopReason, connectionFailure) - - - def test_protocolSwitch(self): - """ - L{BinaryBoxProtocol} has the capacity to switch to a different protocol - on a box boundary. When a protocol is in the process of switching, it - cannot receive traffic. - """ - otherProto = TestProto(None, "outgoing data") - test = self - class SwitchyReceiver: - switched = False - def startReceivingBoxes(self, sender): - pass - def ampBoxReceived(self, box): - test.assertFalse(self.switched, - "Should only receive one box!") - self.switched = True - a._lockForSwitch() - a._switchTo(otherProto) - a = amp.BinaryBoxProtocol(SwitchyReceiver()) - anyOldBox = amp.Box({"include": "lots", - "of": "data"}) - a.makeConnection(self) - # Include a 0-length box at the beginning of the next protocol's data, - # to make sure that AMP doesn't eat the data or try to deliver extra - # boxes either... - moreThanOneBox = anyOldBox.serialize() + "\x00\x00Hello, world!" - a.dataReceived(moreThanOneBox) - self.assertIdentical(otherProto.transport, self) - self.assertEqual("".join(otherProto.data), "\x00\x00Hello, world!") - self.assertEqual(self.data, ["outgoing data"]) - a.dataReceived("more data") - self.assertEqual("".join(otherProto.data), - "\x00\x00Hello, world!more data") - self.assertRaises(amp.ProtocolSwitched, a.sendBox, anyOldBox) - - - def test_protocolSwitchEmptyBuffer(self): - """ - After switching to a different protocol, if no extra bytes beyond - the switch box were delivered, an empty string is not passed to the - switched protocol's C{dataReceived} method. - """ - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - otherProto = TestProto(None, "") - a._switchTo(otherProto) - self.assertEqual(otherProto.data, []) - - - def test_protocolSwitchInvalidStates(self): - """ - In order to make sure the protocol never gets any invalid data sent - into the middle of a box, it must be locked for switching before it is - switched. It can only be unlocked if the switch failed, and attempting - to send a box while it is locked should raise an exception. - """ - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - sampleBox = amp.Box({"some": "data"}) - a._lockForSwitch() - self.assertRaises(amp.ProtocolSwitched, a.sendBox, sampleBox) - a._unlockFromSwitch() - a.sendBox(sampleBox) - self.assertEqual(''.join(self.data), sampleBox.serialize()) - a._lockForSwitch() - otherProto = TestProto(None, "outgoing data") - a._switchTo(otherProto) - self.assertRaises(amp.ProtocolSwitched, a._unlockFromSwitch) - - - def test_protocolSwitchLoseConnection(self): - """ - When the protocol is switched, it should notify its nested protocol of - disconnection. - """ - class Loser(protocol.Protocol): - reason = None - def connectionLost(self, reason): - self.reason = reason - connectionLoser = Loser() - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - a._lockForSwitch() - a._switchTo(connectionLoser) - connectionFailure = Failure(RuntimeError()) - a.connectionLost(connectionFailure) - self.assertEqual(connectionLoser.reason, connectionFailure) - - - def test_protocolSwitchLoseClientConnection(self): - """ - When the protocol is switched, it should notify its nested client - protocol factory of disconnection. - """ - class ClientLoser: - reason = None - def clientConnectionLost(self, connector, reason): - self.reason = reason - a = amp.BinaryBoxProtocol(self) - connectionLoser = protocol.Protocol() - clientLoser = ClientLoser() - a.makeConnection(self) - a._lockForSwitch() - a._switchTo(connectionLoser, clientLoser) - connectionFailure = Failure(RuntimeError()) - a.connectionLost(connectionFailure) - self.assertEqual(clientLoser.reason, connectionFailure) - - - -class AMPTests(unittest.TestCase): - - def test_interfaceDeclarations(self): - """ - The classes in the amp module ought to implement the interfaces that - are declared for their benefit. - """ - for interface, implementation in [(amp.IBoxSender, amp.BinaryBoxProtocol), - (amp.IBoxReceiver, amp.BoxDispatcher), - (amp.IResponderLocator, amp.CommandLocator), - (amp.IResponderLocator, amp.SimpleStringLocator), - (amp.IBoxSender, amp.AMP), - (amp.IBoxReceiver, amp.AMP), - (amp.IResponderLocator, amp.AMP)]: - self.failUnless(interface.implementedBy(implementation), - "%s does not implements(%s)" % (implementation, interface)) - - - def test_helloWorld(self): - """ - Verify that a simple command can be sent and its response received with - the simple low-level string-based API. - """ - c, s, p = connectedServerAndClient() - L = [] - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEqual(L[0]['hello'], HELLO) - - - def test_wireFormatRoundTrip(self): - """ - Verify that mixed-case, underscored and dashed arguments are mapped to - their python names properly. - """ - c, s, p = connectedServerAndClient() - L = [] - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEqual(L[0]['hello'], HELLO) - - - def test_helloWorldUnicode(self): - """ - Verify that unicode arguments can be encoded and decoded. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - HELLO = 'world' - HELLO_UNICODE = 'wor\u1234ld' - c.sendUnicodeHello(HELLO, HELLO_UNICODE).addCallback(L.append) - p.flush() - self.assertEqual(L[0]['hello'], HELLO) - self.assertEqual(L[0]['Print'], HELLO_UNICODE) - - - def test_callRemoteStringRequiresAnswerFalse(self): - """ - L{BoxDispatcher.callRemoteString} returns C{None} if C{requiresAnswer} - is C{False}. - """ - c, s, p = connectedServerAndClient() - ret = c.callRemoteString("WTF", requiresAnswer=False) - self.assertIdentical(ret, None) - - - def test_unknownCommandLow(self): - """ - Verify that unknown commands using low-level APIs will be rejected with an - error, but will NOT terminate the connection. - """ - c, s, p = connectedServerAndClient() - L = [] - def clearAndAdd(e): - """ - You can't propagate the error... - """ - e.trap(amp.UnhandledCommand) - return "OK" - c.callRemoteString("WTF").addErrback(clearAndAdd).addCallback(L.append) - p.flush() - self.assertEqual(L.pop(), "OK") - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEqual(L[0]['hello'], HELLO) - - - def test_unknownCommandHigh(self): - """ - Verify that unknown commands using high-level APIs will be rejected with an - error, but will NOT terminate the connection. - """ - c, s, p = connectedServerAndClient() - L = [] - def clearAndAdd(e): - """ - You can't propagate the error... - """ - e.trap(amp.UnhandledCommand) - return "OK" - c.callRemote(WTF).addErrback(clearAndAdd).addCallback(L.append) - p.flush() - self.assertEqual(L.pop(), "OK") - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEqual(L[0]['hello'], HELLO) - - - def test_brokenReturnValue(self): - """ - It can be very confusing if you write some code which responds to a - command, but gets the return value wrong. Most commonly you end up - returning None instead of a dictionary. - - Verify that if that happens, the framework logs a useful error. - """ - L = [] - SimpleSymmetricCommandProtocol().dispatchCommand( - amp.AmpBox(_command=BrokenReturn.commandName)).addErrback(L.append) - L[0].trap(amp.BadLocalReturn) - self.failUnlessIn('None', repr(L[0].value)) - - - def test_unknownArgument(self): - """ - Verify that unknown arguments are ignored, and not passed to a Python - function which can't accept them. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - HELLO = 'world' - # c.sendHello(HELLO).addCallback(L.append) - c.callRemote(FutureHello, - hello=HELLO, - bonus="I'm not in the book!").addCallback( - L.append) - p.flush() - self.assertEqual(L[0]['hello'], HELLO) - - - def test_simpleReprs(self): - """ - Verify that the various Box objects repr properly, for debugging. - """ - self.assertEqual(type(repr(amp._SwitchBox('a'))), str) - self.assertEqual(type(repr(amp.QuitBox())), str) - self.assertEqual(type(repr(amp.AmpBox())), str) - self.failUnless("AmpBox" in repr(amp.AmpBox())) - - - def test_innerProtocolInRepr(self): - """ - Verify that L{AMP} objects output their innerProtocol when set. - """ - otherProto = TestProto(None, "outgoing data") - a = amp.AMP() - a.innerProtocol = otherProto - - self.assertEqual( - repr(a), " at 0x%x>" % ( - otherProto.instanceId, id(a))) - - - def test_innerProtocolNotInRepr(self): - """ - Verify that L{AMP} objects do not output 'inner' when no innerProtocol - is set. - """ - a = amp.AMP() - self.assertEqual(repr(a), "" % (id(a),)) - - - def test_simpleSSLRepr(self): - """ - L{amp._TLSBox.__repr__} returns a string. - """ - self.assertEqual(type(repr(amp._TLSBox())), str) - - test_simpleSSLRepr.skip = skipSSL - - - def test_keyTooLong(self): - """ - Verify that a key that is too long will immediately raise a synchronous - exception. - """ - c, s, p = connectedServerAndClient() - x = "H" * (0xff+1) - tl = self.assertRaises(amp.TooLong, - c.callRemoteString, "Hello", - **{x: "hi"}) - self.assertTrue(tl.isKey) - self.assertTrue(tl.isLocal) - self.assertIdentical(tl.keyName, None) - self.assertEqual(tl.value, x) - self.assertIn(str(len(x)), repr(tl)) - self.assertIn("key", repr(tl)) - - - def test_valueTooLong(self): - """ - Verify that attempting to send value longer than 64k will immediately - raise an exception. - """ - c, s, p = connectedServerAndClient() - x = "H" * (0xffff+1) - tl = self.assertRaises(amp.TooLong, c.sendHello, x) - p.flush() - self.failIf(tl.isKey) - self.failUnless(tl.isLocal) - self.assertEqual(tl.keyName, 'hello') - self.failUnlessIdentical(tl.value, x) - self.failUnless(str(len(x)) in repr(tl)) - self.failUnless("value" in repr(tl)) - self.failUnless('hello' in repr(tl)) - - - def test_helloWorldCommand(self): - """ - Verify that a simple command can be sent and its response received with - the high-level value parsing API. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEqual(L[0]['hello'], HELLO) - - - def test_helloErrorHandling(self): - """ - Verify that if a known error type is raised and handled, it will be - properly relayed to the other end of the connection and translated into - an exception, and no error will be logged. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'fuck you' - c.sendHello(HELLO).addErrback(L.append) - p.flush() - L[0].trap(UnfriendlyGreeting) - self.assertEqual(str(L[0].value), "Don't be a dick.") - - - def test_helloFatalErrorHandling(self): - """ - Verify that if a known, fatal error type is raised and handled, it will - be properly relayed to the other end of the connection and translated - into an exception, no error will be logged, and the connection will be - terminated. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'die' - c.sendHello(HELLO).addErrback(L.append) - p.flush() - L.pop().trap(DeathThreat) - c.sendHello(HELLO).addErrback(L.append) - p.flush() - L.pop().trap(error.ConnectionDone) - - - - def test_helloNoErrorHandling(self): - """ - Verify that if an unknown error type is raised, it will be relayed to - the other end of the connection and translated into an exception, it - will be logged, and then the connection will be dropped. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = THING_I_DONT_UNDERSTAND - c.sendHello(HELLO).addErrback(L.append) - p.flush() - ure = L.pop() - ure.trap(amp.UnknownRemoteError) - c.sendHello(HELLO).addErrback(L.append) - cl = L.pop() - cl.trap(error.ConnectionDone) - # The exception should have been logged. - self.failUnless(self.flushLoggedErrors(ThingIDontUnderstandError)) - - - - def test_lateAnswer(self): - """ - Verify that a command that does not get answered until after the - connection terminates will not cause any errors. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - c.callRemote(WaitForever).addErrback(L.append) - p.flush() - self.assertEqual(L, []) - s.transport.loseConnection() - p.flush() - L.pop().trap(error.ConnectionDone) - # Just make sure that it doesn't error... - s.waiting.callback({}) - return s.waiting - - - def test_requiresNoAnswer(self): - """ - Verify that a command that requires no answer is run. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'world' - c.callRemote(NoAnswerHello, hello=HELLO) - p.flush() - self.failUnless(s.greeted) - - - def test_requiresNoAnswerFail(self): - """ - Verify that commands sent after a failed no-answer request do not complete. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'fuck you' - c.callRemote(NoAnswerHello, hello=HELLO) - p.flush() - # This should be logged locally. - self.failUnless(self.flushLoggedErrors(amp.RemoteAmpError)) - HELLO = 'world' - c.callRemote(Hello, hello=HELLO).addErrback(L.append) - p.flush() - L.pop().trap(error.ConnectionDone) - self.failIf(s.greeted) - - - def test_noAnswerResponderBadAnswer(self): - """ - Verify that responders of requiresAnswer=False commands have to return - a dictionary anyway. - - (requiresAnswer is a hint from the _client_ - the server may be called - upon to answer commands in any case, if the client wants to know when - they complete.) - """ - c, s, p = connectedServerAndClient( - ServerClass=BadNoAnswerCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - c.callRemote(NoAnswerHello, hello="hello") - p.flush() - le = self.flushLoggedErrors(amp.BadLocalReturn) - self.assertEqual(len(le), 1) - - - def test_noAnswerResponderAskedForAnswer(self): - """ - Verify that responders with requiresAnswer=False will actually respond - if the client sets requiresAnswer=True. In other words, verify that - requiresAnswer is a hint honored only by the client. - """ - c, s, p = connectedServerAndClient( - ServerClass=NoAnswerCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - c.callRemote(Hello, hello="Hello!").addCallback(L.append) - p.flush() - self.assertEqual(len(L), 1) - self.assertEqual(L, [dict(hello="Hello!-noanswer", - Print=None)]) # Optional response argument - - - def test_ampListCommand(self): - """ - Test encoding of an argument that uses the AmpList encoding. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - c.callRemote(GetList, length=10).addCallback(L.append) - p.flush() - values = L.pop().get('body') - self.assertEqual(values, [{'x': 1}] * 10) - - - def test_optionalAmpListOmitted(self): - """ - Sending a command with an omitted AmpList argument that is - designated as optional does not raise an InvalidSignature error. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - c.callRemote(DontRejectMe, magicWord=u'please').addCallback(L.append) - p.flush() - response = L.pop().get('response') - self.assertEqual(response, 'list omitted') - - - def test_optionalAmpListPresent(self): - """ - Sanity check that optional AmpList arguments are processed normally. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - c.callRemote(DontRejectMe, magicWord=u'please', - list=[{'name': 'foo'}]).addCallback(L.append) - p.flush() - response = L.pop().get('response') - self.assertEqual(response, 'foo accepted') - - - def test_failEarlyOnArgSending(self): - """ - Verify that if we pass an invalid argument list (omitting an argument), - an exception will be raised. - """ - self.assertRaises(amp.InvalidSignature, Hello) - - - def test_doubleProtocolSwitch(self): - """ - As a debugging aid, a protocol system should raise a - L{ProtocolSwitched} exception when asked to switch a protocol that is - already switched. - """ - serverDeferred = defer.Deferred() - serverProto = SimpleSymmetricCommandProtocol(serverDeferred) - clientDeferred = defer.Deferred() - clientProto = SimpleSymmetricCommandProtocol(clientDeferred) - c, s, p = connectedServerAndClient(ServerClass=lambda: serverProto, - ClientClass=lambda: clientProto) - def switched(result): - self.assertRaises(amp.ProtocolSwitched, c.switchToTestProtocol) - self.testSucceeded = True - c.switchToTestProtocol().addCallback(switched) - p.flush() - self.failUnless(self.testSucceeded) - - - def test_protocolSwitch(self, switcher=SimpleSymmetricCommandProtocol, - spuriousTraffic=False, - spuriousError=False): - """ - Verify that it is possible to switch to another protocol mid-connection and - send data to it successfully. - """ - self.testSucceeded = False - - serverDeferred = defer.Deferred() - serverProto = switcher(serverDeferred) - clientDeferred = defer.Deferred() - clientProto = switcher(clientDeferred) - c, s, p = connectedServerAndClient(ServerClass=lambda: serverProto, - ClientClass=lambda: clientProto) - - if spuriousTraffic: - wfdr = [] # remote - c.callRemote(WaitForever).addErrback(wfdr.append) - switchDeferred = c.switchToTestProtocol() - if spuriousTraffic: - self.assertRaises(amp.ProtocolSwitched, c.sendHello, 'world') - - def cbConnsLost(((serverSuccess, serverData), - (clientSuccess, clientData))): - self.failUnless(serverSuccess) - self.failUnless(clientSuccess) - self.assertEqual(''.join(serverData), SWITCH_CLIENT_DATA) - self.assertEqual(''.join(clientData), SWITCH_SERVER_DATA) - self.testSucceeded = True - - def cbSwitch(proto): - return defer.DeferredList( - [serverDeferred, clientDeferred]).addCallback(cbConnsLost) - - switchDeferred.addCallback(cbSwitch) - p.flush() - if serverProto.maybeLater is not None: - serverProto.maybeLater.callback(serverProto.maybeLaterProto) - p.flush() - if spuriousTraffic: - # switch is done here; do this here to make sure that if we're - # going to corrupt the connection, we do it before it's closed. - if spuriousError: - s.waiting.errback(amp.RemoteAmpError( - "SPURIOUS", - "Here's some traffic in the form of an error.")) - else: - s.waiting.callback({}) - p.flush() - c.transport.loseConnection() # close it - p.flush() - self.failUnless(self.testSucceeded) - - - def test_protocolSwitchDeferred(self): - """ - Verify that protocol-switching even works if the value returned from - the command that does the switch is deferred. - """ - return self.test_protocolSwitch(switcher=DeferredSymmetricCommandProtocol) - - - def test_protocolSwitchFail(self, switcher=SimpleSymmetricCommandProtocol): - """ - Verify that if we try to switch protocols and it fails, the connection - stays up and we can go back to speaking AMP. - """ - self.testSucceeded = False - - serverDeferred = defer.Deferred() - serverProto = switcher(serverDeferred) - clientDeferred = defer.Deferred() - clientProto = switcher(clientDeferred) - c, s, p = connectedServerAndClient(ServerClass=lambda: serverProto, - ClientClass=lambda: clientProto) - L = [] - c.switchToTestProtocol(fail=True).addErrback(L.append) - p.flush() - L.pop().trap(UnknownProtocol) - self.failIf(self.testSucceeded) - # It's a known error, so let's send a "hello" on the same connection; - # it should work. - c.sendHello('world').addCallback(L.append) - p.flush() - self.assertEqual(L.pop()['hello'], 'world') - - - def test_trafficAfterSwitch(self): - """ - Verify that attempts to send traffic after a switch will not corrupt - the nested protocol. - """ - return self.test_protocolSwitch(spuriousTraffic=True) - - - def test_errorAfterSwitch(self): - """ - Returning an error after a protocol switch should record the underlying - error. - """ - return self.test_protocolSwitch(spuriousTraffic=True, - spuriousError=True) - - - def test_quitBoxQuits(self): - """ - Verify that commands with a responseType of QuitBox will in fact - terminate the connection. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - - L = [] - HELLO = 'world' - GOODBYE = 'everyone' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEqual(L.pop()['hello'], HELLO) - c.callRemote(Goodbye).addCallback(L.append) - p.flush() - self.assertEqual(L.pop()['goodbye'], GOODBYE) - c.sendHello(HELLO).addErrback(L.append) - L.pop().trap(error.ConnectionDone) - - - def test_basicLiteralEmit(self): - """ - Verify that the command dictionaries for a callRemoteN look correct - after being serialized and parsed. - """ - c, s, p = connectedServerAndClient() - L = [] - s.ampBoxReceived = L.append - c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test', - dash_arg='x', underscore_arg='y') - p.flush() - self.assertEqual(len(L), 1) - for k, v in [('_command', Hello.commandName), - ('hello', 'hello test'), - ('mixedCase', 'mixed case arg test'), - ('dash-arg', 'x'), - ('underscore_arg', 'y')]: - self.assertEqual(L[-1].pop(k), v) - L[-1].pop('_ask') - self.assertEqual(L[-1], {}) - - - def test_basicStructuredEmit(self): - """ - Verify that a call similar to basicLiteralEmit's is handled properly with - high-level quoting and passing to Python methods, and that argument - names are correctly handled. - """ - L = [] - class StructuredHello(amp.AMP): - def h(self, *a, **k): - L.append((a, k)) - return dict(hello='aaa') - Hello.responder(h) - c, s, p = connectedServerAndClient(ServerClass=StructuredHello) - c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test', - dash_arg='x', underscore_arg='y').addCallback(L.append) - p.flush() - self.assertEqual(len(L), 2) - self.assertEqual(L[0], - ((), dict( - hello='hello test', - mixedCase='mixed case arg test', - dash_arg='x', - underscore_arg='y', - From=s.transport.getPeer(), - - # XXX - should optional arguments just not be passed? - # passing None seems a little odd, looking at the way it - # turns out here... -glyph - Print=None, - optional=None, - ))) - self.assertEqual(L[1], dict(Print=None, hello='aaa')) - -class PretendRemoteCertificateAuthority: - def checkIsPretendRemote(self): - return True - -class IOSimCert: - verifyCount = 0 - - def options(self, *ign): - return self - - def iosimVerify(self, otherCert): - """ - This isn't a real certificate, and wouldn't work on a real socket, but - iosim specifies a different API so that we don't have to do any crypto - math to demonstrate that the right functions get called in the right - places. - """ - assert otherCert is self - self.verifyCount += 1 - return True - -class OKCert(IOSimCert): - def options(self, x): - assert x.checkIsPretendRemote() - return self - -class GrumpyCert(IOSimCert): - def iosimVerify(self, otherCert): - self.verifyCount += 1 - return False - -class DroppyCert(IOSimCert): - def __init__(self, toDrop): - self.toDrop = toDrop - - def iosimVerify(self, otherCert): - self.verifyCount += 1 - self.toDrop.loseConnection() - return True - -class SecurableProto(FactoryNotifier): - - factory = None - - def verifyFactory(self): - return [PretendRemoteCertificateAuthority()] - - def getTLSVars(self): - cert = self.certFactory() - verify = self.verifyFactory() - return dict( - tls_localCertificate=cert, - tls_verifyAuthorities=verify) - amp.StartTLS.responder(getTLSVars) - - - -class TLSTests(unittest.TestCase): - def test_startingTLS(self): - """ - Verify that starting TLS and succeeding at handshaking sends all the - notifications to all the right places. - """ - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - - okc = OKCert() - svr.certFactory = lambda : okc - - cli.callRemote( - amp.StartTLS, tls_localCertificate=okc, - tls_verifyAuthorities=[PretendRemoteCertificateAuthority()]) - - # let's buffer something to be delivered securely - L = [] - cli.callRemote(SecuredPing).addCallback(L.append) - p.flush() - # once for client once for server - self.assertEqual(okc.verifyCount, 2) - L = [] - cli.callRemote(SecuredPing).addCallback(L.append) - p.flush() - self.assertEqual(L[0], {'pinged': True}) - - - def test_startTooManyTimes(self): - """ - Verify that the protocol will complain if we attempt to renegotiate TLS, - which we don't support. - """ - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - - okc = OKCert() - svr.certFactory = lambda : okc - - cli.callRemote(amp.StartTLS, - tls_localCertificate=okc, - tls_verifyAuthorities=[PretendRemoteCertificateAuthority()]) - p.flush() - cli.noPeerCertificate = True # this is totally fake - self.assertRaises( - amp.OnlyOneTLS, - cli.callRemote, - amp.StartTLS, - tls_localCertificate=okc, - tls_verifyAuthorities=[PretendRemoteCertificateAuthority()]) - - - def test_negotiationFailed(self): - """ - Verify that starting TLS and failing on both sides at handshaking sends - notifications to all the right places and terminates the connection. - """ - - badCert = GrumpyCert() - - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - svr.certFactory = lambda : badCert - - cli.callRemote(amp.StartTLS, - tls_localCertificate=badCert) - - p.flush() - # once for client once for server - but both fail - self.assertEqual(badCert.verifyCount, 2) - d = cli.callRemote(SecuredPing) - p.flush() - self.assertFailure(d, iosim.NativeOpenSSLError) - - - def test_negotiationFailedByClosing(self): - """ - Verify that starting TLS and failing by way of a lost connection - notices that it is probably an SSL problem. - """ - - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - droppyCert = DroppyCert(svr.transport) - svr.certFactory = lambda : droppyCert - - cli.callRemote(amp.StartTLS, tls_localCertificate=droppyCert) - - p.flush() - - self.assertEqual(droppyCert.verifyCount, 2) - - d = cli.callRemote(SecuredPing) - p.flush() - - # it might be a good idea to move this exception somewhere more - # reasonable. - self.assertFailure(d, error.PeerVerifyError) - - skip = skipSSL - - - -class TLSNotAvailableTests(unittest.TestCase): - """ - Tests what happened when ssl is not available in current installation. - """ - - def setUp(self): - """ - Disable ssl in amp. - """ - self.ssl = amp.ssl - amp.ssl = None - - - def tearDown(self): - """ - Restore ssl module. - """ - amp.ssl = self.ssl - - - def test_callRemoteError(self): - """ - Check that callRemote raises an exception when called with a - L{amp.StartTLS}. - """ - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - - okc = OKCert() - svr.certFactory = lambda : okc - - return self.assertFailure(cli.callRemote( - amp.StartTLS, tls_localCertificate=okc, - tls_verifyAuthorities=[PretendRemoteCertificateAuthority()]), - RuntimeError) - - - def test_messageReceivedError(self): - """ - When a client with SSL enabled talks to a server without SSL, it - should return a meaningful error. - """ - svr = SecurableProto() - okc = OKCert() - svr.certFactory = lambda : okc - box = amp.Box() - box['_command'] = 'StartTLS' - box['_ask'] = '1' - boxes = [] - svr.sendBox = boxes.append - svr.makeConnection(StringTransport()) - svr.ampBoxReceived(box) - self.assertEqual(boxes, - [{'_error_code': 'TLS_ERROR', - '_error': '1', - '_error_description': 'TLS not available'}]) - - - -class InheritedError(Exception): - """ - This error is used to check inheritance. - """ - - - -class OtherInheritedError(Exception): - """ - This is a distinct error for checking inheritance. - """ - - - -class BaseCommand(amp.Command): - """ - This provides a command that will be subclassed. - """ - errors = {InheritedError: 'INHERITED_ERROR'} - - - -class InheritedCommand(BaseCommand): - """ - This is a command which subclasses another command but does not override - anything. - """ - - - -class AddErrorsCommand(BaseCommand): - """ - This is a command which subclasses another command but adds errors to the - list. - """ - arguments = [('other', amp.Boolean())] - errors = {OtherInheritedError: 'OTHER_INHERITED_ERROR'} - - - -class NormalCommandProtocol(amp.AMP): - """ - This is a protocol which responds to L{BaseCommand}, and is used to test - that inheritance does not interfere with the normal handling of errors. - """ - def resp(self): - raise InheritedError() - BaseCommand.responder(resp) - - - -class InheritedCommandProtocol(amp.AMP): - """ - This is a protocol which responds to L{InheritedCommand}, and is used to - test that inherited commands inherit their bases' errors if they do not - respond to any of their own. - """ - def resp(self): - raise InheritedError() - InheritedCommand.responder(resp) - - - -class AddedCommandProtocol(amp.AMP): - """ - This is a protocol which responds to L{AddErrorsCommand}, and is used to - test that inherited commands can add their own new types of errors, but - still respond in the same way to their parents types of errors. - """ - def resp(self, other): - if other: - raise OtherInheritedError() - else: - raise InheritedError() - AddErrorsCommand.responder(resp) - - - -class CommandInheritanceTests(unittest.TestCase): - """ - These tests verify that commands inherit error conditions properly. - """ - - def errorCheck(self, err, proto, cmd, **kw): - """ - Check that the appropriate kind of error is raised when a given command - is sent to a given protocol. - """ - c, s, p = connectedServerAndClient(ServerClass=proto, - ClientClass=proto) - d = c.callRemote(cmd, **kw) - d2 = self.failUnlessFailure(d, err) - p.flush() - return d2 - - - def test_basicErrorPropagation(self): - """ - Verify that errors specified in a superclass are respected normally - even if it has subclasses. - """ - return self.errorCheck( - InheritedError, NormalCommandProtocol, BaseCommand) - - - def test_inheritedErrorPropagation(self): - """ - Verify that errors specified in a superclass command are propagated to - its subclasses. - """ - return self.errorCheck( - InheritedError, InheritedCommandProtocol, InheritedCommand) - - - def test_inheritedErrorAddition(self): - """ - Verify that new errors specified in a subclass of an existing command - are honored even if the superclass defines some errors. - """ - return self.errorCheck( - OtherInheritedError, AddedCommandProtocol, AddErrorsCommand, other=True) - - - def test_additionWithOriginalError(self): - """ - Verify that errors specified in a command's superclass are respected - even if that command defines new errors itself. - """ - return self.errorCheck( - InheritedError, AddedCommandProtocol, AddErrorsCommand, other=False) - - -def _loseAndPass(err, proto): - # be specific, pass on the error to the client. - err.trap(error.ConnectionLost, error.ConnectionDone) - del proto.connectionLost - proto.connectionLost(err) - - -class LiveFireBase: - """ - Utility for connected reactor-using tests. - """ - - def setUp(self): - """ - Create an amp server and connect a client to it. - """ - from twisted.internet import reactor - self.serverFactory = protocol.ServerFactory() - self.serverFactory.protocol = self.serverProto - self.clientFactory = protocol.ClientFactory() - self.clientFactory.protocol = self.clientProto - self.clientFactory.onMade = defer.Deferred() - self.serverFactory.onMade = defer.Deferred() - self.serverPort = reactor.listenTCP(0, self.serverFactory) - self.addCleanup(self.serverPort.stopListening) - self.clientConn = reactor.connectTCP( - '127.0.0.1', self.serverPort.getHost().port, - self.clientFactory) - self.addCleanup(self.clientConn.disconnect) - def getProtos(rlst): - self.cli = self.clientFactory.theProto - self.svr = self.serverFactory.theProto - dl = defer.DeferredList([self.clientFactory.onMade, - self.serverFactory.onMade]) - return dl.addCallback(getProtos) - - def tearDown(self): - """ - Cleanup client and server connections, and check the error got at - C{connectionLost}. - """ - L = [] - for conn in self.cli, self.svr: - if conn.transport is not None: - # depend on amp's function connection-dropping behavior - d = defer.Deferred().addErrback(_loseAndPass, conn) - conn.connectionLost = d.errback - conn.transport.loseConnection() - L.append(d) - return defer.gatherResults(L - ).addErrback(lambda first: first.value.subFailure) - - -def show(x): - import sys - sys.stdout.write(x+'\n') - sys.stdout.flush() - - -def tempSelfSigned(): - from twisted.internet import ssl - - sharedDN = ssl.DN(CN='shared') - key = ssl.KeyPair.generate() - cr = key.certificateRequest(sharedDN) - sscrd = key.signCertificateRequest( - sharedDN, cr, lambda dn: True, 1234567) - cert = key.newCertificate(sscrd) - return cert - -if ssl is not None: - tempcert = tempSelfSigned() - - -class LiveFireTLSTests(LiveFireBase, unittest.TestCase): - clientProto = SecurableProto - serverProto = SecurableProto - def test_liveFireCustomTLS(self): - """ - Using real, live TLS, actually negotiate a connection. - - This also looks at the 'peerCertificate' attribute's correctness, since - that's actually loaded using OpenSSL calls, but the main purpose is to - make sure that we didn't miss anything obvious in iosim about TLS - negotiations. - """ - - cert = tempcert - - self.svr.verifyFactory = lambda : [cert] - self.svr.certFactory = lambda : cert - # only needed on the server, we specify the client below. - - def secured(rslt): - x = cert.digest() - def pinged(rslt2): - # Interesting. OpenSSL won't even _tell_ us about the peer - # cert until we negotiate. we should be able to do this in - # 'secured' instead, but it looks like we can't. I think this - # is a bug somewhere far deeper than here. - self.assertEqual(x, self.cli.hostCertificate.digest()) - self.assertEqual(x, self.cli.peerCertificate.digest()) - self.assertEqual(x, self.svr.hostCertificate.digest()) - self.assertEqual(x, self.svr.peerCertificate.digest()) - return self.cli.callRemote(SecuredPing).addCallback(pinged) - return self.cli.callRemote(amp.StartTLS, - tls_localCertificate=cert, - tls_verifyAuthorities=[cert]).addCallback(secured) - - skip = skipSSL - - - -class SlightlySmartTLS(SimpleSymmetricCommandProtocol): - """ - Specific implementation of server side protocol with different - management of TLS. - """ - def getTLSVars(self): - """ - @return: the global C{tempcert} certificate as local certificate. - """ - return dict(tls_localCertificate=tempcert) - amp.StartTLS.responder(getTLSVars) - - -class PlainVanillaLiveFireTests(LiveFireBase, unittest.TestCase): - - clientProto = SimpleSymmetricCommandProtocol - serverProto = SimpleSymmetricCommandProtocol - - def test_liveFireDefaultTLS(self): - """ - Verify that out of the box, we can start TLS to at least encrypt the - connection, even if we don't have any certificates to use. - """ - def secured(result): - return self.cli.callRemote(SecuredPing) - return self.cli.callRemote(amp.StartTLS).addCallback(secured) - - skip = skipSSL - - - -class WithServerTLSVerificationTests(LiveFireBase, unittest.TestCase): - clientProto = SimpleSymmetricCommandProtocol - serverProto = SlightlySmartTLS - - def test_anonymousVerifyingClient(self): - """ - Verify that anonymous clients can verify server certificates. - """ - def secured(result): - return self.cli.callRemote(SecuredPing) - return self.cli.callRemote(amp.StartTLS, - tls_verifyAuthorities=[tempcert] - ).addCallback(secured) - - skip = skipSSL - - - -class ProtocolIncludingArgument(amp.Argument): - """ - An L{amp.Argument} which encodes its parser and serializer - arguments *including the protocol* into its parsed and serialized - forms. - """ - - def fromStringProto(self, string, protocol): - """ - Don't decode anything; just return all possible information. - - @return: A two-tuple of the input string and the protocol. - """ - return (string, protocol) - - def toStringProto(self, obj, protocol): - """ - Encode identifying information about L{object} and protocol - into a string for later verification. - - @type obj: L{object} - @type protocol: L{amp.AMP} - """ - return "%s:%s" % (id(obj), id(protocol)) - - - -class ProtocolIncludingCommand(amp.Command): - """ - A command that has argument and response schemas which use - L{ProtocolIncludingArgument}. - """ - arguments = [('weird', ProtocolIncludingArgument())] - response = [('weird', ProtocolIncludingArgument())] - - - -class MagicSchemaCommand(amp.Command): - """ - A command which overrides L{parseResponse}, L{parseArguments}, and - L{makeResponse}. - """ - def parseResponse(self, strings, protocol): - """ - Don't do any parsing, just jam the input strings and protocol - onto the C{protocol.parseResponseArguments} attribute as a - two-tuple. Return the original strings. - """ - protocol.parseResponseArguments = (strings, protocol) - return strings - parseResponse = classmethod(parseResponse) - - - def parseArguments(cls, strings, protocol): - """ - Don't do any parsing, just jam the input strings and protocol - onto the C{protocol.parseArgumentsArguments} attribute as a - two-tuple. Return the original strings. - """ - protocol.parseArgumentsArguments = (strings, protocol) - return strings - parseArguments = classmethod(parseArguments) - - - def makeArguments(cls, objects, protocol): - """ - Don't do any serializing, just jam the input strings and protocol - onto the C{protocol.makeArgumentsArguments} attribute as a - two-tuple. Return the original strings. - """ - protocol.makeArgumentsArguments = (objects, protocol) - return objects - makeArguments = classmethod(makeArguments) - - - -class NoNetworkProtocol(amp.AMP): - """ - An L{amp.AMP} subclass which overrides private methods to avoid - testing the network. It also provides a responder for - L{MagicSchemaCommand} that does nothing, so that tests can test - aspects of the interaction of L{amp.Command}s and L{amp.AMP}. - - @ivar parseArgumentsArguments: Arguments that have been passed to any - L{MagicSchemaCommand}, if L{MagicSchemaCommand} has been handled by - this protocol. - - @ivar parseResponseArguments: Responses that have been returned from a - L{MagicSchemaCommand}, if L{MagicSchemaCommand} has been handled by - this protocol. - - @ivar makeArgumentsArguments: Arguments that have been serialized by any - L{MagicSchemaCommand}, if L{MagicSchemaCommand} has been handled by - this protocol. - """ - def _sendBoxCommand(self, commandName, strings, requiresAnswer): - """ - Return a Deferred which fires with the original strings. - """ - return defer.succeed(strings) - - MagicSchemaCommand.responder(lambda s, weird: {}) - - - -class MyBox(dict): - """ - A unique dict subclass. - """ - - - -class ProtocolIncludingCommandWithDifferentCommandType( - ProtocolIncludingCommand): - """ - A L{ProtocolIncludingCommand} subclass whose commandType is L{MyBox} - """ - commandType = MyBox - - - -class CommandTests(unittest.TestCase): - """ - Tests for L{amp.Argument} and L{amp.Command}. - """ - def test_argumentInterface(self): - """ - L{Argument} instances provide L{amp.IArgumentType}. - """ - self.assertTrue(verifyObject(amp.IArgumentType, amp.Argument())) - - - def test_parseResponse(self): - """ - There should be a class method of Command which accepts a - mapping of argument names to serialized forms and returns a - similar mapping whose values have been parsed via the - Command's response schema. - """ - protocol = object() - result = 'whatever' - strings = {'weird': result} - self.assertEqual( - ProtocolIncludingCommand.parseResponse(strings, protocol), - {'weird': (result, protocol)}) - - - def test_callRemoteCallsParseResponse(self): - """ - Making a remote call on a L{amp.Command} subclass which - overrides the C{parseResponse} method should call that - C{parseResponse} method to get the response. - """ - client = NoNetworkProtocol() - thingy = "weeoo" - response = client.callRemote(MagicSchemaCommand, weird=thingy) - def gotResponse(ign): - self.assertEqual(client.parseResponseArguments, - ({"weird": thingy}, client)) - response.addCallback(gotResponse) - return response - - - def test_parseArguments(self): - """ - There should be a class method of L{amp.Command} which accepts - a mapping of argument names to serialized forms and returns a - similar mapping whose values have been parsed via the - command's argument schema. - """ - protocol = object() - result = 'whatever' - strings = {'weird': result} - self.assertEqual( - ProtocolIncludingCommand.parseArguments(strings, protocol), - {'weird': (result, protocol)}) - - - def test_responderCallsParseArguments(self): - """ - Making a remote call on a L{amp.Command} subclass which - overrides the C{parseArguments} method should call that - C{parseArguments} method to get the arguments. - """ - protocol = NoNetworkProtocol() - responder = protocol.locateResponder(MagicSchemaCommand.commandName) - argument = object() - response = responder(dict(weird=argument)) - response.addCallback( - lambda ign: self.assertEqual(protocol.parseArgumentsArguments, - ({"weird": argument}, protocol))) - return response - - - def test_makeArguments(self): - """ - There should be a class method of L{amp.Command} which accepts - a mapping of argument names to objects and returns a similar - mapping whose values have been serialized via the command's - argument schema. - """ - protocol = object() - argument = object() - objects = {'weird': argument} - self.assertEqual( - ProtocolIncludingCommand.makeArguments(objects, protocol), - {'weird': "%d:%d" % (id(argument), id(protocol))}) - - - def test_makeArgumentsUsesCommandType(self): - """ - L{amp.Command.makeArguments}'s return type should be the type - of the result of L{amp.Command.commandType}. - """ - protocol = object() - objects = {"weird": "whatever"} - - result = ProtocolIncludingCommandWithDifferentCommandType.makeArguments( - objects, protocol) - self.assertIdentical(type(result), MyBox) - - - def test_callRemoteCallsMakeArguments(self): - """ - Making a remote call on a L{amp.Command} subclass which - overrides the C{makeArguments} method should call that - C{makeArguments} method to get the response. - """ - client = NoNetworkProtocol() - argument = object() - response = client.callRemote(MagicSchemaCommand, weird=argument) - def gotResponse(ign): - self.assertEqual(client.makeArgumentsArguments, - ({"weird": argument}, client)) - response.addCallback(gotResponse) - return response - - - def test_extraArgumentsDisallowed(self): - """ - L{Command.makeArguments} raises L{amp.InvalidSignature} if the objects - dictionary passed to it includes a key which does not correspond to the - Python identifier for a defined argument. - """ - self.assertRaises( - amp.InvalidSignature, - Hello.makeArguments, - dict(hello="hello", bogusArgument=object()), None) - - - def test_wireSpellingDisallowed(self): - """ - If a command argument conflicts with a Python keyword, the - untransformed argument name is not allowed as a key in the dictionary - passed to L{Command.makeArguments}. If it is supplied, - L{amp.InvalidSignature} is raised. - - This may be a pointless implementation restriction which may be lifted. - The current behavior is tested to verify that such arguments are not - silently dropped on the floor (the previous behavior). - """ - self.assertRaises( - amp.InvalidSignature, - Hello.makeArguments, - dict(hello="required", **{"print": "print value"}), - None) - - -class ListOfTestsMixin: - """ - Base class for testing L{ListOf}, a parameterized zero-or-more argument - type. - - @ivar elementType: Subclasses should set this to an L{Argument} - instance. The tests will make a L{ListOf} using this. - - @ivar strings: Subclasses should set this to a dictionary mapping some - number of keys to the correct serialized form for some example - values. These should agree with what L{elementType} - produces/accepts. - - @ivar objects: Subclasses should set this to a dictionary with the same - keys as C{strings} and with values which are the lists which should - serialize to the values in the C{strings} dictionary. - """ - def test_toBox(self): - """ - L{ListOf.toBox} extracts the list of objects from the C{objects} - dictionary passed to it, using the C{name} key also passed to it, - serializes each of the elements in that list using the L{Argument} - instance previously passed to its initializer, combines the serialized - results, and inserts the result into the C{strings} dictionary using - the same C{name} key. - """ - stringList = amp.ListOf(self.elementType) - strings = amp.AmpBox() - for key in self.objects: - stringList.toBox(key, strings, self.objects.copy(), None) - self.assertEqual(strings, self.strings) - - - def test_fromBox(self): - """ - L{ListOf.fromBox} reverses the operation performed by L{ListOf.toBox}. - """ - stringList = amp.ListOf(self.elementType) - objects = {} - for key in self.strings: - stringList.fromBox(key, self.strings.copy(), objects, None) - self.assertEqual(objects, self.objects) - - - -class ListOfStringsTests(unittest.TestCase, ListOfTestsMixin): - """ - Tests for L{ListOf} combined with L{amp.String}. - """ - elementType = amp.String() - - strings = { - "empty": "", - "single": "\x00\x03foo", - "multiple": "\x00\x03bar\x00\x03baz\x00\x04quux"} - - objects = { - "empty": [], - "single": ["foo"], - "multiple": ["bar", "baz", "quux"]} - - -class ListOfIntegersTests(unittest.TestCase, ListOfTestsMixin): - """ - Tests for L{ListOf} combined with L{amp.Integer}. - """ - elementType = amp.Integer() - - huge = ( - 9999999999999999999999999999999999999999999999999999999999 * - 9999999999999999999999999999999999999999999999999999999999) - - strings = { - "empty": "", - "single": "\x00\x0210", - "multiple": "\x00\x011\x00\x0220\x00\x03500", - "huge": "\x00\x74%d" % (huge,), - "negative": "\x00\x02-1"} - - objects = { - "empty": [], - "single": [10], - "multiple": [1, 20, 500], - "huge": [huge], - "negative": [-1]} - - - -class ListOfUnicodeTests(unittest.TestCase, ListOfTestsMixin): - """ - Tests for L{ListOf} combined with L{amp.Unicode}. - """ - elementType = amp.Unicode() - - strings = { - "empty": "", - "single": "\x00\x03foo", - "multiple": "\x00\x03\xe2\x98\x83\x00\x05Hello\x00\x05world"} - - objects = { - "empty": [], - "single": [u"foo"], - "multiple": [u"\N{SNOWMAN}", u"Hello", u"world"]} - - - -class ListOfDecimalTests(unittest.TestCase, ListOfTestsMixin): - """ - Tests for L{ListOf} combined with L{amp.Decimal}. - """ - elementType = amp.Decimal() - - strings = { - "empty": "", - "single": "\x00\x031.1", - "extreme": "\x00\x08Infinity\x00\x09-Infinity", - "scientist": "\x00\x083.141E+5\x00\x0a0.00003141\x00\x083.141E-7" - "\x00\x09-3.141E+5\x00\x0b-0.00003141\x00\x09-3.141E-7", - "engineer": "\x00\x04%s\x00\x06%s" % ( - decimal.Decimal("0e6").to_eng_string(), - decimal.Decimal("1.5E-9").to_eng_string()), - } - - objects = { - "empty": [], - "single": [decimal.Decimal("1.1")], - "extreme": [ - decimal.Decimal("Infinity"), - decimal.Decimal("-Infinity"), - ], - # exarkun objected to AMP supporting engineering notation because - # it was redundant, until we realised that 1E6 has less precision - # than 1000000 and is represented differently. But they compare - # and even hash equally. There were tears. - "scientist": [ - decimal.Decimal("3.141E5"), - decimal.Decimal("3.141e-5"), - decimal.Decimal("3.141E-7"), - decimal.Decimal("-3.141e5"), - decimal.Decimal("-3.141E-5"), - decimal.Decimal("-3.141e-7"), - ], - "engineer": [ - decimal.Decimal("0e6"), - decimal.Decimal("1.5E-9"), - ], - } - - - -class ListOfDecimalNanTests(unittest.TestCase, ListOfTestsMixin): - """ - Tests for L{ListOf} combined with L{amp.Decimal} for not-a-number values. - """ - elementType = amp.Decimal() - - strings = { - "nan": "\x00\x03NaN\x00\x04-NaN\x00\x04sNaN\x00\x05-sNaN", - } - - objects = { - "nan": [ - decimal.Decimal("NaN"), - decimal.Decimal("-NaN"), - decimal.Decimal("sNaN"), - decimal.Decimal("-sNaN"), - ] - } - - def test_fromBox(self): - """ - L{ListOf.fromBox} reverses the operation performed by L{ListOf.toBox}. - """ - # Helpers. Decimal.is_{qnan,snan,signed}() are new in 2.6 (or 2.5.2, - # but who's counting). - def is_qnan(decimal): - return 'NaN' in str(decimal) and 'sNaN' not in str(decimal) - - def is_snan(decimal): - return 'sNaN' in str(decimal) - - def is_signed(decimal): - return '-' in str(decimal) - - # NaN values have unusual equality semantics, so this method is - # overridden to compare the resulting objects in a way which works with - # NaNs. - stringList = amp.ListOf(self.elementType) - objects = {} - for key in self.strings: - stringList.fromBox(key, self.strings.copy(), objects, None) - n = objects["nan"] - self.assertTrue(is_qnan(n[0]) and not is_signed(n[0])) - self.assertTrue(is_qnan(n[1]) and is_signed(n[1])) - self.assertTrue(is_snan(n[2]) and not is_signed(n[2])) - self.assertTrue(is_snan(n[3]) and is_signed(n[3])) - - - -class DecimalTests(unittest.TestCase): - """ - Tests for L{amp.Decimal}. - """ - def test_nonDecimal(self): - """ - L{amp.Decimal.toString} raises L{ValueError} if passed an object which - is not an instance of C{decimal.Decimal}. - """ - argument = amp.Decimal() - self.assertRaises(ValueError, argument.toString, "1.234") - self.assertRaises(ValueError, argument.toString, 1.234) - self.assertRaises(ValueError, argument.toString, 1234) - - - -class ListOfDateTimeTests(unittest.TestCase, ListOfTestsMixin): - """ - Tests for L{ListOf} combined with L{amp.DateTime}. - """ - elementType = amp.DateTime() - - strings = { - "christmas": "\x00\x202010-12-25T00:00:00.000000-00:00" - "\x00\x202010-12-25T00:00:00.000000-00:00", - "christmas in eu": "\x00\x202010-12-25T00:00:00.000000+01:00", - "christmas in iran": "\x00\x202010-12-25T00:00:00.000000+03:30", - "christmas in nyc": "\x00\x202010-12-25T00:00:00.000000-05:00", - "previous tests": "\x00\x202010-12-25T00:00:00.000000+03:19" - "\x00\x202010-12-25T00:00:00.000000-06:59", - } - - objects = { - "christmas": [ - datetime.datetime(2010, 12, 25, 0, 0, 0, tzinfo=amp.utc), - datetime.datetime(2010, 12, 25, 0, 0, 0, tzinfo=tz('+', 0, 0)), - ], - "christmas in eu": [ - datetime.datetime(2010, 12, 25, 0, 0, 0, tzinfo=tz('+', 1, 0)), - ], - "christmas in iran": [ - datetime.datetime(2010, 12, 25, 0, 0, 0, tzinfo=tz('+', 3, 30)), - ], - "christmas in nyc": [ - datetime.datetime(2010, 12, 25, 0, 0, 0, tzinfo=tz('-', 5, 0)), - ], - "previous tests": [ - datetime.datetime(2010, 12, 25, 0, 0, 0, tzinfo=tz('+', 3, 19)), - datetime.datetime(2010, 12, 25, 0, 0, 0, tzinfo=tz('-', 6, 59)), - ], - } - - - -class ListOfOptionalTests(unittest.TestCase): - """ - Tests to ensure L{ListOf} AMP arguments can be omitted from AMP commands - via the 'optional' flag. - """ - def test_requiredArgumentWithNoneValueRaisesTypeError(self): - """ - L{ListOf.toBox} raises C{TypeError} when passed a value of C{None} - for the argument. - """ - stringList = amp.ListOf(amp.Integer()) - self.assertRaises( - TypeError, stringList.toBox, 'omitted', amp.AmpBox(), - {'omitted': None}, None) - - - def test_optionalArgumentWithNoneValueOmitted(self): - """ - L{ListOf.toBox} silently omits serializing any argument with a - value of C{None} that is designated as optional for the protocol. - """ - stringList = amp.ListOf(amp.Integer(), optional=True) - strings = amp.AmpBox() - stringList.toBox('omitted', strings, {'omitted': None}, None) - self.assertEqual(strings, {}) - - - def test_requiredArgumentWithKeyMissingRaisesKeyError(self): - """ - L{ListOf.toBox} raises C{KeyError} if the argument's key is not - present in the objects dictionary. - """ - stringList = amp.ListOf(amp.Integer()) - self.assertRaises( - KeyError, stringList.toBox, 'ommited', amp.AmpBox(), - {'someOtherKey': 0}, None) - - - def test_optionalArgumentWithKeyMissingOmitted(self): - """ - L{ListOf.toBox} silently omits serializing any argument designated - as optional whose key is not present in the objects dictionary. - """ - stringList = amp.ListOf(amp.Integer(), optional=True) - stringList.toBox('ommited', amp.AmpBox(), {'someOtherKey': 0}, None) - - - def test_omittedOptionalArgumentDeserializesAsNone(self): - """ - L{ListOf.fromBox} correctly reverses the operation performed by - L{ListOf.toBox} for optional arguments. - """ - stringList = amp.ListOf(amp.Integer(), optional=True) - objects = {} - stringList.fromBox('omitted', {}, objects, None) - self.assertEqual(objects, {'omitted': None}) - - - -class UNIXStringTransport(object): - """ - An in-memory implementation of L{interfaces.IUNIXTransport} which collects - all data given to it for later inspection. - - @ivar _queue: A C{list} of the data which has been given to this transport, - eg via C{write} or C{sendFileDescriptor}. Elements are two-tuples of a - string (identifying the destination of the data) and the data itself. - """ - implements(interfaces.IUNIXTransport) - - def __init__(self, descriptorFuzz): - """ - @param descriptorFuzz: An offset to apply to descriptors. - @type descriptorFuzz: C{int} - """ - self._fuzz = descriptorFuzz - self._queue = [] - - - def sendFileDescriptor(self, descriptor): - self._queue.append(( - 'fileDescriptorReceived', descriptor + self._fuzz)) - - - def write(self, data): - self._queue.append(('dataReceived', data)) - - - def writeSequence(self, seq): - for data in seq: - self.write(data) - - - def loseConnection(self): - self._queue.append(('connectionLost', Failure(error.ConnectionLost()))) - - - def getHost(self): - return address.UNIXAddress('/tmp/some-path') - - - def getPeer(self): - return address.UNIXAddress('/tmp/another-path') - -# Minimal evidence that we got the signatures right -verifyClass(interfaces.ITransport, UNIXStringTransport) -verifyClass(interfaces.IUNIXTransport, UNIXStringTransport) - - -class DescriptorTests(unittest.TestCase): - """ - Tests for L{amp.Descriptor}, an argument type for passing a file descriptor - over an AMP connection over a UNIX domain socket. - """ - def setUp(self): - self.fuzz = 3 - self.transport = UNIXStringTransport(descriptorFuzz=self.fuzz) - self.protocol = amp.BinaryBoxProtocol( - amp.BoxDispatcher(amp.CommandLocator())) - self.protocol.makeConnection(self.transport) - - - def test_fromStringProto(self): - """ - L{Descriptor.fromStringProto} constructs a file descriptor value by - extracting a previously received file descriptor corresponding to the - wire value of the argument from the L{_DescriptorExchanger} state of the - protocol passed to it. - - This is a whitebox test which involves direct L{_DescriptorExchanger} - state inspection. - """ - argument = amp.Descriptor() - self.protocol.fileDescriptorReceived(5) - self.protocol.fileDescriptorReceived(3) - self.protocol.fileDescriptorReceived(1) - self.assertEqual( - 5, argument.fromStringProto("0", self.protocol)) - self.assertEqual( - 3, argument.fromStringProto("1", self.protocol)) - self.assertEqual( - 1, argument.fromStringProto("2", self.protocol)) - self.assertEqual({}, self.protocol._descriptors) - - - def test_toStringProto(self): - """ - To send a file descriptor, L{Descriptor.toStringProto} uses the - L{IUNIXTransport.sendFileDescriptor} implementation of the transport of - the protocol passed to it to copy the file descriptor. Each subsequent - descriptor sent over a particular AMP connection is assigned the next - integer value, starting from 0. The base ten string representation of - this value is the byte encoding of the argument. - - This is a whitebox test which involves direct L{_DescriptorExchanger} - state inspection and mutation. - """ - argument = amp.Descriptor() - self.assertEqual("0", argument.toStringProto(2, self.protocol)) - self.assertEqual( - ("fileDescriptorReceived", 2 + self.fuzz), self.transport._queue.pop(0)) - self.assertEqual("1", argument.toStringProto(4, self.protocol)) - self.assertEqual( - ("fileDescriptorReceived", 4 + self.fuzz), self.transport._queue.pop(0)) - self.assertEqual("2", argument.toStringProto(6, self.protocol)) - self.assertEqual( - ("fileDescriptorReceived", 6 + self.fuzz), self.transport._queue.pop(0)) - self.assertEqual({}, self.protocol._descriptors) - - - def test_roundTrip(self): - """ - L{amp.Descriptor.fromBox} can interpret an L{amp.AmpBox} constructed by - L{amp.Descriptor.toBox} to reconstruct a file descriptor value. - """ - name = "alpha" - strings = {} - descriptor = 17 - sendObjects = {name: descriptor} - - argument = amp.Descriptor() - argument.toBox(name, strings, sendObjects.copy(), self.protocol) - - receiver = amp.BinaryBoxProtocol( - amp.BoxDispatcher(amp.CommandLocator())) - for event in self.transport._queue: - getattr(receiver, event[0])(*event[1:]) - - receiveObjects = {} - argument.fromBox(name, strings.copy(), receiveObjects, receiver) - - # Make sure we got the descriptor. Adjust by fuzz to be more convincing - # of having gone through L{IUNIXTransport.sendFileDescriptor}, not just - # converted to a string and then parsed back into an integer. - self.assertEqual(descriptor + self.fuzz, receiveObjects[name]) - - - -class DateTimeTests(unittest.TestCase): - """ - Tests for L{amp.DateTime}, L{amp._FixedOffsetTZInfo}, and L{amp.utc}. - """ - string = '9876-01-23T12:34:56.054321-01:23' - tzinfo = tz('-', 1, 23) - object = datetime.datetime(9876, 1, 23, 12, 34, 56, 54321, tzinfo) - - def test_invalidString(self): - """ - L{amp.DateTime.fromString} raises L{ValueError} when passed a string - which does not represent a timestamp in the proper format. - """ - d = amp.DateTime() - self.assertRaises(ValueError, d.fromString, 'abc') - - - def test_invalidDatetime(self): - """ - L{amp.DateTime.toString} raises L{ValueError} when passed a naive - datetime (a datetime with no timezone information). - """ - d = amp.DateTime() - self.assertRaises(ValueError, d.toString, - datetime.datetime(2010, 12, 25, 0, 0, 0)) - - - def test_fromString(self): - """ - L{amp.DateTime.fromString} returns a C{datetime.datetime} with all of - its fields populated from the string passed to it. - """ - argument = amp.DateTime() - value = argument.fromString(self.string) - self.assertEqual(value, self.object) - - - def test_toString(self): - """ - L{amp.DateTime.toString} returns a C{str} in the wire format including - all of the information from the C{datetime.datetime} passed into it, - including the timezone offset. - """ - argument = amp.DateTime() - value = argument.toString(self.object) - self.assertEqual(value, self.string) - - - -class UTCTests(unittest.TestCase): - """ - Tests for L{amp.utc}. - """ - - def test_tzname(self): - """ - L{amp.utc.tzname} returns C{"+00:00"}. - """ - self.assertEqual(amp.utc.tzname(None), '+00:00') - - - def test_dst(self): - """ - L{amp.utc.dst} returns a zero timedelta. - """ - self.assertEqual(amp.utc.dst(None), datetime.timedelta(0)) - - - def test_utcoffset(self): - """ - L{amp.utc.utcoffset} returns a zero timedelta. - """ - self.assertEqual(amp.utc.utcoffset(None), datetime.timedelta(0)) - - - def test_badSign(self): - """ - L{amp._FixedOffsetTZInfo.fromSignHoursMinutes} raises L{ValueError} if - passed an offset sign other than C{'+'} or C{'-'}. - """ - self.assertRaises(ValueError, tz, '?', 0, 0) - - - -if not interfaces.IReactorSSL.providedBy(reactor): - skipMsg = 'This test case requires SSL support in the reactor' - TLSTests.skip = skipMsg - LiveFireTLSTests.skip = skipMsg - PlainVanillaLiveFireTests.skip = skipMsg - WithServerTLSVerificationTests.skip = skipMsg diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_application.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_application.py deleted file mode 100644 index 6f6bf36..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_application.py +++ /dev/null @@ -1,883 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.application} and its interaction with -L{twisted.persisted.sob}. -""" - -import copy, os, pickle -from StringIO import StringIO - -from twisted.trial import unittest -from twisted.application import service, internet, app -from twisted.persisted import sob -from twisted.python import usage -from twisted.internet import interfaces, defer -from twisted.protocols import wire, basic -from twisted.internet import protocol, reactor -from twisted.application import reactors -from twisted.test.proto_helpers import MemoryReactor -from twisted.python.test.modules_helpers import TwistedModulesMixin - - -class Dummy: - processName=None - -class ServiceTests(unittest.TestCase): - - def testName(self): - s = service.Service() - s.setName("hello") - self.assertEqual(s.name, "hello") - - def testParent(self): - s = service.Service() - p = service.MultiService() - s.setServiceParent(p) - self.assertEqual(list(p), [s]) - self.assertEqual(s.parent, p) - - def testApplicationAsParent(self): - s = service.Service() - p = service.Application("") - s.setServiceParent(p) - self.assertEqual(list(service.IServiceCollection(p)), [s]) - self.assertEqual(s.parent, service.IServiceCollection(p)) - - def testNamedChild(self): - s = service.Service() - p = service.MultiService() - s.setName("hello") - s.setServiceParent(p) - self.assertEqual(list(p), [s]) - self.assertEqual(s.parent, p) - self.assertEqual(p.getServiceNamed("hello"), s) - - def testDoublyNamedChild(self): - s = service.Service() - p = service.MultiService() - s.setName("hello") - s.setServiceParent(p) - self.failUnlessRaises(RuntimeError, s.setName, "lala") - - def testDuplicateNamedChild(self): - s = service.Service() - p = service.MultiService() - s.setName("hello") - s.setServiceParent(p) - s = service.Service() - s.setName("hello") - self.failUnlessRaises(RuntimeError, s.setServiceParent, p) - - def testDisowning(self): - s = service.Service() - p = service.MultiService() - s.setServiceParent(p) - self.assertEqual(list(p), [s]) - self.assertEqual(s.parent, p) - s.disownServiceParent() - self.assertEqual(list(p), []) - self.assertEqual(s.parent, None) - - def testRunning(self): - s = service.Service() - self.assert_(not s.running) - s.startService() - self.assert_(s.running) - s.stopService() - self.assert_(not s.running) - - def testRunningChildren1(self): - s = service.Service() - p = service.MultiService() - s.setServiceParent(p) - self.assert_(not s.running) - self.assert_(not p.running) - p.startService() - self.assert_(s.running) - self.assert_(p.running) - p.stopService() - self.assert_(not s.running) - self.assert_(not p.running) - - def testRunningChildren2(self): - s = service.Service() - def checkRunning(): - self.assert_(s.running) - t = service.Service() - t.stopService = checkRunning - t.startService = checkRunning - p = service.MultiService() - s.setServiceParent(p) - t.setServiceParent(p) - p.startService() - p.stopService() - - def testAddingIntoRunning(self): - p = service.MultiService() - p.startService() - s = service.Service() - self.assert_(not s.running) - s.setServiceParent(p) - self.assert_(s.running) - s.disownServiceParent() - self.assert_(not s.running) - - def testPrivileged(self): - s = service.Service() - def pss(): - s.privilegedStarted = 1 - s.privilegedStartService = pss - s1 = service.Service() - p = service.MultiService() - s.setServiceParent(p) - s1.setServiceParent(p) - p.privilegedStartService() - self.assert_(s.privilegedStarted) - - def testCopying(self): - s = service.Service() - s.startService() - s1 = copy.copy(s) - self.assert_(not s1.running) - self.assert_(s.running) - - -if hasattr(os, "getuid"): - curuid = os.getuid() - curgid = os.getgid() -else: - curuid = curgid = 0 - - -class ProcessTests(unittest.TestCase): - - def testID(self): - p = service.Process(5, 6) - self.assertEqual(p.uid, 5) - self.assertEqual(p.gid, 6) - - def testDefaults(self): - p = service.Process(5) - self.assertEqual(p.uid, 5) - self.assertEqual(p.gid, None) - p = service.Process(gid=5) - self.assertEqual(p.uid, None) - self.assertEqual(p.gid, 5) - p = service.Process() - self.assertEqual(p.uid, None) - self.assertEqual(p.gid, None) - - def testProcessName(self): - p = service.Process() - self.assertEqual(p.processName, None) - p.processName = 'hello' - self.assertEqual(p.processName, 'hello') - - -class InterfacesTests(unittest.TestCase): - - def testService(self): - self.assert_(service.IService.providedBy(service.Service())) - - def testMultiService(self): - self.assert_(service.IService.providedBy(service.MultiService())) - self.assert_(service.IServiceCollection.providedBy(service.MultiService())) - - def testProcess(self): - self.assert_(service.IProcess.providedBy(service.Process())) - - -class ApplicationTests(unittest.TestCase): - - def testConstructor(self): - service.Application("hello") - service.Application("hello", 5) - service.Application("hello", 5, 6) - - def testProcessComponent(self): - a = service.Application("hello") - self.assertEqual(service.IProcess(a).uid, None) - self.assertEqual(service.IProcess(a).gid, None) - a = service.Application("hello", 5) - self.assertEqual(service.IProcess(a).uid, 5) - self.assertEqual(service.IProcess(a).gid, None) - a = service.Application("hello", 5, 6) - self.assertEqual(service.IProcess(a).uid, 5) - self.assertEqual(service.IProcess(a).gid, 6) - - def testServiceComponent(self): - a = service.Application("hello") - self.assert_(service.IService(a) is service.IServiceCollection(a)) - self.assertEqual(service.IService(a).name, "hello") - self.assertEqual(service.IService(a).parent, None) - - def testPersistableComponent(self): - a = service.Application("hello") - p = sob.IPersistable(a) - self.assertEqual(p.style, 'pickle') - self.assertEqual(p.name, 'hello') - self.assert_(p.original is a) - -class LoadingTests(unittest.TestCase): - - def test_simpleStoreAndLoad(self): - a = service.Application("hello") - p = sob.IPersistable(a) - for style in 'source pickle'.split(): - p.setStyle(style) - p.save() - a1 = service.loadApplication("hello.ta"+style[0], style) - self.assertEqual(service.IService(a1).name, "hello") - f = open("hello.tac", 'w') - f.writelines([ - "from twisted.application import service\n", - "application = service.Application('hello')\n", - ]) - f.close() - a1 = service.loadApplication("hello.tac", 'python') - self.assertEqual(service.IService(a1).name, "hello") - - - -class AppSupportTests(unittest.TestCase): - - def testPassphrase(self): - self.assertEqual(app.getPassphrase(0), None) - - def testLoadApplication(self): - """ - Test loading an application file in different dump format. - """ - a = service.Application("hello") - baseconfig = {'file': None, 'source': None, 'python':None} - for style in 'source pickle'.split(): - config = baseconfig.copy() - config[{'pickle': 'file'}.get(style, style)] = 'helloapplication' - sob.IPersistable(a).setStyle(style) - sob.IPersistable(a).save(filename='helloapplication') - a1 = app.getApplication(config, None) - self.assertEqual(service.IService(a1).name, "hello") - config = baseconfig.copy() - config['python'] = 'helloapplication' - f = open("helloapplication", 'w') - f.writelines([ - "from twisted.application import service\n", - "application = service.Application('hello')\n", - ]) - f.close() - a1 = app.getApplication(config, None) - self.assertEqual(service.IService(a1).name, "hello") - - def test_convertStyle(self): - appl = service.Application("lala") - for instyle in 'source pickle'.split(): - for outstyle in 'source pickle'.split(): - sob.IPersistable(appl).setStyle(instyle) - sob.IPersistable(appl).save(filename="converttest") - app.convertStyle("converttest", instyle, None, - "converttest.out", outstyle, 0) - appl2 = service.loadApplication("converttest.out", outstyle) - self.assertEqual(service.IService(appl2).name, "lala") - - - def test_startApplication(self): - appl = service.Application("lala") - app.startApplication(appl, 0) - self.assert_(service.IService(appl).running) - - -class Foo(basic.LineReceiver): - def connectionMade(self): - self.transport.write('lalala\r\n') - def lineReceived(self, line): - self.factory.line = line - self.transport.loseConnection() - def connectionLost(self, reason): - self.factory.d.callback(self.factory.line) - - -class DummyApp: - processName = None - def addService(self, service): - self.services[service.name] = service - def removeService(self, service): - del self.services[service.name] - - -class TimerTarget: - def __init__(self): - self.l = [] - def append(self, what): - self.l.append(what) - -class TestEcho(wire.Echo): - def connectionLost(self, reason): - self.d.callback(True) - -class InternetTests(unittest.TestCase): - - def testTCP(self): - s = service.MultiService() - s.startService() - factory = protocol.ServerFactory() - factory.protocol = TestEcho - TestEcho.d = defer.Deferred() - t = internet.TCPServer(0, factory) - t.setServiceParent(s) - num = t._port.getHost().port - factory = protocol.ClientFactory() - factory.d = defer.Deferred() - factory.protocol = Foo - factory.line = None - internet.TCPClient('127.0.0.1', num, factory).setServiceParent(s) - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : s.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - return factory.d - - - def test_UDP(self): - """ - Test L{internet.UDPServer} with a random port: starting the service - should give it valid port, and stopService should free it so that we - can start a server on the same port again. - """ - if not interfaces.IReactorUDP(reactor, None): - raise unittest.SkipTest("This reactor does not support UDP sockets") - p = protocol.DatagramProtocol() - t = internet.UDPServer(0, p) - t.startService() - num = t._port.getHost().port - self.assertNotEquals(num, 0) - def onStop(ignored): - t = internet.UDPServer(num, p) - t.startService() - return t.stopService() - return defer.maybeDeferred(t.stopService).addCallback(onStop) - - - def testPrivileged(self): - factory = protocol.ServerFactory() - factory.protocol = TestEcho - TestEcho.d = defer.Deferred() - t = internet.TCPServer(0, factory) - t.privileged = 1 - t.privilegedStartService() - num = t._port.getHost().port - factory = protocol.ClientFactory() - factory.d = defer.Deferred() - factory.protocol = Foo - factory.line = None - c = internet.TCPClient('127.0.0.1', num, factory) - c.startService() - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : c.stopService()) - factory.d.addCallback(lambda x : t.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - return factory.d - - def testConnectionGettingRefused(self): - factory = protocol.ServerFactory() - factory.protocol = wire.Echo - t = internet.TCPServer(0, factory) - t.startService() - num = t._port.getHost().port - t.stopService() - d = defer.Deferred() - factory = protocol.ClientFactory() - factory.clientConnectionFailed = lambda *args: d.callback(None) - c = internet.TCPClient('127.0.0.1', num, factory) - c.startService() - return d - - def testUNIX(self): - # FIXME: This test is far too dense. It needs comments. - # -- spiv, 2004-11-07 - if not interfaces.IReactorUNIX(reactor, None): - raise unittest.SkipTest, "This reactor does not support UNIX domain sockets" - s = service.MultiService() - s.startService() - factory = protocol.ServerFactory() - factory.protocol = TestEcho - TestEcho.d = defer.Deferred() - t = internet.UNIXServer('echo.skt', factory) - t.setServiceParent(s) - factory = protocol.ClientFactory() - factory.protocol = Foo - factory.d = defer.Deferred() - factory.line = None - internet.UNIXClient('echo.skt', factory).setServiceParent(s) - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : s.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - factory.d.addCallback(self._cbTestUnix, factory, s) - return factory.d - - def _cbTestUnix(self, ignored, factory, s): - TestEcho.d = defer.Deferred() - factory.line = None - factory.d = defer.Deferred() - s.startService() - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : s.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - return factory.d - - def testVolatile(self): - if not interfaces.IReactorUNIX(reactor, None): - raise unittest.SkipTest, "This reactor does not support UNIX domain sockets" - factory = protocol.ServerFactory() - factory.protocol = wire.Echo - t = internet.UNIXServer('echo.skt', factory) - t.startService() - self.failIfIdentical(t._port, None) - t1 = copy.copy(t) - self.assertIdentical(t1._port, None) - t.stopService() - self.assertIdentical(t._port, None) - self.failIf(t.running) - - factory = protocol.ClientFactory() - factory.protocol = wire.Echo - t = internet.UNIXClient('echo.skt', factory) - t.startService() - self.failIfIdentical(t._connection, None) - t1 = copy.copy(t) - self.assertIdentical(t1._connection, None) - t.stopService() - self.assertIdentical(t._connection, None) - self.failIf(t.running) - - def testStoppingServer(self): - if not interfaces.IReactorUNIX(reactor, None): - raise unittest.SkipTest, "This reactor does not support UNIX domain sockets" - factory = protocol.ServerFactory() - factory.protocol = wire.Echo - t = internet.UNIXServer('echo.skt', factory) - t.startService() - t.stopService() - self.failIf(t.running) - factory = protocol.ClientFactory() - d = defer.Deferred() - factory.clientConnectionFailed = lambda *args: d.callback(None) - reactor.connectUNIX('echo.skt', factory) - return d - - def testPickledTimer(self): - target = TimerTarget() - t0 = internet.TimerService(1, target.append, "hello") - t0.startService() - s = pickle.dumps(t0) - t0.stopService() - - t = pickle.loads(s) - self.failIf(t.running) - - def testBrokenTimer(self): - d = defer.Deferred() - t = internet.TimerService(1, lambda: 1 // 0) - oldFailed = t._failed - def _failed(why): - oldFailed(why) - d.callback(None) - t._failed = _failed - t.startService() - d.addCallback(lambda x : t.stopService) - d.addCallback(lambda x : self.assertEqual( - [ZeroDivisionError], - [o.value.__class__ for o in self.flushLoggedErrors(ZeroDivisionError)])) - return d - - - def test_everythingThere(self): - """ - L{twisted.application.internet} dynamically defines a set of - L{service.Service} subclasses that in general have corresponding - reactor.listenXXX or reactor.connectXXX calls. - """ - trans = 'TCP UNIX SSL UDP UNIXDatagram Multicast'.split() - for tran in trans[:]: - if not getattr(interfaces, "IReactor" + tran)(reactor, None): - trans.remove(tran) - for tran in trans: - for side in 'Server Client'.split(): - if tran == "Multicast" and side == "Client": - continue - if tran == "UDP" and side == "Client": - continue - self.assertTrue(hasattr(internet, tran + side)) - method = getattr(internet, tran + side).method - prefix = {'Server': 'listen', 'Client': 'connect'}[side] - self.assertTrue(hasattr(reactor, prefix + method) or - (prefix == "connect" and method == "UDP")) - o = getattr(internet, tran + side)() - self.assertEqual(service.IService(o), o) - - - def test_importAll(self): - """ - L{twisted.application.internet} dynamically defines L{service.Service} - subclasses. This test ensures that the subclasses exposed by C{__all__} - are valid attributes of the module. - """ - for cls in internet.__all__: - self.assertTrue( - hasattr(internet, cls), - '%s not importable from twisted.application.internet' % (cls,)) - - - def test_reactorParametrizationInServer(self): - """ - L{internet._AbstractServer} supports a C{reactor} keyword argument - that can be used to parametrize the reactor used to listen for - connections. - """ - reactor = MemoryReactor() - - factory = object() - t = internet.TCPServer(1234, factory, reactor=reactor) - t.startService() - self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory)) - - - def test_reactorParametrizationInClient(self): - """ - L{internet._AbstractClient} supports a C{reactor} keyword arguments - that can be used to parametrize the reactor used to create new client - connections. - """ - reactor = MemoryReactor() - - factory = protocol.ClientFactory() - t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) - t.startService() - self.assertEqual( - reactor.tcpClients.pop()[:3], ('127.0.0.1', 1234, factory)) - - - def test_reactorParametrizationInServerMultipleStart(self): - """ - Like L{test_reactorParametrizationInServer}, but stop and restart the - service and check that the given reactor is still used. - """ - reactor = MemoryReactor() - - factory = protocol.Factory() - t = internet.TCPServer(1234, factory, reactor=reactor) - t.startService() - self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory)) - t.stopService() - t.startService() - self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory)) - - - def test_reactorParametrizationInClientMultipleStart(self): - """ - Like L{test_reactorParametrizationInClient}, but stop and restart the - service and check that the given reactor is still used. - """ - reactor = MemoryReactor() - - factory = protocol.ClientFactory() - t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) - t.startService() - self.assertEqual( - reactor.tcpClients.pop()[:3], ('127.0.0.1', 1234, factory)) - t.stopService() - t.startService() - self.assertEqual( - reactor.tcpClients.pop()[:3], ('127.0.0.1', 1234, factory)) - - - -class TimerBasicTests(unittest.TestCase): - - def testTimerRuns(self): - d = defer.Deferred() - self.t = internet.TimerService(1, d.callback, 'hello') - self.t.startService() - d.addCallback(self.assertEqual, 'hello') - d.addCallback(lambda x : self.t.stopService()) - d.addCallback(lambda x : self.failIf(self.t.running)) - return d - - def tearDown(self): - return self.t.stopService() - - def testTimerRestart(self): - # restart the same TimerService - d1 = defer.Deferred() - d2 = defer.Deferred() - work = [(d2, "bar"), (d1, "foo")] - def trigger(): - d, arg = work.pop() - d.callback(arg) - self.t = internet.TimerService(1, trigger) - self.t.startService() - def onFirstResult(result): - self.assertEqual(result, 'foo') - return self.t.stopService() - def onFirstStop(ignored): - self.failIf(self.t.running) - self.t.startService() - return d2 - def onSecondResult(result): - self.assertEqual(result, 'bar') - self.t.stopService() - d1.addCallback(onFirstResult) - d1.addCallback(onFirstStop) - d1.addCallback(onSecondResult) - return d1 - - def testTimerLoops(self): - l = [] - def trigger(data, number, d): - l.append(data) - if len(l) == number: - d.callback(l) - d = defer.Deferred() - self.t = internet.TimerService(0.01, trigger, "hello", 10, d) - self.t.startService() - d.addCallback(self.assertEqual, ['hello'] * 10) - d.addCallback(lambda x : self.t.stopService()) - return d - - -class FakeReactor(reactors.Reactor): - """ - A fake reactor with a hooked install method. - """ - - def __init__(self, install, *args, **kwargs): - """ - @param install: any callable that will be used as install method. - @type install: C{callable} - """ - reactors.Reactor.__init__(self, *args, **kwargs) - self.install = install - - - -class PluggableReactorTests(TwistedModulesMixin, unittest.TestCase): - """ - Tests for the reactor discovery/inspection APIs. - """ - - def setUp(self): - """ - Override the L{reactors.getPlugins} function, normally bound to - L{twisted.plugin.getPlugins}, in order to control which - L{IReactorInstaller} plugins are seen as available. - - C{self.pluginResults} can be customized and will be used as the - result of calls to C{reactors.getPlugins}. - """ - self.pluginCalls = [] - self.pluginResults = [] - self.originalFunction = reactors.getPlugins - reactors.getPlugins = self._getPlugins - - - def tearDown(self): - """ - Restore the original L{reactors.getPlugins}. - """ - reactors.getPlugins = self.originalFunction - - - def _getPlugins(self, interface, package=None): - """ - Stand-in for the real getPlugins method which records its arguments - and returns a fixed result. - """ - self.pluginCalls.append((interface, package)) - return list(self.pluginResults) - - - def test_getPluginReactorTypes(self): - """ - Test that reactor plugins are returned from L{getReactorTypes} - """ - name = 'fakereactortest' - package = __name__ + '.fakereactor' - description = 'description' - self.pluginResults = [reactors.Reactor(name, package, description)] - reactorTypes = reactors.getReactorTypes() - - self.assertEqual( - self.pluginCalls, - [(reactors.IReactorInstaller, None)]) - - for r in reactorTypes: - if r.shortName == name: - self.assertEqual(r.description, description) - break - else: - self.fail("Reactor plugin not present in getReactorTypes() result") - - - def test_reactorInstallation(self): - """ - Test that L{reactors.Reactor.install} loads the correct module and - calls its install attribute. - """ - installed = [] - def install(): - installed.append(True) - fakeReactor = FakeReactor(install, - 'fakereactortest', __name__, 'described') - modules = {'fakereactortest': fakeReactor} - self.replaceSysModules(modules) - installer = reactors.Reactor('fakereactor', 'fakereactortest', 'described') - installer.install() - self.assertEqual(installed, [True]) - - - def test_installReactor(self): - """ - Test that the L{reactors.installReactor} function correctly installs - the specified reactor. - """ - installed = [] - def install(): - installed.append(True) - name = 'fakereactortest' - package = __name__ - description = 'description' - self.pluginResults = [FakeReactor(install, name, package, description)] - reactors.installReactor(name) - self.assertEqual(installed, [True]) - - - def test_installReactorReturnsReactor(self): - """ - Test that the L{reactors.installReactor} function correctly returns - the installed reactor. - """ - reactor = object() - def install(): - from twisted import internet - self.patch(internet, 'reactor', reactor) - name = 'fakereactortest' - package = __name__ - description = 'description' - self.pluginResults = [FakeReactor(install, name, package, description)] - installed = reactors.installReactor(name) - self.assertIdentical(installed, reactor) - - - def test_installReactorMultiplePlugins(self): - """ - Test that the L{reactors.installReactor} function correctly installs - the specified reactor when there are multiple reactor plugins. - """ - installed = [] - def install(): - installed.append(True) - name = 'fakereactortest' - package = __name__ - description = 'description' - fakeReactor = FakeReactor(install, name, package, description) - otherReactor = FakeReactor(lambda: None, - "otherreactor", package, description) - self.pluginResults = [otherReactor, fakeReactor] - reactors.installReactor(name) - self.assertEqual(installed, [True]) - - - def test_installNonExistentReactor(self): - """ - Test that L{reactors.installReactor} raises L{reactors.NoSuchReactor} - when asked to install a reactor which it cannot find. - """ - self.pluginResults = [] - self.assertRaises( - reactors.NoSuchReactor, - reactors.installReactor, 'somereactor') - - - def test_installNotAvailableReactor(self): - """ - Test that L{reactors.installReactor} raises an exception when asked to - install a reactor which doesn't work in this environment. - """ - def install(): - raise ImportError("Missing foo bar") - name = 'fakereactortest' - package = __name__ - description = 'description' - self.pluginResults = [FakeReactor(install, name, package, description)] - self.assertRaises(ImportError, reactors.installReactor, name) - - - def test_reactorSelectionMixin(self): - """ - Test that the reactor selected is installed as soon as possible, ie - when the option is parsed. - """ - executed = [] - INSTALL_EVENT = 'reactor installed' - SUBCOMMAND_EVENT = 'subcommands loaded' - - class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin): - def subCommands(self): - executed.append(SUBCOMMAND_EVENT) - return [('subcommand', None, lambda: self, 'test subcommand')] - subCommands = property(subCommands) - - def install(): - executed.append(INSTALL_EVENT) - self.pluginResults = [ - FakeReactor(install, 'fakereactortest', __name__, 'described') - ] - - options = ReactorSelectionOptions() - options.parseOptions(['--reactor', 'fakereactortest', 'subcommand']) - self.assertEqual(executed[0], INSTALL_EVENT) - self.assertEqual(executed.count(INSTALL_EVENT), 1) - self.assertEqual(options["reactor"], "fakereactortest") - - - def test_reactorSelectionMixinNonExistent(self): - """ - Test that the usage mixin exits when trying to use a non existent - reactor (the name not matching to any reactor), giving an error - message. - """ - class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin): - pass - self.pluginResults = [] - - options = ReactorSelectionOptions() - options.messageOutput = StringIO() - e = self.assertRaises(usage.UsageError, options.parseOptions, - ['--reactor', 'fakereactortest', 'subcommand']) - self.assertIn("fakereactortest", e.args[0]) - self.assertIn("help-reactors", e.args[0]) - - - def test_reactorSelectionMixinNotAvailable(self): - """ - Test that the usage mixin exits when trying to use a reactor not - available (the reactor raises an error at installation), giving an - error message. - """ - class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin): - pass - message = "Missing foo bar" - def install(): - raise ImportError(message) - - name = 'fakereactortest' - package = __name__ - description = 'description' - self.pluginResults = [FakeReactor(install, name, package, description)] - - options = ReactorSelectionOptions() - options.messageOutput = StringIO() - e = self.assertRaises(usage.UsageError, options.parseOptions, - ['--reactor', 'fakereactortest', 'subcommand']) - self.assertIn(message, e.args[0]) - self.assertIn("help-reactors", e.args[0]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_banana.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_banana.py deleted file mode 100644 index 2274bfc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_banana.py +++ /dev/null @@ -1,444 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -import StringIO -import sys -from functools import partial - -# Twisted Imports -from twisted.trial import unittest -from twisted.spread import banana -from twisted.python import failure -from twisted.internet import protocol, main -from twisted.test.proto_helpers import StringTransport - - -class MathTests(unittest.TestCase): - def test_int2b128(self): - funkylist = range(0,100) + range(1000,1100) + range(1000000,1000100) + [1024 **10l] - for i in funkylist: - x = StringIO.StringIO() - banana.int2b128(i, x.write) - v = x.getvalue() - y = banana.b1282int(v) - assert y == i, "y = %s; i = %s" % (y,i) - - - -def selectDialect(protocol, dialect): - """ - Dictate a Banana dialect to use. - - @param protocol: A L{banana.Banana} instance which has not yet had a - dialect negotiated. - - @param dialect: A L{bytes} instance naming a Banana dialect to select. - """ - # We can't do this the normal way by delivering bytes because other setup - # stuff gets in the way (for example, clients and servers have incompatible - # negotiations for this step). So use the private API to make this happen. - protocol._selectDialect(dialect) - - - -def encode(bananaFactory, obj): - """ - Banana encode an object using L{banana.Banana.sendEncoded}. - - @param bananaFactory: A no-argument callable which will return a new, - unconnected protocol instance to use to do the encoding (this should - most likely be a L{banana.Banana} instance). - - @param obj: The object to encode. - @type obj: Any type supported by Banana. - - @return: A L{bytes} instance giving the encoded form of C{obj}. - """ - transport = StringTransport() - banana = bananaFactory() - banana.makeConnection(transport) - transport.clear() - - banana.sendEncoded(obj) - return transport.value() - - - -class BananaTestBase(unittest.TestCase): - """ - The base for test classes. It defines commonly used things and sets up a - connection for testing. - """ - encClass = banana.Banana - - def setUp(self): - self.io = StringIO.StringIO() - self.enc = self.encClass() - self.enc.makeConnection(protocol.FileWrapper(self.io)) - selectDialect(self.enc, b"none") - self.enc.expressionReceived = self.putResult - self.encode = partial(encode, self.encClass) - - - def putResult(self, result): - """ - Store an expression received by C{self.enc}. - - @param result: The object that was received. - @type result: Any type supported by Banana. - """ - self.result = result - - - def tearDown(self): - self.enc.connectionLost(failure.Failure(main.CONNECTION_DONE)) - del self.enc - - - -class BananaTests(BananaTestBase): - """ - General banana tests. - """ - - def test_string(self): - self.enc.sendEncoded("hello") - self.enc.dataReceived(self.io.getvalue()) - assert self.result == 'hello' - - - def test_unsupportedUnicode(self): - """ - Banana does not support unicode. ``Banana.sendEncoded`` raises - ``BananaError`` if called with an instance of ``unicode``. - """ - self._unsupportedTypeTest(u"hello", "__builtin__.unicode") - - - def test_unsupportedBuiltinType(self): - """ - Banana does not support arbitrary builtin types like L{type}. - L{banana.Banana.sendEncoded} raises L{banana.BananaError} if called - with an instance of L{type}. - """ - # type is an instance of type - self._unsupportedTypeTest(type, "__builtin__.type") - - - def test_unsupportedUserType(self): - """ - Banana does not support arbitrary user-defined types (such as those - defined with the ``class`` statement). ``Banana.sendEncoded`` raises - ``BananaError`` if called with an instance of such a type. - """ - self._unsupportedTypeTest(MathTests(), __name__ + ".MathTests") - - - def _unsupportedTypeTest(self, obj, name): - """ - Assert that L{banana.Banana.sendEncoded} raises L{banana.BananaError} - if called with the given object. - - @param obj: Some object that Banana does not support. - @param name: The name of the type of the object. - - @raise: The failure exception is raised if L{Banana.sendEncoded} does - not raise L{banana.BananaError} or if the message associated with the - exception is not formatted to include the type of the unsupported - object. - """ - exc = self.assertRaises(banana.BananaError, self.enc.sendEncoded, obj) - self.assertIn("Banana cannot send {0} objects".format(name), str(exc)) - - - def test_int(self): - """ - A positive integer less than 2 ** 32 should round-trip through - banana without changing value and should come out represented - as an C{int} (regardless of the type which was encoded). - """ - for value in (10151, 10151L): - self.enc.sendEncoded(value) - self.enc.dataReceived(self.io.getvalue()) - self.assertEqual(self.result, 10151) - self.assertIsInstance(self.result, int) - - - def test_largeLong(self): - """ - Integers greater than 2 ** 32 and less than -2 ** 32 should - round-trip through banana without changing value and should - come out represented as C{int} instances if the value fits - into that type on the receiving platform. - """ - for exp in (32, 64, 128, 256): - for add in (0, 1): - m = 2 ** exp + add - for n in (m, -m-1): - self.enc.dataReceived(self.encode(n)) - self.assertEqual(self.result, n) - if n > sys.maxint or n < -sys.maxint - 1: - self.assertIsInstance(self.result, long) - else: - self.assertIsInstance(self.result, int) - - - def _getSmallest(self): - # How many bytes of prefix our implementation allows - bytes = self.enc.prefixLimit - # How many useful bits we can extract from that based on Banana's - # base-128 representation. - bits = bytes * 7 - # The largest number we _should_ be able to encode - largest = 2 ** bits - 1 - # The smallest number we _shouldn't_ be able to encode - smallest = largest + 1 - return smallest - - - def test_encodeTooLargeLong(self): - """ - Test that a long above the implementation-specific limit is rejected - as too large to be encoded. - """ - smallest = self._getSmallest() - self.assertRaises(banana.BananaError, self.enc.sendEncoded, smallest) - - - def test_decodeTooLargeLong(self): - """ - Test that a long above the implementation specific limit is rejected - as too large to be decoded. - """ - smallest = self._getSmallest() - self.enc.setPrefixLimit(self.enc.prefixLimit * 2) - self.enc.sendEncoded(smallest) - encoded = self.io.getvalue() - self.io.truncate(0) - self.enc.setPrefixLimit(self.enc.prefixLimit // 2) - - self.assertRaises(banana.BananaError, self.enc.dataReceived, encoded) - - - def _getLargest(self): - return -self._getSmallest() - - - def test_encodeTooSmallLong(self): - """ - Test that a negative long below the implementation-specific limit is - rejected as too small to be encoded. - """ - largest = self._getLargest() - self.assertRaises(banana.BananaError, self.enc.sendEncoded, largest) - - - def test_decodeTooSmallLong(self): - """ - Test that a negative long below the implementation specific limit is - rejected as too small to be decoded. - """ - largest = self._getLargest() - self.enc.setPrefixLimit(self.enc.prefixLimit * 2) - self.enc.sendEncoded(largest) - encoded = self.io.getvalue() - self.io.truncate(0) - self.enc.setPrefixLimit(self.enc.prefixLimit // 2) - - self.assertRaises(banana.BananaError, self.enc.dataReceived, encoded) - - - def test_negativeLong(self): - self.enc.sendEncoded(-1015l) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == -1015l, "should be -1015l, got %s" % self.result - - - def test_integer(self): - self.enc.sendEncoded(1015) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == 1015, "should be 1015, got %s" % self.result - - - def test_negative(self): - self.enc.sendEncoded(-1015) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == -1015, "should be -1015, got %s" % self.result - - - def test_float(self): - self.enc.sendEncoded(1015.) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == 1015. - - - def test_list(self): - foo = [1, 2, [3, 4], [30.5, 40.2], 5, ["six", "seven", ["eight", 9]], [10], []] - self.enc.sendEncoded(foo) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == foo, "%s!=%s" % (repr(self.result), repr(foo)) - - - def test_partial(self): - """ - Test feeding the data byte per byte to the receiver. Normally - data is not split. - """ - foo = [1, 2, [3, 4], [30.5, 40.2], 5, - ["six", "seven", ["eight", 9]], [10], - # TODO: currently the C implementation's a bit buggy... - sys.maxint * 3l, sys.maxint * 2l, sys.maxint * -2l] - self.enc.sendEncoded(foo) - self.feed(self.io.getvalue()) - assert self.result == foo, "%s!=%s" % (repr(self.result), repr(foo)) - - - def feed(self, data): - """ - Feed the data byte per byte to the receiver. - - @param data: The bytes to deliver. - @type data: L{bytes} - """ - for byte in data: - self.enc.dataReceived(byte) - - - def test_oversizedList(self): - data = '\x02\x01\x01\x01\x01\x80' - # list(size=0x0101010102, about 4.3e9) - self.failUnlessRaises(banana.BananaError, self.feed, data) - - - def test_oversizedString(self): - data = '\x02\x01\x01\x01\x01\x82' - # string(size=0x0101010102, about 4.3e9) - self.failUnlessRaises(banana.BananaError, self.feed, data) - - - def test_crashString(self): - crashString = '\x00\x00\x00\x00\x04\x80' - # string(size=0x0400000000, about 17.2e9) - - # cBanana would fold that into a 32-bit 'int', then try to allocate - # a list with PyList_New(). cBanana ignored the NULL return value, - # so it would segfault when trying to free the imaginary list. - - # This variant doesn't segfault straight out in my environment. - # Instead, it takes up large amounts of CPU and memory... - #crashString = '\x00\x00\x00\x00\x01\x80' - # print repr(crashString) - #self.failUnlessRaises(Exception, self.enc.dataReceived, crashString) - try: - # should now raise MemoryError - self.enc.dataReceived(crashString) - except banana.BananaError: - pass - - def test_crashNegativeLong(self): - # There was a bug in cBanana which relied on negating a negative integer - # always giving a positive result, but for the lowest possible number in - # 2s-complement arithmetic, that's not true, i.e. - # long x = -2147483648; - # long y = -x; - # x == y; /* true! */ - # (assuming 32-bit longs) - self.enc.sendEncoded(-2147483648) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == -2147483648, "should be -2147483648, got %s" % self.result - - - def test_sizedIntegerTypes(self): - """ - Test that integers below the maximum C{INT} token size cutoff are - serialized as C{INT} or C{NEG} and that larger integers are - serialized as C{LONGINT} or C{LONGNEG}. - """ - baseIntIn = +2147483647 - baseNegIn = -2147483648 - - baseIntOut = '\x7f\x7f\x7f\x07\x81' - self.assertEqual(self.encode(baseIntIn - 2), '\x7d' + baseIntOut) - self.assertEqual(self.encode(baseIntIn - 1), '\x7e' + baseIntOut) - self.assertEqual(self.encode(baseIntIn - 0), '\x7f' + baseIntOut) - - baseLongIntOut = '\x00\x00\x00\x08\x85' - self.assertEqual(self.encode(baseIntIn + 1), '\x00' + baseLongIntOut) - self.assertEqual(self.encode(baseIntIn + 2), '\x01' + baseLongIntOut) - self.assertEqual(self.encode(baseIntIn + 3), '\x02' + baseLongIntOut) - - baseNegOut = '\x7f\x7f\x7f\x07\x83' - self.assertEqual(self.encode(baseNegIn + 2), '\x7e' + baseNegOut) - self.assertEqual(self.encode(baseNegIn + 1), '\x7f' + baseNegOut) - self.assertEqual(self.encode(baseNegIn + 0), '\x00\x00\x00\x00\x08\x83') - - baseLongNegOut = '\x00\x00\x00\x08\x86' - self.assertEqual(self.encode(baseNegIn - 1), '\x01' + baseLongNegOut) - self.assertEqual(self.encode(baseNegIn - 2), '\x02' + baseLongNegOut) - self.assertEqual(self.encode(baseNegIn - 3), '\x03' + baseLongNegOut) - - - -class DialectTests(BananaTestBase): - """ - Tests for Banana's handling of dialects. - """ - vocab = b'remote' - legalPbItem = chr(banana.Banana.outgoingVocabulary[vocab]) + banana.VOCAB - illegalPbItem = chr(122) + banana.VOCAB - - def test_dialectNotSet(self): - """ - If no dialect has been selected and a PB VOCAB item is received, - L{NotImplementedError} is raised. - """ - self.assertRaises( - NotImplementedError, - self.enc.dataReceived, self.legalPbItem) - - - def test_receivePb(self): - """ - If the PB dialect has been selected, a PB VOCAB item is accepted. - """ - selectDialect(self.enc, b'pb') - self.enc.dataReceived(self.legalPbItem) - self.assertEqual(self.result, self.vocab) - - - def test_receiveIllegalPb(self): - """ - If the PB dialect has been selected and an unrecognized PB VOCAB item - is received, L{banana.Banana.dataReceived} raises L{KeyError}. - """ - selectDialect(self.enc, b'pb') - self.assertRaises(KeyError, self.enc.dataReceived, self.illegalPbItem) - - - def test_sendPb(self): - """ - if pb dialect is selected, the sender must be able to send things in - that dialect. - """ - selectDialect(self.enc, b'pb') - self.enc.sendEncoded(self.vocab) - self.assertEqual(self.legalPbItem, self.io.getvalue()) - - - -class GlobalCoderTests(unittest.TestCase): - """ - Tests for the free functions L{banana.encode} and L{banana.decode}. - """ - def test_statelessDecode(self): - """ - Calls to L{banana.decode} are independent of each other. - """ - # Banana encoding of 2 ** 449 - undecodable = b'\x7f' * 65 + b'\x85' - self.assertRaises(banana.BananaError, banana.decode, undecodable) - - # Banana encoding of 1. This should be decodable even though the - # previous call passed un-decodable data and triggered an exception. - decodable = b'\x01\x81' - self.assertEqual(banana.decode(decodable), 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_compat.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_compat.py deleted file mode 100644 index 02135fa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_compat.py +++ /dev/null @@ -1,732 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Tests for L{twisted.python.compat}. -""" - -from __future__ import division, absolute_import - -import socket, sys, traceback, io, codecs - -from twisted.trial import unittest - -from twisted.python.compat import ( - reduce, execfile, _PY3, comparable, cmp, nativeString, networkString, - unicode as unicodeCompat, lazyByteSlice, reraise, NativeStringIO, - iterbytes, intToBytes, ioType -) -from twisted.python.filepath import FilePath - - - -class IOTypeTests(unittest.SynchronousTestCase): - """ - Test cases for determining a file-like object's type. - """ - - def test_3StringIO(self): - """ - An L{io.StringIO} accepts and returns text. - """ - self.assertEquals(ioType(io.StringIO()), unicodeCompat) - - - def test_3BytesIO(self): - """ - An L{io.BytesIO} accepts and returns bytes. - """ - self.assertEquals(ioType(io.BytesIO()), bytes) - - - def test_3openTextMode(self): - """ - A file opened via 'io.open' in text mode accepts and returns text. - """ - self.assertEquals(ioType(io.open(self.mktemp(), "w")), unicodeCompat) - - - def test_3openBinaryMode(self): - """ - A file opened via 'io.open' in binary mode accepts and returns bytes. - """ - self.assertEquals(ioType(io.open(self.mktemp(), "wb")), bytes) - - - def test_2openTextMode(self): - """ - The special built-in console file in Python 2 which has an 'encoding' - attribute should qualify as a special type, since it accepts both bytes - and text faithfully. - """ - class VerySpecificLie(file): - """ - In their infinite wisdom, the CPython developers saw fit not to - allow us a writable 'encoding' attribute on the built-in 'file' - type in Python 2, despite making it writable in C with - PyFile_SetEncoding. - - Pretend they did not do that. - """ - encoding = 'utf-8' - - self.assertEquals(ioType(VerySpecificLie(self.mktemp(), "wb")), - basestring) - - - def test_2StringIO(self): - """ - Python 2's L{StringIO} and L{cStringIO} modules are both binary I/O. - """ - from cStringIO import StringIO as cStringIO - from StringIO import StringIO - self.assertEquals(ioType(StringIO()), bytes) - self.assertEquals(ioType(cStringIO()), bytes) - - - def test_2openBinaryMode(self): - """ - The normal 'open' builtin in Python 2 will always result in bytes I/O. - """ - self.assertEquals(ioType(open(self.mktemp(), "w")), bytes) - - if _PY3: - test_2openTextMode.skip = "The 'file' type is no longer available." - test_2openBinaryMode.skip = "'io.open' is now the same as 'open'." - test_2StringIO.skip = ("The 'StringIO' and 'cStringIO' modules were " - "subsumed by the 'io' module.") - - - def test_codecsOpenBytes(self): - """ - The L{codecs} module, oddly, returns a file-like object which returns - bytes when not passed an 'encoding' argument. - """ - self.assertEquals(ioType(codecs.open(self.mktemp(), 'wb')), - bytes) - - - def test_codecsOpenText(self): - """ - When passed an encoding, however, the L{codecs} module returns unicode. - """ - self.assertEquals(ioType(codecs.open(self.mktemp(), 'wb', - encoding='utf-8')), - unicodeCompat) - - - def test_defaultToText(self): - """ - When passed an object about which no sensible decision can be made, err - on the side of unicode. - """ - self.assertEquals(ioType(object()), unicodeCompat) - - - -class CompatTests(unittest.SynchronousTestCase): - """ - Various utility functions in C{twisted.python.compat} provide same - functionality as modern Python variants. - """ - - def test_set(self): - """ - L{set} should behave like the expected set interface. - """ - a = set() - a.add('b') - a.add('c') - a.add('a') - b = list(a) - b.sort() - self.assertEqual(b, ['a', 'b', 'c']) - a.remove('b') - b = list(a) - b.sort() - self.assertEqual(b, ['a', 'c']) - - a.discard('d') - - b = set(['r', 's']) - d = a.union(b) - b = list(d) - b.sort() - self.assertEqual(b, ['a', 'c', 'r', 's']) - - - def test_frozenset(self): - """ - L{frozenset} should behave like the expected frozenset interface. - """ - a = frozenset(['a', 'b']) - self.assertRaises(AttributeError, getattr, a, "add") - self.assertEqual(sorted(a), ['a', 'b']) - - b = frozenset(['r', 's']) - d = a.union(b) - b = list(d) - b.sort() - self.assertEqual(b, ['a', 'b', 'r', 's']) - - - def test_reduce(self): - """ - L{reduce} should behave like the builtin reduce. - """ - self.assertEqual(15, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])) - self.assertEqual(16, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 1)) - - - -class IPv6Tests(unittest.SynchronousTestCase): - """ - C{inet_pton} and C{inet_ntop} implementations support IPv6. - """ - - def testNToP(self): - from twisted.python.compat import inet_ntop - - f = lambda a: inet_ntop(socket.AF_INET6, a) - g = lambda a: inet_ntop(socket.AF_INET, a) - - self.assertEqual('::', f('\x00' * 16)) - self.assertEqual('::1', f('\x00' * 15 + '\x01')) - self.assertEqual( - 'aef:b01:506:1001:ffff:9997:55:170', - f('\x0a\xef\x0b\x01\x05\x06\x10\x01\xff\xff\x99\x97\x00\x55\x01' - '\x70')) - - self.assertEqual('1.0.1.0', g('\x01\x00\x01\x00')) - self.assertEqual('170.85.170.85', g('\xaa\x55\xaa\x55')) - self.assertEqual('255.255.255.255', g('\xff\xff\xff\xff')) - - self.assertEqual('100::', f('\x01' + '\x00' * 15)) - self.assertEqual('100::1', f('\x01' + '\x00' * 14 + '\x01')) - - - def testPToN(self): - from twisted.python.compat import inet_pton - - f = lambda a: inet_pton(socket.AF_INET6, a) - g = lambda a: inet_pton(socket.AF_INET, a) - - self.assertEqual('\x00\x00\x00\x00', g('0.0.0.0')) - self.assertEqual('\xff\x00\xff\x00', g('255.0.255.0')) - self.assertEqual('\xaa\xaa\xaa\xaa', g('170.170.170.170')) - - self.assertEqual('\x00' * 16, f('::')) - self.assertEqual('\x00' * 16, f('0::0')) - self.assertEqual('\x00\x01' + '\x00' * 14, f('1::')) - self.assertEqual( - '\x45\xef\x76\xcb\x00\x1a\x56\xef\xaf\xeb\x0b\xac\x19\x24\xae\xae', - f('45ef:76cb:1a:56ef:afeb:bac:1924:aeae')) - - self.assertEqual('\x00' * 14 + '\x00\x01', f('::1')) - self.assertEqual('\x00' * 12 + '\x01\x02\x03\x04', f('::1.2.3.4')) - self.assertEqual( - '\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x01\x02\x03\xff', - f('1:2:3:4:5:6:1.2.3.255')) - - for badaddr in ['1:2:3:4:5:6:7:8:', ':1:2:3:4:5:6:7:8', '1::2::3', - '1:::3', ':::', '1:2', '::1.2', '1.2.3.4::', - 'abcd:1.2.3.4:abcd:abcd:abcd:abcd:abcd', - '1234:1.2.3.4:1234:1234:1234:1234:1234:1234', - '1.2.3.4']: - self.assertRaises(ValueError, f, badaddr) - -if _PY3: - IPv6Tests.skip = "These tests are only relevant to old versions of Python" - - - -class ExecfileCompatTests(unittest.SynchronousTestCase): - """ - Tests for the Python 3-friendly L{execfile} implementation. - """ - - def writeScript(self, content): - """ - Write L{content} to a new temporary file, returning the L{FilePath} - for the new file. - """ - path = self.mktemp() - with open(path, "wb") as f: - f.write(content.encode("ascii")) - return FilePath(path.encode("utf-8")) - - - def test_execfileGlobals(self): - """ - L{execfile} executes the specified file in the given global namespace. - """ - script = self.writeScript(u"foo += 1\n") - globalNamespace = {"foo": 1} - execfile(script.path, globalNamespace) - self.assertEqual(2, globalNamespace["foo"]) - - - def test_execfileGlobalsAndLocals(self): - """ - L{execfile} executes the specified file in the given global and local - namespaces. - """ - script = self.writeScript(u"foo += 1\n") - globalNamespace = {"foo": 10} - localNamespace = {"foo": 20} - execfile(script.path, globalNamespace, localNamespace) - self.assertEqual(10, globalNamespace["foo"]) - self.assertEqual(21, localNamespace["foo"]) - - - def test_execfileUniversalNewlines(self): - """ - L{execfile} reads in the specified file using universal newlines so - that scripts written on one platform will work on another. - """ - for lineEnding in u"\n", u"\r", u"\r\n": - script = self.writeScript(u"foo = 'okay'" + lineEnding) - globalNamespace = {"foo": None} - execfile(script.path, globalNamespace) - self.assertEqual("okay", globalNamespace["foo"]) - - - -class PY3Tests(unittest.SynchronousTestCase): - """ - Identification of Python 2 vs. Python 3. - """ - - def test_python2(self): - """ - On Python 2, C{_PY3} is False. - """ - if sys.version.startswith("2."): - self.assertFalse(_PY3) - - - def test_python3(self): - """ - On Python 3, C{_PY3} is True. - """ - if sys.version.startswith("3."): - self.assertTrue(_PY3) - - - -@comparable -class Comparable(object): - """ - Objects that can be compared to each other, but not others. - """ - def __init__(self, value): - self.value = value - - - def __cmp__(self, other): - if not isinstance(other, Comparable): - return NotImplemented - return cmp(self.value, other.value) - - - -class ComparableTests(unittest.SynchronousTestCase): - """ - L{comparable} decorated classes emulate Python 2's C{__cmp__} semantics. - """ - - def test_equality(self): - """ - Instances of a class that is decorated by C{comparable} support - equality comparisons. - """ - # Make explicitly sure we're using ==: - self.assertTrue(Comparable(1) == Comparable(1)) - self.assertFalse(Comparable(2) == Comparable(1)) - - - def test_nonEquality(self): - """ - Instances of a class that is decorated by C{comparable} support - inequality comparisons. - """ - # Make explicitly sure we're using !=: - self.assertFalse(Comparable(1) != Comparable(1)) - self.assertTrue(Comparable(2) != Comparable(1)) - - - def test_greaterThan(self): - """ - Instances of a class that is decorated by C{comparable} support - greater-than comparisons. - """ - self.assertTrue(Comparable(2) > Comparable(1)) - self.assertFalse(Comparable(0) > Comparable(3)) - - - def test_greaterThanOrEqual(self): - """ - Instances of a class that is decorated by C{comparable} support - greater-than-or-equal comparisons. - """ - self.assertTrue(Comparable(1) >= Comparable(1)) - self.assertTrue(Comparable(2) >= Comparable(1)) - self.assertFalse(Comparable(0) >= Comparable(3)) - - - def test_lessThan(self): - """ - Instances of a class that is decorated by C{comparable} support - less-than comparisons. - """ - self.assertTrue(Comparable(0) < Comparable(3)) - self.assertFalse(Comparable(2) < Comparable(0)) - - - def test_lessThanOrEqual(self): - """ - Instances of a class that is decorated by C{comparable} support - less-than-or-equal comparisons. - """ - self.assertTrue(Comparable(3) <= Comparable(3)) - self.assertTrue(Comparable(0) <= Comparable(3)) - self.assertFalse(Comparable(2) <= Comparable(0)) - - - -class Python3ComparableTests(unittest.SynchronousTestCase): - """ - Python 3-specific functionality of C{comparable}. - """ - - def test_notImplementedEquals(self): - """ - Instances of a class that is decorated by C{comparable} support - returning C{NotImplemented} from C{__eq__} if it is returned by the - underlying C{__cmp__} call. - """ - self.assertEqual(Comparable(1).__eq__(object()), NotImplemented) - - - def test_notImplementedNotEquals(self): - """ - Instances of a class that is decorated by C{comparable} support - returning C{NotImplemented} from C{__ne__} if it is returned by the - underlying C{__cmp__} call. - """ - self.assertEqual(Comparable(1).__ne__(object()), NotImplemented) - - - def test_notImplementedGreaterThan(self): - """ - Instances of a class that is decorated by C{comparable} support - returning C{NotImplemented} from C{__gt__} if it is returned by the - underlying C{__cmp__} call. - """ - self.assertEqual(Comparable(1).__gt__(object()), NotImplemented) - - - def test_notImplementedLessThan(self): - """ - Instances of a class that is decorated by C{comparable} support - returning C{NotImplemented} from C{__lt__} if it is returned by the - underlying C{__cmp__} call. - """ - self.assertEqual(Comparable(1).__lt__(object()), NotImplemented) - - - def test_notImplementedGreaterThanEquals(self): - """ - Instances of a class that is decorated by C{comparable} support - returning C{NotImplemented} from C{__ge__} if it is returned by the - underlying C{__cmp__} call. - """ - self.assertEqual(Comparable(1).__ge__(object()), NotImplemented) - - - def test_notImplementedLessThanEquals(self): - """ - Instances of a class that is decorated by C{comparable} support - returning C{NotImplemented} from C{__le__} if it is returned by the - underlying C{__cmp__} call. - """ - self.assertEqual(Comparable(1).__le__(object()), NotImplemented) - -if not _PY3: - # On Python 2, we just use __cmp__ directly, so checking detailed - # comparison methods doesn't makes sense. - Python3ComparableTests.skip = "Python 3 only." - - - -class CmpTests(unittest.SynchronousTestCase): - """ - L{cmp} should behave like the built-in Python 2 C{cmp}. - """ - - def test_equals(self): - """ - L{cmp} returns 0 for equal objects. - """ - self.assertEqual(cmp(u"a", u"a"), 0) - self.assertEqual(cmp(1, 1), 0) - self.assertEqual(cmp([1], [1]), 0) - - - def test_greaterThan(self): - """ - L{cmp} returns 1 if its first argument is bigger than its second. - """ - self.assertEqual(cmp(4, 0), 1) - self.assertEqual(cmp(b"z", b"a"), 1) - - - def test_lessThan(self): - """ - L{cmp} returns -1 if its first argument is smaller than its second. - """ - self.assertEqual(cmp(0.1, 2.3), -1) - self.assertEqual(cmp(b"a", b"d"), -1) - - - -class StringTests(unittest.SynchronousTestCase): - """ - Compatibility functions and types for strings. - """ - - def assertNativeString(self, original, expected): - """ - Raise an exception indicating a failed test if the output of - C{nativeString(original)} is unequal to the expected string, or is not - a native string. - """ - self.assertEqual(nativeString(original), expected) - self.assertIsInstance(nativeString(original), str) - - - def test_nonASCIIBytesToString(self): - """ - C{nativeString} raises a C{UnicodeError} if input bytes are not ASCII - decodable. - """ - self.assertRaises(UnicodeError, nativeString, b"\xFF") - - - def test_nonASCIIUnicodeToString(self): - """ - C{nativeString} raises a C{UnicodeError} if input Unicode is not ASCII - encodable. - """ - self.assertRaises(UnicodeError, nativeString, u"\u1234") - - - def test_bytesToString(self): - """ - C{nativeString} converts bytes to the native string format, assuming - an ASCII encoding if applicable. - """ - self.assertNativeString(b"hello", "hello") - - - def test_unicodeToString(self): - """ - C{nativeString} converts unicode to the native string format, assuming - an ASCII encoding if applicable. - """ - self.assertNativeString(u"Good day", "Good day") - - - def test_stringToString(self): - """ - C{nativeString} leaves native strings as native strings. - """ - self.assertNativeString("Hello!", "Hello!") - - - def test_unexpectedType(self): - """ - C{nativeString} raises a C{TypeError} if given an object that is not a - string of some sort. - """ - self.assertRaises(TypeError, nativeString, 1) - - - def test_unicode(self): - """ - C{compat.unicode} is C{str} on Python 3, C{unicode} on Python 2. - """ - if _PY3: - expected = str - else: - expected = unicode - self.assertTrue(unicodeCompat is expected) - - - def test_nativeStringIO(self): - """ - L{NativeStringIO} is a file-like object that stores native strings in - memory. - """ - f = NativeStringIO() - f.write("hello") - f.write(" there") - self.assertEqual(f.getvalue(), "hello there") - - - -class NetworkStringTests(unittest.SynchronousTestCase): - """ - Tests for L{networkString}. - """ - def test_bytes(self): - """ - L{networkString} returns a C{bytes} object passed to it unmodified. - """ - self.assertEqual(b"foo", networkString(b"foo")) - - - def test_bytesOutOfRange(self): - """ - L{networkString} raises C{UnicodeError} if passed a C{bytes} instance - containing bytes not used by ASCII. - """ - self.assertRaises( - UnicodeError, networkString, u"\N{SNOWMAN}".encode('utf-8')) - if _PY3: - test_bytes.skip = test_bytesOutOfRange.skip = ( - "Bytes behavior of networkString only provided on Python 2.") - - - def test_unicode(self): - """ - L{networkString} returns a C{unicode} object passed to it encoded into - a C{bytes} instance. - """ - self.assertEqual(b"foo", networkString(u"foo")) - - - def test_unicodeOutOfRange(self): - """ - L{networkString} raises L{UnicodeError} if passed a C{unicode} instance - containing characters not encodable in ASCII. - """ - self.assertRaises( - UnicodeError, networkString, u"\N{SNOWMAN}") - if not _PY3: - test_unicode.skip = test_unicodeOutOfRange.skip = ( - "Unicode behavior of networkString only provided on Python 3.") - - - def test_nonString(self): - """ - L{networkString} raises L{TypeError} if passed a non-string object or - the wrong type of string object. - """ - self.assertRaises(TypeError, networkString, object()) - if _PY3: - self.assertRaises(TypeError, networkString, b"bytes") - else: - self.assertRaises(TypeError, networkString, u"text") - - - -class ReraiseTests(unittest.SynchronousTestCase): - """ - L{reraise} re-raises exceptions on both Python 2 and Python 3. - """ - - def test_reraiseWithNone(self): - """ - Calling L{reraise} with an exception instance and a traceback of - C{None} re-raises it with a new traceback. - """ - try: - 1/0 - except: - typ, value, tb = sys.exc_info() - try: - reraise(value, None) - except: - typ2, value2, tb2 = sys.exc_info() - self.assertEqual(typ2, ZeroDivisionError) - self.assertTrue(value is value2) - self.assertNotEqual(traceback.format_tb(tb)[-1], - traceback.format_tb(tb2)[-1]) - else: - self.fail("The exception was not raised.") - - - def test_reraiseWithTraceback(self): - """ - Calling L{reraise} with an exception instance and a traceback - re-raises the exception with the given traceback. - """ - try: - 1/0 - except: - typ, value, tb = sys.exc_info() - try: - reraise(value, tb) - except: - typ2, value2, tb2 = sys.exc_info() - self.assertEqual(typ2, ZeroDivisionError) - self.assertTrue(value is value2) - self.assertEqual(traceback.format_tb(tb)[-1], - traceback.format_tb(tb2)[-1]) - else: - self.fail("The exception was not raised.") - - - -class Python3BytesTests(unittest.SynchronousTestCase): - """ - Tests for L{iterbytes}, L{intToBytes}, L{lazyByteSlice}. - """ - - def test_iteration(self): - """ - When L{iterbytes} is called with a bytestring, the returned object - can be iterated over, resulting in the individual bytes of the - bytestring. - """ - input = b"abcd" - result = list(iterbytes(input)) - self.assertEqual(result, [b'a', b'b', b'c', b'd']) - - - def test_intToBytes(self): - """ - When L{intToBytes} is called with an integer, the result is an - ASCII-encoded string representation of the number. - """ - self.assertEqual(intToBytes(213), b"213") - - - def test_lazyByteSliceNoOffset(self): - """ - L{lazyByteSlice} called with some bytes returns a semantically equal - version of these bytes. - """ - data = b'123XYZ' - self.assertEqual(bytes(lazyByteSlice(data)), data) - - - def test_lazyByteSliceOffset(self): - """ - L{lazyByteSlice} called with some bytes and an offset returns a - semantically equal version of these bytes starting at the given offset. - """ - data = b'123XYZ' - self.assertEqual(bytes(lazyByteSlice(data, 2)), data[2:]) - - - def test_lazyByteSliceOffsetAndLength(self): - """ - L{lazyByteSlice} called with some bytes, an offset and a length returns - a semantically equal version of these bytes starting at the given - offset, up to the given length. - """ - data = b'123XYZ' - self.assertEqual(bytes(lazyByteSlice(data, 2, 3)), data[2:5]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_context.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_context.py deleted file mode 100644 index 0b5bc65..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_context.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.context}. -""" - -from __future__ import division, absolute_import - -from twisted.trial.unittest import SynchronousTestCase - -from twisted.python import context - -class ContextTests(SynchronousTestCase): - """ - Tests for the module-scope APIs for L{twisted.python.context}. - """ - def test_notPresentIfNotSet(self): - """ - Arbitrary keys which have not been set in the context have an associated - value of C{None}. - """ - self.assertEqual(context.get("x"), None) - - - def test_setByCall(self): - """ - Values may be associated with keys by passing them in a dictionary as - the first argument to L{twisted.python.context.call}. - """ - self.assertEqual(context.call({"x": "y"}, context.get, "x"), "y") - - - def test_unsetAfterCall(self): - """ - After a L{twisted.python.context.call} completes, keys specified in the - call are no longer associated with the values from that call. - """ - context.call({"x": "y"}, lambda: None) - self.assertEqual(context.get("x"), None) - - - def test_setDefault(self): - """ - A default value may be set for a key in the context using - L{twisted.python.context.setDefault}. - """ - key = object() - self.addCleanup(context.defaultContextDict.pop, key, None) - context.setDefault(key, "y") - self.assertEqual("y", context.get(key)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_cooperator.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_cooperator.py deleted file mode 100644 index f87c083..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_cooperator.py +++ /dev/null @@ -1,711 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module contains tests for L{twisted.internet.task.Cooperator} and -related functionality. -""" - -from __future__ import division, absolute_import - -from twisted.internet import reactor, defer, task -from twisted.trial import unittest - - - -class FakeDelayedCall(object): - """ - Fake delayed call which lets us simulate the scheduler. - """ - def __init__(self, func): - """ - A function to run, later. - """ - self.func = func - self.cancelled = False - - - def cancel(self): - """ - Don't run my function later. - """ - self.cancelled = True - - - -class FakeScheduler(object): - """ - A fake scheduler for testing against. - """ - def __init__(self): - """ - Create a fake scheduler with a list of work to do. - """ - self.work = [] - - - def __call__(self, thunk): - """ - Schedule a unit of work to be done later. - """ - unit = FakeDelayedCall(thunk) - self.work.append(unit) - return unit - - - def pump(self): - """ - Do all of the work that is currently available to be done. - """ - work, self.work = self.work, [] - for unit in work: - if not unit.cancelled: - unit.func() - - - -class CooperatorTests(unittest.TestCase): - RESULT = 'done' - - def ebIter(self, err): - err.trap(task.SchedulerStopped) - return self.RESULT - - - def cbIter(self, ign): - self.fail() - - - def testStoppedRejectsNewTasks(self): - """ - Test that Cooperators refuse new tasks when they have been stopped. - """ - def testwith(stuff): - c = task.Cooperator() - c.stop() - d = c.coiterate(iter(()), stuff) - d.addCallback(self.cbIter) - d.addErrback(self.ebIter) - return d.addCallback(lambda result: - self.assertEqual(result, self.RESULT)) - return testwith(None).addCallback(lambda ign: testwith(defer.Deferred())) - - - def testStopRunning(self): - """ - Test that a running iterator will not run to completion when the - cooperator is stopped. - """ - c = task.Cooperator() - def myiter(): - for myiter.value in range(3): - yield myiter.value - myiter.value = -1 - d = c.coiterate(myiter()) - d.addCallback(self.cbIter) - d.addErrback(self.ebIter) - c.stop() - def doasserts(result): - self.assertEqual(result, self.RESULT) - self.assertEqual(myiter.value, -1) - d.addCallback(doasserts) - return d - - - def testStopOutstanding(self): - """ - An iterator run with L{Cooperator.coiterate} paused on a L{Deferred} - yielded by that iterator will fire its own L{Deferred} (the one - returned by C{coiterate}) when L{Cooperator.stop} is called. - """ - testControlD = defer.Deferred() - outstandingD = defer.Deferred() - def myiter(): - reactor.callLater(0, testControlD.callback, None) - yield outstandingD - self.fail() - c = task.Cooperator() - d = c.coiterate(myiter()) - def stopAndGo(ign): - c.stop() - outstandingD.callback('arglebargle') - - testControlD.addCallback(stopAndGo) - d.addCallback(self.cbIter) - d.addErrback(self.ebIter) - - return d.addCallback( - lambda result: self.assertEqual(result, self.RESULT)) - - - def testUnexpectedError(self): - c = task.Cooperator() - def myiter(): - if 0: - yield None - else: - raise RuntimeError() - d = c.coiterate(myiter()) - return self.assertFailure(d, RuntimeError) - - - def testUnexpectedErrorActuallyLater(self): - def myiter(): - D = defer.Deferred() - reactor.callLater(0, D.errback, RuntimeError()) - yield D - - c = task.Cooperator() - d = c.coiterate(myiter()) - return self.assertFailure(d, RuntimeError) - - - def testUnexpectedErrorNotActuallyLater(self): - def myiter(): - yield defer.fail(RuntimeError()) - - c = task.Cooperator() - d = c.coiterate(myiter()) - return self.assertFailure(d, RuntimeError) - - - def testCooperation(self): - L = [] - def myiter(things): - for th in things: - L.append(th) - yield None - - groupsOfThings = ['abc', (1, 2, 3), 'def', (4, 5, 6)] - - c = task.Cooperator() - tasks = [] - for stuff in groupsOfThings: - tasks.append(c.coiterate(myiter(stuff))) - - return defer.DeferredList(tasks).addCallback( - lambda ign: self.assertEqual(tuple(L), sum(zip(*groupsOfThings), ()))) - - - def testResourceExhaustion(self): - output = [] - def myiter(): - for i in range(100): - output.append(i) - if i == 9: - _TPF.stopped = True - yield i - - class _TPF: - stopped = False - def __call__(self): - return self.stopped - - c = task.Cooperator(terminationPredicateFactory=_TPF) - c.coiterate(myiter()).addErrback(self.ebIter) - c._delayedCall.cancel() - # testing a private method because only the test case will ever care - # about this, so we have to carefully clean up after ourselves. - c._tick() - c.stop() - self.failUnless(_TPF.stopped) - self.assertEqual(output, list(range(10))) - - - def testCallbackReCoiterate(self): - """ - If a callback to a deferred returned by coiterate calls coiterate on - the same Cooperator, we should make sure to only do the minimal amount - of scheduling work. (This test was added to demonstrate a specific bug - that was found while writing the scheduler.) - """ - calls = [] - - class FakeCall: - def __init__(self, func): - self.func = func - - def __repr__(self): - return '' % (self.func,) - - def sched(f): - self.failIf(calls, repr(calls)) - calls.append(FakeCall(f)) - return calls[-1] - - c = task.Cooperator(scheduler=sched, terminationPredicateFactory=lambda: lambda: True) - d = c.coiterate(iter(())) - - done = [] - def anotherTask(ign): - c.coiterate(iter(())).addBoth(done.append) - - d.addCallback(anotherTask) - - work = 0 - while not done: - work += 1 - while calls: - calls.pop(0).func() - work += 1 - if work > 50: - self.fail("Cooperator took too long") - - - def test_removingLastTaskStopsScheduledCall(self): - """ - If the last task in a Cooperator is removed, the scheduled call for - the next tick is cancelled, since it is no longer necessary. - - This behavior is useful for tests that want to assert they have left - no reactor state behind when they're done. - """ - calls = [None] - def sched(f): - calls[0] = FakeDelayedCall(f) - return calls[0] - coop = task.Cooperator(scheduler=sched) - - # Add two task; this should schedule the tick: - task1 = coop.cooperate(iter([1, 2])) - task2 = coop.cooperate(iter([1, 2])) - self.assertEqual(calls[0].func, coop._tick) - - # Remove first task; scheduled call should still be going: - task1.stop() - self.assertEqual(calls[0].cancelled, False) - self.assertEqual(coop._delayedCall, calls[0]) - - # Remove second task; scheduled call should be cancelled: - task2.stop() - self.assertEqual(calls[0].cancelled, True) - self.assertEqual(coop._delayedCall, None) - - # Add another task; scheduled call will be recreated: - coop.cooperate(iter([1, 2])) - self.assertEqual(calls[0].cancelled, False) - self.assertEqual(coop._delayedCall, calls[0]) - - - def test_runningWhenStarted(self): - """ - L{Cooperator.running} reports C{True} if the L{Cooperator} - was started on creation. - """ - c = task.Cooperator() - self.assertTrue(c.running) - - - def test_runningWhenNotStarted(self): - """ - L{Cooperator.running} reports C{False} if the L{Cooperator} - has not been started. - """ - c = task.Cooperator(started=False) - self.assertFalse(c.running) - - - def test_runningWhenRunning(self): - """ - L{Cooperator.running} reports C{True} when the L{Cooperator} - is running. - """ - c = task.Cooperator(started=False) - c.start() - self.addCleanup(c.stop) - self.assertTrue(c.running) - - - def test_runningWhenStopped(self): - """ - L{Cooperator.running} reports C{False} after the L{Cooperator} - has been stopped. - """ - c = task.Cooperator(started=False) - c.start() - c.stop() - self.assertFalse(c.running) - - - -class UnhandledException(Exception): - """ - An exception that should go unhandled. - """ - - - -class AliasTests(unittest.TestCase): - """ - Integration test to verify that the global singleton aliases do what - they're supposed to. - """ - - def test_cooperate(self): - """ - L{twisted.internet.task.cooperate} ought to run the generator that it is - """ - d = defer.Deferred() - def doit(): - yield 1 - yield 2 - yield 3 - d.callback("yay") - it = doit() - theTask = task.cooperate(it) - self.assertIn(theTask, task._theCooperator._tasks) - return d - - - -class RunStateTests(unittest.TestCase): - """ - Tests to verify the behavior of L{CooperativeTask.pause}, - L{CooperativeTask.resume}, L{CooperativeTask.stop}, exhausting the - underlying iterator, and their interactions with each other. - """ - - def setUp(self): - """ - Create a cooperator with a fake scheduler and a termination predicate - that ensures only one unit of work will take place per tick. - """ - self._doDeferNext = False - self._doStopNext = False - self._doDieNext = False - self.work = [] - self.scheduler = FakeScheduler() - self.cooperator = task.Cooperator( - scheduler=self.scheduler, - # Always stop after one iteration of work (return a function which - # returns a function which always returns True) - terminationPredicateFactory=lambda: lambda: True) - self.task = self.cooperator.cooperate(self.worker()) - self.cooperator.start() - - - def worker(self): - """ - This is a sample generator which yields Deferreds when we are testing - deferral and an ascending integer count otherwise. - """ - i = 0 - while True: - i += 1 - if self._doDeferNext: - self._doDeferNext = False - d = defer.Deferred() - self.work.append(d) - yield d - elif self._doStopNext: - return - elif self._doDieNext: - raise UnhandledException() - else: - self.work.append(i) - yield i - - - def tearDown(self): - """ - Drop references to interesting parts of the fixture to allow Deferred - errors to be noticed when things start failing. - """ - del self.task - del self.scheduler - - - def deferNext(self): - """ - Defer the next result from my worker iterator. - """ - self._doDeferNext = True - - - def stopNext(self): - """ - Make the next result from my worker iterator be completion (raising - StopIteration). - """ - self._doStopNext = True - - - def dieNext(self): - """ - Make the next result from my worker iterator be raising an - L{UnhandledException}. - """ - def ignoreUnhandled(failure): - failure.trap(UnhandledException) - return None - self._doDieNext = True - - - def test_pauseResume(self): - """ - Cooperators should stop running their tasks when they're paused, and - start again when they're resumed. - """ - # first, sanity check - self.scheduler.pump() - self.assertEqual(self.work, [1]) - self.scheduler.pump() - self.assertEqual(self.work, [1, 2]) - - # OK, now for real - self.task.pause() - self.scheduler.pump() - self.assertEqual(self.work, [1, 2]) - self.task.resume() - # Resuming itself shoult not do any work - self.assertEqual(self.work, [1, 2]) - self.scheduler.pump() - # But when the scheduler rolls around again... - self.assertEqual(self.work, [1, 2, 3]) - - - def test_resumeNotPaused(self): - """ - L{CooperativeTask.resume} should raise a L{TaskNotPaused} exception if - it was not paused; e.g. if L{CooperativeTask.pause} was not invoked - more times than L{CooperativeTask.resume} on that object. - """ - self.assertRaises(task.NotPaused, self.task.resume) - self.task.pause() - self.task.resume() - self.assertRaises(task.NotPaused, self.task.resume) - - - def test_pauseTwice(self): - """ - Pauses on tasks should behave like a stack. If a task is paused twice, - it needs to be resumed twice. - """ - # pause once - self.task.pause() - self.scheduler.pump() - self.assertEqual(self.work, []) - # pause twice - self.task.pause() - self.scheduler.pump() - self.assertEqual(self.work, []) - # resume once (it shouldn't) - self.task.resume() - self.scheduler.pump() - self.assertEqual(self.work, []) - # resume twice (now it should go) - self.task.resume() - self.scheduler.pump() - self.assertEqual(self.work, [1]) - - - def test_pauseWhileDeferred(self): - """ - C{pause()}ing a task while it is waiting on an outstanding - L{defer.Deferred} should put the task into a state where the - outstanding L{defer.Deferred} must be called back I{and} the task is - C{resume}d before it will continue processing. - """ - self.deferNext() - self.scheduler.pump() - self.assertEqual(len(self.work), 1) - self.failUnless(isinstance(self.work[0], defer.Deferred)) - self.scheduler.pump() - self.assertEqual(len(self.work), 1) - self.task.pause() - self.scheduler.pump() - self.assertEqual(len(self.work), 1) - self.task.resume() - self.scheduler.pump() - self.assertEqual(len(self.work), 1) - self.work[0].callback("STUFF!") - self.scheduler.pump() - self.assertEqual(len(self.work), 2) - self.assertEqual(self.work[1], 2) - - - def test_whenDone(self): - """ - L{CooperativeTask.whenDone} returns a Deferred which fires when the - Cooperator's iterator is exhausted. It returns a new Deferred each - time it is called; callbacks added to other invocations will not modify - the value that subsequent invocations will fire with. - """ - - deferred1 = self.task.whenDone() - deferred2 = self.task.whenDone() - results1 = [] - results2 = [] - final1 = [] - final2 = [] - - def callbackOne(result): - results1.append(result) - return 1 - - def callbackTwo(result): - results2.append(result) - return 2 - - deferred1.addCallback(callbackOne) - deferred2.addCallback(callbackTwo) - - deferred1.addCallback(final1.append) - deferred2.addCallback(final2.append) - - # exhaust the task iterator - # callbacks fire - self.stopNext() - self.scheduler.pump() - - self.assertEqual(len(results1), 1) - self.assertEqual(len(results2), 1) - - self.assertIdentical(results1[0], self.task._iterator) - self.assertIdentical(results2[0], self.task._iterator) - - self.assertEqual(final1, [1]) - self.assertEqual(final2, [2]) - - - def test_whenDoneError(self): - """ - L{CooperativeTask.whenDone} returns a L{defer.Deferred} that will fail - when the iterable's C{next} method raises an exception, with that - exception. - """ - deferred1 = self.task.whenDone() - results = [] - deferred1.addErrback(results.append) - self.dieNext() - self.scheduler.pump() - self.assertEqual(len(results), 1) - self.assertEqual(results[0].check(UnhandledException), UnhandledException) - - - def test_whenDoneStop(self): - """ - L{CooperativeTask.whenDone} returns a L{defer.Deferred} that fails with - L{TaskStopped} when the C{stop} method is called on that - L{CooperativeTask}. - """ - deferred1 = self.task.whenDone() - errors = [] - deferred1.addErrback(errors.append) - self.task.stop() - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0].check(task.TaskStopped), task.TaskStopped) - - - def test_whenDoneAlreadyDone(self): - """ - L{CooperativeTask.whenDone} will return a L{defer.Deferred} that will - succeed immediately if its iterator has already completed. - """ - self.stopNext() - self.scheduler.pump() - results = [] - self.task.whenDone().addCallback(results.append) - self.assertEqual(results, [self.task._iterator]) - - - def test_stopStops(self): - """ - C{stop()}ping a task should cause it to be removed from the run just as - C{pause()}ing, with the distinction that C{resume()} will raise a - L{TaskStopped} exception. - """ - self.task.stop() - self.scheduler.pump() - self.assertEqual(len(self.work), 0) - self.assertRaises(task.TaskStopped, self.task.stop) - self.assertRaises(task.TaskStopped, self.task.pause) - # Sanity check - it's still not scheduled, is it? - self.scheduler.pump() - self.assertEqual(self.work, []) - - - def test_pauseStopResume(self): - """ - C{resume()}ing a paused, stopped task should be a no-op; it should not - raise an exception, because it's paused, but neither should it actually - do more work from the task. - """ - self.task.pause() - self.task.stop() - self.task.resume() - self.scheduler.pump() - self.assertEqual(self.work, []) - - - def test_stopDeferred(self): - """ - As a corrolary of the interaction of C{pause()} and C{unpause()}, - C{stop()}ping a task which is waiting on a L{Deferred} should cause the - task to gracefully shut down, meaning that it should not be unpaused - when the deferred fires. - """ - self.deferNext() - self.scheduler.pump() - d = self.work.pop() - self.assertEqual(self.task._pauseCount, 1) - results = [] - d.addBoth(results.append) - self.scheduler.pump() - self.task.stop() - self.scheduler.pump() - d.callback(7) - self.scheduler.pump() - # Let's make sure that Deferred doesn't come out fried with an - # unhandled error that will be logged. The value is None, rather than - # our test value, 7, because this Deferred is returned to and consumed - # by the cooperator code. Its callback therefore has no contract. - self.assertEqual(results, [None]) - # But more importantly, no further work should have happened. - self.assertEqual(self.work, []) - - - def test_stopExhausted(self): - """ - C{stop()}ping a L{CooperativeTask} whose iterator has been exhausted - should raise L{TaskDone}. - """ - self.stopNext() - self.scheduler.pump() - self.assertRaises(task.TaskDone, self.task.stop) - - - def test_stopErrored(self): - """ - C{stop()}ping a L{CooperativeTask} whose iterator has encountered an - error should raise L{TaskFailed}. - """ - self.dieNext() - self.scheduler.pump() - self.assertRaises(task.TaskFailed, self.task.stop) - - - def test_stopCooperatorReentrancy(self): - """ - If a callback of a L{Deferred} from L{CooperativeTask.whenDone} calls - C{Cooperator.stop} on its L{CooperativeTask._cooperator}, the - L{Cooperator} will stop, but the L{CooperativeTask} whose callback is - calling C{stop} should already be considered 'stopped' by the time the - callback is running, and therefore removed from the - L{CoooperativeTask}. - """ - callbackPhases = [] - def stopit(result): - callbackPhases.append(result) - self.cooperator.stop() - # "done" here is a sanity check to make sure that we get all the - # way through the callback; i.e. stop() shouldn't be raising an - # exception due to the stopped-ness of our main task. - callbackPhases.append("done") - self.task.whenDone().addCallback(stopit) - self.stopNext() - self.scheduler.pump() - self.assertEqual(callbackPhases, [self.task._iterator, "done"]) - - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_defer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_defer.py deleted file mode 100644 index ab6d9fe..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_defer.py +++ /dev/null @@ -1,2448 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.internet.defer}. -""" - -from __future__ import division, absolute_import - -import warnings -import gc, traceback -import re - -from twisted.python import failure, log -from twisted.python.compat import _PY3 -from twisted.internet import defer, reactor -from twisted.internet.task import Clock -from twisted.trial import unittest - - - -class GenericError(Exception): - pass - - - -def getDivisionFailure(*args, **kwargs): - """ - Make a L{failure.Failure} of a divide-by-zero error. - - @param args: Any C{*args} are passed to Failure's constructor. - @param kwargs: Any C{**kwargs} are passed to Failure's constructor. - """ - try: - 1/0 - except: - f = failure.Failure(*args, **kwargs) - return f - - - -def fakeCallbackCanceller(deferred): - """ - A fake L{defer.Deferred} canceller which callbacks the L{defer.Deferred} - with C{str} "Callback Result" when cancelling it. - - @param deferred: The cancelled L{defer.Deferred}. - """ - deferred.callback("Callback Result") - - - -class ImmediateFailureMixin(object): - """ - Add additional assertion methods. - """ - - def assertImmediateFailure(self, deferred, exception): - """ - Assert that the given Deferred current result is a Failure with the - given exception. - - @return: The exception instance in the Deferred. - """ - failures = [] - deferred.addErrback(failures.append) - self.assertEqual(len(failures), 1) - self.assertTrue(failures[0].check(exception)) - return failures[0].value - - - -class UtilTests(unittest.TestCase): - """ - Tests for utility functions. - """ - - def test_logErrorReturnsError(self): - """ - L{defer.logError} returns the given error. - """ - error = failure.Failure(RuntimeError()) - result = defer.logError(error) - self.flushLoggedErrors(RuntimeError) - - self.assertIs(error, result) - - - def test_logErrorLogsError(self): - """ - L{defer.logError} logs the given error. - """ - error = failure.Failure(RuntimeError()) - defer.logError(error) - errors = self.flushLoggedErrors(RuntimeError) - - self.assertEquals(errors, [error]) - - - def test_logErrorLogsErrorNoRepr(self): - """ - The text logged by L{defer.logError} has no repr of the failure. - """ - output = [] - - def emit(eventDict): - output.append(log.textFromEventDict(eventDict)) - - log.addObserver(emit) - - error = failure.Failure(RuntimeError()) - defer.logError(error) - self.flushLoggedErrors(RuntimeError) - - self.assertTrue(output[0].startswith("Unhandled Error\nTraceback ")) - - - -class DeferredTests(unittest.SynchronousTestCase, ImmediateFailureMixin): - - def setUp(self): - self.callbackResults = None - self.errbackResults = None - self.callback2Results = None - # Restore the debug flag to its original state when done. - self.addCleanup(defer.setDebugging, defer.getDebugging()) - - def _callback(self, *args, **kw): - self.callbackResults = args, kw - return args[0] - - def _callback2(self, *args, **kw): - self.callback2Results = args, kw - - def _errback(self, *args, **kw): - self.errbackResults = args, kw - - def testCallbackWithoutArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback) - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, (('hello',), {})) - - def testCallbackWithArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback, "world") - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, (('hello', 'world'), {})) - - def testCallbackWithKwArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback, world="world") - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, - (('hello',), {'world': 'world'})) - - def testTwoCallbacks(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback) - deferred.addCallback(self._callback2) - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, - (('hello',), {})) - self.assertEqual(self.callback2Results, - (('hello',), {})) - - def testDeferredList(self): - defr1 = defer.Deferred() - defr2 = defer.Deferred() - defr3 = defer.Deferred() - dl = defer.DeferredList([defr1, defr2, defr3]) - result = [] - def cb(resultList, result=result): - result.extend(resultList) - def catch(err): - return None - dl.addCallbacks(cb, cb) - defr1.callback("1") - defr2.addErrback(catch) - # "catch" is added to eat the GenericError that will be passed on by - # the DeferredList's callback on defr2. If left unhandled, the - # Failure object would cause a log.err() warning about "Unhandled - # error in Deferred". Twisted's pyunit watches for log.err calls and - # treats them as failures. So "catch" must eat the error to prevent - # it from flunking the test. - defr2.errback(GenericError("2")) - defr3.callback("3") - self.assertEqual([result[0], - #result[1][1] is now a Failure instead of an Exception - (result[1][0], str(result[1][1].value)), - result[2]], - - [(defer.SUCCESS, "1"), - (defer.FAILURE, "2"), - (defer.SUCCESS, "3")]) - - def testEmptyDeferredList(self): - result = [] - def cb(resultList, result=result): - result.append(resultList) - - dl = defer.DeferredList([]) - dl.addCallbacks(cb) - self.assertEqual(result, [[]]) - - result[:] = [] - dl = defer.DeferredList([], fireOnOneCallback=1) - dl.addCallbacks(cb) - self.assertEqual(result, []) - - def testDeferredListFireOnOneError(self): - defr1 = defer.Deferred() - defr2 = defer.Deferred() - defr3 = defer.Deferred() - dl = defer.DeferredList([defr1, defr2, defr3], fireOnOneErrback=1) - result = [] - dl.addErrback(result.append) - - # consume errors after they pass through the DeferredList (to avoid - # 'Unhandled error in Deferred'. - def catch(err): - return None - defr2.addErrback(catch) - - # fire one Deferred's callback, no result yet - defr1.callback("1") - self.assertEqual(result, []) - - # fire one Deferred's errback -- now we have a result - defr2.errback(GenericError("from def2")) - self.assertEqual(len(result), 1) - - # extract the result from the list - aFailure = result[0] - - # the type of the failure is a FirstError - self.failUnless(issubclass(aFailure.type, defer.FirstError), - 'issubclass(aFailure.type, defer.FirstError) failed: ' - "failure's type is %r" % (aFailure.type,) - ) - - firstError = aFailure.value - - # check that the GenericError("2") from the deferred at index 1 - # (defr2) is intact inside failure.value - self.assertEqual(firstError.subFailure.type, GenericError) - self.assertEqual(firstError.subFailure.value.args, ("from def2",)) - self.assertEqual(firstError.index, 1) - - - def testDeferredListDontConsumeErrors(self): - d1 = defer.Deferred() - dl = defer.DeferredList([d1]) - - errorTrap = [] - d1.addErrback(errorTrap.append) - - result = [] - dl.addCallback(result.append) - - d1.errback(GenericError('Bang')) - self.assertEqual('Bang', errorTrap[0].value.args[0]) - self.assertEqual(1, len(result)) - self.assertEqual('Bang', result[0][0][1].value.args[0]) - - def testDeferredListConsumeErrors(self): - d1 = defer.Deferred() - dl = defer.DeferredList([d1], consumeErrors=True) - - errorTrap = [] - d1.addErrback(errorTrap.append) - - result = [] - dl.addCallback(result.append) - - d1.errback(GenericError('Bang')) - self.assertEqual([], errorTrap) - self.assertEqual(1, len(result)) - self.assertEqual('Bang', result[0][0][1].value.args[0]) - - def testDeferredListFireOnOneErrorWithAlreadyFiredDeferreds(self): - # Create some deferreds, and errback one - d1 = defer.Deferred() - d2 = defer.Deferred() - d1.errback(GenericError('Bang')) - - # *Then* build the DeferredList, with fireOnOneErrback=True - dl = defer.DeferredList([d1, d2], fireOnOneErrback=True) - result = [] - dl.addErrback(result.append) - self.assertEqual(1, len(result)) - - d1.addErrback(lambda e: None) # Swallow error - - def testDeferredListWithAlreadyFiredDeferreds(self): - # Create some deferreds, and err one, call the other - d1 = defer.Deferred() - d2 = defer.Deferred() - d1.errback(GenericError('Bang')) - d2.callback(2) - - # *Then* build the DeferredList - dl = defer.DeferredList([d1, d2]) - - result = [] - dl.addCallback(result.append) - - self.assertEqual(1, len(result)) - - d1.addErrback(lambda e: None) # Swallow error - - - def test_cancelDeferredList(self): - """ - When cancelling an unfired L{defer.DeferredList}, cancel every - L{defer.Deferred} in the list. - """ - deferredOne = defer.Deferred() - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo]) - deferredList.cancel() - self.failureResultOf(deferredOne, defer.CancelledError) - self.failureResultOf(deferredTwo, defer.CancelledError) - - - def test_cancelDeferredListCallback(self): - """ - When cancelling an unfired L{defer.DeferredList} without the - C{fireOnOneCallback} and C{fireOnOneErrback} flags set, the - L{defer.DeferredList} will be callback with a C{list} of - (success, result) C{tuple}s. - """ - deferredOne = defer.Deferred(fakeCallbackCanceller) - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo]) - deferredList.cancel() - self.failureResultOf(deferredTwo, defer.CancelledError) - result = self.successResultOf(deferredList) - self.assertTrue(result[0][0]) - self.assertEqual(result[0][1], "Callback Result") - self.assertFalse(result[1][0]) - self.assertTrue(result[1][1].check(defer.CancelledError)) - - - def test_cancelDeferredListWithFireOnOneCallback(self): - """ - When cancelling an unfired L{defer.DeferredList} with the flag - C{fireOnOneCallback} set, cancel every L{defer.Deferred} in the list. - """ - deferredOne = defer.Deferred() - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo], - fireOnOneCallback=True) - deferredList.cancel() - self.failureResultOf(deferredOne, defer.CancelledError) - self.failureResultOf(deferredTwo, defer.CancelledError) - - - def test_cancelDeferredListWithFireOnOneCallbackAndDeferredCallback(self): - """ - When cancelling an unfired L{defer.DeferredList} with the flag - C{fireOnOneCallback} set, if one of the L{defer.Deferred} callbacks - in its canceller, the L{defer.DeferredList} will callback with the - result and the index of the L{defer.Deferred} in a C{tuple}. - """ - deferredOne = defer.Deferred(fakeCallbackCanceller) - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo], - fireOnOneCallback=True) - deferredList.cancel() - self.failureResultOf(deferredTwo, defer.CancelledError) - result = self.successResultOf(deferredList) - self.assertEqual(result, ("Callback Result", 0)) - - - def test_cancelDeferredListWithFireOnOneErrback(self): - """ - When cancelling an unfired L{defer.DeferredList} with the flag - C{fireOnOneErrback} set, cancel every L{defer.Deferred} in the list. - """ - deferredOne = defer.Deferred() - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo], - fireOnOneErrback=True) - deferredList.cancel() - self.failureResultOf(deferredOne, defer.CancelledError) - self.failureResultOf(deferredTwo, defer.CancelledError) - deferredListFailure = self.failureResultOf(deferredList, - defer.FirstError) - firstError = deferredListFailure.value - self.assertTrue(firstError.subFailure.check(defer.CancelledError)) - - - def test_cancelDeferredListWithFireOnOneErrbackAllDeferredsCallback(self): - """ - When cancelling an unfired L{defer.DeferredList} with the flag - C{fireOnOneErrback} set, if all the L{defer.Deferred} callbacks - in its canceller, the L{defer.DeferredList} will callback with a - C{list} of (success, result) C{tuple}s. - """ - deferredOne = defer.Deferred(fakeCallbackCanceller) - deferredTwo = defer.Deferred(fakeCallbackCanceller) - deferredList = defer.DeferredList([deferredOne, deferredTwo], - fireOnOneErrback=True) - deferredList.cancel() - result = self.successResultOf(deferredList) - self.assertTrue(result[0][0]) - self.assertEqual(result[0][1], "Callback Result") - self.assertTrue(result[1][0]) - self.assertEqual(result[1][1], "Callback Result") - - - def test_cancelDeferredListWithOriginalDeferreds(self): - """ - Cancelling a L{defer.DeferredList} will cancel the original - L{defer.Deferred}s passed in. - """ - deferredOne = defer.Deferred() - deferredTwo = defer.Deferred() - argumentList = [deferredOne, deferredTwo] - deferredList = defer.DeferredList(argumentList) - deferredThree = defer.Deferred() - argumentList.append(deferredThree) - deferredList.cancel() - self.failureResultOf(deferredOne, defer.CancelledError) - self.failureResultOf(deferredTwo, defer.CancelledError) - self.assertNoResult(deferredThree) - - - def test_cancelDeferredListWithException(self): - """ - Cancelling a L{defer.DeferredList} will cancel every L{defer.Deferred} - in the list even exceptions raised from the C{cancel} method of the - L{defer.Deferred}s. - """ - def cancellerRaisesException(deferred): - """ - A L{defer.Deferred} canceller that raises an exception. - - @param deferred: The cancelled L{defer.Deferred}. - """ - raise RuntimeError("test") - deferredOne = defer.Deferred(cancellerRaisesException) - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo]) - deferredList.cancel() - self.failureResultOf(deferredTwo, defer.CancelledError) - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - - - def test_cancelFiredOnOneCallbackDeferredList(self): - """ - When a L{defer.DeferredList} has fired because one L{defer.Deferred} in - the list fired with a non-failure result, the cancellation will do - nothing instead of cancelling the rest of the L{defer.Deferred}s. - """ - deferredOne = defer.Deferred() - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo], - fireOnOneCallback=True) - deferredOne.callback(None) - deferredList.cancel() - self.assertNoResult(deferredTwo) - - - def test_cancelFiredOnOneErrbackDeferredList(self): - """ - When a L{defer.DeferredList} has fired because one L{defer.Deferred} in - the list fired with a failure result, the cancellation will do - nothing instead of cancelling the rest of the L{defer.Deferred}s. - """ - deferredOne = defer.Deferred() - deferredTwo = defer.Deferred() - deferredList = defer.DeferredList([deferredOne, deferredTwo], - fireOnOneErrback=True) - deferredOne.errback(GenericError("test")) - deferredList.cancel() - self.assertNoResult(deferredTwo) - self.failureResultOf(deferredOne, GenericError) - self.failureResultOf(deferredList, defer.FirstError) - - - def testImmediateSuccess(self): - l = [] - d = defer.succeed("success") - d.addCallback(l.append) - self.assertEqual(l, ["success"]) - - - def testImmediateFailure(self): - l = [] - d = defer.fail(GenericError("fail")) - d.addErrback(l.append) - self.assertEqual(str(l[0].value), "fail") - - def testPausedFailure(self): - l = [] - d = defer.fail(GenericError("fail")) - d.pause() - d.addErrback(l.append) - self.assertEqual(l, []) - d.unpause() - self.assertEqual(str(l[0].value), "fail") - - def testCallbackErrors(self): - l = [] - d = defer.Deferred().addCallback(lambda _: 1 // 0).addErrback(l.append) - d.callback(1) - self.assert_(isinstance(l[0].value, ZeroDivisionError)) - l = [] - d = defer.Deferred().addCallback( - lambda _: failure.Failure(ZeroDivisionError())).addErrback(l.append) - d.callback(1) - self.assert_(isinstance(l[0].value, ZeroDivisionError)) - - def testUnpauseBeforeCallback(self): - d = defer.Deferred() - d.pause() - d.addCallback(self._callback) - d.unpause() - - def testReturnDeferred(self): - d = defer.Deferred() - d2 = defer.Deferred() - d2.pause() - d.addCallback(lambda r, d2=d2: d2) - d.addCallback(self._callback) - d.callback(1) - assert self.callbackResults is None, "Should not have been called yet." - d2.callback(2) - assert self.callbackResults is None, "Still should not have been called yet." - d2.unpause() - assert self.callbackResults[0][0] == 2, "Result should have been from second deferred:%s" % (self.callbackResults,) - - - def test_chainedPausedDeferredWithResult(self): - """ - When a paused Deferred with a result is returned from a callback on - another Deferred, the other Deferred is chained to the first and waits - for it to be unpaused. - """ - expected = object() - paused = defer.Deferred() - paused.callback(expected) - paused.pause() - chained = defer.Deferred() - chained.addCallback(lambda ignored: paused) - chained.callback(None) - - result = [] - chained.addCallback(result.append) - self.assertEqual(result, []) - paused.unpause() - self.assertEqual(result, [expected]) - - - def test_pausedDeferredChained(self): - """ - A paused Deferred encountered while pushing a result forward through a - chain does not prevent earlier Deferreds from continuing to execute - their callbacks. - """ - first = defer.Deferred() - second = defer.Deferred() - first.addCallback(lambda ignored: second) - first.callback(None) - first.pause() - second.callback(None) - result = [] - second.addCallback(result.append) - self.assertEqual(result, [None]) - - - def test_gatherResults(self): - # test successful list of deferreds - l = [] - defer.gatherResults([defer.succeed(1), defer.succeed(2)]).addCallback(l.append) - self.assertEqual(l, [[1, 2]]) - # test failing list of deferreds - l = [] - dl = [defer.succeed(1), defer.fail(ValueError())] - defer.gatherResults(dl).addErrback(l.append) - self.assertEqual(len(l), 1) - self.assert_(isinstance(l[0], failure.Failure)) - # get rid of error - dl[1].addErrback(lambda e: 1) - - - def test_gatherResultsWithConsumeErrors(self): - """ - If a L{Deferred} in the list passed to L{gatherResults} fires with a - failure and C{consumerErrors} is C{True}, the failure is converted to a - C{None} result on that L{Deferred}. - """ - # test successful list of deferreds - dgood = defer.succeed(1) - dbad = defer.fail(RuntimeError("oh noes")) - d = defer.gatherResults([dgood, dbad], consumeErrors=True) - unconsumedErrors = [] - dbad.addErrback(unconsumedErrors.append) - gatheredErrors = [] - d.addErrback(gatheredErrors.append) - - self.assertEqual((len(unconsumedErrors), len(gatheredErrors)), - (0, 1)) - self.assertIsInstance(gatheredErrors[0].value, defer.FirstError) - firstError = gatheredErrors[0].value.subFailure - self.assertIsInstance(firstError.value, RuntimeError) - - - def test_cancelGatherResults(self): - """ - When cancelling the L{defer.gatherResults} call, all the - L{defer.Deferred}s in the list will be cancelled. - """ - deferredOne = defer.Deferred() - deferredTwo = defer.Deferred() - result = defer.gatherResults([deferredOne, deferredTwo]) - result.cancel() - self.failureResultOf(deferredOne, defer.CancelledError) - self.failureResultOf(deferredTwo, defer.CancelledError) - gatherResultsFailure = self.failureResultOf(result, defer.FirstError) - firstError = gatherResultsFailure.value - self.assertTrue(firstError.subFailure.check(defer.CancelledError)) - - - def test_cancelGatherResultsWithAllDeferredsCallback(self): - """ - When cancelling the L{defer.gatherResults} call, if all the - L{defer.Deferred}s callback in their canceller, the L{defer.Deferred} - returned by L{defer.gatherResults} will be callbacked with the C{list} - of the results. - """ - deferredOne = defer.Deferred(fakeCallbackCanceller) - deferredTwo = defer.Deferred(fakeCallbackCanceller) - result = defer.gatherResults([deferredOne, deferredTwo]) - result.cancel() - callbackResult = self.successResultOf(result) - self.assertEqual(callbackResult[0], "Callback Result") - self.assertEqual(callbackResult[1], "Callback Result") - - - def test_maybeDeferredSync(self): - """ - L{defer.maybeDeferred} should retrieve the result of a synchronous - function and pass it to its resulting L{defer.Deferred}. - """ - S, E = [], [] - d = defer.maybeDeferred((lambda x: x + 5), 10) - d.addCallbacks(S.append, E.append) - self.assertEqual(E, []) - self.assertEqual(S, [15]) - - - def test_maybeDeferredSyncError(self): - """ - L{defer.maybeDeferred} should catch exception raised by a synchronous - function and errback its resulting L{defer.Deferred} with it. - """ - S, E = [], [] - try: - '10' + 5 - except TypeError as e: - expected = str(e) - d = defer.maybeDeferred((lambda x: x + 5), '10') - d.addCallbacks(S.append, E.append) - self.assertEqual(S, []) - self.assertEqual(len(E), 1) - self.assertEqual(str(E[0].value), expected) - - - def test_maybeDeferredAsync(self): - """ - L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by - so that original result is the same. - """ - d = defer.Deferred() - d2 = defer.maybeDeferred(lambda: d) - d.callback('Success') - result = [] - d2.addCallback(result.append) - self.assertEqual(result, ['Success']) - - - def test_maybeDeferredAsyncError(self): - """ - L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by - so that L{failure.Failure} returned by the original instance is the - same. - """ - d = defer.Deferred() - d2 = defer.maybeDeferred(lambda: d) - d.errback(failure.Failure(RuntimeError())) - self.assertImmediateFailure(d2, RuntimeError) - - - def test_innerCallbacksPreserved(self): - """ - When a L{Deferred} encounters a result which is another L{Deferred} - which is waiting on a third L{Deferred}, the middle L{Deferred}'s - callbacks are executed after the third L{Deferred} fires and before the - first receives a result. - """ - results = [] - failures = [] - inner = defer.Deferred() - def cb(result): - results.append(('start-of-cb', result)) - d = defer.succeed('inner') - def firstCallback(result): - results.append(('firstCallback', 'inner')) - return inner - def secondCallback(result): - results.append(('secondCallback', result)) - return result * 2 - d.addCallback(firstCallback).addCallback(secondCallback) - d.addErrback(failures.append) - return d - outer = defer.succeed('outer') - outer.addCallback(cb) - inner.callback('orange') - outer.addCallback(results.append) - inner.addErrback(failures.append) - outer.addErrback(failures.append) - self.assertEqual([], failures) - self.assertEqual( - results, - [('start-of-cb', 'outer'), - ('firstCallback', 'inner'), - ('secondCallback', 'orange'), - 'orangeorange']) - - - def test_continueCallbackNotFirst(self): - """ - The continue callback of a L{Deferred} waiting for another L{Deferred} - is not necessarily the first one. This is somewhat a whitebox test - checking that we search for that callback among the whole list of - callbacks. - """ - results = [] - failures = [] - a = defer.Deferred() - - def cb(result): - results.append(('cb', result)) - d = defer.Deferred() - - def firstCallback(ignored): - results.append(('firstCallback', ignored)) - return defer.gatherResults([a]) - - def secondCallback(result): - results.append(('secondCallback', result)) - - d.addCallback(firstCallback) - d.addCallback(secondCallback) - d.addErrback(failures.append) - d.callback(None) - return d - - outer = defer.succeed('outer') - outer.addCallback(cb) - outer.addErrback(failures.append) - self.assertEqual([('cb', 'outer'), ('firstCallback', None)], results) - a.callback('withers') - self.assertEqual([], failures) - self.assertEqual( - results, - [('cb', 'outer'), - ('firstCallback', None), - ('secondCallback', ['withers'])]) - - - def test_callbackOrderPreserved(self): - """ - A callback added to a L{Deferred} after a previous callback attached - another L{Deferred} as a result is run after the callbacks of the other - L{Deferred} are run. - """ - results = [] - failures = [] - a = defer.Deferred() - - def cb(result): - results.append(('cb', result)) - d = defer.Deferred() - - def firstCallback(ignored): - results.append(('firstCallback', ignored)) - return defer.gatherResults([a]) - - def secondCallback(result): - results.append(('secondCallback', result)) - - d.addCallback(firstCallback) - d.addCallback(secondCallback) - d.addErrback(failures.append) - d.callback(None) - return d - - outer = defer.Deferred() - outer.addCallback(cb) - outer.addCallback(lambda x: results.append('final')) - outer.addErrback(failures.append) - outer.callback('outer') - self.assertEqual([('cb', 'outer'), ('firstCallback', None)], results) - a.callback('withers') - self.assertEqual([], failures) - self.assertEqual( - results, - [('cb', 'outer'), - ('firstCallback', None), - ('secondCallback', ['withers']), 'final']) - - - def test_reentrantRunCallbacks(self): - """ - A callback added to a L{Deferred} by a callback on that L{Deferred} - should be added to the end of the callback chain. - """ - deferred = defer.Deferred() - called = [] - def callback3(result): - called.append(3) - def callback2(result): - called.append(2) - def callback1(result): - called.append(1) - deferred.addCallback(callback3) - deferred.addCallback(callback1) - deferred.addCallback(callback2) - deferred.callback(None) - self.assertEqual(called, [1, 2, 3]) - - - def test_nonReentrantCallbacks(self): - """ - A callback added to a L{Deferred} by a callback on that L{Deferred} - should not be executed until the running callback returns. - """ - deferred = defer.Deferred() - called = [] - def callback2(result): - called.append(2) - def callback1(result): - called.append(1) - deferred.addCallback(callback2) - self.assertEqual(called, [1]) - deferred.addCallback(callback1) - deferred.callback(None) - self.assertEqual(called, [1, 2]) - - - def test_reentrantRunCallbacksWithFailure(self): - """ - After an exception is raised by a callback which was added to a - L{Deferred} by a callback on that L{Deferred}, the L{Deferred} should - call the first errback with a L{Failure} wrapping that exception. - """ - exceptionMessage = "callback raised exception" - deferred = defer.Deferred() - def callback2(result): - raise Exception(exceptionMessage) - def callback1(result): - deferred.addCallback(callback2) - deferred.addCallback(callback1) - deferred.callback(None) - exception = self.assertImmediateFailure(deferred, Exception) - self.assertEqual(exception.args, (exceptionMessage,)) - - - def test_synchronousImplicitChain(self): - """ - If a first L{Deferred} with a result is returned from a callback on a - second L{Deferred}, the result of the second L{Deferred} becomes the - result of the first L{Deferred} and the result of the first L{Deferred} - becomes C{None}. - """ - result = object() - first = defer.succeed(result) - second = defer.Deferred() - second.addCallback(lambda ign: first) - second.callback(None) - - results = [] - first.addCallback(results.append) - self.assertIdentical(results[0], None) - second.addCallback(results.append) - self.assertIdentical(results[1], result) - - - def test_asynchronousImplicitChain(self): - """ - If a first L{Deferred} without a result is returned from a callback on - a second L{Deferred}, the result of the second L{Deferred} becomes the - result of the first L{Deferred} as soon as the first L{Deferred} has - one and the result of the first L{Deferred} becomes C{None}. - """ - first = defer.Deferred() - second = defer.Deferred() - second.addCallback(lambda ign: first) - second.callback(None) - - firstResult = [] - first.addCallback(firstResult.append) - secondResult = [] - second.addCallback(secondResult.append) - - self.assertEqual(firstResult, []) - self.assertEqual(secondResult, []) - - result = object() - first.callback(result) - - self.assertEqual(firstResult, [None]) - self.assertEqual(secondResult, [result]) - - - def test_synchronousImplicitErrorChain(self): - """ - If a first L{Deferred} with a L{Failure} result is returned from a - callback on a second L{Deferred}, the first L{Deferred}'s result is - converted to L{None} and no unhandled error is logged when it is - garbage collected. - """ - first = defer.fail(RuntimeError("First Deferred's Failure")) - second = defer.Deferred() - second.addCallback(lambda ign, first=first: first) - second.callback(None) - firstResult = [] - first.addCallback(firstResult.append) - self.assertIdentical(firstResult[0], None) - self.assertImmediateFailure(second, RuntimeError) - - - def test_asynchronousImplicitErrorChain(self): - """ - Let C{a} and C{b} be two L{Deferred}s. - - If C{a} has no result and is returned from a callback on C{b} then when - C{a} fails, C{b}'s result becomes the L{Failure} that was C{a}'s result, - the result of C{a} becomes C{None} so that no unhandled error is logged - when it is garbage collected. - """ - first = defer.Deferred() - second = defer.Deferred() - second.addCallback(lambda ign: first) - second.callback(None) - secondError = [] - second.addErrback(secondError.append) - - firstResult = [] - first.addCallback(firstResult.append) - secondResult = [] - second.addCallback(secondResult.append) - - self.assertEqual(firstResult, []) - self.assertEqual(secondResult, []) - - first.errback(RuntimeError("First Deferred's Failure")) - self.assertTrue(secondError[0].check(RuntimeError)) - self.assertEqual(firstResult, [None]) - self.assertEqual(len(secondResult), 1) - - - def test_doubleAsynchronousImplicitChaining(self): - """ - L{Deferred} chaining is transitive. - - In other words, let A, B, and C be Deferreds. If C is returned from a - callback on B and B is returned from a callback on A then when C fires, - A fires. - """ - first = defer.Deferred() - second = defer.Deferred() - second.addCallback(lambda ign: first) - third = defer.Deferred() - third.addCallback(lambda ign: second) - - thirdResult = [] - third.addCallback(thirdResult.append) - - result = object() - # After this, second is waiting for first to tell it to continue. - second.callback(None) - # And after this, third is waiting for second to tell it to continue. - third.callback(None) - - # Still waiting - self.assertEqual(thirdResult, []) - - # This will tell second to continue which will tell third to continue. - first.callback(result) - - self.assertEqual(thirdResult, [result]) - - - def test_nestedAsynchronousChainedDeferreds(self): - """ - L{Deferred}s can have callbacks that themselves return L{Deferred}s. - When these "inner" L{Deferred}s fire (even asynchronously), the - callback chain continues. - """ - results = [] - failures = [] - - # A Deferred returned in the inner callback. - inner = defer.Deferred() - - def cb(result): - results.append(('start-of-cb', result)) - d = defer.succeed('inner') - - def firstCallback(result): - results.append(('firstCallback', 'inner')) - # Return a Deferred that definitely has not fired yet, so we - # can fire the Deferreds out of order. - return inner - - def secondCallback(result): - results.append(('secondCallback', result)) - return result * 2 - - d.addCallback(firstCallback).addCallback(secondCallback) - d.addErrback(failures.append) - return d - - # Create a synchronous Deferred that has a callback 'cb' that returns - # a Deferred 'd' that has fired but is now waiting on an unfired - # Deferred 'inner'. - outer = defer.succeed('outer') - outer.addCallback(cb) - outer.addCallback(results.append) - # At this point, the callback 'cb' has been entered, and the first - # callback of 'd' has been called. - self.assertEqual( - results, [('start-of-cb', 'outer'), ('firstCallback', 'inner')]) - - # Once the inner Deferred is fired, processing of the outer Deferred's - # callback chain continues. - inner.callback('orange') - - # Make sure there are no errors. - inner.addErrback(failures.append) - outer.addErrback(failures.append) - self.assertEqual( - [], failures, "Got errbacks but wasn't expecting any.") - - self.assertEqual( - results, - [('start-of-cb', 'outer'), - ('firstCallback', 'inner'), - ('secondCallback', 'orange'), - 'orangeorange']) - - - def test_nestedAsynchronousChainedDeferredsWithExtraCallbacks(self): - """ - L{Deferred}s can have callbacks that themselves return L{Deferred}s. - These L{Deferred}s can have other callbacks added before they are - returned, which subtly changes the callback chain. When these "inner" - L{Deferred}s fire (even asynchronously), the outer callback chain - continues. - """ - results = [] - failures = [] - - # A Deferred returned in the inner callback after a callback is - # added explicitly and directly to it. - inner = defer.Deferred() - - def cb(result): - results.append(('start-of-cb', result)) - d = defer.succeed('inner') - - def firstCallback(ignored): - results.append(('firstCallback', ignored)) - # Return a Deferred that definitely has not fired yet with a - # result-transforming callback so we can fire the Deferreds - # out of order and see how the callback affects the ultimate - # results. - return inner.addCallback(lambda x: [x]) - - def secondCallback(result): - results.append(('secondCallback', result)) - return result * 2 - - d.addCallback(firstCallback) - d.addCallback(secondCallback) - d.addErrback(failures.append) - return d - - # Create a synchronous Deferred that has a callback 'cb' that returns - # a Deferred 'd' that has fired but is now waiting on an unfired - # Deferred 'inner'. - outer = defer.succeed('outer') - outer.addCallback(cb) - outer.addCallback(results.append) - # At this point, the callback 'cb' has been entered, and the first - # callback of 'd' has been called. - self.assertEqual( - results, [('start-of-cb', 'outer'), ('firstCallback', 'inner')]) - - # Once the inner Deferred is fired, processing of the outer Deferred's - # callback chain continues. - inner.callback('withers') - - # Make sure there are no errors. - outer.addErrback(failures.append) - inner.addErrback(failures.append) - self.assertEqual( - [], failures, "Got errbacks but wasn't expecting any.") - - self.assertEqual( - results, - [('start-of-cb', 'outer'), - ('firstCallback', 'inner'), - ('secondCallback', ['withers']), - ['withers', 'withers']]) - - - def test_chainDeferredRecordsExplicitChain(self): - """ - When we chain a L{Deferred}, that chaining is recorded explicitly. - """ - a = defer.Deferred() - b = defer.Deferred() - b.chainDeferred(a) - self.assertIdentical(a._chainedTo, b) - - - def test_explicitChainClearedWhenResolved(self): - """ - Any recorded chaining is cleared once the chaining is resolved, since - it no longer exists. - - In other words, if one L{Deferred} is recorded as depending on the - result of another, and I{that} L{Deferred} has fired, then the - dependency is resolved and we no longer benefit from recording it. - """ - a = defer.Deferred() - b = defer.Deferred() - b.chainDeferred(a) - b.callback(None) - self.assertIdentical(a._chainedTo, None) - - - def test_chainDeferredRecordsImplicitChain(self): - """ - We can chain L{Deferred}s implicitly by adding callbacks that return - L{Deferred}s. When this chaining happens, we record it explicitly as - soon as we can find out about it. - """ - a = defer.Deferred() - b = defer.Deferred() - a.addCallback(lambda ignored: b) - a.callback(None) - self.assertIdentical(a._chainedTo, b) - - - def test_circularChainWarning(self): - """ - When a Deferred is returned from a callback directly attached to that - same Deferred, a warning is emitted. - """ - d = defer.Deferred() - def circularCallback(result): - return d - d.addCallback(circularCallback) - d.callback("foo") - - circular_warnings = self.flushWarnings([circularCallback]) - self.assertEqual(len(circular_warnings), 1) - warning = circular_warnings[0] - self.assertEqual(warning['category'], DeprecationWarning) - pattern = "Callback returned the Deferred it was attached to" - self.assertTrue( - re.search(pattern, warning['message']), - "\nExpected match: %r\nGot: %r" % (pattern, warning['message'])) - - - def test_circularChainException(self): - """ - If the deprecation warning for circular deferred callbacks is - configured to be an error, the exception will become the failure - result of the Deferred. - """ - self.addCleanup(setattr, warnings, "filters", warnings.filters) - warnings.filterwarnings("error", category=DeprecationWarning) - d = defer.Deferred() - def circularCallback(result): - return d - d.addCallback(circularCallback) - d.callback("foo") - failure = self.failureResultOf(d) - failure.trap(DeprecationWarning) - - - def test_repr(self): - """ - The C{repr()} of a L{Deferred} contains the class name and a - representation of the internal Python ID. - """ - d = defer.Deferred() - address = id(d) - self.assertEqual( - repr(d), '' % (address,)) - - - def test_reprWithResult(self): - """ - If a L{Deferred} has been fired, then its C{repr()} contains its - result. - """ - d = defer.Deferred() - d.callback('orange') - self.assertEqual( - repr(d), "" % ( - id(d),)) - - - def test_reprWithChaining(self): - """ - If a L{Deferred} C{a} has been fired, but is waiting on another - L{Deferred} C{b} that appears in its callback chain, then C{repr(a)} - says that it is waiting on C{b}. - """ - a = defer.Deferred() - b = defer.Deferred() - b.chainDeferred(a) - self.assertEqual( - repr(a), "" % ( - id(a), id(b))) - - - def test_boundedStackDepth(self): - """ - The depth of the call stack does not grow as more L{Deferred} instances - are chained together. - """ - def chainDeferreds(howMany): - stack = [] - def recordStackDepth(ignored): - stack.append(len(traceback.extract_stack())) - - top = defer.Deferred() - innerDeferreds = [defer.Deferred() for ignored in range(howMany)] - originalInners = innerDeferreds[:] - last = defer.Deferred() - - inner = innerDeferreds.pop() - top.addCallback(lambda ign, inner=inner: inner) - top.addCallback(recordStackDepth) - - while innerDeferreds: - newInner = innerDeferreds.pop() - inner.addCallback(lambda ign, inner=newInner: inner) - inner = newInner - inner.addCallback(lambda ign: last) - - top.callback(None) - for inner in originalInners: - inner.callback(None) - - # Sanity check - the record callback is not intended to have - # fired yet. - self.assertEqual(stack, []) - - # Now fire the last thing and return the stack depth at which the - # callback was invoked. - last.callback(None) - return stack[0] - - # Callbacks should be invoked at the same stack depth regardless of - # how many Deferreds are chained. - self.assertEqual(chainDeferreds(1), chainDeferreds(2)) - - - def test_resultOfDeferredResultOfDeferredOfFiredDeferredCalled(self): - """ - Given three Deferreds, one chained to the next chained to the next, - callbacks on the middle Deferred which are added after the chain is - created are called once the last Deferred fires. - - This is more of a regression-style test. It doesn't exercise any - particular code path through the current implementation of Deferred, but - it does exercise a broken codepath through one of the variations of the - implementation proposed as a resolution to ticket #411. - """ - first = defer.Deferred() - second = defer.Deferred() - third = defer.Deferred() - first.addCallback(lambda ignored: second) - second.addCallback(lambda ignored: third) - second.callback(None) - first.callback(None) - third.callback(None) - L = [] - second.addCallback(L.append) - self.assertEqual(L, [None]) - - - def test_errbackWithNoArgsNoDebug(self): - """ - C{Deferred.errback()} creates a failure from the current Python - exception. When Deferred.debug is not set no globals or locals are - captured in that failure. - """ - defer.setDebugging(False) - d = defer.Deferred() - l = [] - exc = GenericError("Bang") - try: - raise exc - except: - d.errback() - d.addErrback(l.append) - fail = l[0] - self.assertEqual(fail.value, exc) - localz, globalz = fail.frames[0][-2:] - self.assertEqual([], localz) - self.assertEqual([], globalz) - - - def test_errbackWithNoArgs(self): - """ - C{Deferred.errback()} creates a failure from the current Python - exception. When Deferred.debug is set globals and locals are captured - in that failure. - """ - defer.setDebugging(True) - d = defer.Deferred() - l = [] - exc = GenericError("Bang") - try: - raise exc - except: - d.errback() - d.addErrback(l.append) - fail = l[0] - self.assertEqual(fail.value, exc) - localz, globalz = fail.frames[0][-2:] - self.assertNotEquals([], localz) - self.assertNotEquals([], globalz) - - - def test_errorInCallbackDoesNotCaptureVars(self): - """ - An error raised by a callback creates a Failure. The Failure captures - locals and globals if and only if C{Deferred.debug} is set. - """ - d = defer.Deferred() - d.callback(None) - defer.setDebugging(False) - def raiseError(ignored): - raise GenericError("Bang") - d.addCallback(raiseError) - l = [] - d.addErrback(l.append) - fail = l[0] - localz, globalz = fail.frames[0][-2:] - self.assertEqual([], localz) - self.assertEqual([], globalz) - - - def test_errorInCallbackCapturesVarsWhenDebugging(self): - """ - An error raised by a callback creates a Failure. The Failure captures - locals and globals if and only if C{Deferred.debug} is set. - """ - d = defer.Deferred() - d.callback(None) - defer.setDebugging(True) - def raiseError(ignored): - raise GenericError("Bang") - d.addCallback(raiseError) - l = [] - d.addErrback(l.append) - fail = l[0] - localz, globalz = fail.frames[0][-2:] - self.assertNotEquals([], localz) - self.assertNotEquals([], globalz) - - - def test_inlineCallbacksTracebacks(self): - """ - L{defer.inlineCallbacks} that re-raise tracebacks into their deferred - should not lose their tracebacks. - """ - f = getDivisionFailure() - d = defer.Deferred() - try: - f.raiseException() - except: - d.errback() - - def ic(d): - yield d - ic = defer.inlineCallbacks(ic) - newFailure = self.failureResultOf(d) - tb = traceback.extract_tb(newFailure.getTracebackObject()) - - self.assertEqual(len(tb), 2) - self.assertIn('test_defer', tb[0][0]) - self.assertEqual('test_inlineCallbacksTracebacks', tb[0][2]) - self.assertEqual('f.raiseException()', tb[0][3]) - self.assertIn('test_defer', tb[1][0]) - self.assertEqual('getDivisionFailure', tb[1][2]) - self.assertEqual('1/0', tb[1][3]) - - - if _PY3: - # FIXME: https://twistedmatrix.com/trac/ticket/5949 - test_inlineCallbacksTracebacks.skip = ( - "Python 3 support to be fixed in #5949") - - - -class FirstErrorTests(unittest.SynchronousTestCase): - """ - Tests for L{FirstError}. - """ - def test_repr(self): - """ - The repr of a L{FirstError} instance includes the repr of the value of - the sub-failure and the index which corresponds to the L{FirstError}. - """ - exc = ValueError("some text") - try: - raise exc - except: - f = failure.Failure() - - error = defer.FirstError(f, 3) - self.assertEqual( - repr(error), - "FirstError[#3, %s]" % (repr(exc),)) - - - def test_str(self): - """ - The str of a L{FirstError} instance includes the str of the - sub-failure and the index which corresponds to the L{FirstError}. - """ - exc = ValueError("some text") - try: - raise exc - except: - f = failure.Failure() - - error = defer.FirstError(f, 5) - self.assertEqual( - str(error), - "FirstError[#5, %s]" % (str(f),)) - - - def test_comparison(self): - """ - L{FirstError} instances compare equal to each other if and only if - their failure and index compare equal. L{FirstError} instances do not - compare equal to instances of other types. - """ - try: - 1 // 0 - except: - firstFailure = failure.Failure() - - one = defer.FirstError(firstFailure, 13) - anotherOne = defer.FirstError(firstFailure, 13) - - try: - raise ValueError("bar") - except: - secondFailure = failure.Failure() - - another = defer.FirstError(secondFailure, 9) - - self.assertTrue(one == anotherOne) - self.assertFalse(one == another) - self.assertTrue(one != another) - self.assertFalse(one != anotherOne) - - self.assertFalse(one == 10) - - - -class AlreadyCalledTests(unittest.SynchronousTestCase): - def setUp(self): - self._deferredWasDebugging = defer.getDebugging() - defer.setDebugging(True) - - def tearDown(self): - defer.setDebugging(self._deferredWasDebugging) - - def _callback(self, *args, **kw): - pass - def _errback(self, *args, **kw): - pass - - def _call_1(self, d): - d.callback("hello") - def _call_2(self, d): - d.callback("twice") - def _err_1(self, d): - d.errback(failure.Failure(RuntimeError())) - def _err_2(self, d): - d.errback(failure.Failure(RuntimeError())) - - def testAlreadyCalled_CC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) - - def testAlreadyCalled_CE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) - - def testAlreadyCalled_EE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) - - def testAlreadyCalled_EC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) - - - def _count(self, linetype, func, lines, expected): - count = 0 - for line in lines: - if (line.startswith(' %s:' % linetype) and - line.endswith(' %s' % func)): - count += 1 - self.failUnless(count == expected) - - def _check(self, e, caller, invoker1, invoker2): - # make sure the debugging information is vaguely correct - lines = e.args[0].split("\n") - # the creator should list the creator (testAlreadyCalledDebug) but not - # _call_1 or _call_2 or other invokers - self._count('C', caller, lines, 1) - self._count('C', '_call_1', lines, 0) - self._count('C', '_call_2', lines, 0) - self._count('C', '_err_1', lines, 0) - self._count('C', '_err_2', lines, 0) - # invoker should list the first invoker but not the second - self._count('I', invoker1, lines, 1) - self._count('I', invoker2, lines, 0) - - def testAlreadyCalledDebug_CC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError as e: - self._check(e, "testAlreadyCalledDebug_CC", "_call_1", "_call_2") - else: - self.fail("second callback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_CE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._err_2(d) - except defer.AlreadyCalledError as e: - self._check(e, "testAlreadyCalledDebug_CE", "_call_1", "_err_2") - else: - self.fail("second errback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_EC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError as e: - self._check(e, "testAlreadyCalledDebug_EC", "_err_1", "_call_2") - else: - self.fail("second callback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_EE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - try: - self._err_2(d) - except defer.AlreadyCalledError as e: - self._check(e, "testAlreadyCalledDebug_EE", "_err_1", "_err_2") - else: - self.fail("second errback failed to raise AlreadyCalledError") - - def testNoDebugging(self): - defer.setDebugging(False) - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError as e: - self.failIf(e.args) - else: - self.fail("second callback failed to raise AlreadyCalledError") - - - def testSwitchDebugging(self): - # Make sure Deferreds can deal with debug state flipping - # around randomly. This is covering a particular fixed bug. - defer.setDebugging(False) - d = defer.Deferred() - d.addBoth(lambda ign: None) - defer.setDebugging(True) - d.callback(None) - - defer.setDebugging(False) - d = defer.Deferred() - d.callback(None) - defer.setDebugging(True) - d.addBoth(lambda ign: None) - - - -class DeferredCancellerTests(unittest.SynchronousTestCase): - def setUp(self): - self.callbackResults = None - self.errbackResults = None - self.callback2Results = None - self.cancellerCallCount = 0 - - - def tearDown(self): - # Sanity check that the canceller was called at most once. - self.assertTrue(self.cancellerCallCount in (0, 1)) - - - def _callback(self, data): - self.callbackResults = data - return data - - - def _callback2(self, data): - self.callback2Results = data - - - def _errback(self, data): - self.errbackResults = data - - - def test_noCanceller(self): - """ - A L{defer.Deferred} without a canceller must errback with a - L{defer.CancelledError} and not callback. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - self.assertEqual(self.callbackResults, None) - - - def test_raisesAfterCancelAndCallback(self): - """ - A L{defer.Deferred} without a canceller, when cancelled must allow - a single extra call to callback, and raise - L{defer.AlreadyCalledError} if callbacked or errbacked thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - - # A single extra callback should be swallowed. - d.callback(None) - - # But a second call to callback or errback is not. - self.assertRaises(defer.AlreadyCalledError, d.callback, None) - self.assertRaises(defer.AlreadyCalledError, d.errback, Exception()) - - - def test_raisesAfterCancelAndErrback(self): - """ - A L{defer.Deferred} without a canceller, when cancelled must allow - a single extra call to errback, and raise - L{defer.AlreadyCalledError} if callbacked or errbacked thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - - # A single extra errback should be swallowed. - d.errback(Exception()) - - # But a second call to callback or errback is not. - self.assertRaises(defer.AlreadyCalledError, d.callback, None) - self.assertRaises(defer.AlreadyCalledError, d.errback, Exception()) - - - def test_noCancellerMultipleCancelsAfterCancelAndCallback(self): - """ - A L{Deferred} without a canceller, when cancelled and then - callbacked, ignores multiple cancels thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - currentFailure = self.errbackResults - # One callback will be ignored - d.callback(None) - # Cancel should have no effect. - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - - - def test_noCancellerMultipleCancelsAfterCancelAndErrback(self): - """ - A L{defer.Deferred} without a canceller, when cancelled and then - errbacked, ignores multiple cancels thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - currentFailure = self.errbackResults - # One errback will be ignored - d.errback(GenericError()) - # I.e., we should still have a CancelledError. - self.assertEqual(self.errbackResults.type, defer.CancelledError) - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - - - def test_noCancellerMultipleCancel(self): - """ - Calling cancel multiple times on a deferred with no canceller - results in a L{defer.CancelledError}. Subsequent calls to cancel - do not cause an error. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - currentFailure = self.errbackResults - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - - - def test_cancellerMultipleCancel(self): - """ - Verify that calling cancel multiple times on a deferred with a - canceller that does not errback results in a - L{defer.CancelledError} and that subsequent calls to cancel do not - cause an error and that after all that, the canceller was only - called once. - """ - def cancel(d): - self.cancellerCallCount += 1 - - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - currentFailure = self.errbackResults - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - self.assertEqual(self.cancellerCallCount, 1) - - - def test_simpleCanceller(self): - """ - Verify that a L{defer.Deferred} calls its specified canceller when - it is cancelled, and that further call/errbacks raise - L{defer.AlreadyCalledError}. - """ - def cancel(d): - self.cancellerCallCount += 1 - - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.cancellerCallCount, 1) - self.assertEqual(self.errbackResults.type, defer.CancelledError) - - # Test that further call/errbacks are *not* swallowed - self.assertRaises(defer.AlreadyCalledError, d.callback, None) - self.assertRaises(defer.AlreadyCalledError, d.errback, Exception()) - - - def test_cancellerArg(self): - """ - Verify that a canceller is given the correct deferred argument. - """ - def cancel(d1): - self.assertIdentical(d1, d) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - - - def test_cancelAfterCallback(self): - """ - Test that cancelling a deferred after it has been callbacked does - not cause an error. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.errback(GenericError()) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.callback('biff!') - d.cancel() - self.assertEqual(self.cancellerCallCount, 0) - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, 'biff!') - - - def test_cancelAfterErrback(self): - """ - Test that cancelling a L{Deferred} after it has been errbacked does - not result in a L{defer.CancelledError}. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.errback(GenericError()) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.errback(GenericError()) - d.cancel() - self.assertEqual(self.cancellerCallCount, 0) - self.assertEqual(self.errbackResults.type, GenericError) - self.assertEqual(self.callbackResults, None) - - - def test_cancellerThatErrbacks(self): - """ - Test a canceller which errbacks its deferred. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.errback(GenericError()) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.cancellerCallCount, 1) - self.assertEqual(self.errbackResults.type, GenericError) - - - def test_cancellerThatCallbacks(self): - """ - Test a canceller which calls its deferred. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.callback('hello!') - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.cancellerCallCount, 1) - self.assertEqual(self.callbackResults, 'hello!') - self.assertEqual(self.errbackResults, None) - - - def test_cancelNestedDeferred(self): - """ - Verify that a Deferred, a, which is waiting on another Deferred, b, - returned from one of its callbacks, will propagate - L{defer.CancelledError} when a is cancelled. - """ - def innerCancel(d): - self.cancellerCallCount += 1 - def cancel(d): - self.assert_(False) - - b = defer.Deferred(canceller=innerCancel) - a = defer.Deferred(canceller=cancel) - a.callback(None) - a.addCallback(lambda data: b) - a.cancel() - a.addCallbacks(self._callback, self._errback) - # The cancel count should be one (the cancellation done by B) - self.assertEqual(self.cancellerCallCount, 1) - # B's canceller didn't errback, so defer.py will have called errback - # with a CancelledError. - self.assertEqual(self.errbackResults.type, defer.CancelledError) - - - -class LogTests(unittest.SynchronousTestCase): - """ - Test logging of unhandled errors. - """ - - def setUp(self): - """ - Add a custom observer to observer logging. - """ - self.c = [] - log.addObserver(self.c.append) - - def tearDown(self): - """ - Remove the observer. - """ - log.removeObserver(self.c.append) - - - def _loggedErrors(self): - return [e for e in self.c if e["isError"]] - - - def _check(self): - """ - Check the output of the log observer to see if the error is present. - """ - c2 = self._loggedErrors() - self.assertEqual(len(c2), 2) - c2[1]["failure"].trap(ZeroDivisionError) - self.flushLoggedErrors(ZeroDivisionError) - - def test_errorLog(self): - """ - Verify that when a L{Deferred} with no references to it is fired, - and its final result (the one not handled by any callback) is an - exception, that exception will be logged immediately. - """ - defer.Deferred().addCallback(lambda x: 1 // 0).callback(1) - gc.collect() - self._check() - - def test_errorLogWithInnerFrameRef(self): - """ - Same as L{test_errorLog}, but with an inner frame. - """ - def _subErrorLogWithInnerFrameRef(): - d = defer.Deferred() - d.addCallback(lambda x: 1 // 0) - d.callback(1) - - _subErrorLogWithInnerFrameRef() - gc.collect() - self._check() - - def test_errorLogWithInnerFrameCycle(self): - """ - Same as L{test_errorLogWithInnerFrameRef}, plus create a cycle. - """ - def _subErrorLogWithInnerFrameCycle(): - d = defer.Deferred() - d.addCallback(lambda x, d=d: 1 // 0) - d._d = d - d.callback(1) - - _subErrorLogWithInnerFrameCycle() - gc.collect() - self._check() - - - def test_errorLogNoRepr(self): - """ - Verify that when a L{Deferred} with no references to it is fired, - the logged message does not contain a repr of the failure object. - """ - defer.Deferred().addCallback(lambda x: 1 // 0).callback(1) - - gc.collect() - self._check() - - self.assertEqual(2, len(self.c)) - msg = log.textFromEventDict(self.c[-1]) - expected = "Unhandled Error\nTraceback " - self.assertTrue(msg.startswith(expected), - "Expected message starting with: {0!r}". - format(expected)) - - - def test_errorLogDebugInfo(self): - """ - Verify that when a L{Deferred} with no references to it is fired, - the logged message includes debug info if debugging on the deferred - is enabled. - """ - def doit(): - d = defer.Deferred() - d.debug = True - d.addCallback(lambda x: 1 // 0) - d.callback(1) - - doit() - gc.collect() - self._check() - - self.assertEqual(2, len(self.c)) - msg = log.textFromEventDict(self.c[-1]) - expected = "(debug: I" - self.assertTrue(msg.startswith(expected), - "Expected message starting with: {0!r}". - format(expected)) - - - def test_chainedErrorCleanup(self): - """ - If one Deferred with an error result is returned from a callback on - another Deferred, when the first Deferred is garbage collected it does - not log its error. - """ - d = defer.Deferred() - d.addCallback(lambda ign: defer.fail(RuntimeError("zoop"))) - d.callback(None) - - # Sanity check - this isn't too interesting, but we do want the original - # Deferred to have gotten the failure. - results = [] - errors = [] - d.addCallbacks(results.append, errors.append) - self.assertEqual(results, []) - self.assertEqual(len(errors), 1) - errors[0].trap(Exception) - - # Get rid of any references we might have to the inner Deferred (none of - # these should really refer to it, but we're just being safe). - del results, errors, d - # Force a collection cycle so that there's a chance for an error to be - # logged, if it's going to be logged. - gc.collect() - # And make sure it is not. - self.assertEqual(self._loggedErrors(), []) - - - def test_errorClearedByChaining(self): - """ - If a Deferred with a failure result has an errback which chains it to - another Deferred, the initial failure is cleared by the errback so it is - not logged. - """ - # Start off with a Deferred with a failure for a result - bad = defer.fail(Exception("oh no")) - good = defer.Deferred() - # Give it a callback that chains it to another Deferred - bad.addErrback(lambda ignored: good) - # That's all, clean it up. No Deferred here still has a failure result, - # so nothing should be logged. - good = bad = None - gc.collect() - self.assertEqual(self._loggedErrors(), []) - - - -class DeferredListEmptyTests(unittest.SynchronousTestCase): - def setUp(self): - self.callbackRan = 0 - - def testDeferredListEmpty(self): - """Testing empty DeferredList.""" - dl = defer.DeferredList([]) - dl.addCallback(self.cb_empty) - - def cb_empty(self, res): - self.callbackRan = 1 - self.assertEqual([], res) - - def tearDown(self): - self.failUnless(self.callbackRan, "Callback was never run.") - - - -class OtherPrimitivesTests(unittest.SynchronousTestCase, ImmediateFailureMixin): - def _incr(self, result): - self.counter += 1 - - def setUp(self): - self.counter = 0 - - def testLock(self): - lock = defer.DeferredLock() - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 1) - - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 1) - - lock.release() - self.failUnless(lock.locked) - self.assertEqual(self.counter, 2) - - lock.release() - self.failIf(lock.locked) - self.assertEqual(self.counter, 2) - - self.assertRaises(TypeError, lock.run) - - firstUnique = object() - secondUnique = object() - - controlDeferred = defer.Deferred() - def helper(self, b): - self.b = b - return controlDeferred - - resultDeferred = lock.run(helper, self=self, b=firstUnique) - self.failUnless(lock.locked) - self.assertEqual(self.b, firstUnique) - - resultDeferred.addCallback(lambda x: setattr(self, 'result', x)) - - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 2) - - controlDeferred.callback(secondUnique) - self.assertEqual(self.result, secondUnique) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 3) - - d = lock.acquire().addBoth(lambda x: setattr(self, 'result', x)) - d.cancel() - self.assertEqual(self.result.type, defer.CancelledError) - - lock.release() - self.failIf(lock.locked) - - - def test_cancelLockAfterAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredLock} that already - has the lock, the cancel should have no effect. - """ - def _failOnErrback(_): - self.fail("Unexpected errback call!") - lock = defer.DeferredLock() - d = lock.acquire() - d.addErrback(_failOnErrback) - d.cancel() - - - def test_cancelLockBeforeAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredLock} that does not - yet have the lock (i.e., the L{Deferred} has not fired), the cancel - should cause a L{defer.CancelledError} failure. - """ - lock = defer.DeferredLock() - lock.acquire() - d = lock.acquire() - d.cancel() - self.assertImmediateFailure(d, defer.CancelledError) - - - def testSemaphore(self): - N = 13 - sem = defer.DeferredSemaphore(N) - - controlDeferred = defer.Deferred() - def helper(self, arg): - self.arg = arg - return controlDeferred - - results = [] - uniqueObject = object() - resultDeferred = sem.run(helper, self=self, arg=uniqueObject) - resultDeferred.addCallback(results.append) - resultDeferred.addCallback(self._incr) - self.assertEqual(results, []) - self.assertEqual(self.arg, uniqueObject) - controlDeferred.callback(None) - self.assertEqual(results.pop(), None) - self.assertEqual(self.counter, 1) - - self.counter = 0 - for i in range(1, 1 + N): - sem.acquire().addCallback(self._incr) - self.assertEqual(self.counter, i) - - - success = [] - def fail(r): - success.append(False) - def succeed(r): - success.append(True) - d = sem.acquire().addCallbacks(fail, succeed) - d.cancel() - self.assertEqual(success, [True]) - - sem.acquire().addCallback(self._incr) - self.assertEqual(self.counter, N) - - sem.release() - self.assertEqual(self.counter, N + 1) - - for i in range(1, 1 + N): - sem.release() - self.assertEqual(self.counter, N + 1) - - - def test_semaphoreInvalidTokens(self): - """ - If the token count passed to L{DeferredSemaphore} is less than one - then L{ValueError} is raised. - """ - self.assertRaises(ValueError, defer.DeferredSemaphore, 0) - self.assertRaises(ValueError, defer.DeferredSemaphore, -1) - - - def test_cancelSemaphoreAfterAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredSemaphore} that - already has the semaphore, the cancel should have no effect. - """ - def _failOnErrback(_): - self.fail("Unexpected errback call!") - - sem = defer.DeferredSemaphore(1) - d = sem.acquire() - d.addErrback(_failOnErrback) - d.cancel() - - - def test_cancelSemaphoreBeforeAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredSemaphore} that does - not yet have the semaphore (i.e., the L{Deferred} has not fired), - the cancel should cause a L{defer.CancelledError} failure. - """ - sem = defer.DeferredSemaphore(1) - sem.acquire() - d = sem.acquire() - d.cancel() - self.assertImmediateFailure(d, defer.CancelledError) - - - def testQueue(self): - N, M = 2, 2 - queue = defer.DeferredQueue(N, M) - - gotten = [] - - for i in range(M): - queue.get().addCallback(gotten.append) - self.assertRaises(defer.QueueUnderflow, queue.get) - - for i in range(M): - queue.put(i) - self.assertEqual(gotten, list(range(i + 1))) - for i in range(N): - queue.put(N + i) - self.assertEqual(gotten, list(range(M))) - self.assertRaises(defer.QueueOverflow, queue.put, None) - - gotten = [] - for i in range(N): - queue.get().addCallback(gotten.append) - self.assertEqual(gotten, list(range(N, N + i + 1))) - - queue = defer.DeferredQueue() - gotten = [] - for i in range(N): - queue.get().addCallback(gotten.append) - for i in range(N): - queue.put(i) - self.assertEqual(gotten, list(range(N))) - - queue = defer.DeferredQueue(size=0) - self.assertRaises(defer.QueueOverflow, queue.put, None) - - queue = defer.DeferredQueue(backlog=0) - self.assertRaises(defer.QueueUnderflow, queue.get) - - - def test_cancelQueueAfterSynchronousGet(self): - """ - When canceling a L{Deferred} from a L{DeferredQueue} that already has - a result, the cancel should have no effect. - """ - def _failOnErrback(_): - self.fail("Unexpected errback call!") - - queue = defer.DeferredQueue() - d = queue.get() - d.addErrback(_failOnErrback) - queue.put(None) - d.cancel() - - - def test_cancelQueueAfterGet(self): - """ - When canceling a L{Deferred} from a L{DeferredQueue} that does not - have a result (i.e., the L{Deferred} has not fired), the cancel - causes a L{defer.CancelledError} failure. If the queue has a result - later on, it doesn't try to fire the deferred. - """ - queue = defer.DeferredQueue() - d = queue.get() - d.cancel() - self.assertImmediateFailure(d, defer.CancelledError) - def cb(ignore): - # If the deferred is still linked with the deferred queue, it will - # fail with an AlreadyCalledError - queue.put(None) - return queue.get().addCallback(self.assertIdentical, None) - d.addCallback(cb) - done = [] - d.addCallback(done.append) - self.assertEqual(len(done), 1) - - - -class DeferredFilesystemLockTests(unittest.TestCase): - """ - Test the behavior of L{DeferredFilesystemLock} - """ - - def setUp(self): - self.clock = Clock() - self.lock = defer.DeferredFilesystemLock(self.mktemp(), - scheduler=self.clock) - - - def test_waitUntilLockedWithNoLock(self): - """ - Test that the lock can be acquired when no lock is held - """ - d = self.lock.deferUntilLocked(timeout=1) - - return d - - - def test_waitUntilLockedWithTimeoutLocked(self): - """ - Test that the lock can not be acquired when the lock is held - for longer than the timeout. - """ - self.failUnless(self.lock.lock()) - - d = self.lock.deferUntilLocked(timeout=5.5) - self.assertFailure(d, defer.TimeoutError) - - self.clock.pump([1] * 10) - - return d - - - def test_waitUntilLockedWithTimeoutUnlocked(self): - """ - Test that a lock can be acquired while a lock is held - but the lock is unlocked before our timeout. - """ - def onTimeout(f): - f.trap(defer.TimeoutError) - self.fail("Should not have timed out") - - self.failUnless(self.lock.lock()) - - self.clock.callLater(1, self.lock.unlock) - d = self.lock.deferUntilLocked(timeout=10) - d.addErrback(onTimeout) - - self.clock.pump([1] * 10) - - return d - - - def test_defaultScheduler(self): - """ - Test that the default scheduler is set up properly. - """ - lock = defer.DeferredFilesystemLock(self.mktemp()) - - self.assertEqual(lock._scheduler, reactor) - - - def test_concurrentUsage(self): - """ - Test that an appropriate exception is raised when attempting - to use deferUntilLocked concurrently. - """ - self.lock.lock() - self.clock.callLater(1, self.lock.unlock) - - d = self.lock.deferUntilLocked() - d2 = self.lock.deferUntilLocked() - - self.assertFailure(d2, defer.AlreadyTryingToLockError) - - self.clock.advance(1) - - return d - - - def test_multipleUsages(self): - """ - Test that a DeferredFilesystemLock can be used multiple times - """ - def lockAquired(ign): - self.lock.unlock() - d = self.lock.deferUntilLocked() - return d - - self.lock.lock() - self.clock.callLater(1, self.lock.unlock) - - d = self.lock.deferUntilLocked() - d.addCallback(lockAquired) - - self.clock.advance(1) - - return d - - - def test_cancelDeferUntilLocked(self): - """ - When cancelling a L{defer.Deferred} returned by - L{defer.DeferredFilesystemLock.deferUntilLocked}, the - L{defer.DeferredFilesystemLock._tryLockCall} is cancelled. - """ - self.lock.lock() - deferred = self.lock.deferUntilLocked() - tryLockCall = self.lock._tryLockCall - deferred.cancel() - self.assertFalse(tryLockCall.active()) - self.assertEqual(self.lock._tryLockCall, None) - self.failureResultOf(deferred, defer.CancelledError) - - - def test_cancelDeferUntilLockedWithTimeout(self): - """ - When cancel a L{defer.Deferred} returned by - L{defer.DeferredFilesystemLock.deferUntilLocked}, if the timeout is - set, the timeout call will be cancelled. - """ - self.lock.lock() - deferred = self.lock.deferUntilLocked(timeout=1) - timeoutCall = self.lock._timeoutCall - deferred.cancel() - self.assertFalse(timeoutCall.active()) - self.assertEqual(self.lock._timeoutCall, None) - self.failureResultOf(deferred, defer.CancelledError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_defgen.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_defgen.py deleted file mode 100644 index 71d9a0c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_defgen.py +++ /dev/null @@ -1,363 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet.defer.deferredGenerator} and related APIs. -""" - -from __future__ import division, absolute_import - -from twisted.internet import reactor - -from twisted.trial import unittest - -from twisted.internet.defer import waitForDeferred, deferredGenerator, Deferred -from twisted.internet.defer import inlineCallbacks, returnValue -from twisted.internet import defer -from twisted.trial.util import suppress as SUPPRESS -from twisted.python.util import runWithWarningsSuppressed - - -def getThing(): - d = Deferred() - reactor.callLater(0, d.callback, "hi") - return d - -def getOwie(): - d = Deferred() - def CRAP(): - d.errback(ZeroDivisionError('OMG')) - reactor.callLater(0, CRAP) - return d - -# NOTE: most of the tests in DeferredGeneratorTests are duplicated -# with slightly different syntax for the InlineCallbacksTests below. - -class TerminalException(Exception): - pass - -class BaseDefgenTests: - """ - This class sets up a bunch of test cases which will test both - deferredGenerator and inlineCallbacks based generators. The subclasses - DeferredGeneratorTests and InlineCallbacksTests each provide the actual - generator implementations tested. - """ - - def testBasics(self): - """ - Test that a normal deferredGenerator works. Tests yielding a - deferred which callbacks, as well as a deferred errbacks. Also - ensures returning a final value works. - """ - - return self._genBasics().addCallback(self.assertEqual, 'WOOSH') - - def testBuggy(self): - """ - Ensure that a buggy generator properly signals a Failure - condition on result deferred. - """ - return self.assertFailure(self._genBuggy(), ZeroDivisionError) - - def testNothing(self): - """Test that a generator which never yields results in None.""" - - return self._genNothing().addCallback(self.assertEqual, None) - - def testHandledTerminalFailure(self): - """ - Create a Deferred Generator which yields a Deferred which fails and - handles the exception which results. Assert that the Deferred - Generator does not errback its Deferred. - """ - return self._genHandledTerminalFailure().addCallback(self.assertEqual, None) - - def testHandledTerminalAsyncFailure(self): - """ - Just like testHandledTerminalFailure, only with a Deferred which fires - asynchronously with an error. - """ - d = defer.Deferred() - deferredGeneratorResultDeferred = self._genHandledTerminalAsyncFailure(d) - d.errback(TerminalException("Handled Terminal Failure")) - return deferredGeneratorResultDeferred.addCallback( - self.assertEqual, None) - - def testStackUsage(self): - """ - Make sure we don't blow the stack when yielding immediately - available deferreds. - """ - return self._genStackUsage().addCallback(self.assertEqual, 0) - - def testStackUsage2(self): - """ - Make sure we don't blow the stack when yielding immediately - available values. - """ - return self._genStackUsage2().addCallback(self.assertEqual, 0) - - - -def deprecatedDeferredGenerator(f): - """ - Calls L{deferredGenerator} while suppressing the deprecation warning. - - @param f: Function to call - @return: Return value of function. - """ - return runWithWarningsSuppressed( - [ SUPPRESS(message="twisted.internet.defer.deferredGenerator was " - "deprecated") ], - deferredGenerator, f) - - - -class DeferredGeneratorTests(BaseDefgenTests, unittest.TestCase): - - # First provide all the generator impls necessary for BaseDefgenTests - @deprecatedDeferredGenerator - def _genBasics(self): - - x = waitForDeferred(getThing()) - yield x - x = x.getResult() - - self.assertEqual(x, "hi") - - ow = waitForDeferred(getOwie()) - yield ow - try: - ow.getResult() - except ZeroDivisionError as e: - self.assertEqual(str(e), 'OMG') - yield "WOOSH" - return - - - @deprecatedDeferredGenerator - def _genBuggy(self): - yield waitForDeferred(getThing()) - 1//0 - - - @deprecatedDeferredGenerator - def _genNothing(self): - if 0: yield 1 - - - @deprecatedDeferredGenerator - def _genHandledTerminalFailure(self): - x = waitForDeferred(defer.fail(TerminalException("Handled Terminal Failure"))) - yield x - try: - x.getResult() - except TerminalException: - pass - - - @deprecatedDeferredGenerator - def _genHandledTerminalAsyncFailure(self, d): - x = waitForDeferred(d) - yield x - try: - x.getResult() - except TerminalException: - pass - - - def _genStackUsage(self): - for x in range(5000): - # Test with yielding a deferred - x = waitForDeferred(defer.succeed(1)) - yield x - x = x.getResult() - yield 0 - _genStackUsage = deprecatedDeferredGenerator(_genStackUsage) - - def _genStackUsage2(self): - for x in range(5000): - # Test with yielding a random value - yield 1 - yield 0 - _genStackUsage2 = deprecatedDeferredGenerator(_genStackUsage2) - - # Tests unique to deferredGenerator - - def testDeferredYielding(self): - """ - Ensure that yielding a Deferred directly is trapped as an - error. - """ - # See the comment _deferGenerator about d.callback(Deferred). - def _genDeferred(): - yield getThing() - _genDeferred = deprecatedDeferredGenerator(_genDeferred) - - return self.assertFailure(_genDeferred(), TypeError) - - suppress = [ - SUPPRESS(message='twisted.internet.defer.waitForDeferred was ' - 'deprecated') - ] - -class InlineCallbacksTests(BaseDefgenTests, unittest.TestCase): - # First provide all the generator impls necessary for BaseDefgenTests - - def _genBasics(self): - - x = yield getThing() - - self.assertEqual(x, "hi") - - try: - yield getOwie() - except ZeroDivisionError as e: - self.assertEqual(str(e), 'OMG') - returnValue("WOOSH") - _genBasics = inlineCallbacks(_genBasics) - - def _genBuggy(self): - yield getThing() - 1/0 - _genBuggy = inlineCallbacks(_genBuggy) - - - def _genNothing(self): - if 0: yield 1 - _genNothing = inlineCallbacks(_genNothing) - - - def _genHandledTerminalFailure(self): - try: - yield defer.fail(TerminalException("Handled Terminal Failure")) - except TerminalException: - pass - _genHandledTerminalFailure = inlineCallbacks(_genHandledTerminalFailure) - - - def _genHandledTerminalAsyncFailure(self, d): - try: - yield d - except TerminalException: - pass - _genHandledTerminalAsyncFailure = inlineCallbacks( - _genHandledTerminalAsyncFailure) - - - def _genStackUsage(self): - for x in range(5000): - # Test with yielding a deferred - yield defer.succeed(1) - returnValue(0) - _genStackUsage = inlineCallbacks(_genStackUsage) - - def _genStackUsage2(self): - for x in range(5000): - # Test with yielding a random value - yield 1 - returnValue(0) - _genStackUsage2 = inlineCallbacks(_genStackUsage2) - - # Tests unique to inlineCallbacks - - def testYieldNonDeferred(self): - """ - Ensure that yielding a non-deferred passes it back as the - result of the yield expression. - - @return: A L{twisted.internet.defer.Deferred} - @rtype: L{twisted.internet.defer.Deferred} - """ - def _test(): - yield 5 - returnValue(5) - _test = inlineCallbacks(_test) - - return _test().addCallback(self.assertEqual, 5) - - def testReturnNoValue(self): - """Ensure a standard python return results in a None result.""" - def _noReturn(): - yield 5 - return - _noReturn = inlineCallbacks(_noReturn) - - return _noReturn().addCallback(self.assertEqual, None) - - def testReturnValue(self): - """Ensure that returnValue works.""" - def _return(): - yield 5 - returnValue(6) - _return = inlineCallbacks(_return) - - return _return().addCallback(self.assertEqual, 6) - - - def test_nonGeneratorReturn(self): - """ - Ensure that C{TypeError} with a message about L{inlineCallbacks} is - raised when a non-generator returns something other than a generator. - """ - def _noYield(): - return 5 - _noYield = inlineCallbacks(_noYield) - - self.assertIn("inlineCallbacks", - str(self.assertRaises(TypeError, _noYield))) - - - def test_nonGeneratorReturnValue(self): - """ - Ensure that C{TypeError} with a message about L{inlineCallbacks} is - raised when a non-generator calls L{returnValue}. - """ - def _noYield(): - returnValue(5) - _noYield = inlineCallbacks(_noYield) - - self.assertIn("inlineCallbacks", - str(self.assertRaises(TypeError, _noYield))) - - - -class DeprecateDeferredGeneratorTests(unittest.SynchronousTestCase): - """ - Tests that L{DeferredGeneratorTests} and L{waitForDeferred} are - deprecated. - """ - - def test_deferredGeneratorDeprecated(self): - """ - L{deferredGenerator} is deprecated. - """ - @deferredGenerator - def decoratedFunction(): - yield None - - warnings = self.flushWarnings([self.test_deferredGeneratorDeprecated]) - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "twisted.internet.defer.deferredGenerator was deprecated in " - "Twisted 15.0.0; please use " - "twisted.internet.defer.inlineCallbacks instead") - - def test_waitForDeferredDeprecated(self): - """ - L{waitForDeferred} is deprecated. - """ - d = Deferred() - waitForDeferred(d) - - warnings = self.flushWarnings([self.test_waitForDeferredDeprecated]) - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "twisted.internet.defer.waitForDeferred was deprecated in " - "Twisted 15.0.0; please use " - "twisted.internet.defer.inlineCallbacks instead") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_dict.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_dict.py deleted file mode 100644 index bb87267..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_dict.py +++ /dev/null @@ -1,22 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.protocols import dict - -paramString = "\"This is a dqstring \\w\\i\\t\\h boring stuff like: \\\"\" and t\\hes\\\"e are a\\to\\ms" -goodparams = ["This is a dqstring with boring stuff like: \"", "and", "thes\"e", "are", "atoms"] - -class ParamTests(unittest.TestCase): - def testParseParam(self): - """Testing command response handling""" - params = [] - rest = paramString - while 1: - (param, rest) = dict.parseParam(rest) - if param == None: - break - params.append(param) - self.assertEqual(params, goodparams)#, "DictClient.parseParam returns unexpected results") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_dirdbm.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_dirdbm.py deleted file mode 100644 index f3d1f3f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_dirdbm.py +++ /dev/null @@ -1,170 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for dirdbm module. -""" - -import os, shutil, glob - -from twisted.trial import unittest -from twisted.persisted import dirdbm - - - -class DirDbmTests(unittest.TestCase): - - def setUp(self): - self.path = self.mktemp() - self.dbm = dirdbm.open(self.path) - self.items = (('abc', 'foo'), ('/lalal', '\000\001'), ('\000\012', 'baz')) - - - def testAll(self): - k = "//==".decode("base64") - self.dbm[k] = "a" - self.dbm[k] = "a" - self.assertEqual(self.dbm[k], "a") - - - def testRebuildInteraction(self): - from twisted.persisted import dirdbm - from twisted.python import rebuild - - s = dirdbm.Shelf('dirdbm.rebuild.test') - s['key'] = 'value' - rebuild.rebuild(dirdbm) - # print s['key'] - - - def testDbm(self): - d = self.dbm - - # insert keys - keys = [] - values = set() - for k, v in self.items: - d[k] = v - keys.append(k) - values.add(v) - keys.sort() - - # check they exist - for k, v in self.items: - assert d.has_key(k), "has_key() failed" - assert d[k] == v, "database has wrong value" - - # check non existent key - try: - d["XXX"] - except KeyError: - pass - else: - assert 0, "didn't raise KeyError on non-existent key" - - # check keys(), values() and items() - dbkeys = list(d.keys()) - dbvalues = set(d.values()) - dbitems = set(d.items()) - dbkeys.sort() - items = set(self.items) - assert keys == dbkeys, ".keys() output didn't match: %s != %s" % (repr(keys), repr(dbkeys)) - assert values == dbvalues, ".values() output didn't match: %s != %s" % (repr(values), repr(dbvalues)) - assert items == dbitems, "items() didn't match: %s != %s" % (repr(items), repr(dbitems)) - - copyPath = self.mktemp() - d2 = d.copyTo(copyPath) - - copykeys = list(d.keys()) - copyvalues = set(d.values()) - copyitems = set(d.items()) - copykeys.sort() - - assert dbkeys == copykeys, ".copyTo().keys() didn't match: %s != %s" % (repr(dbkeys), repr(copykeys)) - assert dbvalues == copyvalues, ".copyTo().values() didn't match: %s != %s" % (repr(dbvalues), repr(copyvalues)) - assert dbitems == copyitems, ".copyTo().items() didn't match: %s != %s" % (repr(dbkeys), repr(copyitems)) - - d2.clear() - assert len(d2.keys()) == len(d2.values()) == len(d2.items()) == 0, ".clear() failed" - shutil.rmtree(copyPath) - - # delete items - for k, v in self.items: - del d[k] - assert not d.has_key(k), "has_key() even though we deleted it" - assert len(d.keys()) == 0, "database has keys" - assert len(d.values()) == 0, "database has values" - assert len(d.items()) == 0, "database has items" - - - def testModificationTime(self): - import time - # the mtime value for files comes from a different place than the - # gettimeofday() system call. On linux, gettimeofday() can be - # slightly ahead (due to clock drift which gettimeofday() takes into - # account but which open()/write()/close() do not), and if we are - # close to the edge of the next second, time.time() can give a value - # which is larger than the mtime which results from a subsequent - # write(). I consider this a kernel bug, but it is beyond the scope - # of this test. Thus we keep the range of acceptability to 3 seconds time. - # -warner - self.dbm["k"] = "v" - self.assert_(abs(time.time() - self.dbm.getModificationTime("k")) <= 3) - - - def testRecovery(self): - """DirDBM: test recovery from directory after a faked crash""" - k = self.dbm._encode("key1") - f = open(os.path.join(self.path, k + ".rpl"), "wb") - f.write("value") - f.close() - - k2 = self.dbm._encode("key2") - f = open(os.path.join(self.path, k2), "wb") - f.write("correct") - f.close() - f = open(os.path.join(self.path, k2 + ".rpl"), "wb") - f.write("wrong") - f.close() - - f = open(os.path.join(self.path, "aa.new"), "wb") - f.write("deleted") - f.close() - - dbm = dirdbm.DirDBM(self.path) - assert dbm["key1"] == "value" - assert dbm["key2"] == "correct" - assert not glob.glob(os.path.join(self.path, "*.new")) - assert not glob.glob(os.path.join(self.path, "*.rpl")) - - - def test_nonStringKeys(self): - """ - L{dirdbm.DirDBM} operations only support string keys: other types - should raise a C{AssertionError}. This really ought to be a - C{TypeError}, but it'll stay like this for backward compatibility. - """ - self.assertRaises(AssertionError, self.dbm.__setitem__, 2, "3") - try: - self.assertRaises(AssertionError, self.dbm.__setitem__, "2", 3) - except unittest.FailTest: - # dirdbm.Shelf.__setitem__ supports non-string values - self.assertIsInstance(self.dbm, dirdbm.Shelf) - self.assertRaises(AssertionError, self.dbm.__getitem__, 2) - self.assertRaises(AssertionError, self.dbm.__delitem__, 2) - self.assertRaises(AssertionError, self.dbm.has_key, 2) - self.assertRaises(AssertionError, self.dbm.__contains__, 2) - self.assertRaises(AssertionError, self.dbm.getModificationTime, 2) - - - -class ShelfTests(DirDbmTests): - - def setUp(self): - self.path = self.mktemp() - self.dbm = dirdbm.Shelf(self.path) - self.items = (('abc', 'foo'), ('/lalal', '\000\001'), ('\000\012', 'baz'), - ('int', 12), ('float', 12.0), ('tuple', (None, 12))) - - -testCases = [DirDbmTests, ShelfTests] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_doc.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_doc.py deleted file mode 100644 index 14be5a8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_doc.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -import inspect, glob -from os import path - -from twisted.trial import unittest -from twisted.python import reflect -from twisted.python.modules import getModule - - - -def errorInFile(f, line=17, name=''): - """ - Return a filename formatted so emacs will recognize it as an error point - - @param line: Line number in file. Defaults to 17 because that's about how - long the copyright headers are. - """ - return '%s:%d:%s' % (f, line, name) - # return 'File "%s", line %d, in %s' % (f, line, name) - - -class DocCoverageTests(unittest.TestCase): - """ - Looking for docstrings in all modules and packages. - """ - def setUp(self): - self.packageNames = [] - for mod in getModule('twisted').walkModules(): - if mod.isPackage(): - self.packageNames.append(mod.name) - - - def testModules(self): - """ - Looking for docstrings in all modules. - """ - docless = [] - for packageName in self.packageNames: - if packageName in ('twisted.test',): - # because some stuff in here behaves oddly when imported - continue - try: - package = reflect.namedModule(packageName) - except ImportError: - # This is testing doc coverage, not importability. - # (Really, I don't want to deal with the fact that I don't - # have pyserial installed.) - # print e - pass - else: - docless.extend(self.modulesInPackage(packageName, package)) - self.failIf(docless, "No docstrings in module files:\n" - "%s" % ('\n'.join(map(errorInFile, docless)),)) - - - def modulesInPackage(self, packageName, package): - docless = [] - directory = path.dirname(package.__file__) - for modfile in glob.glob(path.join(directory, '*.py')): - moduleName = inspect.getmodulename(modfile) - if moduleName == '__init__': - # These are tested by test_packages. - continue - elif moduleName in ('spelunk_gnome','gtkmanhole'): - # argh special case pygtk evil argh. How does epydoc deal - # with this? - continue - try: - module = reflect.namedModule('.'.join([packageName, - moduleName])) - except Exception: - # print moduleName, "misbehaved:", e - pass - else: - if not inspect.getdoc(module): - docless.append(modfile) - return docless - - - def testPackages(self): - """ - Looking for docstrings in all packages. - """ - docless = [] - for packageName in self.packageNames: - try: - package = reflect.namedModule(packageName) - except Exception: - # This is testing doc coverage, not importability. - # (Really, I don't want to deal with the fact that I don't - # have pyserial installed.) - # print e - pass - else: - if not inspect.getdoc(package): - docless.append(package.__file__.replace('.pyc','.py')) - self.failIf(docless, "No docstrings for package files\n" - "%s" % ('\n'.join(map(errorInFile, docless),))) - - - # This test takes a while and doesn't come close to passing. :( - testModules.skip = "Activate me when you feel like writing docstrings, and fixing GTK crashing bugs." diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_error.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_error.py deleted file mode 100644 index 9918d36..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_error.py +++ /dev/null @@ -1,266 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from __future__ import division, absolute_import - -import socket, errno -from twisted.trial import unittest -from twisted.internet import error -from twisted.python.runtime import platformType - - -class StringificationTests(unittest.SynchronousTestCase): - """Test that the exceptions have useful stringifications. - """ - - listOfTests = [ - #(output, exception[, args[, kwargs]]), - - ("An error occurred binding to an interface.", - error.BindError), - - ("An error occurred binding to an interface: foo.", - error.BindError, ['foo']), - - ("An error occurred binding to an interface: foo bar.", - error.BindError, ['foo', 'bar']), - - ("Couldn't listen on eth0:4242: Foo.", - error.CannotListenError, - ('eth0', 4242, socket.error('Foo'))), - - ("Message is too long to send.", - error.MessageLengthError), - - ("Message is too long to send: foo bar.", - error.MessageLengthError, ['foo', 'bar']), - - ("DNS lookup failed.", - error.DNSLookupError), - - ("DNS lookup failed: foo bar.", - error.DNSLookupError, ['foo', 'bar']), - - ("An error occurred while connecting.", - error.ConnectError), - - ("An error occurred while connecting: someOsError.", - error.ConnectError, ['someOsError']), - - ("An error occurred while connecting: foo.", - error.ConnectError, [], {'string': 'foo'}), - - ("An error occurred while connecting: someOsError: foo.", - error.ConnectError, ['someOsError', 'foo']), - - ("Couldn't bind.", - error.ConnectBindError), - - ("Couldn't bind: someOsError.", - error.ConnectBindError, ['someOsError']), - - ("Couldn't bind: someOsError: foo.", - error.ConnectBindError, ['someOsError', 'foo']), - - ("Hostname couldn't be looked up.", - error.UnknownHostError), - - ("No route to host.", - error.NoRouteError), - - ("Connection was refused by other side.", - error.ConnectionRefusedError), - - ("TCP connection timed out.", - error.TCPTimedOutError), - - ("File used for UNIX socket is no good.", - error.BadFileError), - - ("Service name given as port is unknown.", - error.ServiceNameUnknownError), - - ("User aborted connection.", - error.UserError), - - ("User timeout caused connection failure.", - error.TimeoutError), - - ("An SSL error occurred.", - error.SSLError), - - ("Connection to the other side was lost in a non-clean fashion.", - error.ConnectionLost), - - ("Connection to the other side was lost in a non-clean fashion: foo bar.", - error.ConnectionLost, ['foo', 'bar']), - - ("Connection was closed cleanly.", - error.ConnectionDone), - - ("Connection was closed cleanly: foo bar.", - error.ConnectionDone, ['foo', 'bar']), - - ("Uh.", #TODO nice docstring, you've got there. - error.ConnectionFdescWentAway), - - ("Tried to cancel an already-called event.", - error.AlreadyCalled), - - ("Tried to cancel an already-called event: foo bar.", - error.AlreadyCalled, ['foo', 'bar']), - - ("Tried to cancel an already-cancelled event.", - error.AlreadyCancelled), - - ("Tried to cancel an already-cancelled event: x 2.", - error.AlreadyCancelled, ["x", "2"]), - - ("A process has ended without apparent errors: process finished with exit code 0.", - error.ProcessDone, - [None]), - - ("A process has ended with a probable error condition: process ended.", - error.ProcessTerminated), - - ("A process has ended with a probable error condition: process ended with exit code 42.", - error.ProcessTerminated, - [], - {'exitCode': 42}), - - ("A process has ended with a probable error condition: process ended by signal SIGBUS.", - error.ProcessTerminated, - [], - {'signal': 'SIGBUS'}), - - ("The Connector was not connecting when it was asked to stop connecting.", - error.NotConnectingError), - - ("The Connector was not connecting when it was asked to stop connecting: x 13.", - error.NotConnectingError, ["x", "13"]), - - ("The Port was not listening when it was asked to stop listening.", - error.NotListeningError), - - ("The Port was not listening when it was asked to stop listening: a 12.", - error.NotListeningError, ["a", "12"]), - ] - - def testThemAll(self): - for entry in self.listOfTests: - output = entry[0] - exception = entry[1] - try: - args = entry[2] - except IndexError: - args = () - try: - kwargs = entry[3] - except IndexError: - kwargs = {} - - self.assertEqual( - str(exception(*args, **kwargs)), - output) - - - def test_connectingCancelledError(self): - """ - L{error.ConnectingCancelledError} has an C{address} attribute. - """ - address = object() - e = error.ConnectingCancelledError(address) - self.assertIdentical(e.address, address) - - - -class SubclassingTests(unittest.SynchronousTestCase): - """ - Some exceptions are subclasses of other exceptions. - """ - - def test_connectionLostSubclassOfConnectionClosed(self): - """ - L{error.ConnectionClosed} is a superclass of L{error.ConnectionLost}. - """ - self.assertTrue(issubclass(error.ConnectionLost, - error.ConnectionClosed)) - - - def test_connectionDoneSubclassOfConnectionClosed(self): - """ - L{error.ConnectionClosed} is a superclass of L{error.ConnectionDone}. - """ - self.assertTrue(issubclass(error.ConnectionDone, - error.ConnectionClosed)) - - - def test_invalidAddressErrorSubclassOfValueError(self): - """ - L{ValueError} is a superclass of L{error.InvalidAddressError}. - """ - self.assertTrue(issubclass(error.InvalidAddressError, - ValueError)) - - - - -class GetConnectErrorTests(unittest.SynchronousTestCase): - """ - Given an exception instance thrown by C{socket.connect}, - L{error.getConnectError} returns the appropriate high-level Twisted - exception instance. - """ - - def assertErrnoException(self, errno, expectedClass): - """ - When called with a tuple with the given errno, - L{error.getConnectError} returns an exception which is an instance of - the expected class. - """ - e = (errno, "lalala") - result = error.getConnectError(e) - self.assertCorrectException(errno, "lalala", result, expectedClass) - - - def assertCorrectException(self, errno, message, result, expectedClass): - """ - The given result of L{error.getConnectError} has the given attributes - (C{osError} and C{args}), and is an instance of the given class. - """ - - # Want exact class match, not inherited classes, so no isinstance(): - self.assertEqual(result.__class__, expectedClass) - self.assertEqual(result.osError, errno) - self.assertEqual(result.args, (message,)) - - - def test_errno(self): - """ - L{error.getConnectError} converts based on errno for C{socket.error}. - """ - self.assertErrnoException(errno.ENETUNREACH, error.NoRouteError) - self.assertErrnoException(errno.ECONNREFUSED, error.ConnectionRefusedError) - self.assertErrnoException(errno.ETIMEDOUT, error.TCPTimedOutError) - if platformType == "win32": - self.assertErrnoException(errno.WSAECONNREFUSED, error.ConnectionRefusedError) - self.assertErrnoException(errno.WSAENETUNREACH, error.NoRouteError) - - - def test_gaierror(self): - """ - L{error.getConnectError} converts to a L{error.UnknownHostError} given - a C{socket.gaierror} instance. - """ - result = error.getConnectError(socket.gaierror(12, "hello")) - self.assertCorrectException(12, "hello", result, error.UnknownHostError) - - - def test_nonTuple(self): - """ - L{error.getConnectError} converts to a L{error.ConnectError} given - an argument that cannot be unpacked. - """ - e = Exception() - result = error.getConnectError(e) - self.assertCorrectException(None, e, result, error.ConnectError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_explorer.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_explorer.py deleted file mode 100644 index afa61db..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_explorer.py +++ /dev/null @@ -1,228 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for explorer -""" - -from twisted.trial import unittest - -from twisted.manhole import explorer - -""" -# Tests: - - Get an ObjectLink. Browse ObjectLink.identifier. Is it the same? - - Watch Object. Make sure an ObjectLink is received when: - Call a method. - Set an attribute. - - Have an Object with a setattr class. Watch it. - Do both the navite setattr and the watcher get called? - - Sequences with circular references. Does it blow up? -""" - -class SomeDohickey: - def __init__(self, *a): - self.__dict__['args'] = a - - def bip(self): - return self.args - - -class BrowserTests(unittest.TestCase): - def setUp(self): - self.pool = explorer.explorerPool - self.pool.clear() - self.testThing = ["How many stairs must a man climb down?", - SomeDohickey(42)] - - def test_chain(self): - "Following a chain of Explorers." - xplorer = self.pool.getExplorer(self.testThing, 'testThing') - self.assertEqual(xplorer.id, id(self.testThing)) - self.assertEqual(xplorer.identifier, 'testThing') - - dxplorer = xplorer.get_elements()[1] - self.assertEqual(dxplorer.id, id(self.testThing[1])) - -class Watcher: - zero = 0 - def __init__(self): - self.links = [] - - def receiveBrowserObject(self, olink): - self.links.append(olink) - - def setZero(self): - self.zero = len(self.links) - - def len(self): - return len(self.links) - self.zero - - -class SetattrDohickey: - def __setattr__(self, k, v): - v = list(str(v)) - v.reverse() - self.__dict__[k] = ''.join(v) - -class MiddleMan(SomeDohickey, SetattrDohickey): - pass - -# class TestWatch(unittest.TestCase): -class FIXME_Watch: - def setUp(self): - self.globalNS = globals().copy() - self.localNS = {} - self.browser = explorer.ObjectBrowser(self.globalNS, self.localNS) - self.watcher = Watcher() - - def test_setAttrPlain(self): - "Triggering a watcher response by setting an attribute." - - testThing = SomeDohickey('pencil') - self.browser.watchObject(testThing, 'testThing', - self.watcher.receiveBrowserObject) - self.watcher.setZero() - - testThing.someAttr = 'someValue' - - self.assertEqual(testThing.someAttr, 'someValue') - self.failUnless(self.watcher.len()) - olink = self.watcher.links[-1] - self.assertEqual(olink.id, id(testThing)) - - def test_setAttrChain(self): - "Setting an attribute on a watched object that has __setattr__" - testThing = MiddleMan('pencil') - - self.browser.watchObject(testThing, 'testThing', - self.watcher.receiveBrowserObject) - self.watcher.setZero() - - testThing.someAttr = 'ZORT' - - self.assertEqual(testThing.someAttr, 'TROZ') - self.failUnless(self.watcher.len()) - olink = self.watcher.links[-1] - self.assertEqual(olink.id, id(testThing)) - - - def test_method(self): - "Triggering a watcher response by invoking a method." - - for testThing in (SomeDohickey('pencil'), MiddleMan('pencil')): - self.browser.watchObject(testThing, 'testThing', - self.watcher.receiveBrowserObject) - self.watcher.setZero() - - rval = testThing.bip() - self.assertEqual(rval, ('pencil',)) - - self.failUnless(self.watcher.len()) - olink = self.watcher.links[-1] - self.assertEqual(olink.id, id(testThing)) - - -def function_noArgs(): - "A function which accepts no arguments at all." - return - -def function_simple(a, b, c): - "A function which accepts several arguments." - return a, b, c - -def function_variable(*a, **kw): - "A function which accepts a variable number of args and keywords." - return a, kw - -def function_crazy((alpha, beta), c, d=range(4), **kw): - "A function with a mad crazy signature." - return alpha, beta, c, d, kw - -class BrowseFunctionTests(unittest.TestCase): - - def setUp(self): - self.pool = explorer.explorerPool - self.pool.clear() - - def test_sanity(self): - """Basic checks for browse_function. - - Was the proper type returned? Does it have the right name and ID? - """ - for f_name in ('function_noArgs', 'function_simple', - 'function_variable', 'function_crazy'): - f = eval(f_name) - - xplorer = self.pool.getExplorer(f, f_name) - - self.assertEqual(xplorer.id, id(f)) - - self.failUnless(isinstance(xplorer, explorer.ExplorerFunction)) - - self.assertEqual(xplorer.name, f_name) - - def test_signature_noArgs(self): - """Testing zero-argument function signature. - """ - - xplorer = self.pool.getExplorer(function_noArgs, 'function_noArgs') - - self.assertEqual(len(xplorer.signature), 0) - - def test_signature_simple(self): - """Testing simple function signature. - """ - - xplorer = self.pool.getExplorer(function_simple, 'function_simple') - - expected_signature = ('a','b','c') - - self.assertEqual(xplorer.signature.name, expected_signature) - - def test_signature_variable(self): - """Testing variable-argument function signature. - """ - - xplorer = self.pool.getExplorer(function_variable, - 'function_variable') - - expected_names = ('a','kw') - signature = xplorer.signature - - self.assertEqual(signature.name, expected_names) - self.failUnless(signature.is_varlist(0)) - self.failUnless(signature.is_keyword(1)) - - def test_signature_crazy(self): - """Testing function with crazy signature. - """ - xplorer = self.pool.getExplorer(function_crazy, 'function_crazy') - - signature = xplorer.signature - - # The name of the first argument seems to be indecipherable, - # but make sure it has one (and no default). - self.failUnless(signature.get_name(0)) - self.failUnless(not signature.get_default(0)[0]) - - self.assertEqual(signature.get_name(1), 'c') - - # Get a list of values from a list of ExplorerImmutables. - arg_2_default = map(lambda l: l.value, - signature.get_default(2)[1].get_elements()) - - self.assertEqual(signature.get_name(2), 'd') - self.assertEqual(arg_2_default, range(4)) - - self.assertEqual(signature.get_name(3), 'kw') - self.failUnless(signature.is_keyword(3)) - -if __name__ == '__main__': - unittest.main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_factories.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_factories.py deleted file mode 100644 index 9e0eb41..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_factories.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test code for basic Factory classes. -""" - -from __future__ import division, absolute_import - -import pickle - -from twisted.trial.unittest import TestCase - -from twisted.internet.task import Clock -from twisted.internet.protocol import ReconnectingClientFactory, Protocol - - -class FakeConnector(object): - """ - A fake connector class, to be used to mock connections failed or lost. - """ - - def stopConnecting(self): - pass - - - def connect(self): - pass - - - -class ReconnectingFactoryTests(TestCase): - """ - Tests for L{ReconnectingClientFactory}. - """ - - def test_stopTryingWhenConnected(self): - """ - If a L{ReconnectingClientFactory} has C{stopTrying} called while it is - connected, it does not subsequently attempt to reconnect if the - connection is later lost. - """ - class NoConnectConnector(object): - def stopConnecting(self): - raise RuntimeError("Shouldn't be called, we're connected.") - def connect(self): - raise RuntimeError("Shouldn't be reconnecting.") - - c = ReconnectingClientFactory() - c.protocol = Protocol - # Let's pretend we've connected: - c.buildProtocol(None) - # Now we stop trying, then disconnect: - c.stopTrying() - c.clientConnectionLost(NoConnectConnector(), None) - self.assertFalse(c.continueTrying) - - - def test_stopTryingDoesNotReconnect(self): - """ - Calling stopTrying on a L{ReconnectingClientFactory} doesn't attempt a - retry on any active connector. - """ - class FactoryAwareFakeConnector(FakeConnector): - attemptedRetry = False - - def stopConnecting(self): - """ - Behave as though an ongoing connection attempt has now - failed, and notify the factory of this. - """ - f.clientConnectionFailed(self, None) - - def connect(self): - """ - Record an attempt to reconnect, since this is what we - are trying to avoid. - """ - self.attemptedRetry = True - - f = ReconnectingClientFactory() - f.clock = Clock() - - # simulate an active connection - stopConnecting on this connector should - # be triggered when we call stopTrying - f.connector = FactoryAwareFakeConnector() - f.stopTrying() - - # make sure we never attempted to retry - self.assertFalse(f.connector.attemptedRetry) - self.assertFalse(f.clock.getDelayedCalls()) - - - def test_serializeUnused(self): - """ - A L{ReconnectingClientFactory} which hasn't been used for anything - can be pickled and unpickled and end up with the same state. - """ - original = ReconnectingClientFactory() - reconstituted = pickle.loads(pickle.dumps(original)) - self.assertEqual(original.__dict__, reconstituted.__dict__) - - - def test_serializeWithClock(self): - """ - The clock attribute of L{ReconnectingClientFactory} is not serialized, - and the restored value sets it to the default value, the reactor. - """ - clock = Clock() - original = ReconnectingClientFactory() - original.clock = clock - reconstituted = pickle.loads(pickle.dumps(original)) - self.assertIdentical(reconstituted.clock, None) - - - def test_deserializationResetsParameters(self): - """ - A L{ReconnectingClientFactory} which is unpickled does not have an - L{IConnector} and has its reconnecting timing parameters reset to their - initial values. - """ - factory = ReconnectingClientFactory() - factory.clientConnectionFailed(FakeConnector(), None) - self.addCleanup(factory.stopTrying) - - serialized = pickle.dumps(factory) - unserialized = pickle.loads(serialized) - self.assertEqual(unserialized.connector, None) - self.assertEqual(unserialized._callID, None) - self.assertEqual(unserialized.retries, 0) - self.assertEqual(unserialized.delay, factory.initialDelay) - self.assertEqual(unserialized.continueTrying, True) - - - def test_parametrizedClock(self): - """ - The clock used by L{ReconnectingClientFactory} can be parametrized, so - that one can cleanly test reconnections. - """ - clock = Clock() - factory = ReconnectingClientFactory() - factory.clock = clock - - factory.clientConnectionLost(FakeConnector(), None) - self.assertEqual(len(clock.calls), 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_failure.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_failure.py deleted file mode 100644 index bfb42c5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_failure.py +++ /dev/null @@ -1,989 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for the L{twisted.python.failure} module. -""" - -from __future__ import division, absolute_import - -import re -import sys -import traceback -import pdb -import linecache - -from twisted.python.compat import NativeStringIO, _PY3 -from twisted.python import reflect -from twisted.python import failure - -from twisted.trial.unittest import SynchronousTestCase - - -try: - from twisted.test import raiser -except ImportError: - raiser = None - - - -def getDivisionFailure(*args, **kwargs): - """ - Make a C{Failure} of a divide-by-zero error. - - @param args: Any C{*args} are passed to Failure's constructor. - @param kwargs: Any C{**kwargs} are passed to Failure's constructor. - """ - try: - 1/0 - except: - f = failure.Failure(*args, **kwargs) - return f - - -class FailureTests(SynchronousTestCase): - """ - Tests for L{failure.Failure}. - """ - - def test_failAndTrap(self): - """ - Trapping a L{Failure}. - """ - try: - raise NotImplementedError('test') - except: - f = failure.Failure() - error = f.trap(SystemExit, RuntimeError) - self.assertEqual(error, RuntimeError) - self.assertEqual(f.type, NotImplementedError) - - - def test_trapRaisesCurrentFailure(self): - """ - If the wrapped C{Exception} is not a subclass of one of the - expected types, L{failure.Failure.trap} raises the current - L{failure.Failure} ie C{self}. - """ - exception = ValueError() - try: - raise exception - except: - f = failure.Failure() - untrapped = self.assertRaises(failure.Failure, f.trap, OverflowError) - self.assertIdentical(f, untrapped) - - - if _PY3: - test_trapRaisesCurrentFailure.skip = ( - "In Python3, Failure.trap raises the wrapped Exception " - "instead of the original Failure instance.") - - - def test_trapRaisesWrappedException(self): - """ - If the wrapped C{Exception} is not a subclass of one of the - expected types, L{failure.Failure.trap} raises the wrapped - C{Exception}. - """ - exception = ValueError() - try: - raise exception - except: - f = failure.Failure() - - untrapped = self.assertRaises(ValueError, f.trap, OverflowError) - self.assertIdentical(exception, untrapped) - - - if not _PY3: - test_trapRaisesWrappedException.skip = ( - "In Python2, Failure.trap raises the current Failure instance " - "instead of the wrapped Exception.") - - - def test_failureValueFromFailure(self): - """ - A L{failure.Failure} constructed from another - L{failure.Failure} instance, has its C{value} property set to - the value of that L{failure.Failure} instance. - """ - exception = ValueError() - f1 = failure.Failure(exception) - f2 = failure.Failure(f1) - self.assertIdentical(f2.value, exception) - - - def test_failureValueFromFoundFailure(self): - """ - A L{failure.Failure} constructed without a C{exc_value} - argument, will search for an "original" C{Failure}, and if - found, its value will be used as the value for the new - C{Failure}. - """ - exception = ValueError() - f1 = failure.Failure(exception) - try: - f1.trap(OverflowError) - except: - f2 = failure.Failure() - - self.assertIdentical(f2.value, exception) - - - def assertStartsWith(self, s, prefix): - """ - Assert that C{s} starts with a particular C{prefix}. - - @param s: The input string. - @type s: C{str} - @param prefix: The string that C{s} should start with. - @type prefix: C{str} - """ - self.assertTrue(s.startswith(prefix), - '%r is not the start of %r' % (prefix, s)) - - - def assertEndsWith(self, s, suffix): - """ - Assert that C{s} end with a particular C{suffix}. - - @param s: The input string. - @type s: C{str} - @param suffix: The string that C{s} should end with. - @type suffix: C{str} - """ - self.assertTrue(s.endswith(suffix), - '%r is not the end of %r' % (suffix, s)) - - - def assertTracebackFormat(self, tb, prefix, suffix): - """ - Assert that the C{tb} traceback contains a particular C{prefix} and - C{suffix}. - - @param tb: The traceback string. - @type tb: C{str} - @param prefix: The string that C{tb} should start with. - @type prefix: C{str} - @param suffix: The string that C{tb} should end with. - @type suffix: C{str} - """ - self.assertStartsWith(tb, prefix) - self.assertEndsWith(tb, suffix) - - - def assertDetailedTraceback(self, captureVars=False, cleanFailure=False): - """ - Assert that L{printDetailedTraceback} produces and prints a detailed - traceback. - - The detailed traceback consists of a header:: - - *--- Failure #20 --- - - The body contains the stacktrace:: - - /twisted/trial/_synctest.py:1180: _run(...) - /twisted/python/util.py:1076: runWithWarningsSuppressed(...) - --- --- - /twisted/test/test_failure.py:39: getDivisionFailure(...) - - If C{captureVars} is enabled the body also includes a list of - globals and locals:: - - [ Locals ] - exampleLocalVar : 'xyz' - ... - ( Globals ) - ... - - Or when C{captureVars} is disabled:: - - [Capture of Locals and Globals disabled (use captureVars=True)] - - When C{cleanFailure} is enabled references to other objects are removed - and replaced with strings. - - And finally the footer with the L{Failure}'s value:: - - exceptions.ZeroDivisionError: float division - *--- End of Failure #20 --- - - @param captureVars: Enables L{Failure.captureVars}. - @type captureVars: C{bool} - @param cleanFailure: Enables L{Failure.cleanFailure}. - @type cleanFailure: C{bool} - """ - if captureVars: - exampleLocalVar = 'xyz' - # Silence the linter as this variable is checked via - # the traceback. - exampleLocalVar - - f = getDivisionFailure(captureVars=captureVars) - out = NativeStringIO() - if cleanFailure: - f.cleanFailure() - f.printDetailedTraceback(out) - - tb = out.getvalue() - start = "*--- Failure #%d%s---\n" % (f.count, - (f.pickled and ' (pickled) ') or ' ') - end = "%s: %s\n*--- End of Failure #%s ---\n" % (reflect.qual(f.type), - reflect.safe_str(f.value), f.count) - self.assertTracebackFormat(tb, start, end) - - # Variables are printed on lines with 2 leading spaces. - linesWithVars = [line for line in tb.splitlines() - if line.startswith(' ')] - - if captureVars: - self.assertNotEqual([], linesWithVars) - if cleanFailure: - line = ' exampleLocalVar : "\'xyz\'"' - else: - line = " exampleLocalVar : 'xyz'" - self.assertIn(line, linesWithVars) - else: - self.assertEqual([], linesWithVars) - self.assertIn(' [Capture of Locals and Globals disabled (use ' - 'captureVars=True)]\n', tb) - - - def assertBriefTraceback(self, captureVars=False): - """ - Assert that L{printBriefTraceback} produces and prints a brief - traceback. - - The brief traceback consists of a header:: - - Traceback: : float division - - The body with the stacktrace:: - - /twisted/trial/_synctest.py:1180:_run - /twisted/python/util.py:1076:runWithWarningsSuppressed - - And the footer:: - - --- --- - /twisted/test/test_failure.py:39:getDivisionFailure - - @param captureVars: Enables L{Failure.captureVars}. - @type captureVars: C{bool} - """ - if captureVars: - exampleLocalVar = 'abcde' - # Silence the linter as this variable is checked via - # the traceback. - exampleLocalVar - - f = getDivisionFailure() - out = NativeStringIO() - f.printBriefTraceback(out) - tb = out.getvalue() - stack = '' - for method, filename, lineno, localVars, globalVars in f.frames: - stack += '%s:%s:%s\n' % (filename, lineno, method) - - if _PY3: - zde = "class 'ZeroDivisionError'" - else: - zde = "type 'exceptions.ZeroDivisionError'" - - self.assertTracebackFormat(tb, - "Traceback: <%s>: " % (zde,), - "%s\n%s" % (failure.EXCEPTION_CAUGHT_HERE, stack)) - - if captureVars: - self.assertEqual(None, re.search('exampleLocalVar.*abcde', tb)) - - - def assertDefaultTraceback(self, captureVars=False): - """ - Assert that L{printTraceback} produces and prints a default traceback. - - The default traceback consists of a header:: - - Traceback (most recent call last): - - The body with traceback:: - - File "/twisted/trial/_synctest.py", line 1180, in _run - runWithWarningsSuppressed(suppress, method) - - And the footer:: - - --- --- - File "twisted/test/test_failure.py", line 39, in getDivisionFailure - 1/0 - exceptions.ZeroDivisionError: float division - - @param captureVars: Enables L{Failure.captureVars}. - @type captureVars: C{bool} - """ - if captureVars: - exampleLocalVar = 'xyzzy' - # Silence the linter as this variable is checked via - # the traceback. - exampleLocalVar - - f = getDivisionFailure(captureVars=captureVars) - out = NativeStringIO() - f.printTraceback(out) - tb = out.getvalue() - stack = '' - for method, filename, lineno, localVars, globalVars in f.frames: - stack += ' File "%s", line %s, in %s\n' % (filename, lineno, - method) - stack += ' %s\n' % (linecache.getline( - filename, lineno).strip(),) - - self.assertTracebackFormat(tb, - "Traceback (most recent call last):", - "%s\n%s%s: %s\n" % (failure.EXCEPTION_CAUGHT_HERE, stack, - reflect.qual(f.type), reflect.safe_str(f.value))) - - if captureVars: - self.assertEqual(None, re.search('exampleLocalVar.*xyzzy', tb)) - - - def test_printDetailedTraceback(self): - """ - L{printDetailedTraceback} returns a detailed traceback including the - L{Failure}'s count. - """ - self.assertDetailedTraceback() - - - def test_printBriefTraceback(self): - """ - L{printBriefTraceback} returns a brief traceback. - """ - self.assertBriefTraceback() - - - def test_printTraceback(self): - """ - L{printTraceback} returns a traceback. - """ - self.assertDefaultTraceback() - - - def test_printDetailedTracebackCapturedVars(self): - """ - L{printDetailedTraceback} captures the locals and globals for its - stack frames and adds them to the traceback, when called on a - L{Failure} constructed with C{captureVars=True}. - """ - self.assertDetailedTraceback(captureVars=True) - - - def test_printBriefTracebackCapturedVars(self): - """ - L{printBriefTraceback} returns a brief traceback when called on a - L{Failure} constructed with C{captureVars=True}. - - Local variables on the stack can not be seen in the resulting - traceback. - """ - self.assertBriefTraceback(captureVars=True) - - - def test_printTracebackCapturedVars(self): - """ - L{printTraceback} returns a traceback when called on a L{Failure} - constructed with C{captureVars=True}. - - Local variables on the stack can not be seen in the resulting - traceback. - """ - self.assertDefaultTraceback(captureVars=True) - - - def test_printDetailedTracebackCapturedVarsCleaned(self): - """ - C{printDetailedTraceback} includes information about local variables on - the stack after C{cleanFailure} has been called. - """ - self.assertDetailedTraceback(captureVars=True, cleanFailure=True) - - - def test_invalidFormatFramesDetail(self): - """ - L{failure.format_frames} raises a L{ValueError} if the supplied - C{detail} level is unknown. - """ - self.assertRaises(ValueError, failure.format_frames, None, None, - detail='noisia') - - - def test_ExplictPass(self): - e = RuntimeError() - f = failure.Failure(e) - f.trap(RuntimeError) - self.assertEqual(f.value, e) - - - def _getInnermostFrameLine(self, f): - try: - f.raiseException() - except ZeroDivisionError: - tb = traceback.extract_tb(sys.exc_info()[2]) - return tb[-1][-1] - else: - raise Exception( - "f.raiseException() didn't raise ZeroDivisionError!?") - - - def test_RaiseExceptionWithTB(self): - f = getDivisionFailure() - innerline = self._getInnermostFrameLine(f) - self.assertEqual(innerline, '1/0') - - - def test_stringExceptionConstruction(self): - """ - Constructing a C{Failure} with a string as its exception value raises - a C{TypeError}, as this is no longer supported as of Python 2.6. - """ - exc = self.assertRaises(TypeError, failure.Failure, "ono!") - self.assertIn("Strings are not supported by Failure", str(exc)) - - - def test_ConstructionFails(self): - """ - Creating a Failure with no arguments causes it to try to discover the - current interpreter exception state. If no such state exists, creating - the Failure should raise a synchronous exception. - """ - self.assertRaises(failure.NoCurrentExceptionError, failure.Failure) - - - def test_getTracebackObject(self): - """ - If the C{Failure} has not been cleaned, then C{getTracebackObject} - returns the traceback object that captured in its constructor. - """ - f = getDivisionFailure() - self.assertEqual(f.getTracebackObject(), f.tb) - - - def test_getTracebackObjectFromCaptureVars(self): - """ - C{captureVars=True} has no effect on the result of - C{getTracebackObject}. - """ - try: - 1/0 - except ZeroDivisionError: - noVarsFailure = failure.Failure() - varsFailure = failure.Failure(captureVars=True) - self.assertEqual(noVarsFailure.getTracebackObject(), varsFailure.tb) - - - def test_getTracebackObjectFromClean(self): - """ - If the Failure has been cleaned, then C{getTracebackObject} returns an - object that looks the same to L{traceback.extract_tb}. - """ - f = getDivisionFailure() - expected = traceback.extract_tb(f.getTracebackObject()) - f.cleanFailure() - observed = traceback.extract_tb(f.getTracebackObject()) - self.assertNotEqual(None, expected) - self.assertEqual(expected, observed) - - - def test_getTracebackObjectFromCaptureVarsAndClean(self): - """ - If the Failure was created with captureVars, then C{getTracebackObject} - returns an object that looks the same to L{traceback.extract_tb}. - """ - f = getDivisionFailure(captureVars=True) - expected = traceback.extract_tb(f.getTracebackObject()) - f.cleanFailure() - observed = traceback.extract_tb(f.getTracebackObject()) - self.assertEqual(expected, observed) - - - def test_getTracebackObjectWithoutTraceback(self): - """ - L{failure.Failure}s need not be constructed with traceback objects. If - a C{Failure} has no traceback information at all, C{getTracebackObject} - just returns None. - - None is a good value, because traceback.extract_tb(None) -> []. - """ - f = failure.Failure(Exception("some error")) - self.assertEqual(f.getTracebackObject(), None) - - - def test_tracebackFromExceptionInPython3(self): - """ - If a L{failure.Failure} is constructed with an exception but no - traceback in Python 3, the traceback will be extracted from the - exception's C{__traceback__} attribute. - """ - try: - 1/0 - except: - klass, exception, tb = sys.exc_info() - f = failure.Failure(exception) - self.assertIdentical(f.tb, tb) - - - def test_cleanFailureRemovesTracebackInPython3(self): - """ - L{failure.Failure.cleanFailure} sets the C{__traceback__} attribute of - the exception to C{None} in Python 3. - """ - f = getDivisionFailure() - self.assertNotEqual(f.tb, None) - self.assertIdentical(f.value.__traceback__, f.tb) - f.cleanFailure() - self.assertIdentical(f.value.__traceback__, None) - - if not _PY3: - test_tracebackFromExceptionInPython3.skip = "Python 3 only." - test_cleanFailureRemovesTracebackInPython3.skip = "Python 3 only." - - - -class BrokenStr(Exception): - """ - An exception class the instances of which cannot be presented as strings via - C{str}. - """ - def __str__(self): - # Could raise something else, but there's no point as yet. - raise self - - - -class BrokenExceptionMetaclass(type): - """ - A metaclass for an exception type which cannot be presented as a string via - C{str}. - """ - def __str__(self): - raise ValueError("You cannot make a string out of me.") - - - -class BrokenExceptionType(Exception, object): - """ - The aforementioned exception type which cnanot be presented as a string via - C{str}. - """ - __metaclass__ = BrokenExceptionMetaclass - - - -class GetTracebackTests(SynchronousTestCase): - """ - Tests for L{Failure.getTraceback}. - """ - def _brokenValueTest(self, detail): - """ - Construct a L{Failure} with an exception that raises an exception from - its C{__str__} method and then call C{getTraceback} with the specified - detail and verify that it returns a string. - """ - x = BrokenStr() - f = failure.Failure(x) - traceback = f.getTraceback(detail=detail) - self.assertIsInstance(traceback, str) - - - def test_brokenValueBriefDetail(self): - """ - A L{Failure} might wrap an exception with a C{__str__} method which - raises an exception. In this case, calling C{getTraceback} on the - failure with the C{"brief"} detail does not raise an exception. - """ - self._brokenValueTest("brief") - - - def test_brokenValueDefaultDetail(self): - """ - Like test_brokenValueBriefDetail, but for the C{"default"} detail case. - """ - self._brokenValueTest("default") - - - def test_brokenValueVerboseDetail(self): - """ - Like test_brokenValueBriefDetail, but for the C{"default"} detail case. - """ - self._brokenValueTest("verbose") - - - def _brokenTypeTest(self, detail): - """ - Construct a L{Failure} with an exception type that raises an exception - from its C{__str__} method and then call C{getTraceback} with the - specified detail and verify that it returns a string. - """ - f = failure.Failure(BrokenExceptionType()) - traceback = f.getTraceback(detail=detail) - self.assertIsInstance(traceback, str) - - - def test_brokenTypeBriefDetail(self): - """ - A L{Failure} might wrap an exception the type object of which has a - C{__str__} method which raises an exception. In this case, calling - C{getTraceback} on the failure with the C{"brief"} detail does not raise - an exception. - """ - self._brokenTypeTest("brief") - - - def test_brokenTypeDefaultDetail(self): - """ - Like test_brokenTypeBriefDetail, but for the C{"default"} detail case. - """ - self._brokenTypeTest("default") - - - def test_brokenTypeVerboseDetail(self): - """ - Like test_brokenTypeBriefDetail, but for the C{"verbose"} detail case. - """ - self._brokenTypeTest("verbose") - - - -class FindFailureTests(SynchronousTestCase): - """ - Tests for functionality related to L{Failure._findFailure}. - """ - - def test_findNoFailureInExceptionHandler(self): - """ - Within an exception handler, _findFailure should return - C{None} in case no Failure is associated with the current - exception. - """ - try: - 1/0 - except: - self.assertEqual(failure.Failure._findFailure(), None) - else: - self.fail("No exception raised from 1/0!?") - - - def test_findNoFailure(self): - """ - Outside of an exception handler, _findFailure should return None. - """ - self.assertEqual(sys.exc_info()[-1], None) #environment sanity check - self.assertEqual(failure.Failure._findFailure(), None) - - - def test_findFailure(self): - """ - Within an exception handler, it should be possible to find the - original Failure that caused the current exception (if it was - caused by raiseException). - """ - f = getDivisionFailure() - f.cleanFailure() - try: - f.raiseException() - except: - self.assertEqual(failure.Failure._findFailure(), f) - else: - self.fail("No exception raised from raiseException!?") - - - def test_failureConstructionFindsOriginalFailure(self): - """ - When a Failure is constructed in the context of an exception - handler that is handling an exception raised by - raiseException, the new Failure should be chained to that - original Failure. - """ - f = getDivisionFailure() - f.cleanFailure() - try: - f.raiseException() - except: - newF = failure.Failure() - self.assertEqual(f.getTraceback(), newF.getTraceback()) - else: - self.fail("No exception raised from raiseException!?") - - - def test_failureConstructionWithMungedStackSucceeds(self): - """ - Pyrex and Cython are known to insert fake stack frames so as to give - more Python-like tracebacks. These stack frames with empty code objects - should not break extraction of the exception. - """ - try: - raiser.raiseException() - except raiser.RaiserException: - f = failure.Failure() - self.assertTrue(f.check(raiser.RaiserException)) - else: - self.fail("No exception raised from extension?!") - - - if raiser is None: - skipMsg = "raiser extension not available" - test_failureConstructionWithMungedStackSucceeds.skip = skipMsg - - - -class FormattableTracebackTests(SynchronousTestCase): - """ - Whitebox tests that show that L{failure._Traceback} constructs objects that - can be used by L{traceback.extract_tb}. - - If the objects can be used by L{traceback.extract_tb}, then they can be - formatted using L{traceback.format_tb} and friends. - """ - - def test_singleFrame(self): - """ - A C{_Traceback} object constructed with a single frame should be able - to be passed to L{traceback.extract_tb}, and we should get a singleton - list containing a (filename, lineno, methodname, line) tuple. - """ - tb = failure._Traceback([['method', 'filename.py', 123, {}, {}]]) - # Note that we don't need to test that extract_tb correctly extracts - # the line's contents. In this case, since filename.py doesn't exist, - # it will just use None. - self.assertEqual(traceback.extract_tb(tb), - [('filename.py', 123, 'method', None)]) - - - def test_manyFrames(self): - """ - A C{_Traceback} object constructed with multiple frames should be able - to be passed to L{traceback.extract_tb}, and we should get a list - containing a tuple for each frame. - """ - tb = failure._Traceback([ - ['method1', 'filename.py', 123, {}, {}], - ['method2', 'filename.py', 235, {}, {}]]) - self.assertEqual(traceback.extract_tb(tb), - [('filename.py', 123, 'method1', None), - ('filename.py', 235, 'method2', None)]) - - - -class FrameAttributesTests(SynchronousTestCase): - """ - _Frame objects should possess some basic attributes that qualify them as - fake python Frame objects. - """ - - def test_fakeFrameAttributes(self): - """ - L{_Frame} instances have the C{f_globals} and C{f_locals} attributes - bound to C{dict} instance. They also have the C{f_code} attribute - bound to something like a code object. - """ - frame = failure._Frame("dummyname", "dummyfilename") - self.assertIsInstance(frame.f_globals, dict) - self.assertIsInstance(frame.f_locals, dict) - self.assertIsInstance(frame.f_code, failure._Code) - - - -class DebugModeTests(SynchronousTestCase): - """ - Failure's debug mode should allow jumping into the debugger. - """ - - def setUp(self): - """ - Override pdb.post_mortem so we can make sure it's called. - """ - # Make sure any changes we make are reversed: - post_mortem = pdb.post_mortem - if _PY3: - origInit = failure.Failure.__init__ - else: - origInit = failure.Failure.__dict__['__init__'] - def restore(): - pdb.post_mortem = post_mortem - if _PY3: - failure.Failure.__init__ = origInit - else: - failure.Failure.__dict__['__init__'] = origInit - self.addCleanup(restore) - - self.result = [] - pdb.post_mortem = self.result.append - failure.startDebugMode() - - - def test_regularFailure(self): - """ - If startDebugMode() is called, calling Failure() will first call - pdb.post_mortem with the traceback. - """ - try: - 1/0 - except: - typ, exc, tb = sys.exc_info() - f = failure.Failure() - self.assertEqual(self.result, [tb]) - self.assertEqual(f.captureVars, False) - - - def test_captureVars(self): - """ - If startDebugMode() is called, passing captureVars to Failure() will - not blow up. - """ - try: - 1/0 - except: - typ, exc, tb = sys.exc_info() - f = failure.Failure(captureVars=True) - self.assertEqual(self.result, [tb]) - self.assertEqual(f.captureVars, True) - - - -class ExtendedGeneratorTests(SynchronousTestCase): - """ - Tests C{failure.Failure} support for generator features added in Python 2.5 - """ - - def _throwIntoGenerator(self, f, g): - try: - f.throwExceptionIntoGenerator(g) - except StopIteration: - pass - else: - self.fail("throwExceptionIntoGenerator should have raised " - "StopIteration") - - def test_throwExceptionIntoGenerator(self): - """ - It should be possible to throw the exception that a Failure - represents into a generator. - """ - stuff = [] - def generator(): - try: - yield - except: - stuff.append(sys.exc_info()) - else: - self.fail("Yield should have yielded exception.") - g = generator() - f = getDivisionFailure() - next(g) - self._throwIntoGenerator(f, g) - - self.assertEqual(stuff[0][0], ZeroDivisionError) - self.assertTrue(isinstance(stuff[0][1], ZeroDivisionError)) - - self.assertEqual(traceback.extract_tb(stuff[0][2])[-1][-1], "1/0") - - - def test_findFailureInGenerator(self): - """ - Within an exception handler, it should be possible to find the - original Failure that caused the current exception (if it was - caused by throwExceptionIntoGenerator). - """ - f = getDivisionFailure() - f.cleanFailure() - - foundFailures = [] - def generator(): - try: - yield - except: - foundFailures.append(failure.Failure._findFailure()) - else: - self.fail("No exception sent to generator") - - g = generator() - next(g) - self._throwIntoGenerator(f, g) - - self.assertEqual(foundFailures, [f]) - - - def test_failureConstructionFindsOriginalFailure(self): - """ - When a Failure is constructed in the context of an exception - handler that is handling an exception raised by - throwExceptionIntoGenerator, the new Failure should be chained to that - original Failure. - """ - f = getDivisionFailure() - f.cleanFailure() - - newFailures = [] - - def generator(): - try: - yield - except: - newFailures.append(failure.Failure()) - else: - self.fail("No exception sent to generator") - g = generator() - next(g) - self._throwIntoGenerator(f, g) - - self.assertEqual(len(newFailures), 1) - self.assertEqual(newFailures[0].getTraceback(), f.getTraceback()) - - if _PY3: - # FIXME: https://twistedmatrix.com/trac/ticket/5949 - test_findFailureInGenerator.skip = ( - "Python 3 support to be fixed in #5949") - test_failureConstructionFindsOriginalFailure.skip = ( - "Python 3 support to be fixed in #5949") - - - def test_ambiguousFailureInGenerator(self): - """ - When a generator reraises a different exception, - L{Failure._findFailure} inside the generator should find the reraised - exception rather than original one. - """ - def generator(): - try: - try: - yield - except: - [][1] - except: - self.assertIsInstance(failure.Failure().value, IndexError) - g = generator() - next(g) - f = getDivisionFailure() - self._throwIntoGenerator(f, g) - - - def test_ambiguousFailureFromGenerator(self): - """ - When a generator reraises a different exception, - L{Failure._findFailure} above the generator should find the reraised - exception rather than original one. - """ - def generator(): - try: - yield - except: - [][1] - g = generator() - next(g) - f = getDivisionFailure() - try: - self._throwIntoGenerator(f, g) - except: - self.assertIsInstance(failure.Failure().value, IndexError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_fdesc.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_fdesc.py deleted file mode 100644 index 272d50c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_fdesc.py +++ /dev/null @@ -1,266 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet.fdesc}. -""" - -import os, sys -import errno - -try: - import fcntl -except ImportError: - skip = "not supported on this platform" -else: - from twisted.internet import fdesc - -from twisted.python.util import untilConcludes -from twisted.trial import unittest - - - -class NonBlockingTests(unittest.SynchronousTestCase): - """ - Tests for L{fdesc.setNonBlocking} and L{fdesc.setBlocking}. - """ - - def test_setNonBlocking(self): - """ - L{fdesc.setNonBlocking} sets a file description to non-blocking. - """ - r, w = os.pipe() - self.addCleanup(os.close, r) - self.addCleanup(os.close, w) - self.assertFalse(fcntl.fcntl(r, fcntl.F_GETFL) & os.O_NONBLOCK) - fdesc.setNonBlocking(r) - self.assertTrue(fcntl.fcntl(r, fcntl.F_GETFL) & os.O_NONBLOCK) - - - def test_setBlocking(self): - """ - L{fdesc.setBlocking} sets a file description to blocking. - """ - r, w = os.pipe() - self.addCleanup(os.close, r) - self.addCleanup(os.close, w) - fdesc.setNonBlocking(r) - fdesc.setBlocking(r) - self.assertFalse(fcntl.fcntl(r, fcntl.F_GETFL) & os.O_NONBLOCK) - - - -class ReadWriteTests(unittest.SynchronousTestCase): - """ - Tests for L{fdesc.readFromFD}, L{fdesc.writeToFD}. - """ - - def setUp(self): - """ - Create a non-blocking pipe that can be used in tests. - """ - self.r, self.w = os.pipe() - fdesc.setNonBlocking(self.r) - fdesc.setNonBlocking(self.w) - - - def tearDown(self): - """ - Close pipes. - """ - try: - os.close(self.w) - except OSError: - pass - try: - os.close(self.r) - except OSError: - pass - - - def write(self, d): - """ - Write data to the pipe. - """ - return fdesc.writeToFD(self.w, d) - - - def read(self): - """ - Read data from the pipe. - """ - l = [] - res = fdesc.readFromFD(self.r, l.append) - if res is None: - if l: - return l[0] - else: - return b"" - else: - return res - - - def test_writeAndRead(self): - """ - Test that the number of bytes L{fdesc.writeToFD} reports as written - with its return value are seen by L{fdesc.readFromFD}. - """ - n = self.write(b"hello") - self.failUnless(n > 0) - s = self.read() - self.assertEqual(len(s), n) - self.assertEqual(b"hello"[:n], s) - - - def test_writeAndReadLarge(self): - """ - Similar to L{test_writeAndRead}, but use a much larger string to verify - the behavior for that case. - """ - orig = b"0123456879" * 10000 - written = self.write(orig) - self.failUnless(written > 0) - result = [] - resultlength = 0 - i = 0 - while resultlength < written or i < 50: - result.append(self.read()) - resultlength += len(result[-1]) - # Increment a counter to be sure we'll exit at some point - i += 1 - result = b"".join(result) - self.assertEqual(len(result), written) - self.assertEqual(orig[:written], result) - - - def test_readFromEmpty(self): - """ - Verify that reading from a file descriptor with no data does not raise - an exception and does not result in the callback function being called. - """ - l = [] - result = fdesc.readFromFD(self.r, l.append) - self.assertEqual(l, []) - self.assertEqual(result, None) - - - def test_readFromCleanClose(self): - """ - Test that using L{fdesc.readFromFD} on a cleanly closed file descriptor - returns a connection done indicator. - """ - os.close(self.w) - self.assertEqual(self.read(), fdesc.CONNECTION_DONE) - - - def test_writeToClosed(self): - """ - Verify that writing with L{fdesc.writeToFD} when the read end is closed - results in a connection lost indicator. - """ - os.close(self.r) - self.assertEqual(self.write(b"s"), fdesc.CONNECTION_LOST) - - - def test_readFromInvalid(self): - """ - Verify that reading with L{fdesc.readFromFD} when the read end is - closed results in a connection lost indicator. - """ - os.close(self.r) - self.assertEqual(self.read(), fdesc.CONNECTION_LOST) - - - def test_writeToInvalid(self): - """ - Verify that writing with L{fdesc.writeToFD} when the write end is - closed results in a connection lost indicator. - """ - os.close(self.w) - self.assertEqual(self.write(b"s"), fdesc.CONNECTION_LOST) - - - def test_writeErrors(self): - """ - Test error path for L{fdesc.writeTod}. - """ - oldOsWrite = os.write - def eagainWrite(fd, data): - err = OSError() - err.errno = errno.EAGAIN - raise err - os.write = eagainWrite - try: - self.assertEqual(self.write(b"s"), 0) - finally: - os.write = oldOsWrite - - def eintrWrite(fd, data): - err = OSError() - err.errno = errno.EINTR - raise err - os.write = eintrWrite - try: - self.assertEqual(self.write(b"s"), 0) - finally: - os.write = oldOsWrite - - - -class CloseOnExecTests(unittest.SynchronousTestCase): - """ - Tests for L{fdesc._setCloseOnExec} and L{fdesc._unsetCloseOnExec}. - """ - program = ''' -import os, errno -try: - os.write(%d, b'lul') -except OSError as e: - if e.errno == errno.EBADF: - os._exit(0) - os._exit(5) -except: - os._exit(10) -else: - os._exit(20) -''' - - def _execWithFileDescriptor(self, fObj): - pid = os.fork() - if pid == 0: - try: - os.execv(sys.executable, [sys.executable, '-c', self.program % (fObj.fileno(),)]) - except: - import traceback - traceback.print_exc() - os._exit(30) - else: - # On Linux wait(2) doesn't seem ever able to fail with EINTR but - # POSIX seems to allow it and on OS X it happens quite a lot. - return untilConcludes(os.waitpid, pid, 0)[1] - - - def test_setCloseOnExec(self): - """ - A file descriptor passed to L{fdesc._setCloseOnExec} is not inherited - by a new process image created with one of the exec family of - functions. - """ - with open(self.mktemp(), 'wb') as fObj: - fdesc._setCloseOnExec(fObj.fileno()) - status = self._execWithFileDescriptor(fObj) - self.assertTrue(os.WIFEXITED(status)) - self.assertEqual(os.WEXITSTATUS(status), 0) - - - def test_unsetCloseOnExec(self): - """ - A file descriptor passed to L{fdesc._unsetCloseOnExec} is inherited by - a new process image created with one of the exec family of functions. - """ - with open(self.mktemp(), 'wb') as fObj: - fdesc._setCloseOnExec(fObj.fileno()) - fdesc._unsetCloseOnExec(fObj.fileno()) - status = self._execWithFileDescriptor(fObj) - self.assertTrue(os.WIFEXITED(status)) - self.assertEqual(os.WEXITSTATUS(status), 20) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_finger.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_finger.py deleted file mode 100644 index bcf9fcd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_finger.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.protocols.finger}. -""" - -from twisted.trial import unittest -from twisted.protocols import finger -from twisted.test.proto_helpers import StringTransport - - -class FingerTests(unittest.TestCase): - """ - Tests for L{finger.Finger}. - """ - def setUp(self): - """ - Create and connect a L{finger.Finger} instance. - """ - self.transport = StringTransport() - self.protocol = finger.Finger() - self.protocol.makeConnection(self.transport) - - - def test_simple(self): - """ - When L{finger.Finger} receives a CR LF terminated line, it responds - with the default user status message - that no such user exists. - """ - self.protocol.dataReceived("moshez\r\n") - self.assertEqual( - self.transport.value(), - "Login: moshez\nNo such user\n") - - - def test_simpleW(self): - """ - The behavior for a query which begins with C{"/w"} is the same as the - behavior for one which does not. The user is reported as not existing. - """ - self.protocol.dataReceived("/w moshez\r\n") - self.assertEqual( - self.transport.value(), - "Login: moshez\nNo such user\n") - - - def test_forwarding(self): - """ - When L{finger.Finger} receives a request for a remote user, it responds - with a message rejecting the request. - """ - self.protocol.dataReceived("moshez@example.com\r\n") - self.assertEqual( - self.transport.value(), - "Finger forwarding service denied\n") - - - def test_list(self): - """ - When L{finger.Finger} receives a blank line, it responds with a message - rejecting the request for all online users. - """ - self.protocol.dataReceived("\r\n") - self.assertEqual( - self.transport.value(), - "Finger online list denied\n") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_formmethod.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_formmethod.py deleted file mode 100644 index 41d3601..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_formmethod.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for formmethod module. -""" - -from twisted.trial import unittest - -from twisted.python import formmethod - - -class ArgumentTests(unittest.TestCase): - - def argTest(self, argKlass, testPairs, badValues, *args, **kwargs): - arg = argKlass("name", *args, **kwargs) - for val, result in testPairs: - self.assertEqual(arg.coerce(val), result) - for val in badValues: - self.assertRaises(formmethod.InputError, arg.coerce, val) - - - def test_argument(self): - """ - Test that corce correctly raises NotImplementedError. - """ - arg = formmethod.Argument("name") - self.assertRaises(NotImplementedError, arg.coerce, "") - - - def testString(self): - self.argTest(formmethod.String, [("a", "a"), (1, "1"), ("", "")], ()) - self.argTest(formmethod.String, [("ab", "ab"), ("abc", "abc")], ("2", ""), min=2) - self.argTest(formmethod.String, [("ab", "ab"), ("a", "a")], ("223213", "345x"), max=3) - self.argTest(formmethod.String, [("ab", "ab"), ("add", "add")], ("223213", "x"), min=2, max=3) - - def testInt(self): - self.argTest(formmethod.Integer, [("3", 3), ("-2", -2), ("", None)], ("q", "2.3")) - self.argTest(formmethod.Integer, [("3", 3), ("-2", -2)], ("q", "2.3", ""), allowNone=0) - - def testFloat(self): - self.argTest(formmethod.Float, [("3", 3.0), ("-2.3", -2.3), ("", None)], ("q", "2.3z")) - self.argTest(formmethod.Float, [("3", 3.0), ("-2.3", -2.3)], ("q", "2.3z", ""), - allowNone=0) - - def testChoice(self): - choices = [("a", "apple", "an apple"), - ("b", "banana", "ook")] - self.argTest(formmethod.Choice, [("a", "apple"), ("b", "banana")], - ("c", 1), choices=choices) - - def testFlags(self): - flags = [("a", "apple", "an apple"), - ("b", "banana", "ook")] - self.argTest(formmethod.Flags, - [(["a"], ["apple"]), (["b", "a"], ["banana", "apple"])], - (["a", "c"], ["fdfs"]), - flags=flags) - - def testBoolean(self): - tests = [("yes", 1), ("", 0), ("False", 0), ("no", 0)] - self.argTest(formmethod.Boolean, tests, ()) - - - def test_file(self): - """ - Test the correctness of the coerce function. - """ - arg = formmethod.File("name", allowNone=0) - self.assertEqual(arg.coerce("something"), "something") - self.assertRaises(formmethod.InputError, arg.coerce, None) - arg2 = formmethod.File("name") - self.assertEqual(arg2.coerce(None), None) - - - def testDate(self): - goodTests = { - ("2002", "12", "21"): (2002, 12, 21), - ("1996", "2", "29"): (1996, 2, 29), - ("", "", ""): None, - }.items() - badTests = [("2002", "2", "29"), ("xx", "2", "3"), - ("2002", "13", "1"), ("1999", "12","32"), - ("2002", "1"), ("2002", "2", "3", "4")] - self.argTest(formmethod.Date, goodTests, badTests) - - def testRangedInteger(self): - goodTests = {"0": 0, "12": 12, "3": 3}.items() - badTests = ["-1", "x", "13", "-2000", "3.4"] - self.argTest(formmethod.IntegerRange, goodTests, badTests, 0, 12) - - def testVerifiedPassword(self): - goodTests = {("foo", "foo"): "foo", ("ab", "ab"): "ab"}.items() - badTests = [("ab", "a"), ("12345", "12345"), ("", ""), ("a", "a"), ("a",), ("a", "a", "a")] - self.argTest(formmethod.VerifiedPassword, goodTests, badTests, min=2, max=4) - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ftp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ftp.py deleted file mode 100644 index bbfaf40..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ftp.py +++ /dev/null @@ -1,3535 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -FTP tests. -""" - -import os -import errno -from StringIO import StringIO -import getpass - -from zope.interface import implements -from zope.interface.verify import verifyClass - -from twisted.trial import unittest -from twisted.python.randbytes import insecureRandom -from twisted.cred.portal import IRealm -from twisted.protocols import basic -from twisted.internet import reactor, task, protocol, defer, error -from twisted.internet.interfaces import IConsumer -from twisted.cred.error import UnauthorizedLogin -from twisted.cred import portal, checkers, credentials -from twisted.python import failure, filepath, runtime -from twisted.test import proto_helpers - -from twisted.protocols import ftp, loopback - - -if runtime.platform.isWindows(): - nonPOSIXSkip = "Cannot run on Windows" -else: - nonPOSIXSkip = None - - -class Dummy(basic.LineReceiver): - logname = None - def __init__(self): - self.lines = [] - self.rawData = [] - def connectionMade(self): - self.f = self.factory # to save typing in pdb :-) - def lineReceived(self,line): - self.lines.append(line) - def rawDataReceived(self, data): - self.rawData.append(data) - def lineLengthExceeded(self, line): - pass - - - -class _BufferingProtocol(protocol.Protocol): - def connectionMade(self): - self.buffer = '' - self.d = defer.Deferred() - def dataReceived(self, data): - self.buffer += data - def connectionLost(self, reason): - self.d.callback(self) - - - -class FTPServerTestCase(unittest.TestCase): - """ - Simple tests for an FTP server with the default settings. - - @ivar clientFactory: class used as ftp client. - """ - clientFactory = ftp.FTPClientBasic - userAnonymous = "anonymous" - - def setUp(self): - # Create a directory - self.directory = self.mktemp() - os.mkdir(self.directory) - self.dirPath = filepath.FilePath(self.directory) - - # Start the server - p = portal.Portal(ftp.FTPRealm( - anonymousRoot=self.directory, - userHome=self.directory, - )) - p.registerChecker(checkers.AllowAnonymousAccess(), - credentials.IAnonymous) - - users_checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.username = "test-user" - self.password = "test-password" - users_checker.addUser(self.username, self.password) - p.registerChecker(users_checker, credentials.IUsernamePassword) - - self.factory = ftp.FTPFactory(portal=p, - userAnonymous=self.userAnonymous) - port = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - - # Hook the server's buildProtocol to make the protocol instance - # accessible to tests. - buildProtocol = self.factory.buildProtocol - d1 = defer.Deferred() - def _rememberProtocolInstance(addr): - # Done hooking this. - del self.factory.buildProtocol - - protocol = buildProtocol(addr) - self.serverProtocol = protocol.wrappedProtocol - def cleanupServer(): - if self.serverProtocol.transport is not None: - self.serverProtocol.transport.loseConnection() - self.addCleanup(cleanupServer) - d1.callback(None) - return protocol - self.factory.buildProtocol = _rememberProtocolInstance - - # Connect a client to it - portNum = port.getHost().port - clientCreator = protocol.ClientCreator(reactor, self.clientFactory) - d2 = clientCreator.connectTCP("127.0.0.1", portNum) - def gotClient(client): - self.client = client - self.addCleanup(self.client.transport.loseConnection) - d2.addCallback(gotClient) - return defer.gatherResults([d1, d2]) - - def assertCommandResponse(self, command, expectedResponseLines, - chainDeferred=None): - """Asserts that a sending an FTP command receives the expected - response. - - Returns a Deferred. Optionally accepts a deferred to chain its actions - to. - """ - if chainDeferred is None: - chainDeferred = defer.succeed(None) - - def queueCommand(ignored): - d = self.client.queueStringCommand(command) - def gotResponse(responseLines): - self.assertEqual(expectedResponseLines, responseLines) - return d.addCallback(gotResponse) - return chainDeferred.addCallback(queueCommand) - - def assertCommandFailed(self, command, expectedResponse=None, - chainDeferred=None): - if chainDeferred is None: - chainDeferred = defer.succeed(None) - - def queueCommand(ignored): - return self.client.queueStringCommand(command) - chainDeferred.addCallback(queueCommand) - self.assertFailure(chainDeferred, ftp.CommandFailed) - def failed(exception): - if expectedResponse is not None: - self.assertEqual( - expectedResponse, exception.args[0]) - return chainDeferred.addCallback(failed) - - def _anonymousLogin(self): - d = self.assertCommandResponse( - 'USER anonymous', - ['331 Guest login ok, type your email address as password.']) - return self.assertCommandResponse( - 'PASS test@twistedmatrix.com', - ['230 Anonymous login ok, access restrictions apply.'], - chainDeferred=d) - - def _userLogin(self): - """Authenticates the FTP client using the test account.""" - d = self.assertCommandResponse( - 'USER %s' % (self.username), - ['331 Password required for %s.' % (self.username)]) - return self.assertCommandResponse( - 'PASS %s' % (self.password), - ['230 User logged in, proceed'], - chainDeferred=d) - - - -class FTPAnonymousTests(FTPServerTestCase): - """ - Simple tests for an FTP server with different anonymous username. - The new anonymous username used in this test case is "guest" - """ - userAnonymous = "guest" - - def test_anonymousLogin(self): - """ - Tests whether the changing of the anonymous username is working or not. - The FTP server should not comply about the need of password for the - username 'guest', letting it login as anonymous asking just an email - address as password. - """ - d = self.assertCommandResponse( - 'USER guest', - ['331 Guest login ok, type your email address as password.']) - return self.assertCommandResponse( - 'PASS test@twistedmatrix.com', - ['230 Anonymous login ok, access restrictions apply.'], - chainDeferred=d) - - - -class BasicFTPServerTests(FTPServerTestCase): - def testNotLoggedInReply(self): - """ - When not logged in, most commands other than USER and PASS should - get NOT_LOGGED_IN errors, but some can be called before USER and PASS. - """ - loginRequiredCommandList = ['CDUP', 'CWD', 'LIST', 'MODE', 'PASV', - 'PWD', 'RETR', 'STRU', 'SYST', 'TYPE'] - loginNotRequiredCommandList = ['FEAT'] - - # Issue commands, check responses - def checkFailResponse(exception, command): - failureResponseLines = exception.args[0] - self.failUnless(failureResponseLines[-1].startswith("530"), - "%s - Response didn't start with 530: %r" - % (command, failureResponseLines[-1],)) - - def checkPassResponse(result, command): - result = result[0] - self.failIf(result.startswith("530"), - "%s - Response start with 530: %r" - % (command, result,)) - - deferreds = [] - for command in loginRequiredCommandList: - deferred = self.client.queueStringCommand(command) - self.assertFailure(deferred, ftp.CommandFailed) - deferred.addCallback(checkFailResponse, command) - deferreds.append(deferred) - - for command in loginNotRequiredCommandList: - deferred = self.client.queueStringCommand(command) - deferred.addCallback(checkPassResponse, command) - deferreds.append(deferred) - - return defer.DeferredList(deferreds, fireOnOneErrback=True) - - def testPASSBeforeUSER(self): - """ - Issuing PASS before USER should give an error. - """ - return self.assertCommandFailed( - 'PASS foo', - ["503 Incorrect sequence of commands: " - "USER required before PASS"]) - - def testNoParamsForUSER(self): - """ - Issuing USER without a username is a syntax error. - """ - return self.assertCommandFailed( - 'USER', - ['500 Syntax error: USER requires an argument.']) - - def testNoParamsForPASS(self): - """ - Issuing PASS without a password is a syntax error. - """ - d = self.client.queueStringCommand('USER foo') - return self.assertCommandFailed( - 'PASS', - ['500 Syntax error: PASS requires an argument.'], - chainDeferred=d) - - def testAnonymousLogin(self): - return self._anonymousLogin() - - def testQuit(self): - """ - Issuing QUIT should return a 221 message. - """ - d = self._anonymousLogin() - return self.assertCommandResponse( - 'QUIT', - ['221 Goodbye.'], - chainDeferred=d) - - def testAnonymousLoginDenied(self): - # Reconfigure the server to disallow anonymous access, and to have an - # IUsernamePassword checker that always rejects. - self.factory.allowAnonymous = False - denyAlwaysChecker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.factory.portal.registerChecker(denyAlwaysChecker, - credentials.IUsernamePassword) - - # Same response code as allowAnonymous=True, but different text. - d = self.assertCommandResponse( - 'USER anonymous', - ['331 Password required for anonymous.']) - - # It will be denied. No-one can login. - d = self.assertCommandFailed( - 'PASS test@twistedmatrix.com', - ['530 Sorry, Authentication failed.'], - chainDeferred=d) - - # It's not just saying that. You aren't logged in. - d = self.assertCommandFailed( - 'PWD', - ['530 Please login with USER and PASS.'], - chainDeferred=d) - return d - - - def test_anonymousWriteDenied(self): - """ - When an anonymous user attempts to edit the server-side filesystem, they - will receive a 550 error with a descriptive message. - """ - d = self._anonymousLogin() - return self.assertCommandFailed( - 'MKD newdir', - ['550 Anonymous users are forbidden to change the filesystem'], - chainDeferred=d) - - - def testUnknownCommand(self): - d = self._anonymousLogin() - return self.assertCommandFailed( - 'GIBBERISH', - ["502 Command 'GIBBERISH' not implemented"], - chainDeferred=d) - - def testRETRBeforePORT(self): - d = self._anonymousLogin() - return self.assertCommandFailed( - 'RETR foo', - ["503 Incorrect sequence of commands: " - "PORT or PASV required before RETR"], - chainDeferred=d) - - def testSTORBeforePORT(self): - d = self._anonymousLogin() - return self.assertCommandFailed( - 'STOR foo', - ["503 Incorrect sequence of commands: " - "PORT or PASV required before STOR"], - chainDeferred=d) - - def testBadCommandArgs(self): - d = self._anonymousLogin() - self.assertCommandFailed( - 'MODE z', - ["504 Not implemented for parameter 'z'."], - chainDeferred=d) - self.assertCommandFailed( - 'STRU I', - ["504 Not implemented for parameter 'I'."], - chainDeferred=d) - return d - - def testDecodeHostPort(self): - self.assertEqual(ftp.decodeHostPort('25,234,129,22,100,23'), - ('25.234.129.22', 25623)) - nums = range(6) - for i in range(6): - badValue = list(nums) - badValue[i] = 256 - s = ','.join(map(str, badValue)) - self.assertRaises(ValueError, ftp.decodeHostPort, s) - - - def test_PASV(self): - """ - When the client sends the command C{PASV}, the server responds with a - host and port, and is listening on that port. - """ - # Login - d = self._anonymousLogin() - # Issue a PASV command - d.addCallback(lambda _: self.client.queueStringCommand('PASV')) - def cb(responseLines): - """ - Extract the host and port from the resonse, and - verify the server is listening of the port it claims to be. - """ - host, port = ftp.decodeHostPort(responseLines[-1][4:]) - self.assertEqual(port, self.serverProtocol.dtpPort.getHost().port) - d.addCallback(cb) - # Semi-reasonable way to force cleanup - d.addCallback(lambda _: self.serverProtocol.transport.loseConnection()) - return d - - - def test_SYST(self): - """SYST command will always return UNIX Type: L8""" - d = self._anonymousLogin() - self.assertCommandResponse('SYST', ["215 UNIX Type: L8"], - chainDeferred=d) - return d - - def test_RNFRandRNTO(self): - """ - Sending the RNFR command followed by RNTO, with valid filenames, will - perform a successful rename operation. - """ - # Create user home folder with a 'foo' file. - self.dirPath.child(self.username).createDirectory() - self.dirPath.child(self.username).child('foo').touch() - - d = self._userLogin() - self.assertCommandResponse( - 'RNFR foo', - ["350 Requested file action pending further information."], - chainDeferred=d) - self.assertCommandResponse( - 'RNTO bar', - ["250 Requested File Action Completed OK"], - chainDeferred=d) - - def check_rename(result): - self.assertTrue( - self.dirPath.child(self.username).child('bar').exists()) - return result - - d.addCallback(check_rename) - return d - - def test_RNFRwithoutRNTO(self): - """ - Sending the RNFR command followed by any command other than RNTO - should return an error informing users that RNFR should be followed - by RNTO. - """ - d = self._anonymousLogin() - self.assertCommandResponse( - 'RNFR foo', - ["350 Requested file action pending further information."], - chainDeferred=d) - self.assertCommandFailed( - 'OTHER don-tcare', - ["503 Incorrect sequence of commands: RNTO required after RNFR"], - chainDeferred=d) - return d - - def test_portRangeForwardError(self): - """ - Exceptions other than L{error.CannotListenError} which are raised by - C{listenFactory} should be raised to the caller of L{FTP.getDTPPort}. - """ - def listenFactory(portNumber, factory): - raise RuntimeError() - self.serverProtocol.listenFactory = listenFactory - - self.assertRaises(RuntimeError, self.serverProtocol.getDTPPort, - protocol.Factory()) - - - def test_portRange(self): - """ - L{FTP.passivePortRange} should determine the ports which - L{FTP.getDTPPort} attempts to bind. If no port from that iterator can - be bound, L{error.CannotListenError} should be raised, otherwise the - first successful result from L{FTP.listenFactory} should be returned. - """ - def listenFactory(portNumber, factory): - if portNumber in (22032, 22033, 22034): - raise error.CannotListenError('localhost', portNumber, 'error') - return portNumber - self.serverProtocol.listenFactory = listenFactory - - port = self.serverProtocol.getDTPPort(protocol.Factory()) - self.assertEqual(port, 0) - - self.serverProtocol.passivePortRange = xrange(22032, 65536) - port = self.serverProtocol.getDTPPort(protocol.Factory()) - self.assertEqual(port, 22035) - - self.serverProtocol.passivePortRange = xrange(22032, 22035) - self.assertRaises(error.CannotListenError, - self.serverProtocol.getDTPPort, - protocol.Factory()) - - - def test_portRangeInheritedFromFactory(self): - """ - The L{FTP} instances created by L{ftp.FTPFactory.buildProtocol} have - their C{passivePortRange} attribute set to the same object the - factory's C{passivePortRange} attribute is set to. - """ - portRange = xrange(2017, 2031) - self.factory.passivePortRange = portRange - protocol = self.factory.buildProtocol(None) - self.assertEqual(portRange, protocol.wrappedProtocol.passivePortRange) - - def testFEAT(self): - """ - When the server receives 'FEAT', it should report the list of supported - features. (Additionally, ensure that the server reports various - particular features that are supported by all Twisted FTP servers.) - """ - d = self.client.queueStringCommand('FEAT') - def gotResponse(responseLines): - self.assertEqual('211-Features:', responseLines[0]) - self.assertTrue(' MDTM' in responseLines) - self.assertTrue(' PASV' in responseLines) - self.assertTrue(' TYPE A;I' in responseLines) - self.assertTrue(' SIZE' in responseLines) - self.assertEqual('211 End', responseLines[-1]) - return d.addCallback(gotResponse) - - def testOPTS(self): - """ - When the server receives 'OPTS something', it should report - that the FTP server does not support the option called 'something'. - """ - d = self._anonymousLogin() - self.assertCommandFailed( - 'OPTS something', - ["502 Option 'something' not implemented."], - chainDeferred=d, - ) - return d - - - def test_STORreturnsErrorFromOpen(self): - """ - Any FTP error raised inside STOR while opening the file is returned - to the client. - """ - # We create a folder inside user's home folder and then - # we try to write a file with the same name. - # This will trigger an FTPCmdError. - self.dirPath.child(self.username).createDirectory() - self.dirPath.child(self.username).child('folder').createDirectory() - d = self._userLogin() - - def sendPASV(result): - """ - Send the PASV command required before port. - """ - return self.client.queueStringCommand('PASV') - - def mockDTPInstance(result): - """ - Fake an incoming connection and create a mock DTPInstance so - that PORT command will start processing the request. - """ - self.serverProtocol.dtpFactory.deferred.callback(None) - self.serverProtocol.dtpInstance = object() - return result - - d.addCallback(sendPASV) - d.addCallback(mockDTPInstance) - self.assertCommandFailed( - 'STOR folder', - ["550 folder: is a directory"], - chainDeferred=d, - ) - return d - - - - def test_STORunknownErrorBecomesFileNotFound(self): - """ - Any non FTP error raised inside STOR while opening the file is - converted into FileNotFound error and returned to the client together - with the path. - - The unknown error is logged. - """ - d = self._userLogin() - - def failingOpenForWriting(ignore): - return defer.fail(AssertionError()) - - def sendPASV(result): - """ - Send the PASV command required before port. - """ - return self.client.queueStringCommand('PASV') - - def mockDTPInstance(result): - """ - Fake an incoming connection and create a mock DTPInstance so - that PORT command will start processing the request. - """ - self.serverProtocol.dtpFactory.deferred.callback(None) - self.serverProtocol.dtpInstance = object() - self.serverProtocol.shell.openForWriting = failingOpenForWriting - return result - - def checkLogs(result): - """ - Check that unknown errors are logged. - """ - logs = self.flushLoggedErrors() - self.assertEqual(1, len(logs)) - self.assertIsInstance(logs[0].value, AssertionError) - - d.addCallback(sendPASV) - d.addCallback(mockDTPInstance) - - self.assertCommandFailed( - 'STOR something', - ["550 something: No such file or directory."], - chainDeferred=d, - ) - d.addCallback(checkLogs) - return d - - - -class FTPServerAdvancedClientTests(FTPServerTestCase): - """ - Test FTP server with the L{ftp.FTPClient} class. - """ - clientFactory = ftp.FTPClient - - def test_anonymousSTOR(self): - """ - Try to make an STOR as anonymous, and check that we got a permission - denied error. - """ - def eb(res): - res.trap(ftp.CommandFailed) - self.assertEqual(res.value.args[0][0], - '550 foo: Permission denied.') - d1, d2 = self.client.storeFile('foo') - d2.addErrback(eb) - return defer.gatherResults([d1, d2]) - - def test_STORtransferErrorIsReturned(self): - """ - Any FTP error raised by STOR while transferring the file is returned - to the client. - """ - # Make a failing file writer. - class FailingFileWriter(ftp._FileWriter): - def receive(self): - return defer.fail(ftp.IsADirectoryError("failing_file")) - - def failingSTOR(a, b): - return defer.succeed(FailingFileWriter(None)) - - # Monkey patch the shell so it returns a file writer that will - # fail during transfer. - self.patch(ftp.FTPAnonymousShell, 'openForWriting', failingSTOR) - - def eb(res): - res.trap(ftp.CommandFailed) - logs = self.flushLoggedErrors() - self.assertEqual(1, len(logs)) - self.assertIsInstance(logs[0].value, ftp.IsADirectoryError) - self.assertEqual( - res.value.args[0][0], - "550 failing_file: is a directory") - d1, d2 = self.client.storeFile('failing_file') - d2.addErrback(eb) - return defer.gatherResults([d1, d2]) - - def test_STORunknownTransferErrorBecomesAbort(self): - """ - Any non FTP error raised by STOR while transferring the file is - converted into a critical error and transfer is closed. - - The unknown error is logged. - """ - class FailingFileWriter(ftp._FileWriter): - def receive(self): - return defer.fail(AssertionError()) - - def failingSTOR(a, b): - return defer.succeed(FailingFileWriter(None)) - - # Monkey patch the shell so it returns a file writer that will - # fail during transfer. - self.patch(ftp.FTPAnonymousShell, 'openForWriting', failingSTOR) - - def eb(res): - res.trap(ftp.CommandFailed) - logs = self.flushLoggedErrors() - self.assertEqual(1, len(logs)) - self.assertIsInstance(logs[0].value, AssertionError) - self.assertEqual( - res.value.args[0][0], - "426 Transfer aborted. Data connection closed.") - d1, d2 = self.client.storeFile('failing_file') - d2.addErrback(eb) - return defer.gatherResults([d1, d2]) - - def test_RETRreadError(self): - """ - Any errors during reading a file inside a RETR should be returned to - the client. - """ - # Make a failing file reading. - class FailingFileReader(ftp._FileReader): - def send(self, consumer): - return defer.fail(ftp.IsADirectoryError("blah")) - - def failingRETR(a, b): - return defer.succeed(FailingFileReader(None)) - - # Monkey patch the shell so it returns a file reader that will - # fail. - self.patch(ftp.FTPAnonymousShell, 'openForReading', failingRETR) - - def check_response(failure): - self.flushLoggedErrors() - failure.trap(ftp.CommandFailed) - self.assertEqual( - failure.value.args[0][0], - "125 Data connection already open, starting transfer") - self.assertEqual( - failure.value.args[0][1], - "550 blah: is a directory") - - proto = _BufferingProtocol() - d = self.client.retrieveFile('failing_file', proto) - d.addErrback(check_response) - return d - - - -class FTPServerPasvDataConnectionTests(FTPServerTestCase): - def _makeDataConnection(self, ignored=None): - # Establish a passive data connection (i.e. client connecting to - # server). - d = self.client.queueStringCommand('PASV') - def gotPASV(responseLines): - host, port = ftp.decodeHostPort(responseLines[-1][4:]) - cc = protocol.ClientCreator(reactor, _BufferingProtocol) - return cc.connectTCP('127.0.0.1', port) - return d.addCallback(gotPASV) - - def _download(self, command, chainDeferred=None): - if chainDeferred is None: - chainDeferred = defer.succeed(None) - - chainDeferred.addCallback(self._makeDataConnection) - def queueCommand(downloader): - # wait for the command to return, and the download connection to be - # closed. - d1 = self.client.queueStringCommand(command) - d2 = downloader.d - return defer.gatherResults([d1, d2]) - chainDeferred.addCallback(queueCommand) - - def downloadDone((ignored, downloader)): - return downloader.buffer - return chainDeferred.addCallback(downloadDone) - - def test_LISTEmpty(self): - """ - When listing empty folders, LIST returns an empty response. - """ - d = self._anonymousLogin() - - # No files, so the file listing should be empty - self._download('LIST', chainDeferred=d) - def checkEmpty(result): - self.assertEqual('', result) - return d.addCallback(checkEmpty) - - def test_LISTWithBinLsFlags(self): - """ - LIST ignores requests for folder with names like '-al' and will list - the content of current folder. - """ - os.mkdir(os.path.join(self.directory, 'foo')) - os.mkdir(os.path.join(self.directory, 'bar')) - - # Login - d = self._anonymousLogin() - - self._download('LIST -aL', chainDeferred=d) - - def checkDownload(download): - names = [] - for line in download.splitlines(): - names.append(line.split(' ')[-1]) - self.assertEqual(2, len(names)) - self.assertIn('foo', names) - self.assertIn('bar', names) - - return d.addCallback(checkDownload) - - def test_LISTWithContent(self): - """ - LIST returns all folder's members, each member listed on a separate - line and with name and other details. - """ - os.mkdir(os.path.join(self.directory, 'foo')) - os.mkdir(os.path.join(self.directory, 'bar')) - - # Login - d = self._anonymousLogin() - - # We expect 2 lines because there are two files. - self._download('LIST', chainDeferred=d) - def checkDownload(download): - self.assertEqual(2, len(download[:-2].split('\r\n'))) - d.addCallback(checkDownload) - - # Download a names-only listing. - self._download('NLST ', chainDeferred=d) - def checkDownload(download): - filenames = download[:-2].split('\r\n') - filenames.sort() - self.assertEqual(['bar', 'foo'], filenames) - d.addCallback(checkDownload) - - # Download a listing of the 'foo' subdirectory. 'foo' has no files, so - # the file listing should be empty. - self._download('LIST foo', chainDeferred=d) - def checkDownload(download): - self.assertEqual('', download) - d.addCallback(checkDownload) - - # Change the current working directory to 'foo'. - def chdir(ignored): - return self.client.queueStringCommand('CWD foo') - d.addCallback(chdir) - - # Download a listing from within 'foo', and again it should be empty, - # because LIST uses the working directory by default. - self._download('LIST', chainDeferred=d) - def checkDownload(download): - self.assertEqual('', download) - return d.addCallback(checkDownload) - - - def _listTestHelper(self, command, listOutput, expectedOutput): - """ - Exercise handling by the implementation of I{LIST} or I{NLST} of certain - return values and types from an L{IFTPShell.list} implementation. - - This will issue C{command} and assert that if the L{IFTPShell.list} - implementation includes C{listOutput} as one of the file entries then - the result given to the client is matches C{expectedOutput}. - - @param command: Either C{b"LIST"} or C{b"NLST"} - @type command: L{bytes} - - @param listOutput: A value suitable to be used as an element of the list - returned by L{IFTPShell.list}. Vary the values and types of the - contents to exercise different code paths in the server's handling - of this result. - - @param expectedOutput: A line of output to expect as a result of - C{listOutput} being transformed into a response to the command - issued. - @type expectedOutput: L{bytes} - - @return: A L{Deferred} which fires when the test is done, either with an - L{Failure} if the test failed or with a function object if it - succeeds. The function object is the function which implements - L{IFTPShell.list} (and is useful to make assertions about what - warnings might have been emitted). - @rtype: L{Deferred} - """ - # Login - d = self._anonymousLogin() - - def patchedList(segments, keys=()): - return defer.succeed([listOutput]) - - def loggedIn(result): - self.serverProtocol.shell.list = patchedList - return result - d.addCallback(loggedIn) - - self._download('%s something' % (command,), chainDeferred=d) - - def checkDownload(download): - self.assertEqual(expectedOutput, download) - return patchedList - - return d.addCallback(checkDownload) - - - def test_LISTUnicode(self): - """ - Unicode filenames returned from L{IFTPShell.list} are encoded using - UTF-8 before being sent with the response. - """ - return self._listTestHelper( - "LIST", - (u'my resum\xe9', ( - 0, 1, filepath.Permissions(0777), 0, 0, 'user', 'group')), - 'drwxrwxrwx 0 user group ' - '0 Jan 01 1970 my resum\xc3\xa9\r\n') - - - def test_LISTNonASCIIBytes(self): - """ - When LIST receive a filename as byte string from L{IFTPShell.list} - it will just pass the data to lower level without any change. - """ - return self._listTestHelper( - "LIST", - ('my resum\xc3\xa9', ( - 0, 1, filepath.Permissions(0777), 0, 0, 'user', 'group')), - 'drwxrwxrwx 0 user group ' - '0 Jan 01 1970 my resum\xc3\xa9\r\n') - - - def testManyLargeDownloads(self): - # Login - d = self._anonymousLogin() - - # Download a range of different size files - for size in range(100000, 110000, 500): - fObj = file(os.path.join(self.directory, '%d.txt' % (size,)), 'wb') - fObj.write('x' * size) - fObj.close() - - self._download('RETR %d.txt' % (size,), chainDeferred=d) - def checkDownload(download, size=size): - self.assertEqual(size, len(download)) - d.addCallback(checkDownload) - return d - - - def test_downloadFolder(self): - """ - When RETR is called for a folder, it will fail complaining that - the path is a folder. - """ - # Make a directory in the current working directory - self.dirPath.child('foo').createDirectory() - # Login - d = self._anonymousLogin() - d.addCallback(self._makeDataConnection) - - def retrFolder(downloader): - downloader.transport.loseConnection() - deferred = self.client.queueStringCommand('RETR foo') - return deferred - d.addCallback(retrFolder) - - def failOnSuccess(result): - raise AssertionError('Downloading a folder should not succeed.') - d.addCallback(failOnSuccess) - - def checkError(failure): - failure.trap(ftp.CommandFailed) - self.assertEqual( - ['550 foo: is a directory'], failure.value.message) - current_errors = self.flushLoggedErrors() - self.assertEqual( - 0, len(current_errors), - 'No errors should be logged while downloading a folder.') - d.addErrback(checkError) - return d - - - def test_NLSTEmpty(self): - """ - NLST with no argument returns the directory listing for the current - working directory. - """ - # Login - d = self._anonymousLogin() - - # Touch a file in the current working directory - self.dirPath.child('test.txt').touch() - # Make a directory in the current working directory - self.dirPath.child('foo').createDirectory() - - self._download('NLST ', chainDeferred=d) - def checkDownload(download): - filenames = download[:-2].split('\r\n') - filenames.sort() - self.assertEqual(['foo', 'test.txt'], filenames) - return d.addCallback(checkDownload) - - - def test_NLSTNonexistent(self): - """ - NLST on a non-existent file/directory returns nothing. - """ - # Login - d = self._anonymousLogin() - - self._download('NLST nonexistent.txt', chainDeferred=d) - def checkDownload(download): - self.assertEqual('', download) - return d.addCallback(checkDownload) - - - def test_NLSTUnicode(self): - """ - NLST will receive Unicode filenames for IFTPShell.list, and will - encode them using UTF-8. - """ - return self._listTestHelper( - "NLST", - (u'my resum\xe9', ( - 0, 1, filepath.Permissions(0777), 0, 0, 'user', 'group')), - 'my resum\xc3\xa9\r\n') - - - def test_NLSTNonASCIIBytes(self): - """ - NLST will just pass the non-Unicode data to lower level. - """ - return self._listTestHelper( - "NLST", - ('my resum\xc3\xa9', ( - 0, 1, filepath.Permissions(0777), 0, 0, 'user', 'group')), - 'my resum\xc3\xa9\r\n') - - - def test_NLSTOnPathToFile(self): - """ - NLST on an existent file returns only the path to that file. - """ - # Login - d = self._anonymousLogin() - - # Touch a file in the current working directory - self.dirPath.child('test.txt').touch() - - self._download('NLST test.txt', chainDeferred=d) - - def checkDownload(download): - filenames = download[:-2].split('\r\n') - self.assertEqual(['test.txt'], filenames) - return d.addCallback(checkDownload) - - - -class FTPServerPortDataConnectionTests(FTPServerPasvDataConnectionTests): - def setUp(self): - self.dataPorts = [] - return FTPServerPasvDataConnectionTests.setUp(self) - - def _makeDataConnection(self, ignored=None): - # Establish an active data connection (i.e. server connecting to - # client). - deferred = defer.Deferred() - class DataFactory(protocol.ServerFactory): - protocol = _BufferingProtocol - def buildProtocol(self, addr): - p = protocol.ServerFactory.buildProtocol(self, addr) - reactor.callLater(0, deferred.callback, p) - return p - dataPort = reactor.listenTCP(0, DataFactory(), interface='127.0.0.1') - self.dataPorts.append(dataPort) - cmd = 'PORT ' + ftp.encodeHostPort('127.0.0.1', dataPort.getHost().port) - self.client.queueStringCommand(cmd) - return deferred - - def tearDown(self): - l = [defer.maybeDeferred(port.stopListening) for port in self.dataPorts] - d = defer.maybeDeferred( - FTPServerPasvDataConnectionTests.tearDown, self) - l.append(d) - return defer.DeferredList(l, fireOnOneErrback=True) - - def testPORTCannotConnect(self): - # Login - d = self._anonymousLogin() - - # Listen on a port, and immediately stop listening as a way to find a - # port number that is definitely closed. - def loggedIn(ignored): - port = reactor.listenTCP(0, protocol.Factory(), - interface='127.0.0.1') - portNum = port.getHost().port - d = port.stopListening() - d.addCallback(lambda _: portNum) - return d - d.addCallback(loggedIn) - - # Tell the server to connect to that port with a PORT command, and - # verify that it fails with the right error. - def gotPortNum(portNum): - return self.assertCommandFailed( - 'PORT ' + ftp.encodeHostPort('127.0.0.1', portNum), - ["425 Can't open data connection."]) - return d.addCallback(gotPortNum) - - - def test_nlstGlobbing(self): - """ - When Unix shell globbing is used with NLST only files matching the - pattern will be returned. - """ - self.dirPath.child('test.txt').touch() - self.dirPath.child('ceva.txt').touch() - self.dirPath.child('no.match').touch() - d = self._anonymousLogin() - - self._download('NLST *.txt', chainDeferred=d) - - def checkDownload(download): - filenames = download[:-2].split('\r\n') - filenames.sort() - self.assertEqual(['ceva.txt', 'test.txt'], filenames) - - return d.addCallback(checkDownload) - - - -class DTPFactoryTests(unittest.TestCase): - """ - Tests for L{ftp.DTPFactory}. - """ - def setUp(self): - """ - Create a fake protocol interpreter and a L{ftp.DTPFactory} instance to - test. - """ - self.reactor = task.Clock() - - class ProtocolInterpreter(object): - dtpInstance = None - - self.protocolInterpreter = ProtocolInterpreter() - self.factory = ftp.DTPFactory( - self.protocolInterpreter, None, self.reactor) - - - def test_setTimeout(self): - """ - L{ftp.DTPFactory.setTimeout} uses the reactor passed to its initializer - to set up a timed event to time out the DTP setup after the specified - number of seconds. - """ - # Make sure the factory's deferred fails with the right exception, and - # make it so we can tell exactly when it fires. - finished = [] - d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) - d.addCallback(finished.append) - - self.factory.setTimeout(6) - - # Advance the clock almost to the timeout - self.reactor.advance(5) - - # Nothing should have happened yet. - self.assertFalse(finished) - - # Advance it to the configured timeout. - self.reactor.advance(1) - - # Now the Deferred should have failed with TimeoutError. - self.assertTrue(finished) - - # There should also be no calls left in the reactor. - self.assertFalse(self.reactor.calls) - - - def test_buildProtocolOnce(self): - """ - A L{ftp.DTPFactory} instance's C{buildProtocol} method can be used once - to create a L{ftp.DTP} instance. - """ - protocol = self.factory.buildProtocol(None) - self.assertIsInstance(protocol, ftp.DTP) - - # A subsequent call returns None. - self.assertIdentical(self.factory.buildProtocol(None), None) - - - def test_timeoutAfterConnection(self): - """ - If a timeout has been set up using L{ftp.DTPFactory.setTimeout}, it is - cancelled by L{ftp.DTPFactory.buildProtocol}. - """ - self.factory.setTimeout(10) - self.factory.buildProtocol(None) - # Make sure the call is no longer active. - self.assertFalse(self.reactor.calls) - - - def test_connectionAfterTimeout(self): - """ - If L{ftp.DTPFactory.buildProtocol} is called after the timeout - specified by L{ftp.DTPFactory.setTimeout} has elapsed, C{None} is - returned. - """ - # Handle the error so it doesn't get logged. - d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) - - # Set up the timeout and then cause it to elapse so the Deferred does - # fail. - self.factory.setTimeout(10) - self.reactor.advance(10) - - # Try to get a protocol - we should not be able to. - self.assertIdentical(self.factory.buildProtocol(None), None) - - # Make sure the Deferred is doing the right thing. - return d - - - def test_timeoutAfterConnectionFailed(self): - """ - L{ftp.DTPFactory.deferred} fails with L{PortConnectionError} when - L{ftp.DTPFactory.clientConnectionFailed} is called. If the timeout - specified with L{ftp.DTPFactory.setTimeout} expires after that, nothing - additional happens. - """ - finished = [] - d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) - d.addCallback(finished.append) - - self.factory.setTimeout(10) - self.assertFalse(finished) - self.factory.clientConnectionFailed(None, None) - self.assertTrue(finished) - self.reactor.advance(10) - return d - - - def test_connectionFailedAfterTimeout(self): - """ - If L{ftp.DTPFactory.clientConnectionFailed} is called after the timeout - specified by L{ftp.DTPFactory.setTimeout} has elapsed, nothing beyond - the normal timeout before happens. - """ - # Handle the error so it doesn't get logged. - d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) - - # Set up the timeout and then cause it to elapse so the Deferred does - # fail. - self.factory.setTimeout(10) - self.reactor.advance(10) - - # Now fail the connection attempt. This should do nothing. In - # particular, it should not raise an exception. - self.factory.clientConnectionFailed(None, defer.TimeoutError("foo")) - - # Give the Deferred to trial so it can make sure it did what we - # expected. - return d - - - -class DTPTests(unittest.TestCase): - """ - Tests for L{ftp.DTP}. - - The DTP instances in these tests are generated using - DTPFactory.buildProtocol() - """ - - def setUp(self): - """ - Create a fake protocol interpreter, a L{ftp.DTPFactory} instance, - and dummy transport to help with tests. - """ - self.reactor = task.Clock() - - class ProtocolInterpreter(object): - dtpInstance = None - - self.protocolInterpreter = ProtocolInterpreter() - self.factory = ftp.DTPFactory( - self.protocolInterpreter, None, self.reactor) - self.transport = proto_helpers.StringTransportWithDisconnection() - - - def test_sendLineNewline(self): - """ - L{ftp.DTP.sendLine} writes the line passed to it plus a line delimiter - to its transport. - """ - dtpInstance = self.factory.buildProtocol(None) - dtpInstance.makeConnection(self.transport) - lineContent = 'line content' - - dtpInstance.sendLine(lineContent) - - dataSent = self.transport.value() - self.assertEqual(lineContent + '\r\n', dataSent) - - - -# -- Client Tests ----------------------------------------------------------- - -class PrintLines(protocol.Protocol): - """Helper class used by FTPFileListingTests.""" - - def __init__(self, lines): - self._lines = lines - - def connectionMade(self): - for line in self._lines: - self.transport.write(line + "\r\n") - self.transport.loseConnection() - - - -class MyFTPFileListProtocol(ftp.FTPFileListProtocol): - def __init__(self): - self.other = [] - ftp.FTPFileListProtocol.__init__(self) - - def unknownLine(self, line): - self.other.append(line) - - - -class FTPFileListingTests(unittest.TestCase): - def getFilesForLines(self, lines): - fileList = MyFTPFileListProtocol() - d = loopback.loopbackAsync(PrintLines(lines), fileList) - d.addCallback(lambda _: (fileList.files, fileList.other)) - return d - - def testOneLine(self): - # This example line taken from the docstring for FTPFileListProtocol - line = '-rw-r--r-- 1 root other 531 Jan 29 03:26 README' - def check(((file,), other)): - self.failIf(other, 'unexpect unparsable lines: %s' % repr(other)) - self.failUnless(file['filetype'] == '-', 'misparsed fileitem') - self.failUnless(file['perms'] == 'rw-r--r--', 'misparsed perms') - self.failUnless(file['owner'] == 'root', 'misparsed fileitem') - self.failUnless(file['group'] == 'other', 'misparsed fileitem') - self.failUnless(file['size'] == 531, 'misparsed fileitem') - self.failUnless(file['date'] == 'Jan 29 03:26', 'misparsed fileitem') - self.failUnless(file['filename'] == 'README', 'misparsed fileitem') - self.failUnless(file['nlinks'] == 1, 'misparsed nlinks') - self.failIf(file['linktarget'], 'misparsed linktarget') - return self.getFilesForLines([line]).addCallback(check) - - def testVariantLines(self): - line1 = 'drw-r--r-- 2 root other 531 Jan 9 2003 A' - line2 = 'lrw-r--r-- 1 root other 1 Jan 29 03:26 B -> A' - line3 = 'woohoo! ' - def check(((file1, file2), (other,))): - self.failUnless(other == 'woohoo! \r', 'incorrect other line') - # file 1 - self.failUnless(file1['filetype'] == 'd', 'misparsed fileitem') - self.failUnless(file1['perms'] == 'rw-r--r--', 'misparsed perms') - self.failUnless(file1['owner'] == 'root', 'misparsed owner') - self.failUnless(file1['group'] == 'other', 'misparsed group') - self.failUnless(file1['size'] == 531, 'misparsed size') - self.failUnless(file1['date'] == 'Jan 9 2003', 'misparsed date') - self.failUnless(file1['filename'] == 'A', 'misparsed filename') - self.failUnless(file1['nlinks'] == 2, 'misparsed nlinks') - self.failIf(file1['linktarget'], 'misparsed linktarget') - # file 2 - self.failUnless(file2['filetype'] == 'l', 'misparsed fileitem') - self.failUnless(file2['perms'] == 'rw-r--r--', 'misparsed perms') - self.failUnless(file2['owner'] == 'root', 'misparsed owner') - self.failUnless(file2['group'] == 'other', 'misparsed group') - self.failUnless(file2['size'] == 1, 'misparsed size') - self.failUnless(file2['date'] == 'Jan 29 03:26', 'misparsed date') - self.failUnless(file2['filename'] == 'B', 'misparsed filename') - self.failUnless(file2['nlinks'] == 1, 'misparsed nlinks') - self.failUnless(file2['linktarget'] == 'A', 'misparsed linktarget') - return self.getFilesForLines([line1, line2, line3]).addCallback(check) - - def testUnknownLine(self): - def check((files, others)): - self.failIf(files, 'unexpected file entries') - self.failUnless(others == ['ABC\r', 'not a file\r'], - 'incorrect unparsable lines: %s' % repr(others)) - return self.getFilesForLines(['ABC', 'not a file']).addCallback(check) - - def test_filenameWithUnescapedSpace(self): - ''' - Will parse filenames and linktargets containing unescaped - space characters. - ''' - line1 = 'drw-r--r-- 2 root other 531 Jan 9 2003 A B' - line2 = ( - 'lrw-r--r-- 1 root other 1 Jan 29 03:26 ' - 'B A -> D C/A B' - ) - - def check((files, others)): - self.assertEqual([], others, 'unexpected others entries') - self.assertEqual( - 'A B', files[0]['filename'], 'misparsed filename') - self.assertEqual( - 'B A', files[1]['filename'], 'misparsed filename') - self.assertEqual( - 'D C/A B', files[1]['linktarget'], 'misparsed linktarget') - return self.getFilesForLines([line1, line2]).addCallback(check) - - def test_filenameWithEscapedSpace(self): - ''' - Will parse filenames and linktargets containing escaped - space characters. - ''' - line1 = 'drw-r--r-- 2 root other 531 Jan 9 2003 A\ B' - line2 = ( - 'lrw-r--r-- 1 root other 1 Jan 29 03:26 ' - 'B A -> D\ C/A B' - ) - - def check((files, others)): - self.assertEqual([], others, 'unexpected others entries') - self.assertEqual( - 'A B', files[0]['filename'], 'misparsed filename') - self.assertEqual( - 'B A', files[1]['filename'], 'misparsed filename') - self.assertEqual( - 'D C/A B', files[1]['linktarget'], 'misparsed linktarget') - return self.getFilesForLines([line1, line2]).addCallback(check) - - def testYear(self): - # This example derived from bug description in issue 514. - fileList = ftp.FTPFileListProtocol() - exampleLine = ( - '-rw-r--r-- 1 root other 531 Jan 29 2003 README\n') - class PrintLine(protocol.Protocol): - def connectionMade(self): - self.transport.write(exampleLine) - self.transport.loseConnection() - - def check(ignored): - file = fileList.files[0] - self.failUnless(file['size'] == 531, 'misparsed fileitem') - self.failUnless(file['date'] == 'Jan 29 2003', 'misparsed fileitem') - self.failUnless(file['filename'] == 'README', 'misparsed fileitem') - - d = loopback.loopbackAsync(PrintLine(), fileList) - return d.addCallback(check) - - - -class FTPClientFailedRETRAndErrbacksUponDisconnectTests(unittest.TestCase): - - def testFailedRETR(self): - f = protocol.Factory() - f.noisy = 0 - port = reactor.listenTCP(0, f, interface="127.0.0.1") - self.addCleanup(port.stopListening) - portNum = port.getHost().port - # This test data derived from a bug report by ranty on #twisted - responses = ['220 ready, dude (vsFTPd 1.0.0: beat me, break me)', - # USER anonymous - '331 Please specify the password.', - # PASS twisted@twistedmatrix.com - '230 Login successful. Have fun.', - # TYPE I - '200 Binary it is, then.', - # PASV - '227 Entering Passive Mode (127,0,0,1,%d,%d)' % - (portNum >> 8, portNum & 0xff), - # RETR /file/that/doesnt/exist - '550 Failed to open file.'] - f.buildProtocol = lambda addr: PrintLines(responses) - - cc = protocol.ClientCreator(reactor, ftp.FTPClient, passive=1) - d = cc.connectTCP('127.0.0.1', portNum) - def gotClient(client): - p = protocol.Protocol() - return client.retrieveFile('/file/that/doesnt/exist', p) - d.addCallback(gotClient) - return self.assertFailure(d, ftp.CommandFailed) - - def test_errbacksUponDisconnect(self): - """ - Test the ftp command errbacks when a connection lost happens during - the operation. - """ - ftpClient = ftp.FTPClient() - tr = proto_helpers.StringTransportWithDisconnection() - ftpClient.makeConnection(tr) - tr.protocol = ftpClient - d = ftpClient.list('some path', Dummy()) - m = [] - def _eb(failure): - m.append(failure) - return None - d.addErrback(_eb) - from twisted.internet.main import CONNECTION_LOST - ftpClient.connectionLost(failure.Failure(CONNECTION_LOST)) - self.failUnless(m, m) - return d - - - -class FTPClientTests(unittest.TestCase): - """ - Test advanced FTP client commands. - """ - def setUp(self): - """ - Create a FTP client and connect it to fake transport. - """ - self.client = ftp.FTPClient() - self.transport = proto_helpers.StringTransportWithDisconnection() - self.client.makeConnection(self.transport) - self.transport.protocol = self.client - - - def tearDown(self): - """ - Deliver disconnection notification to the client so that it can - perform any cleanup which may be required. - """ - self.client.connectionLost(error.ConnectionLost()) - - - def _testLogin(self): - """ - Test the login part. - """ - self.assertEqual(self.transport.value(), '') - self.client.lineReceived( - '331 Guest login ok, type your email address as password.') - self.assertEqual(self.transport.value(), 'USER anonymous\r\n') - self.transport.clear() - self.client.lineReceived( - '230 Anonymous login ok, access restrictions apply.') - self.assertEqual(self.transport.value(), 'TYPE I\r\n') - self.transport.clear() - self.client.lineReceived('200 Type set to I.') - - - def test_CDUP(self): - """ - Test the CDUP command. - - L{ftp.FTPClient.cdup} should return a Deferred which fires with a - sequence of one element which is the string the server sent - indicating that the command was executed successfully. - - (XXX - This is a bad API) - """ - def cbCdup(res): - self.assertEqual(res[0], '250 Requested File Action Completed OK') - - self._testLogin() - d = self.client.cdup().addCallback(cbCdup) - self.assertEqual(self.transport.value(), 'CDUP\r\n') - self.transport.clear() - self.client.lineReceived('250 Requested File Action Completed OK') - return d - - - def test_failedCDUP(self): - """ - Test L{ftp.FTPClient.cdup}'s handling of a failed CDUP command. - - When the CDUP command fails, the returned Deferred should errback - with L{ftp.CommandFailed}. - """ - self._testLogin() - d = self.client.cdup() - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'CDUP\r\n') - self.transport.clear() - self.client.lineReceived('550 ..: No such file or directory') - return d - - - def test_PWD(self): - """ - Test the PWD command. - - L{ftp.FTPClient.pwd} should return a Deferred which fires with a - sequence of one element which is a string representing the current - working directory on the server. - - (XXX - This is a bad API) - """ - def cbPwd(res): - self.assertEqual(ftp.parsePWDResponse(res[0]), "/bar/baz") - - self._testLogin() - d = self.client.pwd().addCallback(cbPwd) - self.assertEqual(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('257 "/bar/baz"') - return d - - - def test_failedPWD(self): - """ - Test a failure in PWD command. - - When the PWD command fails, the returned Deferred should errback - with L{ftp.CommandFailed}. - """ - self._testLogin() - d = self.client.pwd() - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('550 /bar/baz: No such file or directory') - return d - - - def test_CWD(self): - """ - Test the CWD command. - - L{ftp.FTPClient.cwd} should return a Deferred which fires with a - sequence of one element which is the string the server sent - indicating that the command was executed successfully. - - (XXX - This is a bad API) - """ - def cbCwd(res): - self.assertEqual(res[0], '250 Requested File Action Completed OK') - - self._testLogin() - d = self.client.cwd("bar/foo").addCallback(cbCwd) - self.assertEqual(self.transport.value(), 'CWD bar/foo\r\n') - self.client.lineReceived('250 Requested File Action Completed OK') - return d - - - def test_failedCWD(self): - """ - Test a failure in CWD command. - - When the PWD command fails, the returned Deferred should errback - with L{ftp.CommandFailed}. - """ - self._testLogin() - d = self.client.cwd("bar/foo") - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'CWD bar/foo\r\n') - self.client.lineReceived('550 bar/foo: No such file or directory') - return d - - - def test_passiveRETR(self): - """ - Test the RETR command in passive mode: get a file and verify its - content. - - L{ftp.FTPClient.retrieveFile} should return a Deferred which fires - with the protocol instance passed to it after the download has - completed. - - (XXX - This API should be based on producers and consumers) - """ - def cbRetr(res, proto): - self.assertEqual(proto.buffer, 'x' * 1000) - - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.dataReceived("x" * 1000) - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - d.addCallback(cbRetr, proto) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'RETR spam\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_RETR(self): - """ - Test the RETR command in non-passive mode. - - Like L{test_passiveRETR} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - self.client.passive = False - - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - portCmd.protocol.makeConnection(proto_helpers.StringTransport()) - portCmd.protocol.dataReceived("x" * 1000) - portCmd.protocol.connectionLost( - failure.Failure(error.ConnectionDone(""))) - - def cbRetr(res, proto): - self.assertEqual(proto.buffer, 'x' * 1000) - - self.client.generatePortCommand = generatePort - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - d.addCallback(cbRetr, proto) - self.assertEqual(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEqual(self.transport.value(), 'RETR spam\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_failedRETR(self): - """ - Try to RETR an unexisting file. - - L{ftp.FTPClient.retrieveFile} should return a Deferred which - errbacks with L{ftp.CommandFailed} if the server indicates the file - cannot be transferred for some reason. - """ - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'RETR spam\r\n') - self.transport.clear() - self.client.lineReceived('550 spam: No such file or directory') - return d - - - def test_lostRETR(self): - """ - Try a RETR, but disconnect during the transfer. - L{ftp.FTPClient.retrieveFile} should return a Deferred which - errbacks with L{ftp.ConnectionLost) - """ - self.client.passive = False - - l = [] - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - tr = proto_helpers.StringTransportWithDisconnection() - portCmd.protocol.makeConnection(tr) - tr.protocol = portCmd.protocol - portCmd.protocol.dataReceived("x" * 500) - l.append(tr) - - self.client.generatePortCommand = generatePort - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - self.assertEqual(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEqual(self.transport.value(), 'RETR spam\r\n') - - self.assert_(l) - l[0].loseConnection() - self.transport.loseConnection() - self.assertFailure(d, ftp.ConnectionLost) - return d - - - def test_passiveSTOR(self): - """ - Test the STOR command: send a file and verify its content. - - L{ftp.FTPClient.storeFile} should return a two-tuple of Deferreds. - The first of which should fire with a protocol instance when the - data connection has been established and is responsible for sending - the contents of the file. The second of which should fire when the - upload has completed, the data connection has been closed, and the - server has acknowledged receipt of the file. - - (XXX - storeFile should take a producer as an argument, instead, and - only return a Deferred which fires when the upload has succeeded or - failed). - """ - tr = proto_helpers.StringTransport() - def cbStore(sender): - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sender.transport.write("x" * 1000) - sender.finish() - sender.connectionLost(failure.Failure(error.ConnectionDone(""))) - - def cbFinish(ign): - self.assertEqual(tr.value(), "x" * 1000) - - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(tr) - - self.client.connectFactory = cbConnect - self._testLogin() - d1, d2 = self.client.storeFile("spam") - d1.addCallback(cbStore) - d2.addCallback(cbFinish) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'STOR spam\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return defer.gatherResults([d1, d2]) - - - def test_failedSTOR(self): - """ - Test a failure in the STOR command. - - If the server does not acknowledge successful receipt of the - uploaded file, the second Deferred returned by - L{ftp.FTPClient.storeFile} should errback with L{ftp.CommandFailed}. - """ - tr = proto_helpers.StringTransport() - def cbStore(sender): - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sender.transport.write("x" * 1000) - sender.finish() - sender.connectionLost(failure.Failure(error.ConnectionDone(""))) - - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(tr) - - self.client.connectFactory = cbConnect - self._testLogin() - d1, d2 = self.client.storeFile("spam") - d1.addCallback(cbStore) - self.assertFailure(d2, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'STOR spam\r\n') - self.transport.clear() - self.client.lineReceived( - '426 Transfer aborted. Data connection closed.') - return defer.gatherResults([d1, d2]) - - - def test_STOR(self): - """ - Test the STOR command in non-passive mode. - - Like L{test_passiveSTOR} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - tr = proto_helpers.StringTransport() - self.client.passive = False - def generatePort(portCmd): - portCmd.text = 'PORT %s' % ftp.encodeHostPort('127.0.0.1', 9876) - portCmd.protocol.makeConnection(tr) - - def cbStore(sender): - self.assertEqual(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEqual(self.transport.value(), 'STOR spam\r\n') - self.transport.clear() - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sender.transport.write("x" * 1000) - sender.finish() - sender.connectionLost(failure.Failure(error.ConnectionDone(""))) - self.client.lineReceived('226 Transfer Complete.') - - def cbFinish(ign): - self.assertEqual(tr.value(), "x" * 1000) - - self.client.generatePortCommand = generatePort - self._testLogin() - d1, d2 = self.client.storeFile("spam") - d1.addCallback(cbStore) - d2.addCallback(cbFinish) - return defer.gatherResults([d1, d2]) - - - def test_passiveLIST(self): - """ - Test the LIST command. - - L{ftp.FTPClient.list} should return a Deferred which fires with a - protocol instance which was passed to list after the command has - succeeded. - - (XXX - This is a very unfortunate API; if my understanding is - correct, the results are always at least line-oriented, so allowing - a per-line parser function to be specified would make this simpler, - but a default implementation should really be provided which knows - how to deal with all the formats used in real servers, so - application developers never have to care about this insanity. It - would also be nice to either get back a Deferred of a list of - filenames or to be able to consume the files as they are received - (which the current API does allow, but in a somewhat inconvenient - fashion) -exarkun) - """ - def cbList(res, fileList): - fls = [f["filename"] for f in fileList.files] - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEqual(fls, expected) - - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sending = [ - '-rw-r--r-- 0 spam egg 100 Oct 10 2006 foo\r\n', - '-rw-r--r-- 3 spam egg 100 Oct 10 2006 bar\r\n', - '-rw-r--r-- 4 spam egg 100 Oct 10 2006 baz\r\n', - ] - for i in sending: - proto.dataReceived(i) - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - fileList = ftp.FTPFileListProtocol() - d = self.client.list('foo/bar', fileList).addCallback(cbList, fileList) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'LIST foo/bar\r\n') - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_LIST(self): - """ - Test the LIST command in non-passive mode. - - Like L{test_passiveLIST} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - self.client.passive = False - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - portCmd.protocol.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sending = [ - '-rw-r--r-- 0 spam egg 100 Oct 10 2006 foo\r\n', - '-rw-r--r-- 3 spam egg 100 Oct 10 2006 bar\r\n', - '-rw-r--r-- 4 spam egg 100 Oct 10 2006 baz\r\n', - ] - for i in sending: - portCmd.protocol.dataReceived(i) - portCmd.protocol.connectionLost( - failure.Failure(error.ConnectionDone(""))) - - def cbList(res, fileList): - fls = [f["filename"] for f in fileList.files] - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEqual(fls, expected) - - self.client.generatePortCommand = generatePort - self._testLogin() - fileList = ftp.FTPFileListProtocol() - d = self.client.list('foo/bar', fileList).addCallback(cbList, fileList) - self.assertEqual(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEqual(self.transport.value(), 'LIST foo/bar\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_failedLIST(self): - """ - Test a failure in LIST command. - - L{ftp.FTPClient.list} should return a Deferred which fails with - L{ftp.CommandFailed} if the server indicates the indicated path is - invalid for some reason. - """ - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - fileList = ftp.FTPFileListProtocol() - d = self.client.list('foo/bar', fileList) - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'LIST foo/bar\r\n') - self.client.lineReceived('550 foo/bar: No such file or directory') - return d - - - def test_NLST(self): - """ - Test the NLST command in non-passive mode. - - L{ftp.FTPClient.nlst} should return a Deferred which fires with a - list of filenames when the list command has completed. - """ - self.client.passive = False - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - portCmd.protocol.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - portCmd.protocol.dataReceived('foo\r\n') - portCmd.protocol.dataReceived('bar\r\n') - portCmd.protocol.dataReceived('baz\r\n') - portCmd.protocol.connectionLost( - failure.Failure(error.ConnectionDone(""))) - - def cbList(res, proto): - fls = proto.buffer.splitlines() - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEqual(fls, expected) - - self.client.generatePortCommand = generatePort - self._testLogin() - lstproto = _BufferingProtocol() - d = self.client.nlst('foo/bar', lstproto).addCallback(cbList, lstproto) - self.assertEqual(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEqual(self.transport.value(), 'NLST foo/bar\r\n') - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_passiveNLST(self): - """ - Test the NLST command. - - Like L{test_passiveNLST} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - def cbList(res, proto): - fls = proto.buffer.splitlines() - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEqual(fls, expected) - - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.dataReceived('foo\r\n') - proto.dataReceived('bar\r\n') - proto.dataReceived('baz\r\n') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - lstproto = _BufferingProtocol() - d = self.client.nlst('foo/bar', lstproto).addCallback(cbList, lstproto) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'NLST foo/bar\r\n') - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_failedNLST(self): - """ - Test a failure in NLST command. - - L{ftp.FTPClient.nlst} should return a Deferred which fails with - L{ftp.CommandFailed} if the server indicates the indicated path is - invalid for some reason. - """ - tr = proto_helpers.StringTransport() - def cbConnect(host, port, factory): - self.assertEqual(host, '127.0.0.1') - self.assertEqual(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(tr) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - lstproto = _BufferingProtocol() - d = self.client.nlst('foo/bar', lstproto) - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEqual(self.transport.value(), 'NLST foo/bar\r\n') - self.client.lineReceived('550 foo/bar: No such file or directory') - return d - - - def test_renameFromTo(self): - """ - L{ftp.FTPClient.rename} issues I{RNTO} and I{RNFR} commands and returns - a L{Deferred} which fires when a file has successfully been renamed. - """ - self._testLogin() - - d = self.client.rename("/spam", "/ham") - self.assertEqual(self.transport.value(), 'RNFR /spam\r\n') - self.transport.clear() - - fromResponse = ( - '350 Requested file action pending further information.\r\n') - self.client.lineReceived(fromResponse) - self.assertEqual(self.transport.value(), 'RNTO /ham\r\n') - toResponse = ( - '250 Requested File Action Completed OK') - self.client.lineReceived(toResponse) - - d.addCallback(self.assertEqual, ([fromResponse], [toResponse])) - return d - - - def test_renameFromToEscapesPaths(self): - """ - L{ftp.FTPClient.rename} issues I{RNTO} and I{RNFR} commands with paths - escaped according to U{http://cr.yp.to/ftp/filesystem.html}. - """ - self._testLogin() - - fromFile = "/foo/ba\nr/baz" - toFile = "/qu\nux" - self.client.rename(fromFile, toFile) - self.client.lineReceived("350 ") - self.client.lineReceived("250 ") - self.assertEqual( - self.transport.value(), - "RNFR /foo/ba\x00r/baz\r\n" - "RNTO /qu\x00ux\r\n") - - - def test_renameFromToFailingOnFirstError(self): - """ - The L{Deferred} returned by L{ftp.FTPClient.rename} is errbacked with - L{CommandFailed} if the I{RNFR} command receives an error response code - (for example, because the file does not exist). - """ - self._testLogin() - - d = self.client.rename("/spam", "/ham") - self.assertEqual(self.transport.value(), 'RNFR /spam\r\n') - self.transport.clear() - - self.client.lineReceived('550 Requested file unavailable.\r\n') - # The RNTO should not execute since the RNFR failed. - self.assertEqual(self.transport.value(), '') - - return self.assertFailure(d, ftp.CommandFailed) - - - def test_renameFromToFailingOnRenameTo(self): - """ - The L{Deferred} returned by L{ftp.FTPClient.rename} is errbacked with - L{CommandFailed} if the I{RNTO} command receives an error response code - (for example, because the destination directory does not exist). - """ - self._testLogin() - - d = self.client.rename("/spam", "/ham") - self.assertEqual(self.transport.value(), 'RNFR /spam\r\n') - self.transport.clear() - - self.client.lineReceived('350 Requested file action pending further information.\r\n') - self.assertEqual(self.transport.value(), 'RNTO /ham\r\n') - self.client.lineReceived('550 Requested file unavailable.\r\n') - return self.assertFailure(d, ftp.CommandFailed) - - - def test_makeDirectory(self): - """ - L{ftp.FTPClient.makeDirectory} issues a I{MKD} command and returns a - L{Deferred} which is called back with the server's response if the - directory is created. - """ - self._testLogin() - - d = self.client.makeDirectory("/spam") - self.assertEqual(self.transport.value(), 'MKD /spam\r\n') - self.client.lineReceived('257 "/spam" created.') - return d.addCallback(self.assertEqual, ['257 "/spam" created.']) - - - def test_makeDirectoryPathEscape(self): - """ - L{ftp.FTPClient.makeDirectory} escapes the path name it sends according - to U{http://cr.yp.to/ftp/filesystem.html}. - """ - self._testLogin() - d = self.client.makeDirectory("/sp\nam") - self.assertEqual(self.transport.value(), 'MKD /sp\x00am\r\n') - # This is necessary to make the Deferred fire. The Deferred needs - # to fire so that tearDown doesn't cause it to errback and fail this - # or (more likely) a later test. - self.client.lineReceived('257 win') - return d - - - def test_failedMakeDirectory(self): - """ - L{ftp.FTPClient.makeDirectory} returns a L{Deferred} which is errbacked - with L{CommandFailed} if the server returns an error response code. - """ - self._testLogin() - - d = self.client.makeDirectory("/spam") - self.assertEqual(self.transport.value(), 'MKD /spam\r\n') - self.client.lineReceived('550 PERMISSION DENIED') - return self.assertFailure(d, ftp.CommandFailed) - - - def test_getDirectory(self): - """ - Test the getDirectory method. - - L{ftp.FTPClient.getDirectory} should return a Deferred which fires with - the current directory on the server. It wraps PWD command. - """ - def cbGet(res): - self.assertEqual(res, "/bar/baz") - - self._testLogin() - d = self.client.getDirectory().addCallback(cbGet) - self.assertEqual(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('257 "/bar/baz"') - return d - - - def test_failedGetDirectory(self): - """ - Test a failure in getDirectory method. - - The behaviour should be the same as PWD. - """ - self._testLogin() - d = self.client.getDirectory() - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('550 /bar/baz: No such file or directory') - return d - - - def test_anotherFailedGetDirectory(self): - """ - Test a different failure in getDirectory method. - - The response should be quoted to be parsed, so it returns an error - otherwise. - """ - self._testLogin() - d = self.client.getDirectory() - self.assertFailure(d, ftp.CommandFailed) - self.assertEqual(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('257 /bar/baz') - return d - - - def test_removeFile(self): - """ - L{ftp.FTPClient.removeFile} sends a I{DELE} command to the server for - the indicated file and returns a Deferred which fires after the server - sends a 250 response code. - """ - self._testLogin() - d = self.client.removeFile("/tmp/test") - self.assertEqual(self.transport.value(), 'DELE /tmp/test\r\n') - response = '250 Requested file action okay, completed.' - self.client.lineReceived(response) - return d.addCallback(self.assertEqual, [response]) - - - def test_failedRemoveFile(self): - """ - If the server returns a response code other than 250 in response to a - I{DELE} sent by L{ftp.FTPClient.removeFile}, the L{Deferred} returned - by C{removeFile} is errbacked with a L{Failure} wrapping a - L{CommandFailed}. - """ - self._testLogin() - d = self.client.removeFile("/tmp/test") - self.assertEqual(self.transport.value(), 'DELE /tmp/test\r\n') - response = '501 Syntax error in parameters or arguments.' - self.client.lineReceived(response) - d = self.assertFailure(d, ftp.CommandFailed) - d.addCallback(lambda exc: self.assertEqual(exc.args, ([response],))) - return d - - - def test_unparsableRemoveFileResponse(self): - """ - If the server returns a response line which cannot be parsed, the - L{Deferred} returned by L{ftp.FTPClient.removeFile} is errbacked with a - L{BadResponse} containing the response. - """ - self._testLogin() - d = self.client.removeFile("/tmp/test") - response = '765 blah blah blah' - self.client.lineReceived(response) - d = self.assertFailure(d, ftp.BadResponse) - d.addCallback(lambda exc: self.assertEqual(exc.args, ([response],))) - return d - - - def test_multilineRemoveFileResponse(self): - """ - If the server returns multiple response lines, the L{Deferred} returned - by L{ftp.FTPClient.removeFile} is still fired with a true value if the - ultimate response code is 250. - """ - self._testLogin() - d = self.client.removeFile("/tmp/test") - response = ['250-perhaps a progress report', - '250 okay'] - map(self.client.lineReceived, response) - return d.addCallback(self.assertTrue) - - - def test_removeDirectory(self): - """ - L{ftp.FTPClient.removeDirectory} sends a I{RMD} command to the server - for the indicated directory and returns a Deferred which fires after - the server sends a 250 response code. - """ - self._testLogin() - d = self.client.removeDirectory('/tmp/test') - self.assertEqual(self.transport.value(), 'RMD /tmp/test\r\n') - response = '250 Requested file action okay, completed.' - self.client.lineReceived(response) - return d.addCallback(self.assertEqual, [response]) - - - def test_failedRemoveDirectory(self): - """ - If the server returns a response code other than 250 in response to a - I{RMD} sent by L{ftp.FTPClient.removeDirectory}, the L{Deferred} - returned by C{removeDirectory} is errbacked with a L{Failure} wrapping - a L{CommandFailed}. - """ - self._testLogin() - d = self.client.removeDirectory("/tmp/test") - self.assertEqual(self.transport.value(), 'RMD /tmp/test\r\n') - response = '501 Syntax error in parameters or arguments.' - self.client.lineReceived(response) - d = self.assertFailure(d, ftp.CommandFailed) - d.addCallback(lambda exc: self.assertEqual(exc.args, ([response],))) - return d - - - def test_unparsableRemoveDirectoryResponse(self): - """ - If the server returns a response line which cannot be parsed, the - L{Deferred} returned by L{ftp.FTPClient.removeDirectory} is errbacked - with a L{BadResponse} containing the response. - """ - self._testLogin() - d = self.client.removeDirectory("/tmp/test") - response = '765 blah blah blah' - self.client.lineReceived(response) - d = self.assertFailure(d, ftp.BadResponse) - d.addCallback(lambda exc: self.assertEqual(exc.args, ([response],))) - return d - - - def test_multilineRemoveDirectoryResponse(self): - """ - If the server returns multiple response lines, the L{Deferred} returned - by L{ftp.FTPClient.removeDirectory} is still fired with a true value - if the ultimate response code is 250. - """ - self._testLogin() - d = self.client.removeDirectory("/tmp/test") - response = ['250-perhaps a progress report', - '250 okay'] - map(self.client.lineReceived, response) - return d.addCallback(self.assertTrue) - - - -class FTPClientBasicTests(unittest.TestCase): - - def testGreeting(self): - # The first response is captured as a greeting. - ftpClient = ftp.FTPClientBasic() - ftpClient.lineReceived('220 Imaginary FTP.') - self.assertEqual(['220 Imaginary FTP.'], ftpClient.greeting) - - def testResponseWithNoMessage(self): - # Responses with no message are still valid, i.e. three digits followed - # by a space is complete response. - ftpClient = ftp.FTPClientBasic() - ftpClient.lineReceived('220 ') - self.assertEqual(['220 '], ftpClient.greeting) - - def testMultilineResponse(self): - ftpClient = ftp.FTPClientBasic() - ftpClient.transport = proto_helpers.StringTransport() - ftpClient.lineReceived('220 Imaginary FTP.') - - # Queue (and send) a dummy command, and set up a callback to capture the - # result - deferred = ftpClient.queueStringCommand('BLAH') - result = [] - deferred.addCallback(result.append) - deferred.addErrback(self.fail) - - # Send the first line of a multiline response. - ftpClient.lineReceived('210-First line.') - self.assertEqual([], result) - - # Send a second line, again prefixed with "nnn-". - ftpClient.lineReceived('123-Second line.') - self.assertEqual([], result) - - # Send a plain line of text, no prefix. - ftpClient.lineReceived('Just some text.') - self.assertEqual([], result) - - # Now send a short (less than 4 chars) line. - ftpClient.lineReceived('Hi') - self.assertEqual([], result) - - # Now send an empty line. - ftpClient.lineReceived('') - self.assertEqual([], result) - - # And a line with 3 digits in it, and nothing else. - ftpClient.lineReceived('321') - self.assertEqual([], result) - - # Now finish it. - ftpClient.lineReceived('210 Done.') - self.assertEqual( - ['210-First line.', - '123-Second line.', - 'Just some text.', - 'Hi', - '', - '321', - '210 Done.'], result[0]) - - - def test_noPasswordGiven(self): - """ - Passing None as the password avoids sending the PASS command. - """ - # Create a client, and give it a greeting. - ftpClient = ftp.FTPClientBasic() - ftpClient.transport = proto_helpers.StringTransport() - ftpClient.lineReceived('220 Welcome to Imaginary FTP.') - - # Queue a login with no password - ftpClient.queueLogin('bob', None) - self.assertEqual('USER bob\r\n', ftpClient.transport.value()) - - # Clear the test buffer, acknowledge the USER command. - ftpClient.transport.clear() - ftpClient.lineReceived('200 Hello bob.') - - # The client shouldn't have sent anything more (i.e. it shouldn't have - # sent a PASS command). - self.assertEqual('', ftpClient.transport.value()) - - - def test_noPasswordNeeded(self): - """ - Receiving a 230 response to USER prevents PASS from being sent. - """ - # Create a client, and give it a greeting. - ftpClient = ftp.FTPClientBasic() - ftpClient.transport = proto_helpers.StringTransport() - ftpClient.lineReceived('220 Welcome to Imaginary FTP.') - - # Queue a login with no password - ftpClient.queueLogin('bob', 'secret') - self.assertEqual('USER bob\r\n', ftpClient.transport.value()) - - # Clear the test buffer, acknowledge the USER command with a 230 - # response code. - ftpClient.transport.clear() - ftpClient.lineReceived('230 Hello bob. No password needed.') - - # The client shouldn't have sent anything more (i.e. it shouldn't have - # sent a PASS command). - self.assertEqual('', ftpClient.transport.value()) - - - -class PathHandlingTests(unittest.TestCase): - def testNormalizer(self): - for inp, outp in [('a', ['a']), - ('/a', ['a']), - ('/', []), - ('a/b/c', ['a', 'b', 'c']), - ('/a/b/c', ['a', 'b', 'c']), - ('/a/', ['a']), - ('a/', ['a'])]: - self.assertEqual(ftp.toSegments([], inp), outp) - - for inp, outp in [('b', ['a', 'b']), - ('b/', ['a', 'b']), - ('/b', ['b']), - ('/b/', ['b']), - ('b/c', ['a', 'b', 'c']), - ('b/c/', ['a', 'b', 'c']), - ('/b/c', ['b', 'c']), - ('/b/c/', ['b', 'c'])]: - self.assertEqual(ftp.toSegments(['a'], inp), outp) - - for inp, outp in [('//', []), - ('//a', ['a']), - ('a//', ['a']), - ('a//b', ['a', 'b'])]: - self.assertEqual(ftp.toSegments([], inp), outp) - - for inp, outp in [('//', []), - ('//b', ['b']), - ('b//c', ['a', 'b', 'c'])]: - self.assertEqual(ftp.toSegments(['a'], inp), outp) - - for inp, outp in [('..', []), - ('../', []), - ('a/..', ['x']), - ('/a/..', []), - ('/a/b/..', ['a']), - ('/a/b/../', ['a']), - ('/a/b/../c', ['a', 'c']), - ('/a/b/../c/', ['a', 'c']), - ('/a/b/../../c', ['c']), - ('/a/b/../../c/', ['c']), - ('/a/b/../../c/..', []), - ('/a/b/../../c/../', [])]: - self.assertEqual(ftp.toSegments(['x'], inp), outp) - - for inp in ['..', '../', 'a/../..', 'a/../../', - '/..', '/../', '/a/../..', '/a/../../', - '/a/b/../../..']: - self.assertRaises(ftp.InvalidPath, ftp.toSegments, [], inp) - - for inp in ['../..', '../../', '../a/../..']: - self.assertRaises(ftp.InvalidPath, ftp.toSegments, ['x'], inp) - - - -class IsGlobbingExpressionTests(unittest.TestCase): - """ - Tests for _isGlobbingExpression utility function. - """ - - def test_isGlobbingExpressionEmptySegments(self): - """ - _isGlobbingExpression will return False for None, or empty - segments. - """ - self.assertFalse(ftp._isGlobbingExpression()) - self.assertFalse(ftp._isGlobbingExpression([])) - self.assertFalse(ftp._isGlobbingExpression(None)) - - - def test_isGlobbingExpressionNoGlob(self): - """ - _isGlobbingExpression will return False for plain segments. - - Also, it only checks the last segment part (filename) and will not - check the path name. - """ - self.assertFalse(ftp._isGlobbingExpression(['ignore', 'expr'])) - self.assertFalse(ftp._isGlobbingExpression(['*.txt', 'expr'])) - - - def test_isGlobbingExpressionGlob(self): - """ - _isGlobbingExpression will return True for segments which contains - globbing characters in the last segment part (filename). - """ - self.assertTrue(ftp._isGlobbingExpression(['ignore', '*.txt'])) - self.assertTrue(ftp._isGlobbingExpression(['ignore', '[a-b].txt'])) - self.assertTrue(ftp._isGlobbingExpression(['ignore', 'fil?.txt'])) - - - -class BaseFTPRealmTests(unittest.TestCase): - """ - Tests for L{ftp.BaseFTPRealm}, a base class to help define L{IFTPShell} - realms with different user home directory policies. - """ - def test_interface(self): - """ - L{ftp.BaseFTPRealm} implements L{IRealm}. - """ - self.assertTrue(verifyClass(IRealm, ftp.BaseFTPRealm)) - - - def test_getHomeDirectory(self): - """ - L{ftp.BaseFTPRealm} calls its C{getHomeDirectory} method with the - avatarId being requested to determine the home directory for that - avatar. - """ - result = filepath.FilePath(self.mktemp()) - avatars = [] - class TestRealm(ftp.BaseFTPRealm): - def getHomeDirectory(self, avatarId): - avatars.append(avatarId) - return result - - realm = TestRealm(self.mktemp()) - iface, avatar, logout = realm.requestAvatar( - "alice@example.com", None, ftp.IFTPShell) - self.assertIsInstance(avatar, ftp.FTPShell) - self.assertEqual(avatar.filesystemRoot, result) - - - def test_anonymous(self): - """ - L{ftp.BaseFTPRealm} returns an L{ftp.FTPAnonymousShell} instance for - anonymous avatar requests. - """ - anonymous = self.mktemp() - realm = ftp.BaseFTPRealm(anonymous) - iface, avatar, logout = realm.requestAvatar( - checkers.ANONYMOUS, None, ftp.IFTPShell) - self.assertIsInstance(avatar, ftp.FTPAnonymousShell) - self.assertEqual(avatar.filesystemRoot, filepath.FilePath(anonymous)) - - - def test_notImplemented(self): - """ - L{ftp.BaseFTPRealm.getHomeDirectory} should be overridden by a subclass - and raises L{NotImplementedError} if it is not. - """ - realm = ftp.BaseFTPRealm(self.mktemp()) - self.assertRaises(NotImplementedError, realm.getHomeDirectory, object()) - - - -class FTPRealmTests(unittest.TestCase): - """ - Tests for L{ftp.FTPRealm}. - """ - def test_getHomeDirectory(self): - """ - L{ftp.FTPRealm} accepts an extra directory to its initializer and treats - the avatarId passed to L{ftp.FTPRealm.getHomeDirectory} as a single path - segment to construct a child of that directory. - """ - base = '/path/to/home' - realm = ftp.FTPRealm(self.mktemp(), base) - home = realm.getHomeDirectory('alice@example.com') - self.assertEqual( - filepath.FilePath(base).child('alice@example.com'), home) - - - def test_defaultHomeDirectory(self): - """ - If no extra directory is passed to L{ftp.FTPRealm}, it uses C{"/home"} - as the base directory containing all user home directories. - """ - realm = ftp.FTPRealm(self.mktemp()) - home = realm.getHomeDirectory('alice@example.com') - self.assertEqual(filepath.FilePath('/home/alice@example.com'), home) - - - -class SystemFTPRealmTests(unittest.TestCase): - """ - Tests for L{ftp.SystemFTPRealm}. - """ - skip = nonPOSIXSkip - - def test_getHomeDirectory(self): - """ - L{ftp.SystemFTPRealm.getHomeDirectory} treats the avatarId passed to it - as a username in the underlying platform and returns that account's home - directory. - """ - # Try to pick a username that will have a home directory. - user = getpass.getuser() - - # Try to find their home directory in a different way than used by the - # implementation. Maybe this is silly and can only introduce spurious - # failures due to system-specific configurations. - import pwd - expected = pwd.getpwnam(user).pw_dir - - realm = ftp.SystemFTPRealm(self.mktemp()) - home = realm.getHomeDirectory(user) - self.assertEqual(home, filepath.FilePath(expected)) - - - def test_noSuchUser(self): - """ - L{ftp.SystemFTPRealm.getHomeDirectory} raises L{UnauthorizedLogin} when - passed a username which has no corresponding home directory in the - system's accounts database. - """ - user = insecureRandom(4).encode('hex') - realm = ftp.SystemFTPRealm(self.mktemp()) - self.assertRaises(UnauthorizedLogin, realm.getHomeDirectory, user) - - - -class ErrnoToFailureTests(unittest.TestCase): - """ - Tests for L{ftp.errnoToFailure} errno checking. - """ - - def test_notFound(self): - """ - C{errno.ENOENT} should be translated to L{ftp.FileNotFoundError}. - """ - d = ftp.errnoToFailure(errno.ENOENT, "foo") - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_permissionDenied(self): - """ - C{errno.EPERM} should be translated to L{ftp.PermissionDeniedError}. - """ - d = ftp.errnoToFailure(errno.EPERM, "foo") - return self.assertFailure(d, ftp.PermissionDeniedError) - - - def test_accessDenied(self): - """ - C{errno.EACCES} should be translated to L{ftp.PermissionDeniedError}. - """ - d = ftp.errnoToFailure(errno.EACCES, "foo") - return self.assertFailure(d, ftp.PermissionDeniedError) - - - def test_notDirectory(self): - """ - C{errno.ENOTDIR} should be translated to L{ftp.IsNotADirectoryError}. - """ - d = ftp.errnoToFailure(errno.ENOTDIR, "foo") - return self.assertFailure(d, ftp.IsNotADirectoryError) - - - def test_fileExists(self): - """ - C{errno.EEXIST} should be translated to L{ftp.FileExistsError}. - """ - d = ftp.errnoToFailure(errno.EEXIST, "foo") - return self.assertFailure(d, ftp.FileExistsError) - - - def test_isDirectory(self): - """ - C{errno.EISDIR} should be translated to L{ftp.IsADirectoryError}. - """ - d = ftp.errnoToFailure(errno.EISDIR, "foo") - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_passThrough(self): - """ - If an unknown errno is passed to L{ftp.errnoToFailure}, it should let - the originating exception pass through. - """ - try: - raise RuntimeError("bar") - except: - d = ftp.errnoToFailure(-1, "foo") - return self.assertFailure(d, RuntimeError) - - - -class AnonymousFTPShellTests(unittest.TestCase): - """ - Test anonymous shell properties. - """ - - def test_anonymousWrite(self): - """ - Check that L{ftp.FTPAnonymousShell} returns an error when trying to - open it in write mode. - """ - shell = ftp.FTPAnonymousShell('') - d = shell.openForWriting(('foo',)) - self.assertFailure(d, ftp.PermissionDeniedError) - return d - - - -class IFTPShellTestsMixin: - """ - Generic tests for the C{IFTPShell} interface. - """ - - def directoryExists(self, path): - """ - Test if the directory exists at C{path}. - - @param path: the relative path to check. - @type path: C{str}. - - @return: C{True} if C{path} exists and is a directory, C{False} if - it's not the case - @rtype: C{bool} - """ - raise NotImplementedError() - - - def createDirectory(self, path): - """ - Create a directory in C{path}. - - @param path: the relative path of the directory to create, with one - segment. - @type path: C{str} - """ - raise NotImplementedError() - - - def fileExists(self, path): - """ - Test if the file exists at C{path}. - - @param path: the relative path to check. - @type path: C{str}. - - @return: C{True} if C{path} exists and is a file, C{False} if it's not - the case. - @rtype: C{bool} - """ - raise NotImplementedError() - - - def createFile(self, path, fileContent=''): - """ - Create a file named C{path} with some content. - - @param path: the relative path of the file to create, without - directory. - @type path: C{str} - - @param fileContent: the content of the file. - @type fileContent: C{str} - """ - raise NotImplementedError() - - - def test_createDirectory(self): - """ - C{directoryExists} should report correctly about directory existence, - and C{createDirectory} should create a directory detectable by - C{directoryExists}. - """ - self.assertFalse(self.directoryExists('bar')) - self.createDirectory('bar') - self.assertTrue(self.directoryExists('bar')) - - - def test_createFile(self): - """ - C{fileExists} should report correctly about file existence, and - C{createFile} should create a file detectable by C{fileExists}. - """ - self.assertFalse(self.fileExists('file.txt')) - self.createFile('file.txt') - self.assertTrue(self.fileExists('file.txt')) - - - def test_makeDirectory(self): - """ - Create a directory and check it ends in the filesystem. - """ - d = self.shell.makeDirectory(('foo',)) - def cb(result): - self.assertTrue(self.directoryExists('foo')) - return d.addCallback(cb) - - - def test_makeDirectoryError(self): - """ - Creating a directory that already exists should fail with a - C{ftp.FileExistsError}. - """ - self.createDirectory('foo') - d = self.shell.makeDirectory(('foo',)) - return self.assertFailure(d, ftp.FileExistsError) - - - def test_removeDirectory(self): - """ - Try to remove a directory and check it's removed from the filesystem. - """ - self.createDirectory('bar') - d = self.shell.removeDirectory(('bar',)) - def cb(result): - self.assertFalse(self.directoryExists('bar')) - return d.addCallback(cb) - - - def test_removeDirectoryOnFile(self): - """ - removeDirectory should not work in file and fail with a - C{ftp.IsNotADirectoryError}. - """ - self.createFile('file.txt') - d = self.shell.removeDirectory(('file.txt',)) - return self.assertFailure(d, ftp.IsNotADirectoryError) - - - def test_removeNotExistingDirectory(self): - """ - Removing directory that doesn't exist should fail with a - C{ftp.FileNotFoundError}. - """ - d = self.shell.removeDirectory(('bar',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_removeFile(self): - """ - Try to remove a file and check it's removed from the filesystem. - """ - self.createFile('file.txt') - d = self.shell.removeFile(('file.txt',)) - def cb(res): - self.assertFalse(self.fileExists('file.txt')) - d.addCallback(cb) - return d - - - def test_removeFileOnDirectory(self): - """ - removeFile should not work on directory. - """ - self.createDirectory('ned') - d = self.shell.removeFile(('ned',)) - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_removeNotExistingFile(self): - """ - Try to remove a non existent file, and check it raises a - L{ftp.FileNotFoundError}. - """ - d = self.shell.removeFile(('foo',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_list(self): - """ - Check the output of the list method. - """ - self.createDirectory('ned') - self.createFile('file.txt') - d = self.shell.list(('.',)) - def cb(l): - l.sort() - self.assertEqual(l, - [('file.txt', []), ('ned', [])]) - return d.addCallback(cb) - - - def test_listWithStat(self): - """ - Check the output of list with asked stats. - """ - self.createDirectory('ned') - self.createFile('file.txt') - d = self.shell.list(('.',), ('size', 'permissions',)) - def cb(l): - l.sort() - self.assertEqual(len(l), 2) - self.assertEqual(l[0][0], 'file.txt') - self.assertEqual(l[1][0], 'ned') - # Size and permissions are reported differently between platforms - # so just check they are present - self.assertEqual(len(l[0][1]), 2) - self.assertEqual(len(l[1][1]), 2) - return d.addCallback(cb) - - - def test_listWithInvalidStat(self): - """ - Querying an invalid stat should result to a C{AttributeError}. - """ - self.createDirectory('ned') - d = self.shell.list(('.',), ('size', 'whateverstat',)) - return self.assertFailure(d, AttributeError) - - - def test_listFile(self): - """ - Check the output of the list method on a file. - """ - self.createFile('file.txt') - d = self.shell.list(('file.txt',)) - def cb(l): - l.sort() - self.assertEqual(l, - [('file.txt', [])]) - return d.addCallback(cb) - - - def test_listNotExistingDirectory(self): - """ - list on a directory that doesn't exist should fail with a - L{ftp.FileNotFoundError}. - """ - d = self.shell.list(('foo',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_access(self): - """ - Try to access a resource. - """ - self.createDirectory('ned') - d = self.shell.access(('ned',)) - return d - - - def test_accessNotFound(self): - """ - access should fail on a resource that doesn't exist. - """ - d = self.shell.access(('foo',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_openForReading(self): - """ - Check that openForReading returns an object providing C{ftp.IReadFile}. - """ - self.createFile('file.txt') - d = self.shell.openForReading(('file.txt',)) - def cb(res): - self.assertTrue(ftp.IReadFile.providedBy(res)) - d.addCallback(cb) - return d - - - def test_openForReadingNotFound(self): - """ - openForReading should fail with a C{ftp.FileNotFoundError} on a file - that doesn't exist. - """ - d = self.shell.openForReading(('ned',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_openForReadingOnDirectory(self): - """ - openForReading should not work on directory. - """ - self.createDirectory('ned') - d = self.shell.openForReading(('ned',)) - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_openForWriting(self): - """ - Check that openForWriting returns an object providing C{ftp.IWriteFile}. - """ - d = self.shell.openForWriting(('foo',)) - def cb1(res): - self.assertTrue(ftp.IWriteFile.providedBy(res)) - return res.receive().addCallback(cb2) - def cb2(res): - self.assertTrue(IConsumer.providedBy(res)) - d.addCallback(cb1) - return d - - - def test_openForWritingExistingDirectory(self): - """ - openForWriting should not be able to open a directory that already - exists. - """ - self.createDirectory('ned') - d = self.shell.openForWriting(('ned',)) - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_openForWritingInNotExistingDirectory(self): - """ - openForWring should fail with a L{ftp.FileNotFoundError} if you specify - a file in a directory that doesn't exist. - """ - self.createDirectory('ned') - d = self.shell.openForWriting(('ned', 'idonotexist', 'foo')) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_statFile(self): - """ - Check the output of the stat method on a file. - """ - fileContent = 'wobble\n' - self.createFile('file.txt', fileContent) - d = self.shell.stat(('file.txt',), ('size', 'directory')) - def cb(res): - self.assertEqual(res[0], len(fileContent)) - self.assertFalse(res[1]) - d.addCallback(cb) - return d - - - def test_statDirectory(self): - """ - Check the output of the stat method on a directory. - """ - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('size', 'directory')) - def cb(res): - self.assertTrue(res[1]) - d.addCallback(cb) - return d - - - def test_statOwnerGroup(self): - """ - Check the owner and groups stats. - """ - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('owner', 'group')) - def cb(res): - self.assertEqual(len(res), 2) - d.addCallback(cb) - return d - - - def test_statHardlinksNotImplemented(self): - """ - If L{twisted.python.filepath.FilePath.getNumberOfHardLinks} is not - implemented, the number returned is 0 - """ - pathFunc = self.shell._path - - def raiseNotImplemented(): - raise NotImplementedError - - def notImplementedFilePath(path): - f = pathFunc(path) - f.getNumberOfHardLinks = raiseNotImplemented - return f - - self.shell._path = notImplementedFilePath - - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('hardlinks',)) - self.assertEqual(self.successResultOf(d), [0]) - - - def test_statOwnerGroupNotImplemented(self): - """ - If L{twisted.python.filepath.FilePath.getUserID} or - L{twisted.python.filepath.FilePath.getGroupID} are not implemented, - the owner returned is "0" and the group is returned as "0" - """ - pathFunc = self.shell._path - - def raiseNotImplemented(): - raise NotImplementedError - - def notImplementedFilePath(path): - f = pathFunc(path) - f.getUserID = raiseNotImplemented - f.getGroupID = raiseNotImplemented - return f - - self.shell._path = notImplementedFilePath - - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('owner', 'group')) - self.assertEqual(self.successResultOf(d), ["0", '0']) - - - def test_statNotExisting(self): - """ - stat should fail with L{ftp.FileNotFoundError} on a file that doesn't - exist. - """ - d = self.shell.stat(('foo',), ('size', 'directory')) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_invalidStat(self): - """ - Querying an invalid stat should result to a C{AttributeError}. - """ - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('size', 'whateverstat')) - return self.assertFailure(d, AttributeError) - - - def test_rename(self): - """ - Try to rename a directory. - """ - self.createDirectory('ned') - d = self.shell.rename(('ned',), ('foo',)) - def cb(res): - self.assertTrue(self.directoryExists('foo')) - self.assertFalse(self.directoryExists('ned')) - return d.addCallback(cb) - - - def test_renameNotExisting(self): - """ - Renaming a directory that doesn't exist should fail with - L{ftp.FileNotFoundError}. - """ - d = self.shell.rename(('foo',), ('bar',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - -class FTPShellTests(unittest.TestCase, IFTPShellTestsMixin): - """ - Tests for the C{ftp.FTPShell} object. - """ - - def setUp(self): - """ - Create a root directory and instantiate a shell. - """ - self.root = filepath.FilePath(self.mktemp()) - self.root.createDirectory() - self.shell = ftp.FTPShell(self.root) - - - def directoryExists(self, path): - """ - Test if the directory exists at C{path}. - """ - return self.root.child(path).isdir() - - - def createDirectory(self, path): - """ - Create a directory in C{path}. - """ - return self.root.child(path).createDirectory() - - - def fileExists(self, path): - """ - Test if the file exists at C{path}. - """ - return self.root.child(path).isfile() - - - def createFile(self, path, fileContent=''): - """ - Create a file named C{path} with some content. - """ - return self.root.child(path).setContent(fileContent) - - - -class TestConsumer(object): - """ - A simple consumer for tests. It only works with non-streaming producers. - - @ivar producer: an object providing - L{twisted.internet.interfaces.IPullProducer}. - """ - - implements(IConsumer) - producer = None - - def registerProducer(self, producer, streaming): - """ - Simple register of producer, checks that no register has happened - before. - """ - assert self.producer is None - self.buffer = [] - self.producer = producer - self.producer.resumeProducing() - - - def unregisterProducer(self): - """ - Unregister the producer, it should be done after a register. - """ - assert self.producer is not None - self.producer = None - - - def write(self, data): - """ - Save the data received. - """ - self.buffer.append(data) - self.producer.resumeProducing() - - - -class TestProducer(object): - """ - A dumb producer. - """ - - def __init__(self, toProduce, consumer): - """ - @param toProduce: data to write - @type toProduce: C{str} - @param consumer: the consumer of data. - @type consumer: C{IConsumer} - """ - self.toProduce = toProduce - self.consumer = consumer - - - def start(self): - """ - Send the data to consume. - """ - self.consumer.write(self.toProduce) - - - -class IReadWriteTestsMixin: - """ - Generic tests for the C{IReadFile} and C{IWriteFile} interfaces. - """ - - def getFileReader(self, content): - """ - Return an object providing C{IReadFile}, ready to send data C{content}. - """ - raise NotImplementedError() - - - def getFileWriter(self): - """ - Return an object providing C{IWriteFile}, ready to receive data. - """ - raise NotImplementedError() - - - def getFileContent(self): - """ - Return the content of the file used. - """ - raise NotImplementedError() - - - def test_read(self): - """ - Test L{ftp.IReadFile}: the implementation should have a send method - returning a C{Deferred} which fires when all the data has been sent - to the consumer, and the data should be correctly send to the consumer. - """ - content = 'wobble\n' - consumer = TestConsumer() - def cbGet(reader): - return reader.send(consumer).addCallback(cbSend) - def cbSend(res): - self.assertEqual("".join(consumer.buffer), content) - return self.getFileReader(content).addCallback(cbGet) - - - def test_write(self): - """ - Test L{ftp.IWriteFile}: the implementation should have a receive - method returning a C{Deferred} which fires with a consumer ready to - receive data to be written. It should also have a close() method that - returns a Deferred. - """ - content = 'elbbow\n' - def cbGet(writer): - return writer.receive().addCallback(cbReceive, writer) - def cbReceive(consumer, writer): - producer = TestProducer(content, consumer) - consumer.registerProducer(None, True) - producer.start() - consumer.unregisterProducer() - return writer.close().addCallback(cbClose) - def cbClose(ignored): - self.assertEqual(self.getFileContent(), content) - return self.getFileWriter().addCallback(cbGet) - - - -class FTPReadWriteTests(unittest.TestCase, IReadWriteTestsMixin): - """ - Tests for C{ftp._FileReader} and C{ftp._FileWriter}, the objects returned - by the shell in C{openForReading}/C{openForWriting}. - """ - - def setUp(self): - """ - Create a temporary file used later. - """ - self.root = filepath.FilePath(self.mktemp()) - self.root.createDirectory() - self.shell = ftp.FTPShell(self.root) - self.filename = "file.txt" - - - def getFileReader(self, content): - """ - Return a C{ftp._FileReader} instance with a file opened for reading. - """ - self.root.child(self.filename).setContent(content) - return self.shell.openForReading((self.filename,)) - - - def getFileWriter(self): - """ - Return a C{ftp._FileWriter} instance with a file opened for writing. - """ - return self.shell.openForWriting((self.filename,)) - - - def getFileContent(self): - """ - Return the content of the temporary file. - """ - return self.root.child(self.filename).getContent() - - - -class CloseTestWriter: - implements(ftp.IWriteFile) - closeStarted = False - def receive(self): - self.s = StringIO() - fc = ftp.FileConsumer(self.s) - return defer.succeed(fc) - def close(self): - self.closeStarted = True - return self.d - - - -class CloseTestShell: - def openForWriting(self, segs): - return defer.succeed(self.writer) - - - -class FTPCloseTests(unittest.TestCase): - """Tests that the server invokes IWriteFile.close""" - - def test_write(self): - """Confirm that FTP uploads (i.e. ftp_STOR) correctly call and wait - upon the IWriteFile object's close() method""" - f = ftp.FTP() - f.workingDirectory = ["root"] - f.shell = CloseTestShell() - f.shell.writer = CloseTestWriter() - f.shell.writer.d = defer.Deferred() - f.factory = ftp.FTPFactory() - f.factory.timeOut = None - f.makeConnection(StringIO()) - - di = ftp.DTP() - di.factory = ftp.DTPFactory(f) - f.dtpInstance = di - di.makeConnection(None)# - - stor_done = [] - d = f.ftp_STOR("path") - d.addCallback(stor_done.append) - # the writer is still receiving data - self.assertFalse(f.shell.writer.closeStarted, "close() called early") - di.dataReceived("some data here") - self.assertFalse(f.shell.writer.closeStarted, "close() called early") - di.connectionLost("reason is ignored") - # now we should be waiting in close() - self.assertTrue(f.shell.writer.closeStarted, "close() not called") - self.assertFalse(stor_done) - f.shell.writer.d.callback("allow close() to finish") - self.assertTrue(stor_done) - - return d # just in case an errback occurred - - - -class FTPResponseCodeTests(unittest.TestCase): - """ - Tests relating directly to response codes. - """ - def test_unique(self): - """ - All of the response code globals (for example C{RESTART_MARKER_REPLY} or - C{USR_NAME_OK_NEED_PASS}) have unique values and are present in the - C{RESPONSE} dictionary. - """ - allValues = set(ftp.RESPONSE) - seenValues = set() - - for key, value in vars(ftp).items(): - if isinstance(value, str) and key.isupper(): - self.assertIn( - value, allValues, - "Code %r with value %r missing from RESPONSE dict" % ( - key, value)) - self.assertNotIn( - value, seenValues, - "Duplicate code %r with value %r" % (key, value)) - seenValues.add(value) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ftp_options.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ftp_options.py deleted file mode 100644 index b5e02e4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ftp_options.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.tap.ftp}. -""" - -from twisted.trial.unittest import TestCase - -from twisted.cred import credentials, error -from twisted.tap.ftp import Options -from twisted.python import versions -from twisted.python.filepath import FilePath - - - -class FTPOptionsTests(TestCase): - """ - Tests for the command line option parser used for C{twistd ftp}. - """ - - usernamePassword = ('iamuser', 'thisispassword') - - def setUp(self): - """ - Create a file with two users. - """ - self.filename = self.mktemp() - f = FilePath(self.filename) - f.setContent(':'.join(self.usernamePassword)) - self.options = Options() - - - def test_passwordfileDeprecation(self): - """ - The C{--password-file} option will emit a warning stating that - said option is deprecated. - """ - self.callDeprecated( - versions.Version("Twisted", 11, 1, 0), - self.options.opt_password_file, self.filename) - - - def test_authAdded(self): - """ - The C{--auth} command-line option will add a checker to the list of - checkers - """ - numCheckers = len(self.options['credCheckers']) - self.options.parseOptions(['--auth', 'file:' + self.filename]) - self.assertEqual(len(self.options['credCheckers']), numCheckers + 1) - - - def test_authFailure(self): - """ - The checker created by the C{--auth} command-line option returns a - L{Deferred} that fails with L{UnauthorizedLogin} when - presented with credentials that are unknown to that checker. - """ - self.options.parseOptions(['--auth', 'file:' + self.filename]) - checker = self.options['credCheckers'][-1] - invalid = credentials.UsernamePassword(self.usernamePassword[0], 'fake') - return (checker.requestAvatarId(invalid) - .addCallbacks( - lambda ignore: self.fail("Wrong password should raise error"), - lambda err: err.trap(error.UnauthorizedLogin))) - - - def test_authSuccess(self): - """ - The checker created by the C{--auth} command-line option returns a - L{Deferred} that returns the avatar id when presented with credentials - that are known to that checker. - """ - self.options.parseOptions(['--auth', 'file:' + self.filename]) - checker = self.options['credCheckers'][-1] - correct = credentials.UsernamePassword(*self.usernamePassword) - return checker.requestAvatarId(correct).addCallback( - lambda username: self.assertEqual(username, correct.username) - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_hook.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_hook.py deleted file mode 100644 index 12f3d2b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_hook.py +++ /dev/null @@ -1,150 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.hook module. -""" - -from twisted.python import hook -from twisted.trial import unittest - -class BaseClass: - """ - dummy class to help in testing. - """ - def __init__(self): - """ - dummy initializer - """ - self.calledBasePre = 0 - self.calledBasePost = 0 - self.calledBase = 0 - - def func(self, a, b): - """ - dummy method - """ - assert a == 1 - assert b == 2 - self.calledBase = self.calledBase + 1 - - -class SubClass(BaseClass): - """ - another dummy class - """ - def __init__(self): - """ - another dummy initializer - """ - BaseClass.__init__(self) - self.calledSubPre = 0 - self.calledSubPost = 0 - self.calledSub = 0 - - def func(self, a, b): - """ - another dummy function - """ - assert a == 1 - assert b == 2 - BaseClass.func(self, a, b) - self.calledSub = self.calledSub + 1 - -_clean_BaseClass = BaseClass.__dict__.copy() -_clean_SubClass = SubClass.__dict__.copy() - -def basePre(base, a, b): - """ - a pre-hook for the base class - """ - base.calledBasePre = base.calledBasePre + 1 - -def basePost(base, a, b): - """ - a post-hook for the base class - """ - base.calledBasePost = base.calledBasePost + 1 - -def subPre(sub, a, b): - """ - a pre-hook for the subclass - """ - sub.calledSubPre = sub.calledSubPre + 1 - -def subPost(sub, a, b): - """ - a post-hook for the subclass - """ - sub.calledSubPost = sub.calledSubPost + 1 - -class HookTests(unittest.TestCase): - """ - test case to make sure hooks are called - """ - def setUp(self): - """Make sure we have clean versions of our classes.""" - BaseClass.__dict__.clear() - BaseClass.__dict__.update(_clean_BaseClass) - SubClass.__dict__.clear() - SubClass.__dict__.update(_clean_SubClass) - - def testBaseHook(self): - """make sure that the base class's hook is called reliably - """ - base = BaseClass() - self.assertEqual(base.calledBase, 0) - self.assertEqual(base.calledBasePre, 0) - base.func(1,2) - self.assertEqual(base.calledBase, 1) - self.assertEqual(base.calledBasePre, 0) - hook.addPre(BaseClass, "func", basePre) - base.func(1, b=2) - self.assertEqual(base.calledBase, 2) - self.assertEqual(base.calledBasePre, 1) - hook.addPost(BaseClass, "func", basePost) - base.func(1, b=2) - self.assertEqual(base.calledBasePost, 1) - self.assertEqual(base.calledBase, 3) - self.assertEqual(base.calledBasePre, 2) - hook.removePre(BaseClass, "func", basePre) - hook.removePost(BaseClass, "func", basePost) - base.func(1, b=2) - self.assertEqual(base.calledBasePost, 1) - self.assertEqual(base.calledBase, 4) - self.assertEqual(base.calledBasePre, 2) - - def testSubHook(self): - """test interactions between base-class hooks and subclass hooks - """ - sub = SubClass() - self.assertEqual(sub.calledSub, 0) - self.assertEqual(sub.calledBase, 0) - sub.func(1, b=2) - self.assertEqual(sub.calledSub, 1) - self.assertEqual(sub.calledBase, 1) - hook.addPre(SubClass, 'func', subPre) - self.assertEqual(sub.calledSub, 1) - self.assertEqual(sub.calledBase, 1) - self.assertEqual(sub.calledSubPre, 0) - self.assertEqual(sub.calledBasePre, 0) - sub.func(1, b=2) - self.assertEqual(sub.calledSub, 2) - self.assertEqual(sub.calledBase, 2) - self.assertEqual(sub.calledSubPre, 1) - self.assertEqual(sub.calledBasePre, 0) - # let the pain begin - hook.addPre(BaseClass, 'func', basePre) - BaseClass.func(sub, 1, b=2) - # sub.func(1, b=2) - self.assertEqual(sub.calledBase, 3) - self.assertEqual(sub.calledBasePre, 1, str(sub.calledBasePre)) - sub.func(1, b=2) - self.assertEqual(sub.calledBasePre, 2) - self.assertEqual(sub.calledBase, 4) - self.assertEqual(sub.calledSubPre, 2) - self.assertEqual(sub.calledSub, 3) - -testCases = [HookTests] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_htb.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_htb.py deleted file mode 100644 index 5b2e4bf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_htb.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- Python -*- - -__version__ = '$Revision: 1.3 $'[11:-2] - -from twisted.trial import unittest -from twisted.protocols import htb - -class DummyClock: - time = 0 - def set(self, when): - self.time = when - - def __call__(self): - return self.time - -class SomeBucket(htb.Bucket): - maxburst = 100 - rate = 2 - -class TestBucketBase(unittest.TestCase): - def setUp(self): - self._realTimeFunc = htb.time - self.clock = DummyClock() - htb.time = self.clock - - def tearDown(self): - htb.time = self._realTimeFunc - -class BucketTests(TestBucketBase): - def testBucketSize(self): - """Testing the size of the bucket.""" - b = SomeBucket() - fit = b.add(1000) - self.assertEqual(100, fit) - - def testBucketDrain(self): - """Testing the bucket's drain rate.""" - b = SomeBucket() - fit = b.add(1000) - self.clock.set(10) - fit = b.add(1000) - self.assertEqual(20, fit) - - def test_bucketEmpty(self): - """ - L{htb.Bucket.drip} returns C{True} if the bucket is empty after that drip. - """ - b = SomeBucket() - b.add(20) - self.clock.set(9) - empty = b.drip() - self.assertFalse(empty) - self.clock.set(10) - empty = b.drip() - self.assertTrue(empty) - -class BucketNestingTests(TestBucketBase): - def setUp(self): - TestBucketBase.setUp(self) - self.parent = SomeBucket() - self.child1 = SomeBucket(self.parent) - self.child2 = SomeBucket(self.parent) - - def testBucketParentSize(self): - # Use up most of the parent bucket. - self.child1.add(90) - fit = self.child2.add(90) - self.assertEqual(10, fit) - - def testBucketParentRate(self): - # Make the parent bucket drain slower. - self.parent.rate = 1 - # Fill both child1 and parent. - self.child1.add(100) - self.clock.set(10) - fit = self.child1.add(100) - # How much room was there? The child bucket would have had 20, - # but the parent bucket only ten (so no, it wouldn't make too much - # sense to have a child bucket draining faster than its parent in a real - # application.) - self.assertEqual(10, fit) - - -# TODO: Test the Transport stuff? - -from test_pcp import DummyConsumer - -class ConsumerShaperTests(TestBucketBase): - def setUp(self): - TestBucketBase.setUp(self) - self.underlying = DummyConsumer() - self.bucket = SomeBucket() - self.shaped = htb.ShapedConsumer(self.underlying, self.bucket) - - def testRate(self): - # Start off with a full bucket, so the burst-size doesn't factor in - # to the calculations. - delta_t = 10 - self.bucket.add(100) - self.shaped.write("x" * 100) - self.clock.set(delta_t) - self.shaped.resumeProducing() - self.assertEqual(len(self.underlying.getvalue()), - delta_t * self.bucket.rate) - - def testBucketRefs(self): - self.assertEqual(self.bucket._refcount, 1) - self.shaped.stopProducing() - self.assertEqual(self.bucket._refcount, 0) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ident.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ident.py deleted file mode 100644 index 8c71b52..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ident.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.protocols.ident module. -""" - -import struct - -from twisted.protocols import ident -from twisted.python import failure -from twisted.internet import error -from twisted.internet import defer - -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport - - - -class ClassParserTests(unittest.TestCase): - """ - Test parsing of ident responses. - """ - - def setUp(self): - """ - Create a ident client used in tests. - """ - self.client = ident.IdentClient() - - - def test_indentError(self): - """ - 'UNKNOWN-ERROR' error should map to the L{ident.IdentError} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 123, 456)) - self.client.lineReceived('123, 456 : ERROR : UNKNOWN-ERROR') - return self.assertFailure(d, ident.IdentError) - - - def test_noUSerError(self): - """ - 'NO-USER' error should map to the L{ident.NoUser} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 234, 456)) - self.client.lineReceived('234, 456 : ERROR : NO-USER') - return self.assertFailure(d, ident.NoUser) - - - def test_invalidPortError(self): - """ - 'INVALID-PORT' error should map to the L{ident.InvalidPort} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 345, 567)) - self.client.lineReceived('345, 567 : ERROR : INVALID-PORT') - return self.assertFailure(d, ident.InvalidPort) - - - def test_hiddenUserError(self): - """ - 'HIDDEN-USER' error should map to the L{ident.HiddenUser} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 567, 789)) - self.client.lineReceived('567, 789 : ERROR : HIDDEN-USER') - return self.assertFailure(d, ident.HiddenUser) - - - def test_lostConnection(self): - """ - A pending query which failed because of a ConnectionLost should - receive an L{ident.IdentError}. - """ - d = defer.Deferred() - self.client.queries.append((d, 765, 432)) - self.client.connectionLost(failure.Failure(error.ConnectionLost())) - return self.assertFailure(d, ident.IdentError) - - - -class TestIdentServer(ident.IdentServer): - def lookup(self, serverAddress, clientAddress): - return self.resultValue - - -class TestErrorIdentServer(ident.IdentServer): - def lookup(self, serverAddress, clientAddress): - raise self.exceptionType() - - -class NewException(RuntimeError): - pass - - -class ServerParserTests(unittest.TestCase): - def testErrors(self): - p = TestErrorIdentServer() - p.makeConnection(StringTransport()) - L = [] - p.sendLine = L.append - - p.exceptionType = ident.IdentError - p.lineReceived('123, 345') - self.assertEqual(L[0], '123, 345 : ERROR : UNKNOWN-ERROR') - - p.exceptionType = ident.NoUser - p.lineReceived('432, 210') - self.assertEqual(L[1], '432, 210 : ERROR : NO-USER') - - p.exceptionType = ident.InvalidPort - p.lineReceived('987, 654') - self.assertEqual(L[2], '987, 654 : ERROR : INVALID-PORT') - - p.exceptionType = ident.HiddenUser - p.lineReceived('756, 827') - self.assertEqual(L[3], '756, 827 : ERROR : HIDDEN-USER') - - p.exceptionType = NewException - p.lineReceived('987, 789') - self.assertEqual(L[4], '987, 789 : ERROR : UNKNOWN-ERROR') - errs = self.flushLoggedErrors(NewException) - self.assertEqual(len(errs), 1) - - for port in -1, 0, 65536, 65537: - del L[:] - p.lineReceived('%d, 5' % (port,)) - p.lineReceived('5, %d' % (port,)) - self.assertEqual( - L, ['%d, 5 : ERROR : INVALID-PORT' % (port,), - '5, %d : ERROR : INVALID-PORT' % (port,)]) - - def testSuccess(self): - p = TestIdentServer() - p.makeConnection(StringTransport()) - L = [] - p.sendLine = L.append - - p.resultValue = ('SYS', 'USER') - p.lineReceived('123, 456') - self.assertEqual(L[0], '123, 456 : USERID : SYS : USER') - - -if struct.pack('=L', 1)[0] == '\x01': - _addr1 = '0100007F' - _addr2 = '04030201' -else: - _addr1 = '7F000001' - _addr2 = '01020304' - - -class ProcMixinTests(unittest.TestCase): - line = ('4: %s:0019 %s:02FA 0A 00000000:00000000 ' - '00:00000000 00000000 0 0 10927 1 f72a5b80 ' - '3000 0 0 2 -1') % (_addr1, _addr2) - - def testDottedQuadFromHexString(self): - p = ident.ProcServerMixin() - self.assertEqual(p.dottedQuadFromHexString(_addr1), '127.0.0.1') - - def testUnpackAddress(self): - p = ident.ProcServerMixin() - self.assertEqual(p.unpackAddress(_addr1 + ':0277'), - ('127.0.0.1', 631)) - - def testLineParser(self): - p = ident.ProcServerMixin() - self.assertEqual( - p.parseLine(self.line), - (('127.0.0.1', 25), ('1.2.3.4', 762), 0)) - - def testExistingAddress(self): - username = [] - p = ident.ProcServerMixin() - p.entries = lambda: iter([self.line]) - p.getUsername = lambda uid: (username.append(uid), 'root')[1] - self.assertEqual( - p.lookup(('127.0.0.1', 25), ('1.2.3.4', 762)), - (p.SYSTEM_NAME, 'root')) - self.assertEqual(username, [0]) - - def testNonExistingAddress(self): - p = ident.ProcServerMixin() - p.entries = lambda: iter([self.line]) - self.assertRaises(ident.NoUser, p.lookup, ('127.0.0.1', 26), - ('1.2.3.4', 762)) - self.assertRaises(ident.NoUser, p.lookup, ('127.0.0.1', 25), - ('1.2.3.5', 762)) - self.assertRaises(ident.NoUser, p.lookup, ('127.0.0.1', 25), - ('1.2.3.4', 763)) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_internet.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_internet.py deleted file mode 100644 index e3e4d78..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_internet.py +++ /dev/null @@ -1,1397 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for lots of functionality provided by L{twisted.internet}. -""" - -from __future__ import division, absolute_import - -import os -import sys -import time - -from twisted.python.compat import _PY3 -from twisted.trial import unittest -from twisted.internet import reactor, protocol, error, abstract, defer -from twisted.internet import interfaces, base - -try: - from twisted.internet import ssl -except ImportError: - ssl = None -if ssl and not ssl.supported: - ssl = None - -from twisted.internet.defer import Deferred -if not _PY3: - from twisted.python import util - - -class ThreePhaseEventTests(unittest.TestCase): - """ - Tests for the private implementation helpers for system event triggers. - """ - def setUp(self): - """ - Create a trigger, an argument, and an event to be used by tests. - """ - self.trigger = lambda x: None - self.arg = object() - self.event = base._ThreePhaseEvent() - - - def test_addInvalidPhase(self): - """ - L{_ThreePhaseEvent.addTrigger} should raise L{KeyError} when called - with an invalid phase. - """ - self.assertRaises( - KeyError, - self.event.addTrigger, 'xxx', self.trigger, self.arg) - - - def test_addBeforeTrigger(self): - """ - L{_ThreePhaseEvent.addTrigger} should accept C{'before'} as a phase, a - callable, and some arguments and add the callable with the arguments to - the before list. - """ - self.event.addTrigger('before', self.trigger, self.arg) - self.assertEqual( - self.event.before, - [(self.trigger, (self.arg,), {})]) - - - def test_addDuringTrigger(self): - """ - L{_ThreePhaseEvent.addTrigger} should accept C{'during'} as a phase, a - callable, and some arguments and add the callable with the arguments to - the during list. - """ - self.event.addTrigger('during', self.trigger, self.arg) - self.assertEqual( - self.event.during, - [(self.trigger, (self.arg,), {})]) - - - def test_addAfterTrigger(self): - """ - L{_ThreePhaseEvent.addTrigger} should accept C{'after'} as a phase, a - callable, and some arguments and add the callable with the arguments to - the after list. - """ - self.event.addTrigger('after', self.trigger, self.arg) - self.assertEqual( - self.event.after, - [(self.trigger, (self.arg,), {})]) - - - def test_removeTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should accept an opaque object - previously returned by L{_ThreePhaseEvent.addTrigger} and remove the - associated trigger. - """ - handle = self.event.addTrigger('before', self.trigger, self.arg) - self.event.removeTrigger(handle) - self.assertEqual(self.event.before, []) - - - def test_removeNonexistentTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should raise L{ValueError} when given - an object not previously returned by L{_ThreePhaseEvent.addTrigger}. - """ - self.assertRaises(ValueError, self.event.removeTrigger, object()) - - - def test_removeRemovedTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should raise L{ValueError} the second - time it is called with an object returned by - L{_ThreePhaseEvent.addTrigger}. - """ - handle = self.event.addTrigger('before', self.trigger, self.arg) - self.event.removeTrigger(handle) - self.assertRaises(ValueError, self.event.removeTrigger, handle) - - - def test_removeAlmostValidTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should raise L{ValueError} if it is - given a trigger handle which resembles a valid trigger handle aside - from its phase being incorrect. - """ - self.assertRaises( - KeyError, - self.event.removeTrigger, ('xxx', self.trigger, (self.arg,), {})) - - - def test_fireEvent(self): - """ - L{_ThreePhaseEvent.fireEvent} should call I{before}, I{during}, and - I{after} phase triggers in that order. - """ - events = [] - self.event.addTrigger('after', events.append, ('first', 'after')) - self.event.addTrigger('during', events.append, ('first', 'during')) - self.event.addTrigger('before', events.append, ('first', 'before')) - self.event.addTrigger('before', events.append, ('second', 'before')) - self.event.addTrigger('during', events.append, ('second', 'during')) - self.event.addTrigger('after', events.append, ('second', 'after')) - - self.assertEqual(events, []) - self.event.fireEvent() - self.assertEqual(events, - [('first', 'before'), ('second', 'before'), - ('first', 'during'), ('second', 'during'), - ('first', 'after'), ('second', 'after')]) - - - def test_asynchronousBefore(self): - """ - L{_ThreePhaseEvent.fireEvent} should wait for any L{Deferred} returned - by a I{before} phase trigger before proceeding to I{during} events. - """ - events = [] - beforeResult = Deferred() - self.event.addTrigger('before', lambda: beforeResult) - self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - - self.assertEqual(events, []) - self.event.fireEvent() - self.assertEqual(events, []) - beforeResult.callback(None) - self.assertEqual(events, ['during', 'after']) - - - def test_beforeTriggerException(self): - """ - If a before-phase trigger raises a synchronous exception, it should be - logged and the remaining triggers should be run. - """ - events = [] - - class DummyException(Exception): - pass - - def raisingTrigger(): - raise DummyException() - - self.event.addTrigger('before', raisingTrigger) - self.event.addTrigger('before', events.append, 'before') - self.event.addTrigger('during', events.append, 'during') - self.event.fireEvent() - self.assertEqual(events, ['before', 'during']) - errors = self.flushLoggedErrors(DummyException) - self.assertEqual(len(errors), 1) - - - def test_duringTriggerException(self): - """ - If a during-phase trigger raises a synchronous exception, it should be - logged and the remaining triggers should be run. - """ - events = [] - - class DummyException(Exception): - pass - - def raisingTrigger(): - raise DummyException() - - self.event.addTrigger('during', raisingTrigger) - self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.assertEqual(events, ['during', 'after']) - errors = self.flushLoggedErrors(DummyException) - self.assertEqual(len(errors), 1) - - - def test_synchronousRemoveAlreadyExecutedBefore(self): - """ - If a before-phase trigger tries to remove another before-phase trigger - which has already run, a warning should be emitted. - """ - events = [] - - def removeTrigger(): - self.event.removeTrigger(beforeHandle) - - beforeHandle = self.event.addTrigger('before', events.append, ('first', 'before')) - self.event.addTrigger('before', removeTrigger) - self.event.addTrigger('before', events.append, ('second', 'before')) - self.assertWarns( - DeprecationWarning, - "Removing already-fired system event triggers will raise an " - "exception in a future version of Twisted.", - __file__, - self.event.fireEvent) - self.assertEqual(events, [('first', 'before'), ('second', 'before')]) - - - def test_synchronousRemovePendingBefore(self): - """ - If a before-phase trigger removes another before-phase trigger which - has not yet run, the removed trigger should not be run. - """ - events = [] - self.event.addTrigger( - 'before', lambda: self.event.removeTrigger(beforeHandle)) - beforeHandle = self.event.addTrigger( - 'before', events.append, ('first', 'before')) - self.event.addTrigger('before', events.append, ('second', 'before')) - self.event.fireEvent() - self.assertEqual(events, [('second', 'before')]) - - - def test_synchronousBeforeRemovesDuring(self): - """ - If a before-phase trigger removes a during-phase trigger, the - during-phase trigger should not be run. - """ - events = [] - self.event.addTrigger( - 'before', lambda: self.event.removeTrigger(duringHandle)) - duringHandle = self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.assertEqual(events, ['after']) - - - def test_asynchronousBeforeRemovesDuring(self): - """ - If a before-phase trigger returns a L{Deferred} and later removes a - during-phase trigger before the L{Deferred} fires, the during-phase - trigger should not be run. - """ - events = [] - beforeResult = Deferred() - self.event.addTrigger('before', lambda: beforeResult) - duringHandle = self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.event.removeTrigger(duringHandle) - beforeResult.callback(None) - self.assertEqual(events, ['after']) - - - def test_synchronousBeforeRemovesConspicuouslySimilarDuring(self): - """ - If a before-phase trigger removes a during-phase trigger which is - identical to an already-executed before-phase trigger aside from their - phases, no warning should be emitted and the during-phase trigger - should not be run. - """ - events = [] - def trigger(): - events.append('trigger') - self.event.addTrigger('before', trigger) - self.event.addTrigger( - 'before', lambda: self.event.removeTrigger(duringTrigger)) - duringTrigger = self.event.addTrigger('during', trigger) - self.event.fireEvent() - self.assertEqual(events, ['trigger']) - - - def test_synchronousRemovePendingDuring(self): - """ - If a during-phase trigger removes another during-phase trigger which - has not yet run, the removed trigger should not be run. - """ - events = [] - self.event.addTrigger( - 'during', lambda: self.event.removeTrigger(duringHandle)) - duringHandle = self.event.addTrigger( - 'during', events.append, ('first', 'during')) - self.event.addTrigger( - 'during', events.append, ('second', 'during')) - self.event.fireEvent() - self.assertEqual(events, [('second', 'during')]) - - - def test_triggersRunOnce(self): - """ - A trigger should only be called on the first call to - L{_ThreePhaseEvent.fireEvent}. - """ - events = [] - self.event.addTrigger('before', events.append, 'before') - self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.event.fireEvent() - self.assertEqual(events, ['before', 'during', 'after']) - - - def test_finishedBeforeTriggersCleared(self): - """ - The temporary list L{_ThreePhaseEvent.finishedBefore} should be emptied - and the state reset to C{'BASE'} before the first during-phase trigger - executes. - """ - events = [] - def duringTrigger(): - events.append('during') - self.assertEqual(self.event.finishedBefore, []) - self.assertEqual(self.event.state, 'BASE') - self.event.addTrigger('before', events.append, 'before') - self.event.addTrigger('during', duringTrigger) - self.event.fireEvent() - self.assertEqual(events, ['before', 'during']) - - - -class SystemEventTests(unittest.TestCase): - """ - Tests for the reactor's implementation of the C{fireSystemEvent}, - C{addSystemEventTrigger}, and C{removeSystemEventTrigger} methods of the - L{IReactorCore} interface. - - @ivar triggers: A list of the handles to triggers which have been added to - the reactor. - """ - def setUp(self): - """ - Create an empty list in which to store trigger handles. - """ - self.triggers = [] - - - def tearDown(self): - """ - Remove all remaining triggers from the reactor. - """ - while self.triggers: - trigger = self.triggers.pop() - try: - reactor.removeSystemEventTrigger(trigger) - except (ValueError, KeyError): - pass - - - def addTrigger(self, event, phase, func): - """ - Add a trigger to the reactor and remember it in C{self.triggers}. - """ - t = reactor.addSystemEventTrigger(event, phase, func) - self.triggers.append(t) - return t - - - def removeTrigger(self, trigger): - """ - Remove a trigger by its handle from the reactor and from - C{self.triggers}. - """ - reactor.removeSystemEventTrigger(trigger) - self.triggers.remove(trigger) - - - def _addSystemEventTriggerTest(self, phase): - eventType = 'test' - events = [] - def trigger(): - events.append(None) - self.addTrigger(phase, eventType, trigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, [None]) - - - def test_beforePhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should accept the C{'before'} - phase and not call the given object until the right event is fired. - """ - self._addSystemEventTriggerTest('before') - - - def test_duringPhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should accept the C{'during'} - phase and not call the given object until the right event is fired. - """ - self._addSystemEventTriggerTest('during') - - - def test_afterPhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should accept the C{'after'} - phase and not call the given object until the right event is fired. - """ - self._addSystemEventTriggerTest('after') - - - def test_unknownPhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should reject phases other than - C{'before'}, C{'during'}, or C{'after'}. - """ - eventType = 'test' - self.assertRaises( - KeyError, self.addTrigger, 'xxx', eventType, lambda: None) - - - def test_beforePreceedsDuring(self): - """ - L{IReactorCore.addSystemEventTrigger} should call triggers added to the - C{'before'} phase before it calls triggers added to the C{'during'} - phase. - """ - eventType = 'test' - events = [] - def beforeTrigger(): - events.append('before') - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, beforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['before', 'during']) - - - def test_duringPreceedsAfter(self): - """ - L{IReactorCore.addSystemEventTrigger} should call triggers added to the - C{'during'} phase before it calls triggers added to the C{'after'} - phase. - """ - eventType = 'test' - events = [] - def duringTrigger(): - events.append('during') - def afterTrigger(): - events.append('after') - self.addTrigger('during', eventType, duringTrigger) - self.addTrigger('after', eventType, afterTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['during', 'after']) - - - def test_beforeReturnsDeferred(self): - """ - If a trigger added to the C{'before'} phase of an event returns a - L{Deferred}, the C{'during'} phase should be delayed until it is called - back. - """ - triggerDeferred = Deferred() - eventType = 'test' - events = [] - def beforeTrigger(): - return triggerDeferred - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, beforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, []) - triggerDeferred.callback(None) - self.assertEqual(events, ['during']) - - - def test_multipleBeforeReturnDeferred(self): - """ - If more than one trigger added to the C{'before'} phase of an event - return L{Deferred}s, the C{'during'} phase should be delayed until they - are all called back. - """ - firstDeferred = Deferred() - secondDeferred = Deferred() - eventType = 'test' - events = [] - def firstBeforeTrigger(): - return firstDeferred - def secondBeforeTrigger(): - return secondDeferred - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, firstBeforeTrigger) - self.addTrigger('before', eventType, secondBeforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, []) - firstDeferred.callback(None) - self.assertEqual(events, []) - secondDeferred.callback(None) - self.assertEqual(events, ['during']) - - - def test_subsequentBeforeTriggerFiresPriorBeforeDeferred(self): - """ - If a trigger added to the C{'before'} phase of an event calls back a - L{Deferred} returned by an earlier trigger in the C{'before'} phase of - the same event, the remaining C{'before'} triggers for that event - should be run and any further L{Deferred}s waited on before proceeding - to the C{'during'} events. - """ - eventType = 'test' - events = [] - firstDeferred = Deferred() - secondDeferred = Deferred() - def firstBeforeTrigger(): - return firstDeferred - def secondBeforeTrigger(): - firstDeferred.callback(None) - def thirdBeforeTrigger(): - events.append('before') - return secondDeferred - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, firstBeforeTrigger) - self.addTrigger('before', eventType, secondBeforeTrigger) - self.addTrigger('before', eventType, thirdBeforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['before']) - secondDeferred.callback(None) - self.assertEqual(events, ['before', 'during']) - - - def test_removeSystemEventTrigger(self): - """ - A trigger removed with L{IReactorCore.removeSystemEventTrigger} should - not be called when the event fires. - """ - eventType = 'test' - events = [] - def firstBeforeTrigger(): - events.append('first') - def secondBeforeTrigger(): - events.append('second') - self.addTrigger('before', eventType, firstBeforeTrigger) - self.removeTrigger( - self.addTrigger('before', eventType, secondBeforeTrigger)) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['first']) - - - def test_removeNonExistentSystemEventTrigger(self): - """ - Passing an object to L{IReactorCore.removeSystemEventTrigger} which was - not returned by a previous call to - L{IReactorCore.addSystemEventTrigger} or which has already been passed - to C{removeSystemEventTrigger} should result in L{TypeError}, - L{KeyError}, or L{ValueError} being raised. - """ - b = self.addTrigger('during', 'test', lambda: None) - self.removeTrigger(b) - self.assertRaises( - TypeError, reactor.removeSystemEventTrigger, None) - self.assertRaises( - ValueError, reactor.removeSystemEventTrigger, b) - self.assertRaises( - KeyError, - reactor.removeSystemEventTrigger, - (b[0], ('xxx',) + b[1][1:])) - - - def test_interactionBetweenDifferentEvents(self): - """ - L{IReactorCore.fireSystemEvent} should behave the same way for a - particular system event regardless of whether Deferreds are being - waited on for a different system event. - """ - events = [] - - firstEvent = 'first-event' - firstDeferred = Deferred() - def beforeFirstEvent(): - events.append(('before', 'first')) - return firstDeferred - def afterFirstEvent(): - events.append(('after', 'first')) - - secondEvent = 'second-event' - secondDeferred = Deferred() - def beforeSecondEvent(): - events.append(('before', 'second')) - return secondDeferred - def afterSecondEvent(): - events.append(('after', 'second')) - - self.addTrigger('before', firstEvent, beforeFirstEvent) - self.addTrigger('after', firstEvent, afterFirstEvent) - self.addTrigger('before', secondEvent, beforeSecondEvent) - self.addTrigger('after', secondEvent, afterSecondEvent) - - self.assertEqual(events, []) - - # After this, firstEvent should be stuck before 'during' waiting for - # firstDeferred. - reactor.fireSystemEvent(firstEvent) - self.assertEqual(events, [('before', 'first')]) - - # After this, secondEvent should be stuck before 'during' waiting for - # secondDeferred. - reactor.fireSystemEvent(secondEvent) - self.assertEqual(events, [('before', 'first'), ('before', 'second')]) - - # After this, firstEvent should have finished completely, but - # secondEvent should be at the same place. - firstDeferred.callback(None) - self.assertEqual(events, [('before', 'first'), ('before', 'second'), - ('after', 'first')]) - - # After this, secondEvent should have finished completely. - secondDeferred.callback(None) - self.assertEqual(events, [('before', 'first'), ('before', 'second'), - ('after', 'first'), ('after', 'second')]) - - - -class TimeTests(unittest.TestCase): - """ - Tests for the IReactorTime part of the reactor. - """ - - - def test_seconds(self): - """ - L{twisted.internet.reactor.seconds} should return something - like a number. - - 1. This test specifically does not assert any relation to the - "system time" as returned by L{time.time} or - L{twisted.python.runtime.seconds}, because at some point we - may find a better option for scheduling calls than - wallclock-time. - 2. This test *also* does not assert anything about the type of - the result, because operations may not return ints or - floats: For example, datetime-datetime == timedelta(0). - """ - now = reactor.seconds() - self.assertEqual(now-now+now, now) - - - def test_callLaterUsesReactorSecondsInDelayedCall(self): - """ - L{reactor.callLater} should use the reactor's seconds factory - to produce the time at which the DelayedCall will be called. - """ - oseconds = reactor.seconds - reactor.seconds = lambda: 100 - try: - call = reactor.callLater(5, lambda: None) - self.assertEqual(call.getTime(), 105) - finally: - reactor.seconds = oseconds - - - def test_callLaterUsesReactorSecondsAsDelayedCallSecondsFactory(self): - """ - L{reactor.callLater} should propagate its own seconds factory - to the DelayedCall to use as its own seconds factory. - """ - oseconds = reactor.seconds - reactor.seconds = lambda: 100 - try: - call = reactor.callLater(5, lambda: None) - self.assertEqual(call.seconds(), 100) - finally: - reactor.seconds = oseconds - - - def test_callLater(self): - """ - Test that a DelayedCall really calls the function it is - supposed to call. - """ - d = Deferred() - reactor.callLater(0, d.callback, None) - d.addCallback(self.assertEqual, None) - return d - - - def test_cancelDelayedCall(self): - """ - Test that when a DelayedCall is cancelled it does not run. - """ - called = [] - def function(): - called.append(None) - call = reactor.callLater(0, function) - call.cancel() - - # Schedule a call in two "iterations" to check to make sure that the - # above call never ran. - d = Deferred() - def check(): - try: - self.assertEqual(called, []) - except: - d.errback() - else: - d.callback(None) - reactor.callLater(0, reactor.callLater, 0, check) - return d - - - def test_cancelCancelledDelayedCall(self): - """ - Test that cancelling a DelayedCall which has already been cancelled - raises the appropriate exception. - """ - call = reactor.callLater(0, lambda: None) - call.cancel() - self.assertRaises(error.AlreadyCancelled, call.cancel) - - - def test_cancelCalledDelayedCallSynchronous(self): - """ - Test that cancelling a DelayedCall in the DelayedCall's function as - that function is being invoked by the DelayedCall raises the - appropriate exception. - """ - d = Deferred() - def later(): - try: - self.assertRaises(error.AlreadyCalled, call.cancel) - except: - d.errback() - else: - d.callback(None) - call = reactor.callLater(0, later) - return d - - - def test_cancelCalledDelayedCallAsynchronous(self): - """ - Test that cancelling a DelayedCall after it has run its function - raises the appropriate exception. - """ - d = Deferred() - def check(): - try: - self.assertRaises(error.AlreadyCalled, call.cancel) - except: - d.errback() - else: - d.callback(None) - def later(): - reactor.callLater(0, check) - call = reactor.callLater(0, later) - return d - - - def testCallLaterTime(self): - d = reactor.callLater(10, lambda: None) - try: - self.failUnless(d.getTime() - (time.time() + 10) < 1) - finally: - d.cancel() - - - def testDelayedCallStringification(self): - # Mostly just make sure str() isn't going to raise anything for - # DelayedCalls within reason. - dc = reactor.callLater(0, lambda x, y: None, 'x', y=10) - str(dc) - dc.reset(5) - str(dc) - dc.cancel() - str(dc) - - dc = reactor.callLater(0, lambda: None, x=[({'hello': u'world'}, 10j), reactor], *range(10)) - str(dc) - dc.cancel() - str(dc) - - def calledBack(ignored): - str(dc) - d = Deferred().addCallback(calledBack) - dc = reactor.callLater(0, d.callback, None) - str(dc) - return d - - - def testDelayedCallSecondsOverride(self): - """ - Test that the C{seconds} argument to DelayedCall gets used instead of - the default timing function, if it is not None. - """ - def seconds(): - return 10 - dc = base.DelayedCall(5, lambda: None, (), {}, lambda dc: None, - lambda dc: None, seconds) - self.assertEqual(dc.getTime(), 5) - dc.reset(3) - self.assertEqual(dc.getTime(), 13) - - -class CallFromThreadStopsAndWakeUpTests(unittest.TestCase): - def testWakeUp(self): - # Make sure other threads can wake up the reactor - d = Deferred() - def wake(): - time.sleep(0.1) - # callFromThread will call wakeUp for us - reactor.callFromThread(d.callback, None) - reactor.callInThread(wake) - return d - - if interfaces.IReactorThreads(reactor, None) is None: - testWakeUp.skip = "Nothing to wake up for without thread support" - - def _stopCallFromThreadCallback(self): - self.stopped = True - - def _callFromThreadCallback(self, d): - reactor.callFromThread(self._callFromThreadCallback2, d) - reactor.callLater(0, self._stopCallFromThreadCallback) - - def _callFromThreadCallback2(self, d): - try: - self.assert_(self.stopped) - except: - # Send the error to the deferred - d.errback() - else: - d.callback(None) - - def testCallFromThreadStops(self): - """ - Ensure that callFromThread from inside a callFromThread - callback doesn't sit in an infinite loop and lets other - things happen too. - """ - self.stopped = False - d = defer.Deferred() - reactor.callFromThread(self._callFromThreadCallback, d) - return d - - -class DelayedTests(unittest.TestCase): - def setUp(self): - self.finished = 0 - self.counter = 0 - self.timers = {} - self.deferred = defer.Deferred() - - def tearDown(self): - for t in self.timers.values(): - t.cancel() - - def checkTimers(self): - l1 = self.timers.values() - l2 = list(reactor.getDelayedCalls()) - - # There should be at least the calls we put in. There may be other - # calls that are none of our business and that we should ignore, - # though. - - missing = [] - for dc in l1: - if dc not in l2: - missing.append(dc) - if missing: - self.finished = 1 - self.failIf(missing, "Should have been missing no calls, instead was missing " + repr(missing)) - - def callback(self, tag): - del self.timers[tag] - self.checkTimers() - - def addCallback(self, tag): - self.callback(tag) - self.addTimer(15, self.callback) - - def done(self, tag): - self.finished = 1 - self.callback(tag) - self.deferred.callback(None) - - def addTimer(self, when, callback): - self.timers[self.counter] = reactor.callLater(when * 0.01, callback, - self.counter) - self.counter += 1 - self.checkTimers() - - def testGetDelayedCalls(self): - if not hasattr(reactor, "getDelayedCalls"): - return - # This is not a race because we don't do anything which might call - # the reactor until we have all the timers set up. If we did, this - # test might fail on slow systems. - self.checkTimers() - self.addTimer(35, self.done) - self.addTimer(20, self.callback) - self.addTimer(30, self.callback) - which = self.counter - self.addTimer(29, self.callback) - self.addTimer(25, self.addCallback) - self.addTimer(26, self.callback) - - self.timers[which].cancel() - del self.timers[which] - self.checkTimers() - - self.deferred.addCallback(lambda x : self.checkTimers()) - return self.deferred - - - def test_active(self): - """ - L{IDelayedCall.active} returns False once the call has run. - """ - dcall = reactor.callLater(0.01, self.deferred.callback, True) - self.assertEqual(dcall.active(), True) - - def checkDeferredCall(success): - self.assertEqual(dcall.active(), False) - return success - - self.deferred.addCallback(checkDeferredCall) - - return self.deferred - - - -resolve_helper = """ -from __future__ import print_function -import %(reactor)s -%(reactor)s.install() -from twisted.internet import reactor - -class Foo: - def __init__(self): - reactor.callWhenRunning(self.start) - self.timer = reactor.callLater(3, self.failed) - def start(self): - reactor.resolve('localhost').addBoth(self.done) - def done(self, res): - print('done', res) - reactor.stop() - def failed(self): - print('failed') - self.timer = None - reactor.stop() -f = Foo() -reactor.run() -""" - -class ChildResolveProtocol(protocol.ProcessProtocol): - def __init__(self, onCompletion): - self.onCompletion = onCompletion - - def connectionMade(self): - self.output = [] - self.error = [] - - def outReceived(self, out): - self.output.append(out) - - def errReceived(self, err): - self.error.append(err) - - def processEnded(self, reason): - self.onCompletion.callback((reason, self.output, self.error)) - self.onCompletion = None - - -class ResolveTests(unittest.TestCase): - def testChildResolve(self): - # I've seen problems with reactor.run under gtk2reactor. Spawn a - # child which just does reactor.resolve after the reactor has - # started, fail if it does not complete in a timely fashion. - helperPath = os.path.abspath(self.mktemp()) - helperFile = open(helperPath, 'w') - - # Eeueuuggg - reactorName = reactor.__module__ - - helperFile.write(resolve_helper % {'reactor': reactorName}) - helperFile.close() - - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - - helperDeferred = Deferred() - helperProto = ChildResolveProtocol(helperDeferred) - - reactor.spawnProcess(helperProto, sys.executable, ("python", "-u", helperPath), env) - - def cbFinished(result): - (reason, output, error) = result - # If the output is "done 127.0.0.1\n" we don't really care what - # else happened. - output = b''.join(output) - if output != b'done 127.0.0.1\n': - self.fail(( - "The child process failed to produce the desired results:\n" - " Reason for termination was: %r\n" - " Output stream was: %r\n" - " Error stream was: %r\n") % (reason.getErrorMessage(), output, b''.join(error))) - - helperDeferred.addCallback(cbFinished) - return helperDeferred - -if not interfaces.IReactorProcess(reactor, None): - ResolveTests.skip = ( - "cannot run test: reactor doesn't support IReactorProcess") - - - -class CallFromThreadTests(unittest.TestCase): - """ - Task scheduling from threads tests. - """ - if interfaces.IReactorThreads(reactor, None) is None: - skip = "Nothing to test without thread support" - - def setUp(self): - self.counter = 0 - self.deferred = Deferred() - - - def schedule(self, *args, **kwargs): - """ - Override in subclasses. - """ - reactor.callFromThread(*args, **kwargs) - - - def test_lotsOfThreadsAreScheduledCorrectly(self): - """ - L{IReactorThreads.callFromThread} can be used to schedule a large - number of calls in the reactor thread. - """ - def addAndMaybeFinish(): - self.counter += 1 - if self.counter == 100: - self.deferred.callback(True) - - for i in range(100): - self.schedule(addAndMaybeFinish) - - return self.deferred - - - def test_threadsAreRunInScheduledOrder(self): - """ - Callbacks should be invoked in the order they were scheduled. - """ - order = [] - - def check(_): - self.assertEqual(order, [1, 2, 3]) - - self.deferred.addCallback(check) - self.schedule(order.append, 1) - self.schedule(order.append, 2) - self.schedule(order.append, 3) - self.schedule(reactor.callFromThread, self.deferred.callback, None) - - return self.deferred - - - def test_scheduledThreadsNotRunUntilReactorRuns(self): - """ - Scheduled tasks should not be run until the reactor starts running. - """ - def incAndFinish(): - self.counter = 1 - self.deferred.callback(True) - self.schedule(incAndFinish) - - # Callback shouldn't have fired yet. - self.assertEqual(self.counter, 0) - - return self.deferred - - - -class MyProtocol(protocol.Protocol): - """ - Sample protocol. - """ - -class MyFactory(protocol.Factory): - """ - Sample factory. - """ - - protocol = MyProtocol - - -class ProtocolTests(unittest.TestCase): - - def testFactory(self): - factory = MyFactory() - protocol = factory.buildProtocol(None) - self.assertEqual(protocol.factory, factory) - self.assert_( isinstance(protocol, factory.protocol) ) - - -class DummyProducer(object): - """ - Very uninteresting producer implementation used by tests to ensure the - right methods are called by the consumer with which it is registered. - - @type events: C{list} of C{str} - @ivar events: The producer/consumer related events which have happened to - this producer. Strings in this list may be C{'resume'}, C{'stop'}, or - C{'pause'}. Elements are added as they occur. - """ - - def __init__(self): - self.events = [] - - - def resumeProducing(self): - self.events.append('resume') - - - def stopProducing(self): - self.events.append('stop') - - - def pauseProducing(self): - self.events.append('pause') - - - -class SillyDescriptor(abstract.FileDescriptor): - """ - A descriptor whose data buffer gets filled very fast. - - Useful for testing FileDescriptor's IConsumer interface, since - the data buffer fills as soon as at least four characters are - written to it, and gets emptied in a single doWrite() cycle. - """ - bufferSize = 3 - connected = True - - def writeSomeData(self, data): - """ - Always write all data. - """ - return len(data) - - - def startWriting(self): - """ - Do nothing: bypass the reactor. - """ - stopWriting = startWriting - - - -class ReentrantProducer(DummyProducer): - """ - Similar to L{DummyProducer}, but with a resumeProducing method which calls - back into an L{IConsumer} method of the consumer against which it is - registered. - - @ivar consumer: The consumer with which this producer has been or will - be registered. - - @ivar methodName: The name of the method to call on the consumer inside - C{resumeProducing}. - - @ivar methodArgs: The arguments to pass to the consumer method invoked in - C{resumeProducing}. - """ - def __init__(self, consumer, methodName, *methodArgs): - super(ReentrantProducer, self).__init__() - self.consumer = consumer - self.methodName = methodName - self.methodArgs = methodArgs - - - def resumeProducing(self): - super(ReentrantProducer, self).resumeProducing() - getattr(self.consumer, self.methodName)(*self.methodArgs) - - - -class ProducerTests(unittest.TestCase): - """ - Test abstract.FileDescriptor's consumer interface. - """ - def test_doubleProducer(self): - """ - Verify that registering a non-streaming producer invokes its - resumeProducing() method and that you can only register one producer - at a time. - """ - fd = abstract.FileDescriptor() - fd.connected = 1 - dp = DummyProducer() - fd.registerProducer(dp, 0) - self.assertEqual(dp.events, ['resume']) - self.assertRaises(RuntimeError, fd.registerProducer, DummyProducer(), 0) - - - def test_unconnectedFileDescriptor(self): - """ - Verify that registering a producer when the connection has already - been closed invokes its stopProducing() method. - """ - fd = abstract.FileDescriptor() - fd.disconnected = 1 - dp = DummyProducer() - fd.registerProducer(dp, 0) - self.assertEqual(dp.events, ['stop']) - - - def _dontPausePullConsumerTest(self, methodName): - """ - Pull consumers don't get their C{pauseProducing} method called if the - descriptor buffer fills up. - - @param _methodName: Either 'write', or 'writeSequence', indicating - which transport method to write data to. - """ - descriptor = SillyDescriptor() - producer = DummyProducer() - descriptor.registerProducer(producer, streaming=False) - self.assertEqual(producer.events, ['resume']) - del producer.events[:] - - # Fill up the descriptor's write buffer so we can observe whether or - # not it pauses its producer in that case. - if methodName == "writeSequence": - descriptor.writeSequence([b'1', b'2', b'3', b'4']) - else: - descriptor.write(b'1234') - - self.assertEqual(producer.events, []) - - - def test_dontPausePullConsumerOnWrite(self): - """ - Verify that FileDescriptor does not call producer.pauseProducing() on a - non-streaming pull producer in response to a L{IConsumer.write} call - which results in a full write buffer. Issue #2286. - """ - return self._dontPausePullConsumerTest('write') - - - def test_dontPausePullConsumerOnWriteSequence(self): - """ - Like L{test_dontPausePullConsumerOnWrite}, but for a call to - C{writeSequence} rather than L{IConsumer.write}. - - C{writeSequence} is not part of L{IConsumer}, but - L{abstract.FileDescriptor} has supported consumery behavior in response - to calls to L{writeSequence} forever. - """ - return self._dontPausePullConsumerTest('writeSequence') - - - def _reentrantStreamingProducerTest(self, methodName): - descriptor = SillyDescriptor() - if methodName == "writeSequence": - data = [b's', b'p', b'am'] - else: - data = b"spam" - producer = ReentrantProducer(descriptor, methodName, data) - descriptor.registerProducer(producer, streaming=True) - - # Start things off by filling up the descriptor's buffer so it will - # pause its producer. - getattr(descriptor, methodName)(data) - - # Sanity check - make sure that worked. - self.assertEqual(producer.events, ['pause']) - del producer.events[:] - - # After one call to doWrite, the buffer has been emptied so the - # FileDescriptor should resume its producer. That will result in an - # immediate call to FileDescriptor.write which will again fill the - # buffer and result in the producer being paused. - descriptor.doWrite() - self.assertEqual(producer.events, ['resume', 'pause']) - del producer.events[:] - - # After a second call to doWrite, the exact same thing should have - # happened. Prior to the bugfix for which this test was written, - # FileDescriptor would have incorrectly believed its producer was - # already resumed (it was paused) and so not resume it again. - descriptor.doWrite() - self.assertEqual(producer.events, ['resume', 'pause']) - - - def test_reentrantStreamingProducerUsingWrite(self): - """ - Verify that FileDescriptor tracks producer's paused state correctly. - Issue #811, fixed in revision r12857. - """ - return self._reentrantStreamingProducerTest('write') - - - def test_reentrantStreamingProducerUsingWriteSequence(self): - """ - Like L{test_reentrantStreamingProducerUsingWrite}, but for calls to - C{writeSequence}. - - C{writeSequence} is B{not} part of L{IConsumer}, however - C{abstract.FileDescriptor} has supported consumery behavior in response - to calls to C{writeSequence} forever. - """ - return self._reentrantStreamingProducerTest('writeSequence') - - - -class PortStringificationTests(unittest.TestCase): - if interfaces.IReactorTCP(reactor, None) is not None: - def testTCP(self): - p = reactor.listenTCP(0, protocol.ServerFactory()) - portNo = p.getHost().port - self.assertNotEqual(str(p).find(str(portNo)), -1, - "%d not found in %s" % (portNo, p)) - return p.stopListening() - - if interfaces.IReactorUDP(reactor, None) is not None: - def testUDP(self): - p = reactor.listenUDP(0, protocol.DatagramProtocol()) - portNo = p.getHost().port - self.assertNotEqual(str(p).find(str(portNo)), -1, - "%d not found in %s" % (portNo, p)) - return p.stopListening() - - if interfaces.IReactorSSL(reactor, None) is not None and ssl: - def testSSL(self, ssl=ssl): - pem = util.sibpath(__file__, 'server.pem') - p = reactor.listenSSL(0, protocol.ServerFactory(), ssl.DefaultOpenSSLContextFactory(pem, pem)) - portNo = p.getHost().port - self.assertNotEqual(str(p).find(str(portNo)), -1, - "%d not found in %s" % (portNo, p)) - return p.stopListening() - - if _PY3: - testSSL.skip = ("Re-enable once the Python 3 SSL port is done.") - - - -class IStreamClientEndpointStringParserTests(unittest.TestCase): - """ - Tests for L{twisted.internet.interfaces.IStreamClientEndpointStringParser}. - """ - def test_deprecated(self): - """ - Accessing L{IStreamClientEndpointStringParser} via the - I{IStreamClientEndpointStringParser} attribute of - L{twisted.internet.interfaces} results in a deprecation warning being - emitted. - """ - interfaces.IStreamClientEndpointStringParser - - warnings = self.flushWarnings([self.test_deprecated]) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "twisted.internet.interfaces.IStreamClientEndpointStringParser " - "was deprecated in Twisted 14.0.0: This interface has been " - "superseded by IStreamClientEndpointStringParserWithReactor.") - self.assertEqual(len(warnings), 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_iosim.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_iosim.py deleted file mode 100644 index 2df9bc4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_iosim.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.test.iosim}. -""" - -from twisted.test.iosim import FakeTransport -from twisted.trial.unittest import TestCase - -class FakeTransportTests(TestCase): - """ - Tests for L{FakeTransport} - """ - - def test_connectionSerial(self): - """ - Each L{FakeTransport} receives a serial number that uniquely identifies - it. - """ - a = FakeTransport(object(), True) - b = FakeTransport(object(), False) - self.assertIsInstance(a.serial, int) - self.assertIsInstance(b.serial, int) - self.assertNotEqual(a.serial, b.serial) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_iutils.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_iutils.py deleted file mode 100644 index 01c2dc9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_iutils.py +++ /dev/null @@ -1,350 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test running processes with the APIs in L{twisted.internet.utils}. -""" - -from __future__ import division, absolute_import - -import warnings, os, stat, sys, signal - -from twisted.python.compat import _PY3 -from twisted.python.runtime import platform -from twisted.trial import unittest -from twisted.internet import error, reactor, utils, interfaces -from twisted.internet.defer import Deferred -from twisted.python.test.test_util import SuppressedWarningsTests - - -class ProcessUtilsTests(unittest.TestCase): - """ - Test running a process using L{getProcessOutput}, L{getProcessValue}, and - L{getProcessOutputAndValue}. - """ - - if interfaces.IReactorProcess(reactor, None) is None: - skip = "reactor doesn't implement IReactorProcess" - - output = None - value = None - exe = sys.executable - - def makeSourceFile(self, sourceLines): - """ - Write the given list of lines to a text file and return the absolute - path to it. - """ - script = self.mktemp() - scriptFile = file(script, 'wt') - scriptFile.write(os.linesep.join(sourceLines) + os.linesep) - scriptFile.close() - return os.path.abspath(script) - - - def test_output(self): - """ - L{getProcessOutput} returns a L{Deferred} which fires with the complete - output of the process it runs after that process exits. - """ - scriptFile = self.makeSourceFile([ - "import sys", - "for s in 'hello world\\n':", - " sys.stdout.write(s)", - " sys.stdout.flush()"]) - d = utils.getProcessOutput(self.exe, ['-u', scriptFile]) - return d.addCallback(self.assertEqual, "hello world\n") - - - def test_outputWithErrorIgnored(self): - """ - The L{Deferred} returned by L{getProcessOutput} is fired with an - L{IOError} L{Failure} if the child process writes to stderr. - """ - # make sure stderr raises an error normally - scriptFile = self.makeSourceFile([ - 'import sys', - 'sys.stderr.write("hello world\\n")' - ]) - - d = utils.getProcessOutput(self.exe, ['-u', scriptFile]) - d = self.assertFailure(d, IOError) - def cbFailed(err): - return self.assertFailure(err.processEnded, error.ProcessDone) - d.addCallback(cbFailed) - return d - - - def test_outputWithErrorCollected(self): - """ - If a C{True} value is supplied for the C{errortoo} parameter to - L{getProcessOutput}, the returned L{Deferred} fires with the child's - stderr output as well as its stdout output. - """ - scriptFile = self.makeSourceFile([ - 'import sys', - # Write the same value to both because ordering isn't guaranteed so - # this simplifies the test. - 'sys.stdout.write("foo")', - 'sys.stdout.flush()', - 'sys.stderr.write("foo")', - 'sys.stderr.flush()']) - - d = utils.getProcessOutput(self.exe, ['-u', scriptFile], errortoo=True) - return d.addCallback(self.assertEqual, "foofoo") - - - def test_value(self): - """ - The L{Deferred} returned by L{getProcessValue} is fired with the exit - status of the child process. - """ - scriptFile = self.makeSourceFile(["raise SystemExit(1)"]) - - d = utils.getProcessValue(self.exe, ['-u', scriptFile]) - return d.addCallback(self.assertEqual, 1) - - - def test_outputAndValue(self): - """ - The L{Deferred} returned by L{getProcessOutputAndValue} fires with a - three-tuple, the elements of which give the data written to the child's - stdout, the data written to the child's stderr, and the exit status of - the child. - """ - scriptFile = self.makeSourceFile([ - "import sys", - "sys.stdout.write('hello world!\\n')", - "sys.stderr.write('goodbye world!\\n')", - "sys.exit(1)" - ]) - - def gotOutputAndValue(out_err_code): - out, err, code = out_err_code - self.assertEqual(out, "hello world!\n") - self.assertEqual(err, "goodbye world!" + os.linesep) - self.assertEqual(code, 1) - d = utils.getProcessOutputAndValue(self.exe, ["-u", scriptFile]) - return d.addCallback(gotOutputAndValue) - - - def test_outputSignal(self): - """ - If the child process exits because of a signal, the L{Deferred} - returned by L{getProcessOutputAndValue} fires a L{Failure} of a tuple - containing the child's stdout, stderr, and the signal which caused - it to exit. - """ - # Use SIGKILL here because it's guaranteed to be delivered. Using - # SIGHUP might not work in, e.g., a buildbot slave run under the - # 'nohup' command. - scriptFile = self.makeSourceFile([ - "import sys, os, signal", - "sys.stdout.write('stdout bytes\\n')", - "sys.stderr.write('stderr bytes\\n')", - "sys.stdout.flush()", - "sys.stderr.flush()", - "os.kill(os.getpid(), signal.SIGKILL)"]) - - def gotOutputAndValue(out_err_sig): - out, err, sig = out_err_sig - self.assertEqual(out, "stdout bytes\n") - self.assertEqual(err, "stderr bytes\n") - self.assertEqual(sig, signal.SIGKILL) - - d = utils.getProcessOutputAndValue(self.exe, ['-u', scriptFile]) - d = self.assertFailure(d, tuple) - return d.addCallback(gotOutputAndValue) - - if platform.isWindows(): - test_outputSignal.skip = "Windows doesn't have real signals." - - - def _pathTest(self, utilFunc, check): - dir = os.path.abspath(self.mktemp()) - os.makedirs(dir) - scriptFile = self.makeSourceFile([ - "import os, sys", - "sys.stdout.write(os.getcwd())"]) - d = utilFunc(self.exe, ['-u', scriptFile], path=dir) - d.addCallback(check, dir) - return d - - - def test_getProcessOutputPath(self): - """ - L{getProcessOutput} runs the given command with the working directory - given by the C{path} parameter. - """ - return self._pathTest(utils.getProcessOutput, self.assertEqual) - - - def test_getProcessValuePath(self): - """ - L{getProcessValue} runs the given command with the working directory - given by the C{path} parameter. - """ - def check(result, ignored): - self.assertEqual(result, 0) - return self._pathTest(utils.getProcessValue, check) - - - def test_getProcessOutputAndValuePath(self): - """ - L{getProcessOutputAndValue} runs the given command with the working - directory given by the C{path} parameter. - """ - def check(out_err_status, dir): - out, err, status = out_err_status - self.assertEqual(out, dir) - self.assertEqual(status, 0) - return self._pathTest(utils.getProcessOutputAndValue, check) - - - def _defaultPathTest(self, utilFunc, check): - # Make another directory to mess around with. - dir = os.path.abspath(self.mktemp()) - os.makedirs(dir) - - scriptFile = self.makeSourceFile([ - "import os, sys, stat", - # Fix the permissions so we can report the working directory. - # On OS X (and maybe elsewhere), os.getcwd() fails with EACCES - # if +x is missing from the working directory. - "os.chmod(%r, stat.S_IXUSR)" % (dir,), - "sys.stdout.write(os.getcwd())"]) - - # Switch to it, but make sure we switch back - self.addCleanup(os.chdir, os.getcwd()) - os.chdir(dir) - - # Get rid of all its permissions, but make sure they get cleaned up - # later, because otherwise it might be hard to delete the trial - # temporary directory. - self.addCleanup( - os.chmod, dir, stat.S_IMODE(os.stat('.').st_mode)) - os.chmod(dir, 0) - - d = utilFunc(self.exe, ['-u', scriptFile]) - d.addCallback(check, dir) - return d - - - def test_getProcessOutputDefaultPath(self): - """ - If no value is supplied for the C{path} parameter, L{getProcessOutput} - runs the given command in the same working directory as the parent - process and succeeds even if the current working directory is not - accessible. - """ - return self._defaultPathTest(utils.getProcessOutput, self.assertEqual) - - - def test_getProcessValueDefaultPath(self): - """ - If no value is supplied for the C{path} parameter, L{getProcessValue} - runs the given command in the same working directory as the parent - process and succeeds even if the current working directory is not - accessible. - """ - def check(result, ignored): - self.assertEqual(result, 0) - return self._defaultPathTest(utils.getProcessValue, check) - - - def test_getProcessOutputAndValueDefaultPath(self): - """ - If no value is supplied for the C{path} parameter, - L{getProcessOutputAndValue} runs the given command in the same working - directory as the parent process and succeeds even if the current - working directory is not accessible. - """ - def check(out_err_status, dir): - out, err, status = out_err_status - self.assertEqual(out, dir) - self.assertEqual(status, 0) - return self._defaultPathTest( - utils.getProcessOutputAndValue, check) - - - -class SuppressWarningsTests(unittest.SynchronousTestCase): - """ - Tests for L{utils.suppressWarnings}. - """ - def test_suppressWarnings(self): - """ - L{utils.suppressWarnings} decorates a function so that the given - warnings are suppressed. - """ - result = [] - def showwarning(self, *a, **kw): - result.append((a, kw)) - self.patch(warnings, "showwarning", showwarning) - - def f(msg): - warnings.warn(msg) - g = utils.suppressWarnings(f, (('ignore',), dict(message="This is message"))) - - # Start off with a sanity check - calling the original function - # should emit the warning. - f("Sanity check message") - self.assertEqual(len(result), 1) - - # Now that that's out of the way, call the wrapped function, and - # make sure no new warnings show up. - g("This is message") - self.assertEqual(len(result), 1) - - # Finally, emit another warning which should not be ignored, and - # make sure it is not. - g("Unignored message") - self.assertEqual(len(result), 2) - - - -class DeferredSuppressedWarningsTests(SuppressedWarningsTests): - """ - Tests for L{utils.runWithWarningsSuppressed}, the version that supports - Deferreds. - """ - # Override the non-Deferred-supporting function from the base class with - # the function we are testing in this class: - runWithWarningsSuppressed = staticmethod(utils.runWithWarningsSuppressed) - - def test_deferredCallback(self): - """ - If the function called by L{utils.runWithWarningsSuppressed} returns a - C{Deferred}, the warning filters aren't removed until the Deferred - fires. - """ - filters = [(("ignore", ".*foo.*"), {}), - (("ignore", ".*bar.*"), {})] - result = Deferred() - self.runWithWarningsSuppressed(filters, lambda: result) - warnings.warn("ignore foo") - result.callback(3) - warnings.warn("ignore foo 2") - self.assertEqual( - ["ignore foo 2"], [w['message'] for w in self.flushWarnings()]) - - - def test_deferredErrback(self): - """ - If the function called by L{utils.runWithWarningsSuppressed} returns a - C{Deferred}, the warning filters aren't removed until the Deferred - fires with an errback. - """ - filters = [(("ignore", ".*foo.*"), {}), - (("ignore", ".*bar.*"), {})] - result = Deferred() - d = self.runWithWarningsSuppressed(filters, lambda: result) - warnings.warn("ignore foo") - result.errback(ZeroDivisionError()) - d.addErrback(lambda f: f.trap(ZeroDivisionError)) - warnings.warn("ignore foo 2") - self.assertEqual( - ["ignore foo 2"], [w['message'] for w in self.flushWarnings()]) - -if _PY3: - del ProcessUtilsTests diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_jelly.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_jelly.py deleted file mode 100644 index f11fd55..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_jelly.py +++ /dev/null @@ -1,680 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{jelly} object serialization. -""" - -import datetime -import decimal - -from twisted.spread import jelly, pb -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport - - -class TestNode(object, jelly.Jellyable): - """ - An object to test jellyfying of new style class instances. - """ - classAttr = 4 - - def __init__(self, parent=None): - if parent: - self.id = parent.id + 1 - parent.children.append(self) - else: - self.id = 1 - self.parent = parent - self.children = [] - - - -class A: - """ - Dummy class. - """ - - def amethod(self): - """ - Method tp be used in serialization tests. - """ - - - -def afunc(self): - """ - A dummy function to test function serialization. - """ - - - -class B: - """ - Dummy class. - """ - - def bmethod(self): - """ - Method to be used in serialization tests. - """ - - - -class C: - """ - Dummy class. - """ - - def cmethod(self): - """ - Method to be used in serialization tests. - """ - - - -class D(object): - """ - Dummy new-style class. - """ - - - -class E(object): - """ - Dummy new-style class with slots. - """ - - __slots__ = ("x", "y") - - def __init__(self, x=None, y=None): - self.x = x - self.y = y - - - def __getstate__(self): - return {"x" : self.x, "y" : self.y} - - - def __setstate__(self, state): - self.x = state["x"] - self.y = state["y"] - - - -class SimpleJellyTest: - def __init__(self, x, y): - self.x = x - self.y = y - - def isTheSameAs(self, other): - return self.__dict__ == other.__dict__ - - - -class JellyTests(unittest.TestCase): - """ - Testcases for L{jelly} module serialization. - - @cvar decimalData: serialized version of decimal data, to be used in tests. - @type decimalData: C{list} - """ - - def _testSecurity(self, inputList, atom): - """ - Helper test method to test security options for a type. - - @param inputList: a sample input for the type. - @param inputList: C{list} - - @param atom: atom identifier for the type. - @type atom: C{str} - """ - c = jelly.jelly(inputList) - taster = jelly.SecurityOptions() - taster.allowBasicTypes() - # By default, it should succeed - jelly.unjelly(c, taster) - taster.allowedTypes.pop(atom) - # But it should raise an exception when disallowed - self.assertRaises(jelly.InsecureJelly, jelly.unjelly, c, taster) - - - def test_methodSelfIdentity(self): - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - im_ = jelly.unjelly(jelly.jelly(b)).a.bmethod - self.assertEqual(im_.im_class, im_.im_self.__class__) - - - def test_methodsNotSelfIdentity(self): - """ - If a class change after an instance has been created, L{jelly.unjelly} - shoud raise a C{TypeError} when trying to unjelly the instance. - """ - a = A() - b = B() - c = C() - a.bmethod = c.cmethod - b.a = a - savecmethod = C.cmethod - del C.cmethod - try: - self.assertRaises(TypeError, jelly.unjelly, jelly.jelly(b)) - finally: - C.cmethod = savecmethod - - - def test_newStyle(self): - n = D() - n.x = 1 - n2 = D() - n.n2 = n2 - n.n3 = n2 - c = jelly.jelly(n) - m = jelly.unjelly(c) - self.assertIsInstance(m, D) - self.assertIdentical(m.n2, m.n3) - - - def test_newStyleWithSlots(self): - """ - A class defined with I{slots} can be jellied and unjellied with the - values for its attributes preserved. - """ - n = E() - n.x = 1 - c = jelly.jelly(n) - m = jelly.unjelly(c) - self.assertIsInstance(m, E) - self.assertEqual(n.x, 1) - - - def test_typeOldStyle(self): - """ - Test that an old style class type can be jellied and unjellied - to the original type. - """ - t = [C] - r = jelly.unjelly(jelly.jelly(t)) - self.assertEqual(t, r) - - - def test_typeNewStyle(self): - """ - Test that a new style class type can be jellied and unjellied - to the original type. - """ - t = [D] - r = jelly.unjelly(jelly.jelly(t)) - self.assertEqual(t, r) - - - def test_typeBuiltin(self): - """ - Test that a builtin type can be jellied and unjellied to the original - type. - """ - t = [str] - r = jelly.unjelly(jelly.jelly(t)) - self.assertEqual(t, r) - - - def test_dateTime(self): - dtn = datetime.datetime.now() - dtd = datetime.datetime.now() - dtn - input = [dtn, dtd] - c = jelly.jelly(input) - output = jelly.unjelly(c) - self.assertEqual(input, output) - self.assertNotIdentical(input, output) - - - def test_decimal(self): - """ - Jellying L{decimal.Decimal} instances and then unjellying the result - should produce objects which represent the values of the original - inputs. - """ - inputList = [decimal.Decimal('9.95'), - decimal.Decimal(0), - decimal.Decimal(123456), - decimal.Decimal('-78.901')] - c = jelly.jelly(inputList) - output = jelly.unjelly(c) - self.assertEqual(inputList, output) - self.assertNotIdentical(inputList, output) - - - decimalData = ['list', ['decimal', 995, -2], ['decimal', 0, 0], - ['decimal', 123456, 0], ['decimal', -78901, -3]] - - - def test_decimalUnjelly(self): - """ - Unjellying the s-expressions produced by jelly for L{decimal.Decimal} - instances should result in L{decimal.Decimal} instances with the values - represented by the s-expressions. - - This test also verifies that C{self.decimalData} contains valid jellied - data. This is important since L{test_decimalMissing} re-uses - C{self.decimalData} and is expected to be unable to produce - L{decimal.Decimal} instances even though the s-expression correctly - represents a list of them. - """ - expected = [decimal.Decimal('9.95'), - decimal.Decimal(0), - decimal.Decimal(123456), - decimal.Decimal('-78.901')] - output = jelly.unjelly(self.decimalData) - self.assertEqual(output, expected) - - - def test_decimalSecurity(self): - """ - By default, C{decimal} objects should be allowed by - L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise - L{jelly.InsecureJelly} when trying to unjelly it. - """ - inputList = [decimal.Decimal('9.95')] - self._testSecurity(inputList, "decimal") - - - def test_set(self): - """ - Jellying C{set} instances and then unjellying the result - should produce objects which represent the values of the original - inputs. - """ - inputList = [set([1, 2, 3])] - output = jelly.unjelly(jelly.jelly(inputList)) - self.assertEqual(inputList, output) - self.assertNotIdentical(inputList, output) - - - def test_frozenset(self): - """ - Jellying C{frozenset} instances and then unjellying the result - should produce objects which represent the values of the original - inputs. - """ - inputList = [frozenset([1, 2, 3])] - output = jelly.unjelly(jelly.jelly(inputList)) - self.assertEqual(inputList, output) - self.assertNotIdentical(inputList, output) - - - def test_setSecurity(self): - """ - By default, C{set} objects should be allowed by - L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise - L{jelly.InsecureJelly} when trying to unjelly it. - """ - inputList = [set([1, 2, 3])] - self._testSecurity(inputList, "set") - - - def test_frozensetSecurity(self): - """ - By default, C{frozenset} objects should be allowed by - L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise - L{jelly.InsecureJelly} when trying to unjelly it. - """ - inputList = [frozenset([1, 2, 3])] - self._testSecurity(inputList, "frozenset") - - - def test_oldSets(self): - """ - Test jellying C{sets.Set}: it should serialize to the same thing as - C{set} jelly, and be unjellied as C{set} if available. - """ - inputList = [jelly._sets.Set([1, 2, 3])] - inputJelly = jelly.jelly(inputList) - self.assertEqual(inputJelly, jelly.jelly([set([1, 2, 3])])) - output = jelly.unjelly(inputJelly) - # Even if the class is different, it should coerce to the same list - self.assertEqual(list(inputList[0]), list(output[0])) - if set is jelly._sets.Set: - self.assertIsInstance(output[0], jelly._sets.Set) - else: - self.assertIsInstance(output[0], set) - - - def test_oldImmutableSets(self): - """ - Test jellying C{sets.ImmutableSet}: it should serialize to the same - thing as C{frozenset} jelly, and be unjellied as C{frozenset} if - available. - """ - inputList = [jelly._sets.ImmutableSet([1, 2, 3])] - inputJelly = jelly.jelly(inputList) - self.assertEqual(inputJelly, jelly.jelly([frozenset([1, 2, 3])])) - output = jelly.unjelly(inputJelly) - # Even if the class is different, it should coerce to the same list - self.assertEqual(list(inputList[0]), list(output[0])) - if frozenset is jelly._sets.ImmutableSet: - self.assertIsInstance(output[0], jelly._sets.ImmutableSet) - else: - self.assertIsInstance(output[0], frozenset) - - - def test_simple(self): - """ - Simplest test case. - """ - self.failUnless(SimpleJellyTest('a', 'b').isTheSameAs( - SimpleJellyTest('a', 'b'))) - a = SimpleJellyTest(1, 2) - cereal = jelly.jelly(a) - b = jelly.unjelly(cereal) - self.failUnless(a.isTheSameAs(b)) - - - def test_identity(self): - """ - Test to make sure that objects retain identity properly. - """ - x = [] - y = (x) - x.append(y) - x.append(y) - self.assertIdentical(x[0], x[1]) - self.assertIdentical(x[0][0], x) - s = jelly.jelly(x) - z = jelly.unjelly(s) - self.assertIdentical(z[0], z[1]) - self.assertIdentical(z[0][0], z) - - - def test_unicode(self): - x = unicode('blah') - y = jelly.unjelly(jelly.jelly(x)) - self.assertEqual(x, y) - self.assertEqual(type(x), type(y)) - - - def test_stressReferences(self): - reref = [] - toplevelTuple = ({'list': reref}, reref) - reref.append(toplevelTuple) - s = jelly.jelly(toplevelTuple) - z = jelly.unjelly(s) - self.assertIdentical(z[0]['list'], z[1]) - self.assertIdentical(z[0]['list'][0], z) - - - def test_moreReferences(self): - a = [] - t = (a,) - a.append((t,)) - s = jelly.jelly(t) - z = jelly.unjelly(s) - self.assertIdentical(z[0][0][0], z) - - - def test_typeSecurity(self): - """ - Test for type-level security of serialization. - """ - taster = jelly.SecurityOptions() - dct = jelly.jelly({}) - self.assertRaises(jelly.InsecureJelly, jelly.unjelly, dct, taster) - - - def test_newStyleClasses(self): - uj = jelly.unjelly(D) - self.assertIdentical(D, uj) - - - def test_lotsaTypes(self): - """ - Test for all types currently supported in jelly - """ - a = A() - jelly.unjelly(jelly.jelly(a)) - jelly.unjelly(jelly.jelly(a.amethod)) - items = [afunc, [1, 2, 3], not bool(1), bool(1), 'test', 20.3, - (1, 2, 3), None, A, unittest, {'a': 1}, A.amethod] - for i in items: - self.assertEqual(i, jelly.unjelly(jelly.jelly(i))) - - - def test_setState(self): - global TupleState - class TupleState: - def __init__(self, other): - self.other = other - def __getstate__(self): - return (self.other,) - def __setstate__(self, state): - self.other = state[0] - def __hash__(self): - return hash(self.other) - a = A() - t1 = TupleState(a) - t2 = TupleState(a) - t3 = TupleState((t1, t2)) - d = {t1: t1, t2: t2, t3: t3, "t3": t3} - t3prime = jelly.unjelly(jelly.jelly(d))["t3"] - self.assertIdentical(t3prime.other[0].other, t3prime.other[1].other) - - - def test_classSecurity(self): - """ - Test for class-level security of serialization. - """ - taster = jelly.SecurityOptions() - taster.allowInstancesOf(A, B) - a = A() - b = B() - c = C() - # add a little complexity to the data - a.b = b - a.c = c - # and a backreference - a.x = b - b.c = c - # first, a friendly insecure serialization - friendly = jelly.jelly(a, taster) - x = jelly.unjelly(friendly, taster) - self.assertIsInstance(x.c, jelly.Unpersistable) - # now, a malicious one - mean = jelly.jelly(a) - self.assertRaises(jelly.InsecureJelly, jelly.unjelly, mean, taster) - self.assertIdentical(x.x, x.b, "Identity mismatch") - # test class serialization - friendly = jelly.jelly(A, taster) - x = jelly.unjelly(friendly, taster) - self.assertIdentical(x, A, "A came back: %s" % x) - - - def test_unjellyable(self): - """ - Test that if Unjellyable is used to deserialize a jellied object, - state comes out right. - """ - class JellyableTestClass(jelly.Jellyable): - pass - jelly.setUnjellyableForClass(JellyableTestClass, jelly.Unjellyable) - input = JellyableTestClass() - input.attribute = 'value' - output = jelly.unjelly(jelly.jelly(input)) - self.assertEqual(output.attribute, 'value') - self.assertIsInstance(output, jelly.Unjellyable) - - - def test_persistentStorage(self): - perst = [{}, 1] - def persistentStore(obj, jel, perst = perst): - perst[1] = perst[1] + 1 - perst[0][perst[1]] = obj - return str(perst[1]) - - def persistentLoad(pidstr, unj, perst = perst): - pid = int(pidstr) - return perst[0][pid] - - a = SimpleJellyTest(1, 2) - b = SimpleJellyTest(3, 4) - c = SimpleJellyTest(5, 6) - - a.b = b - a.c = c - c.b = b - - jel = jelly.jelly(a, persistentStore = persistentStore) - x = jelly.unjelly(jel, persistentLoad = persistentLoad) - - self.assertIdentical(x.b, x.c.b) - self.failUnless(perst[0], "persistentStore was not called.") - self.assertIdentical(x.b, a.b, "Persistent storage identity failure.") - - - def test_newStyleClassesAttributes(self): - n = TestNode() - n1 = TestNode(n) - TestNode(n1) - TestNode(n) - # Jelly it - jel = jelly.jelly(n) - m = jelly.unjelly(jel) - # Check that it has been restored ok - self._check_newstyle(n, m) - - - def _check_newstyle(self, a, b): - self.assertEqual(a.id, b.id) - self.assertEqual(a.classAttr, 4) - self.assertEqual(b.classAttr, 4) - self.assertEqual(len(a.children), len(b.children)) - for x, y in zip(a.children, b.children): - self._check_newstyle(x, y) - - - def test_referenceable(self): - """ - A L{pb.Referenceable} instance jellies to a structure which unjellies to - a L{pb.RemoteReference}. The C{RemoteReference} has a I{luid} that - matches up with the local object key in the L{pb.Broker} which sent the - L{Referenceable}. - """ - ref = pb.Referenceable() - jellyBroker = pb.Broker() - jellyBroker.makeConnection(StringTransport()) - j = jelly.jelly(ref, invoker=jellyBroker) - - unjellyBroker = pb.Broker() - unjellyBroker.makeConnection(StringTransport()) - - uj = jelly.unjelly(j, invoker=unjellyBroker) - self.assertIn(uj.luid, jellyBroker.localObjects) - - - -class JellyDeprecationTests(unittest.TestCase): - """ - Tests for deprecated Jelly things - """ - - def test_deprecatedInstanceAtom(self): - """ - L{jelly.instance_atom} is deprecated since 15.0.0. - """ - jelly.instance_atom - warnings = self.flushWarnings([self.test_deprecatedInstanceAtom]) - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], - 'twisted.spread.jelly.instance_atom was deprecated in Twisted ' - '15.0.0: instance_atom is unused within Twisted.') - self.assertEqual( - warnings[0]['category'], - DeprecationWarning) - - - def test_deprecatedUnjellyingInstanceAtom(self): - """ - Unjellying the instance atom is deprecated with 15.0.0. - """ - jelly.unjelly( - ["instance", - ["class", "twisted.test.test_jelly.A"], - ["dictionary"]]) - warnings = self.flushWarnings() - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], - "Unjelly support for the instance atom is deprecated since " - "Twisted 15.0.0. Upgrade peer for modern instance support.") - self.assertEqual( - warnings[0]['category'], - DeprecationWarning) - - - -class ClassA(pb.Copyable, pb.RemoteCopy): - def __init__(self): - self.ref = ClassB(self) - - - -class ClassB(pb.Copyable, pb.RemoteCopy): - def __init__(self, ref): - self.ref = ref - - - -class CircularReferenceTests(unittest.TestCase): - """ - Tests for circular references handling in the jelly/unjelly process. - """ - - def test_simpleCircle(self): - jelly.setUnjellyableForClass(ClassA, ClassA) - jelly.setUnjellyableForClass(ClassB, ClassB) - a = jelly.unjelly(jelly.jelly(ClassA())) - self.assertIdentical(a.ref.ref, a, - "Identity not preserved in circular reference") - - - def test_circleWithInvoker(self): - class DummyInvokerClass: - pass - dummyInvoker = DummyInvokerClass() - dummyInvoker.serializingPerspective = None - a0 = ClassA() - jelly.setUnjellyableForClass(ClassA, ClassA) - jelly.setUnjellyableForClass(ClassB, ClassB) - j = jelly.jelly(a0, invoker=dummyInvoker) - a1 = jelly.unjelly(j) - self.failUnlessIdentical(a1.ref.ref, a1, - "Identity not preserved in circular reference") - - - def test_set(self): - """ - Check that a C{set} can contain a circular reference and be serialized - and unserialized without losing the reference. - """ - s = set() - a = SimpleJellyTest(s, None) - s.add(a) - res = jelly.unjelly(jelly.jelly(a)) - self.assertIsInstance(res.x, set) - self.assertEqual(list(res.x), [res]) - - - def test_frozenset(self): - """ - Check that a C{frozenset} can contain a circular reference and be - serializeserialized without losing the reference. - """ - a = SimpleJellyTest(None, None) - s = frozenset([a]) - a.x = s - res = jelly.unjelly(jelly.jelly(a)) - self.assertIsInstance(res.x, frozenset) - self.assertEqual(list(res.x), [res]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_lockfile.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_lockfile.py deleted file mode 100644 index 59e0e8d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_lockfile.py +++ /dev/null @@ -1,445 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.lockfile}. -""" - -import os, errno - -from twisted.trial import unittest -from twisted.python import lockfile -from twisted.python.reflect import requireModule -from twisted.python.runtime import platform - -skipKill = None -if platform.isWindows(): - if(requireModule('win32api.OpenProcess') is None and - requireModule('pywintypes') is None - ): - skipKill = ("On windows, lockfile.kill is not implemented in the " - "absence of win32api and/or pywintypes.") - -class UtilTests(unittest.TestCase): - """ - Tests for the helper functions used to implement L{FilesystemLock}. - """ - def test_symlinkEEXIST(self): - """ - L{lockfile.symlink} raises L{OSError} with C{errno} set to L{EEXIST} - when an attempt is made to create a symlink which already exists. - """ - name = self.mktemp() - lockfile.symlink('foo', name) - exc = self.assertRaises(OSError, lockfile.symlink, 'foo', name) - self.assertEqual(exc.errno, errno.EEXIST) - - - def test_symlinkEIOWindows(self): - """ - L{lockfile.symlink} raises L{OSError} with C{errno} set to L{EIO} when - the underlying L{rename} call fails with L{EIO}. - - Renaming a file on Windows may fail if the target of the rename is in - the process of being deleted (directory deletion appears not to be - atomic). - """ - name = self.mktemp() - def fakeRename(src, dst): - raise IOError(errno.EIO, None) - self.patch(lockfile, 'rename', fakeRename) - exc = self.assertRaises(IOError, lockfile.symlink, name, "foo") - self.assertEqual(exc.errno, errno.EIO) - if not platform.isWindows(): - test_symlinkEIOWindows.skip = ( - "special rename EIO handling only necessary and correct on " - "Windows.") - - - def test_readlinkENOENT(self): - """ - L{lockfile.readlink} raises L{OSError} with C{errno} set to L{ENOENT} - when an attempt is made to read a symlink which does not exist. - """ - name = self.mktemp() - exc = self.assertRaises(OSError, lockfile.readlink, name) - self.assertEqual(exc.errno, errno.ENOENT) - - - def test_readlinkEACCESWindows(self): - """ - L{lockfile.readlink} raises L{OSError} with C{errno} set to L{EACCES} - on Windows when the underlying file open attempt fails with C{EACCES}. - - Opening a file on Windows may fail if the path is inside a directory - which is in the process of being deleted (directory deletion appears - not to be atomic). - """ - name = self.mktemp() - def fakeOpen(path, mode): - raise IOError(errno.EACCES, None) - self.patch(lockfile, '_open', fakeOpen) - exc = self.assertRaises(IOError, lockfile.readlink, name) - self.assertEqual(exc.errno, errno.EACCES) - if not platform.isWindows(): - test_readlinkEACCESWindows.skip = ( - "special readlink EACCES handling only necessary and correct on " - "Windows.") - - - def test_kill(self): - """ - L{lockfile.kill} returns without error if passed the PID of a - process which exists and signal C{0}. - """ - lockfile.kill(os.getpid(), 0) - test_kill.skip = skipKill - - - def test_killESRCH(self): - """ - L{lockfile.kill} raises L{OSError} with errno of L{ESRCH} if - passed a PID which does not correspond to any process. - """ - # Hopefully there is no process with PID 2 ** 31 - 1 - exc = self.assertRaises(OSError, lockfile.kill, 2 ** 31 - 1, 0) - self.assertEqual(exc.errno, errno.ESRCH) - test_killESRCH.skip = skipKill - - - def test_noKillCall(self): - """ - Verify that when L{lockfile.kill} does end up as None (e.g. on Windows - without pywin32), it doesn't end up being called and raising a - L{TypeError}. - """ - self.patch(lockfile, "kill", None) - fl = lockfile.FilesystemLock(self.mktemp()) - fl.lock() - self.assertFalse(fl.lock()) - - - -class LockingTests(unittest.TestCase): - def _symlinkErrorTest(self, errno): - def fakeSymlink(source, dest): - raise OSError(errno, None) - self.patch(lockfile, 'symlink', fakeSymlink) - - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - exc = self.assertRaises(OSError, lock.lock) - self.assertEqual(exc.errno, errno) - - - def test_symlinkError(self): - """ - An exception raised by C{symlink} other than C{EEXIST} is passed up to - the caller of L{FilesystemLock.lock}. - """ - self._symlinkErrorTest(errno.ENOSYS) - - - def test_symlinkErrorPOSIX(self): - """ - An L{OSError} raised by C{symlink} on a POSIX platform with an errno of - C{EACCES} or C{EIO} is passed to the caller of L{FilesystemLock.lock}. - - On POSIX, unlike on Windows, these are unexpected errors which cannot - be handled by L{FilesystemLock}. - """ - self._symlinkErrorTest(errno.EACCES) - self._symlinkErrorTest(errno.EIO) - if platform.isWindows(): - test_symlinkErrorPOSIX.skip = ( - "POSIX-specific error propagation not expected on Windows.") - - - def test_cleanlyAcquire(self): - """ - If the lock has never been held, it can be acquired and the C{clean} - and C{locked} attributes are set to C{True}. - """ - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - self.assertTrue(lock.lock()) - self.assertTrue(lock.clean) - self.assertTrue(lock.locked) - - - def test_cleanlyRelease(self): - """ - If a lock is released cleanly, it can be re-acquired and the C{clean} - and C{locked} attributes are set to C{True}. - """ - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - self.assertTrue(lock.lock()) - lock.unlock() - self.assertFalse(lock.locked) - - lock = lockfile.FilesystemLock(lockf) - self.assertTrue(lock.lock()) - self.assertTrue(lock.clean) - self.assertTrue(lock.locked) - - - def test_cannotLockLocked(self): - """ - If a lock is currently locked, it cannot be locked again. - """ - lockf = self.mktemp() - firstLock = lockfile.FilesystemLock(lockf) - self.assertTrue(firstLock.lock()) - - secondLock = lockfile.FilesystemLock(lockf) - self.assertFalse(secondLock.lock()) - self.assertFalse(secondLock.locked) - - - def test_uncleanlyAcquire(self): - """ - If a lock was held by a process which no longer exists, it can be - acquired, the C{clean} attribute is set to C{False}, and the - C{locked} attribute is set to C{True}. - """ - owner = 12345 - - def fakeKill(pid, signal): - if signal != 0: - raise OSError(errno.EPERM, None) - if pid == owner: - raise OSError(errno.ESRCH, None) - - lockf = self.mktemp() - self.patch(lockfile, 'kill', fakeKill) - lockfile.symlink(str(owner), lockf) - - lock = lockfile.FilesystemLock(lockf) - self.assertTrue(lock.lock()) - self.assertFalse(lock.clean) - self.assertTrue(lock.locked) - - self.assertEqual(lockfile.readlink(lockf), str(os.getpid())) - - - def test_lockReleasedBeforeCheck(self): - """ - If the lock is initially held but then released before it can be - examined to determine if the process which held it still exists, it is - acquired and the C{clean} and C{locked} attributes are set to C{True}. - """ - def fakeReadlink(name): - # Pretend to be another process releasing the lock. - lockfile.rmlink(lockf) - # Fall back to the real implementation of readlink. - readlinkPatch.restore() - return lockfile.readlink(name) - readlinkPatch = self.patch(lockfile, 'readlink', fakeReadlink) - - def fakeKill(pid, signal): - if signal != 0: - raise OSError(errno.EPERM, None) - if pid == 43125: - raise OSError(errno.ESRCH, None) - self.patch(lockfile, 'kill', fakeKill) - - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - lockfile.symlink(str(43125), lockf) - self.assertTrue(lock.lock()) - self.assertTrue(lock.clean) - self.assertTrue(lock.locked) - - - def test_lockReleasedDuringAcquireSymlink(self): - """ - If the lock is released while an attempt is made to acquire - it, the lock attempt fails and C{FilesystemLock.lock} returns - C{False}. This can happen on Windows when L{lockfile.symlink} - fails with L{IOError} of C{EIO} because another process is in - the middle of a call to L{os.rmdir} (implemented in terms of - RemoveDirectory) which is not atomic. - """ - def fakeSymlink(src, dst): - # While another process id doing os.rmdir which the Windows - # implementation of rmlink does, a rename call will fail with EIO. - raise OSError(errno.EIO, None) - - self.patch(lockfile, 'symlink', fakeSymlink) - - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - self.assertFalse(lock.lock()) - self.assertFalse(lock.locked) - if not platform.isWindows(): - test_lockReleasedDuringAcquireSymlink.skip = ( - "special rename EIO handling only necessary and correct on " - "Windows.") - - - def test_lockReleasedDuringAcquireReadlink(self): - """ - If the lock is initially held but is released while an attempt - is made to acquire it, the lock attempt fails and - L{FilesystemLock.lock} returns C{False}. - """ - def fakeReadlink(name): - # While another process is doing os.rmdir which the - # Windows implementation of rmlink does, a readlink call - # will fail with EACCES. - raise IOError(errno.EACCES, None) - self.patch(lockfile, 'readlink', fakeReadlink) - - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - lockfile.symlink(str(43125), lockf) - self.assertFalse(lock.lock()) - self.assertFalse(lock.locked) - if not platform.isWindows(): - test_lockReleasedDuringAcquireReadlink.skip = ( - "special readlink EACCES handling only necessary and correct on " - "Windows.") - - - def _readlinkErrorTest(self, exceptionType, errno): - def fakeReadlink(name): - raise exceptionType(errno, None) - self.patch(lockfile, 'readlink', fakeReadlink) - - lockf = self.mktemp() - - # Make it appear locked so it has to use readlink - lockfile.symlink(str(43125), lockf) - - lock = lockfile.FilesystemLock(lockf) - exc = self.assertRaises(exceptionType, lock.lock) - self.assertEqual(exc.errno, errno) - self.assertFalse(lock.locked) - - - def test_readlinkError(self): - """ - An exception raised by C{readlink} other than C{ENOENT} is passed up to - the caller of L{FilesystemLock.lock}. - """ - self._readlinkErrorTest(OSError, errno.ENOSYS) - self._readlinkErrorTest(IOError, errno.ENOSYS) - - - def test_readlinkErrorPOSIX(self): - """ - Any L{IOError} raised by C{readlink} on a POSIX platform passed to the - caller of L{FilesystemLock.lock}. - - On POSIX, unlike on Windows, these are unexpected errors which cannot - be handled by L{FilesystemLock}. - """ - self._readlinkErrorTest(IOError, errno.ENOSYS) - self._readlinkErrorTest(IOError, errno.EACCES) - if platform.isWindows(): - test_readlinkErrorPOSIX.skip = ( - "POSIX-specific error propagation not expected on Windows.") - - - def test_lockCleanedUpConcurrently(self): - """ - If a second process cleans up the lock after a first one checks the - lock and finds that no process is holding it, the first process does - not fail when it tries to clean up the lock. - """ - def fakeRmlink(name): - rmlinkPatch.restore() - # Pretend to be another process cleaning up the lock. - lockfile.rmlink(lockf) - # Fall back to the real implementation of rmlink. - return lockfile.rmlink(name) - rmlinkPatch = self.patch(lockfile, 'rmlink', fakeRmlink) - - def fakeKill(pid, signal): - if signal != 0: - raise OSError(errno.EPERM, None) - if pid == 43125: - raise OSError(errno.ESRCH, None) - self.patch(lockfile, 'kill', fakeKill) - - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - lockfile.symlink(str(43125), lockf) - self.assertTrue(lock.lock()) - self.assertTrue(lock.clean) - self.assertTrue(lock.locked) - - - def test_rmlinkError(self): - """ - An exception raised by L{rmlink} other than C{ENOENT} is passed up - to the caller of L{FilesystemLock.lock}. - """ - def fakeRmlink(name): - raise OSError(errno.ENOSYS, None) - self.patch(lockfile, 'rmlink', fakeRmlink) - - def fakeKill(pid, signal): - if signal != 0: - raise OSError(errno.EPERM, None) - if pid == 43125: - raise OSError(errno.ESRCH, None) - self.patch(lockfile, 'kill', fakeKill) - - lockf = self.mktemp() - - # Make it appear locked so it has to use readlink - lockfile.symlink(str(43125), lockf) - - lock = lockfile.FilesystemLock(lockf) - exc = self.assertRaises(OSError, lock.lock) - self.assertEqual(exc.errno, errno.ENOSYS) - self.assertFalse(lock.locked) - - - def test_killError(self): - """ - If L{kill} raises an exception other than L{OSError} with errno set to - C{ESRCH}, the exception is passed up to the caller of - L{FilesystemLock.lock}. - """ - def fakeKill(pid, signal): - raise OSError(errno.EPERM, None) - self.patch(lockfile, 'kill', fakeKill) - - lockf = self.mktemp() - - # Make it appear locked so it has to use readlink - lockfile.symlink(str(43125), lockf) - - lock = lockfile.FilesystemLock(lockf) - exc = self.assertRaises(OSError, lock.lock) - self.assertEqual(exc.errno, errno.EPERM) - self.assertFalse(lock.locked) - - - def test_unlockOther(self): - """ - L{FilesystemLock.unlock} raises L{ValueError} if called for a lock - which is held by a different process. - """ - lockf = self.mktemp() - lockfile.symlink(str(os.getpid() + 1), lockf) - lock = lockfile.FilesystemLock(lockf) - self.assertRaises(ValueError, lock.unlock) - - - def test_isLocked(self): - """ - L{isLocked} returns C{True} if the named lock is currently locked, - C{False} otherwise. - """ - lockf = self.mktemp() - self.assertFalse(lockfile.isLocked(lockf)) - lock = lockfile.FilesystemLock(lockf) - self.assertTrue(lock.lock()) - self.assertTrue(lockfile.isLocked(lockf)) - lock.unlock() - self.assertFalse(lockfile.isLocked(lockf)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_log.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_log.py deleted file mode 100644 index f3b2943..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_log.py +++ /dev/null @@ -1,1085 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.log}. -""" - -from __future__ import division, absolute_import, print_function - -from twisted.python.compat import _PY3, NativeStringIO as StringIO - -import os -import sys -import time -import logging -import warnings -import calendar -from io import IOBase - -from twisted.trial import unittest - -from twisted.python import log, failure -from twisted.logger.test.test_stdlib import handlerAndBytesIO -from twisted.python.log import LogPublisher -from twisted.logger import ( - LoggingFile, LogLevel as NewLogLevel, LogBeginner, - LogPublisher as NewLogPublisher -) - - -class FakeWarning(Warning): - """ - A unique L{Warning} subclass used by tests for interactions of - L{twisted.python.log} with the L{warnings} module. - """ - - - -class TextFromEventDictTests(unittest.SynchronousTestCase): - """ - Tests for L{textFromEventDict}. - """ - - def test_message(self): - """ - The C{"message"} value, when specified, is concatenated to generate the - message. - """ - eventDict = dict(message=("a", "b", "c")) - text = log.textFromEventDict(eventDict) - self.assertEquals(text, "a b c") - - - - def test_format(self): - """ - The C{"format"} value, when specified, is used to format the message. - """ - eventDict = dict( - message=(), isError=0, format="Hello, %(foo)s!", foo="dude" - ) - text = log.textFromEventDict(eventDict) - self.assertEquals(text, "Hello, dude!") - - - - def test_noMessageNoFormat(self): - """ - If C{"format"} is unspecified and C{"message"} is empty, return - C{None}. - """ - eventDict = dict(message=(), isError=0) - text = log.textFromEventDict(eventDict) - self.assertIdentical(text, None) - - - - def test_whySpecified(self): - """ - The C{"why"} value, when specified, is first part of message. - """ - try: - raise RuntimeError() - except: - eventDict = dict( - message=(), isError=1, failure=failure.Failure(), why="foo" - ) - text = log.textFromEventDict(eventDict) - self.assertTrue(text.startswith("foo\n")) - - - def test_whyDefault(self): - """ - The C{"why"} value, when unspecified, defaults to C{"Unhandled Error"}. - """ - try: - raise RuntimeError() - except: - eventDict = dict(message=(), isError=1, failure=failure.Failure()) - text = log.textFromEventDict(eventDict) - self.assertTrue(text.startswith("Unhandled Error\n")) - - - def test_noTracebackForYou(self): - """ - If unable to obtain a traceback due to an exception, catch it and note - the error. - """ - # Invalid failure object doesn't implement .getTraceback() - eventDict = dict(message=(), isError=1, failure=object()) - text = log.textFromEventDict(eventDict) - self.assertIn("\n(unable to obtain traceback)", text) - - - -class LogTests(unittest.SynchronousTestCase): - - def setUp(self): - self.catcher = [] - self.observer = self.catcher.append - log.addObserver(self.observer) - self.addCleanup(log.removeObserver, self.observer) - - - def testObservation(self): - catcher = self.catcher - log.msg("test", testShouldCatch=True) - i = catcher.pop() - self.assertEqual(i["message"][0], "test") - self.assertEqual(i["testShouldCatch"], True) - self.assertIn("time", i) - self.assertEqual(len(catcher), 0) - - - def testContext(self): - catcher = self.catcher - log.callWithContext({"subsystem": "not the default", - "subsubsystem": "a", - "other": "c"}, - log.callWithContext, - {"subsubsystem": "b"}, log.msg, "foo", other="d") - i = catcher.pop() - self.assertEqual(i['subsubsystem'], 'b') - self.assertEqual(i['subsystem'], 'not the default') - self.assertEqual(i['other'], 'd') - self.assertEqual(i['message'][0], 'foo') - - - def testErrors(self): - for e, ig in [("hello world", "hello world"), - (KeyError(), KeyError), - (failure.Failure(RuntimeError()), RuntimeError)]: - log.err(e) - i = self.catcher.pop() - self.assertEqual(i['isError'], 1) - self.flushLoggedErrors(ig) - - - def testErrorsWithWhy(self): - for e, ig in [("hello world", "hello world"), - (KeyError(), KeyError), - (failure.Failure(RuntimeError()), RuntimeError)]: - log.err(e, 'foobar') - i = self.catcher.pop() - self.assertEqual(i['isError'], 1) - self.assertEqual(i['why'], 'foobar') - self.flushLoggedErrors(ig) - - - def test_erroneousErrors(self): - """ - Exceptions raised by log observers are logged but the observer which - raised the exception remains registered with the publisher. These - exceptions do not prevent the event from being sent to other observers - registered with the publisher. - """ - L1 = [] - L2 = [] - - def broken(event): - 1 // 0 - - for observer in [L1.append, broken, L2.append]: - log.addObserver(observer) - self.addCleanup(log.removeObserver, observer) - - for i in range(3): - # Reset the lists for simpler comparison. - L1[:] = [] - L2[:] = [] - - # Send out the event which will break one of the observers. - log.msg("Howdy, y'all.", log_trace=[]) - - # The broken observer should have caused this to be logged. - excs = self.flushLoggedErrors(ZeroDivisionError) - del self.catcher[:] - self.assertEqual(len(excs), 1) - - # Both other observers should have seen the message. - self.assertEqual(len(L1), 2) - self.assertEqual(len(L2), 2) - - # The first event is delivered to all observers; then, errors - # are delivered. - self.assertEqual(L1[0]['message'], ("Howdy, y'all.",)) - self.assertEqual(L2[0]['message'], ("Howdy, y'all.",)) - - - def test_showwarning(self): - """ - L{twisted.python.log.showwarning} emits the warning as a message - to the Twisted logging system. - """ - publisher = log.LogPublisher() - publisher.addObserver(self.observer) - - publisher.showwarning( - FakeWarning("unique warning message"), FakeWarning, - "warning-filename.py", 27) - event = self.catcher.pop() - self.assertEqual( - event['format'] % event, - 'warning-filename.py:27: twisted.test.test_log.FakeWarning: ' - 'unique warning message') - self.assertEqual(self.catcher, []) - - # Python 2.6 requires that any function used to override the - # warnings.showwarning API accept a "line" parameter or a - # deprecation warning is emitted. - publisher.showwarning( - FakeWarning("unique warning message"), FakeWarning, - "warning-filename.py", 27, line=object()) - event = self.catcher.pop() - self.assertEqual( - event['format'] % event, - 'warning-filename.py:27: twisted.test.test_log.FakeWarning: ' - 'unique warning message') - self.assertEqual(self.catcher, []) - - - def test_warningToFile(self): - """ - L{twisted.python.log.showwarning} passes warnings with an explicit file - target on to the underlying Python warning system. - """ - message = "another unique message" - category = FakeWarning - filename = "warning-filename.py" - lineno = 31 - - output = StringIO() - log.showwarning(message, category, filename, lineno, file=output) - - self.assertEqual( - output.getvalue(), - warnings.formatwarning(message, category, filename, lineno)) - - # In Python 2.6, warnings.showwarning accepts a "line" argument which - # gives the source line the warning message is to include. - if sys.version_info >= (2, 6): - line = "hello world" - output = StringIO() - log.showwarning(message, category, filename, lineno, file=output, - line=line) - - self.assertEqual( - output.getvalue(), - warnings.formatwarning(message, category, filename, lineno, - line)) - - - def test_publisherReportsBrokenObserversPrivately(self): - """ - Log publisher does not use the global L{log.err} when reporting broken - observers. - """ - errors = [] - - def logError(eventDict): - if eventDict.get("isError"): - errors.append(eventDict["failure"].value) - - def fail(eventDict): - raise RuntimeError("test_publisherLocalyReportsBrokenObservers") - - publisher = log.LogPublisher() - publisher.addObserver(logError) - publisher.addObserver(fail) - - publisher.msg("Hello!") - self.assertEqual(set(publisher.observers), set([logError, fail])) - self.assertEqual(len(errors), 1) - self.assertIsInstance(errors[0], RuntimeError) - - - -class FakeFile(list): - - def write(self, bytes): - self.append(bytes) - - - def flush(self): - pass - - -IOBase.register(FakeFile) - - - -class EvilStr: - def __str__(self): - 1 // 0 - - - -class EvilRepr: - def __str__(self): - return "Happy Evil Repr" - - - def __repr__(self): - 1 // 0 - - - -class EvilReprStr(EvilStr, EvilRepr): - pass - - - -class LogPublisherTestCaseMixin: - def setUp(self): - """ - Add a log observer which records log events in C{self.out}. Also, - make sure the default string encoding is ASCII so that - L{testSingleUnicode} can test the behavior of logging unencodable - unicode messages. - """ - self.out = FakeFile() - self.lp = log.LogPublisher() - self.flo = log.FileLogObserver(self.out) - self.lp.addObserver(self.flo.emit) - - try: - str(u'\N{VULGAR FRACTION ONE HALF}') - except UnicodeEncodeError: - # This is the behavior we want - don't change anything. - self._origEncoding = None - else: - if _PY3: - self._origEncoding = None - return - reload(sys) - self._origEncoding = sys.getdefaultencoding() - sys.setdefaultencoding('ascii') - - - def tearDown(self): - """ - Verify that everything written to the fake file C{self.out} was a - C{str}. Also, restore the default string encoding to its previous - setting, if it was modified by L{setUp}. - """ - for chunk in self.out: - self.failUnless(isinstance(chunk, str), - "%r was not a string" % (chunk,)) - - if self._origEncoding is not None: - sys.setdefaultencoding(self._origEncoding) - del sys.setdefaultencoding - - - -class LogPublisherTests(LogPublisherTestCaseMixin, - unittest.SynchronousTestCase): - def testSingleString(self): - self.lp.msg("Hello, world.") - self.assertEqual(len(self.out), 1) - - - def testMultipleString(self): - # Test some stupid behavior that will be deprecated real soon. - # If you are reading this and trying to learn how the logging - # system works, *do not use this feature*. - self.lp.msg("Hello, ", "world.") - self.assertEqual(len(self.out), 1) - - - def test_singleUnicode(self): - """ - L{log.LogPublisher.msg} does not accept non-ASCII Unicode on Python 2, - logging an error instead. - - On Python 3, where Unicode is default message type, the message is - logged normally. - """ - message = u"Hello, \N{VULGAR FRACTION ONE HALF} world." - self.lp.msg(message) - self.assertEqual(len(self.out), 1) - if _PY3: - self.assertIn(message, self.out[0]) - else: - self.assertIn('with str error', self.out[0]) - self.assertIn('UnicodeEncodeError', self.out[0]) - - - -class FileObserverTests(LogPublisherTestCaseMixin, - unittest.SynchronousTestCase): - """ - Tests for L{log.FileObserver}. - """ - ERROR_INVALID_FORMAT = 'Invalid format string' - ERROR_UNFORMATTABLE_OBJECT = 'UNFORMATTABLE OBJECT' - ERROR_FORMAT = ( - 'Invalid format string or unformattable object in log message' - ) - ERROR_PATHOLOGICAL = 'PATHOLOGICAL ERROR' - - ERROR_NO_FORMAT = 'Unable to format event' - ERROR_UNFORMATTABLE_SYSTEM = '[UNFORMATTABLE]' - ERROR_MESSAGE_LOST = 'MESSAGE LOST: unformattable object logged' - - def _getTimezoneOffsetTest(self, tzname, daylightOffset, standardOffset): - """ - Verify that L{getTimezoneOffset} produces the expected offset for a - certain timezone both when daylight saving time is in effect and when - it is not. - - @param tzname: The name of a timezone to exercise. - @type tzname: L{bytes} - - @param daylightOffset: The number of seconds west of UTC the timezone - should be when daylight saving time is in effect. - @type daylightOffset: L{int} - - @param standardOffset: The number of seconds west of UTC the timezone - should be when daylight saving time is not in effect. - @type standardOffset: L{int} - """ - if getattr(time, 'tzset', None) is None: - raise unittest.SkipTest( - "Platform cannot change timezone, cannot verify correct " - "offsets in well-known timezones.") - - originalTimezone = os.environ.get('TZ', None) - try: - os.environ['TZ'] = tzname - time.tzset() - - # The behavior of mktime depends on the current timezone setting. - # So only do this after changing the timezone. - - # Compute a POSIX timestamp for a certain date and time that is - # known to occur at a time when daylight saving time is in effect. - localDaylightTuple = (2006, 6, 30, 0, 0, 0, 4, 181, 1) - daylight = time.mktime(localDaylightTuple) - - # Compute a POSIX timestamp for a certain date and time that is - # known to occur at a time when daylight saving time is not in - # effect. - localStandardTuple = (2007, 1, 31, 0, 0, 0, 2, 31, 0) - standard = time.mktime(localStandardTuple) - - self.assertEqual( - (self.flo.getTimezoneOffset(daylight), - self.flo.getTimezoneOffset(standard)), - (daylightOffset, standardOffset)) - finally: - if originalTimezone is None: - del os.environ['TZ'] - else: - os.environ['TZ'] = originalTimezone - time.tzset() - - - def test_getTimezoneOffsetWestOfUTC(self): - """ - Attempt to verify that L{FileLogObserver.getTimezoneOffset} returns - correct values for the current C{TZ} environment setting for at least - some cases. This test method exercises a timezone that is west of UTC - (and should produce positive results). - """ - self._getTimezoneOffsetTest("America/New_York", 14400, 18000) - - - def test_getTimezoneOffsetEastOfUTC(self): - """ - Attempt to verify that L{FileLogObserver.getTimezoneOffset} returns - correct values for the current C{TZ} environment setting for at least - some cases. This test method exercises a timezone that is east of UTC - (and should produce negative results). - """ - self._getTimezoneOffsetTest("Europe/Berlin", -7200, -3600) - - - def test_getTimezoneOffsetWithoutDaylightSavingTime(self): - """ - Attempt to verify that L{FileLogObserver.getTimezoneOffset} returns - correct values for the current C{TZ} environment setting for at least - some cases. This test method exercises a timezone that does not use - daylight saving time at all (so both summer and winter time test values - should have the same offset). - """ - # Test a timezone that doesn't have DST. mktime() implementations - # available for testing seem happy to produce results for this even - # though it's not entirely valid. - self._getTimezoneOffsetTest("Africa/Johannesburg", -7200, -7200) - - - def test_timeFormatting(self): - """ - Test the method of L{FileLogObserver} which turns a timestamp into a - human-readable string. - """ - when = calendar.timegm((2001, 2, 3, 4, 5, 6, 7, 8, 0)) - - # Pretend to be in US/Eastern for a moment - self.flo.getTimezoneOffset = lambda when: 18000 - self.assertEqual(self.flo.formatTime(when), '2001-02-02 23:05:06-0500') - - # Okay now we're in Eastern Europe somewhere - self.flo.getTimezoneOffset = lambda when: -3600 - self.assertEqual(self.flo.formatTime(when), '2001-02-03 05:05:06+0100') - - # And off in the Pacific or someplace like that - self.flo.getTimezoneOffset = lambda when: -39600 - self.assertEqual(self.flo.formatTime(when), '2001-02-03 15:05:06+1100') - - # One of those weird places with a half-hour offset timezone - self.flo.getTimezoneOffset = lambda when: 5400 - self.assertEqual(self.flo.formatTime(when), '2001-02-03 02:35:06-0130') - - # Half-hour offset in the other direction - self.flo.getTimezoneOffset = lambda when: -5400 - self.assertEqual(self.flo.formatTime(when), '2001-02-03 05:35:06+0130') - - # Test an offset which is between 0 and 60 minutes to make sure the - # sign comes out properly in that case. - self.flo.getTimezoneOffset = lambda when: 1800 - self.assertEqual(self.flo.formatTime(when), '2001-02-03 03:35:06-0030') - - # Test an offset between 0 and 60 minutes in the other direction. - self.flo.getTimezoneOffset = lambda when: -1800 - self.assertEqual(self.flo.formatTime(when), '2001-02-03 04:35:06+0030') - - # If a strftime-format string is present on the logger, it should - # use that instead. Note we don't assert anything about day, hour - # or minute because we cannot easily control what time.strftime() - # thinks the local timezone is. - self.flo.timeFormat = '%Y %m' - self.assertEqual(self.flo.formatTime(when), '2001 02') - - - def test_microsecondTimestampFormatting(self): - """ - L{FileLogObserver.formatTime} supports a value of C{timeFormat} which - includes C{"%f"}, a L{datetime}-only format specifier for microseconds. - """ - self.flo.timeFormat = '%f' - self.assertEqual("600000", self.flo.formatTime(12345.6)) - - - def test_loggingAnObjectWithBroken__str__(self): - # HELLO, MCFLY - self.lp.msg(EvilStr()) - self.assertEqual(len(self.out), 1) - # Logging system shouldn't need to crap itself for this trivial case - self.assertNotIn(self.ERROR_UNFORMATTABLE_OBJECT, self.out[0]) - - - def test_formattingAnObjectWithBroken__str__(self): - self.lp.msg(format='%(blat)s', blat=EvilStr()) - self.assertEqual(len(self.out), 1) - self.assertIn(self.ERROR_INVALID_FORMAT, self.out[0]) - - - def test_brokenSystem__str__(self): - self.lp.msg('huh', system=EvilStr()) - self.assertEqual(len(self.out), 1) - self.assertIn(self.ERROR_FORMAT, self.out[0]) - - - def test_formattingAnObjectWithBroken__repr__Indirect(self): - self.lp.msg(format='%(blat)s', blat=[EvilRepr()]) - self.assertEqual(len(self.out), 1) - self.assertIn(self.ERROR_UNFORMATTABLE_OBJECT, self.out[0]) - - - def test_systemWithBroker__repr__Indirect(self): - self.lp.msg('huh', system=[EvilRepr()]) - self.assertEqual(len(self.out), 1) - self.assertIn(self.ERROR_UNFORMATTABLE_OBJECT, self.out[0]) - - - def test_simpleBrokenFormat(self): - self.lp.msg(format='hooj %s %s', blat=1) - self.assertEqual(len(self.out), 1) - self.assertIn(self.ERROR_INVALID_FORMAT, self.out[0]) - - - def test_ridiculousFormat(self): - self.lp.msg(format=42, blat=1) - self.assertEqual(len(self.out), 1) - self.assertIn(self.ERROR_INVALID_FORMAT, self.out[0]) - - - def test_evilFormat__repr__And__str__(self): - self.lp.msg(format=EvilReprStr(), blat=1) - self.assertEqual(len(self.out), 1) - self.assertIn(self.ERROR_PATHOLOGICAL, self.out[0]) - - - def test_strangeEventDict(self): - """ - This kind of eventDict used to fail silently, so test it does. - """ - self.lp.msg(message='', isError=False) - self.assertEqual(len(self.out), 0) - - - def _startLoggingCleanup(self): - """ - Cleanup after a startLogging() call that mutates the hell out of some - global state. - """ - self.addCleanup(log.theLogPublisher._stopLogging) - self.addCleanup(setattr, sys, 'stdout', sys.stdout) - self.addCleanup(setattr, sys, 'stderr', sys.stderr) - - - def test_printToStderrSetsIsError(self): - """ - startLogging()'s overridden sys.stderr should consider everything - written to it an error. - """ - self._startLoggingCleanup() - fakeFile = StringIO() - log.startLogging(fakeFile) - - def observe(event): - observed.append(event) - observed = [] - log.addObserver(observe) - - print("Hello, world.", file=sys.stderr) - self.assertEqual(observed[0]["isError"], 1) - - - def test_startLogging(self): - """ - startLogging() installs FileLogObserver and overrides sys.stdout and - sys.stderr. - """ - origStdout, origStderr = sys.stdout, sys.stderr - self._startLoggingCleanup() - # When done with test, reset stdout and stderr to current values: - fakeFile = StringIO() - observer = log.startLogging(fakeFile) - self.addCleanup(observer.stop) - log.msg("Hello!") - self.assertIn("Hello!", fakeFile.getvalue()) - self.assertIsInstance(sys.stdout, LoggingFile) - self.assertEqual(sys.stdout.level, NewLogLevel.info) - encoding = getattr(origStdout, "encoding", None) - if not encoding: - encoding = sys.getdefaultencoding() - self.assertEqual(sys.stdout.encoding.upper(), encoding.upper()) - self.assertIsInstance(sys.stderr, LoggingFile) - self.assertEqual(sys.stderr.level, NewLogLevel.error) - encoding = getattr(origStderr, "encoding", None) - if not encoding: - encoding = sys.getdefaultencoding() - self.assertEqual(sys.stderr.encoding.upper(), encoding.upper()) - - - def test_startLoggingTwice(self): - """ - There are some obscure error conditions that can occur when logging is - started twice. See http://twistedmatrix.com/trac/ticket/3289 for more - information. - """ - self._startLoggingCleanup() - # The bug is particular to the way that the t.p.log 'global' function - # handle stdout. If we use our own stream, the error doesn't occur. If - # we use our own LogPublisher, the error doesn't occur. - sys.stdout = StringIO() - - def showError(eventDict): - if eventDict['isError']: - sys.__stdout__.write(eventDict['failure'].getTraceback()) - - log.addObserver(showError) - self.addCleanup(log.removeObserver, showError) - observer = log.startLogging(sys.stdout) - self.addCleanup(observer.stop) - # At this point, we expect that sys.stdout is a StdioOnnaStick object. - self.assertIsInstance(sys.stdout, LoggingFile) - fakeStdout = sys.stdout - observer = log.startLogging(sys.stdout) - self.assertIdentical(sys.stdout, fakeStdout) - - - def test_startLoggingOverridesWarning(self): - """ - startLogging() overrides global C{warnings.showwarning} such that - warnings go to Twisted log observers. - """ - self._startLoggingCleanup() - newPublisher = NewLogPublisher() - - class SysModule(object): - stdout = object() - stderr = object() - - tempLogPublisher = LogPublisher( - newPublisher, newPublisher, - logBeginner=LogBeginner(newPublisher, StringIO(), SysModule, - warnings) - ) - # Trial reports warnings in two ways. First, it intercepts the global - # 'showwarning' function *itself*, after starting logging (by way of - # the '_collectWarnings' function which collects all warnings as a - # around the test's 'run' method). Second, it has a log observer which - # immediately reports warnings when they're propagated into the log - # system (which, in normal operation, happens only at the end of the - # test case). In order to avoid printing a spurious warning in this - # test, we first replace the global log publisher's 'showwarning' in - # the module with our own. - self.patch(log, "theLogPublisher", tempLogPublisher) - # And, one last thing, pretend we're starting from a fresh import, or - # warnings.warn won't be patched at all. - log._oldshowwarning = None - # Global mutable state is bad, kids. Stay in school. - fakeFile = StringIO() - # We didn't previously save log messages, so let's make sure we don't - # save them any more. - evt = {"pre-start": "event"} - received = [] - - def preStartObserver(x): - if 'pre-start' in x.keys(): - received.append(x) - - newPublisher(evt) - newPublisher.addObserver(preStartObserver) - log.startLogging(fakeFile, setStdout=False) - self.addCleanup(tempLogPublisher._stopLogging) - self.assertEquals(received, []) - warnings.warn("hello!") - output = fakeFile.getvalue() - self.assertIn("UserWarning: hello!", output) - - - def test_emitPrefix(self): - """ - FileLogObserver.emit() will add a timestamp and system prefix to its - file output. - """ - output = StringIO() - flo = log.FileLogObserver(output) - events = [] - - def observer(event): - # Capture the event for reference and pass it along to flo - events.append(event) - flo.emit(event) - - publisher = log.LogPublisher() - publisher.addObserver(observer) - - publisher.msg("Hello!") - self.assertEqual(len(events), 1) - event = events[0] - - result = output.getvalue() - prefix = "{time} [{system}] ".format( - time=flo.formatTime(event["time"]), system=event["system"], - ) - - self.assertTrue( - result.startswith(prefix), - "{0!r} does not start with {1!r}".format(result, prefix) - ) - - - def test_emitNewline(self): - """ - FileLogObserver.emit() will append a newline to its file output. - """ - output = StringIO() - flo = log.FileLogObserver(output) - - publisher = log.LogPublisher() - publisher.addObserver(flo.emit) - - publisher.msg("Hello!") - - result = output.getvalue() - suffix = "Hello!\n" - - self.assertTrue( - result.endswith(suffix), - "{0!r} does not end with {1!r}".format(result, suffix) - ) - - - -class PythonLoggingObserverTests(unittest.SynchronousTestCase): - """ - Test the bridge with python logging module. - """ - def setUp(self): - rootLogger = logging.getLogger("") - originalLevel = rootLogger.getEffectiveLevel() - rootLogger.setLevel(logging.DEBUG) - - @self.addCleanup - def restoreLevel(): - rootLogger.setLevel(originalLevel) - self.hdlr, self.out = handlerAndBytesIO() - rootLogger.addHandler(self.hdlr) - - @self.addCleanup - def removeLogger(): - rootLogger.removeHandler(self.hdlr) - self.hdlr.close() - - self.lp = log.LogPublisher() - self.obs = log.PythonLoggingObserver() - self.lp.addObserver(self.obs.emit) - - - def test_singleString(self): - """ - Test simple output, and default log level. - """ - self.lp.msg("Hello, world.") - self.assertIn(b"Hello, world.", self.out.getvalue()) - self.assertIn(b"INFO", self.out.getvalue()) - - - def test_errorString(self): - """ - Test error output. - """ - f = failure.Failure(ValueError("That is bad.")) - self.lp.msg(failure=f, isError=True) - prefix = b"CRITICAL:" - output = self.out.getvalue() - self.assertTrue( - output.startswith(prefix), - "Does not start with {0!r}: {1!r}".format(prefix, output) - ) - - - def test_formatString(self): - """ - Test logging with a format. - """ - self.lp.msg(format="%(bar)s oo %(foo)s", bar="Hello", foo="world") - self.assertIn(b"Hello oo world", self.out.getvalue()) - - - def test_customLevel(self): - """ - Test the logLevel keyword for customizing level used. - """ - self.lp.msg("Spam egg.", logLevel=logging.ERROR) - self.assertIn(b"Spam egg.", self.out.getvalue()) - self.assertIn(b"ERROR", self.out.getvalue()) - self.out.seek(0, 0) - self.out.truncate() - self.lp.msg("Foo bar.", logLevel=logging.WARNING) - self.assertIn(b"Foo bar.", self.out.getvalue()) - self.assertIn(b"WARNING", self.out.getvalue()) - - - def test_strangeEventDict(self): - """ - Verify that an event dictionary which is not an error and has an empty - message isn't recorded. - """ - self.lp.msg(message='', isError=False) - self.assertEqual(self.out.getvalue(), b'') - - - -class PythonLoggingIntegrationTests(unittest.SynchronousTestCase): - """ - Test integration of python logging bridge. - """ - - def test_startStopObserver(self): - """ - Test that start and stop methods of the observer actually register - and unregister to the log system. - """ - oldAddObserver = log.addObserver - oldRemoveObserver = log.removeObserver - l = [] - try: - log.addObserver = l.append - log.removeObserver = l.remove - obs = log.PythonLoggingObserver() - obs.start() - self.assertEqual(l[0], obs.emit) - obs.stop() - self.assertEqual(len(l), 0) - finally: - log.addObserver = oldAddObserver - log.removeObserver = oldRemoveObserver - - - def test_inheritance(self): - """ - Test that we can inherit L{log.PythonLoggingObserver} and use super: - that's basically a validation that L{log.PythonLoggingObserver} is - new-style class. - """ - class MyObserver(log.PythonLoggingObserver): - def emit(self, eventDict): - super(MyObserver, self).emit(eventDict) - obs = MyObserver() - l = [] - oldEmit = log.PythonLoggingObserver.emit - try: - log.PythonLoggingObserver.emit = l.append - obs.emit('foo') - self.assertEqual(len(l), 1) - finally: - log.PythonLoggingObserver.emit = oldEmit - - - -class DefaultObserverTests(unittest.SynchronousTestCase): - """ - Test the default observer. - """ - - def test_failureLogger(self): - """ - The reason argument passed to log.err() appears in the report - generated by DefaultObserver. - """ - self.catcher = [] - self.observer = self.catcher.append - log.addObserver(self.observer) - self.addCleanup(log.removeObserver, self.observer) - - obs = log.DefaultObserver() - obs.stderr = StringIO() - obs.start() - self.addCleanup(obs.stop) - - reason = "The reason." - log.err(Exception(), reason) - errors = self.flushLoggedErrors() - - self.assertIn(reason, obs.stderr.getvalue()) - self.assertEqual(len(errors), 1) - - - def test_emitEventWithBrokenRepr(self): - """ - DefaultObserver.emit() does not raise when it observes an error event - with a message that causes L{repr} to raise. - """ - class Ouch(object): - def __repr__(self): - return str(1 / 0) - - message = ("foo", Ouch()) - event = dict(message=message, isError=1) - - observer = log.DefaultObserver() - with StringIO() as output: - observer.stderr = output - observer.emit(event) - self.assertTrue(output.getvalue().startswith("foo 0: - msg += '\n' - raise self.failureException( - '%snot not unequal (__ne__ not implemented correctly):' - '\na = %s\nb = %s\n' - % (msg, pformat(first), pformat(second))) - return first - - - def test_rwxFromBools(self): - """ - L{RWX}'s constructor takes a set of booleans - """ - for r in (True, False): - for w in (True, False): - for x in (True, False): - rwx = filepath.RWX(r, w, x) - self.assertEqual(rwx.read, r) - self.assertEqual(rwx.write, w) - self.assertEqual(rwx.execute, x) - rwx = filepath.RWX(True, True, True) - self.assertTrue(rwx.read and rwx.write and rwx.execute) - - - def test_rwxEqNe(self): - """ - L{RWX}'s created with the same booleans are equivalent. If booleans - are different, they are not equal. - """ - for r in (True, False): - for w in (True, False): - for x in (True, False): - self.assertEqual(filepath.RWX(r, w, x), - filepath.RWX(r, w, x)) - self.assertNotUnequal(filepath.RWX(r, w, x), - filepath.RWX(r, w, x)) - self.assertNotEqual(filepath.RWX(True, True, True), - filepath.RWX(True, True, False)) - self.assertNotEqual(3, filepath.RWX(True, True, True)) - - - def test_rwxShorthand(self): - """ - L{RWX}'s shorthand string should be 'rwx' if read, write, and execute - permission bits are true. If any of those permissions bits are false, - the character is replaced by a '-'. - """ - - def getChar(val, letter): - if val: - return letter - return '-' - - for r in (True, False): - for w in (True, False): - for x in (True, False): - rwx = filepath.RWX(r, w, x) - self.assertEqual(rwx.shorthand(), - getChar(r, 'r') + - getChar(w, 'w') + - getChar(x, 'x')) - self.assertEqual(filepath.RWX(True, False, True).shorthand(), "r-x") - - - def test_permissionsFromStat(self): - """ - L{Permissions}'s constructor takes a valid permissions bitmask and - parsaes it to produce the correct set of boolean permissions. - """ - def _rwxFromStat(statModeInt, who): - def getPermissionBit(what, who): - return (statModeInt & - getattr(stat, "S_I%s%s" % (what, who))) > 0 - return filepath.RWX(*[getPermissionBit(what, who) for what in - ('R', 'W', 'X')]) - - for u in range(0, 8): - for g in range(0, 8): - for o in range(0, 8): - chmodString = "%d%d%d" % (u, g, o) - chmodVal = int(chmodString, 8) - perm = filepath.Permissions(chmodVal) - self.assertEqual(perm.user, - _rwxFromStat(chmodVal, "USR"), - "%s: got user: %s" % - (chmodString, perm.user)) - self.assertEqual(perm.group, - _rwxFromStat(chmodVal, "GRP"), - "%s: got group: %s" % - (chmodString, perm.group)) - self.assertEqual(perm.other, - _rwxFromStat(chmodVal, "OTH"), - "%s: got other: %s" % - (chmodString, perm.other)) - perm = filepath.Permissions(0o777) - for who in ("user", "group", "other"): - for what in ("read", "write", "execute"): - self.assertTrue(getattr(getattr(perm, who), what)) - - - def test_permissionsEq(self): - """ - Two L{Permissions}'s that are created with the same bitmask - are equivalent - """ - self.assertEqual(filepath.Permissions(0o777), - filepath.Permissions(0o777)) - self.assertNotUnequal(filepath.Permissions(0o777), - filepath.Permissions(0o777)) - self.assertNotEqual(filepath.Permissions(0o777), - filepath.Permissions(0o700)) - self.assertNotEqual(3, filepath.Permissions(0o777)) - - - def test_permissionsShorthand(self): - """ - L{Permissions}'s shorthand string is the RWX shorthand string for its - user permission bits, group permission bits, and other permission bits - concatenated together, without a space. - """ - for u in range(0, 8): - for g in range(0, 8): - for o in range(0, 8): - perm = filepath.Permissions(int("0o%d%d%d" % (u, g, o), 8)) - self.assertEqual(perm.shorthand(), - ''.join(x.shorthand() for x in ( - perm.user, perm.group, perm.other))) - self.assertEqual(filepath.Permissions(0o770).shorthand(), "rwxrwx---") - - - -class FilePathTests(AbstractFilePathTests): - """ - Test various L{FilePath} path manipulations. - - In particular, note that tests defined on this class instead of on the base - class are only run against L{twisted.python.filepath}. - """ - def test_chmod(self): - """ - L{FilePath.chmod} modifies the permissions of - the passed file as expected (using C{os.stat} to check). We use some - basic modes that should work everywhere (even on Windows). - """ - for mode in (0o555, 0o777): - self.path.child(b"sub1").chmod(mode) - self.assertEqual( - stat.S_IMODE(os.stat(self.path.child(b"sub1").path).st_mode), - mode) - - - def symlink(self, target, name): - """ - Create a symbolic link named C{name} pointing at C{target}. - - @type target: C{str} - @type name: C{str} - @raise SkipTest: raised if symbolic links are not supported on the - host platform. - """ - if getattr(os, 'symlink', None) is None: - raise SkipTest( - "Platform does not support symbolic links.") - os.symlink(target, name) - - - def createLinks(self): - """ - Create several symbolic links to files and directories. - """ - subdir = self.path.child(b"sub1") - self.symlink(subdir.path, self._mkpath(b"sub1.link")) - self.symlink(subdir.child(b"file2").path, self._mkpath(b"file2.link")) - self.symlink(subdir.child(b"file2").path, - self._mkpath(b"sub1", b"sub1.file2.link")) - - - def test_realpathSymlink(self): - """ - L{FilePath.realpath} returns the path of the ultimate target of a - symlink. - """ - self.createLinks() - self.symlink(self.path.child(b"file2.link").path, - self.path.child(b"link.link").path) - self.assertEqual(self.path.child(b"link.link").realpath(), - self.path.child(b"sub1").child(b"file2")) - - - def test_realpathCyclicalSymlink(self): - """ - L{FilePath.realpath} raises L{filepath.LinkError} if the path is a - symbolic link which is part of a cycle. - """ - self.symlink(self.path.child(b"link1").path, self.path.child(b"link2").path) - self.symlink(self.path.child(b"link2").path, self.path.child(b"link1").path) - self.assertRaises(filepath.LinkError, - self.path.child(b"link2").realpath) - - - def test_realpathNoSymlink(self): - """ - L{FilePath.realpath} returns the path itself if the path is not a - symbolic link. - """ - self.assertEqual(self.path.child(b"sub1").realpath(), - self.path.child(b"sub1")) - - - def test_walkCyclicalSymlink(self): - """ - Verify that walking a path with a cyclical symlink raises an error - """ - self.createLinks() - self.symlink(self.path.child(b"sub1").path, - self.path.child(b"sub1").child(b"sub1.loopylink").path) - def iterateOverPath(): - return [foo.path for foo in self.path.walk()] - self.assertRaises(filepath.LinkError, iterateOverPath) - - - def test_walkObeysDescendWithCyclicalSymlinks(self): - """ - Verify that, after making a path with cyclical symlinks, when the - supplied C{descend} predicate returns C{False}, the target is not - traversed, as if it was a simple symlink. - """ - self.createLinks() - # we create cyclical symlinks - self.symlink(self.path.child(b"sub1").path, - self.path.child(b"sub1").child(b"sub1.loopylink").path) - def noSymLinks(path): - return not path.islink() - def iterateOverPath(): - return [foo.path for foo in self.path.walk(descend=noSymLinks)] - self.assertTrue(iterateOverPath()) - - - def test_walkObeysDescend(self): - """ - Verify that when the supplied C{descend} predicate returns C{False}, - the target is not traversed. - """ - self.createLinks() - def noSymLinks(path): - return not path.islink() - x = [foo.path for foo in self.path.walk(descend=noSymLinks)] - self.assertEqual(set(x), set(self.all)) - - - def test_getAndSet(self): - content = b'newcontent' - self.path.child(b'new').setContent(content) - newcontent = self.path.child(b'new').getContent() - self.assertEqual(content, newcontent) - content = b'content' - self.path.child(b'new').setContent(content, b'.tmp') - newcontent = self.path.child(b'new').getContent() - self.assertEqual(content, newcontent) - - - def test_getContentFileClosing(self): - """ - If reading from the underlying file raises an exception, - L{FilePath.getContent} raises that exception after closing the file. - """ - fp = ExplodingFilePath(b"") - self.assertRaises(IOError, fp.getContent) - self.assertTrue(fp.fp.closed) - - - def test_symbolicLink(self): - """ - Verify the behavior of the C{isLink} method against links and - non-links. Also check that the symbolic link shares the directory - property with its target. - """ - s4 = self.path.child(b"sub4") - s3 = self.path.child(b"sub3") - self.symlink(s3.path, s4.path) - self.assertTrue(s4.islink()) - self.assertFalse(s3.islink()) - self.assertTrue(s4.isdir()) - self.assertTrue(s3.isdir()) - - - def test_linkTo(self): - """ - Verify that symlink creates a valid symlink that is both a link and a - file if its target is a file, or a directory if its target is a - directory. - """ - targetLinks = [ - (self.path.child(b"sub2"), self.path.child(b"sub2.link")), - (self.path.child(b"sub2").child(b"file3.ext1"), - self.path.child(b"file3.ext1.link")) - ] - for target, link in targetLinks: - target.linkTo(link) - self.assertTrue(link.islink(), "This is a link") - self.assertEqual(target.isdir(), link.isdir()) - self.assertEqual(target.isfile(), link.isfile()) - - - def test_linkToErrors(self): - """ - Verify C{linkTo} fails in the following case: - - the target is in a directory that doesn't exist - - the target already exists - """ - self.assertRaises(OSError, self.path.child(b"file1").linkTo, - self.path.child(b'nosub').child(b'file1')) - self.assertRaises(OSError, self.path.child(b"file1").linkTo, - self.path.child(b'sub1').child(b'file2')) - - - if not getattr(os, "symlink", None): - skipMsg = "Your platform does not support symbolic links." - test_symbolicLink.skip = skipMsg - test_linkTo.skip = skipMsg - test_linkToErrors.skip = skipMsg - - - def testMultiExt(self): - f3 = self.path.child(b'sub3').child(b'file3') - exts = b'.foo', b'.bar', b'ext1', b'ext2', b'ext3' - self.failIf(f3.siblingExtensionSearch(*exts)) - f3e = f3.siblingExtension(b".foo") - f3e.touch() - self.failIf(not f3.siblingExtensionSearch(*exts).exists()) - self.failIf(not f3.siblingExtensionSearch(b'*').exists()) - f3e.remove() - self.failIf(f3.siblingExtensionSearch(*exts)) - - def testPreauthChild(self): - fp = filepath.FilePath(b'.') - fp.preauthChild(b'foo/bar') - self.assertRaises(filepath.InsecurePath, fp.child, u'/mon\u20acy') - - def testStatCache(self): - p = self.path.child(b'stattest') - p.touch() - self.assertEqual(p.getsize(), 0) - self.assertEqual(abs(p.getmtime() - time.time()) // 20, 0) - self.assertEqual(abs(p.getctime() - time.time()) // 20, 0) - self.assertEqual(abs(p.getatime() - time.time()) // 20, 0) - self.assertEqual(p.exists(), True) - self.assertEqual(p.exists(), True) - # OOB removal: FilePath.remove() will automatically restat - os.remove(p.path) - # test caching - self.assertEqual(p.exists(), True) - p.restat(reraise=False) - self.assertEqual(p.exists(), False) - self.assertEqual(p.islink(), False) - self.assertEqual(p.isdir(), False) - self.assertEqual(p.isfile(), False) - - def testPersist(self): - newpath = pickle.loads(pickle.dumps(self.path)) - self.assertEqual(self.path.__class__, newpath.__class__) - self.assertEqual(self.path.path, newpath.path) - - def testInsecureUNIX(self): - self.assertRaises(filepath.InsecurePath, self.path.child, b"..") - self.assertRaises(filepath.InsecurePath, self.path.child, b"/etc") - self.assertRaises(filepath.InsecurePath, self.path.child, b"../..") - - def testInsecureWin32(self): - self.assertRaises(filepath.InsecurePath, self.path.child, b"..\\..") - self.assertRaises(filepath.InsecurePath, self.path.child, b"C:randomfile") - - if platform.getType() != 'win32': - testInsecureWin32.skip = "Test will run only on Windows." - - - def testInsecureWin32Whacky(self): - """ - Windows has 'special' filenames like NUL and CON and COM1 and LPR - and PRN and ... god knows what else. They can be located anywhere in - the filesystem. For obvious reasons, we do not wish to normally permit - access to these. - """ - self.assertRaises(filepath.InsecurePath, self.path.child, b"CON") - self.assertRaises(filepath.InsecurePath, self.path.child, b"C:CON") - self.assertRaises(filepath.InsecurePath, self.path.child, r"C:\CON") - - if platform.getType() != 'win32': - testInsecureWin32Whacky.skip = "Test will run only on Windows." - - - def testComparison(self): - self.assertEqual(filepath.FilePath(b'a'), - filepath.FilePath(b'a')) - self.failUnless(filepath.FilePath(b'z') > - filepath.FilePath(b'a')) - self.failUnless(filepath.FilePath(b'z') >= - filepath.FilePath(b'a')) - self.failUnless(filepath.FilePath(b'a') >= - filepath.FilePath(b'a')) - self.failUnless(filepath.FilePath(b'a') <= - filepath.FilePath(b'a')) - self.failUnless(filepath.FilePath(b'a') < - filepath.FilePath(b'z')) - self.failUnless(filepath.FilePath(b'a') <= - filepath.FilePath(b'z')) - self.failUnless(filepath.FilePath(b'a') != - filepath.FilePath(b'z')) - self.failUnless(filepath.FilePath(b'z') != - filepath.FilePath(b'a')) - - self.failIf(filepath.FilePath(b'z') != - filepath.FilePath(b'z')) - - - def test_descendantOnly(self): - """ - If C{".."} is in the sequence passed to L{FilePath.descendant}, - L{InsecurePath} is raised. - """ - self.assertRaises( - filepath.InsecurePath, - self.path.descendant, [u'mon\u20acy', u'..']) - - - def testSibling(self): - p = self.path.child(b'sibling_start') - ts = p.sibling(b'sibling_test') - self.assertEqual(ts.dirname(), p.dirname()) - self.assertEqual(ts.basename(), b'sibling_test') - ts.createDirectory() - self.assertIn(ts, self.path.children()) - - def testTemporarySibling(self): - ts = self.path.temporarySibling() - self.assertEqual(ts.dirname(), self.path.dirname()) - self.assertNotIn(ts.basename(), self.path.listdir()) - ts.createDirectory() - self.assertIn(ts, self.path.parent().children()) - - - def test_temporarySiblingExtension(self): - """ - If L{FilePath.temporarySibling} is given an extension argument, it will - produce path objects with that extension appended to their names. - """ - testExtension = b".test-extension" - ts = self.path.temporarySibling(testExtension) - self.assertTrue(ts.basename().endswith(testExtension), - "%s does not end with %s" % ( - ts.basename(), testExtension)) - - - def test_removeDirectory(self): - """ - L{FilePath.remove} on a L{FilePath} that refers to a directory will - recursively delete its contents. - """ - self.path.remove() - self.failIf(self.path.exists()) - - - def test_removeWithSymlink(self): - """ - For a path which is a symbolic link, L{FilePath.remove} just deletes - the link, not the target. - """ - link = self.path.child(b"sub1.link") - # setUp creates the sub1 child - self.symlink(self.path.child(b"sub1").path, link.path) - link.remove() - self.assertFalse(link.exists()) - self.assertTrue(self.path.child(b"sub1").exists()) - - - def test_copyToDirectory(self): - """ - L{FilePath.copyTo} makes a copy of all the contents of the directory - named by that L{FilePath} if it is able to do so. - """ - oldPaths = list(self.path.walk()) # Record initial state - fp = filepath.FilePath(self.mktemp()) - self.path.copyTo(fp) - self.path.remove() - fp.copyTo(self.path) - newPaths = list(self.path.walk()) # Record double-copy state - newPaths.sort() - oldPaths.sort() - self.assertEqual(newPaths, oldPaths) - - - def test_copyToMissingDestFileClosing(self): - """ - If an exception is raised while L{FilePath.copyTo} is trying to open - source file to read from, the destination file is closed and the - exception is raised to the caller of L{FilePath.copyTo}. - """ - nosuch = self.path.child(b"nothere") - # Make it look like something to copy, even though it doesn't exist. - # This could happen if the file is deleted between the isfile check and - # the file actually being opened. - nosuch.isfile = lambda: True - - # We won't get as far as writing to this file, but it's still useful for - # tracking whether we closed it. - destination = ExplodingFilePath(self.mktemp()) - - self.assertRaises(IOError, nosuch.copyTo, destination) - self.assertTrue(destination.fp.closed) - - - def test_copyToFileClosing(self): - """ - If an exception is raised while L{FilePath.copyTo} is copying bytes - between two regular files, the source and destination files are closed - and the exception propagates to the caller of L{FilePath.copyTo}. - """ - destination = ExplodingFilePath(self.mktemp()) - source = ExplodingFilePath(__file__) - self.assertRaises(IOError, source.copyTo, destination) - self.assertTrue(source.fp.closed) - self.assertTrue(destination.fp.closed) - - - def test_copyToDirectoryItself(self): - """ - L{FilePath.copyTo} fails with an OSError or IOError (depending on - platform, as it propagates errors from open() and write()) when - attempting to copy a directory to a child of itself. - """ - self.assertRaises((OSError, IOError), - self.path.copyTo, self.path.child(b'file1')) - - - def test_copyToWithSymlink(self): - """ - Verify that copying with followLinks=True copies symlink targets - instead of symlinks - """ - self.symlink(self.path.child(b"sub1").path, - self.path.child(b"link1").path) - fp = filepath.FilePath(self.mktemp()) - self.path.copyTo(fp) - self.assertFalse(fp.child(b"link1").islink()) - self.assertEqual([x.basename() for x in fp.child(b"sub1").children()], - [x.basename() for x in fp.child(b"link1").children()]) - - - def test_copyToWithoutSymlink(self): - """ - Verify that copying with followLinks=False copies symlinks as symlinks - """ - self.symlink(b"sub1", self.path.child(b"link1").path) - fp = filepath.FilePath(self.mktemp()) - self.path.copyTo(fp, followLinks=False) - self.assertTrue(fp.child(b"link1").islink()) - self.assertEqual(os.readlink(self.path.child(b"link1").path), - os.readlink(fp.child(b"link1").path)) - - - def test_copyToMissingSource(self): - """ - If the source path is missing, L{FilePath.copyTo} raises L{OSError}. - """ - path = filepath.FilePath(self.mktemp()) - exc = self.assertRaises(OSError, path.copyTo, b'some other path') - self.assertEqual(exc.errno, errno.ENOENT) - - - def test_moveTo(self): - """ - Verify that moving an entire directory results into another directory - with the same content. - """ - oldPaths = list(self.path.walk()) # Record initial state - fp = filepath.FilePath(self.mktemp()) - self.path.moveTo(fp) - fp.moveTo(self.path) - newPaths = list(self.path.walk()) # Record double-move state - newPaths.sort() - oldPaths.sort() - self.assertEqual(newPaths, oldPaths) - - - def test_moveToExistsCache(self): - """ - A L{FilePath} that has been moved aside with L{FilePath.moveTo} no - longer registers as existing. Its previously non-existent target - exists, though, as it was created by the call to C{moveTo}. - """ - fp = filepath.FilePath(self.mktemp()) - fp2 = filepath.FilePath(self.mktemp()) - fp.touch() - - # Both a sanity check (make sure the file status looks right) and an - # enticement for stat-caching logic to kick in and remember that these - # exist / don't exist. - self.assertEqual(fp.exists(), True) - self.assertEqual(fp2.exists(), False) - - fp.moveTo(fp2) - self.assertEqual(fp.exists(), False) - self.assertEqual(fp2.exists(), True) - - - def test_moveToExistsCacheCrossMount(self): - """ - The assertion of test_moveToExistsCache should hold in the case of a - cross-mount move. - """ - self.setUpFaultyRename() - self.test_moveToExistsCache() - - - def test_moveToSizeCache(self, hook=lambda : None): - """ - L{FilePath.moveTo} clears its destination's status cache, such that - calls to L{FilePath.getsize} after the call to C{moveTo} will report the - new size, not the old one. - - This is a separate test from C{test_moveToExistsCache} because it is - intended to cover the fact that the destination's cache is dropped; - test_moveToExistsCache doesn't cover this case because (currently) a - file that doesn't exist yet does not cache the fact of its non- - existence. - """ - fp = filepath.FilePath(self.mktemp()) - fp2 = filepath.FilePath(self.mktemp()) - fp.setContent(b"1234") - fp2.setContent(b"1234567890") - hook() - - # Sanity check / kick off caching. - self.assertEqual(fp.getsize(), 4) - self.assertEqual(fp2.getsize(), 10) - # Actually attempting to replace a file on Windows would fail with - # ERROR_ALREADY_EXISTS, but we don't need to test that, just the cached - # metadata, so, delete the file ... - os.remove(fp2.path) - # ... but don't clear the status cache, as fp2.remove() would. - self.assertEqual(fp2.getsize(), 10) - - fp.moveTo(fp2) - self.assertEqual(fp2.getsize(), 4) - - - def test_moveToSizeCacheCrossMount(self): - """ - The assertion of test_moveToSizeCache should hold in the case of a - cross-mount move. - """ - self.test_moveToSizeCache(hook=self.setUpFaultyRename) - - - def test_moveToError(self): - """ - Verify error behavior of moveTo: it should raises one of OSError or - IOError if you want to move a path into one of its child. It's simply - the error raised by the underlying rename system call. - """ - self.assertRaises((OSError, IOError), self.path.moveTo, self.path.child(b'file1')) - - - def setUpFaultyRename(self): - """ - Set up a C{os.rename} that will fail with L{errno.EXDEV} on first call. - This is used to simulate a cross-device rename failure. - - @return: a list of pair (src, dest) of calls to C{os.rename} - @rtype: C{list} of C{tuple} - """ - invokedWith = [] - def faultyRename(src, dest): - invokedWith.append((src, dest)) - if len(invokedWith) == 1: - raise OSError(errno.EXDEV, 'Test-induced failure simulating ' - 'cross-device rename failure') - return originalRename(src, dest) - - originalRename = os.rename - self.patch(os, "rename", faultyRename) - return invokedWith - - - def test_crossMountMoveTo(self): - """ - C{moveTo} should be able to handle C{EXDEV} error raised by - C{os.rename} when trying to move a file on a different mounted - filesystem. - """ - invokedWith = self.setUpFaultyRename() - # Bit of a whitebox test - force os.rename, which moveTo tries - # before falling back to a slower method, to fail, forcing moveTo to - # use the slower behavior. - self.test_moveTo() - # A bit of a sanity check for this whitebox test - if our rename - # was never invoked, the test has probably fallen into disrepair! - self.assertTrue(invokedWith) - - - def test_crossMountMoveToWithSymlink(self): - """ - By default, when moving a symlink, it should follow the link and - actually copy the content of the linked node. - """ - invokedWith = self.setUpFaultyRename() - f2 = self.path.child(b'file2') - f3 = self.path.child(b'file3') - self.symlink(self.path.child(b'file1').path, f2.path) - f2.moveTo(f3) - self.assertFalse(f3.islink()) - self.assertEqual(f3.getContent(), b'file 1') - self.assertTrue(invokedWith) - - - def test_crossMountMoveToWithoutSymlink(self): - """ - Verify that moveTo called with followLinks=False actually create - another symlink. - """ - invokedWith = self.setUpFaultyRename() - f2 = self.path.child(b'file2') - f3 = self.path.child(b'file3') - self.symlink(self.path.child(b'file1').path, f2.path) - f2.moveTo(f3, followLinks=False) - self.assertTrue(f3.islink()) - self.assertEqual(f3.getContent(), b'file 1') - self.assertTrue(invokedWith) - - - def test_createBinaryMode(self): - """ - L{FilePath.create} should always open (and write to) files in binary - mode; line-feed octets should be unmodified. - - (While this test should pass on all platforms, it is only really - interesting on platforms which have the concept of binary mode, i.e. - Windows platforms.) - """ - path = filepath.FilePath(self.mktemp()) - f = path.create() - self.failUnless("b" in f.mode) - f.write(b"\n") - f.close() - read = open(path.path, "rb").read() - self.assertEqual(read, b"\n") - - - def testOpen(self): - # Opening a file for reading when it does not already exist is an error - nonexistent = self.path.child(b'nonexistent') - e = self.assertRaises(IOError, nonexistent.open) - self.assertEqual(e.errno, errno.ENOENT) - - # Opening a file for writing when it does not exist is okay - writer = self.path.child(b'writer') - f = writer.open('w') - f.write(b'abc\ndef') - f.close() - - # Make sure those bytes ended up there - and test opening a file for - # reading when it does exist at the same time - f = writer.open() - self.assertEqual(f.read(), b'abc\ndef') - f.close() - - # Re-opening that file in write mode should erase whatever was there. - f = writer.open('w') - f.close() - f = writer.open() - self.assertEqual(f.read(), b'') - f.close() - - # Put some bytes in a file so we can test that appending does not - # destroy them. - appender = self.path.child(b'appender') - f = appender.open('w') - f.write(b'abc') - f.close() - - f = appender.open('a') - f.write(b'def') - f.close() - - f = appender.open('r') - self.assertEqual(f.read(), b'abcdef') - f.close() - - # read/write should let us do both without erasing those bytes - f = appender.open('r+') - self.assertEqual(f.read(), b'abcdef') - # ANSI C *requires* an fseek or an fgetpos between an fread and an - # fwrite or an fwrite and a fread. We can't reliable get Python to - # invoke fgetpos, so we seek to a 0 byte offset from the current - # position instead. Also, Python sucks for making this seek - # relative to 1 instead of a symbolic constant representing the - # current file position. - f.seek(0, 1) - # Put in some new bytes for us to test for later. - f.write(b'ghi') - f.close() - - # Make sure those new bytes really showed up - f = appender.open('r') - self.assertEqual(f.read(), b'abcdefghi') - f.close() - - # write/read should let us do both, but erase anything that's there - # already. - f = appender.open('w+') - self.assertEqual(f.read(), b'') - f.seek(0, 1) # Don't forget this! - f.write(b'123') - f.close() - - # super append mode should let us read and write and also position the - # cursor at the end of the file, without erasing everything. - f = appender.open('a+') - - # The order of these lines may seem surprising, but it is necessary. - # The cursor is not at the end of the file until after the first write. - f.write(b'456') - f.seek(0, 1) # Asinine. - self.assertEqual(f.read(), b'') - - f.seek(0, 0) - self.assertEqual(f.read(), b'123456') - f.close() - - # Opening a file exclusively must fail if that file exists already. - nonexistent.requireCreate(True) - nonexistent.open('w').close() - existent = nonexistent - del nonexistent - self.assertRaises((OSError, IOError), existent.open) - - - def test_openWithExplicitBinaryMode(self): - """ - Due to a bug in Python 2.7 on Windows including multiple 'b' - characters in the mode passed to the built-in open() will cause an - error. FilePath.open() ensures that only a single 'b' character is - included in the mode passed to the built-in open(). - - See http://bugs.python.org/issue7686 for details about the bug. - """ - writer = self.path.child(b'explicit-binary') - file = writer.open('wb') - file.write(b'abc\ndef') - file.close() - self.assertTrue(writer.exists) - - - def test_openWithRedundantExplicitBinaryModes(self): - """ - Due to a bug in Python 2.7 on Windows including multiple 'b' - characters in the mode passed to the built-in open() will cause an - error. No matter how many 'b' modes are specified, FilePath.open() - ensures that only a single 'b' character is included in the mode - passed to the built-in open(). - - See http://bugs.python.org/issue7686 for details about the bug. - """ - writer = self.path.child(b'multiple-binary') - file = writer.open('wbb') - file.write(b'abc\ndef') - file.close() - self.assertTrue(writer.exists) - - - def test_existsCache(self): - """ - Check that C{filepath.FilePath.exists} correctly restat the object if - an operation has occurred in the mean time. - """ - fp = filepath.FilePath(self.mktemp()) - self.assertEqual(fp.exists(), False) - - fp.makedirs() - self.assertEqual(fp.exists(), True) - - - def test_changed(self): - """ - L{FilePath.changed} indicates that the L{FilePath} has changed, but does - not re-read the status information from the filesystem until it is - queried again via another method, such as C{getsize}. - """ - fp = filepath.FilePath(self.mktemp()) - fp.setContent(b"12345") - self.assertEqual(fp.getsize(), 5) - - # Someone else comes along and changes the file. - fObj = open(fp.path, 'wb') - fObj.write(b"12345678") - fObj.close() - - # Sanity check for caching: size should still be 5. - self.assertEqual(fp.getsize(), 5) - fp.changed() - - # This path should look like we don't know what status it's in, not that - # we know that it didn't exist when last we checked. - self.assertEqual(fp.statinfo, None) - self.assertEqual(fp.getsize(), 8) - - - def test_getPermissions_POSIX(self): - """ - Getting permissions for a file returns a L{Permissions} object for - POSIX platforms (which supports separate user, group, and other - permissions bits. - """ - for mode in (0o777, 0o700): - self.path.child(b"sub1").chmod(mode) - self.assertEqual(self.path.child(b"sub1").getPermissions(), - filepath.Permissions(mode)) - self.path.child(b"sub1").chmod(0o764) #sanity check - self.assertEqual( - self.path.child(b"sub1").getPermissions().shorthand(), - "rwxrw-r--") - - - def test_deprecateStatinfoGetter(self): - """ - Getting L{twisted.python.filepath.FilePath.statinfo} is deprecated. - """ - fp = filepath.FilePath(self.mktemp()) - fp.statinfo - warningInfo = self.flushWarnings([self.test_deprecateStatinfoGetter]) - self.assertEquals(len(warningInfo), 1) - self.assertEquals(warningInfo[0]['category'], DeprecationWarning) - self.assertEquals( - warningInfo[0]['message'], - "twisted.python.filepath.FilePath.statinfo was deprecated in " - "Twisted 15.0.0; please use other FilePath methods such as " - "getsize(), isdir(), getModificationTime(), etc. instead") - - - def test_deprecateStatinfoSetter(self): - """ - Setting L{twisted.python.filepath.FilePath.statinfo} is deprecated. - """ - fp = filepath.FilePath(self.mktemp()) - fp.statinfo = None - warningInfo = self.flushWarnings([self.test_deprecateStatinfoSetter]) - self.assertEquals(len(warningInfo), 1) - self.assertEquals(warningInfo[0]['category'], DeprecationWarning) - self.assertEquals( - warningInfo[0]['message'], - "twisted.python.filepath.FilePath.statinfo was deprecated in " - "Twisted 15.0.0; please use other FilePath methods such as " - "getsize(), isdir(), getModificationTime(), etc. instead") - - - def test_deprecateStatinfoSetterSets(self): - """ - Setting L{twisted.python.filepath.FilePath.statinfo} changes the value - of _statinfo such that getting statinfo again returns the new value. - """ - fp = filepath.FilePath(self.mktemp()) - fp.statinfo = None - self.assertEquals(fp.statinfo, None) - - - def test_filePathNotDeprecated(self): - """ - While accessing L{twisted.python.filepath.FilePath.statinfo} is - deprecated, the filepath itself is not. - """ - filepath.FilePath(self.mktemp()) - warningInfo = self.flushWarnings([self.test_filePathNotDeprecated]) - self.assertEquals(warningInfo, []) - - - def test_getPermissions_Windows(self): - """ - Getting permissions for a file returns a L{Permissions} object in - Windows. Windows requires a different test, because user permissions - = group permissions = other permissions. Also, chmod may not be able - to set the execute bit, so we are skipping tests that set the execute - bit. - """ - # Change permission after test so file can be deleted - self.addCleanup(self.path.child(b"sub1").chmod, 0o777) - - for mode in (0o777, 0o555): - self.path.child(b"sub1").chmod(mode) - self.assertEqual(self.path.child(b"sub1").getPermissions(), - filepath.Permissions(mode)) - self.path.child(b"sub1").chmod(0o511) #sanity check to make sure that - # user=group=other permissions - self.assertEqual(self.path.child(b"sub1").getPermissions().shorthand(), - "r-xr-xr-x") - - - def test_whetherBlockOrSocket(self): - """ - Ensure that a file is not a block or socket - """ - self.assertFalse(self.path.isBlockDevice()) - self.assertFalse(self.path.isSocket()) - - - def test_statinfoBitsNotImplementedInWindows(self): - """ - Verify that certain file stats are not available on Windows - """ - self.assertRaises(NotImplementedError, self.path.getInodeNumber) - self.assertRaises(NotImplementedError, self.path.getDevice) - self.assertRaises(NotImplementedError, self.path.getNumberOfHardLinks) - self.assertRaises(NotImplementedError, self.path.getUserID) - self.assertRaises(NotImplementedError, self.path.getGroupID) - - - def test_statinfoBitsAreNumbers(self): - """ - Verify that file inode/device/nlinks/uid/gid stats are numbers in - a POSIX environment - """ - if _PY3: - numbers = int - else: - numbers = (int, long) - c = self.path.child(b'file1') - for p in self.path, c: - self.assertIsInstance(p.getInodeNumber(), numbers) - self.assertIsInstance(p.getDevice(), numbers) - self.assertIsInstance(p.getNumberOfHardLinks(), numbers) - self.assertIsInstance(p.getUserID(), numbers) - self.assertIsInstance(p.getGroupID(), numbers) - self.assertEqual(self.path.getUserID(), c.getUserID()) - self.assertEqual(self.path.getGroupID(), c.getGroupID()) - - - def test_statinfoNumbersAreValid(self): - """ - Verify that the right numbers come back from the right accessor methods - for file inode/device/nlinks/uid/gid (in a POSIX environment) - """ - # specify fake statinfo information - class FakeStat: - st_ino = 200 - st_dev = 300 - st_nlink = 400 - st_uid = 500 - st_gid = 600 - - # monkey patch in a fake restat method for self.path - fake = FakeStat() - def fakeRestat(*args, **kwargs): - self.path._statinfo = fake - self.path.restat = fakeRestat - - # ensure that restat will need to be called to get values - self.path._statinfo = None - - self.assertEqual(self.path.getInodeNumber(), fake.st_ino) - self.assertEqual(self.path.getDevice(), fake.st_dev) - self.assertEqual(self.path.getNumberOfHardLinks(), fake.st_nlink) - self.assertEqual(self.path.getUserID(), fake.st_uid) - self.assertEqual(self.path.getGroupID(), fake.st_gid) - - - if platform.isWindows(): - test_statinfoBitsAreNumbers.skip = True - test_statinfoNumbersAreValid.skip = True - test_getPermissions_POSIX.skip = True - else: - test_statinfoBitsNotImplementedInWindows.skip = "Test will run only on Windows." - test_getPermissions_Windows.skip = "Test will run only on Windows." - - - -class SetContentTests(BytesTestCase): - """ - Tests for L{FilePath.setContent}. - """ - def test_write(self): - """ - Contents of the file referred to by a L{FilePath} can be written using - L{FilePath.setContent}. - """ - pathString = self.mktemp() - path = filepath.FilePath(pathString) - path.setContent(b"hello, world") - with open(pathString, "rb") as fObj: - contents = fObj.read() - self.assertEqual(b"hello, world", contents) - - - def test_fileClosing(self): - """ - If writing to the underlying file raises an exception, - L{FilePath.setContent} raises that exception after closing the file. - """ - fp = ExplodingFilePath(b"") - self.assertRaises(IOError, fp.setContent, b"blah") - self.assertTrue(fp.fp.closed) - - - def test_nameCollision(self): - """ - L{FilePath.setContent} will use a different temporary filename on each - invocation, so that multiple processes, threads, or reentrant - invocations will not collide with each other. - """ - fp = TrackingFilePath(self.mktemp()) - fp.setContent(b"alpha") - fp.setContent(b"beta") - - # Sanity check: setContent should only open one derivative path each - # time to store the temporary file. - openedSiblings = fp.openedPaths() - self.assertEqual(len(openedSiblings), 2) - self.assertNotEqual(openedSiblings[0], openedSiblings[1]) - - - def _assertOneOpened(self, fp, extension): - """ - Assert that the L{TrackingFilePath} C{fp} was used to open one sibling - with the given extension. - - @param fp: A L{TrackingFilePath} which should have been used to open - file at a sibling path. - @type fp: L{TrackingFilePath} - - @param extension: The extension the sibling path is expected to have - had. - @type extension: L{bytes} - - @raise: C{self.failureException} is raised if the extension of the - opened file is incorrect or if not exactly one file was opened - using C{fp}. - """ - opened = fp.openedPaths() - self.assertEqual(len(opened), 1, "expected exactly one opened file") - self.assertTrue( - opened[0].basename().endswith(extension), - "%s does not end with %r extension" % ( - opened[0].basename(), extension)) - - - def test_defaultExtension(self): - """ - L{FilePath.setContent} creates temporary files with the extension - I{.new} if no alternate extension value is given. - """ - fp = TrackingFilePath(self.mktemp()) - fp.setContent(b"hello") - self._assertOneOpened(fp, b".new") - - - def test_customExtension(self): - """ - L{FilePath.setContent} creates temporary files with a user-supplied - extension so that if it is somehow interrupted while writing them the - file that it leaves behind will be identifiable. - """ - fp = TrackingFilePath(self.mktemp()) - fp.setContent(b"goodbye", b"-something-else") - self._assertOneOpened(fp, b"-something-else") - - - -class UnicodeFilePathTests(TestCase): - """ - L{FilePath} instances should have the same internal representation as they - were instantiated with. - """ - - def test_UnicodeInstantiation(self): - """ - L{FilePath} instantiated with a text path will return a text-mode - FilePath. - """ - fp = filepath.FilePath(u'./mon\u20acy') - self.assertEqual(type(fp.path), unicode) - - - def test_UnicodeInstantiationBytesChild(self): - """ - Calling L{FilePath.child} on a text-mode L{FilePath} with a L{bytes} - subpath will return a bytes-mode FilePath. - """ - fp = filepath.FilePath(u'./parent-mon\u20acy') - child = fp.child(u'child-mon\u20acy'.encode('utf-8')) - self.assertEqual(type(child.path), bytes) - - - def test_UnicodeInstantiationUnicodeChild(self): - """ - Calling L{FilePath.child} on a text-mode L{FilePath} with a text - subpath will return a text-mode FilePath. - """ - fp = filepath.FilePath(u'./parent-mon\u20acy') - child = fp.child(u'mon\u20acy') - self.assertEqual(type(child.path), unicode) - - - def test_UnicodeInstantiationUnicodePreauthChild(self): - """ - Calling L{FilePath.preauthChild} on a text-mode L{FilePath} with a text - subpath will return a text-mode FilePath. - """ - fp = filepath.FilePath(u'./parent-mon\u20acy') - child = fp.preauthChild(u'mon\u20acy') - self.assertEqual(type(child.path), unicode) - - - def test_UnicodeInstantiationBytesPreauthChild(self): - """ - Calling L{FilePath.preauthChild} on a text-mode L{FilePath} with a bytes - subpath will return a bytes-mode FilePath. - """ - fp = filepath.FilePath(u'./parent-mon\u20acy') - child = fp.preauthChild(u'child-mon\u20acy'.encode('utf-8')) - self.assertEqual(type(child.path), bytes) - - - def test_BytesInstantiation(self): - """ - L{FilePath} instantiated with a L{bytes} path will return a bytes-mode - FilePath. - """ - fp = filepath.FilePath(b"./") - self.assertEqual(type(fp.path), bytes) - - - def test_BytesInstantiationBytesChild(self): - """ - Calling L{FilePath.child} on a bytes-mode L{FilePath} with a bytes - subpath will return a bytes-mode FilePath. - """ - fp = filepath.FilePath(b"./") - child = fp.child(u'child-mon\u20acy'.encode('utf-8')) - self.assertEqual(type(child.path), bytes) - - - def test_BytesInstantiationUnicodeChild(self): - """ - Calling L{FilePath.child} on a bytes-mode L{FilePath} with a text - subpath will return a text-mode FilePath. - """ - fp = filepath.FilePath(u'parent-mon\u20acy'.encode('utf-8')) - child = fp.child(u"mon\u20acy") - self.assertEqual(type(child.path), unicode) - - - def test_BytesInstantiationBytesPreauthChild(self): - """ - Calling L{FilePath.preauthChild} on a bytes-mode L{FilePath} with a - bytes subpath will return a bytes-mode FilePath. - """ - fp = filepath.FilePath(u'./parent-mon\u20acy'.encode('utf-8')) - child = fp.preauthChild(u'child-mon\u20acy'.encode('utf-8')) - self.assertEqual(type(child.path), bytes) - - - def test_BytesInstantiationUnicodePreauthChild(self): - """ - Calling L{FilePath.preauthChild} on a bytes-mode L{FilePath} with a text - subpath will return a text-mode FilePath. - """ - fp = filepath.FilePath(u'./parent-mon\u20acy'.encode('utf-8')) - child = fp.preauthChild(u"mon\u20acy") - self.assertEqual(type(child.path), unicode) - - - def test_unicoderepr(self): - """ - The repr of a L{unicode} L{FilePath} shouldn't burst into flames. - """ - fp = filepath.FilePath(u"/mon\u20acy") - reprOutput = repr(fp) - if _PY3: - self.assertEqual("FilePath('/mon\u20acy')", reprOutput) - else: - self.assertEqual("FilePath(u'/mon\\u20acy')", reprOutput) - - - def test_unicodereprOnBrokenPy26(self): - """ - The repr of a L{unicode} L{FilePath} shouldn't burst into flames. This - test case is for Pythons prior to 2.6.5 which has a broken abspath which - coerces some Unicode paths to bytes. - """ - fp = filepath.FilePath(u"/") - reprOutput = repr(fp) - if _PY3: - self.assertEqual("FilePath('/')", reprOutput) - else: - self.assertEqual("FilePath(u'/')", reprOutput) - - - def test_bytesrepr(self): - """ - The repr of a L{bytes} L{FilePath} shouldn't burst into flames. - """ - fp = filepath.FilePath(u'/parent-mon\u20acy'.encode('utf-8')) - reprOutput = repr(fp) - if _PY3: - self.assertEqual( - "FilePath(b'/parent-mon\\xe2\\x82\\xacy')", reprOutput) - else: - self.assertEqual( - "FilePath('/parent-mon\\xe2\\x82\\xacy')", reprOutput) - - - def test_unicodereprWindows(self): - """ - The repr of a L{unicode} L{FilePath} shouldn't burst into flames. - """ - fp = filepath.FilePath(u"C:\\") - reprOutput = repr(fp) - if _PY3: - self.assertEqual("FilePath('C:\\\\')", reprOutput) - else: - self.assertEqual("FilePath(u'C:\\\\')", reprOutput) - - - def test_bytesreprWindows(self): - """ - The repr of a L{bytes} L{FilePath} shouldn't burst into flames. - """ - fp = filepath.FilePath(b"C:\\") - reprOutput = repr(fp) - if _PY3: - self.assertEqual("FilePath(b'C:\\\\')", reprOutput) - else: - self.assertEqual("FilePath('C:\\\\')", reprOutput) - - - if platform.isWindows(): - test_unicoderepr.skip = "Test will not work on Windows" - test_unicodereprOnBrokenPy26.skip = "Test will not work on Windows" - test_bytesrepr.skip = "Test will not work on Windows" - else: - test_unicodereprWindows.skip = "Test only works on Windows" - test_bytesreprWindows.skip = "Test only works on Windows" - - - def test_mixedTypeGlobChildren(self): - """ - C{globChildren} will return the same type as the pattern argument. - """ - fp = filepath.FilePath(u"/") - children = fp.globChildren(b"*") - self.assertIsInstance(children[0].path, bytes) - - - def test_unicodeGlobChildren(self): - """ - C{globChildren} works with L{unicode}. - """ - fp = filepath.FilePath(u"/") - children = fp.globChildren(u"*") - self.assertIsInstance(children[0].path, unicode) - - - def test_unicodeBasename(self): - """ - Calling C{basename} on an text- L{FilePath} returns L{unicode}. - """ - fp = filepath.FilePath(u"./") - self.assertIsInstance(fp.basename(), unicode) - - - def test_unicodeDirname(self): - """ - Calling C{dirname} on a text-mode L{FilePath} returns L{unicode}. - """ - fp = filepath.FilePath(u"./") - self.assertIsInstance(fp.dirname(), unicode) - - - def test_unicodeParent(self): - """ - Calling C{parent} on a text-mode L{FilePath} will return a text-mode - L{FilePath}. - """ - fp = filepath.FilePath(u"./") - parent = fp.parent() - self.assertIsInstance(parent.path, unicode) - - - def test_mixedTypeTemporarySibling(self): - """ - A L{bytes} extension to C{temporarySibling} will mean a L{bytes} mode - L{FilePath} is returned. - """ - fp = filepath.FilePath(u"./mon\u20acy") - tempSibling = fp.temporarySibling(b".txt") - self.assertIsInstance(tempSibling.path, bytes) - - - def test_unicodeTemporarySibling(self): - """ - A L{unicode} extension to C{temporarySibling} will mean a L{unicode} - mode L{FilePath} is returned. - """ - fp = filepath.FilePath(u"/tmp/mon\u20acy") - tempSibling = fp.temporarySibling(u".txt") - self.assertIsInstance(tempSibling.path, unicode) - - - def test_mixedTypeSiblingExtensionSearch(self): - """ - C{siblingExtensionSearch} called with L{bytes} on a L{unicode}-mode - L{FilePath} will return a L{list} of L{bytes}-mode L{FilePath}s. - """ - fp = filepath.FilePath(u"./mon\u20acy") - sibling = filepath.FilePath(fp._asTextPath() + u".txt") - sibling.touch() - newPath = fp.siblingExtensionSearch(b".txt") - - self.assertIsInstance(newPath, filepath.FilePath) - self.assertIsInstance(newPath.path, bytes) - - - def test_unicodeSiblingExtensionSearch(self): - """ - C{siblingExtensionSearch} called with L{unicode} on a L{unicode}-mode - L{FilePath} will return a L{list} of L{unicode}-mode L{FilePath}s. - """ - fp = filepath.FilePath(u"./mon\u20acy") - sibling = filepath.FilePath(fp._asTextPath() + u".txt") - sibling.touch() - - newPath = fp.siblingExtensionSearch(u".txt") - - self.assertIsInstance(newPath, filepath.FilePath) - self.assertIsInstance(newPath.path, unicode) - - - def test_mixedTypeSiblingExtension(self): - """ - C{siblingExtension} called with L{bytes} on a L{unicode}-mode - L{FilePath} will return a L{bytes}-mode L{FilePath}. - """ - fp = filepath.FilePath(u"./mon\u20acy") - sibling = filepath.FilePath(fp._asTextPath() + u".txt") - sibling.touch() - - newPath = fp.siblingExtension(b".txt") - - self.assertIsInstance(newPath, filepath.FilePath) - self.assertIsInstance(newPath.path, bytes) - - - def test_unicodeSiblingExtension(self): - """ - C{siblingExtension} called with L{unicode} on a L{unicode}-mode - L{FilePath} will return a L{unicode}-mode L{FilePath}. - """ - fp = filepath.FilePath(u"./mon\u20acy") - sibling = filepath.FilePath(fp._asTextPath() + u".txt") - sibling.touch() - - newPath = fp.siblingExtension(u".txt") - - self.assertIsInstance(newPath, filepath.FilePath) - self.assertIsInstance(newPath.path, unicode) - - - def test_mixedTypeChildSearchPreauth(self): - """ - C{childSearchPreauth} called with L{bytes} on a L{unicode}-mode - L{FilePath} will return a L{bytes}-mode L{FilePath}. - """ - fp = filepath.FilePath(u"./mon\u20acy") - fp.createDirectory() - self.addCleanup(lambda: fp.remove()) - child = fp.child("text.txt") - child.touch() - - newPath = fp.childSearchPreauth(b"text.txt") - - self.assertIsInstance(newPath, filepath.FilePath) - self.assertIsInstance(newPath.path, bytes) - - - def test_unicodeChildSearchPreauth(self): - """ - C{childSearchPreauth} called with L{unicode} on a L{unicode}-mode - L{FilePath} will return a L{unicode}-mode L{FilePath}. - """ - fp = filepath.FilePath(u"./mon\u20acy") - fp.createDirectory() - self.addCleanup(lambda: fp.remove()) - child = fp.child("text.txt") - child.touch() - - newPath = fp.childSearchPreauth(u"text.txt") - - self.assertIsInstance(newPath, filepath.FilePath) - self.assertIsInstance(newPath.path, unicode) - - - def test_asBytesModeFromUnicode(self): - """ - C{asBytesMode} on a L{unicode}-mode L{FilePath} returns a new - L{bytes}-mode L{FilePath}. - """ - fp = filepath.FilePath(u"./tmp") - newfp = fp.asBytesMode() - self.assertIsNot(fp, newfp) - self.assertIsInstance(newfp.path, bytes) - - - def test_asTextModeFromBytes(self): - """ - C{asBytesMode} on a L{unicode}-mode L{FilePath} returns a new - L{bytes}-mode L{FilePath}. - """ - fp = filepath.FilePath(b"./tmp") - newfp = fp.asTextMode() - self.assertIsNot(fp, newfp) - self.assertIsInstance(newfp.path, unicode) - - - def test_asBytesModeFromBytes(self): - """ - C{asBytesMode} on a L{bytes}-mode L{FilePath} returns the same - L{bytes}-mode L{FilePath}. - """ - fp = filepath.FilePath(b"./tmp") - newfp = fp.asBytesMode() - self.assertIs(fp, newfp) - self.assertIsInstance(newfp.path, bytes) - - - def test_asTextModeFromUnicode(self): - """ - C{asTextMode} on a L{unicode}-mode L{FilePath} returns the same - L{unicode}-mode L{FilePath}. - """ - fp = filepath.FilePath(u"./tmp") - newfp = fp.asTextMode() - self.assertIs(fp, newfp) - self.assertIsInstance(newfp.path, unicode) - - - def test_asBytesModeFromUnicodeWithEncoding(self): - """ - C{asBytesMode} with an C{encoding} argument uses that encoding when - coercing the L{unicode}-mode L{FilePath} to a L{bytes}-mode L{FilePath}. - """ - fp = filepath.FilePath(u"\u2603") - newfp = fp.asBytesMode(encoding="utf-8") - self.assertIn(b"\xe2\x98\x83", newfp.path) - - - def test_asTextModeFromBytesWithEncoding(self): - """ - C{asTextMode} with an C{encoding} argument uses that encoding when - coercing the L{bytes}-mode L{FilePath} to a L{unicode}-mode L{FilePath}. - """ - fp = filepath.FilePath(b'\xe2\x98\x83') - newfp = fp.asTextMode(encoding="utf-8") - self.assertIn(u"\u2603", newfp.path) - - - def test_asBytesModeFromUnicodeWithUnusableEncoding(self): - """ - C{asBytesMode} with an C{encoding} argument that can't be used to encode - the unicode path raises a L{UnicodeError}. - """ - fp = filepath.FilePath(u"\u2603") - with self.assertRaises(UnicodeError): - fp.asBytesMode(encoding="ascii") - - - def test_asTextModeFromBytesWithUnusableEncoding(self): - """ - C{asTextMode} with an C{encoding} argument that can't be used to encode - the unicode path raises a L{UnicodeError}. - """ - fp = filepath.FilePath(b"\u2603") - with self.assertRaises(UnicodeError): - fp.asTextMode(encoding="utf-32") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pb.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pb.py deleted file mode 100644 index 9224d27..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pb.py +++ /dev/null @@ -1,1846 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for Perspective Broker module. - -TODO: update protocol level tests to use new connection API, leaving -only specific tests for old API. -""" - -# issue1195 TODOs: replace pump.pump() with something involving Deferreds. -# Clean up warning suppression. - -import sys, os, time, gc, weakref - -from cStringIO import StringIO -from zope.interface import implements, Interface - -from twisted.trial import unittest -from twisted.spread import pb, util, publish, jelly -from twisted.internet import protocol, main, reactor -from twisted.internet.error import ConnectionRefusedError -from twisted.internet.defer import Deferred, gatherResults, succeed -from twisted.protocols.policies import WrappingFactory -from twisted.python import failure, log -from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials -from twisted.cred import portal, checkers, credentials - - -class Dummy(pb.Viewable): - def view_doNothing(self, user): - if isinstance(user, DummyPerspective): - return 'hello world!' - else: - return 'goodbye, cruel world!' - - -class DummyPerspective(pb.Avatar): - """ - An L{IPerspective} avatar which will be used in some tests. - """ - def perspective_getDummyViewPoint(self): - return Dummy() - - - -class DummyRealm(object): - implements(portal.IRealm) - - def requestAvatar(self, avatarId, mind, *interfaces): - for iface in interfaces: - if iface is pb.IPerspective: - return iface, DummyPerspective(avatarId), lambda: None - - -class IOPump: - """ - Utility to pump data between clients and servers for protocol testing. - - Perhaps this is a utility worthy of being in protocol.py? - """ - def __init__(self, client, server, clientIO, serverIO): - self.client = client - self.server = server - self.clientIO = clientIO - self.serverIO = serverIO - - - def flush(self): - """ - Pump until there is no more input or output or until L{stop} is called. - This does not run any timers, so don't use it with any code that calls - reactor.callLater. - """ - # failsafe timeout - self._stop = False - timeout = time.time() + 5 - while not self._stop and self.pump(): - if time.time() > timeout: - return - - - def stop(self): - """ - Stop a running L{flush} operation, even if data remains to be - transferred. - """ - self._stop = True - - - def pump(self): - """ - Move data back and forth. - - Returns whether any data was moved. - """ - self.clientIO.seek(0) - self.serverIO.seek(0) - cData = self.clientIO.read() - sData = self.serverIO.read() - self.clientIO.seek(0) - self.serverIO.seek(0) - self.clientIO.truncate() - self.serverIO.truncate() - self.client.transport._checkProducer() - self.server.transport._checkProducer() - for byte in cData: - self.server.dataReceived(byte) - for byte in sData: - self.client.dataReceived(byte) - if cData or sData: - return 1 - else: - return 0 - - - -def connectedServerAndClient(realm=None): - """ - Connect a client and server L{Broker} together with an L{IOPump} - - @param realm: realm to use, defaulting to a L{DummyRealm} - - @returns: a 3-tuple (client, server, pump). - """ - realm = realm or DummyRealm() - clientBroker = pb.Broker() - checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(guest='guest') - factory = pb.PBServerFactory(portal.Portal(realm, [checker])) - serverBroker = factory.buildProtocol(('127.0.0.1',)) - - clientTransport = StringIO() - serverTransport = StringIO() - clientBroker.makeConnection(protocol.FileWrapper(clientTransport)) - serverBroker.makeConnection(protocol.FileWrapper(serverTransport)) - pump = IOPump(clientBroker, serverBroker, clientTransport, serverTransport) - # Challenge-response authentication: - pump.flush() - return clientBroker, serverBroker, pump - - -class SimpleRemote(pb.Referenceable): - def remote_thunk(self, arg): - self.arg = arg - return arg + 1 - - def remote_knuth(self, arg): - raise Exception() - - -class NestedRemote(pb.Referenceable): - def remote_getSimple(self): - return SimpleRemote() - - -class SimpleCopy(pb.Copyable): - def __init__(self): - self.x = 1 - self.y = {"Hello":"World"} - self.z = ['test'] - - -class SimpleLocalCopy(pb.RemoteCopy): - pass - -pb.setUnjellyableForClass(SimpleCopy, SimpleLocalCopy) - - -class SimpleFactoryCopy(pb.Copyable): - """ - @cvar allIDs: hold every created instances of this class. - @type allIDs: C{dict} - """ - allIDs = {} - def __init__(self, id): - self.id = id - SimpleFactoryCopy.allIDs[id] = self - - -def createFactoryCopy(state): - """ - Factory of L{SimpleFactoryCopy}, getting a created instance given the - C{id} found in C{state}. - """ - stateId = state.get("id", None) - if stateId is None: - raise RuntimeError("factory copy state has no 'id' member %s" % - (repr(state),)) - if not stateId in SimpleFactoryCopy.allIDs: - raise RuntimeError("factory class has no ID: %s" % - (SimpleFactoryCopy.allIDs,)) - inst = SimpleFactoryCopy.allIDs[stateId] - if not inst: - raise RuntimeError("factory method found no object with id") - return inst - -pb.setUnjellyableFactoryForClass(SimpleFactoryCopy, createFactoryCopy) - - -class NestedCopy(pb.Referenceable): - def remote_getCopy(self): - return SimpleCopy() - - def remote_getFactory(self, value): - return SimpleFactoryCopy(value) - - - -class SimpleCache(pb.Cacheable): - def __init___(self): - self.x = 1 - self.y = {"Hello":"World"} - self.z = ['test'] - - -class NestedComplicatedCache(pb.Referenceable): - def __init__(self): - self.c = VeryVeryComplicatedCacheable() - - def remote_getCache(self): - return self.c - - -class VeryVeryComplicatedCacheable(pb.Cacheable): - def __init__(self): - self.x = 1 - self.y = 2 - self.foo = 3 - - def setFoo4(self): - self.foo = 4 - self.observer.callRemote('foo',4) - - def getStateToCacheAndObserveFor(self, perspective, observer): - self.observer = observer - return {"x": self.x, - "y": self.y, - "foo": self.foo} - - def stoppedObserving(self, perspective, observer): - log.msg("stopped observing") - observer.callRemote("end") - if observer == self.observer: - self.observer = None - - -class RatherBaroqueCache(pb.RemoteCache): - def observe_foo(self, newFoo): - self.foo = newFoo - - def observe_end(self): - log.msg("the end of things") - -pb.setUnjellyableForClass(VeryVeryComplicatedCacheable, RatherBaroqueCache) - - -class SimpleLocalCache(pb.RemoteCache): - def setCopyableState(self, state): - self.__dict__.update(state) - - def checkMethod(self): - return self.check - - def checkSelf(self): - return self - - def check(self): - return 1 - -pb.setUnjellyableForClass(SimpleCache, SimpleLocalCache) - - -class NestedCache(pb.Referenceable): - def __init__(self): - self.x = SimpleCache() - - def remote_getCache(self): - return [self.x,self.x] - - def remote_putCache(self, cache): - return (self.x is cache) - - -class Observable(pb.Referenceable): - def __init__(self): - self.observers = [] - - def remote_observe(self, obs): - self.observers.append(obs) - - def remote_unobserve(self, obs): - self.observers.remove(obs) - - def notify(self, obj): - for observer in self.observers: - observer.callRemote('notify', self, obj) - - -class DeferredRemote(pb.Referenceable): - def __init__(self): - self.run = 0 - - def runMe(self, arg): - self.run = arg - return arg + 1 - - def dontRunMe(self, arg): - assert 0, "shouldn't have been run!" - - def remote_doItLater(self): - """ - Return a L{Deferred} to be fired on client side. When fired, - C{self.runMe} is called. - """ - d = Deferred() - d.addCallbacks(self.runMe, self.dontRunMe) - self.d = d - return d - - -class Observer(pb.Referenceable): - notified = 0 - obj = None - def remote_notify(self, other, obj): - self.obj = obj - self.notified = self.notified + 1 - other.callRemote('unobserve',self) - - -class NewStyleCopy(pb.Copyable, pb.RemoteCopy, object): - def __init__(self, s): - self.s = s -pb.setUnjellyableForClass(NewStyleCopy, NewStyleCopy) - - -class NewStyleCopy2(pb.Copyable, pb.RemoteCopy, object): - allocated = 0 - initialized = 0 - value = 1 - - def __new__(self): - NewStyleCopy2.allocated += 1 - inst = object.__new__(self) - inst.value = 2 - return inst - - def __init__(self): - NewStyleCopy2.initialized += 1 - -pb.setUnjellyableForClass(NewStyleCopy2, NewStyleCopy2) - - -class NewStyleCacheCopy(pb.Cacheable, pb.RemoteCache, object): - def getStateToCacheAndObserveFor(self, perspective, observer): - return self.__dict__ - -pb.setUnjellyableForClass(NewStyleCacheCopy, NewStyleCacheCopy) - - -class Echoer(pb.Root): - def remote_echo(self, st): - return st - - -class CachedReturner(pb.Root): - def __init__(self, cache): - self.cache = cache - def remote_giveMeCache(self, st): - return self.cache - - -class NewStyleTests(unittest.TestCase): - def setUp(self): - """ - Create a pb server using L{Echoer} protocol and connect a client to it. - """ - self.serverFactory = pb.PBServerFactory(Echoer()) - self.wrapper = WrappingFactory(self.serverFactory) - self.server = reactor.listenTCP(0, self.wrapper) - clientFactory = pb.PBClientFactory() - reactor.connectTCP("localhost", self.server.getHost().port, - clientFactory) - def gotRoot(ref): - self.ref = ref - return clientFactory.getRootObject().addCallback(gotRoot) - - - def tearDown(self): - """ - Close client and server connections, reset values of L{NewStyleCopy2} - class variables. - """ - NewStyleCopy2.allocated = 0 - NewStyleCopy2.initialized = 0 - NewStyleCopy2.value = 1 - self.ref.broker.transport.loseConnection() - # Disconnect any server-side connections too. - for proto in self.wrapper.protocols: - proto.transport.loseConnection() - return self.server.stopListening() - - def test_newStyle(self): - """ - Create a new style object, send it over the wire, and check the result. - """ - orig = NewStyleCopy("value") - d = self.ref.callRemote("echo", orig) - def cb(res): - self.failUnless(isinstance(res, NewStyleCopy)) - self.assertEqual(res.s, "value") - self.failIf(res is orig) # no cheating :) - d.addCallback(cb) - return d - - def test_alloc(self): - """ - Send a new style object and check the number of allocations. - """ - orig = NewStyleCopy2() - self.assertEqual(NewStyleCopy2.allocated, 1) - self.assertEqual(NewStyleCopy2.initialized, 1) - d = self.ref.callRemote("echo", orig) - def cb(res): - # receiving the response creates a third one on the way back - self.failUnless(isinstance(res, NewStyleCopy2)) - self.assertEqual(res.value, 2) - self.assertEqual(NewStyleCopy2.allocated, 3) - self.assertEqual(NewStyleCopy2.initialized, 1) - self.failIf(res is orig) # no cheating :) - # sending the object creates a second one on the far side - d.addCallback(cb) - return d - - - -class ConnectionNotifyServerFactory(pb.PBServerFactory): - """ - A server factory which stores the last connection and fires a - L{Deferred} on connection made. This factory can handle only one - client connection. - - @ivar protocolInstance: the last protocol instance. - @type protocolInstance: C{pb.Broker} - - @ivar connectionMade: the deferred fired upon connection. - @type connectionMade: C{Deferred} - """ - protocolInstance = None - - def __init__(self, root): - """ - Initialize the factory. - """ - pb.PBServerFactory.__init__(self, root) - self.connectionMade = Deferred() - - - def clientConnectionMade(self, protocol): - """ - Store the protocol and fire the connection deferred. - """ - self.protocolInstance = protocol - d, self.connectionMade = self.connectionMade, None - if d is not None: - d.callback(None) - - - -class NewStyleCachedTests(unittest.TestCase): - def setUp(self): - """ - Create a pb server using L{CachedReturner} protocol and connect a - client to it. - """ - self.orig = NewStyleCacheCopy() - self.orig.s = "value" - self.server = reactor.listenTCP(0, - ConnectionNotifyServerFactory(CachedReturner(self.orig))) - clientFactory = pb.PBClientFactory() - reactor.connectTCP("localhost", self.server.getHost().port, - clientFactory) - def gotRoot(ref): - self.ref = ref - d1 = clientFactory.getRootObject().addCallback(gotRoot) - d2 = self.server.factory.connectionMade - return gatherResults([d1, d2]) - - - def tearDown(self): - """ - Close client and server connections. - """ - self.server.factory.protocolInstance.transport.loseConnection() - self.ref.broker.transport.loseConnection() - return self.server.stopListening() - - - def test_newStyleCache(self): - """ - A new-style cacheable object can be retrieved and re-retrieved over a - single connection. The value of an attribute of the cacheable can be - accessed on the receiving side. - """ - d = self.ref.callRemote("giveMeCache", self.orig) - def cb(res, again): - self.assertIsInstance(res, NewStyleCacheCopy) - self.assertEqual("value", res.s) - # no cheating :) - self.assertNotIdentical(self.orig, res) - - if again: - # Save a reference so it stays alive for the rest of this test - self.res = res - # And ask for it again to exercise the special re-jelly logic in - # Cacheable. - return self.ref.callRemote("giveMeCache", self.orig) - d.addCallback(cb, True) - d.addCallback(cb, False) - return d - - - -class BrokerTests(unittest.TestCase): - thunkResult = None - - def tearDown(self): - try: - # from RemotePublished.getFileName - os.unlink('None-None-TESTING.pub') - except OSError: - pass - - def thunkErrorBad(self, error): - self.fail("This should cause a return value, not %s" % (error,)) - - def thunkResultGood(self, result): - self.thunkResult = result - - def thunkErrorGood(self, tb): - pass - - def thunkResultBad(self, result): - self.fail("This should cause an error, not %s" % (result,)) - - def test_reference(self): - c, s, pump = connectedServerAndClient() - - class X(pb.Referenceable): - def remote_catch(self,arg): - self.caught = arg - - class Y(pb.Referenceable): - def remote_throw(self, a, b): - a.callRemote('catch', b) - - s.setNameForLocal("y", Y()) - y = c.remoteForName("y") - x = X() - z = X() - y.callRemote('throw', x, z) - pump.pump() - pump.pump() - pump.pump() - self.assertIdentical(x.caught, z, "X should have caught Z") - - # make sure references to remote methods are equals - self.assertEqual(y.remoteMethod('throw'), y.remoteMethod('throw')) - - def test_result(self): - c, s, pump = connectedServerAndClient() - for x, y in (c, s), (s, c): - # test reflexivity - foo = SimpleRemote() - x.setNameForLocal("foo", foo) - bar = y.remoteForName("foo") - self.expectedThunkResult = 8 - bar.callRemote('thunk',self.expectedThunkResult - 1 - ).addCallbacks(self.thunkResultGood, self.thunkErrorBad) - # Send question. - pump.pump() - # Send response. - pump.pump() - # Shouldn't require any more pumping than that... - self.assertEqual(self.thunkResult, self.expectedThunkResult, - "result wasn't received.") - - def refcountResult(self, result): - self.nestedRemote = result - - def test_tooManyRefs(self): - l = [] - e = [] - c, s, pump = connectedServerAndClient() - foo = NestedRemote() - s.setNameForLocal("foo", foo) - x = c.remoteForName("foo") - for igno in xrange(pb.MAX_BROKER_REFS + 10): - if s.transport.closed or c.transport.closed: - break - x.callRemote("getSimple").addCallbacks(l.append, e.append) - pump.pump() - expected = (pb.MAX_BROKER_REFS - 1) - self.assertTrue(s.transport.closed, "transport was not closed") - self.assertEqual(len(l), expected, - "expected %s got %s" % (expected, len(l))) - - def test_copy(self): - c, s, pump = connectedServerAndClient() - foo = NestedCopy() - s.setNameForLocal("foo", foo) - x = c.remoteForName("foo") - x.callRemote('getCopy' - ).addCallbacks(self.thunkResultGood, self.thunkErrorBad) - pump.pump() - pump.pump() - self.assertEqual(self.thunkResult.x, 1) - self.assertEqual(self.thunkResult.y['Hello'], 'World') - self.assertEqual(self.thunkResult.z[0], 'test') - - def test_observe(self): - c, s, pump = connectedServerAndClient() - - # this is really testing the comparison between remote objects, to make - # sure that you can *UN*observe when you have an observer architecture. - a = Observable() - b = Observer() - s.setNameForLocal("a", a) - ra = c.remoteForName("a") - ra.callRemote('observe',b) - pump.pump() - a.notify(1) - pump.pump() - pump.pump() - a.notify(10) - pump.pump() - pump.pump() - self.assertNotIdentical(b.obj, None, "didn't notify") - self.assertEqual(b.obj, 1, 'notified too much') - - def test_defer(self): - c, s, pump = connectedServerAndClient() - d = DeferredRemote() - s.setNameForLocal("d", d) - e = c.remoteForName("d") - pump.pump(); pump.pump() - results = [] - e.callRemote('doItLater').addCallback(results.append) - pump.pump(); pump.pump() - self.assertFalse(d.run, "Deferred method run too early.") - d.d.callback(5) - self.assertEqual(d.run, 5, "Deferred method run too late.") - pump.pump(); pump.pump() - self.assertEqual(results[0], 6, "Incorrect result.") - - - def test_refcount(self): - c, s, pump = connectedServerAndClient() - foo = NestedRemote() - s.setNameForLocal("foo", foo) - bar = c.remoteForName("foo") - bar.callRemote('getSimple' - ).addCallbacks(self.refcountResult, self.thunkErrorBad) - - # send question - pump.pump() - # send response - pump.pump() - - # delving into internal structures here, because GC is sort of - # inherently internal. - rluid = self.nestedRemote.luid - self.assertIn(rluid, s.localObjects) - del self.nestedRemote - # nudge the gc - if sys.hexversion >= 0x2000000: - gc.collect() - # try to nudge the GC even if we can't really - pump.pump() - pump.pump() - pump.pump() - self.assertNotIn(rluid, s.localObjects) - - def test_cache(self): - c, s, pump = connectedServerAndClient() - obj = NestedCache() - obj2 = NestedComplicatedCache() - vcc = obj2.c - s.setNameForLocal("obj", obj) - s.setNameForLocal("xxx", obj2) - o2 = c.remoteForName("obj") - o3 = c.remoteForName("xxx") - coll = [] - o2.callRemote("getCache" - ).addCallback(coll.append).addErrback(coll.append) - o2.callRemote("getCache" - ).addCallback(coll.append).addErrback(coll.append) - complex = [] - o3.callRemote("getCache").addCallback(complex.append) - o3.callRemote("getCache").addCallback(complex.append) - pump.flush() - # `worst things first' - self.assertEqual(complex[0].x, 1) - self.assertEqual(complex[0].y, 2) - self.assertEqual(complex[0].foo, 3) - - vcc.setFoo4() - pump.flush() - self.assertEqual(complex[0].foo, 4) - self.assertEqual(len(coll), 2) - cp = coll[0][0] - self.assertIdentical(cp.checkMethod().im_self, cp, - "potential refcounting issue") - self.assertIdentical(cp.checkSelf(), cp, - "other potential refcounting issue") - col2 = [] - o2.callRemote('putCache',cp).addCallback(col2.append) - pump.flush() - # The objects were the same (testing lcache identity) - self.assertTrue(col2[0]) - # test equality of references to methods - self.assertEqual(o2.remoteMethod("getCache"), - o2.remoteMethod("getCache")) - - # now, refcounting (similiar to testRefCount) - luid = cp.luid - baroqueLuid = complex[0].luid - self.assertIn(luid, s.remotelyCachedObjects, - "remote cache doesn't have it") - del coll - del cp - pump.flush() - del complex - del col2 - # extra nudge... - pump.flush() - # del vcc.observer - # nudge the gc - if sys.hexversion >= 0x2000000: - gc.collect() - # try to nudge the GC even if we can't really - pump.flush() - # The GC is done with it. - self.assertNotIn(luid, s.remotelyCachedObjects, - "Server still had it after GC") - self.assertNotIn(luid, c.locallyCachedObjects, - "Client still had it after GC") - self.assertNotIn(baroqueLuid, s.remotelyCachedObjects, - "Server still had complex after GC") - self.assertNotIn(baroqueLuid, c.locallyCachedObjects, - "Client still had complex after GC") - self.assertIdentical(vcc.observer, None, "observer was not removed") - - def test_publishable(self): - try: - os.unlink('None-None-TESTING.pub') # from RemotePublished.getFileName - except OSError: - pass # Sometimes it's not there. - c, s, pump = connectedServerAndClient() - foo = GetPublisher() - # foo.pub.timestamp = 1.0 - s.setNameForLocal("foo", foo) - bar = c.remoteForName("foo") - accum = [] - bar.callRemote('getPub').addCallbacks(accum.append, self.thunkErrorBad) - pump.flush() - obj = accum.pop() - self.assertEqual(obj.activateCalled, 1) - self.assertEqual(obj.isActivated, 1) - self.assertEqual(obj.yayIGotPublished, 1) - # timestamp's dirty, we don't have a cache file - self.assertEqual(obj._wasCleanWhenLoaded, 0) - c, s, pump = connectedServerAndClient() - s.setNameForLocal("foo", foo) - bar = c.remoteForName("foo") - bar.callRemote('getPub').addCallbacks(accum.append, self.thunkErrorBad) - pump.flush() - obj = accum.pop() - # timestamp's clean, our cache file is up-to-date - self.assertEqual(obj._wasCleanWhenLoaded, 1) - - def gotCopy(self, val): - self.thunkResult = val.id - - - def test_factoryCopy(self): - c, s, pump = connectedServerAndClient() - ID = 99 - obj = NestedCopy() - s.setNameForLocal("foo", obj) - x = c.remoteForName("foo") - x.callRemote('getFactory', ID - ).addCallbacks(self.gotCopy, self.thunkResultBad) - pump.pump() - pump.pump() - pump.pump() - self.assertEqual(self.thunkResult, ID, - "ID not correct on factory object %s" % (self.thunkResult,)) - - -bigString = "helloworld" * 50 - -callbackArgs = None -callbackKeyword = None - -def finishedCallback(*args, **kw): - global callbackArgs, callbackKeyword - callbackArgs = args - callbackKeyword = kw - - -class Pagerizer(pb.Referenceable): - def __init__(self, callback, *args, **kw): - self.callback, self.args, self.kw = callback, args, kw - - def remote_getPages(self, collector): - util.StringPager(collector, bigString, 100, - self.callback, *self.args, **self.kw) - self.args = self.kw = None - - -class FilePagerizer(pb.Referenceable): - pager = None - - def __init__(self, filename, callback, *args, **kw): - self.filename = filename - self.callback, self.args, self.kw = callback, args, kw - - def remote_getPages(self, collector): - self.pager = util.FilePager(collector, file(self.filename), - self.callback, *self.args, **self.kw) - self.args = self.kw = None - - - -class PagingTests(unittest.TestCase): - """ - Test pb objects sending data by pages. - """ - - def setUp(self): - """ - Create a file used to test L{util.FilePager}. - """ - self.filename = self.mktemp() - fd = file(self.filename, 'w') - fd.write(bigString) - fd.close() - - - def test_pagingWithCallback(self): - """ - Test L{util.StringPager}, passing a callback to fire when all pages - are sent. - """ - c, s, pump = connectedServerAndClient() - s.setNameForLocal("foo", Pagerizer(finishedCallback, 'hello', value=10)) - x = c.remoteForName("foo") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEqual(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - self.assertEqual(callbackArgs, ('hello',), - "Completed callback not invoked") - self.assertEqual(callbackKeyword, {'value': 10}, - "Completed callback not invoked") - - - def test_pagingWithoutCallback(self): - """ - Test L{util.StringPager} without a callback. - """ - c, s, pump = connectedServerAndClient() - s.setNameForLocal("foo", Pagerizer(None)) - x = c.remoteForName("foo") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEqual(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - - - def test_emptyFilePaging(self): - """ - Test L{util.FilePager}, sending an empty file. - """ - filenameEmpty = self.mktemp() - fd = file(filenameEmpty, 'w') - fd.close() - c, s, pump = connectedServerAndClient() - pagerizer = FilePagerizer(filenameEmpty, None) - s.setNameForLocal("bar", pagerizer) - x = c.remoteForName("bar") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - ttl = 10 - while not l and ttl > 0: - pump.pump() - ttl -= 1 - if not ttl: - self.fail('getAllPages timed out') - self.assertEqual(''.join(l[0]), '', - "Pages received not equal to pages sent!") - - - def test_filePagingWithCallback(self): - """ - Test L{util.FilePager}, passing a callback to fire when all pages - are sent, and verify that the pager doesn't keep chunks in memory. - """ - c, s, pump = connectedServerAndClient() - pagerizer = FilePagerizer(self.filename, finishedCallback, - 'frodo', value = 9) - s.setNameForLocal("bar", pagerizer) - x = c.remoteForName("bar") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEqual(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - self.assertEqual(callbackArgs, ('frodo',), - "Completed callback not invoked") - self.assertEqual(callbackKeyword, {'value': 9}, - "Completed callback not invoked") - self.assertEqual(pagerizer.pager.chunks, []) - - - def test_filePagingWithoutCallback(self): - """ - Test L{util.FilePager} without a callback. - """ - c, s, pump = connectedServerAndClient() - pagerizer = FilePagerizer(self.filename, None) - s.setNameForLocal("bar", pagerizer) - x = c.remoteForName("bar") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEqual(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - self.assertEqual(pagerizer.pager.chunks, []) - - - -class DumbPublishable(publish.Publishable): - def getStateToPublish(self): - return {"yayIGotPublished": 1} - - -class DumbPub(publish.RemotePublished): - def activated(self): - self.activateCalled = 1 - - -class GetPublisher(pb.Referenceable): - def __init__(self): - self.pub = DumbPublishable("TESTING") - - def remote_getPub(self): - return self.pub - - -pb.setUnjellyableForClass(DumbPublishable, DumbPub) - -class DisconnectionTests(unittest.TestCase): - """ - Test disconnection callbacks. - """ - - def error(self, *args): - raise RuntimeError("I shouldn't have been called: %s" % (args,)) - - - def gotDisconnected(self): - """ - Called on broker disconnect. - """ - self.gotCallback = 1 - - def objectDisconnected(self, o): - """ - Called on RemoteReference disconnect. - """ - self.assertEqual(o, self.remoteObject) - self.objectCallback = 1 - - def test_badSerialization(self): - c, s, pump = connectedServerAndClient() - pump.pump() - s.setNameForLocal("o", BadCopySet()) - g = c.remoteForName("o") - l = [] - g.callRemote("setBadCopy", BadCopyable()).addErrback(l.append) - pump.flush() - self.assertEqual(len(l), 1) - - def test_disconnection(self): - c, s, pump = connectedServerAndClient() - pump.pump() - s.setNameForLocal("o", SimpleRemote()) - - # get a client reference to server object - r = c.remoteForName("o") - pump.pump() - pump.pump() - pump.pump() - - # register and then unregister disconnect callbacks - # making sure they get unregistered - c.notifyOnDisconnect(self.error) - self.assertIn(self.error, c.disconnects) - c.dontNotifyOnDisconnect(self.error) - self.assertNotIn(self.error, c.disconnects) - - r.notifyOnDisconnect(self.error) - self.assertIn(r._disconnected, c.disconnects) - self.assertIn(self.error, r.disconnectCallbacks) - r.dontNotifyOnDisconnect(self.error) - self.assertNotIn(r._disconnected, c.disconnects) - self.assertNotIn(self.error, r.disconnectCallbacks) - - # register disconnect callbacks - c.notifyOnDisconnect(self.gotDisconnected) - r.notifyOnDisconnect(self.objectDisconnected) - self.remoteObject = r - - # disconnect - c.connectionLost(failure.Failure(main.CONNECTION_DONE)) - self.assertTrue(self.gotCallback) - self.assertTrue(self.objectCallback) - - -class FreakOut(Exception): - pass - - -class BadCopyable(pb.Copyable): - def getStateToCopyFor(self, p): - raise FreakOut() - - -class BadCopySet(pb.Referenceable): - def remote_setBadCopy(self, bc): - return None - - -class LocalRemoteTest(util.LocalAsRemote): - reportAllTracebacks = 0 - - def sync_add1(self, x): - return x + 1 - - def async_add(self, x=0, y=1): - return x + y - - def async_fail(self): - raise RuntimeError() - - - -class MyPerspective(pb.Avatar): - """ - @ivar loggedIn: set to C{True} when the avatar is logged in. - @type loggedIn: C{bool} - - @ivar loggedOut: set to C{True} when the avatar is logged out. - @type loggedOut: C{bool} - """ - implements(pb.IPerspective) - - loggedIn = loggedOut = False - - def __init__(self, avatarId): - self.avatarId = avatarId - - - def perspective_getAvatarId(self): - """ - Return the avatar identifier which was used to access this avatar. - """ - return self.avatarId - - - def perspective_getViewPoint(self): - return MyView() - - - def perspective_add(self, a, b): - """ - Add the given objects and return the result. This is a method - unavailable on L{Echoer}, so it can only be invoked by authenticated - users who received their avatar from L{TestRealm}. - """ - return a + b - - - def logout(self): - self.loggedOut = True - - - -class TestRealm(object): - """ - A realm which repeatedly gives out a single instance of L{MyPerspective} - for non-anonymous logins and which gives out a new instance of L{Echoer} - for each anonymous login. - - @ivar lastPerspective: The L{MyPerspective} most recently created and - returned from C{requestAvatar}. - - @ivar perspectiveFactory: A one-argument callable which will be used to - create avatars to be returned from C{requestAvatar}. - """ - perspectiveFactory = MyPerspective - - lastPerspective = None - - def requestAvatar(self, avatarId, mind, interface): - """ - Verify that the mind and interface supplied have the expected values - (this should really be done somewhere else, like inside a test method) - and return an avatar appropriate for the given identifier. - """ - assert interface == pb.IPerspective - assert mind == "BRAINS!" - if avatarId is checkers.ANONYMOUS: - return pb.IPerspective, Echoer(), lambda: None - else: - self.lastPerspective = self.perspectiveFactory(avatarId) - self.lastPerspective.loggedIn = True - return ( - pb.IPerspective, self.lastPerspective, - self.lastPerspective.logout) - - - -class MyView(pb.Viewable): - - def view_check(self, user): - return isinstance(user, MyPerspective) - - - -class LeakyRealm(TestRealm): - """ - A realm which hangs onto a reference to the mind object in its logout - function. - """ - def __init__(self, mindEater): - """ - Create a L{LeakyRealm}. - - @param mindEater: a callable that will be called with the C{mind} - object when it is available - """ - self._mindEater = mindEater - - - def requestAvatar(self, avatarId, mind, interface): - self._mindEater(mind) - persp = self.perspectiveFactory(avatarId) - return (pb.IPerspective, persp, lambda : (mind, persp.logout())) - - - -class NewCredLeakTests(unittest.TestCase): - """ - Tests to try to trigger memory leaks. - """ - def test_logoutLeak(self): - """ - The server does not leak a reference when the client disconnects - suddenly, even if the cred logout function forms a reference cycle with - the perspective. - """ - # keep a weak reference to the mind object, which we can verify later - # evaluates to None, thereby ensuring the reference leak is fixed. - self.mindRef = None - def setMindRef(mind): - self.mindRef = weakref.ref(mind) - - clientBroker, serverBroker, pump = connectedServerAndClient( - LeakyRealm(setMindRef)) - - # log in from the client - connectionBroken = [] - root = clientBroker.remoteForName("root") - d = root.callRemote("login", 'guest') - def cbResponse((challenge, challenger)): - mind = SimpleRemote() - return challenger.callRemote("respond", - pb.respond(challenge, 'guest'), mind) - d.addCallback(cbResponse) - def connectionLost(_): - pump.stop() # don't try to pump data anymore - it won't work - connectionBroken.append(1) - serverBroker.connectionLost(failure.Failure(RuntimeError("boom"))) - d.addCallback(connectionLost) - - # flush out the response and connectionLost - pump.flush() - self.assertEqual(connectionBroken, [1]) - - # and check for lingering references - requestAvatar sets mindRef - # to a weakref to the mind; this object should be gc'd, and thus - # the ref should return None - gc.collect() - self.assertEqual(self.mindRef(), None) - - - -class NewCredTests(unittest.TestCase): - """ - Tests related to the L{twisted.cred} support in PB. - """ - def setUp(self): - """ - Create a portal with no checkers and wrap it around a simple test - realm. Set up a PB server on a TCP port which serves perspectives - using that portal. - """ - self.realm = TestRealm() - self.portal = portal.Portal(self.realm) - self.factory = ConnectionNotifyServerFactory(self.portal) - self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - self.portno = self.port.getHost().port - - - def tearDown(self): - """ - Shut down the TCP port created by L{setUp}. - """ - return self.port.stopListening() - - - def getFactoryAndRootObject(self, clientFactory=pb.PBClientFactory): - """ - Create a connection to the test server. - - @param clientFactory: the factory class used to create the connection. - - @return: a tuple (C{factory}, C{deferred}), where factory is an - instance of C{clientFactory} and C{deferred} the L{Deferred} firing - with the PB root object. - """ - factory = clientFactory() - rootObjDeferred = factory.getRootObject() - connector = reactor.connectTCP('127.0.0.1', self.portno, factory) - self.addCleanup(connector.disconnect) - return factory, rootObjDeferred - - - def test_getRootObject(self): - """ - Assert only that L{PBClientFactory.getRootObject}'s Deferred fires with - a L{RemoteReference}. - """ - factory, rootObjDeferred = self.getFactoryAndRootObject() - - def gotRootObject(rootObj): - self.assertIsInstance(rootObj, pb.RemoteReference) - disconnectedDeferred = Deferred() - rootObj.notifyOnDisconnect(disconnectedDeferred.callback) - factory.disconnect() - return disconnectedDeferred - - return rootObjDeferred.addCallback(gotRootObject) - - - def test_deadReferenceError(self): - """ - Test that when a connection is lost, calling a method on a - RemoteReference obtained from it raises DeadReferenceError. - """ - factory, rootObjDeferred = self.getFactoryAndRootObject() - - def gotRootObject(rootObj): - disconnectedDeferred = Deferred() - rootObj.notifyOnDisconnect(disconnectedDeferred.callback) - - def lostConnection(ign): - self.assertRaises( - pb.DeadReferenceError, - rootObj.callRemote, 'method') - - disconnectedDeferred.addCallback(lostConnection) - factory.disconnect() - return disconnectedDeferred - - return rootObjDeferred.addCallback(gotRootObject) - - - def test_clientConnectionLost(self): - """ - Test that if the L{reconnecting} flag is passed with a True value then - a remote call made from a disconnection notification callback gets a - result successfully. - """ - class ReconnectOnce(pb.PBClientFactory): - reconnectedAlready = False - def clientConnectionLost(self, connector, reason): - reconnecting = not self.reconnectedAlready - self.reconnectedAlready = True - if reconnecting: - connector.connect() - return pb.PBClientFactory.clientConnectionLost( - self, connector, reason, reconnecting) - - factory, rootObjDeferred = self.getFactoryAndRootObject(ReconnectOnce) - - def gotRootObject(rootObj): - self.assertIsInstance(rootObj, pb.RemoteReference) - - d = Deferred() - rootObj.notifyOnDisconnect(d.callback) - factory.disconnect() - - def disconnected(ign): - d = factory.getRootObject() - - def gotAnotherRootObject(anotherRootObj): - self.assertIsInstance(anotherRootObj, pb.RemoteReference) - - d = Deferred() - anotherRootObj.notifyOnDisconnect(d.callback) - factory.disconnect() - return d - return d.addCallback(gotAnotherRootObject) - return d.addCallback(disconnected) - return rootObjDeferred.addCallback(gotRootObject) - - - def test_immediateClose(self): - """ - Test that if a Broker loses its connection without receiving any bytes, - it doesn't raise any exceptions or log any errors. - """ - serverProto = self.factory.buildProtocol(('127.0.0.1', 12345)) - serverProto.makeConnection(protocol.FileWrapper(StringIO())) - serverProto.connectionLost(failure.Failure(main.CONNECTION_DONE)) - - - def test_loginConnectionRefused(self): - """ - L{PBClientFactory.login} returns a L{Deferred} which is errbacked - with the L{ConnectionRefusedError} if the underlying connection is - refused. - """ - clientFactory = pb.PBClientFactory() - loginDeferred = clientFactory.login( - credentials.UsernamePassword("foo", "bar")) - clientFactory.clientConnectionFailed( - None, - failure.Failure( - ConnectionRefusedError("Test simulated refused connection"))) - return self.assertFailure(loginDeferred, ConnectionRefusedError) - - - def _disconnect(self, ignore, factory): - """ - Helper method disconnecting the given client factory and returning a - C{Deferred} that will fire when the server connection has noticed the - disconnection. - """ - disconnectedDeferred = Deferred() - self.factory.protocolInstance.notifyOnDisconnect( - lambda: disconnectedDeferred.callback(None)) - factory.disconnect() - return disconnectedDeferred - - - def test_loginLogout(self): - """ - Test that login can be performed with IUsernamePassword credentials and - that when the connection is dropped the avatar is logged out. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - creds = credentials.UsernamePassword("user", "pass") - - # NOTE: real code probably won't need anything where we have the - # "BRAINS!" argument, passing None is fine. We just do it here to - # test that it is being passed. It is used to give additional info to - # the realm to aid perspective creation, if you don't need that, - # ignore it. - mind = "BRAINS!" - - d = factory.login(creds, mind) - def cbLogin(perspective): - self.assertTrue(self.realm.lastPerspective.loggedIn) - self.assertIsInstance(perspective, pb.RemoteReference) - return self._disconnect(None, factory) - d.addCallback(cbLogin) - - def cbLogout(ignored): - self.assertTrue(self.realm.lastPerspective.loggedOut) - d.addCallback(cbLogout) - - connector = reactor.connectTCP("127.0.0.1", self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_logoutAfterDecref(self): - """ - If a L{RemoteReference} to an L{IPerspective} avatar is decrefed and - there remain no other references to the avatar on the server, the - avatar is garbage collected and the logout method called. - """ - loggedOut = Deferred() - - class EventPerspective(pb.Avatar): - """ - An avatar which fires a Deferred when it is logged out. - """ - def __init__(self, avatarId): - pass - - def logout(self): - loggedOut.callback(None) - - self.realm.perspectiveFactory = EventPerspective - - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(foo='bar')) - factory = pb.PBClientFactory() - d = factory.login( - credentials.UsernamePassword('foo', 'bar'), "BRAINS!") - def cbLoggedIn(avatar): - # Just wait for the logout to happen, as it should since the - # reference to the avatar will shortly no longer exists. - return loggedOut - d.addCallback(cbLoggedIn) - def cbLoggedOut(ignored): - # Verify that the server broker's _localCleanup dict isn't growing - # without bound. - self.assertEqual(self.factory.protocolInstance._localCleanup, {}) - d.addCallback(cbLoggedOut) - d.addCallback(self._disconnect, factory) - connector = reactor.connectTCP("127.0.0.1", self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_concurrentLogin(self): - """ - Two different correct login attempts can be made on the same root - object at the same time and produce two different resulting avatars. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse( - foo='bar', baz='quux')) - factory = pb.PBClientFactory() - - firstLogin = factory.login( - credentials.UsernamePassword('foo', 'bar'), "BRAINS!") - secondLogin = factory.login( - credentials.UsernamePassword('baz', 'quux'), "BRAINS!") - d = gatherResults([firstLogin, secondLogin]) - def cbLoggedIn((first, second)): - return gatherResults([ - first.callRemote('getAvatarId'), - second.callRemote('getAvatarId')]) - d.addCallback(cbLoggedIn) - def cbAvatarIds((first, second)): - self.assertEqual(first, 'foo') - self.assertEqual(second, 'baz') - d.addCallback(cbAvatarIds) - d.addCallback(self._disconnect, factory) - - connector = reactor.connectTCP('127.0.0.1', self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_badUsernamePasswordLogin(self): - """ - Test that a login attempt with an invalid user or invalid password - fails in the appropriate way. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - - firstLogin = factory.login( - credentials.UsernamePassword('nosuchuser', 'pass')) - secondLogin = factory.login( - credentials.UsernamePassword('user', 'wrongpass')) - - self.assertFailure(firstLogin, UnauthorizedLogin) - self.assertFailure(secondLogin, UnauthorizedLogin) - d = gatherResults([firstLogin, secondLogin]) - - def cleanup(ignore): - errors = self.flushLoggedErrors(UnauthorizedLogin) - self.assertEqual(len(errors), 2) - return self._disconnect(None, factory) - d.addCallback(cleanup) - - connector = reactor.connectTCP("127.0.0.1", self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_anonymousLogin(self): - """ - Verify that a PB server using a portal configured with an checker which - allows IAnonymous credentials can be logged into using IAnonymous - credentials. - """ - self.portal.registerChecker(checkers.AllowAnonymousAccess()) - factory = pb.PBClientFactory() - d = factory.login(credentials.Anonymous(), "BRAINS!") - - def cbLoggedIn(perspective): - return perspective.callRemote('echo', 123) - d.addCallback(cbLoggedIn) - - d.addCallback(self.assertEqual, 123) - - d.addCallback(self._disconnect, factory) - - connector = reactor.connectTCP("127.0.0.1", self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_anonymousLoginNotPermitted(self): - """ - Verify that without an anonymous checker set up, anonymous login is - rejected. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login(credentials.Anonymous(), "BRAINS!") - self.assertFailure(d, UnhandledCredentials) - - def cleanup(ignore): - errors = self.flushLoggedErrors(UnhandledCredentials) - self.assertEqual(len(errors), 1) - return self._disconnect(None, factory) - d.addCallback(cleanup) - - connector = reactor.connectTCP('127.0.0.1', self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_anonymousLoginWithMultipleCheckers(self): - """ - Like L{test_anonymousLogin} but against a portal with a checker for - both IAnonymous and IUsernamePassword. - """ - self.portal.registerChecker(checkers.AllowAnonymousAccess()) - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login(credentials.Anonymous(), "BRAINS!") - - def cbLogin(perspective): - return perspective.callRemote('echo', 123) - d.addCallback(cbLogin) - - d.addCallback(self.assertEqual, 123) - - d.addCallback(self._disconnect, factory) - - connector = reactor.connectTCP('127.0.0.1', self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_authenticatedLoginWithMultipleCheckers(self): - """ - Like L{test_anonymousLoginWithMultipleCheckers} but check that - username/password authentication works. - """ - self.portal.registerChecker(checkers.AllowAnonymousAccess()) - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login( - credentials.UsernamePassword('user', 'pass'), "BRAINS!") - - def cbLogin(perspective): - return perspective.callRemote('add', 100, 23) - d.addCallback(cbLogin) - - d.addCallback(self.assertEqual, 123) - - d.addCallback(self._disconnect, factory) - - connector = reactor.connectTCP('127.0.0.1', self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - def test_view(self): - """ - Verify that a viewpoint can be retrieved after authenticating with - cred. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login( - credentials.UsernamePassword("user", "pass"), "BRAINS!") - - def cbLogin(perspective): - return perspective.callRemote("getViewPoint") - d.addCallback(cbLogin) - - def cbView(viewpoint): - return viewpoint.callRemote("check") - d.addCallback(cbView) - - d.addCallback(self.assertTrue) - - d.addCallback(self._disconnect, factory) - - connector = reactor.connectTCP("127.0.0.1", self.portno, factory) - self.addCleanup(connector.disconnect) - return d - - - -class NonSubclassingPerspective: - implements(pb.IPerspective) - - def __init__(self, avatarId): - pass - - # IPerspective implementation - def perspectiveMessageReceived(self, broker, message, args, kwargs): - args = broker.unserialize(args, self) - kwargs = broker.unserialize(kwargs, self) - return broker.serialize((message, args, kwargs)) - - # Methods required by TestRealm - def logout(self): - self.loggedOut = True - - - -class NSPTests(unittest.TestCase): - """ - Tests for authentication against a realm where the L{IPerspective} - implementation is not a subclass of L{Avatar}. - """ - def setUp(self): - self.realm = TestRealm() - self.realm.perspectiveFactory = NonSubclassingPerspective - self.portal = portal.Portal(self.realm) - self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.checker.addUser("user", "pass") - self.portal.registerChecker(self.checker) - self.factory = WrappingFactory(pb.PBServerFactory(self.portal)) - self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - self.addCleanup(self.port.stopListening) - self.portno = self.port.getHost().port - - - def test_NSP(self): - """ - An L{IPerspective} implementation which does not subclass - L{Avatar} can expose remote methods for the client to call. - """ - factory = pb.PBClientFactory() - d = factory.login(credentials.UsernamePassword('user', 'pass'), - "BRAINS!") - reactor.connectTCP('127.0.0.1', self.portno, factory) - d.addCallback(lambda p: p.callRemote('ANYTHING', 'here', bar='baz')) - d.addCallback(self.assertEqual, - ('ANYTHING', ('here',), {'bar': 'baz'})) - def cleanup(ignored): - factory.disconnect() - for p in self.factory.protocols: - p.transport.loseConnection() - d.addCallback(cleanup) - return d - - - -class IForwarded(Interface): - """ - Interface used for testing L{util.LocalAsyncForwarder}. - """ - - def forwardMe(): - """ - Simple synchronous method. - """ - - def forwardDeferred(): - """ - Simple asynchronous method. - """ - - -class Forwarded: - """ - Test implementation of L{IForwarded}. - - @ivar forwarded: set if C{forwardMe} is called. - @type forwarded: C{bool} - @ivar unforwarded: set if C{dontForwardMe} is called. - @type unforwarded: C{bool} - """ - implements(IForwarded) - forwarded = False - unforwarded = False - - def forwardMe(self): - """ - Set a local flag to test afterwards. - """ - self.forwarded = True - - def dontForwardMe(self): - """ - Set a local flag to test afterwards. This should not be called as it's - not in the interface. - """ - self.unforwarded = True - - def forwardDeferred(self): - """ - Asynchronously return C{True}. - """ - return succeed(True) - - -class SpreadUtilTests(unittest.TestCase): - """ - Tests for L{twisted.spread.util}. - """ - - def test_sync(self): - """ - Call a synchronous method of a L{util.LocalAsRemote} object and check - the result. - """ - o = LocalRemoteTest() - self.assertEqual(o.callRemote("add1", 2), 3) - - def test_async(self): - """ - Call an asynchronous method of a L{util.LocalAsRemote} object and check - the result. - """ - o = LocalRemoteTest() - o = LocalRemoteTest() - d = o.callRemote("add", 2, y=4) - self.assertIsInstance(d, Deferred) - d.addCallback(self.assertEqual, 6) - return d - - def test_asyncFail(self): - """ - Test a asynchronous failure on a remote method call. - """ - o = LocalRemoteTest() - d = o.callRemote("fail") - def eb(f): - self.assertTrue(isinstance(f, failure.Failure)) - f.trap(RuntimeError) - d.addCallbacks(lambda res: self.fail("supposed to fail"), eb) - return d - - def test_remoteMethod(self): - """ - Test the C{remoteMethod} facility of L{util.LocalAsRemote}. - """ - o = LocalRemoteTest() - m = o.remoteMethod("add1") - self.assertEqual(m(3), 4) - - def test_localAsyncForwarder(self): - """ - Test a call to L{util.LocalAsyncForwarder} using L{Forwarded} local - object. - """ - f = Forwarded() - lf = util.LocalAsyncForwarder(f, IForwarded) - lf.callRemote("forwardMe") - self.assertTrue(f.forwarded) - lf.callRemote("dontForwardMe") - self.assertFalse(f.unforwarded) - rr = lf.callRemote("forwardDeferred") - l = [] - rr.addCallback(l.append) - self.assertEqual(l[0], 1) - - - -class PBWithSecurityOptionsTests(unittest.TestCase): - """ - Test security customization. - """ - - def test_clientDefaultSecurityOptions(self): - """ - By default, client broker should use C{jelly.globalSecurity} as - security settings. - """ - factory = pb.PBClientFactory() - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, jelly.globalSecurity) - - - def test_serverDefaultSecurityOptions(self): - """ - By default, server broker should use C{jelly.globalSecurity} as - security settings. - """ - factory = pb.PBServerFactory(Echoer()) - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, jelly.globalSecurity) - - - def test_clientSecurityCustomization(self): - """ - Check that the security settings are passed from the client factory to - the broker object. - """ - security = jelly.SecurityOptions() - factory = pb.PBClientFactory(security=security) - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, security) - - - def test_serverSecurityCustomization(self): - """ - Check that the security settings are passed from the server factory to - the broker object. - """ - security = jelly.SecurityOptions() - factory = pb.PBServerFactory(Echoer(), security=security) - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, security) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pbfailure.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pbfailure.py deleted file mode 100644 index 4463c69..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pbfailure.py +++ /dev/null @@ -1,469 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for error handling in PB. -""" - -from StringIO import StringIO - -from twisted.trial import unittest -from twisted.spread import pb, flavors, jelly -from twisted.internet import reactor, defer -from twisted.python import log - -## -# test exceptions -## -class AsynchronousException(Exception): - """ - Helper used to test remote methods which return Deferreds which fail with - exceptions which are not L{pb.Error} subclasses. - """ - - -class SynchronousException(Exception): - """ - Helper used to test remote methods which raise exceptions which are not - L{pb.Error} subclasses. - """ - - -class AsynchronousError(pb.Error): - """ - Helper used to test remote methods which return Deferreds which fail with - exceptions which are L{pb.Error} subclasses. - """ - - -class SynchronousError(pb.Error): - """ - Helper used to test remote methods which raise exceptions which are - L{pb.Error} subclasses. - """ - - -#class JellyError(flavors.Jellyable, pb.Error): pass -class JellyError(flavors.Jellyable, pb.Error, pb.RemoteCopy): - pass - - -class SecurityError(pb.Error, pb.RemoteCopy): - pass - -pb.setUnjellyableForClass(JellyError, JellyError) -pb.setUnjellyableForClass(SecurityError, SecurityError) -pb.globalSecurity.allowInstancesOf(SecurityError) - - -#### -# server-side -#### -class SimpleRoot(pb.Root): - def remote_asynchronousException(self): - """ - Fail asynchronously with a non-pb.Error exception. - """ - return defer.fail(AsynchronousException("remote asynchronous exception")) - - def remote_synchronousException(self): - """ - Fail synchronously with a non-pb.Error exception. - """ - raise SynchronousException("remote synchronous exception") - - def remote_asynchronousError(self): - """ - Fail asynchronously with a pb.Error exception. - """ - return defer.fail(AsynchronousError("remote asynchronous error")) - - def remote_synchronousError(self): - """ - Fail synchronously with a pb.Error exception. - """ - raise SynchronousError("remote synchronous error") - - def remote_unknownError(self): - """ - Fail with error that is not known to client. - """ - class UnknownError(pb.Error): - pass - raise UnknownError("I'm not known to client!") - - def remote_jelly(self): - self.raiseJelly() - - def remote_security(self): - self.raiseSecurity() - - def remote_deferredJelly(self): - d = defer.Deferred() - d.addCallback(self.raiseJelly) - d.callback(None) - return d - - def remote_deferredSecurity(self): - d = defer.Deferred() - d.addCallback(self.raiseSecurity) - d.callback(None) - return d - - def raiseJelly(self, results=None): - raise JellyError("I'm jellyable!") - - def raiseSecurity(self, results=None): - raise SecurityError("I'm secure!") - - - -class SaveProtocolServerFactory(pb.PBServerFactory): - """ - A L{pb.PBServerFactory} that saves the latest connected client in - C{protocolInstance}. - """ - protocolInstance = None - - def clientConnectionMade(self, protocol): - """ - Keep track of the given protocol. - """ - self.protocolInstance = protocol - - - -class PBConnTestCase(unittest.TestCase): - unsafeTracebacks = 0 - - def setUp(self): - self._setUpServer() - self._setUpClient() - - def _setUpServer(self): - self.serverFactory = SaveProtocolServerFactory(SimpleRoot()) - self.serverFactory.unsafeTracebacks = self.unsafeTracebacks - self.serverPort = reactor.listenTCP(0, self.serverFactory, interface="127.0.0.1") - - def _setUpClient(self): - portNo = self.serverPort.getHost().port - self.clientFactory = pb.PBClientFactory() - self.clientConnector = reactor.connectTCP("127.0.0.1", portNo, self.clientFactory) - - def tearDown(self): - if self.serverFactory.protocolInstance is not None: - self.serverFactory.protocolInstance.transport.loseConnection() - return defer.gatherResults([ - self._tearDownServer(), - self._tearDownClient()]) - - def _tearDownServer(self): - return defer.maybeDeferred(self.serverPort.stopListening) - - def _tearDownClient(self): - self.clientConnector.disconnect() - return defer.succeed(None) - - - -class PBFailureTests(PBConnTestCase): - compare = unittest.TestCase.assertEqual - - - def _exceptionTest(self, method, exceptionType, flush): - def eb(err): - err.trap(exceptionType) - self.compare(err.traceback, "Traceback unavailable\n") - if flush: - errs = self.flushLoggedErrors(exceptionType) - self.assertEqual(len(errs), 1) - return (err.type, err.value, err.traceback) - d = self.clientFactory.getRootObject() - def gotRootObject(root): - d = root.callRemote(method) - d.addErrback(eb) - return d - d.addCallback(gotRootObject) - return d - - - def test_asynchronousException(self): - """ - Test that a Deferred returned by a remote method which already has a - Failure correctly has that error passed back to the calling side. - """ - return self._exceptionTest( - 'asynchronousException', AsynchronousException, True) - - - def test_synchronousException(self): - """ - Like L{test_asynchronousException}, but for a method which raises an - exception synchronously. - """ - return self._exceptionTest( - 'synchronousException', SynchronousException, True) - - - def test_asynchronousError(self): - """ - Like L{test_asynchronousException}, but for a method which returns a - Deferred failing with an L{pb.Error} subclass. - """ - return self._exceptionTest( - 'asynchronousError', AsynchronousError, False) - - - def test_synchronousError(self): - """ - Like L{test_asynchronousError}, but for a method which synchronously - raises a L{pb.Error} subclass. - """ - return self._exceptionTest( - 'synchronousError', SynchronousError, False) - - - def _success(self, result, expectedResult): - self.assertEqual(result, expectedResult) - return result - - - def _addFailingCallbacks(self, remoteCall, expectedResult, eb): - remoteCall.addCallbacks(self._success, eb, - callbackArgs=(expectedResult,)) - return remoteCall - - - def _testImpl(self, method, expected, eb, exc=None): - """ - Call the given remote method and attach the given errback to the - resulting Deferred. If C{exc} is not None, also assert that one - exception of that type was logged. - """ - rootDeferred = self.clientFactory.getRootObject() - def gotRootObj(obj): - failureDeferred = self._addFailingCallbacks(obj.callRemote(method), expected, eb) - if exc is not None: - def gotFailure(err): - self.assertEqual(len(self.flushLoggedErrors(exc)), 1) - return err - failureDeferred.addBoth(gotFailure) - return failureDeferred - rootDeferred.addCallback(gotRootObj) - return rootDeferred - - - def test_jellyFailure(self): - """ - Test that an exception which is a subclass of L{pb.Error} has more - information passed across the network to the calling side. - """ - def failureJelly(fail): - fail.trap(JellyError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 43 - return self._testImpl('jelly', 43, failureJelly) - - - def test_deferredJellyFailure(self): - """ - Test that a Deferred which fails with a L{pb.Error} is treated in - the same way as a synchronously raised L{pb.Error}. - """ - def failureDeferredJelly(fail): - fail.trap(JellyError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 430 - return self._testImpl('deferredJelly', 430, failureDeferredJelly) - - - def test_unjellyableFailure(self): - """ - An non-jellyable L{pb.Error} subclass raised by a remote method is - turned into a Failure with a type set to the FQPN of the exception - type. - """ - def failureUnjellyable(fail): - self.assertEqual( - fail.type, 'twisted.test.test_pbfailure.SynchronousError') - return 431 - return self._testImpl('synchronousError', 431, failureUnjellyable) - - - def test_unknownFailure(self): - """ - Test that an exception which is a subclass of L{pb.Error} but not - known on the client side has its type set properly. - """ - def failureUnknown(fail): - self.assertEqual( - fail.type, 'twisted.test.test_pbfailure.UnknownError') - return 4310 - return self._testImpl('unknownError', 4310, failureUnknown) - - - def test_securityFailure(self): - """ - Test that even if an exception is not explicitly jellyable (by being - a L{pb.Jellyable} subclass), as long as it is an L{pb.Error} - subclass it receives the same special treatment. - """ - def failureSecurity(fail): - fail.trap(SecurityError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 4300 - return self._testImpl('security', 4300, failureSecurity) - - - def test_deferredSecurity(self): - """ - Test that a Deferred which fails with a L{pb.Error} which is not - also a L{pb.Jellyable} is treated in the same way as a synchronously - raised exception of the same type. - """ - def failureDeferredSecurity(fail): - fail.trap(SecurityError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 43000 - return self._testImpl('deferredSecurity', 43000, failureDeferredSecurity) - - - def test_noSuchMethodFailure(self): - """ - Test that attempting to call a method which is not defined correctly - results in an AttributeError on the calling side. - """ - def failureNoSuch(fail): - fail.trap(pb.NoSuchMethod) - self.compare(fail.traceback, "Traceback unavailable\n") - return 42000 - return self._testImpl('nosuch', 42000, failureNoSuch, AttributeError) - - - def test_copiedFailureLogging(self): - """ - Test that a copied failure received from a PB call can be logged - locally. - - Note: this test needs some serious help: all it really tests is that - log.err(copiedFailure) doesn't raise an exception. - """ - d = self.clientFactory.getRootObject() - - def connected(rootObj): - return rootObj.callRemote('synchronousException') - d.addCallback(connected) - - def exception(failure): - log.err(failure) - errs = self.flushLoggedErrors(SynchronousException) - self.assertEqual(len(errs), 2) - d.addErrback(exception) - - return d - - - def test_throwExceptionIntoGenerator(self): - """ - L{pb.CopiedFailure.throwExceptionIntoGenerator} will throw a - L{RemoteError} into the given paused generator at the point where it - last yielded. - """ - original = pb.CopyableFailure(AttributeError("foo")) - copy = jelly.unjelly(jelly.jelly(original, invoker=DummyInvoker())) - exception = [] - def generatorFunc(): - try: - yield None - except pb.RemoteError, exc: - exception.append(exc) - else: - self.fail("RemoteError not raised") - gen = generatorFunc() - gen.send(None) - self.assertRaises(StopIteration, copy.throwExceptionIntoGenerator, gen) - self.assertEqual(len(exception), 1) - exc = exception[0] - self.assertEqual(exc.remoteType, "exceptions.AttributeError") - self.assertEqual(exc.args, ("foo",)) - self.assertEqual(exc.remoteTraceback, 'Traceback unavailable\n') - - - -class PBFailureUnsafeTests(PBFailureTests): - compare = unittest.TestCase.failIfEquals - unsafeTracebacks = 1 - - - -class DummyInvoker(object): - """ - A behaviorless object to be used as the invoker parameter to - L{jelly.jelly}. - """ - serializingPerspective = None - - - -class FailureJellyingTests(unittest.TestCase): - """ - Tests for the interaction of jelly and failures. - """ - def test_unjelliedFailureCheck(self): - """ - An unjellied L{CopyableFailure} has a check method which behaves the - same way as the original L{CopyableFailure}'s check method. - """ - original = pb.CopyableFailure(ZeroDivisionError()) - self.assertIdentical( - original.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical(original.check(ArithmeticError), ArithmeticError) - copied = jelly.unjelly(jelly.jelly(original, invoker=DummyInvoker())) - self.assertIdentical( - copied.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical(copied.check(ArithmeticError), ArithmeticError) - - - def test_twiceUnjelliedFailureCheck(self): - """ - The object which results from jellying a L{CopyableFailure}, unjellying - the result, creating a new L{CopyableFailure} from the result of that, - jellying it, and finally unjellying the result of that has a check - method which behaves the same way as the original L{CopyableFailure}'s - check method. - """ - original = pb.CopyableFailure(ZeroDivisionError()) - self.assertIdentical( - original.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical(original.check(ArithmeticError), ArithmeticError) - copiedOnce = jelly.unjelly( - jelly.jelly(original, invoker=DummyInvoker())) - derivative = pb.CopyableFailure(copiedOnce) - copiedTwice = jelly.unjelly( - jelly.jelly(derivative, invoker=DummyInvoker())) - self.assertIdentical( - copiedTwice.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical( - copiedTwice.check(ArithmeticError), ArithmeticError) - - - def test_printTracebackIncludesValue(self): - """ - When L{CopiedFailure.printTraceback} is used to print a copied failure - which was unjellied from a L{CopyableFailure} with C{unsafeTracebacks} - set to C{False}, the string representation of the exception value is - included in the output. - """ - original = pb.CopyableFailure(Exception("some reason")) - copied = jelly.unjelly(jelly.jelly(original, invoker=DummyInvoker())) - output = StringIO() - copied.printTraceback(output) - self.assertEqual( - "Traceback from remote host -- Traceback unavailable\n" - "exceptions.Exception: some reason\n", - output.getvalue()) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pcp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pcp.py deleted file mode 100644 index 79e4591..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_pcp.py +++ /dev/null @@ -1,367 +0,0 @@ -# -*- Python -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -__version__ = '$Revision: 1.5 $'[11:-2] - -from twisted.trial import unittest -from twisted.protocols import pcp - -# Goal: - -# Take a Protocol instance. Own all outgoing data - anything that -# would go to p.transport.write. Own all incoming data - anything -# that comes to p.dataReceived. - -# I need: -# Something with the AbstractFileDescriptor interface. -# That is: -# - acts as a Transport -# - has a method write() -# - which buffers -# - acts as a Consumer -# - has a registerProducer, unRegisterProducer -# - tells the Producer to back off (pauseProducing) when its buffer is full. -# - tells the Producer to resumeProducing when its buffer is not so full. -# - acts as a Producer -# - calls registerProducer -# - calls write() on consumers -# - honors requests to pause/resume producing -# - honors stopProducing, and passes it along to upstream Producers - - -class DummyTransport: - """A dumb transport to wrap around.""" - - def __init__(self): - self._writes = [] - - def write(self, data): - self._writes.append(data) - - def getvalue(self): - return ''.join(self._writes) - -class DummyProducer: - resumed = False - stopped = False - paused = False - - def __init__(self, consumer): - self.consumer = consumer - - def resumeProducing(self): - self.resumed = True - self.paused = False - - def pauseProducing(self): - self.paused = True - - def stopProducing(self): - self.stopped = True - - -class DummyConsumer(DummyTransport): - producer = None - finished = False - unregistered = True - - def registerProducer(self, producer, streaming): - self.producer = (producer, streaming) - - def unregisterProducer(self): - self.unregistered = True - - def finish(self): - self.finished = True - -class TransportInterfaceTests(unittest.TestCase): - proxyClass = pcp.BasicProducerConsumerProxy - - def setUp(self): - self.underlying = DummyConsumer() - self.transport = self.proxyClass(self.underlying) - - def testWrite(self): - self.transport.write("some bytes") - -class ConsumerInterfaceTest: - """Test ProducerConsumerProxy as a Consumer. - - Normally we have ProducingServer -> ConsumingTransport. - - If I am to go between (Server -> Shaper -> Transport), I have to - play the role of Consumer convincingly for the ProducingServer. - """ - - def setUp(self): - self.underlying = DummyConsumer() - self.consumer = self.proxyClass(self.underlying) - self.producer = DummyProducer(self.consumer) - - def testRegisterPush(self): - self.consumer.registerProducer(self.producer, True) - ## Consumer should NOT have called PushProducer.resumeProducing - self.failIf(self.producer.resumed) - - ## I'm I'm just a proxy, should I only do resumeProducing when - ## I get poked myself? - #def testRegisterPull(self): - # self.consumer.registerProducer(self.producer, False) - # ## Consumer SHOULD have called PushProducer.resumeProducing - # self.failUnless(self.producer.resumed) - - def testUnregister(self): - self.consumer.registerProducer(self.producer, False) - self.consumer.unregisterProducer() - # Now when the consumer would ordinarily want more data, it - # shouldn't ask producer for it. - # The most succinct way to trigger "want more data" is to proxy for - # a PullProducer and have someone ask me for data. - self.producer.resumed = False - self.consumer.resumeProducing() - self.failIf(self.producer.resumed) - - def testFinish(self): - self.consumer.registerProducer(self.producer, False) - self.consumer.finish() - # I guess finish should behave like unregister? - self.producer.resumed = False - self.consumer.resumeProducing() - self.failIf(self.producer.resumed) - - -class ProducerInterfaceTest: - """Test ProducerConsumerProxy as a Producer. - - Normally we have ProducingServer -> ConsumingTransport. - - If I am to go between (Server -> Shaper -> Transport), I have to - play the role of Producer convincingly for the ConsumingTransport. - """ - - def setUp(self): - self.consumer = DummyConsumer() - self.producer = self.proxyClass(self.consumer) - - def testRegistersProducer(self): - self.assertEqual(self.consumer.producer[0], self.producer) - - def testPause(self): - self.producer.pauseProducing() - self.producer.write("yakkity yak") - self.failIf(self.consumer.getvalue(), - "Paused producer should not have sent data.") - - def testResume(self): - self.producer.pauseProducing() - self.producer.resumeProducing() - self.producer.write("yakkity yak") - self.assertEqual(self.consumer.getvalue(), "yakkity yak") - - def testResumeNoEmptyWrite(self): - self.producer.pauseProducing() - self.producer.resumeProducing() - self.assertEqual(len(self.consumer._writes), 0, - "Resume triggered an empty write.") - - def testResumeBuffer(self): - self.producer.pauseProducing() - self.producer.write("buffer this") - self.producer.resumeProducing() - self.assertEqual(self.consumer.getvalue(), "buffer this") - - def testStop(self): - self.producer.stopProducing() - self.producer.write("yakkity yak") - self.failIf(self.consumer.getvalue(), - "Stopped producer should not have sent data.") - - -class PCP_ConsumerInterfaceTests(ConsumerInterfaceTest, unittest.TestCase): - proxyClass = pcp.BasicProducerConsumerProxy - -class PCPII_ConsumerInterfaceTests(ConsumerInterfaceTest, unittest.TestCase): - proxyClass = pcp.ProducerConsumerProxy - -class PCP_ProducerInterfaceTests(ProducerInterfaceTest, unittest.TestCase): - proxyClass = pcp.BasicProducerConsumerProxy - -class PCPII_ProducerInterfaceTests(ProducerInterfaceTest, unittest.TestCase): - proxyClass = pcp.ProducerConsumerProxy - -class ProducerProxyTests(unittest.TestCase): - """Producer methods on me should be relayed to the Producer I proxy. - """ - proxyClass = pcp.BasicProducerConsumerProxy - - def setUp(self): - self.proxy = self.proxyClass(None) - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, True) - - def testStop(self): - self.proxy.stopProducing() - self.failUnless(self.parentProducer.stopped) - - -class ConsumerProxyTests(unittest.TestCase): - """Consumer methods on me should be relayed to the Consumer I proxy. - """ - proxyClass = pcp.BasicProducerConsumerProxy - - def setUp(self): - self.underlying = DummyConsumer() - self.consumer = self.proxyClass(self.underlying) - - def testWrite(self): - # NOTE: This test only valid for streaming (Push) systems. - self.consumer.write("some bytes") - self.assertEqual(self.underlying.getvalue(), "some bytes") - - def testFinish(self): - self.consumer.finish() - self.failUnless(self.underlying.finished) - - def testUnregister(self): - self.consumer.unregisterProducer() - self.failUnless(self.underlying.unregistered) - - -class PullProducerTest: - def setUp(self): - self.underlying = DummyConsumer() - self.proxy = self.proxyClass(self.underlying) - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, True) - - def testHoldWrites(self): - self.proxy.write("hello") - # Consumer should get no data before it says resumeProducing. - self.failIf(self.underlying.getvalue(), - "Pulling Consumer got data before it pulled.") - - def testPull(self): - self.proxy.write("hello") - self.proxy.resumeProducing() - self.assertEqual(self.underlying.getvalue(), "hello") - - def testMergeWrites(self): - self.proxy.write("hello ") - self.proxy.write("sunshine") - self.proxy.resumeProducing() - nwrites = len(self.underlying._writes) - self.assertEqual(nwrites, 1, "Pull resulted in %d writes instead " - "of 1." % (nwrites,)) - self.assertEqual(self.underlying.getvalue(), "hello sunshine") - - - def testLateWrite(self): - # consumer sends its initial pull before we have data - self.proxy.resumeProducing() - self.proxy.write("data") - # This data should answer that pull request. - self.assertEqual(self.underlying.getvalue(), "data") - -class PCP_PullProducerTests(PullProducerTest, unittest.TestCase): - class proxyClass(pcp.BasicProducerConsumerProxy): - iAmStreaming = False - -class PCPII_PullProducerTests(PullProducerTest, unittest.TestCase): - class proxyClass(pcp.ProducerConsumerProxy): - iAmStreaming = False - -# Buffering! - -class BufferedConsumerTests(unittest.TestCase): - """As a consumer, ask the producer to pause after too much data.""" - - proxyClass = pcp.ProducerConsumerProxy - - def setUp(self): - self.underlying = DummyConsumer() - self.proxy = self.proxyClass(self.underlying) - self.proxy.bufferSize = 100 - - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, True) - - def testRegisterPull(self): - self.proxy.registerProducer(self.parentProducer, False) - ## Consumer SHOULD have called PushProducer.resumeProducing - self.failUnless(self.parentProducer.resumed) - - def testPauseIntercept(self): - self.proxy.pauseProducing() - self.failIf(self.parentProducer.paused) - - def testResumeIntercept(self): - self.proxy.pauseProducing() - self.proxy.resumeProducing() - # With a streaming producer, just because the proxy was resumed is - # not necessarily a reason to resume the parent producer. The state - # of the buffer should decide that. - self.failIf(self.parentProducer.resumed) - - def testTriggerPause(self): - """Make sure I say \"when.\"""" - - # Pause the proxy so data sent to it builds up in its buffer. - self.proxy.pauseProducing() - self.failIf(self.parentProducer.paused, "don't pause yet") - self.proxy.write("x" * 51) - self.failIf(self.parentProducer.paused, "don't pause yet") - self.proxy.write("x" * 51) - self.failUnless(self.parentProducer.paused) - - def testTriggerResume(self): - """Make sure I resumeProducing when my buffer empties.""" - self.proxy.pauseProducing() - self.proxy.write("x" * 102) - self.failUnless(self.parentProducer.paused, "should be paused") - self.proxy.resumeProducing() - # Resuming should have emptied my buffer, so I should tell my - # parent to resume too. - self.failIf(self.parentProducer.paused, - "Producer should have resumed.") - self.failIf(self.proxy.producerPaused) - -class BufferedPullTests(unittest.TestCase): - class proxyClass(pcp.ProducerConsumerProxy): - iAmStreaming = False - - def _writeSomeData(self, data): - pcp.ProducerConsumerProxy._writeSomeData(self, data[:100]) - return min(len(data), 100) - - def setUp(self): - self.underlying = DummyConsumer() - self.proxy = self.proxyClass(self.underlying) - self.proxy.bufferSize = 100 - - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, False) - - def testResumePull(self): - # If proxy has no data to send on resumeProducing, it had better pull - # some from its PullProducer. - self.parentProducer.resumed = False - self.proxy.resumeProducing() - self.failUnless(self.parentProducer.resumed) - - def testLateWriteBuffering(self): - # consumer sends its initial pull before we have data - self.proxy.resumeProducing() - self.proxy.write("datum" * 21) - # This data should answer that pull request. - self.assertEqual(self.underlying.getvalue(), "datum" * 20) - # but there should be some left over - self.assertEqual(self.proxy._buffer, ["datum"]) - - -# TODO: -# test that web request finishing bug (when we weren't proxying -# unregisterProducer but were proxying finish, web file transfers -# would hang on the last block.) -# test what happens if writeSomeBytes decided to write zero bytes. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_persisted.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_persisted.py deleted file mode 100644 index 3481f3a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_persisted.py +++ /dev/null @@ -1,377 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -# System Imports -import sys - -from twisted.trial import unittest - -try: - import cPickle as pickle -except ImportError: - import pickle - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -# Twisted Imports -from twisted.persisted import styles, aot, crefutil - - -class VersionTests(unittest.TestCase): - def test_nullVersionUpgrade(self): - global NullVersioned - class NullVersioned: - ok = 0 - pkcl = pickle.dumps(NullVersioned()) - class NullVersioned(styles.Versioned): - persistenceVersion = 1 - def upgradeToVersion1(self): - self.ok = 1 - mnv = pickle.loads(pkcl) - styles.doUpgrade() - assert mnv.ok, "initial upgrade not run!" - - def test_versionUpgrade(self): - global MyVersioned - class MyVersioned(styles.Versioned): - persistenceVersion = 2 - persistenceForgets = ['garbagedata'] - v3 = 0 - v4 = 0 - - def __init__(self): - self.somedata = 'xxx' - self.garbagedata = lambda q: 'cant persist' - - def upgradeToVersion3(self): - self.v3 += 1 - - def upgradeToVersion4(self): - self.v4 += 1 - mv = MyVersioned() - assert not (mv.v3 or mv.v4), "hasn't been upgraded yet" - pickl = pickle.dumps(mv) - MyVersioned.persistenceVersion = 4 - obj = pickle.loads(pickl) - styles.doUpgrade() - assert obj.v3, "didn't do version 3 upgrade" - assert obj.v4, "didn't do version 4 upgrade" - pickl = pickle.dumps(obj) - obj = pickle.loads(pickl) - styles.doUpgrade() - assert obj.v3 == 1, "upgraded unnecessarily" - assert obj.v4 == 1, "upgraded unnecessarily" - - def test_nonIdentityHash(self): - global ClassWithCustomHash - class ClassWithCustomHash(styles.Versioned): - def __init__(self, unique, hash): - self.unique = unique - self.hash = hash - def __hash__(self): - return self.hash - - v1 = ClassWithCustomHash('v1', 0) - v2 = ClassWithCustomHash('v2', 0) - - pkl = pickle.dumps((v1, v2)) - del v1, v2 - ClassWithCustomHash.persistenceVersion = 1 - ClassWithCustomHash.upgradeToVersion1 = lambda self: setattr(self, 'upgraded', True) - v1, v2 = pickle.loads(pkl) - styles.doUpgrade() - self.assertEqual(v1.unique, 'v1') - self.assertEqual(v2.unique, 'v2') - self.failUnless(v1.upgraded) - self.failUnless(v2.upgraded) - - def test_upgradeDeserializesObjectsRequiringUpgrade(self): - global ToyClassA, ToyClassB - class ToyClassA(styles.Versioned): - pass - class ToyClassB(styles.Versioned): - pass - x = ToyClassA() - y = ToyClassB() - pklA, pklB = pickle.dumps(x), pickle.dumps(y) - del x, y - ToyClassA.persistenceVersion = 1 - def upgradeToVersion1(self): - self.y = pickle.loads(pklB) - styles.doUpgrade() - ToyClassA.upgradeToVersion1 = upgradeToVersion1 - ToyClassB.persistenceVersion = 1 - ToyClassB.upgradeToVersion1 = lambda self: setattr(self, 'upgraded', True) - - x = pickle.loads(pklA) - styles.doUpgrade() - self.failUnless(x.y.upgraded) - - - -class VersionedSubClass(styles.Versioned): - pass - - - -class SecondVersionedSubClass(styles.Versioned): - pass - - - -class VersionedSubSubClass(VersionedSubClass): - pass - - - -class VersionedDiamondSubClass(VersionedSubSubClass, SecondVersionedSubClass): - pass - - - -class AybabtuTests(unittest.TestCase): - """ - L{styles._aybabtu} gets all of classes in the inheritance hierarchy of its - argument that are strictly between L{Versioned} and the class itself. - """ - - def test_aybabtuStrictEmpty(self): - """ - L{styles._aybabtu} of L{Versioned} itself is an empty list. - """ - self.assertEqual(styles._aybabtu(styles.Versioned), []) - - - def test_aybabtuStrictSubclass(self): - """ - There are no classes I{between} L{VersionedSubClass} and L{Versioned}, - so L{styles._aybabtu} returns an empty list. - """ - self.assertEqual(styles._aybabtu(VersionedSubClass), []) - - - def test_aybabtuSubsubclass(self): - """ - With a sub-sub-class of L{Versioned}, L{styles._aybabtu} returns a list - containing the intervening subclass. - """ - self.assertEqual(styles._aybabtu(VersionedSubSubClass), - [VersionedSubClass]) - - - def test_aybabtuStrict(self): - """ - For a diamond-shaped inheritance graph, L{styles._aybabtu} returns a - list containing I{both} intermediate subclasses. - """ - self.assertEqual( - styles._aybabtu(VersionedDiamondSubClass), - [VersionedSubSubClass, VersionedSubClass, SecondVersionedSubClass]) - - - -class MyEphemeral(styles.Ephemeral): - - def __init__(self, x): - self.x = x - - -class EphemeralTests(unittest.TestCase): - - def test_ephemeral(self): - o = MyEphemeral(3) - self.assertEqual(o.__class__, MyEphemeral) - self.assertEqual(o.x, 3) - - pickl = pickle.dumps(o) - o = pickle.loads(pickl) - - self.assertEqual(o.__class__, styles.Ephemeral) - self.assert_(not hasattr(o, 'x')) - - -class Pickleable: - - def __init__(self, x): - self.x = x - - def getX(self): - return self.x - -class A: - """ - dummy class - """ - def amethod(self): - pass - -class B: - """ - dummy class - """ - def bmethod(self): - pass - -def funktion(): - pass - -class PicklingTests(unittest.TestCase): - """Test pickling of extra object types.""" - - def test_module(self): - pickl = pickle.dumps(styles) - o = pickle.loads(pickl) - self.assertEqual(o, styles) - - def test_classMethod(self): - pickl = pickle.dumps(Pickleable.getX) - o = pickle.loads(pickl) - self.assertEqual(o, Pickleable.getX) - - def test_instanceMethod(self): - obj = Pickleable(4) - pickl = pickle.dumps(obj.getX) - o = pickle.loads(pickl) - self.assertEqual(o(), 4) - self.assertEqual(type(o), type(obj.getX)) - - def test_stringIO(self): - f = StringIO.StringIO() - f.write("abc") - pickl = pickle.dumps(f) - o = pickle.loads(pickl) - self.assertEqual(type(o), type(f)) - self.assertEqual(f.getvalue(), "abc") - - -class EvilSourceror: - def __init__(self, x): - self.a = self - self.a.b = self - self.a.b.c = x - -class NonDictState: - def __getstate__(self): - return self.state - def __setstate__(self, state): - self.state = state - -class AOTTests(unittest.TestCase): - def test_simpleTypes(self): - obj = (1, 2.0, 3j, True, slice(1, 2, 3), 'hello', u'world', sys.maxint + 1, None, Ellipsis) - rtObj = aot.unjellyFromSource(aot.jellyToSource(obj)) - self.assertEqual(obj, rtObj) - - def test_methodSelfIdentity(self): - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - im_ = aot.unjellyFromSource(aot.jellyToSource(b)).a.bmethod - self.assertEqual(im_.im_class, im_.im_self.__class__) - - - def test_methodNotSelfIdentity(self): - """ - If a class change after an instance has been created, - L{aot.unjellyFromSource} shoud raise a C{TypeError} when trying to - unjelly the instance. - """ - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - savedbmethod = B.bmethod - del B.bmethod - try: - self.assertRaises(TypeError, aot.unjellyFromSource, - aot.jellyToSource(b)) - finally: - B.bmethod = savedbmethod - - - def test_unsupportedType(self): - """ - L{aot.jellyToSource} should raise a C{TypeError} when trying to jelly - an unknown type. - """ - try: - set - except: - from sets import Set as set - self.assertRaises(TypeError, aot.jellyToSource, set()) - - - def test_basicIdentity(self): - # Anyone wanting to make this datastructure more complex, and thus this - # test more comprehensive, is welcome to do so. - aj = aot.AOTJellier().jellyToAO - d = {'hello': 'world', "method": aj} - l = [1, 2, 3, - "he\tllo\n\n\"x world!", - u"goodbye \n\t\u1010 world!", - 1, 1.0, 100 ** 100l, unittest, aot.AOTJellier, d, - funktion - ] - t = tuple(l) - l.append(l) - l.append(t) - l.append(t) - uj = aot.unjellyFromSource(aot.jellyToSource([l, l])) - assert uj[0] is uj[1] - assert uj[1][0:5] == l[0:5] - - - def test_nonDictState(self): - a = NonDictState() - a.state = "meringue!" - assert aot.unjellyFromSource(aot.jellyToSource(a)).state == a.state - - def test_copyReg(self): - s = "foo_bar" - sio = StringIO.StringIO() - sio.write(s) - uj = aot.unjellyFromSource(aot.jellyToSource(sio)) - # print repr(uj.__dict__) - assert uj.getvalue() == s - - def test_funkyReferences(self): - o = EvilSourceror(EvilSourceror([])) - j1 = aot.jellyToAOT(o) - oj = aot.unjellyFromAOT(j1) - - assert oj.a is oj - assert oj.a.b is oj.b - assert oj.c is not oj.c.c - - -class CrefUtilTests(unittest.TestCase): - """ - Tests for L{crefutil}. - """ - - def test_dictUnknownKey(self): - """ - L{crefutil._DictKeyAndValue} only support keys C{0} and C{1}. - """ - d = crefutil._DictKeyAndValue({}) - self.assertRaises(RuntimeError, d.__setitem__, 2, 3) - - - def test_deferSetMultipleTimes(self): - """ - L{crefutil._Defer} can be assigned a key only one time. - """ - d = crefutil._Defer() - d[0] = 1 - self.assertRaises(RuntimeError, d.__setitem__, 0, 1) - - - -testCases = [VersionTests, EphemeralTests, PicklingTests] - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_plugin.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_plugin.py deleted file mode 100644 index aac4940..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_plugin.py +++ /dev/null @@ -1,719 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for Twisted plugin system. -""" - -import sys, errno, os, time -import compileall - -from zope.interface import Interface - -from twisted.trial import unittest -from twisted.python.log import textFromEventDict, addObserver, removeObserver -from twisted.python.filepath import FilePath -from twisted.python.util import mergeFunctionMetadata - -from twisted import plugin - - - -class ITestPlugin(Interface): - """ - A plugin for use by the plugin system's unit tests. - - Do not use this. - """ - - - -class ITestPlugin2(Interface): - """ - See L{ITestPlugin}. - """ - - - -class PluginTests(unittest.TestCase): - """ - Tests which verify the behavior of the current, active Twisted plugins - directory. - """ - - def setUp(self): - """ - Save C{sys.path} and C{sys.modules}, and create a package for tests. - """ - self.originalPath = sys.path[:] - self.savedModules = sys.modules.copy() - - self.root = FilePath(self.mktemp()) - self.root.createDirectory() - self.package = self.root.child('mypackage') - self.package.createDirectory() - self.package.child('__init__.py').setContent("") - - FilePath(__file__).sibling('plugin_basic.py' - ).copyTo(self.package.child('testplugin.py')) - - self.originalPlugin = "testplugin" - - sys.path.insert(0, self.root.path) - import mypackage - self.module = mypackage - - - def tearDown(self): - """ - Restore C{sys.path} and C{sys.modules} to their original values. - """ - sys.path[:] = self.originalPath - sys.modules.clear() - sys.modules.update(self.savedModules) - - - def _unimportPythonModule(self, module, deleteSource=False): - modulePath = module.__name__.split('.') - packageName = '.'.join(modulePath[:-1]) - moduleName = modulePath[-1] - - delattr(sys.modules[packageName], moduleName) - del sys.modules[module.__name__] - for ext in ['c', 'o'] + (deleteSource and [''] or []): - try: - os.remove(module.__file__ + ext) - except OSError, ose: - if ose.errno != errno.ENOENT: - raise - - - def _clearCache(self): - """ - Remove the plugins B{droping.cache} file. - """ - self.package.child('dropin.cache').remove() - - - def _withCacheness(meth): - """ - This is a paranoid test wrapper, that calls C{meth} 2 times, clear the - cache, and calls it 2 other times. It's supposed to ensure that the - plugin system behaves correctly no matter what the state of the cache - is. - """ - def wrapped(self): - meth(self) - meth(self) - self._clearCache() - meth(self) - meth(self) - return mergeFunctionMetadata(meth, wrapped) - - - def test_cache(self): - """ - Check that the cache returned by L{plugin.getCache} hold the plugin - B{testplugin}, and that this plugin has the properties we expect: - provide L{TestPlugin}, has the good name and description, and can be - loaded successfully. - """ - cache = plugin.getCache(self.module) - - dropin = cache[self.originalPlugin] - self.assertEqual(dropin.moduleName, - 'mypackage.%s' % (self.originalPlugin,)) - self.assertIn("I'm a test drop-in.", dropin.description) - - # Note, not the preferred way to get a plugin by its interface. - p1 = [p for p in dropin.plugins if ITestPlugin in p.provided][0] - self.assertIdentical(p1.dropin, dropin) - self.assertEqual(p1.name, "TestPlugin") - - # Check the content of the description comes from the plugin module - # docstring - self.assertEqual( - p1.description.strip(), - "A plugin used solely for testing purposes.") - self.assertEqual(p1.provided, [ITestPlugin, plugin.IPlugin]) - realPlugin = p1.load() - # The plugin should match the class present in sys.modules - self.assertIdentical( - realPlugin, - sys.modules['mypackage.%s' % (self.originalPlugin,)].TestPlugin) - - # And it should also match if we import it classicly - import mypackage.testplugin as tp - self.assertIdentical(realPlugin, tp.TestPlugin) - - test_cache = _withCacheness(test_cache) - - - def test_plugins(self): - """ - L{plugin.getPlugins} should return the list of plugins matching the - specified interface (here, L{ITestPlugin2}), and these plugins - should be instances of classes with a C{test} method, to be sure - L{plugin.getPlugins} load classes correctly. - """ - plugins = list(plugin.getPlugins(ITestPlugin2, self.module)) - - self.assertEqual(len(plugins), 2) - - names = ['AnotherTestPlugin', 'ThirdTestPlugin'] - for p in plugins: - names.remove(p.__name__) - p.test() - - test_plugins = _withCacheness(test_plugins) - - - def test_detectNewFiles(self): - """ - Check that L{plugin.getPlugins} is able to detect plugins added at - runtime. - """ - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - try: - # Check that the current situation is clean - self.failIfIn('mypackage.pluginextra', sys.modules) - self.failIf(hasattr(sys.modules['mypackage'], 'pluginextra'), - "mypackage still has pluginextra module") - - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - - # We should find 2 plugins: the one in testplugin, and the one in - # pluginextra - self.assertEqual(len(plgs), 2) - - names = ['TestPlugin', 'FourthTestPlugin'] - for p in plgs: - names.remove(p.__name__) - p.test1() - finally: - self._unimportPythonModule( - sys.modules['mypackage.pluginextra'], - True) - - test_detectNewFiles = _withCacheness(test_detectNewFiles) - - - def test_detectFilesChanged(self): - """ - Check that if the content of a plugin change, L{plugin.getPlugins} is - able to detect the new plugins added. - """ - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - try: - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - # Sanity check - self.assertEqual(len(plgs), 2) - - FilePath(__file__).sibling('plugin_extra2.py' - ).copyTo(self.package.child('pluginextra.py')) - - # Fake out Python. - self._unimportPythonModule(sys.modules['mypackage.pluginextra']) - - # Make sure additions are noticed - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - - self.assertEqual(len(plgs), 3) - - names = ['TestPlugin', 'FourthTestPlugin', 'FifthTestPlugin'] - for p in plgs: - names.remove(p.__name__) - p.test1() - finally: - self._unimportPythonModule( - sys.modules['mypackage.pluginextra'], - True) - - test_detectFilesChanged = _withCacheness(test_detectFilesChanged) - - - def test_detectFilesRemoved(self): - """ - Check that when a dropin file is removed, L{plugin.getPlugins} doesn't - return it anymore. - """ - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - try: - # Generate a cache with pluginextra in it. - list(plugin.getPlugins(ITestPlugin, self.module)) - - finally: - self._unimportPythonModule( - sys.modules['mypackage.pluginextra'], - True) - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEqual(1, len(plgs)) - - test_detectFilesRemoved = _withCacheness(test_detectFilesRemoved) - - - def test_nonexistentPathEntry(self): - """ - Test that getCache skips over any entries in a plugin package's - C{__path__} which do not exist. - """ - path = self.mktemp() - self.failIf(os.path.exists(path)) - # Add the test directory to the plugins path - self.module.__path__.append(path) - try: - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEqual(len(plgs), 1) - finally: - self.module.__path__.remove(path) - - test_nonexistentPathEntry = _withCacheness(test_nonexistentPathEntry) - - - def test_nonDirectoryChildEntry(self): - """ - Test that getCache skips over any entries in a plugin package's - C{__path__} which refer to children of paths which are not directories. - """ - path = FilePath(self.mktemp()) - self.failIf(path.exists()) - path.touch() - child = path.child("test_package").path - self.module.__path__.append(child) - try: - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEqual(len(plgs), 1) - finally: - self.module.__path__.remove(child) - - test_nonDirectoryChildEntry = _withCacheness(test_nonDirectoryChildEntry) - - - def test_deployedMode(self): - """ - The C{dropin.cache} file may not be writable: the cache should still be - attainable, but an error should be logged to show that the cache - couldn't be updated. - """ - # Generate the cache - plugin.getCache(self.module) - - cachepath = self.package.child('dropin.cache') - - # Add a new plugin - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - - os.chmod(self.package.path, 0500) - # Change the right of dropin.cache too for windows - os.chmod(cachepath.path, 0400) - self.addCleanup(os.chmod, self.package.path, 0700) - self.addCleanup(os.chmod, cachepath.path, 0700) - - # Start observing log events to see the warning - events = [] - addObserver(events.append) - self.addCleanup(removeObserver, events.append) - - cache = plugin.getCache(self.module) - # The new plugin should be reported - self.assertIn('pluginextra', cache) - self.assertIn(self.originalPlugin, cache) - - # Make sure something was logged about the cache. - expected = "Unable to write to plugin cache %s: error number %d" % ( - cachepath.path, errno.EPERM) - for event in events: - if expected in textFromEventDict(event): - break - else: - self.fail( - "Did not observe unwriteable cache warning in log " - "events: %r" % (events,)) - - - -# This is something like the Twisted plugins file. -pluginInitFile = """ -from twisted.plugin import pluginPackagePaths -__path__.extend(pluginPackagePaths(__name__)) -__all__ = [] -""" - -def pluginFileContents(name): - return ( - "from zope.interface import classProvides\n" - "from twisted.plugin import IPlugin\n" - "from twisted.test.test_plugin import ITestPlugin\n" - "\n" - "class %s(object):\n" - " classProvides(IPlugin, ITestPlugin)\n") % (name,) - - -def _createPluginDummy(entrypath, pluginContent, real, pluginModule): - """ - Create a plugindummy package. - """ - entrypath.createDirectory() - pkg = entrypath.child('plugindummy') - pkg.createDirectory() - if real: - pkg.child('__init__.py').setContent('') - plugs = pkg.child('plugins') - plugs.createDirectory() - if real: - plugs.child('__init__.py').setContent(pluginInitFile) - plugs.child(pluginModule + '.py').setContent(pluginContent) - return plugs - - - -class DeveloperSetupTests(unittest.TestCase): - """ - These tests verify things about the plugin system without actually - interacting with the deployed 'twisted.plugins' package, instead creating a - temporary package. - """ - - def setUp(self): - """ - Create a complex environment with multiple entries on sys.path, akin to - a developer's environment who has a development (trunk) checkout of - Twisted, a system installed version of Twisted (for their operating - system's tools) and a project which provides Twisted plugins. - """ - self.savedPath = sys.path[:] - self.savedModules = sys.modules.copy() - self.fakeRoot = FilePath(self.mktemp()) - self.fakeRoot.createDirectory() - self.systemPath = self.fakeRoot.child('system_path') - self.devPath = self.fakeRoot.child('development_path') - self.appPath = self.fakeRoot.child('application_path') - self.systemPackage = _createPluginDummy( - self.systemPath, pluginFileContents('system'), - True, 'plugindummy_builtin') - self.devPackage = _createPluginDummy( - self.devPath, pluginFileContents('dev'), - True, 'plugindummy_builtin') - self.appPackage = _createPluginDummy( - self.appPath, pluginFileContents('app'), - False, 'plugindummy_app') - - # Now we're going to do the system installation. - sys.path.extend([x.path for x in [self.systemPath, - self.appPath]]) - # Run all the way through the plugins list to cause the - # L{plugin.getPlugins} generator to write cache files for the system - # installation. - self.getAllPlugins() - self.sysplug = self.systemPath.child('plugindummy').child('plugins') - self.syscache = self.sysplug.child('dropin.cache') - # Make sure there's a nice big difference in modification times so that - # we won't re-build the system cache. - now = time.time() - os.utime( - self.sysplug.child('plugindummy_builtin.py').path, - (now - 5000,) * 2) - os.utime(self.syscache.path, (now - 2000,) * 2) - # For extra realism, let's make sure that the system path is no longer - # writable. - self.lockSystem() - self.resetEnvironment() - - - def lockSystem(self): - """ - Lock the system directories, as if they were unwritable by this user. - """ - os.chmod(self.sysplug.path, 0555) - os.chmod(self.syscache.path, 0555) - - - def unlockSystem(self): - """ - Unlock the system directories, as if they were writable by this user. - """ - os.chmod(self.sysplug.path, 0777) - os.chmod(self.syscache.path, 0777) - - - def getAllPlugins(self): - """ - Get all the plugins loadable from our dummy package, and return their - short names. - """ - # Import the module we just added to our path. (Local scope because - # this package doesn't exist outside of this test.) - import plugindummy.plugins - x = list(plugin.getPlugins(ITestPlugin, plugindummy.plugins)) - return [plug.__name__ for plug in x] - - - def resetEnvironment(self): - """ - Change the environment to what it should be just as the test is - starting. - """ - self.unsetEnvironment() - sys.path.extend([x.path for x in [self.devPath, - self.systemPath, - self.appPath]]) - - def unsetEnvironment(self): - """ - Change the Python environment back to what it was before the test was - started. - """ - sys.modules.clear() - sys.modules.update(self.savedModules) - sys.path[:] = self.savedPath - - - def tearDown(self): - """ - Reset the Python environment to what it was before this test ran, and - restore permissions on files which were marked read-only so that the - directory may be cleanly cleaned up. - """ - self.unsetEnvironment() - # Normally we wouldn't "clean up" the filesystem like this (leaving - # things for post-test inspection), but if we left the permissions the - # way they were, we'd be leaving files around that the buildbots - # couldn't delete, and that would be bad. - self.unlockSystem() - - - def test_developmentPluginAvailability(self): - """ - Plugins added in the development path should be loadable, even when - the (now non-importable) system path contains its own idea of the - list of plugins for a package. Inversely, plugins added in the - system path should not be available. - """ - # Run 3 times: uncached, cached, and then cached again to make sure we - # didn't overwrite / corrupt the cache on the cached try. - for x in range(3): - names = self.getAllPlugins() - names.sort() - self.assertEqual(names, ['app', 'dev']) - - - def test_freshPyReplacesStalePyc(self): - """ - Verify that if a stale .pyc file on the PYTHONPATH is replaced by a - fresh .py file, the plugins in the new .py are picked up rather than - the stale .pyc, even if the .pyc is still around. - """ - mypath = self.appPackage.child("stale.py") - mypath.setContent(pluginFileContents('one')) - # Make it super stale - x = time.time() - 1000 - os.utime(mypath.path, (x, x)) - pyc = mypath.sibling('stale.pyc') - # compile it - compileall.compile_dir(self.appPackage.path, quiet=1) - os.utime(pyc.path, (x, x)) - # Eliminate the other option. - mypath.remove() - # Make sure it's the .pyc path getting cached. - self.resetEnvironment() - # Sanity check. - self.assertIn('one', self.getAllPlugins()) - self.failIfIn('two', self.getAllPlugins()) - self.resetEnvironment() - mypath.setContent(pluginFileContents('two')) - self.failIfIn('one', self.getAllPlugins()) - self.assertIn('two', self.getAllPlugins()) - - - def test_newPluginsOnReadOnlyPath(self): - """ - Verify that a failure to write the dropin.cache file on a read-only - path will not affect the list of plugins returned. - - Note: this test should pass on both Linux and Windows, but may not - provide useful coverage on Windows due to the different meaning of - "read-only directory". - """ - self.unlockSystem() - self.sysplug.child('newstuff.py').setContent(pluginFileContents('one')) - self.lockSystem() - - # Take the developer path out, so that the system plugins are actually - # examined. - sys.path.remove(self.devPath.path) - - # Start observing log events to see the warning - events = [] - addObserver(events.append) - self.addCleanup(removeObserver, events.append) - - self.assertIn('one', self.getAllPlugins()) - - # Make sure something was logged about the cache. - expected = "Unable to write to plugin cache %s: error number %d" % ( - self.syscache.path, errno.EPERM) - for event in events: - if expected in textFromEventDict(event): - break - else: - self.fail( - "Did not observe unwriteable cache warning in log " - "events: %r" % (events,)) - - - -class AdjacentPackageTests(unittest.TestCase): - """ - Tests for the behavior of the plugin system when there are multiple - installed copies of the package containing the plugins being loaded. - """ - - def setUp(self): - """ - Save the elements of C{sys.path} and the items of C{sys.modules}. - """ - self.originalPath = sys.path[:] - self.savedModules = sys.modules.copy() - - - def tearDown(self): - """ - Restore C{sys.path} and C{sys.modules} to their original values. - """ - sys.path[:] = self.originalPath - sys.modules.clear() - sys.modules.update(self.savedModules) - - - def createDummyPackage(self, root, name, pluginName): - """ - Create a directory containing a Python package named I{dummy} with a - I{plugins} subpackage. - - @type root: L{FilePath} - @param root: The directory in which to create the hierarchy. - - @type name: C{str} - @param name: The name of the directory to create which will contain - the package. - - @type pluginName: C{str} - @param pluginName: The name of a module to create in the - I{dummy.plugins} package. - - @rtype: L{FilePath} - @return: The directory which was created to contain the I{dummy} - package. - """ - directory = root.child(name) - package = directory.child('dummy') - package.makedirs() - package.child('__init__.py').setContent('') - plugins = package.child('plugins') - plugins.makedirs() - plugins.child('__init__.py').setContent(pluginInitFile) - pluginModule = plugins.child(pluginName + '.py') - pluginModule.setContent(pluginFileContents(name)) - return directory - - - def test_hiddenPackageSamePluginModuleNameObscured(self): - """ - Only plugins from the first package in sys.path should be returned by - getPlugins in the case where there are two Python packages by the same - name installed, each with a plugin module by a single name. - """ - root = FilePath(self.mktemp()) - root.makedirs() - - firstDirectory = self.createDummyPackage(root, 'first', 'someplugin') - secondDirectory = self.createDummyPackage(root, 'second', 'someplugin') - - sys.path.append(firstDirectory.path) - sys.path.append(secondDirectory.path) - - import dummy.plugins - - plugins = list(plugin.getPlugins(ITestPlugin, dummy.plugins)) - self.assertEqual(['first'], [p.__name__ for p in plugins]) - - - def test_hiddenPackageDifferentPluginModuleNameObscured(self): - """ - Plugins from the first package in sys.path should be returned by - getPlugins in the case where there are two Python packages by the same - name installed, each with a plugin module by a different name. - """ - root = FilePath(self.mktemp()) - root.makedirs() - - firstDirectory = self.createDummyPackage(root, 'first', 'thisplugin') - secondDirectory = self.createDummyPackage(root, 'second', 'thatplugin') - - sys.path.append(firstDirectory.path) - sys.path.append(secondDirectory.path) - - import dummy.plugins - - plugins = list(plugin.getPlugins(ITestPlugin, dummy.plugins)) - self.assertEqual(['first'], [p.__name__ for p in plugins]) - - - -class PackagePathTests(unittest.TestCase): - """ - Tests for L{plugin.pluginPackagePaths} which constructs search paths for - plugin packages. - """ - - def setUp(self): - """ - Save the elements of C{sys.path}. - """ - self.originalPath = sys.path[:] - - - def tearDown(self): - """ - Restore C{sys.path} to its original value. - """ - sys.path[:] = self.originalPath - - - def test_pluginDirectories(self): - """ - L{plugin.pluginPackagePaths} should return a list containing each - directory in C{sys.path} with a suffix based on the supplied package - name. - """ - foo = FilePath('foo') - bar = FilePath('bar') - sys.path = [foo.path, bar.path] - self.assertEqual( - plugin.pluginPackagePaths('dummy.plugins'), - [foo.child('dummy').child('plugins').path, - bar.child('dummy').child('plugins').path]) - - - def test_pluginPackagesExcluded(self): - """ - L{plugin.pluginPackagePaths} should exclude directories which are - Python packages. The only allowed plugin package (the only one - associated with a I{dummy} package which Python will allow to be - imported) will already be known to the caller of - L{plugin.pluginPackagePaths} and will most commonly already be in - the C{__path__} they are about to mutate. - """ - root = FilePath(self.mktemp()) - foo = root.child('foo').child('dummy').child('plugins') - foo.makedirs() - foo.child('__init__.py').setContent('') - sys.path = [root.child('foo').path, root.child('bar').path] - self.assertEqual( - plugin.pluginPackagePaths('dummy.plugins'), - [root.child('bar').child('dummy').child('plugins').path]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_policies.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_policies.py deleted file mode 100644 index 47bc406..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_policies.py +++ /dev/null @@ -1,872 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test code for policies. -""" - -from __future__ import division, absolute_import - -from zope.interface import Interface, implementer, implementedBy - -from twisted.python.compat import NativeStringIO -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport -from twisted.test.proto_helpers import StringTransportWithDisconnection - -from twisted.internet import protocol, reactor, address, defer, task -from twisted.protocols import policies - - - -class SimpleProtocol(protocol.Protocol): - - connected = disconnected = 0 - buffer = b"" - - def __init__(self): - self.dConnected = defer.Deferred() - self.dDisconnected = defer.Deferred() - - def connectionMade(self): - self.connected = 1 - self.dConnected.callback('') - - def connectionLost(self, reason): - self.disconnected = 1 - self.dDisconnected.callback('') - - def dataReceived(self, data): - self.buffer += data - - - -class SillyFactory(protocol.ClientFactory): - - def __init__(self, p): - self.p = p - - def buildProtocol(self, addr): - return self.p - - -class EchoProtocol(protocol.Protocol): - paused = False - - def pauseProducing(self): - self.paused = True - - def resumeProducing(self): - self.paused = False - - def stopProducing(self): - pass - - def dataReceived(self, data): - self.transport.write(data) - - - -class Server(protocol.ServerFactory): - """ - A simple server factory using L{EchoProtocol}. - """ - protocol = EchoProtocol - - - -class TestableThrottlingFactory(policies.ThrottlingFactory): - """ - L{policies.ThrottlingFactory} using a L{task.Clock} for tests. - """ - - def __init__(self, clock, *args, **kwargs): - """ - @param clock: object providing a callLater method that can be used - for tests. - @type clock: C{task.Clock} or alike. - """ - policies.ThrottlingFactory.__init__(self, *args, **kwargs) - self.clock = clock - - - def callLater(self, period, func): - """ - Forward to the testable clock. - """ - return self.clock.callLater(period, func) - - - -class TestableTimeoutFactory(policies.TimeoutFactory): - """ - L{policies.TimeoutFactory} using a L{task.Clock} for tests. - """ - - def __init__(self, clock, *args, **kwargs): - """ - @param clock: object providing a callLater method that can be used - for tests. - @type clock: C{task.Clock} or alike. - """ - policies.TimeoutFactory.__init__(self, *args, **kwargs) - self.clock = clock - - - def callLater(self, period, func): - """ - Forward to the testable clock. - """ - return self.clock.callLater(period, func) - - - -class WrapperTests(unittest.TestCase): - """ - Tests for L{WrappingFactory} and L{ProtocolWrapper}. - """ - def test_protocolFactoryAttribute(self): - """ - Make sure protocol.factory is the wrapped factory, not the wrapping - factory. - """ - f = Server() - wf = policies.WrappingFactory(f) - p = wf.buildProtocol(address.IPv4Address('TCP', '127.0.0.1', 35)) - self.assertIdentical(p.wrappedProtocol.factory, f) - - - def test_transportInterfaces(self): - """ - The transport wrapper passed to the wrapped protocol's - C{makeConnection} provides the same interfaces as are provided by the - original transport. - """ - class IStubTransport(Interface): - pass - - @implementer(IStubTransport) - class StubTransport: - pass - - # Looking up what ProtocolWrapper implements also mutates the class. - # It adds __implemented__ and __providedBy__ attributes to it. These - # prevent __getattr__ from causing the IStubTransport.providedBy call - # below from returning True. If, by accident, nothing else causes - # these attributes to be added to ProtocolWrapper, the test will pass, - # but the interface will only be provided until something does trigger - # their addition. So we just trigger it right now to be sure. - implementedBy(policies.ProtocolWrapper) - - proto = protocol.Protocol() - wrapper = policies.ProtocolWrapper(policies.WrappingFactory(None), proto) - - wrapper.makeConnection(StubTransport()) - self.assertTrue(IStubTransport.providedBy(proto.transport)) - - - def test_factoryLogPrefix(self): - """ - L{WrappingFactory.logPrefix} is customized to mention both the original - factory and the wrapping factory. - """ - server = Server() - factory = policies.WrappingFactory(server) - self.assertEqual("Server (WrappingFactory)", factory.logPrefix()) - - - def test_factoryLogPrefixFallback(self): - """ - If the wrapped factory doesn't have a L{logPrefix} method, - L{WrappingFactory.logPrefix} falls back to the factory class name. - """ - class NoFactory(object): - pass - - server = NoFactory() - factory = policies.WrappingFactory(server) - self.assertEqual("NoFactory (WrappingFactory)", factory.logPrefix()) - - - def test_protocolLogPrefix(self): - """ - L{ProtocolWrapper.logPrefix} is customized to mention both the original - protocol and the wrapper. - """ - server = Server() - factory = policies.WrappingFactory(server) - protocol = factory.buildProtocol( - address.IPv4Address('TCP', '127.0.0.1', 35)) - self.assertEqual("EchoProtocol (ProtocolWrapper)", - protocol.logPrefix()) - - - def test_protocolLogPrefixFallback(self): - """ - If the wrapped protocol doesn't have a L{logPrefix} method, - L{ProtocolWrapper.logPrefix} falls back to the protocol class name. - """ - class NoProtocol(object): - pass - - server = Server() - server.protocol = NoProtocol - factory = policies.WrappingFactory(server) - protocol = factory.buildProtocol( - address.IPv4Address('TCP', '127.0.0.1', 35)) - self.assertEqual("NoProtocol (ProtocolWrapper)", - protocol.logPrefix()) - - - def _getWrapper(self): - """ - Return L{policies.ProtocolWrapper} that has been connected to a - L{StringTransport}. - """ - wrapper = policies.ProtocolWrapper(policies.WrappingFactory(Server()), - protocol.Protocol()) - transport = StringTransport() - wrapper.makeConnection(transport) - return wrapper - - - def test_getHost(self): - """ - L{policies.ProtocolWrapper.getHost} calls C{getHost} on the underlying - transport. - """ - wrapper = self._getWrapper() - self.assertEqual(wrapper.getHost(), wrapper.transport.getHost()) - - - def test_getPeer(self): - """ - L{policies.ProtocolWrapper.getPeer} calls C{getPeer} on the underlying - transport. - """ - wrapper = self._getWrapper() - self.assertEqual(wrapper.getPeer(), wrapper.transport.getPeer()) - - - def test_registerProducer(self): - """ - L{policies.ProtocolWrapper.registerProducer} calls C{registerProducer} - on the underlying transport. - """ - wrapper = self._getWrapper() - producer = object() - wrapper.registerProducer(producer, True) - self.assertIdentical(wrapper.transport.producer, producer) - self.assertTrue(wrapper.transport.streaming) - - - def test_unregisterProducer(self): - """ - L{policies.ProtocolWrapper.unregisterProducer} calls - C{unregisterProducer} on the underlying transport. - """ - wrapper = self._getWrapper() - producer = object() - wrapper.registerProducer(producer, True) - wrapper.unregisterProducer() - self.assertIdentical(wrapper.transport.producer, None) - self.assertIdentical(wrapper.transport.streaming, None) - - - def test_stopConsuming(self): - """ - L{policies.ProtocolWrapper.stopConsuming} calls C{stopConsuming} on - the underlying transport. - """ - wrapper = self._getWrapper() - result = [] - wrapper.transport.stopConsuming = lambda: result.append(True) - wrapper.stopConsuming() - self.assertEqual(result, [True]) - - - def test_startedConnecting(self): - """ - L{policies.WrappingFactory.startedConnecting} calls - C{startedConnecting} on the underlying factory. - """ - result = [] - class Factory(object): - def startedConnecting(self, connector): - result.append(connector) - - wrapper = policies.WrappingFactory(Factory()) - connector = object() - wrapper.startedConnecting(connector) - self.assertEqual(result, [connector]) - - - def test_clientConnectionLost(self): - """ - L{policies.WrappingFactory.clientConnectionLost} calls - C{clientConnectionLost} on the underlying factory. - """ - result = [] - class Factory(object): - def clientConnectionLost(self, connector, reason): - result.append((connector, reason)) - - wrapper = policies.WrappingFactory(Factory()) - connector = object() - reason = object() - wrapper.clientConnectionLost(connector, reason) - self.assertEqual(result, [(connector, reason)]) - - - def test_clientConnectionFailed(self): - """ - L{policies.WrappingFactory.clientConnectionFailed} calls - C{clientConnectionFailed} on the underlying factory. - """ - result = [] - class Factory(object): - def clientConnectionFailed(self, connector, reason): - result.append((connector, reason)) - - wrapper = policies.WrappingFactory(Factory()) - connector = object() - reason = object() - wrapper.clientConnectionFailed(connector, reason) - self.assertEqual(result, [(connector, reason)]) - - - -class WrappingFactory(policies.WrappingFactory): - protocol = lambda s, f, p: p - - def startFactory(self): - policies.WrappingFactory.startFactory(self) - self.deferred.callback(None) - - - -class ThrottlingTests(unittest.TestCase): - """ - Tests for L{policies.ThrottlingFactory}. - """ - - def test_limit(self): - """ - Full test using a custom server limiting number of connections. - """ - server = Server() - c1, c2, c3, c4 = [SimpleProtocol() for i in range(4)] - tServer = policies.ThrottlingFactory(server, 2) - wrapTServer = WrappingFactory(tServer) - wrapTServer.deferred = defer.Deferred() - - # Start listening - p = reactor.listenTCP(0, wrapTServer, interface="127.0.0.1") - n = p.getHost().port - - def _connect123(results): - reactor.connectTCP("127.0.0.1", n, SillyFactory(c1)) - c1.dConnected.addCallback( - lambda r: reactor.connectTCP("127.0.0.1", n, SillyFactory(c2))) - c2.dConnected.addCallback( - lambda r: reactor.connectTCP("127.0.0.1", n, SillyFactory(c3))) - return c3.dDisconnected - - def _check123(results): - self.assertEqual([c.connected for c in (c1, c2, c3)], [1, 1, 1]) - self.assertEqual([c.disconnected for c in (c1, c2, c3)], [0, 0, 1]) - self.assertEqual(len(tServer.protocols.keys()), 2) - return results - - def _lose1(results): - # disconnect one protocol and now another should be able to connect - c1.transport.loseConnection() - return c1.dDisconnected - - def _connect4(results): - reactor.connectTCP("127.0.0.1", n, SillyFactory(c4)) - return c4.dConnected - - def _check4(results): - self.assertEqual(c4.connected, 1) - self.assertEqual(c4.disconnected, 0) - return results - - def _cleanup(results): - for c in c2, c4: - c.transport.loseConnection() - return defer.DeferredList([ - defer.maybeDeferred(p.stopListening), - c2.dDisconnected, - c4.dDisconnected]) - - wrapTServer.deferred.addCallback(_connect123) - wrapTServer.deferred.addCallback(_check123) - wrapTServer.deferred.addCallback(_lose1) - wrapTServer.deferred.addCallback(_connect4) - wrapTServer.deferred.addCallback(_check4) - wrapTServer.deferred.addCallback(_cleanup) - return wrapTServer.deferred - - - def test_writeSequence(self): - """ - L{ThrottlingProtocol.writeSequence} is called on the underlying factory. - """ - server = Server() - tServer = TestableThrottlingFactory(task.Clock(), server) - protocol = tServer.buildProtocol( - address.IPv4Address('TCP', '127.0.0.1', 0)) - transport = StringTransportWithDisconnection() - transport.protocol = protocol - protocol.makeConnection(transport) - - protocol.writeSequence([b'bytes'] * 4) - self.assertEqual(transport.value(), b"bytesbytesbytesbytes") - self.assertEqual(tServer.writtenThisSecond, 20) - - - def test_writeLimit(self): - """ - Check the writeLimit parameter: write data, and check for the pause - status. - """ - server = Server() - tServer = TestableThrottlingFactory(task.Clock(), server, writeLimit=10) - port = tServer.buildProtocol(address.IPv4Address('TCP', '127.0.0.1', 0)) - tr = StringTransportWithDisconnection() - tr.protocol = port - port.makeConnection(tr) - port.producer = port.wrappedProtocol - - port.dataReceived(b"0123456789") - port.dataReceived(b"abcdefghij") - self.assertEqual(tr.value(), b"0123456789abcdefghij") - self.assertEqual(tServer.writtenThisSecond, 20) - self.assertFalse(port.wrappedProtocol.paused) - - # at this point server should've written 20 bytes, 10 bytes - # above the limit so writing should be paused around 1 second - # from 'now', and resumed a second after that - tServer.clock.advance(1.05) - self.assertEqual(tServer.writtenThisSecond, 0) - self.assertTrue(port.wrappedProtocol.paused) - - tServer.clock.advance(1.05) - self.assertEqual(tServer.writtenThisSecond, 0) - self.assertFalse(port.wrappedProtocol.paused) - - - def test_readLimit(self): - """ - Check the readLimit parameter: read data and check for the pause - status. - """ - server = Server() - tServer = TestableThrottlingFactory(task.Clock(), server, readLimit=10) - port = tServer.buildProtocol(address.IPv4Address('TCP', '127.0.0.1', 0)) - tr = StringTransportWithDisconnection() - tr.protocol = port - port.makeConnection(tr) - - port.dataReceived(b"0123456789") - port.dataReceived(b"abcdefghij") - self.assertEqual(tr.value(), b"0123456789abcdefghij") - self.assertEqual(tServer.readThisSecond, 20) - - tServer.clock.advance(1.05) - self.assertEqual(tServer.readThisSecond, 0) - self.assertEqual(tr.producerState, 'paused') - - tServer.clock.advance(1.05) - self.assertEqual(tServer.readThisSecond, 0) - self.assertEqual(tr.producerState, 'producing') - - tr.clear() - port.dataReceived(b"0123456789") - port.dataReceived(b"abcdefghij") - self.assertEqual(tr.value(), b"0123456789abcdefghij") - self.assertEqual(tServer.readThisSecond, 20) - - tServer.clock.advance(1.05) - self.assertEqual(tServer.readThisSecond, 0) - self.assertEqual(tr.producerState, 'paused') - - tServer.clock.advance(1.05) - self.assertEqual(tServer.readThisSecond, 0) - self.assertEqual(tr.producerState, 'producing') - - - -class TimeoutFactoryTests(unittest.TestCase): - """ - Tests for L{policies.TimeoutFactory}. - """ - - def setUp(self): - """ - Create a testable, deterministic clock, and a set of - server factory/protocol/transport. - """ - self.clock = task.Clock() - wrappedFactory = protocol.ServerFactory() - wrappedFactory.protocol = SimpleProtocol - self.factory = TestableTimeoutFactory(self.clock, wrappedFactory, 3) - self.proto = self.factory.buildProtocol( - address.IPv4Address('TCP', '127.0.0.1', 12345)) - self.transport = StringTransportWithDisconnection() - self.transport.protocol = self.proto - self.proto.makeConnection(self.transport) - - - def test_timeout(self): - """ - Make sure that when a TimeoutFactory accepts a connection, it will - time out that connection if no data is read or written within the - timeout period. - """ - # Let almost 3 time units pass - self.clock.pump([0.0, 0.5, 1.0, 1.0, 0.4]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Now let the timer elapse - self.clock.pump([0.0, 0.2]) - self.failUnless(self.proto.wrappedProtocol.disconnected) - - - def test_sendAvoidsTimeout(self): - """ - Make sure that writing data to a transport from a protocol - constructed by a TimeoutFactory resets the timeout countdown. - """ - # Let half the countdown period elapse - self.clock.pump([0.0, 0.5, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Send some data (self.proto is the /real/ proto's transport, so this - # is the write that gets called) - self.proto.write(b'bytes bytes bytes') - - # More time passes, putting us past the original timeout - self.clock.pump([0.0, 1.0, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Make sure writeSequence delays timeout as well - self.proto.writeSequence([b'bytes'] * 3) - - # Tick tock - self.clock.pump([0.0, 1.0, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Don't write anything more, just let the timeout expire - self.clock.pump([0.0, 2.0]) - self.failUnless(self.proto.wrappedProtocol.disconnected) - - - def test_receiveAvoidsTimeout(self): - """ - Make sure that receiving data also resets the timeout countdown. - """ - # Let half the countdown period elapse - self.clock.pump([0.0, 1.0, 0.5]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Some bytes arrive, they should reset the counter - self.proto.dataReceived(b'bytes bytes bytes') - - # We pass the original timeout - self.clock.pump([0.0, 1.0, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Nothing more arrives though, the new timeout deadline is passed, - # the connection should be dropped. - self.clock.pump([0.0, 1.0, 1.0]) - self.failUnless(self.proto.wrappedProtocol.disconnected) - - - -class TimeoutTester(protocol.Protocol, policies.TimeoutMixin): - """ - A testable protocol with timeout facility. - - @ivar timedOut: set to C{True} if a timeout has been detected. - @type timedOut: C{bool} - """ - timeOut = 3 - timedOut = False - - def __init__(self, clock): - """ - Initialize the protocol with a C{task.Clock} object. - """ - self.clock = clock - - - def connectionMade(self): - """ - Upon connection, set the timeout. - """ - self.setTimeout(self.timeOut) - - - def dataReceived(self, data): - """ - Reset the timeout on data. - """ - self.resetTimeout() - protocol.Protocol.dataReceived(self, data) - - - def connectionLost(self, reason=None): - """ - On connection lost, cancel all timeout operations. - """ - self.setTimeout(None) - - - def timeoutConnection(self): - """ - Flags the timedOut variable to indicate the timeout of the connection. - """ - self.timedOut = True - - - def callLater(self, timeout, func, *args, **kwargs): - """ - Override callLater to use the deterministic clock. - """ - return self.clock.callLater(timeout, func, *args, **kwargs) - - - -class TimeoutMixinTests(unittest.TestCase): - """ - Tests for L{policies.TimeoutMixin}. - """ - - def setUp(self): - """ - Create a testable, deterministic clock and a C{TimeoutTester} instance. - """ - self.clock = task.Clock() - self.proto = TimeoutTester(self.clock) - - - def test_overriddenCallLater(self): - """ - Test that the callLater of the clock is used instead of - C{reactor.callLater}. - """ - self.proto.setTimeout(10) - self.assertEqual(len(self.clock.calls), 1) - - - def test_timeout(self): - """ - Check that the protocol does timeout at the time specified by its - C{timeOut} attribute. - """ - self.proto.makeConnection(StringTransport()) - - # timeOut value is 3 - self.clock.pump([0, 0.5, 1.0, 1.0]) - self.failIf(self.proto.timedOut) - self.clock.pump([0, 1.0]) - self.failUnless(self.proto.timedOut) - - - def test_noTimeout(self): - """ - Check that receiving data is delaying the timeout of the connection. - """ - self.proto.makeConnection(StringTransport()) - - self.clock.pump([0, 0.5, 1.0, 1.0]) - self.failIf(self.proto.timedOut) - self.proto.dataReceived(b'hello there') - self.clock.pump([0, 1.0, 1.0, 0.5]) - self.failIf(self.proto.timedOut) - self.clock.pump([0, 1.0]) - self.failUnless(self.proto.timedOut) - - - def test_resetTimeout(self): - """ - Check that setting a new value for timeout cancel the previous value - and install a new timeout. - """ - self.proto.timeOut = None - self.proto.makeConnection(StringTransport()) - - self.proto.setTimeout(1) - self.assertEqual(self.proto.timeOut, 1) - - self.clock.pump([0, 0.9]) - self.failIf(self.proto.timedOut) - self.clock.pump([0, 0.2]) - self.failUnless(self.proto.timedOut) - - - def test_cancelTimeout(self): - """ - Setting the timeout to C{None} cancel any timeout operations. - """ - self.proto.timeOut = 5 - self.proto.makeConnection(StringTransport()) - - self.proto.setTimeout(None) - self.assertEqual(self.proto.timeOut, None) - - self.clock.pump([0, 5, 5, 5]) - self.failIf(self.proto.timedOut) - - - def test_return(self): - """ - setTimeout should return the value of the previous timeout. - """ - self.proto.timeOut = 5 - - self.assertEqual(self.proto.setTimeout(10), 5) - self.assertEqual(self.proto.setTimeout(None), 10) - self.assertEqual(self.proto.setTimeout(1), None) - self.assertEqual(self.proto.timeOut, 1) - - # Clean up the DelayedCall - self.proto.setTimeout(None) - - - -class LimitTotalConnectionsFactoryTests(unittest.TestCase): - """Tests for policies.LimitTotalConnectionsFactory""" - def testConnectionCounting(self): - # Make a basic factory - factory = policies.LimitTotalConnectionsFactory() - factory.protocol = protocol.Protocol - - # connectionCount starts at zero - self.assertEqual(0, factory.connectionCount) - - # connectionCount increments as connections are made - p1 = factory.buildProtocol(None) - self.assertEqual(1, factory.connectionCount) - p2 = factory.buildProtocol(None) - self.assertEqual(2, factory.connectionCount) - - # and decrements as they are lost - p1.connectionLost(None) - self.assertEqual(1, factory.connectionCount) - p2.connectionLost(None) - self.assertEqual(0, factory.connectionCount) - - def testConnectionLimiting(self): - # Make a basic factory with a connection limit of 1 - factory = policies.LimitTotalConnectionsFactory() - factory.protocol = protocol.Protocol - factory.connectionLimit = 1 - - # Make a connection - p = factory.buildProtocol(None) - self.assertNotEqual(None, p) - self.assertEqual(1, factory.connectionCount) - - # Try to make a second connection, which will exceed the connection - # limit. This should return None, because overflowProtocol is None. - self.assertEqual(None, factory.buildProtocol(None)) - self.assertEqual(1, factory.connectionCount) - - # Define an overflow protocol - class OverflowProtocol(protocol.Protocol): - def connectionMade(self): - factory.overflowed = True - factory.overflowProtocol = OverflowProtocol - factory.overflowed = False - - # Try to make a second connection again, now that we have an overflow - # protocol. Note that overflow connections count towards the connection - # count. - op = factory.buildProtocol(None) - op.makeConnection(None) # to trigger connectionMade - self.assertEqual(True, factory.overflowed) - self.assertEqual(2, factory.connectionCount) - - # Close the connections. - p.connectionLost(None) - self.assertEqual(1, factory.connectionCount) - op.connectionLost(None) - self.assertEqual(0, factory.connectionCount) - - -class WriteSequenceEchoProtocol(EchoProtocol): - def dataReceived(self, bytes): - if bytes.find(b'vector!') != -1: - self.transport.writeSequence([bytes]) - else: - EchoProtocol.dataReceived(self, bytes) - -class TestLoggingFactory(policies.TrafficLoggingFactory): - openFile = None - def open(self, name): - assert self.openFile is None, "open() called too many times" - self.openFile = NativeStringIO() - return self.openFile - - - -class LoggingFactoryTests(unittest.TestCase): - """ - Tests for L{policies.TrafficLoggingFactory}. - """ - - def test_thingsGetLogged(self): - """ - Check the output produced by L{policies.TrafficLoggingFactory}. - """ - wrappedFactory = Server() - wrappedFactory.protocol = WriteSequenceEchoProtocol - t = StringTransportWithDisconnection() - f = TestLoggingFactory(wrappedFactory, 'test') - p = f.buildProtocol(('1.2.3.4', 5678)) - t.protocol = p - p.makeConnection(t) - - v = f.openFile.getvalue() - self.assertIn('*', v) - self.failIf(t.value()) - - p.dataReceived(b'here are some bytes') - - v = f.openFile.getvalue() - self.assertIn("C 1: %r" % (b'here are some bytes',), v) - self.assertIn("S 1: %r" % (b'here are some bytes',), v) - self.assertEqual(t.value(), b'here are some bytes') - - t.clear() - p.dataReceived(b'prepare for vector! to the extreme') - v = f.openFile.getvalue() - self.assertIn("SV 1: %r" % ([b'prepare for vector! to the extreme'],), v) - self.assertEqual(t.value(), b'prepare for vector! to the extreme') - - p.loseConnection() - - v = f.openFile.getvalue() - self.assertIn('ConnectionDone', v) - - - def test_counter(self): - """ - Test counter management with the resetCounter method. - """ - wrappedFactory = Server() - f = TestLoggingFactory(wrappedFactory, 'test') - self.assertEqual(f._counter, 0) - f.buildProtocol(('1.2.3.4', 5678)) - self.assertEqual(f._counter, 1) - # Reset log file - f.openFile = None - f.buildProtocol(('1.2.3.4', 5679)) - self.assertEqual(f._counter, 2) - - f.resetCounter() - self.assertEqual(f._counter, 0) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_postfix.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_postfix.py deleted file mode 100644 index d121e44..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_postfix.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.protocols.postfix module. -""" - -from twisted.trial import unittest -from twisted.protocols import postfix -from twisted.test.proto_helpers import StringTransport - - -class PostfixTCPMapQuoteTests(unittest.TestCase): - data = [ - # (raw, quoted, [aliasQuotedForms]), - ('foo', 'foo'), - ('foo bar', 'foo%20bar'), - ('foo\tbar', 'foo%09bar'), - ('foo\nbar', 'foo%0Abar', 'foo%0abar'), - ('foo\r\nbar', 'foo%0D%0Abar', 'foo%0D%0abar', 'foo%0d%0Abar', 'foo%0d%0abar'), - ('foo ', 'foo%20'), - (' foo', '%20foo'), - ] - - def testData(self): - for entry in self.data: - raw = entry[0] - quoted = entry[1:] - - self.assertEqual(postfix.quote(raw), quoted[0]) - for q in quoted: - self.assertEqual(postfix.unquote(q), raw) - -class PostfixTCPMapServerTestCase: - data = { - # 'key': 'value', - } - - chat = [ - # (input, expected_output), - ] - - def test_chat(self): - """ - Test that I{get} and I{put} commands are responded to correctly by - L{postfix.PostfixTCPMapServer} when its factory is an instance of - L{postifx.PostfixTCPMapDictServerFactory}. - """ - factory = postfix.PostfixTCPMapDictServerFactory(self.data) - transport = StringTransport() - - protocol = postfix.PostfixTCPMapServer() - protocol.service = factory - protocol.factory = factory - protocol.makeConnection(transport) - - for input, expected_output in self.chat: - protocol.lineReceived(input) - self.assertEqual( - transport.value(), expected_output, - 'For %r, expected %r but got %r' % ( - input, expected_output, transport.value())) - transport.clear() - protocol.setTimeout(None) - - - def test_deferredChat(self): - """ - Test that I{get} and I{put} commands are responded to correctly by - L{postfix.PostfixTCPMapServer} when its factory is an instance of - L{postifx.PostfixTCPMapDeferringDictServerFactory}. - """ - factory = postfix.PostfixTCPMapDeferringDictServerFactory(self.data) - transport = StringTransport() - - protocol = postfix.PostfixTCPMapServer() - protocol.service = factory - protocol.factory = factory - protocol.makeConnection(transport) - - for input, expected_output in self.chat: - protocol.lineReceived(input) - self.assertEqual( - transport.value(), expected_output, - 'For %r, expected %r but got %r' % ( - input, expected_output, transport.value())) - transport.clear() - protocol.setTimeout(None) - - - -class ValidTests(PostfixTCPMapServerTestCase, unittest.TestCase): - data = { - 'foo': 'ThisIs Foo', - 'bar': ' bar really is found\r\n', - } - chat = [ - ('get', "400 Command 'get' takes 1 parameters.\n"), - ('get foo bar', "500 \n"), - ('put', "400 Command 'put' takes 2 parameters.\n"), - ('put foo', "400 Command 'put' takes 2 parameters.\n"), - ('put foo bar baz', "500 put is not implemented yet.\n"), - ('put foo bar', '500 put is not implemented yet.\n'), - ('get foo', '200 ThisIs%20Foo\n'), - ('get bar', '200 %20bar%20really%20is%20found%0D%0A\n'), - ('get baz', '500 \n'), - ('foo', '400 unknown command\n'), - ] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_process.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_process.py deleted file mode 100644 index 591dd30..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_process.py +++ /dev/null @@ -1,2613 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test running processes. - -@var CONCURRENT_PROCESS_TEST_COUNT: The number of concurrent processes to use - to stress-test the spawnProcess API. This value is tuned to a number of - processes which has been determined to stay below various - experimentally-determined limitations of our supported platforms. - Particularly, Windows XP seems to have some undocumented limitations which - cause spurious failures if this value is pushed too high. U{Please see - this ticket for a discussion of how we arrived at its current value. - } -""" - -from __future__ import division, absolute_import - -import gzip -import os -import sys -import signal -import errno -import gc -import stat -import operator - - -try: - import fcntl -except ImportError: - fcntl = process = None -else: - from twisted.internet import process - -from zope.interface.verify import verifyObject - -from io import BytesIO - -from twisted.python.log import msg -from twisted.internet import reactor, protocol, error, interfaces, defer -from twisted.trial import unittest -from twisted.python import util, runtime, procutils -from twisted.python.compat import _PY3, networkString, xrange -from twisted.python.filepath import FilePath, _asFilesystemBytes - - -# Get the current Python executable as a bytestring. -pyExe = FilePath(sys.executable)._asBytesPath() -CONCURRENT_PROCESS_TEST_COUNT = 25 - - -class StubProcessProtocol(protocol.ProcessProtocol): - """ - ProcessProtocol counter-implementation: all methods on this class raise an - exception, so instances of this may be used to verify that only certain - methods are called. - """ - def outReceived(self, data): - raise NotImplementedError() - - def errReceived(self, data): - raise NotImplementedError() - - def inConnectionLost(self): - raise NotImplementedError() - - def outConnectionLost(self): - raise NotImplementedError() - - def errConnectionLost(self): - raise NotImplementedError() - - - -class ProcessProtocolTests(unittest.TestCase): - """ - Tests for behavior provided by the process protocol base class, - L{protocol.ProcessProtocol}. - """ - def test_interface(self): - """ - L{ProcessProtocol} implements L{IProcessProtocol}. - """ - verifyObject(interfaces.IProcessProtocol, protocol.ProcessProtocol()) - - - def test_outReceived(self): - """ - Verify that when stdout is delivered to - L{ProcessProtocol.childDataReceived}, it is forwarded to - L{ProcessProtocol.outReceived}. - """ - received = [] - class OutProtocol(StubProcessProtocol): - def outReceived(self, data): - received.append(data) - - bytesToSend = b"bytes" - p = OutProtocol() - p.childDataReceived(1, bytesToSend) - self.assertEqual(received, [bytesToSend]) - - - def test_errReceived(self): - """ - Similar to L{test_outReceived}, but for stderr. - """ - received = [] - class ErrProtocol(StubProcessProtocol): - def errReceived(self, data): - received.append(data) - - bytesToSend = b"bytes" - p = ErrProtocol() - p.childDataReceived(2, bytesToSend) - self.assertEqual(received, [bytesToSend]) - - - def test_inConnectionLost(self): - """ - Verify that when stdin close notification is delivered to - L{ProcessProtocol.childConnectionLost}, it is forwarded to - L{ProcessProtocol.inConnectionLost}. - """ - lost = [] - class InLostProtocol(StubProcessProtocol): - def inConnectionLost(self): - lost.append(None) - - p = InLostProtocol() - p.childConnectionLost(0) - self.assertEqual(lost, [None]) - - - def test_outConnectionLost(self): - """ - Similar to L{test_inConnectionLost}, but for stdout. - """ - lost = [] - class OutLostProtocol(StubProcessProtocol): - def outConnectionLost(self): - lost.append(None) - - p = OutLostProtocol() - p.childConnectionLost(1) - self.assertEqual(lost, [None]) - - - def test_errConnectionLost(self): - """ - Similar to L{test_inConnectionLost}, but for stderr. - """ - lost = [] - class ErrLostProtocol(StubProcessProtocol): - def errConnectionLost(self): - lost.append(None) - - p = ErrLostProtocol() - p.childConnectionLost(2) - self.assertEqual(lost, [None]) - - - -class TrivialProcessProtocol(protocol.ProcessProtocol): - """ - Simple process protocol for tests purpose. - - @ivar outData: data received from stdin - @ivar errData: data received from stderr - """ - - def __init__(self, d): - """ - Create the deferred that will be fired at the end, and initialize - data structures. - """ - self.deferred = d - self.outData = [] - self.errData = [] - - def processEnded(self, reason): - self.reason = reason - self.deferred.callback(None) - - def outReceived(self, data): - self.outData.append(data) - - def errReceived(self, data): - self.errData.append(data) - - -class TestProcessProtocol(protocol.ProcessProtocol): - - def connectionMade(self): - self.stages = [1] - self.data = b'' - self.err = b'' - self.transport.write(b"abcd") - - def childDataReceived(self, childFD, data): - """ - Override and disable the dispatch provided by the base class to ensure - that it is really this method which is being called, and the transport - is not going directly to L{outReceived} or L{errReceived}. - """ - if childFD == 1: - self.data += data - elif childFD == 2: - self.err += data - - - def childConnectionLost(self, childFD): - """ - Similarly to L{childDataReceived}, disable the automatic dispatch - provided by the base implementation to verify that the transport is - calling this method directly. - """ - if childFD == 1: - self.stages.append(2) - if self.data != b"abcd": - raise RuntimeError( - "Data was %r instead of 'abcd'" % (self.data,)) - self.transport.write(b"1234") - elif childFD == 2: - self.stages.append(3) - if self.err != b"1234": - raise RuntimeError( - "Err was %r instead of '1234'" % (self.err,)) - self.transport.write(b"abcd") - self.stages.append(4) - elif childFD == 0: - self.stages.append(5) - - def processEnded(self, reason): - self.reason = reason - self.deferred.callback(None) - - -class EchoProtocol(protocol.ProcessProtocol): - - s = b"1234567" * 1001 - n = 10 - finished = 0 - - failure = None - - def __init__(self, onEnded): - self.onEnded = onEnded - self.count = 0 - - def connectionMade(self): - assert self.n > 2 - for i in range(self.n - 2): - self.transport.write(self.s) - # test writeSequence - self.transport.writeSequence([self.s, self.s]) - self.buffer = self.s * self.n - - def outReceived(self, data): - if self.buffer[self.count:self.count+len(data)] != data: - self.failure = ("wrong bytes received", data, self.count) - self.transport.closeStdin() - else: - self.count += len(data) - if self.count == len(self.buffer): - self.transport.closeStdin() - - def processEnded(self, reason): - self.finished = 1 - if not reason.check(error.ProcessDone): - self.failure = "process didn't terminate normally: " + str(reason) - self.onEnded.callback(self) - - - -class SignalProtocol(protocol.ProcessProtocol): - """ - A process protocol that sends a signal when data is first received. - - @ivar deferred: deferred firing on C{processEnded}. - @type deferred: L{defer.Deferred} - - @ivar signal: the signal to send to the process. - @type signal: C{str} - - @ivar signaled: A flag tracking whether the signal has been sent to the - child or not yet. C{False} until it is sent, then C{True}. - @type signaled: C{bool} - """ - - def __init__(self, deferred, sig): - self.deferred = deferred - self.signal = sig - self.signaled = False - - - def outReceived(self, data): - """ - Handle the first output from the child process (which indicates it - is set up and ready to receive the signal) by sending the signal to - it. Also log all output to help with debugging. - """ - msg("Received %r from child stdout" % (data,)) - if not self.signaled: - self.signaled = True - self.transport.signalProcess(self.signal) - - - def errReceived(self, data): - """ - Log all data received from the child's stderr to help with - debugging. - """ - msg("Received %r from child stderr" % (data,)) - - - def processEnded(self, reason): - """ - Callback C{self.deferred} with C{None} if C{reason} is a - L{error.ProcessTerminated} failure with C{exitCode} set to C{None}, - C{signal} set to C{self.signal}, and C{status} holding the status code - of the exited process. Otherwise, errback with a C{ValueError} - describing the problem. - """ - msg("Child exited: %r" % (reason.getTraceback(),)) - if not reason.check(error.ProcessTerminated): - return self.deferred.errback( - ValueError("wrong termination: %s" % (reason,))) - v = reason.value - if isinstance(self.signal, str): - signalValue = getattr(signal, 'SIG' + self.signal) - else: - signalValue = self.signal - if v.exitCode is not None: - return self.deferred.errback( - ValueError("SIG%s: exitCode is %s, not None" % - (self.signal, v.exitCode))) - if v.signal != signalValue: - return self.deferred.errback( - ValueError("SIG%s: .signal was %s, wanted %s" % - (self.signal, v.signal, signalValue))) - if os.WTERMSIG(v.status) != signalValue: - return self.deferred.errback( - ValueError('SIG%s: %s' % (self.signal, os.WTERMSIG(v.status)))) - self.deferred.callback(None) - - - -class TestManyProcessProtocol(TestProcessProtocol): - def __init__(self): - self.deferred = defer.Deferred() - - def processEnded(self, reason): - self.reason = reason - if reason.check(error.ProcessDone): - self.deferred.callback(None) - else: - self.deferred.errback(reason) - - - -class UtilityProcessProtocol(protocol.ProcessProtocol): - """ - Helper class for launching a Python process and getting a result from it. - - @ivar program: A string giving a Python program for the child process to - run. - """ - program = None - - @classmethod - def run(cls, reactor, argv, env): - """ - Run a Python process connected to a new instance of this protocol - class. Return the protocol instance. - - The Python process is given C{self.program} on the command line to - execute, in addition to anything specified by C{argv}. C{env} is - the complete environment. - """ - self = cls() - reactor.spawnProcess( - self, pyExe, [pyExe, b"-c", self.program] + argv, env=env) - return self - - - def __init__(self): - self.bytes = [] - self.requests = [] - - - def parseChunks(self, bytes): - """ - Called with all bytes received on stdout when the process exits. - """ - raise NotImplementedError() - - - def getResult(self): - """ - Return a Deferred which will fire with the result of L{parseChunks} - when the child process exits. - """ - d = defer.Deferred() - self.requests.append(d) - return d - - - def _fireResultDeferreds(self, result): - """ - Callback all Deferreds returned up until now by L{getResult} - with the given result object. - """ - requests = self.requests - self.requests = None - for d in requests: - d.callback(result) - - - def outReceived(self, bytes): - """ - Accumulate output from the child process in a list. - """ - self.bytes.append(bytes) - - - def processEnded(self, reason): - """ - Handle process termination by parsing all received output and firing - any waiting Deferreds. - """ - self._fireResultDeferreds(self.parseChunks(self.bytes)) - - - - -class GetArgumentVector(UtilityProcessProtocol): - """ - Protocol which will read a serialized argv from a process and - expose it to interested parties. - """ - program = networkString( - "from sys import stdout, argv\n" - "stdout.write(chr(0).join(argv))\n" - "stdout.flush()\n") - - def parseChunks(self, chunks): - """ - Parse the output from the process to which this protocol was - connected, which is a single unterminated line of \\0-separated - strings giving the argv of that process. Return this as a list of - str objects. - """ - return b''.join(chunks).split(b'\0') - - - -class GetEnvironmentDictionary(UtilityProcessProtocol): - """ - Protocol which will read a serialized environment dict from a process - and expose it to interested parties. - """ - program = networkString( - "from sys import stdout\n" - "from os import environ\n" - "items = environ.items()\n" - "stdout.write(chr(0).join([k + chr(0) + v for k, v in items]))\n" - "stdout.flush()\n") - - def parseChunks(self, chunks): - """ - Parse the output from the process to which this protocol was - connected, which is a single unterminated line of \\0-separated - strings giving key value pairs of the environment from that process. - Return this as a dictionary. - """ - environString = b''.join(chunks) - if not environString: - return {} - environ = iter(environString.split(b'\0')) - d = {} - while 1: - try: - k = next(environ) - except StopIteration: - break - else: - v = next(environ) - d[k] = v - return d - - - -class ProcessTests(unittest.TestCase): - """Test running a process.""" - - usePTY = False - - def testStdio(self): - """twisted.internet.stdio test.""" - scriptPath = FilePath(__file__).sibling(b"process_twisted.py").path - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - env = {b"PYTHONPATH": _asFilesystemBytes(os.pathsep.join(sys.path))} - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=env, - path=None, usePTY=self.usePTY) - p.transport.write(b"hello, world") - p.transport.write(b"abc") - p.transport.write(b"123") - p.transport.closeStdin() - - def processEnded(ign): - self.assertEqual(p.outF.getvalue(), b"hello, worldabc123", - "Output follows:\n" - "%s\n" - "Error message from process_twisted follows:\n" - "%s\n" % (p.outF.getvalue(), p.errF.getvalue())) - return d.addCallback(processEnded) - - - def test_unsetPid(self): - """ - Test if pid is None/non-None before/after process termination. This - reuses process_echoer.py to get a process that blocks on stdin. - """ - finished = defer.Deferred() - p = TrivialProcessProtocol(finished) - scriptPath = FilePath(__file__).sibling(b"process_echoer.py").path - procTrans = reactor.spawnProcess(p, pyExe, - [pyExe, scriptPath], env=None) - self.failUnless(procTrans.pid) - - def afterProcessEnd(ignored): - self.assertEqual(procTrans.pid, None) - - p.transport.closeStdin() - return finished.addCallback(afterProcessEnd) - - - def test_process(self): - """ - Test running a process: check its output, it exitCode, some property of - signalProcess. - """ - scriptPath = FilePath(__file__).sibling(b"process_tester.py").path - d = defer.Deferred() - p = TestProcessProtocol() - p.deferred = d - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=None) - def check(ignored): - self.assertEqual(p.stages, [1, 2, 3, 4, 5]) - f = p.reason - f.trap(error.ProcessTerminated) - self.assertEqual(f.value.exitCode, 23) - # would .signal be available on non-posix? - # self.assertEqual(f.value.signal, None) - self.assertRaises( - error.ProcessExitedAlready, p.transport.signalProcess, 'INT') - try: - import process_tester, glob - for f in glob.glob(process_tester.test_file_match): - os.remove(f) - except: - pass - d.addCallback(check) - return d - - def testManyProcesses(self): - - def _check(results, protocols): - for p in protocols: - self.assertEqual(p.stages, [1, 2, 3, 4, 5], "[%d] stages = %s" % (id(p.transport), str(p.stages))) - # test status code - f = p.reason - f.trap(error.ProcessTerminated) - self.assertEqual(f.value.exitCode, 23) - - scriptPath = FilePath(__file__).sibling(b"process_tester.py").path - args = [pyExe, b"-u", scriptPath] - protocols = [] - deferreds = [] - - for i in xrange(CONCURRENT_PROCESS_TEST_COUNT): - p = TestManyProcessProtocol() - protocols.append(p) - reactor.spawnProcess(p, pyExe, args, env=None) - deferreds.append(p.deferred) - - deferredList = defer.DeferredList(deferreds, consumeErrors=True) - deferredList.addCallback(_check, protocols) - return deferredList - - - def test_echo(self): - """ - A spawning a subprocess which echoes its stdin to its stdout via - C{reactor.spawnProcess} will result in that echoed output being - delivered to outReceived. - """ - finished = defer.Deferred() - p = EchoProtocol(finished) - - scriptPath = FilePath(__file__).sibling(b"process_echoer.py").path - reactor.spawnProcess(p, pyExe, [pyExe, scriptPath], env=None) - - def asserts(ignored): - self.failIf(p.failure, p.failure) - self.failUnless(hasattr(p, 'buffer')) - self.assertEqual(len(p.buffer), len(p.s * p.n)) - - def takedownProcess(err): - p.transport.closeStdin() - return err - - return finished.addCallback(asserts).addErrback(takedownProcess) - - - def testCommandLine(self): - args = [br'a\"b ', br'a\b ', br' a\\"b', br' a\\b', br'"foo bar" "', - b'\tab', b'"\\', b'a"b', b"a'b"] - scriptPath = FilePath(__file__).sibling(b"process_cmdline.py").path - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath] + args, - env=None, path=None) - - def processEnded(ign): - self.assertEqual(p.errF.getvalue(), b"") - recvdArgs = p.outF.getvalue().splitlines() - self.assertEqual(recvdArgs, args) - return d.addCallback(processEnded) - - - def test_wrongArguments(self): - """ - Test invalid arguments to spawnProcess: arguments and environment - must only contains string or unicode, and not null bytes. - """ - p = protocol.ProcessProtocol() - - badEnvs = [ - {b"foo": 2}, - {b"foo": b"egg\0a"}, - {3: b"bar"}, - {b"bar\0foo": b"bar"}] - - badArgs = [ - [pyExe, 2], - b"spam", - [pyExe, b"foo\0bar"]] - - # Sanity check - this will fail for people who have mucked with - # their site configuration in a stupid way, but there's nothing we - # can do about that. - badUnicode = u'\N{SNOWMAN}' - try: - badUnicode.encode(sys.getdefaultencoding()) - except UnicodeEncodeError: - # Okay, that unicode doesn't encode, put it in as a bad environment - # key. - badEnvs.append({badUnicode: 'value for bad unicode key'}) - badEnvs.append({'key for bad unicode value': badUnicode}) - badArgs.append([pyExe, badUnicode]) - else: - # It _did_ encode. Most likely, Gtk2 is being used and the - # default system encoding is UTF-8, which can encode anything. - # In any case, if implicit unicode -> str conversion works for - # that string, we can't test that TypeError gets raised instead, - # so just leave it off. - pass - - for env in badEnvs: - self.assertRaises( - TypeError, - reactor.spawnProcess, p, pyExe, [pyExe, b"-c", b""], env=env) - - for args in badArgs: - self.assertRaises( - TypeError, - reactor.spawnProcess, p, pyExe, args, env=None) - - - # Use upper-case so that the environment key test uses an upper case - # name: some versions of Windows only support upper case environment - # variable names, and I think Python (as of 2.5) doesn't use the right - # syscall for lowercase or mixed case names to work anyway. - okayUnicode = u"UNICODE" - encodedValue = b"UNICODE" - - def _deprecatedUnicodeSupportTest(self, processProtocolClass, argv=[], env={}): - """ - Check that a deprecation warning is emitted when passing unicode to - spawnProcess for an argv value or an environment key or value. - Check that the warning is of the right type, has the right message, - and refers to the correct file. Unfortunately, don't check that the - line number is correct, because that is too hard for me to figure - out. - - @param processProtocolClass: A L{UtilityProcessProtocol} subclass - which will be instantiated to communicate with the child process. - - @param argv: The argv argument to spawnProcess. - - @param env: The env argument to spawnProcess. - - @return: A Deferred which fires when the test is complete. - """ - # Sanity to check to make sure we can actually encode this unicode - # with the default system encoding. This may be excessively - # paranoid. -exarkun - self.assertEqual( - self.okayUnicode.encode(sys.getdefaultencoding()), - self.encodedValue) - - p = self.assertWarns(DeprecationWarning, - "Argument strings and environment keys/values passed to " - "reactor.spawnProcess should be str, not unicode.", __file__, - processProtocolClass.run, reactor, argv, env) - return p.getResult() - - - def test_deprecatedUnicodeArgvSupport(self): - """ - Test that a unicode string passed for an argument value is allowed - if it can be encoded with the default system encoding, but that a - deprecation warning is emitted. - """ - d = self._deprecatedUnicodeSupportTest(GetArgumentVector, argv=[self.okayUnicode]) - def gotArgVector(argv): - self.assertEqual(argv, [b'-c', self.encodedValue]) - d.addCallback(gotArgVector) - return d - - - def test_deprecatedUnicodeEnvKeySupport(self): - """ - Test that a unicode string passed for the key of the environment - dictionary is allowed if it can be encoded with the default system - encoding, but that a deprecation warning is emitted. - """ - d = self._deprecatedUnicodeSupportTest( - GetEnvironmentDictionary, env={self.okayUnicode: self.encodedValue}) - def gotEnvironment(environ): - self.assertEqual(environ[self.encodedValue], self.encodedValue) - d.addCallback(gotEnvironment) - return d - - - def test_deprecatedUnicodeEnvValueSupport(self): - """ - Test that a unicode string passed for the value of the environment - dictionary is allowed if it can be encoded with the default system - encoding, but that a deprecation warning is emitted. - """ - d = self._deprecatedUnicodeSupportTest( - GetEnvironmentDictionary, env={self.encodedValue: self.okayUnicode}) - def gotEnvironment(environ): - # On Windows, the environment contains more things than we - # specified, so only make sure that at least the key we wanted - # is there, rather than testing the dictionary for exact - # equality. - self.assertEqual(environ[self.encodedValue], self.encodedValue) - d.addCallback(gotEnvironment) - return d - - - -class TwoProcessProtocol(protocol.ProcessProtocol): - num = -1 - finished = 0 - def __init__(self): - self.deferred = defer.Deferred() - def outReceived(self, data): - pass - def processEnded(self, reason): - self.finished = 1 - self.deferred.callback(None) - -class TestTwoProcessesBase: - def setUp(self): - self.processes = [None, None] - self.pp = [None, None] - self.done = 0 - self.verbose = 0 - - def createProcesses(self, usePTY=0): - scriptPath = FilePath(__file__).sibling(b"process_reader.py").path - for num in (0,1): - self.pp[num] = TwoProcessProtocol() - self.pp[num].num = num - p = reactor.spawnProcess(self.pp[num], pyExe, - [pyExe, b"-u", scriptPath], - env=None, usePTY=usePTY) - self.processes[num] = p - - def close(self, num): - if self.verbose: print("closing stdin [%d]" % num) - p = self.processes[num] - pp = self.pp[num] - self.failIf(pp.finished, "Process finished too early") - p.loseConnection() - if self.verbose: print(self.pp[0].finished, self.pp[1].finished) - - def _onClose(self): - return defer.gatherResults([ p.deferred for p in self.pp ]) - - def testClose(self): - if self.verbose: print("starting processes") - self.createProcesses() - reactor.callLater(1, self.close, 0) - reactor.callLater(2, self.close, 1) - return self._onClose() - -class TwoProcessesNonPosixTests(TestTwoProcessesBase, unittest.TestCase): - pass - -class TwoProcessesPosixTests(TestTwoProcessesBase, unittest.TestCase): - def tearDown(self): - for pp, pr in zip(self.pp, self.processes): - if not pp.finished: - try: - os.kill(pr.pid, signal.SIGTERM) - except OSError: - # If the test failed the process may already be dead - # The error here is only noise - pass - return self._onClose() - - def kill(self, num): - if self.verbose: print("kill [%d] with SIGTERM" % num) - p = self.processes[num] - pp = self.pp[num] - self.failIf(pp.finished, "Process finished too early") - os.kill(p.pid, signal.SIGTERM) - if self.verbose: print(self.pp[0].finished, self.pp[1].finished) - - def testKill(self): - if self.verbose: print("starting processes") - self.createProcesses(usePTY=0) - reactor.callLater(1, self.kill, 0) - reactor.callLater(2, self.kill, 1) - return self._onClose() - - def testClosePty(self): - if self.verbose: print("starting processes") - self.createProcesses(usePTY=1) - reactor.callLater(1, self.close, 0) - reactor.callLater(2, self.close, 1) - return self._onClose() - - def testKillPty(self): - if self.verbose: print("starting processes") - self.createProcesses(usePTY=1) - reactor.callLater(1, self.kill, 0) - reactor.callLater(2, self.kill, 1) - return self._onClose() - -class FDChecker(protocol.ProcessProtocol): - state = 0 - data = b"" - failed = None - - def __init__(self, d): - self.deferred = d - - def fail(self, why): - self.failed = why - self.deferred.callback(None) - - def connectionMade(self): - self.transport.writeToChild(0, b"abcd") - self.state = 1 - - def childDataReceived(self, childFD, data): - if self.state == 1: - if childFD != 1: - self.fail("read '%s' on fd %d (not 1) during state 1" \ - % (childFD, data)) - return - self.data += data - #print "len", len(self.data) - if len(self.data) == 6: - if self.data != b"righto": - self.fail("got '%s' on fd1, expected 'righto'" \ - % self.data) - return - self.data = b"" - self.state = 2 - #print "state2", self.state - self.transport.writeToChild(3, b"efgh") - return - if self.state == 2: - self.fail("read '%s' on fd %s during state 2" % (childFD, data)) - return - if self.state == 3: - if childFD != 1: - self.fail("read '%s' on fd %s (not 1) during state 3" \ - % (childFD, data)) - return - self.data += data - if len(self.data) == 6: - if self.data != b"closed": - self.fail("got '%s' on fd1, expected 'closed'" \ - % self.data) - return - self.state = 4 - return - if self.state == 4: - self.fail("read '%s' on fd %s during state 4" % (childFD, data)) - return - - def childConnectionLost(self, childFD): - if self.state == 1: - self.fail("got connectionLost(%d) during state 1" % childFD) - return - if self.state == 2: - if childFD != 4: - self.fail("got connectionLost(%d) (not 4) during state 2" \ - % childFD) - return - self.state = 3 - self.transport.closeChildFD(5) - return - - def processEnded(self, status): - rc = status.value.exitCode - if self.state != 4: - self.fail("processEnded early, rc %d" % rc) - return - if status.value.signal != None: - self.fail("processEnded with signal %s" % status.value.signal) - return - if rc != 0: - self.fail("processEnded with rc %d" % rc) - return - self.deferred.callback(None) - - -class FDTests(unittest.TestCase): - - def testFD(self): - scriptPath = FilePath(__file__).sibling(b"process_fds.py").path - d = defer.Deferred() - p = FDChecker(d) - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=None, - path=None, - childFDs={0:"w", 1:"r", 2:2, - 3:"w", 4:"r", 5:"w"}) - d.addCallback(lambda x : self.failIf(p.failed, p.failed)) - return d - - def testLinger(self): - # See what happens when all the pipes close before the process - # actually stops. This test *requires* SIGCHLD catching to work, - # as there is no other way to find out the process is done. - scriptPath = FilePath(__file__).sibling(b"process_linger.py").path - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=None, - path=None, - childFDs={1:"r", 2:2}, - ) - def processEnded(ign): - self.assertEqual(p.outF.getvalue(), - b"here is some text\ngoodbye\n") - return d.addCallback(processEnded) - - - -class Accumulator(protocol.ProcessProtocol): - """Accumulate data from a process.""" - - closed = 0 - endedDeferred = None - - def connectionMade(self): - self.outF = BytesIO() - self.errF = BytesIO() - - def outReceived(self, d): - self.outF.write(d) - - def errReceived(self, d): - self.errF.write(d) - - def outConnectionLost(self): - pass - - def errConnectionLost(self): - pass - - def processEnded(self, reason): - self.closed = 1 - if self.endedDeferred is not None: - d, self.endedDeferred = self.endedDeferred, None - d.callback(None) - - -class PosixProcessBase(object): - """ - Test running processes. - """ - usePTY = False - - def getCommand(self, commandName): - """ - Return the path of the shell command named C{commandName}, looking at - common locations. - """ - binLoc = FilePath('/bin').child(commandName) - usrbinLoc = FilePath('/usr/bin').child(commandName) - - if binLoc.exists(): - return binLoc._asBytesPath() - elif usrbinLoc.exists(): - return usrbinLoc._asBytesPath() - else: - raise RuntimeError( - "%s not found in /bin or /usr/bin" % (commandName,)) - - - def testNormalTermination(self): - cmd = self.getCommand('true') - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, cmd, [b'true'], env=None, - usePTY=self.usePTY) - def check(ignored): - p.reason.trap(error.ProcessDone) - self.assertEqual(p.reason.value.exitCode, 0) - self.assertEqual(p.reason.value.signal, None) - d.addCallback(check) - return d - - - def test_abnormalTermination(self): - """ - When a process terminates with a system exit code set to 1, - C{processEnded} is called with a L{error.ProcessTerminated} error, - the C{exitCode} attribute reflecting the system exit code. - """ - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, pyExe, - [pyExe, b'-c', b'import sys; sys.exit(1)'], - env=None, usePTY=self.usePTY) - - def check(ignored): - p.reason.trap(error.ProcessTerminated) - self.assertEqual(p.reason.value.exitCode, 1) - self.assertEqual(p.reason.value.signal, None) - d.addCallback(check) - return d - - - def _testSignal(self, sig): - scriptPath = FilePath(__file__).sibling(b"process_signal.py").path - d = defer.Deferred() - p = SignalProtocol(d, sig) - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=None, - usePTY=self.usePTY) - return d - - - def test_signalHUP(self): - """ - Sending the SIGHUP signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGHUP}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('HUP') - - - def test_signalINT(self): - """ - Sending the SIGINT signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGINT}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('INT') - - - def test_signalKILL(self): - """ - Sending the SIGKILL signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGKILL}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('KILL') - - - def test_signalTERM(self): - """ - Sending the SIGTERM signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGTERM}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('TERM') - - - def test_childSignalHandling(self): - """ - The disposition of signals which are ignored in the parent - process is reset to the default behavior for the child - process. - """ - # Somewhat arbitrarily select SIGUSR1 here. It satisfies our - # requirements that: - # - The interpreter not fiddle around with the handler - # behind our backs at startup time (this disqualifies - # signals like SIGINT and SIGPIPE). - # - The default behavior is to exit. - # - # This lets us send the signal to the child and then verify - # that it exits with a status code indicating that it was - # indeed the signal which caused it to exit. - which = signal.SIGUSR1 - - # Ignore the signal in the parent (and make sure we clean it - # up). - handler = signal.signal(which, signal.SIG_IGN) - self.addCleanup(signal.signal, signal.SIGUSR1, handler) - - # Now do the test. - return self._testSignal(signal.SIGUSR1) - - - def test_executionError(self): - """ - Raise an error during execvpe to check error management. - """ - cmd = self.getCommand('false') - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - def buggyexecvpe(command, args, environment): - raise RuntimeError("Ouch") - oldexecvpe = os.execvpe - os.execvpe = buggyexecvpe - try: - reactor.spawnProcess(p, cmd, [b'false'], env=None, - usePTY=self.usePTY) - - def check(ignored): - errData = b"".join(p.errData + p.outData) - self.assertIn(b"Upon execvpe", errData) - self.assertIn(b"Ouch", errData) - d.addCallback(check) - finally: - os.execvpe = oldexecvpe - return d - - - def test_errorInProcessEnded(self): - """ - The handler which reaps a process is removed when the process is - reaped, even if the protocol's C{processEnded} method raises an - exception. - """ - connected = defer.Deferred() - ended = defer.Deferred() - - # This script runs until we disconnect its transport. - scriptPath = FilePath(__file__).sibling(b"process_echoer.py").path - - class ErrorInProcessEnded(protocol.ProcessProtocol): - """ - A protocol that raises an error in C{processEnded}. - """ - def makeConnection(self, transport): - connected.callback(transport) - - def processEnded(self, reason): - reactor.callLater(0, ended.callback, None) - raise RuntimeError("Deliberate error") - - # Launch the process. - reactor.spawnProcess( - ErrorInProcessEnded(), pyExe, - [pyExe, scriptPath], - env=None, path=None) - - pid = [] - def cbConnected(transport): - pid.append(transport.pid) - # There's now a reap process handler registered. - self.assertIn(transport.pid, process.reapProcessHandlers) - - # Kill the process cleanly, triggering an error in the protocol. - transport.loseConnection() - connected.addCallback(cbConnected) - - def checkTerminated(ignored): - # The exception was logged. - excs = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(excs), 1) - # The process is no longer scheduled for reaping. - self.assertNotIn(pid[0], process.reapProcessHandlers) - ended.addCallback(checkTerminated) - - return ended - - - -class MockSignal(object): - """ - Neuter L{signal.signal}, but pass other attributes unscathed - """ - def signal(self, sig, action): - return signal.getsignal(sig) - - def __getattr__(self, attr): - return getattr(signal, attr) - - -class MockOS(object): - """ - The mock OS: overwrite L{os}, L{fcntl} and {sys} functions with fake ones. - - @ivar exited: set to True when C{_exit} is called. - @type exited: C{bool} - - @ivar O_RDWR: dumb value faking C{os.O_RDWR}. - @type O_RDWR: C{int} - - @ivar O_NOCTTY: dumb value faking C{os.O_NOCTTY}. - @type O_NOCTTY: C{int} - - @ivar WNOHANG: dumb value faking C{os.WNOHANG}. - @type WNOHANG: C{int} - - @ivar raiseFork: if not C{None}, subsequent calls to fork will raise this - object. - @type raiseFork: C{NoneType} or C{Exception} - - @ivar raiseExec: if set, subsequent calls to execvpe will raise an error. - @type raiseExec: C{bool} - - @ivar fdio: fake file object returned by calls to fdopen. - @type fdio: C{BytesIO} or C{BytesIO} - - @ivar actions: hold names of some actions executed by the object, in order - of execution. - - @type actions: C{list} of C{str} - - @ivar closed: keep track of the file descriptor closed. - @type closed: C{list} of C{int} - - @ivar child: whether fork return for the child or the parent. - @type child: C{bool} - - @ivar pipeCount: count the number of time that C{os.pipe} has been called. - @type pipeCount: C{int} - - @ivar raiseWaitPid: if set, subsequent calls to waitpid will raise - the error specified. - @type raiseWaitPid: C{None} or a class - - @ivar waitChild: if set, subsequent calls to waitpid will return it. - @type waitChild: C{None} or a tuple - - @ivar euid: the uid returned by the fake C{os.geteuid} - @type euid: C{int} - - @ivar egid: the gid returned by the fake C{os.getegid} - @type egid: C{int} - - @ivar seteuidCalls: stored results of C{os.seteuid} calls. - @type seteuidCalls: C{list} - - @ivar setegidCalls: stored results of C{os.setegid} calls. - @type setegidCalls: C{list} - - @ivar path: the path returned by C{os.path.expanduser}. - @type path: C{str} - - @ivar raiseKill: if set, subsequent call to kill will raise the error - specified. - @type raiseKill: C{None} or an exception instance. - - @ivar readData: data returned by C{os.read}. - @type readData: C{str} - """ - exited = False - raiseExec = False - fdio = None - child = True - raiseWaitPid = None - raiseFork = None - waitChild = None - euid = 0 - egid = 0 - path = None - raiseKill = None - readData = b"" - - def __init__(self): - """ - Initialize data structures. - """ - self.actions = [] - self.closed = [] - self.pipeCount = 0 - self.O_RDWR = -1 - self.O_NOCTTY = -2 - self.WNOHANG = -4 - self.WEXITSTATUS = lambda x: 0 - self.WIFEXITED = lambda x: 1 - self.seteuidCalls = [] - self.setegidCalls = [] - - - def open(self, dev, flags): - """ - Fake C{os.open}. Return a non fd number to be sure it's not used - elsewhere. - """ - return -3 - - - def fstat(self, fd): - """ - Fake C{os.fstat}. Return a C{os.stat_result} filled with garbage. - """ - return os.stat_result((0,) * 10) - - - def fdopen(self, fd, flag): - """ - Fake C{os.fdopen}. Return a file-like object whose content can - be tested later via C{self.fdio}. - """ - if flag == "wb": - self.fdio = BytesIO() - else: - assert False - return self.fdio - - - def setsid(self): - """ - Fake C{os.setsid}. Save action. - """ - self.actions.append('setsid') - - - def fork(self): - """ - Fake C{os.fork}. Save the action in C{self.actions}, and return 0 if - C{self.child} is set, or a dumb number. - """ - self.actions.append(('fork', gc.isenabled())) - if self.raiseFork is not None: - raise self.raiseFork - elif self.child: - # Child result is 0 - return 0 - else: - return 21 - - - def close(self, fd): - """ - Fake C{os.close}, saving the closed fd in C{self.closed}. - """ - self.closed.append(fd) - - - def dup2(self, fd1, fd2): - """ - Fake C{os.dup2}. Do nothing. - """ - - - def write(self, fd, data): - """ - Fake C{os.write}. Save action. - """ - self.actions.append(("write", fd, data)) - - - def read(self, fd, size): - """ - Fake C{os.read}: save action, and return C{readData} content. - - @param fd: The file descriptor to read. - - @param size: The maximum number of bytes to read. - - @return: A fixed C{bytes} buffer. - """ - self.actions.append(('read', fd, size)) - return self.readData - - - def execvpe(self, command, args, env): - """ - Fake C{os.execvpe}. Save the action, and raise an error if - C{self.raiseExec} is set. - """ - self.actions.append('exec') - if self.raiseExec: - raise RuntimeError("Bar") - - - def pipe(self): - """ - Fake C{os.pipe}. Return non fd numbers to be sure it's not used - elsewhere, and increment C{self.pipeCount}. This is used to uniquify - the result. - """ - self.pipeCount += 1 - return - 2 * self.pipeCount + 1, - 2 * self.pipeCount - - - def ttyname(self, fd): - """ - Fake C{os.ttyname}. Return a dumb string. - """ - return "foo" - - - def _exit(self, code): - """ - Fake C{os._exit}. Save the action, set the C{self.exited} flag, and - raise C{SystemError}. - """ - self.actions.append(('exit', code)) - self.exited = True - # Don't forget to raise an error, or you'll end up in parent - # code path. - raise SystemError() - - - def ioctl(self, fd, flags, arg): - """ - Override C{fcntl.ioctl}. Do nothing. - """ - - - def setNonBlocking(self, fd): - """ - Override C{fdesc.setNonBlocking}. Do nothing. - """ - - - def waitpid(self, pid, options): - """ - Override C{os.waitpid}. Return values meaning that the child process - has exited, save executed action. - """ - self.actions.append('waitpid') - if self.raiseWaitPid is not None: - raise self.raiseWaitPid - if self.waitChild is not None: - return self.waitChild - return 1, 0 - - - def settrace(self, arg): - """ - Override C{sys.settrace} to keep coverage working. - """ - - - def getgid(self): - """ - Override C{os.getgid}. Return a dumb number. - """ - return 1235 - - - def getuid(self): - """ - Override C{os.getuid}. Return a dumb number. - """ - return 1237 - - - def setuid(self, val): - """ - Override C{os.setuid}. Do nothing. - """ - self.actions.append(('setuid', val)) - - - def setgid(self, val): - """ - Override C{os.setgid}. Do nothing. - """ - self.actions.append(('setgid', val)) - - - def setregid(self, val1, val2): - """ - Override C{os.setregid}. Do nothing. - """ - self.actions.append(('setregid', val1, val2)) - - - def setreuid(self, val1, val2): - """ - Override C{os.setreuid}. Save the action. - """ - self.actions.append(('setreuid', val1, val2)) - - - def switchUID(self, uid, gid): - """ - Override C{util.switchuid}. Save the action. - """ - self.actions.append(('switchuid', uid, gid)) - - - def openpty(self): - """ - Override C{pty.openpty}, returning fake file descriptors. - """ - return -12, -13 - - - def chdir(self, path): - """ - Override C{os.chdir}. Save the action. - - @param path: The path to change the current directory to. - """ - self.actions.append(('chdir', path)) - - - def geteuid(self): - """ - Mock C{os.geteuid}, returning C{self.euid} instead. - """ - return self.euid - - - def getegid(self): - """ - Mock C{os.getegid}, returning C{self.egid} instead. - """ - return self.egid - - - def seteuid(self, egid): - """ - Mock C{os.seteuid}, store result. - """ - self.seteuidCalls.append(egid) - - - def setegid(self, egid): - """ - Mock C{os.setegid}, store result. - """ - self.setegidCalls.append(egid) - - - def expanduser(self, path): - """ - Mock C{os.path.expanduser}. - """ - return self.path - - - def getpwnam(self, user): - """ - Mock C{pwd.getpwnam}. - """ - return 0, 0, 1, 2 - - - def listdir(self, path): - """ - Override C{os.listdir}, returning fake contents of '/dev/fd' - """ - return "-1", "-2" - - - def kill(self, pid, signalID): - """ - Override C{os.kill}: save the action and raise C{self.raiseKill} if - specified. - """ - self.actions.append(('kill', pid, signalID)) - if self.raiseKill is not None: - raise self.raiseKill - - - def unlink(self, filename): - """ - Override C{os.unlink}. Save the action. - - @param filename: The file name to remove. - """ - self.actions.append(('unlink', filename)) - - - def umask(self, mask): - """ - Override C{os.umask}. Save the action. - - @param mask: The new file mode creation mask. - """ - self.actions.append(('umask', mask)) - - - def getpid(self): - """ - Return a fixed PID value. - - @return: A fixed value. - """ - return 6789 - - - def getfilesystemencoding(self): - """ - Return a fixed filesystem encoding. - - @return: A fixed value of "utf8". - """ - return "utf8" - - -if process is not None: - class DumbProcessWriter(process.ProcessWriter): - """ - A fake L{process.ProcessWriter} used for tests. - """ - - def startReading(self): - """ - Here's the faking: don't do anything here. - """ - - - - class DumbProcessReader(process.ProcessReader): - """ - A fake L{process.ProcessReader} used for tests. - """ - - def startReading(self): - """ - Here's the faking: don't do anything here. - """ - - - - class DumbPTYProcess(process.PTYProcess): - """ - A fake L{process.PTYProcess} used for tests. - """ - - def startReading(self): - """ - Here's the faking: don't do anything here. - """ - - - -class MockProcessTests(unittest.TestCase): - """ - Mock a process runner to test forked child code path. - """ - if process is None: - skip = "twisted.internet.process is never used on Windows" - - def setUp(self): - """ - Replace L{process} os, fcntl, sys, switchUID, fdesc and pty modules - with the mock class L{MockOS}. - """ - if gc.isenabled(): - self.addCleanup(gc.enable) - else: - self.addCleanup(gc.disable) - self.mockos = MockOS() - self.mockos.euid = 1236 - self.mockos.egid = 1234 - self.patch(process, "os", self.mockos) - self.patch(process, "fcntl", self.mockos) - self.patch(process, "sys", self.mockos) - self.patch(process, "switchUID", self.mockos.switchUID) - self.patch(process, "fdesc", self.mockos) - self.patch(process.Process, "processReaderFactory", DumbProcessReader) - self.patch(process.Process, "processWriterFactory", DumbProcessWriter) - self.patch(process, "pty", self.mockos) - - self.mocksig = MockSignal() - self.patch(process, "signal", self.mocksig) - - - def tearDown(self): - """ - Reset processes registered for reap. - """ - process.reapProcessHandlers = {} - - - def test_mockFork(self): - """ - Test a classic spawnProcess. Check the path of the client code: - fork, exec, exit. - """ - gc.enable() - - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - try: - reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=False) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEqual( - self.mockos.actions, [("fork", False), "exec", ("exit", 1)]) - else: - self.fail("Should not be here") - - # It should leave the garbage collector disabled. - self.assertFalse(gc.isenabled()) - - - def _mockForkInParentTest(self): - """ - Assert that in the main process, spawnProcess disables the garbage - collector, calls fork, closes the pipe file descriptors it created for - the child process, and calls waitpid. - """ - self.mockos.child = False - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=False) - # It should close the first read pipe, and the 2 last write pipes - self.assertEqual(set(self.mockos.closed), set([-1, -4, -6])) - self.assertEqual(self.mockos.actions, [("fork", False), "waitpid"]) - - - def test_mockForkInParentGarbageCollectorEnabled(self): - """ - The garbage collector should be enabled when L{reactor.spawnProcess} - returns if it was initially enabled. - - @see L{_mockForkInParentTest} - """ - gc.enable() - self._mockForkInParentTest() - self.assertTrue(gc.isenabled()) - - - def test_mockForkInParentGarbageCollectorDisabled(self): - """ - The garbage collector should be disabled when L{reactor.spawnProcess} - returns if it was initially disabled. - - @see L{_mockForkInParentTest} - """ - gc.disable() - self._mockForkInParentTest() - self.assertFalse(gc.isenabled()) - - - def test_mockForkTTY(self): - """ - Test a TTY spawnProcess: check the path of the client code: - fork, exec, exit. - """ - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - self.assertRaises(SystemError, reactor.spawnProcess, p, cmd, [b'ouch'], - env=None, usePTY=True) - self.assertTrue(self.mockos.exited) - self.assertEqual( - self.mockos.actions, - [("fork", False), "setsid", "exec", ("exit", 1)]) - - - def _mockWithForkError(self): - """ - Assert that if the fork call fails, no other process setup calls are - made and that spawnProcess raises the exception fork raised. - """ - self.mockos.raiseFork = OSError(errno.EAGAIN, None) - protocol = TrivialProcessProtocol(None) - self.assertRaises(OSError, reactor.spawnProcess, protocol, None) - self.assertEqual(self.mockos.actions, [("fork", False)]) - - - def test_mockWithForkErrorGarbageCollectorEnabled(self): - """ - The garbage collector should be enabled when L{reactor.spawnProcess} - raises because L{os.fork} raised, if it was initially enabled. - """ - gc.enable() - self._mockWithForkError() - self.assertTrue(gc.isenabled()) - - - def test_mockWithForkErrorGarbageCollectorDisabled(self): - """ - The garbage collector should be disabled when - L{reactor.spawnProcess} raises because L{os.fork} raised, if it was - initially disabled. - """ - gc.disable() - self._mockWithForkError() - self.assertFalse(gc.isenabled()) - - - def test_mockForkErrorCloseFDs(self): - """ - When C{os.fork} raises an exception, the file descriptors created - before are closed and don't leak. - """ - self._mockWithForkError() - self.assertEqual(set(self.mockos.closed), set([-1, -4, -6, -2, -3, -5])) - - - def test_mockForkErrorGivenFDs(self): - """ - When C{os.forks} raises an exception and that file descriptors have - been specified with the C{childFDs} arguments of - L{reactor.spawnProcess}, they are not closed. - """ - self.mockos.raiseFork = OSError(errno.EAGAIN, None) - protocol = TrivialProcessProtocol(None) - self.assertRaises(OSError, reactor.spawnProcess, protocol, None, - childFDs={0: -10, 1: -11, 2: -13}) - self.assertEqual(self.mockos.actions, [("fork", False)]) - self.assertEqual(self.mockos.closed, []) - - # We can also put "r" or "w" to let twisted create the pipes - self.assertRaises(OSError, reactor.spawnProcess, protocol, None, - childFDs={0: "r", 1: -11, 2: -13}) - self.assertEqual(set(self.mockos.closed), set([-1, -2])) - - - def test_mockForkErrorClosePTY(self): - """ - When C{os.fork} raises an exception, the file descriptors created by - C{pty.openpty} are closed and don't leak, when C{usePTY} is set to - C{True}. - """ - self.mockos.raiseFork = OSError(errno.EAGAIN, None) - protocol = TrivialProcessProtocol(None) - self.assertRaises(OSError, reactor.spawnProcess, protocol, None, - usePTY=True) - self.assertEqual(self.mockos.actions, [("fork", False)]) - self.assertEqual(set(self.mockos.closed), set([-12, -13])) - - - def test_mockForkErrorPTYGivenFDs(self): - """ - If a tuple is passed to C{usePTY} to specify slave and master file - descriptors and that C{os.fork} raises an exception, these file - descriptors aren't closed. - """ - self.mockos.raiseFork = OSError(errno.EAGAIN, None) - protocol = TrivialProcessProtocol(None) - self.assertRaises(OSError, reactor.spawnProcess, protocol, None, - usePTY=(-20, -21, 'foo')) - self.assertEqual(self.mockos.actions, [("fork", False)]) - self.assertEqual(self.mockos.closed, []) - - - def test_mockWithExecError(self): - """ - Spawn a process but simulate an error during execution in the client - path: C{os.execvpe} raises an error. It should close all the standard - fds, try to print the error encountered, and exit cleanly. - """ - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - self.mockos.raiseExec = True - try: - reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=False) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEqual( - self.mockos.actions, [("fork", False), "exec", ("exit", 1)]) - # Check that fd have been closed - self.assertIn(0, self.mockos.closed) - self.assertIn(1, self.mockos.closed) - self.assertIn(2, self.mockos.closed) - # Check content of traceback - self.assertIn(b"RuntimeError: Bar", self.mockos.fdio.getvalue()) - else: - self.fail("Should not be here") - - - def test_mockSetUid(self): - """ - Try creating a process with setting its uid: it's almost the same path - as the standard path, but with a C{switchUID} call before the exec. - """ - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - try: - reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=False, uid=8080) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEqual( - self.mockos.actions, - [('fork', False), ('setuid', 0), ('setgid', 0), - ('switchuid', 8080, 1234), 'exec', ('exit', 1)]) - else: - self.fail("Should not be here") - - - def test_mockSetUidInParent(self): - """ - When spawning a child process with a UID different from the UID of the - current process, the current process does not have its UID changed. - """ - self.mockos.child = False - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=False, uid=8080) - self.assertEqual(self.mockos.actions, [('fork', False), 'waitpid']) - - - def test_mockPTYSetUid(self): - """ - Try creating a PTY process with setting its uid: it's almost the same - path as the standard path, but with a C{switchUID} call before the - exec. - """ - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - try: - reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=True, uid=8081) - except SystemError: - self.assertTrue(self.mockos.exited) - self.assertEqual( - self.mockos.actions, - [('fork', False), 'setsid', ('setuid', 0), ('setgid', 0), - ('switchuid', 8081, 1234), 'exec', ('exit', 1)]) - else: - self.fail("Should not be here") - - - def test_mockPTYSetUidInParent(self): - """ - When spawning a child process with PTY and a UID different from the UID - of the current process, the current process does not have its UID - changed. - """ - self.mockos.child = False - cmd = b'/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - oldPTYProcess = process.PTYProcess - try: - process.PTYProcess = DumbPTYProcess - reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=True, uid=8080) - finally: - process.PTYProcess = oldPTYProcess - self.assertEqual(self.mockos.actions, [('fork', False), 'waitpid']) - - - def test_mockWithWaitError(self): - """ - Test that reapProcess logs errors raised. - """ - self.mockos.child = False - cmd = b'/mock/ouch' - self.mockos.waitChild = (0, 0) - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - proc = reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=False) - self.assertEqual(self.mockos.actions, [("fork", False), "waitpid"]) - - self.mockos.raiseWaitPid = OSError() - proc.reapProcess() - errors = self.flushLoggedErrors() - self.assertEqual(len(errors), 1) - errors[0].trap(OSError) - - - def test_mockErrorECHILDInReapProcess(self): - """ - Test that reapProcess doesn't log anything when waitpid raises a - C{OSError} with errno C{ECHILD}. - """ - self.mockos.child = False - cmd = b'/mock/ouch' - self.mockos.waitChild = (0, 0) - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - proc = reactor.spawnProcess(p, cmd, [b'ouch'], env=None, - usePTY=False) - self.assertEqual(self.mockos.actions, [("fork", False), "waitpid"]) - - self.mockos.raiseWaitPid = OSError() - self.mockos.raiseWaitPid.errno = errno.ECHILD - # This should not produce any errors - proc.reapProcess() - - - def test_mockErrorInPipe(self): - """ - If C{os.pipe} raises an exception after some pipes where created, the - created pipes are closed and don't leak. - """ - pipes = [-1, -2, -3, -4] - def pipe(): - try: - return pipes.pop(0), pipes.pop(0) - except IndexError: - raise OSError() - self.mockos.pipe = pipe - protocol = TrivialProcessProtocol(None) - self.assertRaises(OSError, reactor.spawnProcess, protocol, None) - self.assertEqual(self.mockos.actions, []) - self.assertEqual(set(self.mockos.closed), set([-4, -3, -2, -1])) - - - def test_kill(self): - """ - L{process.Process.signalProcess} calls C{os.kill} translating the given - signal string to the PID. - """ - self.mockos.child = False - self.mockos.waitChild = (0, 0) - cmd = b'/mock/ouch' - p = TrivialProcessProtocol(None) - proc = reactor.spawnProcess(p, cmd, [b'ouch'], env=None, usePTY=False) - proc.signalProcess("KILL") - self.assertEqual(self.mockos.actions, - [('fork', False), 'waitpid', ('kill', 21, signal.SIGKILL)]) - - - def test_killExited(self): - """ - L{process.Process.signalProcess} raises L{error.ProcessExitedAlready} - if the process has exited. - """ - self.mockos.child = False - cmd = b'/mock/ouch' - p = TrivialProcessProtocol(None) - proc = reactor.spawnProcess(p, cmd, [b'ouch'], env=None, usePTY=False) - # We didn't specify a waitpid value, so the waitpid call in - # registerReapProcessHandler has already reaped the process - self.assertRaises(error.ProcessExitedAlready, - proc.signalProcess, "KILL") - - - def test_killExitedButNotDetected(self): - """ - L{process.Process.signalProcess} raises L{error.ProcessExitedAlready} - if the process has exited but that twisted hasn't seen it (for example, - if the process has been waited outside of twisted): C{os.kill} then - raise C{OSError} with C{errno.ESRCH} as errno. - """ - self.mockos.child = False - self.mockos.waitChild = (0, 0) - cmd = b'/mock/ouch' - p = TrivialProcessProtocol(None) - proc = reactor.spawnProcess(p, cmd, [b'ouch'], env=None, usePTY=False) - self.mockos.raiseKill = OSError(errno.ESRCH, "Not found") - self.assertRaises(error.ProcessExitedAlready, - proc.signalProcess, "KILL") - - - def test_killErrorInKill(self): - """ - L{process.Process.signalProcess} doesn't mask C{OSError} exceptions if - the errno is different from C{errno.ESRCH}. - """ - self.mockos.child = False - self.mockos.waitChild = (0, 0) - cmd = b'/mock/ouch' - p = TrivialProcessProtocol(None) - proc = reactor.spawnProcess(p, cmd, [b'ouch'], env=None, usePTY=False) - self.mockos.raiseKill = OSError(errno.EINVAL, "Invalid signal") - err = self.assertRaises(OSError, - proc.signalProcess, "KILL") - self.assertEquals(err.errno, errno.EINVAL) - - - -class PosixProcessTests(unittest.TestCase, PosixProcessBase): - # add two non-pty test cases - - def test_stderr(self): - """ - Bytes written to stderr by the spawned process are passed to the - C{errReceived} callback on the C{ProcessProtocol} passed to - C{spawnProcess}. - """ - value = "42" - - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, pyExe, - [pyExe, b"-c", - networkString("import sys; sys.stderr.write" - "('{0}')".format(value))], - env=None, path="/tmp", - usePTY=self.usePTY) - - def processEnded(ign): - self.assertEqual(b"42", p.errF.getvalue()) - return d.addCallback(processEnded) - - - def testProcess(self): - cmd = self.getCommand('gzip') - s = b"there's no place like home!\n" * 3 - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, cmd, [cmd, b"-c"], env=None, path="/tmp", - usePTY=self.usePTY) - p.transport.write(s) - p.transport.closeStdin() - - def processEnded(ign): - f = p.outF - f.seek(0, 0) - gf = gzip.GzipFile(fileobj=f) - self.assertEqual(gf.read(), s) - return d.addCallback(processEnded) - - - -class PosixProcessPTYTests(unittest.TestCase, PosixProcessBase): - """ - Just like PosixProcessTests, but use ptys instead of pipes. - """ - usePTY = True - # PTYs only offer one input and one output. What still makes sense? - # testNormalTermination - # test_abnormalTermination - # testSignal - # testProcess, but not without p.transport.closeStdin - # might be solveable: TODO: add test if so - - def testOpeningTTY(self): - scriptPath = FilePath(__file__).sibling(b"process_tty.py").path - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=None, - path=None, usePTY=self.usePTY) - p.transport.write(b"hello world!\n") - - def processEnded(ign): - self.assertRaises( - error.ProcessExitedAlready, p.transport.signalProcess, 'HUP') - self.assertEqual( - p.outF.getvalue(), - b"hello world!\r\nhello world!\r\n", - "Error message from process_tty follows:\n\n%s\n\n" % p.outF.getvalue()) - return d.addCallback(processEnded) - - - def testBadArgs(self): - pyArgs = [pyExe, b"-u", b"-c", b"print('hello')"] - p = Accumulator() - self.assertRaises(ValueError, reactor.spawnProcess, p, pyExe, pyArgs, - usePTY=1, childFDs={1:b'r'}) - - - -class Win32SignalProtocol(SignalProtocol): - """ - A win32-specific process protocol that handles C{processEnded} - differently: processes should exit with exit code 1. - """ - - def processEnded(self, reason): - """ - Callback C{self.deferred} with C{None} if C{reason} is a - L{error.ProcessTerminated} failure with C{exitCode} set to 1. - Otherwise, errback with a C{ValueError} describing the problem. - """ - if not reason.check(error.ProcessTerminated): - return self.deferred.errback( - ValueError("wrong termination: %s" % (reason,))) - v = reason.value - if v.exitCode != 1: - return self.deferred.errback( - ValueError("Wrong exit code: %s" % (v.exitCode,))) - self.deferred.callback(None) - - - -class Win32ProcessTests(unittest.TestCase): - """ - Test process programs that are packaged with twisted. - """ - - def testStdinReader(self): - scriptPath = FilePath(__file__).sibling(b"process_stdinreader.py").path - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=None, - path=None) - p.transport.write(b"hello, world") - p.transport.closeStdin() - - def processEnded(ign): - self.assertEqual(p.errF.getvalue(), "err\nerr\n") - self.assertEqual(p.outF.getvalue(), "out\nhello, world\nout\n") - return d.addCallback(processEnded) - - - def testBadArgs(self): - pyArgs = [pyExe, b"-u", b"-c", b"print('hello')"] - p = Accumulator() - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, uid=1) - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, gid=1) - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, usePTY=1) - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, childFDs={1:'r'}) - - - def _testSignal(self, sig): - scriptPath = FilePath(__file__).sibling(b"process_signal.py").path - d = defer.Deferred() - p = Win32SignalProtocol(d, sig) - reactor.spawnProcess(p, pyExe, [pyExe, b"-u", scriptPath], env=None) - return d - - - def test_signalTERM(self): - """ - Sending the SIGTERM signal terminates a created process, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} attribute set to 1. - """ - return self._testSignal('TERM') - - - def test_signalINT(self): - """ - Sending the SIGINT signal terminates a created process, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} attribute set to 1. - """ - return self._testSignal('INT') - - - def test_signalKILL(self): - """ - Sending the SIGKILL signal terminates a created process, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} attribute set to 1. - """ - return self._testSignal('KILL') - - - def test_closeHandles(self): - """ - The win32 handles should be properly closed when the process exits. - """ - import win32api - - connected = defer.Deferred() - ended = defer.Deferred() - - class SimpleProtocol(protocol.ProcessProtocol): - """ - A protocol that fires deferreds when connected and disconnected. - """ - def makeConnection(self, transport): - connected.callback(transport) - - def processEnded(self, reason): - ended.callback(None) - - p = SimpleProtocol() - pyArgs = [pyExe, b"-u", b"-c", b"print('hello')"] - proc = reactor.spawnProcess(p, pyExe, pyArgs) - - def cbConnected(transport): - self.assertIdentical(transport, proc) - # perform a basic validity test on the handles - win32api.GetHandleInformation(proc.hProcess) - win32api.GetHandleInformation(proc.hThread) - # And save their values for later - self.hProcess = proc.hProcess - self.hThread = proc.hThread - connected.addCallback(cbConnected) - - def checkTerminated(ignored): - # The attributes on the process object must be reset... - self.assertIdentical(proc.pid, None) - self.assertIdentical(proc.hProcess, None) - self.assertIdentical(proc.hThread, None) - # ...and the handles must be closed. - self.assertRaises(win32api.error, - win32api.GetHandleInformation, self.hProcess) - self.assertRaises(win32api.error, - win32api.GetHandleInformation, self.hThread) - ended.addCallback(checkTerminated) - - return defer.gatherResults([connected, ended]) - - - -class Win32UnicodeEnvironmentTests(unittest.TestCase): - """ - Tests for Unicode environment on Windows - """ - goodKey = u'UNICODE' - goodValue = u'UNICODE' - - def test_encodableUnicodeEnvironment(self): - """ - Test C{os.environ} (inherited by every subprocess on Windows) that - contains an ascii-encodable Unicode string. This is different from - passing Unicode environment explicitly to spawnProcess (which is not - supported). - """ - os.environ[self.goodKey] = self.goodValue - self.addCleanup(operator.delitem, os.environ, self.goodKey) - - p = GetEnvironmentDictionary.run(reactor, [], {}) - def gotEnvironment(environ): - self.assertEqual( - environ[self.goodKey.encode('ascii')], - self.goodValue.encode('ascii')) - return p.getResult().addCallback(gotEnvironment) - - - -class Dumbwin32procPidTests(unittest.TestCase): - """ - Simple test for the pid attribute of Process on win32. - """ - - def test_pid(self): - """ - Launch process with mock win32process. The only mock aspect of this - module is that the pid of the process created will always be 42. - """ - from twisted.internet import _dumbwin32proc - from twisted.test import mock_win32process - self.patch(_dumbwin32proc, "win32process", mock_win32process) - scriptPath = util.sibpath(__file__, "process_cmdline.py") - - d = defer.Deferred() - processProto = TrivialProcessProtocol(d) - comspec = bytes(os.environ["COMSPEC"]) - cmd = [comspec, b"/c", pyExe, scriptPath] - - p = _dumbwin32proc.Process(reactor, - processProto, - None, - cmd, - {}, - None) - self.assertEqual(42, p.pid) - self.assertEqual("", repr(p)) - - def pidCompleteCb(result): - self.assertEqual(None, p.pid) - return d.addCallback(pidCompleteCb) - - - -class UtilTests(unittest.TestCase): - """ - Tests for process-related helper functions (currently only - L{procutils.which}. - """ - def setUp(self): - """ - Create several directories and files, some of which are executable - and some of which are not. Save the current PATH setting. - """ - j = os.path.join - - base = self.mktemp() - - self.foo = j(base, "foo") - self.baz = j(base, "baz") - self.foobar = j(self.foo, "bar") - self.foobaz = j(self.foo, "baz") - self.bazfoo = j(self.baz, "foo") - self.bazbar = j(self.baz, "bar") - - for d in self.foobar, self.foobaz, self.bazfoo, self.bazbar: - os.makedirs(d) - - for name, mode in [(j(self.foobaz, "executable"), 0o700), - (j(self.foo, "executable"), 0o700), - (j(self.bazfoo, "executable"), 0o700), - (j(self.bazfoo, "executable.bin"), 0o700), - (j(self.bazbar, "executable"), 0)]: - f = open(name, "wb") - f.close() - os.chmod(name, mode) - - self.oldPath = os.environ.get('PATH', None) - os.environ['PATH'] = os.pathsep.join(( - self.foobar, self.foobaz, self.bazfoo, self.bazbar)) - - - def tearDown(self): - """ - Restore the saved PATH setting, and set all created files readable - again so that they can be deleted easily. - """ - os.chmod(os.path.join(self.bazbar, "executable"), stat.S_IWUSR) - if self.oldPath is None: - try: - del os.environ['PATH'] - except KeyError: - pass - else: - os.environ['PATH'] = self.oldPath - - - def test_whichWithoutPATH(self): - """ - Test that if C{os.environ} does not have a C{'PATH'} key, - L{procutils.which} returns an empty list. - """ - del os.environ['PATH'] - self.assertEqual(procutils.which("executable"), []) - - - def testWhich(self): - j = os.path.join - paths = procutils.which("executable") - expectedPaths = [j(self.foobaz, "executable"), - j(self.bazfoo, "executable")] - if runtime.platform.isWindows(): - expectedPaths.append(j(self.bazbar, "executable")) - self.assertEqual(paths, expectedPaths) - - - def testWhichPathExt(self): - j = os.path.join - old = os.environ.get('PATHEXT', None) - os.environ['PATHEXT'] = os.pathsep.join(('.bin', '.exe', '.sh')) - try: - paths = procutils.which("executable") - finally: - if old is None: - del os.environ['PATHEXT'] - else: - os.environ['PATHEXT'] = old - expectedPaths = [j(self.foobaz, "executable"), - j(self.bazfoo, "executable"), - j(self.bazfoo, "executable.bin")] - if runtime.platform.isWindows(): - expectedPaths.append(j(self.bazbar, "executable")) - self.assertEqual(paths, expectedPaths) - - - -class ClosingPipesProcessProtocol(protocol.ProcessProtocol): - output = b'' - errput = b'' - - def __init__(self, outOrErr): - self.deferred = defer.Deferred() - self.outOrErr = outOrErr - - def processEnded(self, reason): - self.deferred.callback(reason) - - def outReceived(self, data): - self.output += data - - def errReceived(self, data): - self.errput += data - - - -class ClosingPipesTests(unittest.TestCase): - - def doit(self, fd): - """ - Create a child process and close one of its output descriptors using - L{IProcessTransport.closeStdout} or L{IProcessTransport.closeStderr}. - Return a L{Deferred} which fires after verifying that the descriptor was - really closed. - """ - p = ClosingPipesProcessProtocol(True) - self.assertFailure(p.deferred, error.ProcessTerminated) - p.deferred.addCallback(self._endProcess, p) - reactor.spawnProcess( - p, pyExe, [ - pyExe, b'-u', b'-c', - networkString('try: input = raw_input\n' - 'except NameError: pass\n' - 'input()\n' - 'import sys, os, time\n' - # Give the system a bit of time to notice the closed - # descriptor. Another option would be to poll() for HUP - # instead of relying on an os.write to fail with SIGPIPE. - # However, that wouldn't work on OS X (or Windows?). - 'for i in range(1000):\n' - ' os.write(%d, b"foo\\n")\n' - ' time.sleep(0.01)\n' - 'sys.exit(42)\n' % (fd,)) - ], - env=None) - - if fd == 1: - p.transport.closeStdout() - elif fd == 2: - p.transport.closeStderr() - else: - raise RuntimeError - - # Give the close time to propagate - p.transport.write(b'go\n') - - # make the buggy case not hang - p.transport.closeStdin() - return p.deferred - - - def _endProcess(self, reason, p): - """ - Check that a failed write prevented the process from getting to its - custom exit code. - """ - # child must not get past that write without raising - self.assertNotEquals( - reason.exitCode, 42, 'process reason was %r' % reason) - self.assertEqual(p.output, b'') - return p.errput - - - def test_stdout(self): - """ - ProcessProtocol.transport.closeStdout actually closes the pipe. - """ - d = self.doit(1) - def _check(errput): - if _PY3: - self.assertIn(b'BrokenPipeError', errput) - else: - self.assertIn(b'OSError', errput) - if runtime.platform.getType() != 'win32': - self.assertIn(b'Broken pipe', errput) - d.addCallback(_check) - return d - - - def test_stderr(self): - """ - ProcessProtocol.transport.closeStderr actually closes the pipe. - """ - d = self.doit(2) - def _check(errput): - # there should be no stderr open, so nothing for it to - # write the error to. - self.assertEqual(errput, b'') - d.addCallback(_check) - return d - - -skipMessage = "wrong platform or reactor doesn't support IReactorProcess" -if (runtime.platform.getType() != 'posix') or (not interfaces.IReactorProcess(reactor, None)): - PosixProcessTests.skip = skipMessage - PosixProcessPTYTests.skip = skipMessage - TwoProcessesPosixTests.skip = skipMessage - FDTests.skip = skipMessage - -if (runtime.platform.getType() != 'win32') or (not interfaces.IReactorProcess(reactor, None)): - Win32ProcessTests.skip = skipMessage - TwoProcessesNonPosixTests.skip = skipMessage - Dumbwin32procPidTests.skip = skipMessage - Win32UnicodeEnvironmentTests.skip = skipMessage - -if not interfaces.IReactorProcess(reactor, None): - ProcessTests.skip = skipMessage - ClosingPipesTests.skip = skipMessage diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_protocols.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_protocols.py deleted file mode 100644 index 4e10b48..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_protocols.py +++ /dev/null @@ -1,236 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.protocols package. -""" - -from twisted.trial import unittest -from twisted.protocols import wire, portforward -from twisted.internet import reactor, defer, address, protocol -from twisted.test import proto_helpers - - -class WireTests(unittest.TestCase): - """ - Test wire protocols. - """ - - def test_echo(self): - """ - Test wire.Echo protocol: send some data and check it send it back. - """ - t = proto_helpers.StringTransport() - a = wire.Echo() - a.makeConnection(t) - a.dataReceived("hello") - a.dataReceived("world") - a.dataReceived("how") - a.dataReceived("are") - a.dataReceived("you") - self.assertEqual(t.value(), "helloworldhowareyou") - - - def test_who(self): - """ - Test wire.Who protocol. - """ - t = proto_helpers.StringTransport() - a = wire.Who() - a.makeConnection(t) - self.assertEqual(t.value(), "root\r\n") - - - def test_QOTD(self): - """ - Test wire.QOTD protocol. - """ - t = proto_helpers.StringTransport() - a = wire.QOTD() - a.makeConnection(t) - self.assertEqual(t.value(), - "An apple a day keeps the doctor away.\r\n") - - - def test_discard(self): - """ - Test wire.Discard protocol. - """ - t = proto_helpers.StringTransport() - a = wire.Discard() - a.makeConnection(t) - a.dataReceived("hello") - a.dataReceived("world") - a.dataReceived("how") - a.dataReceived("are") - a.dataReceived("you") - self.assertEqual(t.value(), "") - - - -class TestableProxyClientFactory(portforward.ProxyClientFactory): - """ - Test proxy client factory that keeps the last created protocol instance. - - @ivar protoInstance: the last instance of the protocol. - @type protoInstance: L{portforward.ProxyClient} - """ - - def buildProtocol(self, addr): - """ - Create the protocol instance and keeps track of it. - """ - proto = portforward.ProxyClientFactory.buildProtocol(self, addr) - self.protoInstance = proto - return proto - - - -class TestableProxyFactory(portforward.ProxyFactory): - """ - Test proxy factory that keeps the last created protocol instance. - - @ivar protoInstance: the last instance of the protocol. - @type protoInstance: L{portforward.ProxyServer} - - @ivar clientFactoryInstance: client factory used by C{protoInstance} to - create forward connections. - @type clientFactoryInstance: L{TestableProxyClientFactory} - """ - - def buildProtocol(self, addr): - """ - Create the protocol instance, keeps track of it, and makes it use - C{clientFactoryInstance} as client factory. - """ - proto = portforward.ProxyFactory.buildProtocol(self, addr) - self.clientFactoryInstance = TestableProxyClientFactory() - # Force the use of this specific instance - proto.clientProtocolFactory = lambda: self.clientFactoryInstance - self.protoInstance = proto - return proto - - - -class PortforwardingTests(unittest.TestCase): - """ - Test port forwarding. - """ - - def setUp(self): - self.serverProtocol = wire.Echo() - self.clientProtocol = protocol.Protocol() - self.openPorts = [] - - - def tearDown(self): - try: - self.proxyServerFactory.protoInstance.transport.loseConnection() - except AttributeError: - pass - try: - pi = self.proxyServerFactory.clientFactoryInstance.protoInstance - pi.transport.loseConnection() - except AttributeError: - pass - try: - self.clientProtocol.transport.loseConnection() - except AttributeError: - pass - try: - self.serverProtocol.transport.loseConnection() - except AttributeError: - pass - return defer.gatherResults( - [defer.maybeDeferred(p.stopListening) for p in self.openPorts]) - - - def test_portforward(self): - """ - Test port forwarding through Echo protocol. - """ - realServerFactory = protocol.ServerFactory() - realServerFactory.protocol = lambda: self.serverProtocol - realServerPort = reactor.listenTCP(0, realServerFactory, - interface='127.0.0.1') - self.openPorts.append(realServerPort) - self.proxyServerFactory = TestableProxyFactory('127.0.0.1', - realServerPort.getHost().port) - proxyServerPort = reactor.listenTCP(0, self.proxyServerFactory, - interface='127.0.0.1') - self.openPorts.append(proxyServerPort) - - nBytes = 1000 - received = [] - d = defer.Deferred() - - def testDataReceived(data): - received.extend(data) - if len(received) >= nBytes: - self.assertEqual(''.join(received), 'x' * nBytes) - d.callback(None) - - self.clientProtocol.dataReceived = testDataReceived - - def testConnectionMade(): - self.clientProtocol.transport.write('x' * nBytes) - - self.clientProtocol.connectionMade = testConnectionMade - - clientFactory = protocol.ClientFactory() - clientFactory.protocol = lambda: self.clientProtocol - - reactor.connectTCP( - '127.0.0.1', proxyServerPort.getHost().port, clientFactory) - - return d - - - def test_registerProducers(self): - """ - The proxy client registers itself as a producer of the proxy server and - vice versa. - """ - # create a ProxyServer instance - addr = address.IPv4Address('TCP', '127.0.0.1', 0) - server = portforward.ProxyFactory('127.0.0.1', 0).buildProtocol(addr) - - # set the reactor for this test - reactor = proto_helpers.MemoryReactor() - server.reactor = reactor - - # make the connection - serverTransport = proto_helpers.StringTransport() - server.makeConnection(serverTransport) - - # check that the ProxyClientFactory is connecting to the backend - self.assertEqual(len(reactor.tcpClients), 1) - # get the factory instance and check it's the one we expect - host, port, clientFactory, timeout, _ = reactor.tcpClients[0] - self.assertIsInstance(clientFactory, portforward.ProxyClientFactory) - - # Connect it - client = clientFactory.buildProtocol(addr) - clientTransport = proto_helpers.StringTransport() - client.makeConnection(clientTransport) - - # check that the producers are registered - self.assertIdentical(clientTransport.producer, serverTransport) - self.assertIdentical(serverTransport.producer, clientTransport) - # check the streaming attribute in both transports - self.assertTrue(clientTransport.streaming) - self.assertTrue(serverTransport.streaming) - - - -class StringTransportTests(unittest.TestCase): - """ - Test L{proto_helpers.StringTransport} helper behaviour. - """ - - def test_noUnicode(self): - """ - Test that L{proto_helpers.StringTransport} doesn't accept unicode data. - """ - s = proto_helpers.StringTransport() - self.assertRaises(TypeError, s.write, u'foo') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_randbytes.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_randbytes.py deleted file mode 100644 index 5e20da5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_randbytes.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.python.randbytes}. -""" - -from __future__ import division, absolute_import - -from twisted.trial import unittest -from twisted.python import randbytes - - - -class SecureRandomTestCaseBase(object): - """ - Base class for secureRandom test cases. - """ - - def _check(self, source): - """ - The given random bytes source should return the number of bytes - requested each time it is called and should probably not return the - same bytes on two consecutive calls (although this is a perfectly - legitimate occurrence and rejecting it may generate a spurious failure - -- maybe we'll get lucky and the heat death with come first). - """ - for nbytes in range(17, 25): - s = source(nbytes) - self.assertEqual(len(s), nbytes) - s2 = source(nbytes) - self.assertEqual(len(s2), nbytes) - # This is crude but hey - self.assertNotEquals(s2, s) - - - -class SecureRandomTests(SecureRandomTestCaseBase, unittest.TestCase): - """ - Test secureRandom under normal conditions. - """ - - def test_normal(self): - """ - L{randbytes.secureRandom} should return a string of the requested - length and make some effort to make its result otherwise unpredictable. - """ - self._check(randbytes.secureRandom) - - - -class ConditionalSecureRandomTests(SecureRandomTestCaseBase, - unittest.SynchronousTestCase): - """ - Test random sources one by one, then remove it to. - """ - - def setUp(self): - """ - Create a L{randbytes.RandomFactory} to use in the tests. - """ - self.factory = randbytes.RandomFactory() - - - def errorFactory(self, nbytes): - """ - A factory raising an error when a source is not available. - """ - raise randbytes.SourceNotAvailable() - - - def test_osUrandom(self): - """ - L{RandomFactory._osUrandom} should work as a random source whenever - L{os.urandom} is available. - """ - self._check(self.factory._osUrandom) - - - def test_withoutAnything(self): - """ - Remove all secure sources and assert it raises a failure. Then try the - fallback parameter. - """ - self.factory._osUrandom = self.errorFactory - self.assertRaises(randbytes.SecureRandomNotAvailable, - self.factory.secureRandom, 18) - def wrapper(): - return self.factory.secureRandom(18, fallback=True) - s = self.assertWarns( - RuntimeWarning, - "urandom unavailable - " - "proceeding with non-cryptographically secure random source", - __file__, - wrapper) - self.assertEqual(len(s), 18) - - - -class RandomBaseTests(SecureRandomTestCaseBase, unittest.SynchronousTestCase): - """ - 'Normal' random test cases. - """ - - def test_normal(self): - """ - Test basic case. - """ - self._check(randbytes.insecureRandom) - - - def test_withoutGetrandbits(self): - """ - Test C{insecureRandom} without C{random.getrandbits}. - """ - factory = randbytes.RandomFactory() - factory.getrandbits = None - self._check(factory.insecureRandom) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_rebuild.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_rebuild.py deleted file mode 100644 index 7a6158f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_rebuild.py +++ /dev/null @@ -1,252 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -import sys, os -import types - -from twisted.trial import unittest -from twisted.python import rebuild - -import crash_test_dummy -f = crash_test_dummy.foo - -class Foo: pass -class Bar(Foo): pass -class Baz(object): pass -class Buz(Bar, Baz): pass - -class HashRaisesRuntimeError: - """ - Things that don't hash (raise an Exception) should be ignored by the - rebuilder. - - @ivar hashCalled: C{bool} set to True when __hash__ is called. - """ - def __init__(self): - self.hashCalled = False - - def __hash__(self): - self.hashCalled = True - raise RuntimeError('not a TypeError!') - - - -unhashableObject = None # set in test_hashException - - - -class RebuildTests(unittest.TestCase): - """ - Simple testcase for rebuilding, to at least exercise the code. - """ - def setUp(self): - self.libPath = self.mktemp() - os.mkdir(self.libPath) - self.fakelibPath = os.path.join(self.libPath, 'twisted_rebuild_fakelib') - os.mkdir(self.fakelibPath) - file(os.path.join(self.fakelibPath, '__init__.py'), 'w').close() - sys.path.insert(0, self.libPath) - - def tearDown(self): - sys.path.remove(self.libPath) - - def testFileRebuild(self): - from twisted.python.util import sibpath - import shutil, time - shutil.copyfile(sibpath(__file__, "myrebuilder1.py"), - os.path.join(self.fakelibPath, "myrebuilder.py")) - from twisted_rebuild_fakelib import myrebuilder - a = myrebuilder.A() - try: - object - except NameError: - pass - else: - from twisted.test import test_rebuild - b = myrebuilder.B() - class C(myrebuilder.B): - pass - test_rebuild.C = C - C() - i = myrebuilder.Inherit() - self.assertEqual(a.a(), 'a') - # necessary because the file has not "changed" if a second has not gone - # by in unix. This sucks, but it's not often that you'll be doing more - # than one reload per second. - time.sleep(1.1) - shutil.copyfile(sibpath(__file__, "myrebuilder2.py"), - os.path.join(self.fakelibPath, "myrebuilder.py")) - rebuild.rebuild(myrebuilder) - try: - object - except NameError: - pass - else: - b2 = myrebuilder.B() - self.assertEqual(b2.b(), 'c') - self.assertEqual(b.b(), 'c') - self.assertEqual(i.a(), 'd') - self.assertEqual(a.a(), 'b') - # more work to be done on new-style classes - # self.assertEqual(c.b(), 'c') - - def testRebuild(self): - """ - Rebuilding an unchanged module. - """ - # This test would actually pass if rebuild was a no-op, but it - # ensures rebuild doesn't break stuff while being a less - # complex test than testFileRebuild. - - x = crash_test_dummy.X('a') - - rebuild.rebuild(crash_test_dummy, doLog=False) - # Instance rebuilding is triggered by attribute access. - x.do() - self.failUnlessIdentical(x.__class__, crash_test_dummy.X) - - self.failUnlessIdentical(f, crash_test_dummy.foo) - - def testComponentInteraction(self): - x = crash_test_dummy.XComponent() - x.setAdapter(crash_test_dummy.IX, crash_test_dummy.XA) - x.getComponent(crash_test_dummy.IX) - rebuild.rebuild(crash_test_dummy, 0) - newComponent = x.getComponent(crash_test_dummy.IX) - - newComponent.method() - - self.assertEqual(newComponent.__class__, crash_test_dummy.XA) - - # Test that a duplicate registerAdapter is not allowed - from twisted.python import components - self.failUnlessRaises(ValueError, components.registerAdapter, - crash_test_dummy.XA, crash_test_dummy.X, - crash_test_dummy.IX) - - def testUpdateInstance(self): - global Foo, Buz - - b = Buz() - - class Foo: - def foo(self): - pass - class Buz(Bar, Baz): - x = 10 - - rebuild.updateInstance(b) - assert hasattr(b, 'foo'), "Missing method on rebuilt instance" - assert hasattr(b, 'x'), "Missing class attribute on rebuilt instance" - - def testBananaInteraction(self): - from twisted.python import rebuild - from twisted.spread import banana - rebuild.latestClass(banana.Banana) - - - def test_hashException(self): - """ - Rebuilding something that has a __hash__ that raises a non-TypeError - shouldn't cause rebuild to die. - """ - global unhashableObject - unhashableObject = HashRaisesRuntimeError() - def _cleanup(): - global unhashableObject - unhashableObject = None - self.addCleanup(_cleanup) - rebuild.rebuild(rebuild) - self.assertEqual(unhashableObject.hashCalled, True) - - - -class NewStyleTests(unittest.TestCase): - """ - Tests for rebuilding new-style classes of various sorts. - """ - def setUp(self): - self.m = types.ModuleType('whipping') - sys.modules['whipping'] = self.m - - - def tearDown(self): - del sys.modules['whipping'] - del self.m - - - def test_slots(self): - """ - Try to rebuild a new style class with slots defined. - """ - classDefinition = ( - "class SlottedClass(object):\n" - " __slots__ = ['a']\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.SlottedClass() - inst.a = 7 - exec classDefinition in self.m.__dict__ - rebuild.updateInstance(inst) - self.assertEqual(inst.a, 7) - self.assertIdentical(type(inst), self.m.SlottedClass) - - if sys.version_info < (2, 6): - test_slots.skip = "__class__ assignment for class with slots is only available starting Python 2.6" - - - def test_errorSlots(self): - """ - Try to rebuild a new style class with slots defined: this should fail. - """ - classDefinition = ( - "class SlottedClass(object):\n" - " __slots__ = ['a']\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.SlottedClass() - inst.a = 7 - exec classDefinition in self.m.__dict__ - self.assertRaises(rebuild.RebuildError, rebuild.updateInstance, inst) - - if sys.version_info >= (2, 6): - test_errorSlots.skip = "__class__ assignment for class with slots should work starting Python 2.6" - - - def test_typeSubclass(self): - """ - Try to rebuild a base type subclass. - """ - classDefinition = ( - "class ListSubclass(list):\n" - " pass\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.ListSubclass() - inst.append(2) - exec classDefinition in self.m.__dict__ - rebuild.updateInstance(inst) - self.assertEqual(inst[0], 2) - self.assertIdentical(type(inst), self.m.ListSubclass) - - - def test_instanceSlots(self): - """ - Test that when rebuilding an instance with a __slots__ attribute, it - fails accurately instead of giving a L{rebuild.RebuildError}. - """ - classDefinition = ( - "class NotSlottedClass(object):\n" - " pass\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.NotSlottedClass() - inst.__slots__ = ['a'] - classDefinition = ( - "class NotSlottedClass:\n" - " pass\n") - exec classDefinition in self.m.__dict__ - # Moving from new-style class to old-style should fail. - self.assertRaises(TypeError, rebuild.updateInstance, inst) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_reflect.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_reflect.py deleted file mode 100644 index 2745629..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_reflect.py +++ /dev/null @@ -1,946 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for the L{twisted.python.reflect} module. -""" - -from __future__ import division, absolute_import - -import os -import weakref -from collections import deque - -from twisted.python.compat import _PY3 -from twisted.trial import unittest -from twisted.trial.unittest import SynchronousTestCase as TestCase -from twisted.python import reflect -from twisted.python.reflect import ( - accumulateMethods, prefixedMethods, prefixedMethodNames, - addMethodNamesToDict, fullyQualifiedName) -from twisted.python.versions import Version - - -class Base(object): - """ - A no-op class which can be used to verify the behavior of - method-discovering APIs. - """ - - def method(self): - """ - A no-op method which can be discovered. - """ - - - -class Sub(Base): - """ - A subclass of a class with a method which can be discovered. - """ - - - -class Separate(object): - """ - A no-op class with methods with differing prefixes. - """ - - def good_method(self): - """ - A no-op method which a matching prefix to be discovered. - """ - - - def bad_method(self): - """ - A no-op method with a mismatched prefix to not be discovered. - """ - - - -class AccumulateMethodsTests(TestCase): - """ - Tests for L{accumulateMethods} which finds methods on a class hierarchy and - adds them to a dictionary. - """ - - def test_ownClass(self): - """ - If x is and instance of Base and Base defines a method named method, - L{accumulateMethods} adds an item to the given dictionary with - C{"method"} as the key and a bound method object for Base.method value. - """ - x = Base() - output = {} - accumulateMethods(x, output) - self.assertEqual({"method": x.method}, output) - - - def test_baseClass(self): - """ - If x is an instance of Sub and Sub is a subclass of Base and Base - defines a method named method, L{accumulateMethods} adds an item to the - given dictionary with C{"method"} as the key and a bound method object - for Base.method as the value. - """ - x = Sub() - output = {} - accumulateMethods(x, output) - self.assertEqual({"method": x.method}, output) - - - def test_prefix(self): - """ - If a prefix is given, L{accumulateMethods} limits its results to - methods beginning with that prefix. Keys in the resulting dictionary - also have the prefix removed from them. - """ - x = Separate() - output = {} - accumulateMethods(x, output, 'good_') - self.assertEqual({'method': x.good_method}, output) - - - -class PrefixedMethodsTests(TestCase): - """ - Tests for L{prefixedMethods} which finds methods on a class hierarchy and - adds them to a dictionary. - """ - - def test_onlyObject(self): - """ - L{prefixedMethods} returns a list of the methods discovered on an - object. - """ - x = Base() - output = prefixedMethods(x) - self.assertEqual([x.method], output) - - - def test_prefix(self): - """ - If a prefix is given, L{prefixedMethods} returns only methods named - with that prefix. - """ - x = Separate() - output = prefixedMethods(x, 'good_') - self.assertEqual([x.good_method], output) - - - -class PrefixedMethodNamesTests(TestCase): - """ - Tests for L{prefixedMethodNames}. - """ - def test_method(self): - """ - L{prefixedMethodNames} returns a list including methods with the given - prefix defined on the class passed to it. - """ - self.assertEqual(["method"], prefixedMethodNames(Separate, "good_")) - - - def test_inheritedMethod(self): - """ - L{prefixedMethodNames} returns a list included methods with the given - prefix defined on base classes of the class passed to it. - """ - class Child(Separate): - pass - self.assertEqual(["method"], prefixedMethodNames(Child, "good_")) - - - -class AddMethodNamesToDictTests(TestCase): - """ - Tests for L{addMethodNamesToDict}. - """ - def test_baseClass(self): - """ - If C{baseClass} is passed to L{addMethodNamesToDict}, only methods which - are a subclass of C{baseClass} are added to the result dictionary. - """ - class Alternate(object): - pass - - class Child(Separate, Alternate): - def good_alternate(self): - pass - - result = {} - addMethodNamesToDict(Child, result, 'good_', Alternate) - self.assertEqual({'alternate': 1}, result) - - - -class Summer(object): - """ - A class we look up as part of the LookupsTests. - """ - - def reallySet(self): - """ - Do something. - """ - - - -class LookupsTests(TestCase): - """ - Tests for L{namedClass}, L{namedModule}, and L{namedAny}. - """ - - def test_namedClassLookup(self): - """ - L{namedClass} should return the class object for the name it is passed. - """ - self.assertIdentical( - reflect.namedClass("twisted.test.test_reflect.Summer"), - Summer) - - - def test_namedModuleLookup(self): - """ - L{namedModule} should return the module object for the name it is - passed. - """ - from twisted.python import monkey - self.assertIdentical( - reflect.namedModule("twisted.python.monkey"), monkey) - - - def test_namedAnyPackageLookup(self): - """ - L{namedAny} should return the package object for the name it is passed. - """ - import twisted.python - self.assertIdentical( - reflect.namedAny("twisted.python"), twisted.python) - - - def test_namedAnyModuleLookup(self): - """ - L{namedAny} should return the module object for the name it is passed. - """ - from twisted.python import monkey - self.assertIdentical( - reflect.namedAny("twisted.python.monkey"), monkey) - - - def test_namedAnyClassLookup(self): - """ - L{namedAny} should return the class object for the name it is passed. - """ - self.assertIdentical( - reflect.namedAny("twisted.test.test_reflect.Summer"), - Summer) - - - def test_namedAnyAttributeLookup(self): - """ - L{namedAny} should return the object an attribute of a non-module, - non-package object is bound to for the name it is passed. - """ - # Note - not assertIs because unbound method lookup creates a new - # object every time. This is a foolishness of Python's object - # implementation, not a bug in Twisted. - self.assertEqual( - reflect.namedAny( - "twisted.test.test_reflect.Summer.reallySet"), - Summer.reallySet) - - - def test_namedAnySecondAttributeLookup(self): - """ - L{namedAny} should return the object an attribute of an object which - itself was an attribute of a non-module, non-package object is bound to - for the name it is passed. - """ - self.assertIdentical( - reflect.namedAny( - "twisted.test.test_reflect." - "Summer.reallySet.__doc__"), - Summer.reallySet.__doc__) - - - def test_importExceptions(self): - """ - Exceptions raised by modules which L{namedAny} causes to be imported - should pass through L{namedAny} to the caller. - """ - self.assertRaises( - ZeroDivisionError, - reflect.namedAny, "twisted.test.reflect_helper_ZDE") - # Make sure that there is post-failed-import cleanup - self.assertRaises( - ZeroDivisionError, - reflect.namedAny, "twisted.test.reflect_helper_ZDE") - self.assertRaises( - ValueError, - reflect.namedAny, "twisted.test.reflect_helper_VE") - # Modules which themselves raise ImportError when imported should - # result in an ImportError - self.assertRaises( - ImportError, - reflect.namedAny, "twisted.test.reflect_helper_IE") - - - def test_attributeExceptions(self): - """ - If segments on the end of a fully-qualified Python name represents - attributes which aren't actually present on the object represented by - the earlier segments, L{namedAny} should raise an L{AttributeError}. - """ - self.assertRaises( - AttributeError, - reflect.namedAny, "twisted.nosuchmoduleintheworld") - # ImportError behaves somewhat differently between "import - # extant.nonextant" and "import extant.nonextant.nonextant", so test - # the latter as well. - self.assertRaises( - AttributeError, - reflect.namedAny, "twisted.nosuch.modulein.theworld") - self.assertRaises( - AttributeError, - reflect.namedAny, - "twisted.test.test_reflect.Summer.nosuchattribute") - - - def test_invalidNames(self): - """ - Passing a name which isn't a fully-qualified Python name to L{namedAny} - should result in one of the following exceptions: - - L{InvalidName}: the name is not a dot-separated list of Python - objects - - L{ObjectNotFound}: the object doesn't exist - - L{ModuleNotFound}: the object doesn't exist and there is only one - component in the name - """ - err = self.assertRaises(reflect.ModuleNotFound, reflect.namedAny, - 'nosuchmoduleintheworld') - self.assertEqual(str(err), "No module named 'nosuchmoduleintheworld'") - - # This is a dot-separated list, but it isn't valid! - err = self.assertRaises(reflect.ObjectNotFound, reflect.namedAny, - "@#$@(#.!@(#!@#") - self.assertEqual(str(err), "'@#$@(#.!@(#!@#' does not name an object") - - err = self.assertRaises(reflect.ObjectNotFound, reflect.namedAny, - "tcelfer.nohtyp.detsiwt") - self.assertEqual( - str(err), - "'tcelfer.nohtyp.detsiwt' does not name an object") - - err = self.assertRaises(reflect.InvalidName, reflect.namedAny, '') - self.assertEqual(str(err), 'Empty module name') - - for invalidName in ['.twisted', 'twisted.', 'twisted..python']: - err = self.assertRaises( - reflect.InvalidName, reflect.namedAny, invalidName) - self.assertEqual( - str(err), - "name must be a string giving a '.'-separated list of Python " - "identifiers, not %r" % (invalidName,)) - - - def test_requireModuleImportError(self): - """ - When module import fails with ImportError it returns the specified - default value. - """ - for name in ['nosuchmtopodule', 'no.such.module']: - default = object() - - result = reflect.requireModule(name, default=default) - - self.assertIs(result, default) - - - def test_requireModuleDefaultNone(self): - """ - When module import fails it returns C{None} by default. - """ - result = reflect.requireModule('no.such.module') - - self.assertIs(None, result) - - - def test_requireModuleRequestedImport(self): - """ - When module import succeed it returns the module and not the default - value. - """ - from twisted.python import monkey - default = object() - - self.assertIs( - reflect.requireModule('twisted.python.monkey', default=default), - monkey, - ) - - - -class Breakable(object): - - breakRepr = False - breakStr = False - - def __str__(self): - if self.breakStr: - raise RuntimeError("str!") - else: - return '' - - - def __repr__(self): - if self.breakRepr: - raise RuntimeError("repr!") - else: - return 'Breakable()' - - - -class BrokenType(Breakable, type): - breakName = False - - def get___name__(self): - if self.breakName: - raise RuntimeError("no name") - return 'BrokenType' - __name__ = property(get___name__) - - - -BTBase = BrokenType('BTBase', (Breakable,), - {"breakRepr": True, - "breakStr": True}) - - - -class NoClassAttr(Breakable): - __class__ = property(lambda x: x.not_class) - - - -class SafeReprTests(TestCase): - """ - Tests for L{reflect.safe_repr} function. - """ - - def test_workingRepr(self): - """ - L{reflect.safe_repr} produces the same output as C{repr} on a working - object. - """ - xs = ([1, 2, 3], b'a') - self.assertEqual(list(map(reflect.safe_repr, xs)), list(map(repr, xs))) - - - def test_brokenRepr(self): - """ - L{reflect.safe_repr} returns a string with class name, address, and - traceback when the repr call failed. - """ - b = Breakable() - b.breakRepr = True - bRepr = reflect.safe_repr(b) - self.assertIn("Breakable instance at 0x", bRepr) - # Check that the file is in the repr, but without the extension as it - # can be .py/.pyc - self.assertIn(os.path.splitext(__file__)[0], bRepr) - self.assertIn("RuntimeError: repr!", bRepr) - - - def test_brokenStr(self): - """ - L{reflect.safe_repr} isn't affected by a broken C{__str__} method. - """ - b = Breakable() - b.breakStr = True - self.assertEqual(reflect.safe_repr(b), repr(b)) - - - def test_brokenClassRepr(self): - class X(BTBase): - breakRepr = True - reflect.safe_repr(X) - reflect.safe_repr(X()) - - - def test_brokenReprIncludesID(self): - """ - C{id} is used to print the ID of the object in case of an error. - - L{safe_repr} includes a traceback after a newline, so we only check - against the first line of the repr. - """ - class X(BTBase): - breakRepr = True - - xRepr = reflect.safe_repr(X) - xReprExpected = ('= (2, 7): - self.assertIdentical( - None, found, - "Should not have found twisted.python._initgroups extension " - "definition.") - else: - self.assertNotIdentical( - None, found, - "Should have found twisted.python._initgroups extension " - "definition.") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_shortcut.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_shortcut.py deleted file mode 100644 index 7ded805..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_shortcut.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Test win32 shortcut script -""" - -from twisted.trial import unittest - -import os -if os.name == 'nt': - - skipWindowsNopywin32 = None - try: - from twisted.python import shortcut - except ImportError: - skipWindowsNopywin32 = ("On windows, twisted.python.shortcut is not " - "available in the absence of win32com.") - import os.path - - class ShortcutTests(unittest.TestCase): - def testCreate(self): - s1=shortcut.Shortcut("test_shortcut.py") - tempname=self.mktemp() + '.lnk' - s1.save(tempname) - self.assert_(os.path.exists(tempname)) - sc=shortcut.open(tempname) - self.assert_(sc.GetPath(0)[0].endswith('test_shortcut.py')) - ShortcutTests.skip = skipWindowsNopywin32 diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sip.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sip.py deleted file mode 100644 index b2c895c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sip.py +++ /dev/null @@ -1,982 +0,0 @@ -# -*- test-case-name: twisted.test.test_sip -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Session Initialization Protocol tests.""" - -from twisted.trial import unittest, util -from twisted.protocols import sip -from twisted.internet import defer, reactor, utils -from twisted.python.versions import Version - -from twisted.test import proto_helpers - -from twisted import cred - -from zope.interface import implements - - -# request, prefixed by random CRLFs -request1 = "\n\r\n\n\r" + """\ -INVITE sip:foo SIP/2.0 -From: mo -To: joe -Content-Length: 4 - -abcd""".replace("\n", "\r\n") - -# request, no content-length -request2 = """INVITE sip:foo SIP/2.0 -From: mo -To: joe - -1234""".replace("\n", "\r\n") - -# request, with garbage after -request3 = """INVITE sip:foo SIP/2.0 -From: mo -To: joe -Content-Length: 4 - -1234 - -lalalal""".replace("\n", "\r\n") - -# three requests -request4 = """INVITE sip:foo SIP/2.0 -From: mo -To: joe -Content-Length: 0 - -INVITE sip:loop SIP/2.0 -From: foo -To: bar -Content-Length: 4 - -abcdINVITE sip:loop SIP/2.0 -From: foo -To: bar -Content-Length: 4 - -1234""".replace("\n", "\r\n") - -# response, no content -response1 = """SIP/2.0 200 OK -From: foo -To:bar -Content-Length: 0 - -""".replace("\n", "\r\n") - -# short header version -request_short = """\ -INVITE sip:foo SIP/2.0 -f: mo -t: joe -l: 4 - -abcd""".replace("\n", "\r\n") - -request_natted = """\ -INVITE sip:foo SIP/2.0 -Via: SIP/2.0/UDP 10.0.0.1:5060;rport - -""".replace("\n", "\r\n") - -# multiline headers (example from RFC 3621). -response_multiline = """\ -SIP/2.0 200 OK -Via: SIP/2.0/UDP server10.biloxi.com - ;branch=z9hG4bKnashds8;received=192.0.2.3 -Via: SIP/2.0/UDP bigbox3.site3.atlanta.com - ;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2 -Via: SIP/2.0/UDP pc33.atlanta.com - ;branch=z9hG4bK776asdhds ;received=192.0.2.1 -To: Bob ;tag=a6c85cf -From: Alice ;tag=1928301774 -Call-ID: a84b4c76e66710@pc33.atlanta.com -CSeq: 314159 INVITE -Contact: -Content-Type: application/sdp -Content-Length: 0 -\n""".replace("\n", "\r\n") - -class TestRealm: - def requestAvatar(self, avatarId, mind, *interfaces): - return sip.IContact, None, lambda: None - -class MessageParsingTests(unittest.TestCase): - def setUp(self): - self.l = [] - self.parser = sip.MessagesParser(self.l.append) - - def feedMessage(self, message): - self.parser.dataReceived(message) - self.parser.dataDone() - - def validateMessage(self, m, method, uri, headers, body): - """Validate Requests.""" - self.assertEqual(m.method, method) - self.assertEqual(m.uri.toString(), uri) - self.assertEqual(m.headers, headers) - self.assertEqual(m.body, body) - self.assertEqual(m.finished, 1) - - def testSimple(self): - l = self.l - self.feedMessage(request1) - self.assertEqual(len(l), 1) - self.validateMessage( - l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "abcd") - - def testTwoMessages(self): - l = self.l - self.feedMessage(request1) - self.feedMessage(request2) - self.assertEqual(len(l), 2) - self.validateMessage( - l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "abcd") - self.validateMessage(l[1], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"]}, - "1234") - - def testGarbage(self): - l = self.l - self.feedMessage(request3) - self.assertEqual(len(l), 1) - self.validateMessage( - l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "1234") - - def testThreeInOne(self): - l = self.l - self.feedMessage(request4) - self.assertEqual(len(l), 3) - self.validateMessage( - l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["0"]}, - "") - self.validateMessage( - l[1], "INVITE", "sip:loop", - {"from": ["foo"], "to": ["bar"], "content-length": ["4"]}, - "abcd") - self.validateMessage( - l[2], "INVITE", "sip:loop", - {"from": ["foo"], "to": ["bar"], "content-length": ["4"]}, - "1234") - - def testShort(self): - l = self.l - self.feedMessage(request_short) - self.assertEqual(len(l), 1) - self.validateMessage( - l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "abcd") - - def testSimpleResponse(self): - l = self.l - self.feedMessage(response1) - self.assertEqual(len(l), 1) - m = l[0] - self.assertEqual(m.code, 200) - self.assertEqual(m.phrase, "OK") - self.assertEqual( - m.headers, - {"from": ["foo"], "to": ["bar"], "content-length": ["0"]}) - self.assertEqual(m.body, "") - self.assertEqual(m.finished, 1) - - - def test_multiLine(self): - """ - A header may be split across multiple lines. Subsequent lines begin - with C{" "} or C{"\\t"}. - """ - l = self.l - self.feedMessage(response_multiline) - self.assertEquals(len(l), 1) - m = l[0] - self.assertEquals( - m.headers['via'][0], - "SIP/2.0/UDP server10.biloxi.com;" - "branch=z9hG4bKnashds8;received=192.0.2.3") - self.assertEquals( - m.headers['via'][1], - "SIP/2.0/UDP bigbox3.site3.atlanta.com;" - "branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2") - self.assertEquals( - m.headers['via'][2], - "SIP/2.0/UDP pc33.atlanta.com;" - "branch=z9hG4bK776asdhds ;received=192.0.2.1") - - - -class MessageParsingFeedDataCharByCharTests(MessageParsingTests): - """Same as base class, but feed data char by char.""" - - def feedMessage(self, message): - for c in message: - self.parser.dataReceived(c) - self.parser.dataDone() - - -class MakeMessageTests(unittest.TestCase): - - def testRequest(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("foo", "bar") - self.assertEqual( - r.toString(), - "INVITE sip:foo SIP/2.0\r\nFoo: bar\r\n\r\n") - - def testResponse(self): - r = sip.Response(200, "OK") - r.addHeader("foo", "bar") - r.addHeader("Content-Length", "4") - r.bodyDataReceived("1234") - self.assertEqual( - r.toString(), - "SIP/2.0 200 OK\r\nFoo: bar\r\nContent-Length: 4\r\n\r\n1234") - - def testStatusCode(self): - r = sip.Response(200) - self.assertEqual(r.toString(), "SIP/2.0 200 OK\r\n\r\n") - - -class ViaTests(unittest.TestCase): - - def checkRoundtrip(self, v): - s = v.toString() - self.assertEqual(s, sip.parseViaHeader(s).toString()) - - def testExtraWhitespace(self): - v1 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060') - v2 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060') - self.assertEqual(v1.transport, v2.transport) - self.assertEqual(v1.host, v2.host) - self.assertEqual(v1.port, v2.port) - - def test_complex(self): - """ - Test parsing a Via header with one of everything. - """ - s = ("SIP/2.0/UDP first.example.com:4000;ttl=16;maddr=224.2.0.1" - " ;branch=a7c6a8dlze (Example)") - v = sip.parseViaHeader(s) - self.assertEqual(v.transport, "UDP") - self.assertEqual(v.host, "first.example.com") - self.assertEqual(v.port, 4000) - self.assertEqual(v.rport, None) - self.assertEqual(v.rportValue, None) - self.assertEqual(v.rportRequested, False) - self.assertEqual(v.ttl, 16) - self.assertEqual(v.maddr, "224.2.0.1") - self.assertEqual(v.branch, "a7c6a8dlze") - self.assertEqual(v.hidden, 0) - self.assertEqual(v.toString(), - "SIP/2.0/UDP first.example.com:4000" - ";ttl=16;branch=a7c6a8dlze;maddr=224.2.0.1") - self.checkRoundtrip(v) - - def test_simple(self): - """ - Test parsing a simple Via header. - """ - s = "SIP/2.0/UDP example.com;hidden" - v = sip.parseViaHeader(s) - self.assertEqual(v.transport, "UDP") - self.assertEqual(v.host, "example.com") - self.assertEqual(v.port, 5060) - self.assertEqual(v.rport, None) - self.assertEqual(v.rportValue, None) - self.assertEqual(v.rportRequested, False) - self.assertEqual(v.ttl, None) - self.assertEqual(v.maddr, None) - self.assertEqual(v.branch, None) - self.assertEqual(v.hidden, True) - self.assertEqual(v.toString(), - "SIP/2.0/UDP example.com:5060;hidden") - self.checkRoundtrip(v) - - def testSimpler(self): - v = sip.Via("example.com") - self.checkRoundtrip(v) - - - def test_deprecatedRPort(self): - """ - Setting rport to True is deprecated, but still produces a Via header - with the expected properties. - """ - v = sip.Via("foo.bar", rport=True) - - warnings = self.flushWarnings( - offendingFunctions=[self.test_deprecatedRPort]) - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], - 'rport=True is deprecated since Twisted 9.0.') - self.assertEqual( - warnings[0]['category'], - DeprecationWarning) - - self.assertEqual(v.toString(), "SIP/2.0/UDP foo.bar:5060;rport") - self.assertEqual(v.rport, True) - self.assertEqual(v.rportRequested, True) - self.assertEqual(v.rportValue, None) - - - def test_rport(self): - """ - An rport setting of None should insert the parameter with no value. - """ - v = sip.Via("foo.bar", rport=None) - self.assertEqual(v.toString(), "SIP/2.0/UDP foo.bar:5060;rport") - self.assertEqual(v.rportRequested, True) - self.assertEqual(v.rportValue, None) - - - def test_rportValue(self): - """ - An rport numeric setting should insert the parameter with the number - value given. - """ - v = sip.Via("foo.bar", rport=1) - self.assertEqual(v.toString(), "SIP/2.0/UDP foo.bar:5060;rport=1") - self.assertEqual(v.rportRequested, False) - self.assertEqual(v.rportValue, 1) - self.assertEqual(v.rport, 1) - - - def testNAT(self): - s = "SIP/2.0/UDP 10.0.0.1:5060;received=22.13.1.5;rport=12345" - v = sip.parseViaHeader(s) - self.assertEqual(v.transport, "UDP") - self.assertEqual(v.host, "10.0.0.1") - self.assertEqual(v.port, 5060) - self.assertEqual(v.received, "22.13.1.5") - self.assertEqual(v.rport, 12345) - - self.assertNotEquals(v.toString().find("rport=12345"), -1) - - - def test_unknownParams(self): - """ - Parsing and serializing Via headers with unknown parameters should work. - """ - s = "SIP/2.0/UDP example.com:5060;branch=a12345b;bogus;pie=delicious" - v = sip.parseViaHeader(s) - self.assertEqual(v.toString(), s) - - - -class URLTests(unittest.TestCase): - - def testRoundtrip(self): - for url in [ - "sip:j.doe@big.com", - "sip:j.doe:secret@big.com;transport=tcp", - "sip:j.doe@big.com?subject=project", - "sip:example.com", - ]: - self.assertEqual(sip.parseURL(url).toString(), url) - - def testComplex(self): - s = ("sip:user:pass@hosta:123;transport=udp;user=phone;method=foo;" - "ttl=12;maddr=1.2.3.4;blah;goo=bar?a=b&c=d") - url = sip.parseURL(s) - for k, v in [("username", "user"), ("password", "pass"), - ("host", "hosta"), ("port", 123), - ("transport", "udp"), ("usertype", "phone"), - ("method", "foo"), ("ttl", 12), - ("maddr", "1.2.3.4"), ("other", ["blah", "goo=bar"]), - ("headers", {"a": "b", "c": "d"})]: - self.assertEqual(getattr(url, k), v) - - -class ParseTests(unittest.TestCase): - - def testParseAddress(self): - for address, name, urls, params in [ - ('"A. G. Bell" ', - "A. G. Bell", "sip:foo@example.com", {}), - ("Anon ", "Anon", "sip:foo@example.com", {}), - ("sip:foo@example.com", "", "sip:foo@example.com", {}), - ("", "", "sip:foo@example.com", {}), - ("foo ;tag=bar;foo=baz", "foo", - "sip:foo@example.com", {"tag": "bar", "foo": "baz"}), - ]: - gname, gurl, gparams = sip.parseAddress(address) - self.assertEqual(name, gname) - self.assertEqual(gurl.toString(), urls) - self.assertEqual(gparams, params) - - -class DummyLocator: - implements(sip.ILocator) - def getAddress(self, logicalURL): - return defer.succeed(sip.URL("server.com", port=5060)) - -class FailingLocator: - implements(sip.ILocator) - def getAddress(self, logicalURL): - return defer.fail(LookupError()) - - -class ProxyTests(unittest.TestCase): - - def setUp(self): - self.proxy = sip.Proxy("127.0.0.1") - self.proxy.locator = DummyLocator() - self.sent = [] - self.proxy.sendMessage = lambda dest, msg: self.sent.append((dest, msg)) - - def testRequestForward(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("via", sip.Via("1.2.3.5").toString()) - r.addHeader("foo", "bar") - r.addHeader("to", "") - r.addHeader("contact", "") - self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060)) - self.assertEqual(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEqual(dest.port, 5060) - self.assertEqual(dest.host, "server.com") - self.assertEqual(m.uri.toString(), "sip:foo") - self.assertEqual(m.method, "INVITE") - self.assertEqual(m.headers["via"], - ["SIP/2.0/UDP 127.0.0.1:5060", - "SIP/2.0/UDP 1.2.3.4:5060", - "SIP/2.0/UDP 1.2.3.5:5060"]) - - - def testReceivedRequestForward(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("foo", "bar") - r.addHeader("to", "") - r.addHeader("contact", "") - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - dest, m = self.sent[0] - self.assertEqual(m.headers["via"], - ["SIP/2.0/UDP 127.0.0.1:5060", - "SIP/2.0/UDP 1.2.3.4:5060;received=1.1.1.1"]) - - - def testResponseWrongVia(self): - # first via must match proxy's address - r = sip.Response(200) - r.addHeader("via", sip.Via("foo.com").toString()) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEqual(len(self.sent), 0) - - def testResponseForward(self): - r = sip.Response(200) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - r.addHeader("via", sip.Via("client.com", port=1234).toString()) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEqual(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEqual((dest.host, dest.port), ("client.com", 1234)) - self.assertEqual(m.code, 200) - self.assertEqual(m.headers["via"], ["SIP/2.0/UDP client.com:1234"]) - - def testReceivedResponseForward(self): - r = sip.Response(200) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - r.addHeader( - "via", - sip.Via("10.0.0.1", received="client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEqual(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEqual((dest.host, dest.port), ("client.com", 5060)) - - def testResponseToUs(self): - r = sip.Response(200) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - l = [] - self.proxy.gotResponse = lambda *a: l.append(a) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEqual(len(l), 1) - m, addr = l[0] - self.assertEqual(len(m.headers.get("via", [])), 0) - self.assertEqual(m.code, 200) - - def testLoop(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEqual(self.sent, []) - - def testCantForwardRequest(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("to", "") - self.proxy.locator = FailingLocator() - self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060)) - self.assertEqual(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEqual((dest.host, dest.port), ("1.2.3.4", 5060)) - self.assertEqual(m.code, 404) - self.assertEqual(m.headers["via"], ["SIP/2.0/UDP 1.2.3.4:5060"]) - - def testCantForwardResponse(self): - pass - - #testCantForwardResponse.skip = "not implemented yet" - - -class RegistrationTests(unittest.TestCase): - - def setUp(self): - self.proxy = sip.RegisterProxy(host="127.0.0.1") - self.registry = sip.InMemoryRegistry("bell.example.com") - self.proxy.registry = self.proxy.locator = self.registry - self.sent = [] - self.proxy.sendMessage = lambda dest, msg: self.sent.append((dest, msg)) - setUp = utils.suppressWarnings(setUp, - util.suppress(category=DeprecationWarning, - message=r'twisted.protocols.sip.DigestAuthorizer was deprecated')) - - def tearDown(self): - for d, uri in self.registry.users.values(): - d.cancel() - del self.proxy - - def register(self): - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - def unregister(self): - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "*") - r.addHeader("via", sip.Via("client.com").toString()) - r.addHeader("expires", "0") - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - def testRegister(self): - self.register() - dest, m = self.sent[0] - self.assertEqual((dest.host, dest.port), ("client.com", 5060)) - self.assertEqual(m.code, 200) - self.assertEqual(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) - self.assertEqual(m.headers["to"], ["sip:joe@bell.example.com"]) - self.assertEqual(m.headers["contact"], ["sip:joe@client.com:5060"]) - self.failUnless( - int(m.headers["expires"][0]) in (3600, 3601, 3599, 3598)) - self.assertEqual(len(self.registry.users), 1) - dc, uri = self.registry.users["joe"] - self.assertEqual(uri.toString(), "sip:joe@client.com:5060") - d = self.proxy.locator.getAddress(sip.URL(username="joe", - host="bell.example.com")) - d.addCallback(lambda desturl : (desturl.host, desturl.port)) - d.addCallback(self.assertEqual, ('client.com', 5060)) - return d - - def testUnregister(self): - self.register() - self.unregister() - dest, m = self.sent[1] - self.assertEqual((dest.host, dest.port), ("client.com", 5060)) - self.assertEqual(m.code, 200) - self.assertEqual(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) - self.assertEqual(m.headers["to"], ["sip:joe@bell.example.com"]) - self.assertEqual(m.headers["contact"], ["sip:joe@client.com:5060"]) - self.assertEqual(m.headers["expires"], ["0"]) - self.assertEqual(self.registry.users, {}) - - - def addPortal(self): - r = TestRealm() - p = cred.portal.Portal(r) - c = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse() - c.addUser('userXname@127.0.0.1', 'passXword') - p.registerChecker(c) - self.proxy.portal = p - - def testFailedAuthentication(self): - self.addPortal() - self.register() - - self.assertEqual(len(self.registry.users), 0) - self.assertEqual(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEqual(m.code, 401) - - - def test_basicAuthentication(self): - """ - Test that registration with basic authentication succeeds. - """ - self.addPortal() - self.proxy.authorizers = self.proxy.authorizers.copy() - self.proxy.authorizers['basic'] = sip.BasicAuthorizer() - warnings = self.flushWarnings( - offendingFunctions=[self.test_basicAuthentication]) - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], - "twisted.protocols.sip.BasicAuthorizer was deprecated in " - "Twisted 9.0.0") - self.assertEqual( - warnings[0]['category'], - DeprecationWarning) - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - r.addHeader("authorization", - "Basic " + "userXname:passXword".encode('base64')) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - self.assertEqual(len(self.registry.users), 1) - self.assertEqual(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEqual(m.code, 200) - - - def test_failedBasicAuthentication(self): - """ - Failed registration with basic authentication results in an - unauthorized error response. - """ - self.addPortal() - self.proxy.authorizers = self.proxy.authorizers.copy() - self.proxy.authorizers['basic'] = sip.BasicAuthorizer() - warnings = self.flushWarnings( - offendingFunctions=[self.test_failedBasicAuthentication]) - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], - "twisted.protocols.sip.BasicAuthorizer was deprecated in " - "Twisted 9.0.0") - self.assertEqual( - warnings[0]['category'], - DeprecationWarning) - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - r.addHeader( - "authorization", "Basic " + "userXname:password".encode('base64')) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - self.assertEqual(len(self.registry.users), 0) - self.assertEqual(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEqual(m.code, 401) - - - def testWrongDomainRegister(self): - r = sip.Request("REGISTER", "sip:wrong.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEqual(len(self.sent), 0) - - def testWrongToDomainRegister(self): - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@foo.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEqual(len(self.sent), 0) - - def testWrongDomainLookup(self): - self.register() - url = sip.URL(username="joe", host="foo.com") - d = self.proxy.locator.getAddress(url) - self.assertFailure(d, LookupError) - return d - - def testNoContactLookup(self): - self.register() - url = sip.URL(username="jane", host="bell.example.com") - d = self.proxy.locator.getAddress(url) - self.assertFailure(d, LookupError) - return d - - -class Client(sip.Base): - - def __init__(self): - sip.Base.__init__(self) - self.received = [] - self.deferred = defer.Deferred() - - def handle_response(self, response, addr): - self.received.append(response) - self.deferred.callback(self.received) - - -class LiveTests(unittest.TestCase): - - def setUp(self): - self.proxy = sip.RegisterProxy(host="127.0.0.1") - self.registry = sip.InMemoryRegistry("bell.example.com") - self.proxy.registry = self.proxy.locator = self.registry - self.serverPort = reactor.listenUDP( - 0, self.proxy, interface="127.0.0.1") - self.client = Client() - self.clientPort = reactor.listenUDP( - 0, self.client, interface="127.0.0.1") - self.serverAddress = (self.serverPort.getHost().host, - self.serverPort.getHost().port) - setUp = utils.suppressWarnings(setUp, - util.suppress(category=DeprecationWarning, - message=r'twisted.protocols.sip.DigestAuthorizer was deprecated')) - - def tearDown(self): - for d, uri in self.registry.users.values(): - d.cancel() - d1 = defer.maybeDeferred(self.clientPort.stopListening) - d2 = defer.maybeDeferred(self.serverPort.stopListening) - return defer.gatherResults([d1, d2]) - - def testRegister(self): - p = self.clientPort.getHost().port - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@127.0.0.1:%d" % p) - r.addHeader("via", sip.Via("127.0.0.1", port=p).toString()) - self.client.sendMessage( - sip.URL(host="127.0.0.1", port=self.serverAddress[1]), r) - d = self.client.deferred - def check(received): - self.assertEqual(len(received), 1) - r = received[0] - self.assertEqual(r.code, 200) - d.addCallback(check) - return d - - def test_amoralRPort(self): - """ - rport is allowed without a value, apparently because server - implementors might be too stupid to check the received port - against 5060 and see if they're equal, and because client - implementors might be too stupid to bind to port 5060, or set a - value on the rport parameter they send if they bind to another - port. - """ - p = self.clientPort.getHost().port - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@127.0.0.1:%d" % p) - r.addHeader("via", sip.Via("127.0.0.1", port=p, rport=True).toString()) - warnings = self.flushWarnings( - offendingFunctions=[self.test_amoralRPort]) - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], - 'rport=True is deprecated since Twisted 9.0.') - self.assertEqual( - warnings[0]['category'], - DeprecationWarning) - self.client.sendMessage(sip.URL(host="127.0.0.1", - port=self.serverAddress[1]), - r) - d = self.client.deferred - def check(received): - self.assertEqual(len(received), 1) - r = received[0] - self.assertEqual(r.code, 200) - d.addCallback(check) - return d - - - -registerRequest = """ -REGISTER sip:intarweb.us SIP/2.0\r -Via: SIP/2.0/UDP 192.168.1.100:50609\r -From: \r -To: \r -Contact: "exarkun" \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9898 REGISTER\r -Expires: 500\r -User-Agent: X-Lite build 1061\r -Content-Length: 0\r -\r -""" - -challengeResponse = """\ -SIP/2.0 401 Unauthorized\r -Via: SIP/2.0/UDP 192.168.1.100:50609;received=127.0.0.1;rport=5632\r -To: \r -From: \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9898 REGISTER\r -WWW-Authenticate: Digest nonce="92956076410767313901322208775",opaque="1674186428",qop-options="auth",algorithm="MD5",realm="intarweb.us"\r -\r -""" - -authRequest = """\ -REGISTER sip:intarweb.us SIP/2.0\r -Via: SIP/2.0/UDP 192.168.1.100:50609\r -From: \r -To: \r -Contact: "exarkun" \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9899 REGISTER\r -Expires: 500\r -Authorization: Digest username="exarkun",realm="intarweb.us",nonce="92956076410767313901322208775",response="4a47980eea31694f997369214292374b",uri="sip:intarweb.us",algorithm=MD5,opaque="1674186428"\r -User-Agent: X-Lite build 1061\r -Content-Length: 0\r -\r -""" - -okResponse = """\ -SIP/2.0 200 OK\r -Via: SIP/2.0/UDP 192.168.1.100:50609;received=127.0.0.1;rport=5632\r -To: \r -From: \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9899 REGISTER\r -Contact: sip:exarkun@127.0.0.1:5632\r -Expires: 3600\r -Content-Length: 0\r -\r -""" - -class FakeDigestAuthorizer(sip.DigestAuthorizer): - def generateNonce(self): - return '92956076410767313901322208775' - def generateOpaque(self): - return '1674186428' - - -class FakeRegistry(sip.InMemoryRegistry): - """Make sure expiration is always seen to be 3600. - - Otherwise slow reactors fail tests incorrectly. - """ - - def _cbReg(self, reg): - if 3600 < reg.secondsToExpiry or reg.secondsToExpiry < 3598: - raise RuntimeError( - "bad seconds to expire: %s" % reg.secondsToExpiry) - reg.secondsToExpiry = 3600 - return reg - - def getRegistrationInfo(self, uri): - d = sip.InMemoryRegistry.getRegistrationInfo(self, uri) - return d.addCallback(self._cbReg) - - def registerAddress(self, domainURL, logicalURL, physicalURL): - d = sip.InMemoryRegistry.registerAddress( - self, domainURL, logicalURL, physicalURL) - return d.addCallback(self._cbReg) - -class AuthorizationTests(unittest.TestCase): - def setUp(self): - self.proxy = sip.RegisterProxy(host="intarweb.us") - self.proxy.authorizers = self.proxy.authorizers.copy() - self.proxy.authorizers['digest'] = FakeDigestAuthorizer() - - self.registry = FakeRegistry("intarweb.us") - self.proxy.registry = self.proxy.locator = self.registry - self.transport = proto_helpers.FakeDatagramTransport() - self.proxy.transport = self.transport - - r = TestRealm() - p = cred.portal.Portal(r) - c = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse() - c.addUser('exarkun@intarweb.us', 'password') - p.registerChecker(c) - self.proxy.portal = p - setUp = utils.suppressWarnings(setUp, - util.suppress(category=DeprecationWarning, - message=r'twisted.protocols.sip.DigestAuthorizer was deprecated')) - - def tearDown(self): - for d, uri in self.registry.users.values(): - d.cancel() - del self.proxy - - def testChallenge(self): - self.proxy.datagramReceived(registerRequest, ("127.0.0.1", 5632)) - - self.assertEqual( - self.transport.written[-1], - ((challengeResponse, ("127.0.0.1", 5632))) - ) - self.transport.written = [] - - self.proxy.datagramReceived(authRequest, ("127.0.0.1", 5632)) - - self.assertEqual( - self.transport.written[-1], - ((okResponse, ("127.0.0.1", 5632))) - ) - testChallenge.suppress = [ - util.suppress( - category=DeprecationWarning, - message=r'twisted.protocols.sip.DigestAuthorizer was deprecated'), - util.suppress( - category=DeprecationWarning, - message=r'twisted.protocols.sip.DigestedCredentials was deprecated'), - util.suppress( - category=DeprecationWarning, - message=r'twisted.protocols.sip.DigestCalcHA1 was deprecated'), - util.suppress( - category=DeprecationWarning, - message=r'twisted.protocols.sip.DigestCalcResponse was deprecated')] - - - -class DeprecationTests(unittest.TestCase): - """ - Tests for deprecation of obsolete components of L{twisted.protocols.sip}. - """ - - def test_deprecatedDigestCalcHA1(self): - """ - L{sip.DigestCalcHA1} is deprecated. - """ - self.callDeprecated(Version("Twisted", 9, 0, 0), - sip.DigestCalcHA1, '', '', '', '', '', '') - - - def test_deprecatedDigestCalcResponse(self): - """ - L{sip.DigestCalcResponse} is deprecated. - """ - self.callDeprecated(Version("Twisted", 9, 0, 0), - sip.DigestCalcResponse, '', '', '', '', '', '', '', - '') - - def test_deprecatedBasicAuthorizer(self): - """ - L{sip.BasicAuthorizer} is deprecated. - """ - self.callDeprecated(Version("Twisted", 9, 0, 0), sip.BasicAuthorizer) - - - def test_deprecatedDigestAuthorizer(self): - """ - L{sip.DigestAuthorizer} is deprecated. - """ - self.callDeprecated(Version("Twisted", 9, 0, 0), sip.DigestAuthorizer) - - - def test_deprecatedDigestedCredentials(self): - """ - L{sip.DigestedCredentials} is deprecated. - """ - self.callDeprecated(Version("Twisted", 9, 0, 0), - sip.DigestedCredentials, '', {}, {}) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sob.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sob.py deleted file mode 100644 index ac8c9b8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sob.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -import sys, os - -try: - import Crypto.Cipher.AES -except ImportError: - Crypto = None - -from twisted.trial import unittest -from twisted.persisted import sob -from twisted.python import components - -class Dummy(components.Componentized): - pass - -objects = [ -1, -"hello", -(1, "hello"), -[1, "hello"], -{1:"hello"}, -] - -class FakeModule(object): - pass - -class PersistTests(unittest.TestCase): - def testStyles(self): - for o in objects: - p = sob.Persistent(o, '') - for style in 'source pickle'.split(): - p.setStyle(style) - p.save(filename='persisttest.'+style) - o1 = sob.load('persisttest.'+style, style) - self.assertEqual(o, o1) - - def testStylesBeingSet(self): - o = Dummy() - o.foo = 5 - o.setComponent(sob.IPersistable, sob.Persistent(o, 'lala')) - for style in 'source pickle'.split(): - sob.IPersistable(o).setStyle(style) - sob.IPersistable(o).save(filename='lala.'+style) - o1 = sob.load('lala.'+style, style) - self.assertEqual(o.foo, o1.foo) - self.assertEqual(sob.IPersistable(o1).style, style) - - - def testNames(self): - o = [1,2,3] - p = sob.Persistent(o, 'object') - for style in 'source pickle'.split(): - p.setStyle(style) - p.save() - o1 = sob.load('object.ta'+style[0], style) - self.assertEqual(o, o1) - for tag in 'lala lolo'.split(): - p.save(tag) - o1 = sob.load('object-'+tag+'.ta'+style[0], style) - self.assertEqual(o, o1) - - def testEncryptedStyles(self): - for o in objects: - phrase='once I was the king of spain' - p = sob.Persistent(o, '') - for style in 'source pickle'.split(): - p.setStyle(style) - p.save(filename='epersisttest.'+style, passphrase=phrase) - o1 = sob.load('epersisttest.'+style, style, phrase) - self.assertEqual(o, o1) - if Crypto is None: - testEncryptedStyles.skip = "PyCrypto required for encrypted config" - - def testPython(self): - f = open("persisttest.python", 'w') - f.write('foo=[1,2,3] ') - f.close() - o = sob.loadValueFromFile('persisttest.python', 'foo') - self.assertEqual(o, [1,2,3]) - - def testEncryptedPython(self): - phrase='once I was the king of spain' - f = open("epersisttest.python", 'w') - f.write( - sob._encrypt(phrase, 'foo=[1,2,3]')) - f.close() - o = sob.loadValueFromFile('epersisttest.python', 'foo', phrase) - self.assertEqual(o, [1,2,3]) - if Crypto is None: - testEncryptedPython.skip = "PyCrypto required for encrypted config" - - def testTypeGuesser(self): - self.assertRaises(KeyError, sob.guessType, "file.blah") - self.assertEqual('python', sob.guessType("file.py")) - self.assertEqual('python', sob.guessType("file.tac")) - self.assertEqual('python', sob.guessType("file.etac")) - self.assertEqual('pickle', sob.guessType("file.tap")) - self.assertEqual('pickle', sob.guessType("file.etap")) - self.assertEqual('source', sob.guessType("file.tas")) - self.assertEqual('source', sob.guessType("file.etas")) - - def testEverythingEphemeralGetattr(self): - """ - Verify that _EverythingEphermal.__getattr__ works. - """ - self.fakeMain.testMainModGetattr = 1 - - dirname = self.mktemp() - os.mkdir(dirname) - - filename = os.path.join(dirname, 'persisttest.ee_getattr') - - f = file(filename, 'w') - f.write('import __main__\n') - f.write('if __main__.testMainModGetattr != 1: raise AssertionError\n') - f.write('app = None\n') - f.close() - - sob.load(filename, 'source') - - def testEverythingEphemeralSetattr(self): - """ - Verify that _EverythingEphemeral.__setattr__ won't affect __main__. - """ - self.fakeMain.testMainModSetattr = 1 - - dirname = self.mktemp() - os.mkdir(dirname) - - filename = os.path.join(dirname, 'persisttest.ee_setattr') - f = file(filename, 'w') - f.write('import __main__\n') - f.write('__main__.testMainModSetattr = 2\n') - f.write('app = None\n') - f.close() - - sob.load(filename, 'source') - - self.assertEqual(self.fakeMain.testMainModSetattr, 1) - - def testEverythingEphemeralException(self): - """ - Test that an exception during load() won't cause _EE to mask __main__ - """ - dirname = self.mktemp() - os.mkdir(dirname) - filename = os.path.join(dirname, 'persisttest.ee_exception') - - f = file(filename, 'w') - f.write('raise ValueError\n') - f.close() - - self.assertRaises(ValueError, sob.load, filename, 'source') - self.assertEqual(type(sys.modules['__main__']), FakeModule) - - def setUp(self): - """ - Replace the __main__ module with a fake one, so that it can be mutated - in tests - """ - self.realMain = sys.modules['__main__'] - self.fakeMain = sys.modules['__main__'] = FakeModule() - - def tearDown(self): - """ - Restore __main__ to its original value - """ - sys.modules['__main__'] = self.realMain - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_socks.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_socks.py deleted file mode 100644 index 624ac19..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_socks.py +++ /dev/null @@ -1,496 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.protocol.socks}, an implementation of the SOCKSv4 and -SOCKSv4a protocols. -""" - -import struct, socket - -from twisted.trial import unittest -from twisted.test import proto_helpers -from twisted.internet import defer, address -from twisted.internet.error import DNSLookupError -from twisted.protocols import socks - - -class StringTCPTransport(proto_helpers.StringTransport): - stringTCPTransport_closing = False - peer = None - - def getPeer(self): - return self.peer - - def getHost(self): - return address.IPv4Address('TCP', '2.3.4.5', 42) - - def loseConnection(self): - self.stringTCPTransport_closing = True - - - -class FakeResolverReactor: - """ - Bare-bones reactor with deterministic behavior for the resolve method. - """ - def __init__(self, names): - """ - @type names: C{dict} containing C{str} keys and C{str} values. - @param names: A hostname to IP address mapping. The IP addresses are - stringified dotted quads. - """ - self.names = names - - - def resolve(self, hostname): - """ - Resolve a hostname by looking it up in the C{names} dictionary. - """ - try: - return defer.succeed(self.names[hostname]) - except KeyError: - return defer.fail( - DNSLookupError("FakeResolverReactor couldn't find " + hostname)) - - - -class SOCKSv4Driver(socks.SOCKSv4): - # last SOCKSv4Outgoing instantiated - driver_outgoing = None - - # last SOCKSv4IncomingFactory instantiated - driver_listen = None - - def connectClass(self, host, port, klass, *args): - # fake it - proto = klass(*args) - proto.transport = StringTCPTransport() - proto.transport.peer = address.IPv4Address('TCP', host, port) - proto.connectionMade() - self.driver_outgoing = proto - return defer.succeed(proto) - - def listenClass(self, port, klass, *args): - # fake it - factory = klass(*args) - self.driver_listen = factory - if port == 0: - port = 1234 - return defer.succeed(('6.7.8.9', port)) - - - -class ConnectTests(unittest.TestCase): - """ - Tests for SOCKS and SOCKSv4a connect requests using the L{SOCKSv4} protocol. - """ - def setUp(self): - self.sock = SOCKSv4Driver() - self.sock.transport = StringTCPTransport() - self.sock.connectionMade() - self.sock.reactor = FakeResolverReactor({"localhost":"127.0.0.1"}) - - - def tearDown(self): - outgoing = self.sock.driver_outgoing - if outgoing is not None: - self.assert_(outgoing.transport.stringTCPTransport_closing, - "Outgoing SOCKS connections need to be closed.") - - - def test_simple(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 34) - + socket.inet_aton('1.2.3.4')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - self.assert_(self.sock.driver_outgoing is not None) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(self.sock.driver_outgoing.transport.value(), - 'hello, world') - - # the other way around - self.sock.driver_outgoing.dataReceived('hi there') - self.assertEqual(self.sock.transport.value(), 'hi there') - - self.sock.connectionLost('fake reason') - - - def test_socks4aSuccessfulResolution(self): - """ - If the destination IP address has zeros for the first three octets and - non-zero for the fourth octet, the client is attempting a v4a - connection. A hostname is specified after the user ID string and the - server connects to the address that hostname resolves to. - - @see: U{http://en.wikipedia.org/wiki/SOCKS#SOCKS_4a_protocol} - """ - # send the domain name "localhost" to be resolved - clientRequest = ( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('0.0.0.1') - + 'fooBAZ\0' - + 'localhost\0') - - # Deliver the bytes one by one to exercise the protocol's buffering - # logic. FakeResolverReactor's resolve method is invoked to "resolve" - # the hostname. - for byte in clientRequest: - self.sock.dataReceived(byte) - - sent = self.sock.transport.value() - self.sock.transport.clear() - - # Verify that the server responded with the address which will be - # connected to. - self.assertEqual( - sent, - struct.pack('!BBH', 0, 90, 34) + socket.inet_aton('127.0.0.1')) - self.assertFalse(self.sock.transport.stringTCPTransport_closing) - self.assertNotIdentical(self.sock.driver_outgoing, None) - - # Pass some data through and verify it is forwarded to the outgoing - # connection. - self.sock.dataReceived('hello, world') - self.assertEqual( - self.sock.driver_outgoing.transport.value(), 'hello, world') - - # Deliver some data from the output connection and verify it is - # passed along to the incoming side. - self.sock.driver_outgoing.dataReceived('hi there') - self.assertEqual(self.sock.transport.value(), 'hi there') - - self.sock.connectionLost('fake reason') - - - def test_socks4aFailedResolution(self): - """ - Failed hostname resolution on a SOCKSv4a packet results in a 91 error - response and the connection getting closed. - """ - # send the domain name "failinghost" to be resolved - clientRequest = ( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('0.0.0.1') - + 'fooBAZ\0' - + 'failinghost\0') - - # Deliver the bytes one by one to exercise the protocol's buffering - # logic. FakeResolverReactor's resolve method is invoked to "resolve" - # the hostname. - for byte in clientRequest: - self.sock.dataReceived(byte) - - # Verify that the server responds with a 91 error. - sent = self.sock.transport.value() - self.assertEqual( - sent, - struct.pack('!BBH', 0, 91, 0) + socket.inet_aton('0.0.0.0')) - - # A failed resolution causes the transport to drop the connection. - self.assertTrue(self.sock.transport.stringTCPTransport_closing) - self.assertIdentical(self.sock.driver_outgoing, None) - - - def test_accessDenied(self): - self.sock.authorize = lambda code, server, port, user: 0 - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 4242) - + socket.inet_aton('10.2.3.4') - + 'fooBAR' - + '\0') - self.assertEqual(self.sock.transport.value(), - struct.pack('!BBH', 0, 91, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(self.sock.transport.stringTCPTransport_closing) - self.assertIdentical(self.sock.driver_outgoing, None) - - - def test_eofRemote(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - self.sock.transport.clear() - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(self.sock.driver_outgoing.transport.value(), - 'hello, world') - - # now close it from the server side - self.sock.driver_outgoing.transport.loseConnection() - self.sock.driver_outgoing.connectionLost('fake reason') - - - def test_eofLocal(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - self.sock.transport.clear() - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(self.sock.driver_outgoing.transport.value(), - 'hello, world') - - # now close it from the client side - self.sock.connectionLost('fake reason') - - - -class BindTests(unittest.TestCase): - """ - Tests for SOCKS and SOCKSv4a bind requests using the L{SOCKSv4} protocol. - """ - def setUp(self): - self.sock = SOCKSv4Driver() - self.sock.transport = StringTCPTransport() - self.sock.connectionMade() - self.sock.reactor = FakeResolverReactor({"localhost":"127.0.0.1"}) - -## def tearDown(self): -## # TODO ensure the listen port is closed -## listen = self.sock.driver_listen -## if listen is not None: -## self.assert_(incoming.transport.stringTCPTransport_closing, -## "Incoming SOCKS connections need to be closed.") - - def test_simple(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 1234) - + socket.inet_aton('6.7.8.9')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - self.assert_(self.sock.driver_listen is not None) - - # connect - incoming = self.sock.driver_listen.buildProtocol(('1.2.3.4', 5345)) - self.assertNotIdentical(incoming, None) - incoming.transport = StringTCPTransport() - incoming.connectionMade() - - # now we should have the second reply packet - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(incoming.transport.value(), - 'hello, world') - - # the other way around - incoming.dataReceived('hi there') - self.assertEqual(self.sock.transport.value(), 'hi there') - - self.sock.connectionLost('fake reason') - - - def test_socks4a(self): - """ - If the destination IP address has zeros for the first three octets and - non-zero for the fourth octet, the client is attempting a v4a - connection. A hostname is specified after the user ID string and the - server connects to the address that hostname resolves to. - - @see: U{http://en.wikipedia.org/wiki/SOCKS#SOCKS_4a_protocol} - """ - # send the domain name "localhost" to be resolved - clientRequest = ( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('0.0.0.1') - + 'fooBAZ\0' - + 'localhost\0') - - # Deliver the bytes one by one to exercise the protocol's buffering - # logic. FakeResolverReactor's resolve method is invoked to "resolve" - # the hostname. - for byte in clientRequest: - self.sock.dataReceived(byte) - - sent = self.sock.transport.value() - self.sock.transport.clear() - - # Verify that the server responded with the address which will be - # connected to. - self.assertEqual( - sent, - struct.pack('!BBH', 0, 90, 1234) + socket.inet_aton('6.7.8.9')) - self.assertFalse(self.sock.transport.stringTCPTransport_closing) - self.assertNotIdentical(self.sock.driver_listen, None) - - # connect - incoming = self.sock.driver_listen.buildProtocol(('127.0.0.1', 5345)) - self.assertNotIdentical(incoming, None) - incoming.transport = StringTCPTransport() - incoming.connectionMade() - - # now we should have the second reply packet - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 0) - + socket.inet_aton('0.0.0.0')) - self.assertNotIdentical( - self.sock.transport.stringTCPTransport_closing, None) - - # Deliver some data from the output connection and verify it is - # passed along to the incoming side. - self.sock.dataReceived('hi there') - self.assertEqual(incoming.transport.value(), 'hi there') - - # the other way around - incoming.dataReceived('hi there') - self.assertEqual(self.sock.transport.value(), 'hi there') - - self.sock.connectionLost('fake reason') - - - def test_socks4aFailedResolution(self): - """ - Failed hostname resolution on a SOCKSv4a packet results in a 91 error - response and the connection getting closed. - """ - # send the domain name "failinghost" to be resolved - clientRequest = ( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('0.0.0.1') - + 'fooBAZ\0' - + 'failinghost\0') - - # Deliver the bytes one by one to exercise the protocol's buffering - # logic. FakeResolverReactor's resolve method is invoked to "resolve" - # the hostname. - for byte in clientRequest: - self.sock.dataReceived(byte) - - # Verify that the server responds with a 91 error. - sent = self.sock.transport.value() - self.assertEqual( - sent, - struct.pack('!BBH', 0, 91, 0) + socket.inet_aton('0.0.0.0')) - - # A failed resolution causes the transport to drop the connection. - self.assertTrue(self.sock.transport.stringTCPTransport_closing) - self.assertIdentical(self.sock.driver_outgoing, None) - - - def test_accessDenied(self): - self.sock.authorize = lambda code, server, port, user: 0 - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 4242) - + socket.inet_aton('10.2.3.4') - + 'fooBAR' - + '\0') - self.assertEqual(self.sock.transport.value(), - struct.pack('!BBH', 0, 91, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(self.sock.transport.stringTCPTransport_closing) - self.assertIdentical(self.sock.driver_listen, None) - - def test_eofRemote(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # connect - incoming = self.sock.driver_listen.buildProtocol(('1.2.3.4', 5345)) - self.assertNotIdentical(incoming, None) - incoming.transport = StringTCPTransport() - incoming.connectionMade() - - # now we should have the second reply packet - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(incoming.transport.value(), - 'hello, world') - - # now close it from the server side - incoming.transport.loseConnection() - incoming.connectionLost('fake reason') - - def test_eofLocal(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # connect - incoming = self.sock.driver_listen.buildProtocol(('1.2.3.4', 5345)) - self.assertNotIdentical(incoming, None) - incoming.transport = StringTCPTransport() - incoming.connectionMade() - - # now we should have the second reply packet - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(incoming.transport.value(), - 'hello, world') - - # now close it from the client side - self.sock.connectionLost('fake reason') - - def test_badSource(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # connect from WRONG address - incoming = self.sock.driver_listen.buildProtocol(('1.6.6.6', 666)) - self.assertIdentical(incoming, None) - - # Now we should have the second reply packet and it should - # be a failure. The connection should be closing. - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 91, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(self.sock.transport.stringTCPTransport_closing) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ssl.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ssl.py deleted file mode 100644 index 09c4337..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_ssl.py +++ /dev/null @@ -1,726 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for twisted SSL support. -""" -from __future__ import division, absolute_import - -from twisted.python.filepath import FilePath -from twisted.trial import unittest -from twisted.internet import protocol, reactor, interfaces, defer -from twisted.internet.error import ConnectionDone -from twisted.protocols import basic -from twisted.python.reflect import requireModule -from twisted.python.runtime import platform -from twisted.test.test_tcp import ProperlyCloseFilesMixin - -import os, errno - -try: - from OpenSSL import SSL, crypto - from twisted.internet import ssl - from twisted.test.ssl_helpers import ClientTLSContext, certPath -except ImportError: - def _noSSL(): - # ugh, make pyflakes happy. - global SSL - global ssl - SSL = ssl = None - _noSSL() - -try: - from twisted.protocols import tls as newTLS -except ImportError: - # Assuming SSL exists, we're using old version in reactor (i.e. non-protocol) - newTLS = None - - -class UnintelligentProtocol(basic.LineReceiver): - """ - @ivar deferred: a deferred that will fire at connection lost. - @type deferred: L{defer.Deferred} - - @cvar pretext: text sent before TLS is set up. - @type pretext: C{bytes} - - @cvar posttext: text sent after TLS is set up. - @type posttext: C{bytes} - """ - pretext = [ - b"first line", - b"last thing before tls starts", - b"STARTTLS"] - - posttext = [ - b"first thing after tls started", - b"last thing ever"] - - def __init__(self): - self.deferred = defer.Deferred() - - - def connectionMade(self): - for l in self.pretext: - self.sendLine(l) - - - def lineReceived(self, line): - if line == b"READY": - self.transport.startTLS(ClientTLSContext(), self.factory.client) - for l in self.posttext: - self.sendLine(l) - self.transport.loseConnection() - - - def connectionLost(self, reason): - self.deferred.callback(None) - - - -class LineCollector(basic.LineReceiver): - """ - @ivar deferred: a deferred that will fire at connection lost. - @type deferred: L{defer.Deferred} - - @ivar doTLS: whether the protocol is initiate TLS or not. - @type doTLS: C{bool} - - @ivar fillBuffer: if set to True, it will send lots of data once - C{STARTTLS} is received. - @type fillBuffer: C{bool} - """ - - def __init__(self, doTLS, fillBuffer=False): - self.doTLS = doTLS - self.fillBuffer = fillBuffer - self.deferred = defer.Deferred() - - - def connectionMade(self): - self.factory.rawdata = b'' - self.factory.lines = [] - - - def lineReceived(self, line): - self.factory.lines.append(line) - if line == b'STARTTLS': - if self.fillBuffer: - for x in range(500): - self.sendLine(b'X' * 1000) - self.sendLine(b'READY') - if self.doTLS: - ctx = ServerTLSContext( - privateKeyFileName=certPath, - certificateFileName=certPath, - ) - self.transport.startTLS(ctx, self.factory.server) - else: - self.setRawMode() - - - def rawDataReceived(self, data): - self.factory.rawdata += data - self.transport.loseConnection() - - - def connectionLost(self, reason): - self.deferred.callback(None) - - - -class SingleLineServerProtocol(protocol.Protocol): - """ - A protocol that sends a single line of data at C{connectionMade}. - """ - - def connectionMade(self): - self.transport.write(b"+OK \r\n") - self.transport.getPeerCertificate() - - - -class RecordingClientProtocol(protocol.Protocol): - """ - @ivar deferred: a deferred that will fire with first received content. - @type deferred: L{defer.Deferred} - """ - - def __init__(self): - self.deferred = defer.Deferred() - - - def connectionMade(self): - self.transport.getPeerCertificate() - - - def dataReceived(self, data): - self.deferred.callback(data) - - - -class ImmediatelyDisconnectingProtocol(protocol.Protocol): - """ - A protocol that disconnect immediately on connection. It fires the - C{connectionDisconnected} deferred of its factory on connetion lost. - """ - - def connectionMade(self): - self.transport.loseConnection() - - - def connectionLost(self, reason): - self.factory.connectionDisconnected.callback(None) - - - -def generateCertificateObjects(organization, organizationalUnit): - """ - Create a certificate for given C{organization} and C{organizationalUnit}. - - @return: a tuple of (key, request, certificate) objects. - """ - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 512) - req = crypto.X509Req() - subject = req.get_subject() - subject.O = organization - subject.OU = organizationalUnit - req.set_pubkey(pkey) - req.sign(pkey, "md5") - - # Here comes the actual certificate - cert = crypto.X509() - cert.set_serial_number(1) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(60) # Testing certificates need not be long lived - cert.set_issuer(req.get_subject()) - cert.set_subject(req.get_subject()) - cert.set_pubkey(req.get_pubkey()) - cert.sign(pkey, "md5") - - return pkey, req, cert - - - -def generateCertificateFiles(basename, organization, organizationalUnit): - """ - Create certificate files key, req and cert prefixed by C{basename} for - given C{organization} and C{organizationalUnit}. - """ - pkey, req, cert = generateCertificateObjects(organization, organizationalUnit) - - for ext, obj, dumpFunc in [ - ('key', pkey, crypto.dump_privatekey), - ('req', req, crypto.dump_certificate_request), - ('cert', cert, crypto.dump_certificate)]: - fName = os.extsep.join((basename, ext)).encode("utf-8") - FilePath(fName).setContent(dumpFunc(crypto.FILETYPE_PEM, obj)) - - - -class ContextGeneratingMixin: - """ - Offer methods to create L{ssl.DefaultOpenSSLContextFactory} for both client - and server. - - @ivar clientBase: prefix of client certificate files. - @type clientBase: C{str} - - @ivar serverBase: prefix of server certificate files. - @type serverBase: C{str} - - @ivar clientCtxFactory: a generated context factory to be used in - C{reactor.connectSSL}. - @type clientCtxFactory: L{ssl.DefaultOpenSSLContextFactory} - - @ivar serverCtxFactory: a generated context factory to be used in - C{reactor.listenSSL}. - @type serverCtxFactory: L{ssl.DefaultOpenSSLContextFactory} - """ - - def makeContextFactory(self, org, orgUnit, *args, **kwArgs): - base = self.mktemp() - generateCertificateFiles(base, org, orgUnit) - serverCtxFactory = ssl.DefaultOpenSSLContextFactory( - os.extsep.join((base, 'key')), - os.extsep.join((base, 'cert')), - *args, **kwArgs) - - return base, serverCtxFactory - - - def setupServerAndClient(self, clientArgs, clientKwArgs, serverArgs, - serverKwArgs): - self.clientBase, self.clientCtxFactory = self.makeContextFactory( - *clientArgs, **clientKwArgs) - self.serverBase, self.serverCtxFactory = self.makeContextFactory( - *serverArgs, **serverKwArgs) - - - -if SSL is not None: - class ServerTLSContext(ssl.DefaultOpenSSLContextFactory): - """ - A context factory with a default method set to L{SSL.TLSv1_METHOD}. - """ - isClient = False - - def __init__(self, *args, **kw): - kw['sslmethod'] = SSL.TLSv1_METHOD - ssl.DefaultOpenSSLContextFactory.__init__(self, *args, **kw) - - - -class StolenTCPTests(ProperlyCloseFilesMixin, unittest.TestCase): - """ - For SSL transports, test many of the same things which are tested for - TCP transports. - """ - - def createServer(self, address, portNumber, factory): - """ - Create an SSL server with a certificate using L{IReactorSSL.listenSSL}. - """ - cert = ssl.PrivateCertificate.loadPEM(FilePath(certPath).getContent()) - contextFactory = cert.options() - return reactor.listenSSL( - portNumber, factory, contextFactory, interface=address) - - - def connectClient(self, address, portNumber, clientCreator): - """ - Create an SSL client using L{IReactorSSL.connectSSL}. - """ - contextFactory = ssl.CertificateOptions() - return clientCreator.connectSSL(address, portNumber, contextFactory) - - - def getHandleExceptionType(self): - """ - Return L{SSL.Error} as the expected error type which will be raised by - a write to the L{OpenSSL.SSL.Connection} object after it has been - closed. - """ - return SSL.Error - - - def getHandleErrorCode(self): - """ - Return the argument L{SSL.Error} will be constructed with for this - case. This is basically just a random OpenSSL implementation detail. - It would be better if this test worked in a way which did not require - this. - """ - # Windows 2000 SP 4 and Windows XP SP 2 give back WSAENOTSOCK for - # SSL.Connection.write for some reason. The twisted.protocols.tls - # implementation of IReactorSSL doesn't suffer from this imprecation, - # though, since it is isolated from the Windows I/O layer (I suppose?). - - # If test_properlyCloseFiles waited for the SSL handshake to complete - # and performed an orderly shutdown, then this would probably be a - # little less weird: writing to a shutdown SSL connection has a more - # well-defined failure mode (or at least it should). - - # So figure out if twisted.protocols.tls is in use. If it can be - # imported, it should be. - if requireModule('twisted.protocols.tls') is None: - # It isn't available, so we expect WSAENOTSOCK if we're on Windows. - if platform.getType() == 'win32': - return errno.WSAENOTSOCK - - # Otherwise, we expect an error about how we tried to write to a - # shutdown connection. This is terribly implementation-specific. - return [('SSL routines', 'SSL_write', 'protocol is shutdown')] - - - -class TLSTests(unittest.TestCase): - """ - Tests for startTLS support. - - @ivar fillBuffer: forwarded to L{LineCollector.fillBuffer} - @type fillBuffer: C{bool} - """ - fillBuffer = False - - clientProto = None - serverProto = None - - - def tearDown(self): - if self.clientProto.transport is not None: - self.clientProto.transport.loseConnection() - if self.serverProto.transport is not None: - self.serverProto.transport.loseConnection() - - - def _runTest(self, clientProto, serverProto, clientIsServer=False): - """ - Helper method to run TLS tests. - - @param clientProto: protocol instance attached to the client - connection. - @param serverProto: protocol instance attached to the server - connection. - @param clientIsServer: flag indicated if client should initiate - startTLS instead of server. - - @return: a L{defer.Deferred} that will fire when both connections are - lost. - """ - self.clientProto = clientProto - cf = self.clientFactory = protocol.ClientFactory() - cf.protocol = lambda: clientProto - if clientIsServer: - cf.server = False - else: - cf.client = True - - self.serverProto = serverProto - sf = self.serverFactory = protocol.ServerFactory() - sf.protocol = lambda: serverProto - if clientIsServer: - sf.client = False - else: - sf.server = True - - port = reactor.listenTCP(0, sf, interface="127.0.0.1") - self.addCleanup(port.stopListening) - - reactor.connectTCP('127.0.0.1', port.getHost().port, cf) - - return defer.gatherResults([clientProto.deferred, serverProto.deferred]) - - - def test_TLS(self): - """ - Test for server and client startTLS: client should received data both - before and after the startTLS. - """ - def check(ignore): - self.assertEqual( - self.serverFactory.lines, - UnintelligentProtocol.pretext + UnintelligentProtocol.posttext - ) - d = self._runTest(UnintelligentProtocol(), - LineCollector(True, self.fillBuffer)) - return d.addCallback(check) - - - def test_unTLS(self): - """ - Test for server startTLS not followed by a startTLS in client: the data - received after server startTLS should be received as raw. - """ - def check(ignored): - self.assertEqual( - self.serverFactory.lines, - UnintelligentProtocol.pretext - ) - self.failUnless(self.serverFactory.rawdata, - "No encrypted bytes received") - d = self._runTest(UnintelligentProtocol(), - LineCollector(False, self.fillBuffer)) - return d.addCallback(check) - - - def test_backwardsTLS(self): - """ - Test startTLS first initiated by client. - """ - def check(ignored): - self.assertEqual( - self.clientFactory.lines, - UnintelligentProtocol.pretext + UnintelligentProtocol.posttext - ) - d = self._runTest(LineCollector(True, self.fillBuffer), - UnintelligentProtocol(), True) - return d.addCallback(check) - - - -class SpammyTLSTests(TLSTests): - """ - Test TLS features with bytes sitting in the out buffer. - """ - fillBuffer = True - - - -class BufferingTests(unittest.TestCase): - serverProto = None - clientProto = None - - - def tearDown(self): - if self.serverProto.transport is not None: - self.serverProto.transport.loseConnection() - if self.clientProto.transport is not None: - self.clientProto.transport.loseConnection() - - - def test_openSSLBuffering(self): - serverProto = self.serverProto = SingleLineServerProtocol() - clientProto = self.clientProto = RecordingClientProtocol() - - server = protocol.ServerFactory() - client = self.client = protocol.ClientFactory() - - server.protocol = lambda: serverProto - client.protocol = lambda: clientProto - - sCTX = ssl.DefaultOpenSSLContextFactory(certPath, certPath) - cCTX = ssl.ClientContextFactory() - - port = reactor.listenSSL(0, server, sCTX, interface='127.0.0.1') - self.addCleanup(port.stopListening) - - reactor.connectSSL('127.0.0.1', port.getHost().port, client, cCTX) - - return clientProto.deferred.addCallback( - self.assertEqual, b"+OK \r\n") - - - -class ConnectionLostTests(unittest.TestCase, ContextGeneratingMixin): - """ - SSL connection closing tests. - """ - - def testImmediateDisconnect(self): - org = "twisted.test.test_ssl" - self.setupServerAndClient( - (org, org + ", client"), {}, - (org, org + ", server"), {}) - - # Set up a server, connect to it with a client, which should work since our verifiers - # allow anything, then disconnect. - serverProtocolFactory = protocol.ServerFactory() - serverProtocolFactory.protocol = protocol.Protocol - self.serverPort = serverPort = reactor.listenSSL(0, - serverProtocolFactory, self.serverCtxFactory) - - clientProtocolFactory = protocol.ClientFactory() - clientProtocolFactory.protocol = ImmediatelyDisconnectingProtocol - clientProtocolFactory.connectionDisconnected = defer.Deferred() - reactor.connectSSL('127.0.0.1', - serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory) - - return clientProtocolFactory.connectionDisconnected.addCallback( - lambda ignoredResult: self.serverPort.stopListening()) - - - def test_bothSidesLoseConnection(self): - """ - Both sides of SSL connection close connection; the connections should - close cleanly, and only after the underlying TCP connection has - disconnected. - """ - class CloseAfterHandshake(protocol.Protocol): - gotData = False - - def __init__(self): - self.done = defer.Deferred() - - def connectionMade(self): - self.transport.write(b"a") - - def dataReceived(self, data): - # If we got data, handshake is over: - self.gotData = True - self.transport.loseConnection() - - def connectionLost(self, reason): - if not self.gotData: - reason = RuntimeError("We never received the data!") - self.done.errback(reason) - del self.done - - org = "twisted.test.test_ssl" - self.setupServerAndClient( - (org, org + ", client"), {}, - (org, org + ", server"), {}) - - serverProtocol = CloseAfterHandshake() - serverProtocolFactory = protocol.ServerFactory() - serverProtocolFactory.protocol = lambda: serverProtocol - serverPort = reactor.listenSSL(0, - serverProtocolFactory, self.serverCtxFactory) - self.addCleanup(serverPort.stopListening) - - clientProtocol = CloseAfterHandshake() - clientProtocolFactory = protocol.ClientFactory() - clientProtocolFactory.protocol = lambda: clientProtocol - reactor.connectSSL('127.0.0.1', - serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory) - - def checkResult(failure): - failure.trap(ConnectionDone) - return defer.gatherResults( - [clientProtocol.done.addErrback(checkResult), - serverProtocol.done.addErrback(checkResult)]) - - if newTLS is None: - test_bothSidesLoseConnection.skip = "Old SSL code doesn't always close cleanly." - - - def testFailedVerify(self): - org = "twisted.test.test_ssl" - self.setupServerAndClient( - (org, org + ", client"), {}, - (org, org + ", server"), {}) - - def verify(*a): - return False - self.clientCtxFactory.getContext().set_verify(SSL.VERIFY_PEER, verify) - - serverConnLost = defer.Deferred() - serverProtocol = protocol.Protocol() - serverProtocol.connectionLost = serverConnLost.callback - serverProtocolFactory = protocol.ServerFactory() - serverProtocolFactory.protocol = lambda: serverProtocol - self.serverPort = serverPort = reactor.listenSSL(0, - serverProtocolFactory, self.serverCtxFactory) - - clientConnLost = defer.Deferred() - clientProtocol = protocol.Protocol() - clientProtocol.connectionLost = clientConnLost.callback - clientProtocolFactory = protocol.ClientFactory() - clientProtocolFactory.protocol = lambda: clientProtocol - reactor.connectSSL('127.0.0.1', - serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory) - - dl = defer.DeferredList([serverConnLost, clientConnLost], consumeErrors=True) - return dl.addCallback(self._cbLostConns) - - - def _cbLostConns(self, results): - (sSuccess, sResult), (cSuccess, cResult) = results - - self.failIf(sSuccess) - self.failIf(cSuccess) - - acceptableErrors = [SSL.Error] - - # Rather than getting a verification failure on Windows, we are getting - # a connection failure. Without something like sslverify proxying - # in-between we can't fix up the platform's errors, so let's just - # specifically say it is only OK in this one case to keep the tests - # passing. Normally we'd like to be as strict as possible here, so - # we're not going to allow this to report errors incorrectly on any - # other platforms. - - if platform.isWindows(): - from twisted.internet.error import ConnectionLost - acceptableErrors.append(ConnectionLost) - - sResult.trap(*acceptableErrors) - cResult.trap(*acceptableErrors) - - return self.serverPort.stopListening() - - - -class FakeContext: - """ - L{OpenSSL.SSL.Context} double which can more easily be inspected. - """ - def __init__(self, method): - self._method = method - self._options = 0 - - - def set_options(self, options): - self._options |= options - - - def use_certificate_file(self, fileName): - pass - - - def use_privatekey_file(self, fileName): - pass - - - -class DefaultOpenSSLContextFactoryTests(unittest.TestCase): - """ - Tests for L{ssl.DefaultOpenSSLContextFactory}. - """ - def setUp(self): - # pyOpenSSL Context objects aren't introspectable enough. Pass in - # an alternate context factory so we can inspect what is done to it. - self.contextFactory = ssl.DefaultOpenSSLContextFactory( - certPath, certPath, _contextFactory=FakeContext) - self.context = self.contextFactory.getContext() - - - def test_method(self): - """ - L{ssl.DefaultOpenSSLContextFactory.getContext} returns an SSL context - which can use SSLv3 or TLSv1 but not SSLv2. - """ - # SSLv23_METHOD allows SSLv2, SSLv3, or TLSv1 - self.assertEqual(self.context._method, SSL.SSLv23_METHOD) - - # And OP_NO_SSLv2 disables the SSLv2 support. - self.assertTrue(self.context._options & SSL.OP_NO_SSLv2) - - # Make sure SSLv3 and TLSv1 aren't disabled though. - self.assertFalse(self.context._options & SSL.OP_NO_SSLv3) - self.assertFalse(self.context._options & SSL.OP_NO_TLSv1) - - - def test_missingCertificateFile(self): - """ - Instantiating L{ssl.DefaultOpenSSLContextFactory} with a certificate - filename which does not identify an existing file results in the - initializer raising L{OpenSSL.SSL.Error}. - """ - self.assertRaises( - SSL.Error, - ssl.DefaultOpenSSLContextFactory, certPath, self.mktemp()) - - - def test_missingPrivateKeyFile(self): - """ - Instantiating L{ssl.DefaultOpenSSLContextFactory} with a private key - filename which does not identify an existing file results in the - initializer raising L{OpenSSL.SSL.Error}. - """ - self.assertRaises( - SSL.Error, - ssl.DefaultOpenSSLContextFactory, self.mktemp(), certPath) - - - -class ClientContextFactoryTests(unittest.TestCase): - """ - Tests for L{ssl.ClientContextFactory}. - """ - def setUp(self): - self.contextFactory = ssl.ClientContextFactory() - self.contextFactory._contextFactory = FakeContext - self.context = self.contextFactory.getContext() - - - def test_method(self): - """ - L{ssl.ClientContextFactory.getContext} returns a context which can use - SSLv3 or TLSv1 but not SSLv2. - """ - self.assertEqual(self.context._method, SSL.SSLv23_METHOD) - self.assertTrue(self.context._options & SSL.OP_NO_SSLv2) - self.assertFalse(self.context._options & SSL.OP_NO_SSLv3) - self.assertFalse(self.context._options & SSL.OP_NO_TLSv1) - - - -if interfaces.IReactorSSL(reactor, None) is None: - for tCase in [StolenTCPTests, TLSTests, SpammyTLSTests, - BufferingTests, ConnectionLostTests, - DefaultOpenSSLContextFactoryTests, - ClientContextFactoryTests]: - tCase.skip = "Reactor does not support SSL, cannot run SSL tests" - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sslverify.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sslverify.py deleted file mode 100644 index 89617bd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_sslverify.py +++ /dev/null @@ -1,2457 +0,0 @@ -# Copyright 2005 Divmod, Inc. See LICENSE file for details -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet._sslverify}. -""" - -from __future__ import division, absolute_import - -import sys -import itertools - -from zope.interface import implementer - -skipSSL = None -skipSNI = None -try: - import OpenSSL -except ImportError: - skipSSL = "OpenSSL is required for SSL tests." - skipSNI = skipSSL -else: - from OpenSSL import SSL - from OpenSSL.crypto import PKey, X509 - from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM - if getattr(SSL.Context, "set_tlsext_servername_callback", None) is None: - skipSNI = "PyOpenSSL 0.13 or greater required for SNI support." - -from twisted.test.test_twisted import SetAsideModule -from twisted.test.iosim import connectedServerAndClient - -from twisted.internet.error import ConnectionClosed -from twisted.python.compat import nativeString, _PY3 -from twisted.python.constants import NamedConstant, Names -from twisted.python.filepath import FilePath - -from twisted.trial import unittest, util -from twisted.internet import protocol, defer, reactor - -from twisted.internet.error import CertificateError, ConnectionLost -from twisted.internet import interfaces -from twisted.python.versions import Version - -if not skipSSL: - from twisted.internet.ssl import platformTrust, VerificationError - from twisted.internet import _sslverify as sslverify - from twisted.protocols.tls import TLSMemoryBIOFactory - -# A couple of static PEM-format certificates to be used by various tests. -A_HOST_CERTIFICATE_PEM = """ ------BEGIN CERTIFICATE----- - MIIC2jCCAkMCAjA5MA0GCSqGSIb3DQEBBAUAMIG0MQswCQYDVQQGEwJVUzEiMCAG - A1UEAxMZZXhhbXBsZS50d2lzdGVkbWF0cml4LmNvbTEPMA0GA1UEBxMGQm9zdG9u - MRwwGgYDVQQKExNUd2lzdGVkIE1hdHJpeCBMYWJzMRYwFAYDVQQIEw1NYXNzYWNo - dXNldHRzMScwJQYJKoZIhvcNAQkBFhhub2JvZHlAdHdpc3RlZG1hdHJpeC5jb20x - ETAPBgNVBAsTCFNlY3VyaXR5MB4XDTA2MDgxNjAxMDEwOFoXDTA3MDgxNjAxMDEw - OFowgbQxCzAJBgNVBAYTAlVTMSIwIAYDVQQDExlleGFtcGxlLnR3aXN0ZWRtYXRy - aXguY29tMQ8wDQYDVQQHEwZCb3N0b24xHDAaBgNVBAoTE1R3aXN0ZWQgTWF0cml4 - IExhYnMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxJzAlBgkqhkiG9w0BCQEWGG5v - Ym9keUB0d2lzdGVkbWF0cml4LmNvbTERMA8GA1UECxMIU2VjdXJpdHkwgZ8wDQYJ - KoZIhvcNAQEBBQADgY0AMIGJAoGBAMzH8CDF/U91y/bdbdbJKnLgnyvQ9Ig9ZNZp - 8hpsu4huil60zF03+Lexg2l1FIfURScjBuaJMR6HiMYTMjhzLuByRZ17KW4wYkGi - KXstz03VIKy4Tjc+v4aXFI4XdRw10gGMGQlGGscXF/RSoN84VoDKBfOMWdXeConJ - VyC4w3iJAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAviMT4lBoxOgQy32LIgZ4lVCj - JNOiZYg8GMQ6y0ugp86X80UjOvkGtNf/R7YgED/giKRN/q/XJiLJDEhzknkocwmO - S+4b2XpiaZYxRyKWwL221O7CGmtWYyZl2+92YYmmCiNzWQPfP6BOMlfax0AGLHls - fXzCWdG0O/3Lk2SRM0I= ------END CERTIFICATE----- -""" - -A_PEER_CERTIFICATE_PEM = """ ------BEGIN CERTIFICATE----- - MIIC3jCCAkcCAjA6MA0GCSqGSIb3DQEBBAUAMIG2MQswCQYDVQQGEwJVUzEiMCAG - A1UEAxMZZXhhbXBsZS50d2lzdGVkbWF0cml4LmNvbTEPMA0GA1UEBxMGQm9zdG9u - MRwwGgYDVQQKExNUd2lzdGVkIE1hdHJpeCBMYWJzMRYwFAYDVQQIEw1NYXNzYWNo - dXNldHRzMSkwJwYJKoZIhvcNAQkBFhpzb21lYm9keUB0d2lzdGVkbWF0cml4LmNv - bTERMA8GA1UECxMIU2VjdXJpdHkwHhcNMDYwODE2MDEwMTU2WhcNMDcwODE2MDEw - MTU2WjCBtjELMAkGA1UEBhMCVVMxIjAgBgNVBAMTGWV4YW1wbGUudHdpc3RlZG1h - dHJpeC5jb20xDzANBgNVBAcTBkJvc3RvbjEcMBoGA1UEChMTVHdpc3RlZCBNYXRy - aXggTGFiczEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEpMCcGCSqGSIb3DQEJARYa - c29tZWJvZHlAdHdpc3RlZG1hdHJpeC5jb20xETAPBgNVBAsTCFNlY3VyaXR5MIGf - MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnm+WBlgFNbMlHehib9ePGGDXF+Nz4 - CjGuUmVBaXCRCiVjg3kSDecwqfb0fqTksBZ+oQ1UBjMcSh7OcvFXJZnUesBikGWE - JE4V8Bjh+RmbJ1ZAlUPZ40bAkww0OpyIRAGMvKG+4yLFTO4WDxKmfDcrOb6ID8WJ - e1u+i3XGkIf/5QIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAD4Oukm3YYkhedUepBEA - vvXIQhVDqL7mk6OqYdXmNj6R7ZMC8WWvGZxrzDI1bZuB+4aIxxd1FXC3UOHiR/xg - i9cDl1y8P/qRp4aEBNF6rI0D4AxTbfnHQx4ERDAOShJdYZs/2zifPJ6va6YvrEyr - yqDtGhklsWW3ZwBzEh5VEOUp ------END CERTIFICATE----- -""" - - - -class DummyOpenSSL(object): - """ - A fake of the L{OpenSSL} module. - - @ivar __version__: A string describing I{pyOpenSSL} version number the fake - is emulating. - @type __version__: L{str} - """ - def __init__(self, major, minor, patch=None): - """ - @param major: The major version number to emulate. I{X} in the version - I{X.Y}. - @type major: L{int} - - @param minor: The minor version number to emulate. I{Y} in the version - I{X.Y}. - @type minor: L{int} - - """ - self.__version__ = "%d.%d" % (major, minor) - if patch is not None: - self.__version__ += ".%d" % (patch,) - -_preTwelveOpenSSL = DummyOpenSSL(0, 11) -_postTwelveOpenSSL = DummyOpenSSL(0, 13, 1) - - -def counter(counter=itertools.count()): - """ - Each time we're called, return the next integer in the natural numbers. - """ - return next(counter) - - - -def makeCertificate(**kw): - keypair = PKey() - keypair.generate_key(TYPE_RSA, 768) - - certificate = X509() - certificate.gmtime_adj_notBefore(0) - certificate.gmtime_adj_notAfter(60 * 60 * 24 * 365) # One year - for xname in certificate.get_issuer(), certificate.get_subject(): - for (k, v) in kw.items(): - setattr(xname, k, nativeString(v)) - - certificate.set_serial_number(counter()) - certificate.set_pubkey(keypair) - certificate.sign(keypair, "md5") - - return keypair, certificate - - - -def certificatesForAuthorityAndServer(commonName=b'example.com'): - """ - Create a self-signed CA certificate and server certificate signed by the - CA. - - @param commonName: The C{commonName} to embed in the certificate. - @type commonName: L{bytes} - - @return: a 2-tuple of C{(certificate_authority_certificate, - server_certificate)} - @rtype: L{tuple} of (L{sslverify.Certificate}, - L{sslverify.PrivateCertificate}) - """ - serverDN = sslverify.DistinguishedName(commonName=commonName) - serverKey = sslverify.KeyPair.generate() - serverCertReq = serverKey.certificateRequest(serverDN) - - caDN = sslverify.DistinguishedName(commonName=b'CA') - caKey= sslverify.KeyPair.generate() - caCertReq = caKey.certificateRequest(caDN) - caSelfCertData = caKey.signCertificateRequest( - caDN, caCertReq, lambda dn: True, 516) - caSelfCert = caKey.newCertificate(caSelfCertData) - - serverCertData = caKey.signCertificateRequest( - caDN, serverCertReq, lambda dn: True, 516) - serverCert = serverKey.newCertificate(serverCertData) - return caSelfCert, serverCert - - - -def loopbackTLSConnection(trustRoot, privateKeyFile, chainedCertFile=None): - """ - Create a loopback TLS connection with the given trust and keys. - - @param trustRoot: the C{trustRoot} argument for the client connection's - context. - @type trustRoot: L{sslverify.IOpenSSLTrustRoot} - - @param privateKeyFile: The name of the file containing the private key. - @type privateKeyFile: L{str} (native string; file name) - - @param chainedCertFile: The name of the chained certificate file. - @type chainedCertFile: L{str} (native string; file name) - - @return: 3-tuple of server-protocol, client-protocol, and L{IOPump} - @rtype: L{tuple} - """ - class ContextFactory(object): - def getContext(self): - """ - Create a context for the server side of the connection. - - @return: an SSL context using a certificate and key. - @rtype: C{OpenSSL.SSL.Context} - """ - ctx = SSL.Context(SSL.TLSv1_METHOD) - if chainedCertFile is not None: - ctx.use_certificate_chain_file(chainedCertFile) - ctx.use_privatekey_file(privateKeyFile) - # Let the test author know if they screwed something up. - ctx.check_privatekey() - return ctx - - class GreetingServer(protocol.Protocol): - greeting = b"greetings!" - def connectionMade(self): - self.transport.write(self.greeting) - - class ListeningClient(protocol.Protocol): - data = b'' - lostReason = None - def dataReceived(self, data): - self.data += data - def connectionLost(self, reason): - self.lostReason = reason - - serverOpts = ContextFactory() - clientOpts = sslverify.OpenSSLCertificateOptions(trustRoot=trustRoot) - - clientFactory = TLSMemoryBIOFactory( - clientOpts, isClient=True, - wrappedFactory=protocol.Factory.forProtocol(GreetingServer) - ) - serverFactory = TLSMemoryBIOFactory( - serverOpts, isClient=False, - wrappedFactory=protocol.Factory.forProtocol(ListeningClient) - ) - - sProto, cProto, pump = connectedServerAndClient( - lambda: serverFactory.buildProtocol(None), - lambda: clientFactory.buildProtocol(None) - ) - return sProto, cProto, pump - - - -def pathContainingDumpOf(testCase, *dumpables): - """ - Create a temporary file to store some serializable-as-PEM objects in, and - return its name. - - @param testCase: a test case to use for generating a temporary directory. - @type testCase: L{twisted.trial.unittest.TestCase} - - @param dumpables: arguments are objects from pyOpenSSL with a C{dump} - method, taking a pyOpenSSL file-type constant, such as - L{OpenSSL.crypto.FILETYPE_PEM} or L{OpenSSL.crypto.FILETYPE_ASN1}. - @type dumpables: L{tuple} of L{object} with C{dump} method taking L{int} - returning L{bytes} - - @return: the path to a file where all of the dumpables were dumped in PEM - format. - @rtype: L{str} - """ - fname = testCase.mktemp() - with open(fname, "wb") as f: - for dumpable in dumpables: - f.write(dumpable.dump(FILETYPE_PEM)) - return fname - - - -class DataCallbackProtocol(protocol.Protocol): - def dataReceived(self, data): - d, self.factory.onData = self.factory.onData, None - if d is not None: - d.callback(data) - - def connectionLost(self, reason): - d, self.factory.onLost = self.factory.onLost, None - if d is not None: - d.errback(reason) - -class WritingProtocol(protocol.Protocol): - byte = b'x' - def connectionMade(self): - self.transport.write(self.byte) - - def connectionLost(self, reason): - self.factory.onLost.errback(reason) - - - -class FakeContext(object): - """ - Introspectable fake of an C{OpenSSL.SSL.Context}. - - Saves call arguments for later introspection. - - Necessary because C{Context} offers poor introspection. cf. this - U{pyOpenSSL bug}. - - @ivar _method: See C{method} parameter of L{__init__}. - - @ivar _options: C{int} of C{OR}ed values from calls of L{set_options}. - - @ivar _certificate: Set by L{use_certificate}. - - @ivar _privateKey: Set by L{use_privatekey}. - - @ivar _verify: Set by L{set_verify}. - - @ivar _verifyDepth: Set by L{set_verify_depth}. - - @ivar _sessionID: Set by L{set_session_id}. - - @ivar _extraCertChain: Accumulated C{list} of all extra certificates added - by L{add_extra_chain_cert}. - - @ivar _cipherList: Set by L{set_cipher_list}. - - @ivar _dhFilename: Set by L{load_tmp_dh}. - - @ivar _defaultVerifyPathsSet: Set by L{set_default_verify_paths} - """ - _options = 0 - - def __init__(self, method): - self._method = method - self._extraCertChain = [] - self._defaultVerifyPathsSet = False - - - def set_options(self, options): - self._options |= options - - - def use_certificate(self, certificate): - self._certificate = certificate - - - def use_privatekey(self, privateKey): - self._privateKey = privateKey - - - def check_privatekey(self): - return None - - - def set_verify(self, flags, callback): - self._verify = flags, callback - - - def set_verify_depth(self, depth): - self._verifyDepth = depth - - - def set_session_id(self, sessionID): - self._sessionID = sessionID - - - def add_extra_chain_cert(self, cert): - self._extraCertChain.append(cert) - - - def set_cipher_list(self, cipherList): - self._cipherList = cipherList - - - def load_tmp_dh(self, dhfilename): - self._dhFilename = dhfilename - - - def set_default_verify_paths(self): - """ - Set the default paths for the platform. - """ - self._defaultVerifyPathsSet = True - - - -class ClientOptionsTests(unittest.SynchronousTestCase): - """ - Tests for L{sslverify.optionsForClientTLS}. - """ - if skipSSL: - skip = skipSSL - - def test_extraKeywords(self): - """ - When passed a keyword parameter other than C{extraCertificateOptions}, - L{sslverify.optionsForClientTLS} raises an exception just like a - normal Python function would. - """ - error = self.assertRaises( - TypeError, - sslverify.optionsForClientTLS, - hostname=u'alpha', someRandomThing=u'beta', - ) - self.assertEqual( - str(error), - "optionsForClientTLS() got an unexpected keyword argument " - "'someRandomThing'" - ) - - - def test_bytesFailFast(self): - """ - If you pass L{bytes} as the hostname to - L{sslverify.optionsForClientTLS} it immediately raises a L{TypeError}. - """ - error = self.assertRaises( - TypeError, - sslverify.optionsForClientTLS, b'not-actually-a-hostname.com' - ) - expectedText = ( - "optionsForClientTLS requires text for host names, not " + - bytes.__name__ - ) - self.assertEqual(str(error), expectedText) - - - -class OpenSSLOptionsTests(unittest.TestCase): - if skipSSL: - skip = skipSSL - - serverPort = clientConn = None - onServerLost = onClientLost = None - - sKey = None - sCert = None - cKey = None - cCert = None - - def setUp(self): - """ - Create class variables of client and server certificates. - """ - self.sKey, self.sCert = makeCertificate( - O=b"Server Test Certificate", - CN=b"server") - self.cKey, self.cCert = makeCertificate( - O=b"Client Test Certificate", - CN=b"client") - self.caCert1 = makeCertificate( - O=b"CA Test Certificate 1", - CN=b"ca1")[1] - self.caCert2 = makeCertificate( - O=b"CA Test Certificate", - CN=b"ca2")[1] - self.caCerts = [self.caCert1, self.caCert2] - self.extraCertChain = self.caCerts - - - def tearDown(self): - if self.serverPort is not None: - self.serverPort.stopListening() - if self.clientConn is not None: - self.clientConn.disconnect() - - L = [] - if self.onServerLost is not None: - L.append(self.onServerLost) - if self.onClientLost is not None: - L.append(self.onClientLost) - - return defer.DeferredList(L, consumeErrors=True) - - def loopback(self, serverCertOpts, clientCertOpts, - onServerLost=None, onClientLost=None, onData=None): - if onServerLost is None: - self.onServerLost = onServerLost = defer.Deferred() - if onClientLost is None: - self.onClientLost = onClientLost = defer.Deferred() - if onData is None: - onData = defer.Deferred() - - serverFactory = protocol.ServerFactory() - serverFactory.protocol = DataCallbackProtocol - serverFactory.onLost = onServerLost - serverFactory.onData = onData - - clientFactory = protocol.ClientFactory() - clientFactory.protocol = WritingProtocol - clientFactory.onLost = onClientLost - - self.serverPort = reactor.listenSSL(0, serverFactory, serverCertOpts) - self.clientConn = reactor.connectSSL('127.0.0.1', - self.serverPort.getHost().port, clientFactory, clientCertOpts) - - - def test_constructorWithOnlyPrivateKey(self): - """ - C{privateKey} and C{certificate} make only sense if both are set. - """ - self.assertRaises( - ValueError, - sslverify.OpenSSLCertificateOptions, privateKey=self.sKey - ) - - - def test_constructorWithOnlyCertificate(self): - """ - C{privateKey} and C{certificate} make only sense if both are set. - """ - self.assertRaises( - ValueError, - sslverify.OpenSSLCertificateOptions, certificate=self.sCert - ) - - - def test_constructorWithCertificateAndPrivateKey(self): - """ - Specifying C{privateKey} and C{certificate} initializes correctly. - """ - opts = sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert) - self.assertEqual(opts.privateKey, self.sKey) - self.assertEqual(opts.certificate, self.sCert) - self.assertEqual(opts.extraCertChain, []) - - - def test_constructorDoesNotAllowVerifyWithoutCACerts(self): - """ - C{verify} must not be C{True} without specifying C{caCerts}. - """ - self.assertRaises( - ValueError, - sslverify.OpenSSLCertificateOptions, - privateKey=self.sKey, certificate=self.sCert, verify=True - ) - - - def test_constructorDoesNotAllowLegacyWithTrustRoot(self): - """ - C{verify}, C{requireCertificate}, and C{caCerts} must not be specified - by the caller (to be I{any} value, even the default!) when specifying - C{trustRoot}. - """ - self.assertRaises( - TypeError, - sslverify.OpenSSLCertificateOptions, - privateKey=self.sKey, certificate=self.sCert, - verify=True, trustRoot=None, caCerts=self.caCerts, - ) - self.assertRaises( - TypeError, - sslverify.OpenSSLCertificateOptions, - privateKey=self.sKey, certificate=self.sCert, - trustRoot=None, requireCertificate=True, - ) - - - def test_constructorAllowsCACertsWithoutVerify(self): - """ - It's currently a NOP, but valid. - """ - opts = sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, - caCerts=self.caCerts) - self.assertFalse(opts.verify) - self.assertEqual(self.caCerts, opts.caCerts) - - - def test_constructorWithVerifyAndCACerts(self): - """ - Specifying C{verify} and C{caCerts} initializes correctly. - """ - opts = sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, - verify=True, - caCerts=self.caCerts) - self.assertTrue(opts.verify) - self.assertEqual(self.caCerts, opts.caCerts) - - - def test_constructorSetsExtraChain(self): - """ - Setting C{extraCertChain} works if C{certificate} and C{privateKey} are - set along with it. - """ - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - extraCertChain=self.extraCertChain, - ) - self.assertEqual(self.extraCertChain, opts.extraCertChain) - - - def test_constructorDoesNotAllowExtraChainWithoutPrivateKey(self): - """ - A C{extraCertChain} without C{privateKey} doesn't make sense and is - thus rejected. - """ - self.assertRaises( - ValueError, - sslverify.OpenSSLCertificateOptions, - certificate=self.sCert, - extraCertChain=self.extraCertChain, - ) - - - def test_constructorDoesNotAllowExtraChainWithOutPrivateKey(self): - """ - A C{extraCertChain} without C{certificate} doesn't make sense and is - thus rejected. - """ - self.assertRaises( - ValueError, - sslverify.OpenSSLCertificateOptions, - privateKey=self.sKey, - extraCertChain=self.extraCertChain, - ) - - - def test_extraChainFilesAreAddedIfSupplied(self): - """ - If C{extraCertChain} is set and all prerequisites are met, the - specified chain certificates are added to C{Context}s that get - created. - """ - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - extraCertChain=self.extraCertChain, - ) - opts._contextFactory = FakeContext - ctx = opts.getContext() - self.assertEqual(self.sKey, ctx._privateKey) - self.assertEqual(self.sCert, ctx._certificate) - self.assertEqual(self.extraCertChain, ctx._extraCertChain) - - - def test_extraChainDoesNotBreakPyOpenSSL(self): - """ - C{extraCertChain} doesn't break C{OpenSSL.SSL.Context} creation. - """ - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - extraCertChain=self.extraCertChain, - ) - ctx = opts.getContext() - self.assertIsInstance(ctx, SSL.Context) - - - def test_acceptableCiphersAreAlwaysSet(self): - """ - If the user doesn't supply custom acceptable ciphers, a shipped secure - default is used. We can't check directly for it because the effective - cipher string we set varies with platforms. - """ - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - ) - opts._contextFactory = FakeContext - ctx = opts.getContext() - self.assertEqual(opts._cipherString, ctx._cipherList) - - - def test_givesMeaningfulErrorMessageIfNoCipherMatches(self): - """ - If there is no valid cipher that matches the user's wishes, - a L{ValueError} is raised. - """ - self.assertRaises( - ValueError, - sslverify.OpenSSLCertificateOptions, - privateKey=self.sKey, - certificate=self.sCert, - acceptableCiphers= - sslverify.OpenSSLAcceptableCiphers.fromOpenSSLCipherString('') - ) - - - def test_honorsAcceptableCiphersArgument(self): - """ - If acceptable ciphers are passed, they are used. - """ - @implementer(interfaces.IAcceptableCiphers) - class FakeAcceptableCiphers(object): - def selectCiphers(self, _): - return [sslverify.OpenSSLCipher(u'sentinel')] - - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - acceptableCiphers=FakeAcceptableCiphers(), - ) - opts._contextFactory = FakeContext - ctx = opts.getContext() - self.assertEqual(u'sentinel', ctx._cipherList) - - - def test_basicSecurityOptionsAreSet(self): - """ - Every context must have C{OP_NO_SSLv2}, C{OP_NO_COMPRESSION}, and - C{OP_CIPHER_SERVER_PREFERENCE} set. - """ - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - ) - opts._contextFactory = FakeContext - ctx = opts.getContext() - options = (SSL.OP_NO_SSLv2 | opts._OP_NO_COMPRESSION | - opts._OP_CIPHER_SERVER_PREFERENCE) - self.assertEqual(options, ctx._options & options) - - - def test_singleUseKeys(self): - """ - If C{singleUseKeys} is set, every context must have - C{OP_SINGLE_DH_USE} and C{OP_SINGLE_ECDH_USE} set. - """ - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - enableSingleUseKeys=True, - ) - opts._contextFactory = FakeContext - ctx = opts.getContext() - options = SSL.OP_SINGLE_DH_USE | opts._OP_SINGLE_ECDH_USE - self.assertEqual(options, ctx._options & options) - - - def test_dhParams(self): - """ - If C{dhParams} is set, they are loaded into each new context. - """ - class FakeDiffieHellmanParameters(object): - _dhFile = FilePath(b'dh.params') - - dhParams = FakeDiffieHellmanParameters() - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - dhParameters=dhParams, - ) - opts._contextFactory = FakeContext - ctx = opts.getContext() - self.assertEqual( - FakeDiffieHellmanParameters._dhFile.path, - ctx._dhFilename - ) - - - def test_ecDoesNotBreakConstructor(self): - """ - Missing ECC does not break the constructor and sets C{_ecCurve} to - L{None}. - """ - def raiser(self): - raise NotImplementedError - self.patch(sslverify._OpenSSLECCurve, "_getBinding", raiser) - - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - ) - self.assertIs(None, opts._ecCurve) - - - def test_ecNeverBreaksGetContext(self): - """ - ECDHE support is best effort only and errors are ignored. - """ - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - ) - opts._ecCurve = object() - ctx = opts.getContext() - self.assertIsInstance(ctx, SSL.Context) - - - def test_ecSuccessWithRealBindings(self): - """ - Integration test that checks the positive code path to ensure that we - use the API properly. - """ - try: - defaultCurve = sslverify._OpenSSLECCurve( - sslverify._defaultCurveName - ) - except NotImplementedError: - raise unittest.SkipTest( - "Underlying pyOpenSSL is not based on cryptography." - ) - opts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - ) - self.assertEqual(defaultCurve, opts._ecCurve) - # Exercise positive code path. getContext swallows errors so we do it - # explicitly by hand. - opts._ecCurve.addECKeyToContext(opts.getContext()) - - - def test_abbreviatingDistinguishedNames(self): - """ - Check that abbreviations used in certificates correctly map to - complete names. - """ - self.assertEqual( - sslverify.DN(CN=b'a', OU=b'hello'), - sslverify.DistinguishedName(commonName=b'a', - organizationalUnitName=b'hello')) - self.assertNotEquals( - sslverify.DN(CN=b'a', OU=b'hello'), - sslverify.DN(CN=b'a', OU=b'hello', emailAddress=b'xxx')) - dn = sslverify.DN(CN=b'abcdefg') - self.assertRaises(AttributeError, setattr, dn, 'Cn', b'x') - self.assertEqual(dn.CN, dn.commonName) - dn.CN = b'bcdefga' - self.assertEqual(dn.CN, dn.commonName) - - - def testInspectDistinguishedName(self): - n = sslverify.DN(commonName=b'common name', - organizationName=b'organization name', - organizationalUnitName=b'organizational unit name', - localityName=b'locality name', - stateOrProvinceName=b'state or province name', - countryName=b'country name', - emailAddress=b'email address') - s = n.inspect() - for k in [ - 'common name', - 'organization name', - 'organizational unit name', - 'locality name', - 'state or province name', - 'country name', - 'email address']: - self.assertIn(k, s, "%r was not in inspect output." % (k,)) - self.assertIn(k.title(), s, "%r was not in inspect output." % (k,)) - - - def testInspectDistinguishedNameWithoutAllFields(self): - n = sslverify.DN(localityName=b'locality name') - s = n.inspect() - for k in [ - 'common name', - 'organization name', - 'organizational unit name', - 'state or province name', - 'country name', - 'email address']: - self.assertNotIn(k, s, "%r was in inspect output." % (k,)) - self.assertNotIn(k.title(), s, "%r was in inspect output." % (k,)) - self.assertIn('locality name', s) - self.assertIn('Locality Name', s) - - - def test_inspectCertificate(self): - """ - Test that the C{inspect} method of L{sslverify.Certificate} returns - a human-readable string containing some basic information about the - certificate. - """ - c = sslverify.Certificate.loadPEM(A_HOST_CERTIFICATE_PEM) - self.assertEqual( - c.inspect().split('\n'), - ["Certificate For Subject:", - " Common Name: example.twistedmatrix.com", - " Country Name: US", - " Email Address: nobody@twistedmatrix.com", - " Locality Name: Boston", - " Organization Name: Twisted Matrix Labs", - " Organizational Unit Name: Security", - " State Or Province Name: Massachusetts", - "", - "Issuer:", - " Common Name: example.twistedmatrix.com", - " Country Name: US", - " Email Address: nobody@twistedmatrix.com", - " Locality Name: Boston", - " Organization Name: Twisted Matrix Labs", - " Organizational Unit Name: Security", - " State Or Province Name: Massachusetts", - "", - "Serial Number: 12345", - "Digest: C4:96:11:00:30:C3:EC:EE:A3:55:AA:ED:8C:84:85:18", - # Maintenance Note: the algorithm used to compute the following - # "public key hash" is highly dubious and might break at some - # point in the future. See the docstring for PublicKey.keyHash - # for information on how this might be addressed in the future. - "Public Key with Hash: 50d4b8070143375b3330dedf3a8b9e91"]) - - - def test_publicKeyMatching(self): - """ - L{PublicKey.matches} returns L{True} for keys from certificates with - the same key, and L{False} for keys from certificates with different - keys. - """ - hostA = sslverify.Certificate.loadPEM(A_HOST_CERTIFICATE_PEM) - hostB = sslverify.Certificate.loadPEM(A_HOST_CERTIFICATE_PEM) - peerA = sslverify.Certificate.loadPEM(A_PEER_CERTIFICATE_PEM) - - self.assertTrue(hostA.getPublicKey().matches(hostB.getPublicKey())) - self.assertFalse(peerA.getPublicKey().matches(hostA.getPublicKey())) - - - def test_certificateOptionsSerialization(self): - """ - Test that __setstate__(__getstate__()) round-trips properly. - """ - firstOpts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - method=SSL.SSLv3_METHOD, - verify=True, - caCerts=[self.sCert], - verifyDepth=2, - requireCertificate=False, - verifyOnce=False, - enableSingleUseKeys=False, - enableSessions=False, - fixBrokenPeers=True, - enableSessionTickets=True) - context = firstOpts.getContext() - self.assertIdentical(context, firstOpts._context) - self.assertNotIdentical(context, None) - state = firstOpts.__getstate__() - self.assertNotIn("_context", state) - - opts = sslverify.OpenSSLCertificateOptions() - opts.__setstate__(state) - self.assertEqual(opts.privateKey, self.sKey) - self.assertEqual(opts.certificate, self.sCert) - self.assertEqual(opts.method, SSL.SSLv3_METHOD) - self.assertEqual(opts.verify, True) - self.assertEqual(opts.caCerts, [self.sCert]) - self.assertEqual(opts.verifyDepth, 2) - self.assertEqual(opts.requireCertificate, False) - self.assertEqual(opts.verifyOnce, False) - self.assertEqual(opts.enableSingleUseKeys, False) - self.assertEqual(opts.enableSessions, False) - self.assertEqual(opts.fixBrokenPeers, True) - self.assertEqual(opts.enableSessionTickets, True) - - test_certificateOptionsSerialization.suppress = [ - util.suppress(category = DeprecationWarning, - message='twisted\.internet\._sslverify\.*__[gs]etstate__')] - - - def test_certificateOptionsSessionTickets(self): - """ - Enabling session tickets should not set the OP_NO_TICKET option. - """ - opts = sslverify.OpenSSLCertificateOptions(enableSessionTickets=True) - ctx = opts.getContext() - self.assertEqual(0, ctx.set_options(0) & 0x00004000) - - - def test_certificateOptionsSessionTicketsDisabled(self): - """ - Enabling session tickets should set the OP_NO_TICKET option. - """ - opts = sslverify.OpenSSLCertificateOptions(enableSessionTickets=False) - ctx = opts.getContext() - self.assertEqual(0x00004000, ctx.set_options(0) & 0x00004000) - - - def test_allowedAnonymousClientConnection(self): - """ - Check that anonymous connections are allowed when certificates aren't - required on the server. - """ - onData = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, requireCertificate=False), - sslverify.OpenSSLCertificateOptions( - requireCertificate=False), - onData=onData) - - return onData.addCallback( - lambda result: self.assertEqual(result, WritingProtocol.byte)) - - - def test_refusedAnonymousClientConnection(self): - """ - Check that anonymous connections are refused when certificates are - required on the server. - """ - onServerLost = defer.Deferred() - onClientLost = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=True, - caCerts=[self.sCert], requireCertificate=True), - sslverify.OpenSSLCertificateOptions( - requireCertificate=False), - onServerLost=onServerLost, - onClientLost=onClientLost) - - d = defer.DeferredList([onClientLost, onServerLost], - consumeErrors=True) - - - def afterLost(result): - ((cSuccess, cResult), (sSuccess, sResult)) = result - self.failIf(cSuccess) - self.failIf(sSuccess) - # Win32 fails to report the SSL Error, and report a connection lost - # instead: there is a race condition so that's not totally - # surprising (see ticket #2877 in the tracker) - self.assertIsInstance(cResult.value, (SSL.Error, ConnectionLost)) - self.assertIsInstance(sResult.value, SSL.Error) - - return d.addCallback(afterLost) - - def test_failedCertificateVerification(self): - """ - Check that connecting with a certificate not accepted by the server CA - fails. - """ - onServerLost = defer.Deferred() - onClientLost = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=False, - requireCertificate=False), - sslverify.OpenSSLCertificateOptions(verify=True, - requireCertificate=False, caCerts=[self.cCert]), - onServerLost=onServerLost, - onClientLost=onClientLost) - - d = defer.DeferredList([onClientLost, onServerLost], - consumeErrors=True) - def afterLost(result): - ((cSuccess, cResult), (sSuccess, sResult)) = result - self.failIf(cSuccess) - self.failIf(sSuccess) - - return d.addCallback(afterLost) - - def test_successfulCertificateVerification(self): - """ - Test a successful connection with client certificate validation on - server side. - """ - onData = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=False, - requireCertificate=False), - sslverify.OpenSSLCertificateOptions(verify=True, - requireCertificate=True, caCerts=[self.sCert]), - onData=onData) - - return onData.addCallback( - lambda result: self.assertEqual(result, WritingProtocol.byte)) - - def test_successfulSymmetricSelfSignedCertificateVerification(self): - """ - Test a successful connection with validation on both server and client - sides. - """ - onData = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=True, - requireCertificate=True, caCerts=[self.cCert]), - sslverify.OpenSSLCertificateOptions(privateKey=self.cKey, - certificate=self.cCert, verify=True, - requireCertificate=True, caCerts=[self.sCert]), - onData=onData) - - return onData.addCallback( - lambda result: self.assertEqual(result, WritingProtocol.byte)) - - def test_verification(self): - """ - Check certificates verification building custom certificates data. - """ - clientDN = sslverify.DistinguishedName(commonName='client') - clientKey = sslverify.KeyPair.generate() - clientCertReq = clientKey.certificateRequest(clientDN) - - serverDN = sslverify.DistinguishedName(commonName='server') - serverKey = sslverify.KeyPair.generate() - serverCertReq = serverKey.certificateRequest(serverDN) - - clientSelfCertReq = clientKey.certificateRequest(clientDN) - clientSelfCertData = clientKey.signCertificateRequest( - clientDN, clientSelfCertReq, lambda dn: True, 132) - clientSelfCert = clientKey.newCertificate(clientSelfCertData) - - serverSelfCertReq = serverKey.certificateRequest(serverDN) - serverSelfCertData = serverKey.signCertificateRequest( - serverDN, serverSelfCertReq, lambda dn: True, 516) - serverSelfCert = serverKey.newCertificate(serverSelfCertData) - - clientCertData = serverKey.signCertificateRequest( - serverDN, clientCertReq, lambda dn: True, 7) - clientCert = clientKey.newCertificate(clientCertData) - - serverCertData = clientKey.signCertificateRequest( - clientDN, serverCertReq, lambda dn: True, 42) - serverCert = serverKey.newCertificate(serverCertData) - - onData = defer.Deferred() - - serverOpts = serverCert.options(serverSelfCert) - clientOpts = clientCert.options(clientSelfCert) - - self.loopback(serverOpts, - clientOpts, - onData=onData) - - return onData.addCallback( - lambda result: self.assertEqual(result, WritingProtocol.byte)) - - - -class DeprecationTests(unittest.SynchronousTestCase): - """ - Tests for deprecation of L{sslverify.OpenSSLCertificateOptions}'s support - of the pickle protocol. - """ - if skipSSL: - skip = skipSSL - - def test_getstateDeprecation(self): - """ - L{sslverify.OpenSSLCertificateOptions.__getstate__} is deprecated. - """ - self.callDeprecated( - (Version("Twisted", 15, 0, 0), "a real persistence system"), - sslverify.OpenSSLCertificateOptions().__getstate__) - - - def test_setstateDeprecation(self): - """ - L{sslverify.OpenSSLCertificateOptions.__setstate__} is deprecated. - """ - self.callDeprecated( - (Version("Twisted", 15, 0, 0), "a real persistence system"), - sslverify.OpenSSLCertificateOptions().__setstate__, {}) - - - -class ProtocolVersion(Names): - """ - L{ProtocolVersion} provides constants representing each version of the - SSL/TLS protocol. - """ - SSLv2 = NamedConstant() - SSLv3 = NamedConstant() - TLSv1_0 = NamedConstant() - TLSv1_1 = NamedConstant() - TLSv1_2 = NamedConstant() - - - -class ProtocolVersionTests(unittest.TestCase): - """ - Tests for L{sslverify.OpenSSLCertificateOptions}'s SSL/TLS version - selection features. - """ - if skipSSL: - skip = skipSSL - else: - _METHOD_TO_PROTOCOL = { - SSL.SSLv2_METHOD: set([ProtocolVersion.SSLv2]), - SSL.SSLv3_METHOD: set([ProtocolVersion.SSLv3]), - SSL.TLSv1_METHOD: set([ProtocolVersion.TLSv1_0]), - getattr(SSL, "TLSv1_1_METHOD", object()): - set([ProtocolVersion.TLSv1_1]), - getattr(SSL, "TLSv1_2_METHOD", object()): - set([ProtocolVersion.TLSv1_2]), - - # Presently, SSLv23_METHOD means (SSLv2, SSLv3, TLSv1.0, TLSv1.1, - # TLSv1.2) (excluding any protocol versions not implemented by the - # underlying version of OpenSSL). - SSL.SSLv23_METHOD: set(ProtocolVersion.iterconstants()), - } - - _EXCLUSION_OPS = { - SSL.OP_NO_SSLv2: ProtocolVersion.SSLv2, - SSL.OP_NO_SSLv3: ProtocolVersion.SSLv3, - SSL.OP_NO_TLSv1: ProtocolVersion.TLSv1_0, - getattr(SSL, "OP_NO_TLSv1_1", 0): ProtocolVersion.TLSv1_1, - getattr(SSL, "OP_NO_TLSv1_2", 0): ProtocolVersion.TLSv1_2, - } - - - def _protocols(self, opts): - """ - Determine which SSL/TLS protocol versions are allowed by C{opts}. - - @param opts: An L{sslverify.OpenSSLCertificateOptions} instance to - inspect. - - @return: A L{set} of L{NamedConstant}s from L{ProtocolVersion} - indicating which SSL/TLS protocol versions connections negotiated - using C{opts} will allow. - """ - protocols = self._METHOD_TO_PROTOCOL[opts.method].copy() - context = opts.getContext() - options = context.set_options(0) - if opts.method == SSL.SSLv23_METHOD: - # Exclusions apply only to SSLv23_METHOD and no others. - for opt, exclude in self._EXCLUSION_OPS.items(): - if options & opt: - protocols.discard(exclude) - return protocols - - - def test_default(self): - """ - When L{sslverify.OpenSSLCertificateOptions} is initialized with no - specific protocol versions all versions of TLS are allowed and no - versions of SSL are allowed. - """ - self.assertEqual( - set([ProtocolVersion.TLSv1_0, - ProtocolVersion.TLSv1_1, - ProtocolVersion.TLSv1_2]), - self._protocols(sslverify.OpenSSLCertificateOptions())) - - - def test_SSLv23(self): - """ - When L{sslverify.OpenSSLCertificateOptions} is initialized with - C{SSLv23_METHOD} all versions of TLS and SSLv3 are allowed. - """ - self.assertEqual( - set([ProtocolVersion.SSLv3, - ProtocolVersion.TLSv1_0, - ProtocolVersion.TLSv1_1, - ProtocolVersion.TLSv1_2]), - self._protocols(sslverify.OpenSSLCertificateOptions( - method=SSL.SSLv23_METHOD))) - - - -class TrustRootTests(unittest.TestCase): - """ - Tests for L{sslverify.OpenSSLCertificateOptions}' C{trustRoot} argument, - L{sslverify.platformTrust}, and their interactions. - """ - if skipSSL: - skip = skipSSL - - def test_caCertsPlatformDefaults(self): - """ - Specifying a C{trustRoot} of L{sslverify.OpenSSLDefaultPaths} when - initializing L{sslverify.OpenSSLCertificateOptions} loads the - platform-provided trusted certificates via C{set_default_verify_paths}. - """ - opts = sslverify.OpenSSLCertificateOptions( - trustRoot=sslverify.OpenSSLDefaultPaths(), - ) - fc = FakeContext(SSL.TLSv1_METHOD) - opts._contextFactory = lambda method: fc - opts.getContext() - self.assertTrue(fc._defaultVerifyPathsSet) - - - def test_trustRootPlatformRejectsUntrustedCA(self): - """ - Specifying a C{trustRoot} of L{platformTrust} when initializing - L{sslverify.OpenSSLCertificateOptions} causes certificates issued by a - newly created CA to be rejected by an SSL connection using these - options. - - Note that this test should I{always} pass, even on platforms where the - CA certificates are not installed, as long as L{platformTrust} rejects - completely invalid / unknown root CA certificates. This is simply a - smoke test to make sure that verification is happening at all. - """ - caSelfCert, serverCert = certificatesForAuthorityAndServer() - chainedCert = pathContainingDumpOf(self, serverCert, caSelfCert) - privateKey = pathContainingDumpOf(self, serverCert.privateKey) - - sProto, cProto, pump = loopbackTLSConnection( - trustRoot=platformTrust(), - privateKeyFile=privateKey, - chainedCertFile=chainedCert, - ) - # No data was received. - self.assertEqual(cProto.wrappedProtocol.data, b'') - - # It was an L{SSL.Error}. - self.assertEqual(cProto.wrappedProtocol.lostReason.type, SSL.Error) - - # Some combination of OpenSSL and PyOpenSSL is bad at reporting errors. - err = cProto.wrappedProtocol.lostReason.value - self.assertEqual(err.args[0][0][2], 'tlsv1 alert unknown ca') - - - def test_trustRootSpecificCertificate(self): - """ - Specifying a L{Certificate} object for L{trustRoot} will result in that - certificate being the only trust root for a client. - """ - caCert, serverCert = certificatesForAuthorityAndServer() - otherCa, otherServer = certificatesForAuthorityAndServer() - sProto, cProto, pump = loopbackTLSConnection( - trustRoot=caCert, - privateKeyFile=pathContainingDumpOf(self, serverCert.privateKey), - chainedCertFile=pathContainingDumpOf(self, serverCert), - ) - pump.flush() - self.assertIs(cProto.wrappedProtocol.lostReason, None) - self.assertEqual(cProto.wrappedProtocol.data, - sProto.wrappedProtocol.greeting) - - - -class ServiceIdentityTests(unittest.SynchronousTestCase): - """ - Tests for the verification of the peer's service's identity via the - C{hostname} argument to L{sslverify.OpenSSLCertificateOptions}. - """ - - if skipSSL: - skip = skipSSL - - def serviceIdentitySetup(self, clientHostname, serverHostname, - serverContextSetup=lambda ctx: None, - validCertificate=True, - clientPresentsCertificate=False, - validClientCertificate=True, - serverVerifies=False, - buggyInfoCallback=False, - fakePlatformTrust=False, - useDefaultTrust=False): - """ - Connect a server and a client. - - @param clientHostname: The I{client's idea} of the server's hostname; - passed as the C{hostname} to the - L{sslverify.OpenSSLCertificateOptions} instance. - @type clientHostname: L{unicode} - - @param serverHostname: The I{server's own idea} of the server's - hostname; present in the certificate presented by the server. - @type serverHostname: L{unicode} - - @param serverContextSetup: a 1-argument callable invoked with the - L{OpenSSL.SSL.Context} after it's produced. - @type serverContextSetup: L{callable} taking L{OpenSSL.SSL.Context} - returning L{NoneType}. - - @param validCertificate: Is the server's certificate valid? L{True} if - so, L{False} otherwise. - @type validCertificate: L{bool} - - @param clientPresentsCertificate: Should the client present a - certificate to the server? Defaults to 'no'. - @type clientPresentsCertificate: L{bool} - - @param validClientCertificate: If the client presents a certificate, - should it actually be a valid one, i.e. signed by the same CA that - the server is checking? Defaults to 'yes'. - @type validClientCertificate: L{bool} - - @param serverVerifies: Should the server verify the client's - certificate? Defaults to 'no'. - @type serverVerifies: L{bool} - - @param buggyInfoCallback: Should we patch the implementation so that - the C{info_callback} passed to OpenSSL to have a bug and raise an - exception (L{ZeroDivisionError})? Defaults to 'no'. - @type buggyInfoCallback: L{bool} - - @param fakePlatformTrust: Should we fake the platformTrust to be the - same as our fake server certificate authority, so that we can test - it's being used? Defaults to 'no' and we just pass platform trust. - @type fakePlatformTrust: L{bool} - - @param useDefaultTrust: Should we avoid passing the C{trustRoot} to - L{ssl.optionsForClientTLS}? Defaults to 'no'. - @type useDefaultTrust: L{bool} - - @return: see L{connectedServerAndClient}. - @rtype: see L{connectedServerAndClient}. - """ - serverIDNA = sslverify._idnaBytes(serverHostname) - serverCA, serverCert = certificatesForAuthorityAndServer(serverIDNA) - other = {} - passClientCert = None - clientCA, clientCert = certificatesForAuthorityAndServer(u'client') - if serverVerifies: - other.update(trustRoot=clientCA) - - if clientPresentsCertificate: - if validClientCertificate: - passClientCert = clientCert - else: - bogusCA, bogus = certificatesForAuthorityAndServer(u'client') - passClientCert = bogus - - serverOpts = sslverify.OpenSSLCertificateOptions( - privateKey=serverCert.privateKey.original, - certificate=serverCert.original, - **other - ) - serverContextSetup(serverOpts.getContext()) - if not validCertificate: - serverCA, otherServer = certificatesForAuthorityAndServer( - serverIDNA - ) - if buggyInfoCallback: - def broken(*a, **k): - """ - Raise an exception. - - @param a: Arguments for an C{info_callback} - - @param k: Keyword arguments for an C{info_callback} - """ - 1 / 0 - self.patch( - sslverify.ClientTLSOptions, "_identityVerifyingInfoCallback", - broken, - ) - - signature = {'hostname': clientHostname} - if passClientCert: - signature.update(clientCertificate=passClientCert) - if not useDefaultTrust: - signature.update(trustRoot=serverCA) - if fakePlatformTrust: - self.patch(sslverify, "platformTrust", lambda: serverCA) - - clientOpts = sslverify.optionsForClientTLS(**signature) - - class GreetingServer(protocol.Protocol): - greeting = b"greetings!" - lostReason = None - data = b'' - def connectionMade(self): - self.transport.write(self.greeting) - def dataReceived(self, data): - self.data += data - def connectionLost(self, reason): - self.lostReason = reason - - class GreetingClient(protocol.Protocol): - greeting = b'cheerio!' - data = b'' - lostReason = None - def connectionMade(self): - self.transport.write(self.greeting) - def dataReceived(self, data): - self.data += data - def connectionLost(self, reason): - self.lostReason = reason - - self.serverOpts = serverOpts - self.clientOpts = clientOpts - - clientFactory = TLSMemoryBIOFactory( - clientOpts, isClient=True, - wrappedFactory=protocol.Factory.forProtocol(GreetingClient) - ) - serverFactory = TLSMemoryBIOFactory( - serverOpts, isClient=False, - wrappedFactory=protocol.Factory.forProtocol(GreetingServer) - ) - return connectedServerAndClient( - lambda: serverFactory.buildProtocol(None), - lambda: clientFactory.buildProtocol(None), - ) - - - def test_invalidHostname(self): - """ - When a certificate containing an invalid hostname is received from the - server, the connection is immediately dropped. - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"wrong-host.example.com", - u"correct-host.example.com", - ) - self.assertEqual(cProto.wrappedProtocol.data, b'') - self.assertEqual(sProto.wrappedProtocol.data, b'') - - cErr = cProto.wrappedProtocol.lostReason.value - sErr = sProto.wrappedProtocol.lostReason.value - - self.assertIsInstance(cErr, VerificationError) - self.assertIsInstance(sErr, ConnectionClosed) - - - def test_validHostname(self): - """ - Whenever a valid certificate containing a valid hostname is received, - connection proceeds normally. - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"valid.example.com", - u"valid.example.com", - ) - self.assertEqual(cProto.wrappedProtocol.data, - b'greetings!') - - cErr = cProto.wrappedProtocol.lostReason - sErr = sProto.wrappedProtocol.lostReason - self.assertIdentical(cErr, None) - self.assertIdentical(sErr, None) - - - def test_validHostnameInvalidCertificate(self): - """ - When an invalid certificate containing a perfectly valid hostname is - received, the connection is aborted with an OpenSSL error. - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"valid.example.com", - u"valid.example.com", - validCertificate=False, - ) - - self.assertEqual(cProto.wrappedProtocol.data, b'') - self.assertEqual(sProto.wrappedProtocol.data, b'') - - cErr = cProto.wrappedProtocol.lostReason.value - sErr = sProto.wrappedProtocol.lostReason.value - - self.assertIsInstance(cErr, SSL.Error) - self.assertIsInstance(sErr, SSL.Error) - - - def test_realCAsBetterNotSignOurBogusTestCerts(self): - """ - If we use the default trust from the platform, our dinky certificate - should I{really} fail. - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"valid.example.com", - u"valid.example.com", - validCertificate=False, - useDefaultTrust=True, - ) - - self.assertEqual(cProto.wrappedProtocol.data, b'') - self.assertEqual(sProto.wrappedProtocol.data, b'') - - cErr = cProto.wrappedProtocol.lostReason.value - sErr = sProto.wrappedProtocol.lostReason.value - - self.assertIsInstance(cErr, SSL.Error) - self.assertIsInstance(sErr, SSL.Error) - - - def test_butIfTheyDidItWouldWork(self): - """ - L{ssl.optionsForClientTLS} should be using L{ssl.platformTrust} by - default, so if we fake that out then it should trust ourselves again. - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"valid.example.com", - u"valid.example.com", - useDefaultTrust=True, - fakePlatformTrust=True, - ) - self.assertEqual(cProto.wrappedProtocol.data, - b'greetings!') - - cErr = cProto.wrappedProtocol.lostReason - sErr = sProto.wrappedProtocol.lostReason - self.assertIdentical(cErr, None) - self.assertIdentical(sErr, None) - - - def test_clientPresentsCertificate(self): - """ - When the server verifies and the client presents a valid certificate - for that verification by passing it to - L{sslverify.optionsForClientTLS}, communication proceeds. - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"valid.example.com", - u"valid.example.com", - validCertificate=True, - serverVerifies=True, - clientPresentsCertificate=True, - ) - - self.assertEqual(cProto.wrappedProtocol.data, - b'greetings!') - - cErr = cProto.wrappedProtocol.lostReason - sErr = sProto.wrappedProtocol.lostReason - self.assertIdentical(cErr, None) - self.assertIdentical(sErr, None) - - - def test_clientPresentsBadCertificate(self): - """ - When the server verifies and the client presents an invalid certificate - for that verification by passing it to - L{sslverify.optionsForClientTLS}, the connection cannot be established - with an SSL error. - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"valid.example.com", - u"valid.example.com", - validCertificate=True, - serverVerifies=True, - validClientCertificate=False, - clientPresentsCertificate=True, - ) - - self.assertEqual(cProto.wrappedProtocol.data, - b'') - - cErr = cProto.wrappedProtocol.lostReason.value - sErr = sProto.wrappedProtocol.lostReason.value - - self.assertIsInstance(cErr, SSL.Error) - self.assertIsInstance(sErr, SSL.Error) - - - def test_hostnameIsIndicated(self): - """ - Specifying the C{hostname} argument to L{CertificateOptions} also sets - the U{Server Name Extension - } TLS indication - field to the correct value. - """ - names = [] - def setupServerContext(ctx): - def servername_received(conn): - names.append(conn.get_servername().decode("ascii")) - ctx.set_tlsext_servername_callback(servername_received) - cProto, sProto, pump = self.serviceIdentitySetup( - u"valid.example.com", - u"valid.example.com", - setupServerContext - ) - self.assertEqual(names, [u"valid.example.com"]) - - if skipSNI is not None: - test_hostnameIsIndicated.skip = skipSNI - - - def test_hostnameEncoding(self): - """ - Hostnames are encoded as IDNA. - """ - names = [] - hello = u"h\N{LATIN SMALL LETTER A WITH ACUTE}llo.example.com" - def setupServerContext(ctx): - def servername_received(conn): - serverIDNA = sslverify._idnaText(conn.get_servername()) - names.append(serverIDNA) - ctx.set_tlsext_servername_callback(servername_received) - cProto, sProto, pump = self.serviceIdentitySetup( - hello, hello, setupServerContext - ) - self.assertEqual(names, [hello]) - self.assertEqual(cProto.wrappedProtocol.data, - b'greetings!') - - cErr = cProto.wrappedProtocol.lostReason - sErr = sProto.wrappedProtocol.lostReason - self.assertIdentical(cErr, None) - self.assertIdentical(sErr, None) - - if skipSNI is not None: - test_hostnameEncoding.skip = skipSNI - - - def test_fallback(self): - """ - L{sslverify.simpleVerifyHostname} checks string equality on the - commonName of a connection's certificate's subject, doing nothing if it - matches and raising L{VerificationError} if it doesn't. - """ - name = 'something.example.com' - class Connection(object): - def get_peer_certificate(self): - """ - Fake of L{OpenSSL.SSL.Connection.get_peer_certificate}. - - @return: A certificate with a known common name. - @rtype: L{OpenSSL.crypto.X509} - """ - cert = X509() - cert.get_subject().commonName = name - return cert - conn = Connection() - self.assertIdentical( - sslverify.simpleVerifyHostname(conn, u'something.example.com'), - None - ) - self.assertRaises( - sslverify.SimpleVerificationError, - sslverify.simpleVerifyHostname, conn, u'nonsense' - ) - - def test_surpriseFromInfoCallback(self): - """ - pyOpenSSL isn't always so great about reporting errors. If one occurs - in the verification info callback, it should be logged and the - connection should be shut down (if possible, anyway; the app_data could - be clobbered but there's no point testing for that). - """ - cProto, sProto, pump = self.serviceIdentitySetup( - u"correct-host.example.com", - u"correct-host.example.com", - buggyInfoCallback=True, - ) - self.assertEqual(cProto.wrappedProtocol.data, b'') - self.assertEqual(sProto.wrappedProtocol.data, b'') - - cErr = cProto.wrappedProtocol.lostReason.value - sErr = sProto.wrappedProtocol.lostReason.value - - self.assertIsInstance(cErr, ZeroDivisionError) - self.assertIsInstance(sErr, ConnectionClosed) - errors = self.flushLoggedErrors(ZeroDivisionError) - self.assertTrue(errors) - - - -class _NotSSLTransport: - def getHandle(self): - return self - - - -class _MaybeSSLTransport: - def getHandle(self): - return self - - def get_peer_certificate(self): - return None - - def get_host_certificate(self): - return None - - - -class _ActualSSLTransport: - def getHandle(self): - return self - - def get_host_certificate(self): - return sslverify.Certificate.loadPEM(A_HOST_CERTIFICATE_PEM).original - - def get_peer_certificate(self): - return sslverify.Certificate.loadPEM(A_PEER_CERTIFICATE_PEM).original - - - -class ConstructorsTests(unittest.TestCase): - if skipSSL: - skip = skipSSL - - def test_peerFromNonSSLTransport(self): - """ - Verify that peerFromTransport raises an exception if the transport - passed is not actually an SSL transport. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.peerFromTransport, - _NotSSLTransport()) - self.failUnless(str(x).startswith("non-TLS")) - - - def test_peerFromBlankSSLTransport(self): - """ - Verify that peerFromTransport raises an exception if the transport - passed is an SSL transport, but doesn't have a peer certificate. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.peerFromTransport, - _MaybeSSLTransport()) - self.failUnless(str(x).startswith("TLS")) - - - def test_hostFromNonSSLTransport(self): - """ - Verify that hostFromTransport raises an exception if the transport - passed is not actually an SSL transport. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.hostFromTransport, - _NotSSLTransport()) - self.failUnless(str(x).startswith("non-TLS")) - - - def test_hostFromBlankSSLTransport(self): - """ - Verify that hostFromTransport raises an exception if the transport - passed is an SSL transport, but doesn't have a host certificate. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.hostFromTransport, - _MaybeSSLTransport()) - self.failUnless(str(x).startswith("TLS")) - - - def test_hostFromSSLTransport(self): - """ - Verify that hostFromTransport successfully creates the correct - certificate if passed a valid SSL transport. - """ - self.assertEqual( - sslverify.Certificate.hostFromTransport( - _ActualSSLTransport()).serialNumber(), - 12345) - - - def test_peerFromSSLTransport(self): - """ - Verify that peerFromTransport successfully creates the correct - certificate if passed a valid SSL transport. - """ - self.assertEqual( - sslverify.Certificate.peerFromTransport( - _ActualSSLTransport()).serialNumber(), - 12346) - - - -class OpenSSLCipherTests(unittest.TestCase): - """ - Tests for twisted.internet._sslverify.OpenSSLCipher. - """ - if skipSSL: - skip = skipSSL - - cipherName = u'CIPHER-STRING' - - def test_constructorSetsFullName(self): - """ - The first argument passed to the constructor becomes the full name. - """ - self.assertEqual( - self.cipherName, - sslverify.OpenSSLCipher(self.cipherName).fullName - ) - - - def test_repr(self): - """ - C{repr(cipher)} returns a valid constructor call. - """ - cipher = sslverify.OpenSSLCipher(self.cipherName) - self.assertEqual( - cipher, - eval(repr(cipher), {'OpenSSLCipher': sslverify.OpenSSLCipher}) - ) - - - def test_eqSameClass(self): - """ - Equal type and C{fullName} means that the objects are equal. - """ - cipher1 = sslverify.OpenSSLCipher(self.cipherName) - cipher2 = sslverify.OpenSSLCipher(self.cipherName) - self.assertEqual(cipher1, cipher2) - - - def test_eqSameNameDifferentType(self): - """ - If ciphers have the same name but different types, they're still - different. - """ - class DifferentCipher(object): - fullName = self.cipherName - - self.assertNotEqual( - sslverify.OpenSSLCipher(self.cipherName), - DifferentCipher(), - ) - - - -class ExpandCipherStringTests(unittest.TestCase): - """ - Tests for twisted.internet._sslverify._expandCipherString. - """ - if skipSSL: - skip = skipSSL - - def test_doesNotStumbleOverEmptyList(self): - """ - If the expanded cipher list is empty, an empty L{list} is returned. - """ - self.assertEqual( - [], - sslverify._expandCipherString(u'', SSL.SSLv23_METHOD, 0) - ) - - - def test_doesNotSwallowOtherSSLErrors(self): - """ - Only no cipher matches get swallowed, every other SSL error gets - propagated. - """ - def raiser(_): - # Unfortunately, there seems to be no way to trigger a real SSL - # error artificially. - raise SSL.Error([['', '', '']]) - ctx = FakeContext(SSL.SSLv23_METHOD) - ctx.set_cipher_list = raiser - self.patch(sslverify.SSL, 'Context', lambda _: ctx) - self.assertRaises( - SSL.Error, - sslverify._expandCipherString, u'ALL', SSL.SSLv23_METHOD, 0 - ) - - - def test_returnsListOfICiphers(self): - """ - L{sslverify._expandCipherString} always returns a L{list} of - L{interfaces.ICipher}. - """ - ciphers = sslverify._expandCipherString(u'ALL', SSL.SSLv23_METHOD, 0) - self.assertIsInstance(ciphers, list) - bogus = [] - for c in ciphers: - if not interfaces.ICipher.providedBy(c): - bogus.append(c) - - self.assertEqual([], bogus) - - - -class AcceptableCiphersTests(unittest.TestCase): - """ - Tests for twisted.internet._sslverify.OpenSSLAcceptableCiphers. - """ - if skipSSL: - skip = skipSSL - - def test_selectOnEmptyListReturnsEmptyList(self): - """ - If no ciphers are available, nothing can be selected. - """ - ac = sslverify.OpenSSLAcceptableCiphers([]) - self.assertEqual([], ac.selectCiphers([])) - - - def test_selectReturnsOnlyFromAvailable(self): - """ - Select only returns a cross section of what is available and what is - desirable. - """ - ac = sslverify.OpenSSLAcceptableCiphers([ - sslverify.OpenSSLCipher('A'), - sslverify.OpenSSLCipher('B'), - ]) - self.assertEqual([sslverify.OpenSSLCipher('B')], - ac.selectCiphers([sslverify.OpenSSLCipher('B'), - sslverify.OpenSSLCipher('C')])) - - - def test_fromOpenSSLCipherStringExpandsToListOfCiphers(self): - """ - If L{sslverify.OpenSSLAcceptableCiphers.fromOpenSSLCipherString} is - called it expands the string to a list of ciphers. - """ - ac = sslverify.OpenSSLAcceptableCiphers.fromOpenSSLCipherString('ALL') - self.assertIsInstance(ac._ciphers, list) - self.assertTrue(all(sslverify.ICipher.providedBy(c) - for c in ac._ciphers)) - - - -class DiffieHellmanParametersTests(unittest.TestCase): - """ - Tests for twisted.internet._sslverify.OpenSSLDHParameters. - """ - if skipSSL: - skip = skipSSL - filePath = FilePath(b'dh.params') - - def test_fromFile(self): - """ - Calling C{fromFile} with a filename returns an instance with that file - name saved. - """ - params = sslverify.OpenSSLDiffieHellmanParameters.fromFile( - self.filePath - ) - self.assertEqual(self.filePath, params._dhFile) - - - -class FakeECKey(object): - """ - An introspectable fake of a key. - - @ivar _nid: A free form nid. - """ - def __init__(self, nid): - self._nid = nid - - - -class FakeNID(object): - """ - An introspectable fake of a NID. - - @ivar _snName: A free form sn name. - """ - def __init__(self, snName): - self._snName = snName - - - -class FakeLib(object): - """ - An introspectable fake of cryptography's lib object. - - @ivar _createdKey: A set of keys that have been created by this instance. - @type _createdKey: L{set} of L{FakeKey} - - @cvar NID_undef: A symbolic constant for undefined NIDs. - @type NID_undef: L{FakeNID} - """ - NID_undef = FakeNID("undef") - - def __init__(self): - self._createdKeys = set() - - - def OBJ_sn2nid(self, snName): - """ - Create a L{FakeNID} with C{snName} and return it. - - @param snName: a free form name that gets passed to the constructor - of L{FakeNID}. - - @return: a new L{FakeNID}. - @rtype: L{FakeNID}. - """ - return FakeNID(snName) - - - def EC_KEY_new_by_curve_name(self, nid): - """ - Create a L{FakeECKey}, save it to C{_createdKeys} and return it. - - @param nid: an arbitrary object that is passed to the constructor of - L{FakeECKey}. - - @return: a new L{FakeECKey} - @rtype: L{FakeECKey} - """ - key = FakeECKey(nid) - self._createdKeys.add(key) - return key - - - def EC_KEY_free(self, key): - """ - Remove C{key} from C{_createdKey}. - - @param key: a key object to be freed; i.e. removed from - C{_createdKeys}. - - @raises ValueError: If C{key} is not in C{_createdKeys} and thus not - created by us. - """ - try: - self._createdKeys.remove(key) - except KeyError: - raise ValueError("Unallocated EC key attempted to free.") - - - def SSL_CTX_set_tmp_ecdh(self, ffiContext, key): - """ - Does not do anything. - - @param ffiContext: ignored - @param key: ignored - """ - - - -class FakeLibTests(unittest.TestCase): - """ - Tests for FakeLib - """ - def test_objSn2Nid(self): - """ - Returns a L{FakeNID} with correct name. - """ - nid = FakeNID("test") - self.assertEqual("test", nid._snName) - - - def test_emptyKeys(self): - """ - A new L{FakeLib} has an empty set for created keys. - """ - self.assertEqual(set(), FakeLib()._createdKeys) - - - def test_newKey(self): - """ - If a new key is created, it's added to C{_createdKeys}. - """ - lib = FakeLib() - key = lib.EC_KEY_new_by_curve_name(FakeNID("name")) - self.assertEqual(set([key]), lib._createdKeys) - - - def test_freeUnknownKey(self): - """ - Raise L{ValueError} if an unknown key is attempted to be freed. - """ - key = FakeECKey(object()) - self.assertRaises( - ValueError, - FakeLib().EC_KEY_free, key - ) - - - def test_freeKnownKey(self): - """ - Freeing an allocated key removes it from C{_createdKeys}. - """ - lib = FakeLib() - key = lib.EC_KEY_new_by_curve_name(FakeNID("name")) - lib.EC_KEY_free(key) - self.assertEqual(set(), lib._createdKeys) - - - -class FakeFFI(object): - """ - A fake of a cryptography's ffi object. - - @cvar NULL: Symbolic constant for CFFI's NULL objects. - """ - NULL = object() - - - -class FakeBinding(object): - """ - A fake of cryptography's binding object. - - @type lib: L{FakeLib} - @type ffi: L{FakeFFI} - """ - def __init__(self, lib=None, ffi=None): - self.lib = lib or FakeLib() - self.ffi = ffi or FakeFFI() - - - -class ECCurveTests(unittest.TestCase): - """ - Tests for twisted.internet._sslverify.OpenSSLECCurve. - """ - if skipSSL: - skip = skipSSL - - def test_missingBinding(self): - """ - Raise L{NotImplementedError} if pyOpenSSL is not based on cryptography. - """ - def raiser(self): - raise NotImplementedError - self.patch(sslverify._OpenSSLECCurve, "_getBinding", raiser) - self.assertRaises( - NotImplementedError, - sslverify._OpenSSLECCurve, sslverify._defaultCurveName, - ) - - - def test_nonECbinding(self): - """ - Raise L{NotImplementedError} if pyOpenSSL is based on cryptography but - cryptography lacks required EC methods. - """ - def raiser(self): - raise AttributeError - lib = FakeLib() - lib.OBJ_sn2nid = raiser - self.patch(sslverify._OpenSSLECCurve, - "_getBinding", - lambda self: FakeBinding(lib=lib)) - self.assertRaises( - NotImplementedError, - sslverify._OpenSSLECCurve, sslverify._defaultCurveName, - ) - - - def test_wrongName(self): - """ - Raise L{ValueError} on unknown sn names. - """ - lib = FakeLib() - lib.OBJ_sn2nid = lambda self: FakeLib.NID_undef - self.patch(sslverify._OpenSSLECCurve, - "_getBinding", - lambda self: FakeBinding(lib=lib)) - self.assertRaises( - ValueError, - sslverify._OpenSSLECCurve, u"doesNotExist", - ) - - - def test_keyFails(self): - """ - Raise L{EnvironmentError} if key creation fails. - """ - lib = FakeLib() - lib.EC_KEY_new_by_curve_name = lambda *a, **kw: FakeFFI.NULL - self.patch(sslverify._OpenSSLECCurve, - "_getBinding", - lambda self: FakeBinding(lib=lib)) - curve = sslverify._OpenSSLECCurve(sslverify._defaultCurveName) - self.assertRaises( - EnvironmentError, - curve.addECKeyToContext, object() - ) - - - def test_keyGetsFreed(self): - """ - Don't leak a key when adding it to a context. - """ - lib = FakeLib() - self.patch(sslverify._OpenSSLECCurve, - "_getBinding", - lambda self: FakeBinding(lib=lib)) - curve = sslverify._OpenSSLECCurve(sslverify._defaultCurveName) - ctx = FakeContext(None) - ctx._context = None - curve.addECKeyToContext(ctx) - self.assertEqual(set(), lib._createdKeys) - - - -class KeyPairTests(unittest.TestCase): - """ - Tests for L{sslverify.KeyPair}. - """ - if skipSSL: - skip = skipSSL - - def setUp(self): - """ - Create test certificate. - """ - self.sKey = makeCertificate( - O=b"Server Test Certificate", - CN=b"server")[0] - - - def test_getstateDeprecation(self): - """ - L{sslverify.KeyPair.__getstate__} is deprecated. - """ - self.callDeprecated( - (Version("Twisted", 15, 0, 0), "a real persistence system"), - sslverify.KeyPair(self.sKey).__getstate__) - - - def test_setstateDeprecation(self): - """ - {sslverify.KeyPair.__setstate__} is deprecated. - """ - state = sslverify.KeyPair(self.sKey).dump() - self.callDeprecated( - (Version("Twisted", 15, 0, 0), "a real persistence system"), - sslverify.KeyPair(self.sKey).__setstate__, state) - - - -class OpenSSLVersionTestsMixin(object): - """ - A mixin defining tests relating to the version declaration interface of - I{pyOpenSSL}. - - This is used to verify that the fake I{OpenSSL} module presents its fake - version information in the same way as the real L{OpenSSL} module. - """ - def test_string(self): - """ - C{OpenSSL.__version__} is a native string. - """ - self.assertIsInstance(self.OpenSSL.__version__, str) - - - def test_oneOrTwoDots(self): - """ - C{OpenSSL.__version__} has either two or three version components. - """ - self.assertIn(self.OpenSSL.__version__.count("."), (1, 2)) - - - def test_majorDotMinor(self): - """ - C{OpenSSL.__version__} declares the major and minor versions as - non-negative integers separated by C{"."}. - """ - parts = self.OpenSSL.__version__.split(".") - major = int(parts[0]) - minor = int(parts[1]) - self.assertEqual( - (True, True), - (major >= 0, minor >= 0)) - - - -class RealOpenSSLTests(OpenSSLVersionTestsMixin, unittest.SynchronousTestCase): - """ - Apply the pyOpenSSL version tests to the real C{OpenSSL} package. - """ - if skipSSL is None: - OpenSSL = OpenSSL - else: - skip = skipSSL - - - -class PreTwelveDummyOpenSSLTests(OpenSSLVersionTestsMixin, - unittest.SynchronousTestCase): - """ - Apply the pyOpenSSL version tests to an instance of L{DummyOpenSSL} that - pretends to be older than 0.12. - """ - OpenSSL = _preTwelveOpenSSL - - - -class PostTwelveDummyOpenSSLTests(OpenSSLVersionTestsMixin, - unittest.SynchronousTestCase): - """ - Apply the pyOpenSSL version tests to an instance of L{DummyOpenSSL} that - pretends to be newer than 0.12. - """ - OpenSSL = _postTwelveOpenSSL - - - -class SelectVerifyImplementationTests(unittest.SynchronousTestCase): - """ - Tests for L{_selectVerifyImplementation}. - """ - if skipSSL is not None: - skip = skipSSL - - def test_pyOpenSSLTooOld(self): - """ - If the version of I{pyOpenSSL} installed is older than 0.12 then - L{_selectVerifyImplementation} returns L{simpleVerifyHostname} and - L{SimpleVerificationError}. - """ - result = sslverify._selectVerifyImplementation(_preTwelveOpenSSL) - expected = ( - sslverify.simpleVerifyHostname, sslverify.SimpleVerificationError) - self.assertEqual(expected, result) - test_pyOpenSSLTooOld.suppress = [ - util.suppress( - message="Your version of pyOpenSSL, 0.11, is out of date."), - ] - - - def test_pyOpenSSLTooOldWarning(self): - """ - If the version of I{pyOpenSSL} installed is older than 0.12 then - L{_selectVerifyImplementation} emits a L{UserWarning} advising the user - to upgrade. - """ - sslverify._selectVerifyImplementation(_preTwelveOpenSSL) - [warning] = list( - warning - for warning - in self.flushWarnings() - if warning["category"] == UserWarning) - - expectedMessage = ( - "Your version of pyOpenSSL, 0.11, is out of date. Please upgrade " - "to at least 0.12 and install service_identity from " - ". Without the " - "service_identity module and a recent enough pyOpenSSL to support " - "it, Twisted can perform only rudimentary TLS client hostname " - "verification. Many valid certificate/hostname mappings may be " - "rejected.") - - self.assertEqual( - (warning["message"], warning["filename"], warning["lineno"]), - # Make sure we're abusing the warning system to a sufficient - # degree: there is no filename or line number that makes sense for - # this warning to "blame" for the problem. It is a system - # misconfiguration. So the location information should be blank - # (or as blank as we can make it). - (expectedMessage, "", 0)) - - - def test_dependencyMissing(self): - """ - If I{service_identity} cannot be imported then - L{_selectVerifyImplementation} returns L{simpleVerifyHostname} and - L{SimpleVerificationError}. - """ - with SetAsideModule("service_identity"): - sys.modules["service_identity"] = None - - result = sslverify._selectVerifyImplementation(_postTwelveOpenSSL) - expected = ( - sslverify.simpleVerifyHostname, - sslverify.SimpleVerificationError) - self.assertEqual(expected, result) - test_dependencyMissing.suppress = [ - util.suppress( - message=( - "You do not have a working installation of the " - "service_identity module"), - ), - ] - - - def test_dependencyMissingWarning(self): - """ - If I{service_identity} cannot be imported then - L{_selectVerifyImplementation} emits a L{UserWarning} advising the user - of the exact error. - """ - with SetAsideModule("service_identity"): - sys.modules["service_identity"] = None - - sslverify._selectVerifyImplementation(_postTwelveOpenSSL) - - [warning] = list( - warning - for warning - in self.flushWarnings() - if warning["category"] == UserWarning) - - if _PY3: - importError = ( - "'import of 'service_identity' halted; None in sys.modules'") - else: - importError = "'No module named service_identity'" - - expectedMessage = ( - "You do not have a working installation of the " - "service_identity module: {message}. Please install it from " - " " - "and make sure all of its dependencies are satisfied. " - "Without the service_identity module and a recent enough " - "pyOpenSSL to support it, Twisted can perform only " - "rudimentary TLS client hostname verification. Many valid " - "certificate/hostname mappings may be rejected.").format( - message=importError) - - self.assertEqual( - (warning["message"], warning["filename"], warning["lineno"]), - # See the comment in test_pyOpenSSLTooOldWarning. - (expectedMessage, "", 0)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stateful.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stateful.py deleted file mode 100644 index 85d5a65..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stateful.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.protocols.stateful -""" - -from twisted.trial.unittest import TestCase -from twisted.protocols.test import test_basic -from twisted.protocols.stateful import StatefulProtocol - -from struct import pack, unpack, calcsize - - -class MyInt32StringReceiver(StatefulProtocol): - """ - A stateful Int32StringReceiver. - """ - MAX_LENGTH = 99999 - structFormat = "!I" - prefixLength = calcsize(structFormat) - - def getInitialState(self): - return self._getHeader, 4 - - def lengthLimitExceeded(self, length): - self.transport.loseConnection() - - def _getHeader(self, msg): - length, = unpack("!i", msg) - if length > self.MAX_LENGTH: - self.lengthLimitExceeded(length) - return - return self._getString, length - - def _getString(self, msg): - self.stringReceived(msg) - return self._getHeader, 4 - - def stringReceived(self, msg): - """ - Override this. - """ - raise NotImplementedError - - def sendString(self, data): - """ - Send an int32-prefixed string to the other end of the connection. - """ - self.transport.write(pack(self.structFormat, len(data)) + data) - - -class TestInt32(MyInt32StringReceiver): - def connectionMade(self): - self.received = [] - - def stringReceived(self, s): - self.received.append(s) - - MAX_LENGTH = 50 - closed = 0 - - def connectionLost(self, reason): - self.closed = 1 - - -class Int32Tests(TestCase, test_basic.IntNTestCaseMixin): - protocol = TestInt32 - strings = ["a", "b" * 16] - illegalStrings = ["\x10\x00\x00\x00aaaaaa"] - partialStrings = ["\x00\x00\x00", "hello there", ""] - - def test_bigReceive(self): - r = self.getProtocol() - big = "" - for s in self.strings * 4: - big += pack("!i", len(s)) + s - r.dataReceived(big) - self.assertEqual(r.received, self.strings * 4) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stdio.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stdio.py deleted file mode 100644 index f88b1a0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stdio.py +++ /dev/null @@ -1,370 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet.stdio}. -""" - -import os, sys, itertools - -from twisted.trial import unittest -from twisted.python import filepath, log -from twisted.python.reflect import requireModule -from twisted.python.runtime import platform -from twisted.internet import error, defer, protocol, stdio, reactor -from twisted.test.test_tcp import ConnectionLostNotifyingProtocol - - -# A short string which is intended to appear here and nowhere else, -# particularly not in any random garbage output CPython unavoidable -# generates (such as in warning text and so forth). This is searched -# for in the output from stdio_test_lastwrite.py and if it is found at -# the end, the functionality works. -UNIQUE_LAST_WRITE_STRING = 'xyz123abc Twisted is great!' - -skipWindowsNopywin32 = None -if platform.isWindows(): - if requireModule('win32process') is None: - skipWindowsNopywin32 = ("On windows, spawnProcess is not available " - "in the absence of win32process.") - - -class StandardIOTestProcessProtocol(protocol.ProcessProtocol): - """ - Test helper for collecting output from a child process and notifying - something when it exits. - - @ivar onConnection: A L{defer.Deferred} which will be called back with - C{None} when the connection to the child process is established. - - @ivar onCompletion: A L{defer.Deferred} which will be errbacked with the - failure associated with the child process exiting when it exits. - - @ivar onDataReceived: A L{defer.Deferred} which will be called back with - this instance whenever C{childDataReceived} is called, or C{None} to - suppress these callbacks. - - @ivar data: A C{dict} mapping file descriptors to strings containing all - bytes received from the child process on each file descriptor. - """ - onDataReceived = None - - def __init__(self): - self.onConnection = defer.Deferred() - self.onCompletion = defer.Deferred() - self.data = {} - - - def connectionMade(self): - self.onConnection.callback(None) - - - def childDataReceived(self, name, bytes): - """ - Record all bytes received from the child process in the C{data} - dictionary. Fire C{onDataReceived} if it is not C{None}. - """ - self.data[name] = self.data.get(name, '') + bytes - if self.onDataReceived is not None: - d, self.onDataReceived = self.onDataReceived, None - d.callback(self) - - - def processEnded(self, reason): - self.onCompletion.callback(reason) - - - -class StandardInputOutputTests(unittest.TestCase): - - skip = skipWindowsNopywin32 - - def _spawnProcess(self, proto, sibling, *args, **kw): - """ - Launch a child Python process and communicate with it using the - given ProcessProtocol. - - @param proto: A L{ProcessProtocol} instance which will be connected - to the child process. - - @param sibling: The basename of a file containing the Python program - to run in the child process. - - @param *args: strings which will be passed to the child process on - the command line as C{argv[2:]}. - - @param **kw: additional arguments to pass to L{reactor.spawnProcess}. - - @return: The L{IProcessTransport} provider for the spawned process. - """ - import twisted - subenv = dict(os.environ) - subenv['PYTHONPATH'] = os.pathsep.join( - [os.path.abspath( - os.path.dirname(os.path.dirname(twisted.__file__))), - subenv.get('PYTHONPATH', '') - ]) - args = [sys.executable, - filepath.FilePath(__file__).sibling(sibling).path, - reactor.__class__.__module__] + list(args) - return reactor.spawnProcess( - proto, - sys.executable, - args, - env=subenv, - **kw) - - - def _requireFailure(self, d, callback): - def cb(result): - self.fail("Process terminated with non-Failure: %r" % (result,)) - def eb(err): - return callback(err) - return d.addCallbacks(cb, eb) - - - def test_loseConnection(self): - """ - Verify that a protocol connected to L{StandardIO} can disconnect - itself using C{transport.loseConnection}. - """ - errorLogFile = self.mktemp() - log.msg("Child process logging to " + errorLogFile) - p = StandardIOTestProcessProtocol() - d = p.onCompletion - self._spawnProcess(p, 'stdio_test_loseconn.py', errorLogFile) - - def processEnded(reason): - # Copy the child's log to ours so it's more visible. - for line in file(errorLogFile): - log.msg("Child logged: " + line.rstrip()) - - self.failIfIn(1, p.data) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_readConnectionLost(self): - """ - When stdin is closed and the protocol connected to it implements - L{IHalfCloseableProtocol}, the protocol's C{readConnectionLost} method - is called. - """ - errorLogFile = self.mktemp() - log.msg("Child process logging to " + errorLogFile) - p = StandardIOTestProcessProtocol() - p.onDataReceived = defer.Deferred() - - def cbBytes(ignored): - d = p.onCompletion - p.transport.closeStdin() - return d - p.onDataReceived.addCallback(cbBytes) - - def processEnded(reason): - reason.trap(error.ProcessDone) - d = self._requireFailure(p.onDataReceived, processEnded) - - self._spawnProcess( - p, 'stdio_test_halfclose.py', errorLogFile) - return d - - - def test_lastWriteReceived(self): - """ - Verify that a write made directly to stdout using L{os.write} - after StandardIO has finished is reliably received by the - process reading that stdout. - """ - p = StandardIOTestProcessProtocol() - - # Note: the OS X bug which prompted the addition of this test - # is an apparent race condition involving non-blocking PTYs. - # Delaying the parent process significantly increases the - # likelihood of the race going the wrong way. If you need to - # fiddle with this code at all, uncommenting the next line - # will likely make your life much easier. It is commented out - # because it makes the test quite slow. - - # p.onConnection.addCallback(lambda ign: __import__('time').sleep(5)) - - try: - self._spawnProcess( - p, 'stdio_test_lastwrite.py', UNIQUE_LAST_WRITE_STRING, - usePTY=True) - except ValueError, e: - # Some platforms don't work with usePTY=True - raise unittest.SkipTest(str(e)) - - def processEnded(reason): - """ - Asserts that the parent received the bytes written by the child - immediately after the child starts. - """ - self.assertTrue( - p.data[1].endswith(UNIQUE_LAST_WRITE_STRING), - "Received %r from child, did not find expected bytes." % ( - p.data,)) - reason.trap(error.ProcessDone) - return self._requireFailure(p.onCompletion, processEnded) - - - def test_hostAndPeer(self): - """ - Verify that the transport of a protocol connected to L{StandardIO} - has C{getHost} and C{getPeer} methods. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - self._spawnProcess(p, 'stdio_test_hostpeer.py') - - def processEnded(reason): - host, peer = p.data[1].splitlines() - self.failUnless(host) - self.failUnless(peer) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_write(self): - """ - Verify that the C{write} method of the transport of a protocol - connected to L{StandardIO} sends bytes to standard out. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - self._spawnProcess(p, 'stdio_test_write.py') - - def processEnded(reason): - self.assertEqual(p.data[1], 'ok!') - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_writeSequence(self): - """ - Verify that the C{writeSequence} method of the transport of a - protocol connected to L{StandardIO} sends bytes to standard out. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - self._spawnProcess(p, 'stdio_test_writeseq.py') - - def processEnded(reason): - self.assertEqual(p.data[1], 'ok!') - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def _junkPath(self): - junkPath = self.mktemp() - junkFile = file(junkPath, 'w') - for i in xrange(1024): - junkFile.write(str(i) + '\n') - junkFile.close() - return junkPath - - - def test_producer(self): - """ - Verify that the transport of a protocol connected to L{StandardIO} - is a working L{IProducer} provider. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - written = [] - toWrite = range(100) - - def connectionMade(ign): - if toWrite: - written.append(str(toWrite.pop()) + "\n") - proc.write(written[-1]) - reactor.callLater(0.01, connectionMade, None) - - proc = self._spawnProcess(p, 'stdio_test_producer.py') - - p.onConnection.addCallback(connectionMade) - - def processEnded(reason): - self.assertEqual(p.data[1], ''.join(written)) - self.failIf(toWrite, "Connection lost with %d writes left to go." % (len(toWrite),)) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_consumer(self): - """ - Verify that the transport of a protocol connected to L{StandardIO} - is a working L{IConsumer} provider. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - junkPath = self._junkPath() - - self._spawnProcess(p, 'stdio_test_consumer.py', junkPath) - - def processEnded(reason): - self.assertEqual(p.data[1], file(junkPath).read()) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_normalFileStandardOut(self): - """ - If L{StandardIO} is created with a file descriptor which refers to a - normal file (ie, a file from the filesystem), L{StandardIO.write} - writes bytes to that file. In particular, it does not immediately - consider the file closed or call its protocol's C{connectionLost} - method. - """ - onConnLost = defer.Deferred() - proto = ConnectionLostNotifyingProtocol(onConnLost) - path = filepath.FilePath(self.mktemp()) - self.normal = normal = path.open('w') - self.addCleanup(normal.close) - - kwargs = dict(stdout=normal.fileno()) - if not platform.isWindows(): - # Make a fake stdin so that StandardIO doesn't mess with the *real* - # stdin. - r, w = os.pipe() - self.addCleanup(os.close, r) - self.addCleanup(os.close, w) - kwargs['stdin'] = r - connection = stdio.StandardIO(proto, **kwargs) - - # The reactor needs to spin a bit before it might have incorrectly - # decided stdout is closed. Use this counter to keep track of how - # much we've let it spin. If it closes before we expected, this - # counter will have a value that's too small and we'll know. - howMany = 5 - count = itertools.count() - - def spin(): - for value in count: - if value == howMany: - connection.loseConnection() - return - connection.write(str(value)) - break - reactor.callLater(0, spin) - reactor.callLater(0, spin) - - # Once the connection is lost, make sure the counter is at the - # appropriate value. - def cbLost(reason): - self.assertEqual(count.next(), howMany + 1) - self.assertEqual( - path.getContent(), - ''.join(map(str, range(howMany)))) - onConnLost.addCallback(cbLost) - return onConnLost - - if platform.isWindows(): - test_normalFileStandardOut.skip = ( - "StandardIO does not accept stdout as an argument to Windows. " - "Testing redirection to a file is therefore harder.") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_strerror.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_strerror.py deleted file mode 100644 index 41667d2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_strerror.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test strerror -""" - -import socket -import os - -from twisted.trial.unittest import TestCase -from twisted.internet.tcp import ECONNABORTED -from twisted.python.win32 import _ErrorFormatter, formatError -from twisted.python.runtime import platform - - -class _MyWindowsException(OSError): - """ - An exception type like L{ctypes.WinError}, but available on all platforms. - """ - - - -class ErrorFormatingTests(TestCase): - """ - Tests for C{_ErrorFormatter.formatError}. - """ - probeErrorCode = ECONNABORTED - probeMessage = "correct message value" - - def test_strerrorFormatting(self): - """ - L{_ErrorFormatter.formatError} should use L{os.strerror} to format - error messages if it is constructed without any better mechanism. - """ - formatter = _ErrorFormatter(None, None, None) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, os.strerror(self.probeErrorCode)) - - - def test_emptyErrorTab(self): - """ - L{_ErrorFormatter.formatError} should use L{os.strerror} to format - error messages if it is constructed with only an error tab which does - not contain the error code it is called with. - """ - error = 1 - # Sanity check - self.assertNotEqual(self.probeErrorCode, error) - formatter = _ErrorFormatter(None, None, {error: 'wrong message'}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, os.strerror(self.probeErrorCode)) - - - def test_errorTab(self): - """ - L{_ErrorFormatter.formatError} should use C{errorTab} if it is supplied - and contains the requested error code. - """ - formatter = _ErrorFormatter( - None, None, {self.probeErrorCode: self.probeMessage}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, self.probeMessage) - - - def test_formatMessage(self): - """ - L{_ErrorFormatter.formatError} should return the return value of - C{formatMessage} if it is supplied. - """ - formatCalls = [] - def formatMessage(errorCode): - formatCalls.append(errorCode) - return self.probeMessage - formatter = _ErrorFormatter( - None, formatMessage, {self.probeErrorCode: 'wrong message'}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, self.probeMessage) - self.assertEqual(formatCalls, [self.probeErrorCode]) - - - def test_winError(self): - """ - L{_ErrorFormatter.formatError} should return the message argument from - the exception L{winError} returns, if L{winError} is supplied. - """ - winCalls = [] - def winError(errorCode): - winCalls.append(errorCode) - return _MyWindowsException(errorCode, self.probeMessage) - formatter = _ErrorFormatter( - winError, - lambda error: 'formatMessage: wrong message', - {self.probeErrorCode: 'errorTab: wrong message'}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, self.probeMessage) - - - def test_fromEnvironment(self): - """ - L{_ErrorFormatter.fromEnvironment} should create an L{_ErrorFormatter} - instance with attributes populated from available modules. - """ - formatter = _ErrorFormatter.fromEnvironment() - - if formatter.winError is not None: - from ctypes import WinError - self.assertEqual( - formatter.formatError(self.probeErrorCode), - WinError(self.probeErrorCode).strerror) - formatter.winError = None - - if formatter.formatMessage is not None: - from win32api import FormatMessage - self.assertEqual( - formatter.formatError(self.probeErrorCode), - FormatMessage(self.probeErrorCode)) - formatter.formatMessage = None - - if formatter.errorTab is not None: - from socket import errorTab - self.assertEqual( - formatter.formatError(self.probeErrorCode), - errorTab[self.probeErrorCode]) - - if platform.getType() != "win32": - test_fromEnvironment.skip = "Test will run only on Windows." - - - def test_correctLookups(self): - """ - Given an known-good errno, make sure that formatMessage gives results - matching either C{socket.errorTab}, C{ctypes.WinError}, or - C{win32api.FormatMessage}. - """ - acceptable = [socket.errorTab[ECONNABORTED]] - try: - from ctypes import WinError - acceptable.append(WinError(ECONNABORTED).strerror) - except ImportError: - pass - try: - from win32api import FormatMessage - acceptable.append(FormatMessage(ECONNABORTED)) - except ImportError: - pass - - self.assertIn(formatError(ECONNABORTED), acceptable) - - if platform.getType() != "win32": - test_correctLookups.skip = "Test will run only on Windows." diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stringtransport.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stringtransport.py deleted file mode 100644 index 540fd62..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_stringtransport.py +++ /dev/null @@ -1,313 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.test.proto_helpers}. -""" - -from zope.interface.verify import verifyObject - -from twisted.internet.interfaces import (ITransport, IPushProducer, IConsumer, - IReactorTCP, IReactorSSL, IReactorUNIX, IAddress, IListeningPort, - IConnector) -from twisted.internet.address import IPv4Address -from twisted.trial.unittest import TestCase -from twisted.test.proto_helpers import (StringTransport, MemoryReactor, - RaisingMemoryReactor) -from twisted.internet.protocol import ClientFactory, Factory - - -class StringTransportTests(TestCase): - """ - Tests for L{twisted.test.proto_helpers.StringTransport}. - """ - def setUp(self): - self.transport = StringTransport() - - - def test_interfaces(self): - """ - L{StringTransport} instances provide L{ITransport}, L{IPushProducer}, - and L{IConsumer}. - """ - self.assertTrue(verifyObject(ITransport, self.transport)) - self.assertTrue(verifyObject(IPushProducer, self.transport)) - self.assertTrue(verifyObject(IConsumer, self.transport)) - - - def test_registerProducer(self): - """ - L{StringTransport.registerProducer} records the arguments supplied to - it as instance attributes. - """ - producer = object() - streaming = object() - self.transport.registerProducer(producer, streaming) - self.assertIdentical(self.transport.producer, producer) - self.assertIdentical(self.transport.streaming, streaming) - - - def test_disallowedRegisterProducer(self): - """ - L{StringTransport.registerProducer} raises L{RuntimeError} if a - producer is already registered. - """ - producer = object() - self.transport.registerProducer(producer, True) - self.assertRaises( - RuntimeError, self.transport.registerProducer, object(), False) - self.assertIdentical(self.transport.producer, producer) - self.assertTrue(self.transport.streaming) - - - def test_unregisterProducer(self): - """ - L{StringTransport.unregisterProducer} causes the transport to forget - about the registered producer and makes it possible to register a new - one. - """ - oldProducer = object() - newProducer = object() - self.transport.registerProducer(oldProducer, False) - self.transport.unregisterProducer() - self.assertIdentical(self.transport.producer, None) - self.transport.registerProducer(newProducer, True) - self.assertIdentical(self.transport.producer, newProducer) - self.assertTrue(self.transport.streaming) - - - def test_invalidUnregisterProducer(self): - """ - L{StringTransport.unregisterProducer} raises L{RuntimeError} if called - when no producer is registered. - """ - self.assertRaises(RuntimeError, self.transport.unregisterProducer) - - - def test_initialProducerState(self): - """ - L{StringTransport.producerState} is initially C{'producing'}. - """ - self.assertEqual(self.transport.producerState, 'producing') - - - def test_pauseProducing(self): - """ - L{StringTransport.pauseProducing} changes the C{producerState} of the - transport to C{'paused'}. - """ - self.transport.pauseProducing() - self.assertEqual(self.transport.producerState, 'paused') - - - def test_resumeProducing(self): - """ - L{StringTransport.resumeProducing} changes the C{producerState} of the - transport to C{'producing'}. - """ - self.transport.pauseProducing() - self.transport.resumeProducing() - self.assertEqual(self.transport.producerState, 'producing') - - - def test_stopProducing(self): - """ - L{StringTransport.stopProducing} changes the C{'producerState'} of the - transport to C{'stopped'}. - """ - self.transport.stopProducing() - self.assertEqual(self.transport.producerState, 'stopped') - - - def test_stoppedTransportCannotPause(self): - """ - L{StringTransport.pauseProducing} raises L{RuntimeError} if the - transport has been stopped. - """ - self.transport.stopProducing() - self.assertRaises(RuntimeError, self.transport.pauseProducing) - - - def test_stoppedTransportCannotResume(self): - """ - L{StringTransport.resumeProducing} raises L{RuntimeError} if the - transport has been stopped. - """ - self.transport.stopProducing() - self.assertRaises(RuntimeError, self.transport.resumeProducing) - - - def test_disconnectingTransportCannotPause(self): - """ - L{StringTransport.pauseProducing} raises L{RuntimeError} if the - transport is being disconnected. - """ - self.transport.loseConnection() - self.assertRaises(RuntimeError, self.transport.pauseProducing) - - - def test_disconnectingTransportCannotResume(self): - """ - L{StringTransport.resumeProducing} raises L{RuntimeError} if the - transport is being disconnected. - """ - self.transport.loseConnection() - self.assertRaises(RuntimeError, self.transport.resumeProducing) - - - def test_loseConnectionSetsDisconnecting(self): - """ - L{StringTransport.loseConnection} toggles the C{disconnecting} instance - variable to C{True}. - """ - self.assertFalse(self.transport.disconnecting) - self.transport.loseConnection() - self.assertTrue(self.transport.disconnecting) - - - def test_specifiedHostAddress(self): - """ - If a host address is passed to L{StringTransport.__init__}, that - value is returned from L{StringTransport.getHost}. - """ - address = object() - self.assertIdentical(StringTransport(address).getHost(), address) - - - def test_specifiedPeerAddress(self): - """ - If a peer address is passed to L{StringTransport.__init__}, that - value is returned from L{StringTransport.getPeer}. - """ - address = object() - self.assertIdentical( - StringTransport(peerAddress=address).getPeer(), address) - - - def test_defaultHostAddress(self): - """ - If no host address is passed to L{StringTransport.__init__}, an - L{IPv4Address} is returned from L{StringTransport.getHost}. - """ - address = StringTransport().getHost() - self.assertIsInstance(address, IPv4Address) - - - def test_defaultPeerAddress(self): - """ - If no peer address is passed to L{StringTransport.__init__}, an - L{IPv4Address} is returned from L{StringTransport.getPeer}. - """ - address = StringTransport().getPeer() - self.assertIsInstance(address, IPv4Address) - - - -class ReactorTests(TestCase): - """ - Tests for L{MemoryReactor} and L{RaisingMemoryReactor}. - """ - - def test_memoryReactorProvides(self): - """ - L{MemoryReactor} provides all of the attributes described by the - interfaces it advertises. - """ - memoryReactor = MemoryReactor() - verifyObject(IReactorTCP, memoryReactor) - verifyObject(IReactorSSL, memoryReactor) - verifyObject(IReactorUNIX, memoryReactor) - - - def test_raisingReactorProvides(self): - """ - L{RaisingMemoryReactor} provides all of the attributes described by the - interfaces it advertises. - """ - raisingReactor = RaisingMemoryReactor() - verifyObject(IReactorTCP, raisingReactor) - verifyObject(IReactorSSL, raisingReactor) - verifyObject(IReactorUNIX, raisingReactor) - - - def test_connectDestination(self): - """ - L{MemoryReactor.connectTCP}, L{MemoryReactor.connectSSL}, and - L{MemoryReactor.connectUNIX} will return an L{IConnector} whose - C{getDestination} method returns an L{IAddress} with attributes which - reflect the values passed. - """ - memoryReactor = MemoryReactor() - for connector in [memoryReactor.connectTCP( - "test.example.com", 8321, ClientFactory()), - memoryReactor.connectSSL( - "test.example.com", 8321, ClientFactory(), - None)]: - verifyObject(IConnector, connector) - address = connector.getDestination() - verifyObject(IAddress, address) - self.assertEqual(address.host, "test.example.com") - self.assertEqual(address.port, 8321) - connector = memoryReactor.connectUNIX("/fake/path", ClientFactory()) - verifyObject(IConnector, connector) - address = connector.getDestination() - verifyObject(IAddress, address) - self.assertEqual(address.name, "/fake/path") - - - def test_listenDefaultHost(self): - """ - L{MemoryReactor.listenTCP}, L{MemoryReactor.listenSSL} and - L{MemoryReactor.listenUNIX} will return an L{IListeningPort} whose - C{getHost} method returns an L{IAddress}; C{listenTCP} and C{listenSSL} - will have a default host of C{'0.0.0.0'}, and a port that reflects the - value passed, and C{listenUNIX} will have a name that reflects the path - passed. - """ - memoryReactor = MemoryReactor() - for port in [memoryReactor.listenTCP(8242, Factory()), - memoryReactor.listenSSL(8242, Factory(), None)]: - verifyObject(IListeningPort, port) - address = port.getHost() - verifyObject(IAddress, address) - self.assertEqual(address.host, '0.0.0.0') - self.assertEqual(address.port, 8242) - port = memoryReactor.listenUNIX("/path/to/socket", Factory()) - verifyObject(IListeningPort, port) - address = port.getHost() - verifyObject(IAddress, address) - self.assertEqual(address.name, "/path/to/socket") - - - def test_readers(self): - """ - Adding, removing, and listing readers works. - """ - reader = object() - reactor = MemoryReactor() - - reactor.addReader(reader) - reactor.addReader(reader) - - self.assertEqual(reactor.getReaders(), [reader]) - - reactor.removeReader(reader) - - self.assertEqual(reactor.getReaders(), []) - - - def test_writers(self): - """ - Adding, removing, and listing writers works. - """ - writer = object() - reactor = MemoryReactor() - - reactor.addWriter(writer) - reactor.addWriter(writer) - - self.assertEqual(reactor.getWriters(), [writer]) - - reactor.removeWriter(writer) - - self.assertEqual(reactor.getWriters(), []) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_strports.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_strports.py deleted file mode 100644 index 08e508e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_strports.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.application.strports}. -""" - -from twisted.trial.unittest import TestCase -from twisted.application import strports -from twisted.application import internet -from twisted.internet.test.test_endpoints import ParserTests -from twisted.internet.protocol import Factory -from twisted.internet.endpoints import TCP4ServerEndpoint, UNIXServerEndpoint - - - -class DeprecatedParseTests(ParserTests): - """ - L{strports.parse} is deprecated. It's an alias for a method that is now - private in L{twisted.internet.endpoints}. - """ - - def parse(self, *a, **kw): - result = strports.parse(*a, **kw) - warnings = self.flushWarnings([self.parse]) - self.assertEqual(len(warnings), 1) - self.assertEqual( - warnings[0]['message'], - "twisted.application.strports.parse was deprecated " - "in Twisted 10.2.0: in favor of twisted.internet.endpoints.serverFromString") - return result - - - def test_simpleNumeric(self): - """ - Base numeric ports should be parsed as TCP. - """ - self.assertEqual(self.parse('80', self.f), - ('TCP', (80, self.f), {'interface':'', 'backlog':50})) - - - def test_allKeywords(self): - """ - A collection of keyword arguments with no prefixed type, like 'port=80', - will be parsed as keyword arguments to 'tcp'. - """ - self.assertEqual(self.parse('port=80', self.f), - ('TCP', (80, self.f), {'interface':'', 'backlog':50})) - - - -class ServiceTests(TestCase): - """ - Tests for L{strports.service}. - """ - - def test_service(self): - """ - L{strports.service} returns a L{StreamServerEndpointService} - constructed with an endpoint produced from - L{endpoint.serverFromString}, using the same syntax. - """ - reactor = object() # the cake is a lie - aFactory = Factory() - aGoodPort = 1337 - svc = strports.service( - 'tcp:'+str(aGoodPort), aFactory, reactor=reactor) - self.assertIsInstance(svc, internet.StreamServerEndpointService) - - # See twisted.application.test.test_internet.EndpointServiceTests. - # test_synchronousRaiseRaisesSynchronously - self.assertEqual(svc._raiseSynchronously, True) - self.assertIsInstance(svc.endpoint, TCP4ServerEndpoint) - # Maybe we should implement equality for endpoints. - self.assertEqual(svc.endpoint._port, aGoodPort) - self.assertIdentical(svc.factory, aFactory) - self.assertIdentical(svc.endpoint._reactor, reactor) - - - def test_serviceDefaultReactor(self): - """ - L{strports.service} will use the default reactor when none is provided - as an argument. - """ - from twisted.internet import reactor as globalReactor - aService = strports.service("tcp:80", None) - self.assertIdentical(aService.endpoint._reactor, globalReactor) - - - def test_serviceDeprecatedDefault(self): - """ - L{strports.service} still accepts a 'default' argument, which will - affect the parsing of 'default' (i.e. 'not containing a colon') - endpoint descriptions, but this behavior is deprecated. - """ - svc = strports.service("8080", None, "unix") - self.assertIsInstance(svc.endpoint, UNIXServerEndpoint) - warnings = self.flushWarnings([self.test_serviceDeprecatedDefault]) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "The 'default' parameter was deprecated in Twisted 10.2.0. " - "Use qualified endpoint descriptions; for example, 'tcp:8080'.") - self.assertEqual(len(warnings), 1) - - # Almost the same case, but slightly tricky - explicitly passing the old - # default value, None, also must trigger a deprecation warning. - svc = strports.service("tcp:8080", None, None) - self.assertIsInstance(svc.endpoint, TCP4ServerEndpoint) - warnings = self.flushWarnings([self.test_serviceDeprecatedDefault]) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "The 'default' parameter was deprecated in Twisted 10.2.0.") - self.assertEqual(len(warnings), 1) - - - def test_serviceDeprecatedUnqualified(self): - """ - Unqualified strport descriptions, i.e. "8080", are deprecated. - """ - svc = strports.service("8080", None) - self.assertIsInstance(svc.endpoint, TCP4ServerEndpoint) - warnings = self.flushWarnings( - [self.test_serviceDeprecatedUnqualified]) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "Unqualified strport description passed to 'service'." - "Use qualified endpoint descriptions; for example, 'tcp:8080'.") - self.assertEqual(len(warnings), 1) - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_task.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_task.py deleted file mode 100644 index 5b73a63..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_task.py +++ /dev/null @@ -1,1083 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet.task}. -""" - -from __future__ import division, absolute_import - -from twisted.trial import unittest - -from twisted.internet import interfaces, task, reactor, defer, error -from twisted.internet.main import installReactor -from twisted.internet.test.modulehelpers import NoReactor - -# Be compatible with any jerks who used our private stuff -Clock = task.Clock - -from twisted.python import failure - - -class TestableLoopingCall(task.LoopingCall): - def __init__(self, clock, *a, **kw): - super(TestableLoopingCall, self).__init__(*a, **kw) - self.clock = clock - - - -class TestException(Exception): - pass - - - -class ClockTests(unittest.TestCase): - """ - Test the non-wallclock based clock implementation. - """ - def testSeconds(self): - """ - Test that the C{seconds} method of the fake clock returns fake time. - """ - c = task.Clock() - self.assertEqual(c.seconds(), 0) - - - def testCallLater(self): - """ - Test that calls can be scheduled for later with the fake clock and - hands back an L{IDelayedCall}. - """ - c = task.Clock() - call = c.callLater(1, lambda a, b: None, 1, b=2) - self.failUnless(interfaces.IDelayedCall.providedBy(call)) - self.assertEqual(call.getTime(), 1) - self.failUnless(call.active()) - - - def testCallLaterCancelled(self): - """ - Test that calls can be cancelled. - """ - c = task.Clock() - call = c.callLater(1, lambda a, b: None, 1, b=2) - call.cancel() - self.failIf(call.active()) - - - def test_callLaterOrdering(self): - """ - Test that the DelayedCall returned is not one previously - created. - """ - c = task.Clock() - call1 = c.callLater(10, lambda a, b: None, 1, b=2) - call2 = c.callLater(1, lambda a, b: None, 3, b=4) - self.failIf(call1 is call2) - - - def testAdvance(self): - """ - Test that advancing the clock will fire some calls. - """ - events = [] - c = task.Clock() - call = c.callLater(2, lambda: events.append(None)) - c.advance(1) - self.assertEqual(events, []) - c.advance(1) - self.assertEqual(events, [None]) - self.failIf(call.active()) - - - def testAdvanceCancel(self): - """ - Test attempting to cancel the call in a callback. - - AlreadyCalled should be raised, not for example a ValueError from - removing the call from Clock.calls. This requires call.called to be - set before the callback is called. - """ - c = task.Clock() - def cb(): - self.assertRaises(error.AlreadyCalled, call.cancel) - call = c.callLater(1, cb) - c.advance(1) - - - def testCallLaterDelayed(self): - """ - Test that calls can be delayed. - """ - events = [] - c = task.Clock() - call = c.callLater(1, lambda a, b: events.append((a, b)), 1, b=2) - call.delay(1) - self.assertEqual(call.getTime(), 2) - c.advance(1.5) - self.assertEqual(events, []) - c.advance(1.0) - self.assertEqual(events, [(1, 2)]) - - - def testCallLaterResetLater(self): - """ - Test that calls can have their time reset to a later time. - """ - events = [] - c = task.Clock() - call = c.callLater(2, lambda a, b: events.append((a, b)), 1, b=2) - c.advance(1) - call.reset(3) - self.assertEqual(call.getTime(), 4) - c.advance(2) - self.assertEqual(events, []) - c.advance(1) - self.assertEqual(events, [(1, 2)]) - - - def testCallLaterResetSooner(self): - """ - Test that calls can have their time reset to an earlier time. - """ - events = [] - c = task.Clock() - call = c.callLater(4, lambda a, b: events.append((a, b)), 1, b=2) - call.reset(3) - self.assertEqual(call.getTime(), 3) - c.advance(3) - self.assertEqual(events, [(1, 2)]) - - - def test_getDelayedCalls(self): - """ - Test that we can get a list of all delayed calls - """ - c = task.Clock() - call = c.callLater(1, lambda x: None) - call2 = c.callLater(2, lambda x: None) - - calls = c.getDelayedCalls() - - self.assertEqual(set([call, call2]), set(calls)) - - - def test_getDelayedCallsEmpty(self): - """ - Test that we get an empty list from getDelayedCalls on a newly - constructed Clock. - """ - c = task.Clock() - self.assertEqual(c.getDelayedCalls(), []) - - - def test_providesIReactorTime(self): - c = task.Clock() - self.failUnless(interfaces.IReactorTime.providedBy(c), - "Clock does not provide IReactorTime") - - - def test_callLaterKeepsCallsOrdered(self): - """ - The order of calls scheduled by L{task.Clock.callLater} is honored when - adding a new call via calling L{task.Clock.callLater} again. - - For example, if L{task.Clock.callLater} is invoked with a callable "A" - and a time t0, and then the L{IDelayedCall} which results from that is - C{reset} to a later time t2 which is greater than t0, and I{then} - L{task.Clock.callLater} is invoked again with a callable "B", and time - t1 which is less than t2 but greater than t0, "B" will be invoked before - "A". - """ - result = [] - expected = [('b', 2.0), ('a', 3.0)] - clock = task.Clock() - logtime = lambda n: result.append((n, clock.seconds())) - - call_a = clock.callLater(1.0, logtime, "a") - call_a.reset(3.0) - clock.callLater(2.0, logtime, "b") - - clock.pump([1]*3) - self.assertEqual(result, expected) - - - def test_callLaterResetKeepsCallsOrdered(self): - """ - The order of calls scheduled by L{task.Clock.callLater} is honored when - re-scheduling an existing call via L{IDelayedCall.reset} on the result - of a previous call to C{callLater}. - - For example, if L{task.Clock.callLater} is invoked with a callable "A" - and a time t0, and then L{task.Clock.callLater} is invoked again with a - callable "B", and time t1 greater than t0, and finally the - L{IDelayedCall} for "A" is C{reset} to a later time, t2, which is - greater than t1, "B" will be invoked before "A". - """ - result = [] - expected = [('b', 2.0), ('a', 3.0)] - clock = task.Clock() - logtime = lambda n: result.append((n, clock.seconds())) - - call_a = clock.callLater(1.0, logtime, "a") - clock.callLater(2.0, logtime, "b") - call_a.reset(3.0) - - clock.pump([1]*3) - self.assertEqual(result, expected) - - - def test_callLaterResetInsideCallKeepsCallsOrdered(self): - """ - The order of calls scheduled by L{task.Clock.callLater} is honored when - re-scheduling an existing call via L{IDelayedCall.reset} on the result - of a previous call to C{callLater}, even when that call to C{reset} - occurs within the callable scheduled by C{callLater} itself. - """ - result = [] - expected = [('c', 3.0), ('b', 4.0)] - clock = task.Clock() - logtime = lambda n: result.append((n, clock.seconds())) - - call_b = clock.callLater(2.0, logtime, "b") - def a(): - call_b.reset(3.0) - - clock.callLater(1.0, a) - clock.callLater(3.0, logtime, "c") - - clock.pump([0.5] * 10) - self.assertEqual(result, expected) - - - -class LoopTests(unittest.TestCase): - """ - Tests for L{task.LoopingCall} based on a fake L{IReactorTime} - implementation. - """ - def test_defaultClock(self): - """ - L{LoopingCall}'s default clock should be the reactor. - """ - call = task.LoopingCall(lambda: None) - self.assertEqual(call.clock, reactor) - - - def test_callbackTimeSkips(self): - """ - When more time than the defined interval passes during the execution - of a callback, L{LoopingCall} should schedule the next call for the - next interval which is still in the future. - """ - times = [] - callDuration = None - clock = task.Clock() - def aCallback(): - times.append(clock.seconds()) - clock.advance(callDuration) - call = task.LoopingCall(aCallback) - call.clock = clock - - # Start a LoopingCall with a 0.5 second increment, and immediately call - # the callable. - callDuration = 2 - call.start(0.5) - - # Verify that the callable was called, and since it was immediate, with - # no skips. - self.assertEqual(times, [0]) - - # The callback should have advanced the clock by the callDuration. - self.assertEqual(clock.seconds(), callDuration) - - # An iteration should have occurred at 2, but since 2 is the present - # and not the future, it is skipped. - - clock.advance(0) - self.assertEqual(times, [0]) - - # 2.5 is in the future, and is not skipped. - callDuration = 1 - clock.advance(0.5) - self.assertEqual(times, [0, 2.5]) - self.assertEqual(clock.seconds(), 3.5) - - # Another iteration should have occurred, but it is again the - # present and not the future, so it is skipped as well. - clock.advance(0) - self.assertEqual(times, [0, 2.5]) - - # 4 is in the future, and is not skipped. - callDuration = 0 - clock.advance(0.5) - self.assertEqual(times, [0, 2.5, 4]) - self.assertEqual(clock.seconds(), 4) - - - def test_reactorTimeSkips(self): - """ - When more time than the defined interval passes between when - L{LoopingCall} schedules itself to run again and when it actually - runs again, it should schedule the next call for the next interval - which is still in the future. - """ - times = [] - clock = task.Clock() - def aCallback(): - times.append(clock.seconds()) - - # Start a LoopingCall that tracks the time passed, with a 0.5 second - # increment. - call = task.LoopingCall(aCallback) - call.clock = clock - call.start(0.5) - - # Initially, no time should have passed! - self.assertEqual(times, [0]) - - # Advance the clock by 2 seconds (2 seconds should have passed) - clock.advance(2) - self.assertEqual(times, [0, 2]) - - # Advance the clock by 1 second (3 total should have passed) - clock.advance(1) - self.assertEqual(times, [0, 2, 3]) - - # Advance the clock by 0 seconds (this should have no effect!) - clock.advance(0) - self.assertEqual(times, [0, 2, 3]) - - - def test_reactorTimeCountSkips(self): - """ - When L{LoopingCall} schedules itself to run again, if more than the - specified interval has passed, it should schedule the next call for the - next interval which is still in the future. If it was created - using L{LoopingCall.withCount}, a positional argument will be - inserted at the beginning of the argument list, indicating the number - of calls that should have been made. - """ - times = [] - clock = task.Clock() - def aCallback(numCalls): - times.append((clock.seconds(), numCalls)) - - # Start a LoopingCall that tracks the time passed, and the number of - # skips, with a 0.5 second increment. - call = task.LoopingCall.withCount(aCallback) - call.clock = clock - INTERVAL = 0.5 - REALISTIC_DELAY = 0.01 - call.start(INTERVAL) - - # Initially, no seconds should have passed, and one calls should have - # been made. - self.assertEqual(times, [(0, 1)]) - - # After the interval (plus a small delay, to account for the time that - # the reactor takes to wake up and process the LoopingCall), we should - # still have only made one call. - clock.advance(INTERVAL + REALISTIC_DELAY) - self.assertEqual(times, [(0, 1), (INTERVAL + REALISTIC_DELAY, 1)]) - - # After advancing the clock by three intervals (plus a small delay to - # account for the reactor), we should have skipped two calls; one less - # than the number of intervals which have completely elapsed. Along - # with the call we did actually make, the final number of calls is 3. - clock.advance((3 * INTERVAL) + REALISTIC_DELAY) - self.assertEqual(times, - [(0, 1), (INTERVAL + REALISTIC_DELAY, 1), - ((4 * INTERVAL) + (2 * REALISTIC_DELAY), 3)]) - - # Advancing the clock by 0 seconds should not cause any changes! - clock.advance(0) - self.assertEqual(times, - [(0, 1), (INTERVAL + REALISTIC_DELAY, 1), - ((4 * INTERVAL) + (2 * REALISTIC_DELAY), 3)]) - - - def test_countLengthyIntervalCounts(self): - """ - L{LoopingCall.withCount} counts only calls that were expected to be - made. So, if more than one, but less than two intervals pass between - invocations, it won't increase the count above 1. For example, a - L{LoopingCall} with interval T expects to be invoked at T, 2T, 3T, etc. - However, the reactor takes some time to get around to calling it, so in - practice it will be called at T+something, 2T+something, 3T+something; - and due to other things going on in the reactor, "something" is - variable. It won't increase the count unless "something" is greater - than T. So if the L{LoopingCall} is invoked at T, 2.75T, and 3T, - the count has not increased, even though the distance between - invocation 1 and invocation 2 is 1.75T. - """ - times = [] - clock = task.Clock() - def aCallback(count): - times.append((clock.seconds(), count)) - - # Start a LoopingCall that tracks the time passed, and the number of - # calls, with a 0.5 second increment. - call = task.LoopingCall.withCount(aCallback) - call.clock = clock - INTERVAL = 0.5 - REALISTIC_DELAY = 0.01 - call.start(INTERVAL) - self.assertEqual(times.pop(), (0, 1)) - - # About one interval... So far, so good - clock.advance(INTERVAL + REALISTIC_DELAY) - self.assertEqual(times.pop(), (INTERVAL + REALISTIC_DELAY, 1)) - - # Oh no, something delayed us for a while. - clock.advance(INTERVAL * 1.75) - self.assertEqual(times.pop(), ((2.75 * INTERVAL) + REALISTIC_DELAY, 1)) - - # Back on track! We got invoked when we expected this time. - clock.advance(INTERVAL * 0.25) - self.assertEqual(times.pop(), ((3.0 * INTERVAL) + REALISTIC_DELAY, 1)) - - - def test_withCountFloatingPointBoundary(self): - """ - L{task.LoopingCall.withCount} should never invoke its callable with a - zero. Specifically, if a L{task.LoopingCall} created with C{withCount} - has its L{start } method invoked with a - floating-point number which introduces decimal inaccuracy when - multiplied or divided, such as "0.1", L{task.LoopingCall} will never - invoke its callable with 0. Also, the sum of all the values passed to - its callable as the "count" will be an integer, the number of intervals - that have elapsed. - - This is a regression test for a particularly tricky case to implement. - """ - clock = task.Clock() - accumulator = [] - call = task.LoopingCall.withCount(accumulator.append) - call.clock = clock - - # 'count': the number of ticks within the time span, the number of - # calls that should be made. this should be a value which causes - # floating-point inaccuracy as the denominator for the timespan. - count = 10 - # 'timespan': the amount of virtual time that the test will take, in - # seconds, as a floating point number - timespan = 1.0 - # 'interval': the amount of time for one actual call. - interval = timespan / count - - call.start(interval, now=False) - for x in range(count): - clock.advance(interval) - - # There is still an epsilon of inaccuracy here; 0.1 is not quite - # exactly 1/10 in binary, so we need to push our clock over the - # threshold. - epsilon = timespan - sum([interval] * count) - clock.advance(epsilon) - secondsValue = clock.seconds() - # The following two assertions are here to ensure that if the values of - # count, timespan, and interval are changed, that the test remains - # valid. First, the "epsilon" value here measures the floating-point - # inaccuracy in question, and so if it doesn't exist then we are not - # triggering an interesting condition. - self.assertTrue(abs(epsilon) > 0.0, - "{0} should be greater than zero" - .format(epsilon)) - # Secondly, task.Clock should behave in such a way that once we have - # advanced to this point, it has reached or exceeded the timespan. - self.assertTrue(secondsValue >= timespan, - "{0} should be greater than or equal to {1}" - .format(secondsValue, timespan)) - - self.assertEqual(sum(accumulator), count) - self.assertNotIn(0, accumulator) - - - def testBasicFunction(self): - # Arrange to have time advanced enough so that our function is - # called a few times. - # Only need to go to 2.5 to get 3 calls, since the first call - # happens before any time has elapsed. - timings = [0.05, 0.1, 0.1] - - clock = task.Clock() - - L = [] - def foo(a, b, c=None, d=None): - L.append((a, b, c, d)) - - lc = TestableLoopingCall(clock, foo, "a", "b", d="d") - D = lc.start(0.1) - - theResult = [] - def saveResult(result): - theResult.append(result) - D.addCallback(saveResult) - - clock.pump(timings) - - self.assertEqual(len(L), 3, - "got %d iterations, not 3" % (len(L),)) - - for (a, b, c, d) in L: - self.assertEqual(a, "a") - self.assertEqual(b, "b") - self.assertEqual(c, None) - self.assertEqual(d, "d") - - lc.stop() - self.assertIdentical(theResult[0], lc) - - # Make sure it isn't planning to do anything further. - self.failIf(clock.calls) - - - def testDelayedStart(self): - timings = [0.05, 0.1, 0.1] - - clock = task.Clock() - - L = [] - lc = TestableLoopingCall(clock, L.append, None) - d = lc.start(0.1, now=False) - - theResult = [] - def saveResult(result): - theResult.append(result) - d.addCallback(saveResult) - - clock.pump(timings) - - self.assertEqual(len(L), 2, - "got %d iterations, not 2" % (len(L),)) - lc.stop() - self.assertIdentical(theResult[0], lc) - - self.failIf(clock.calls) - - - def testBadDelay(self): - lc = task.LoopingCall(lambda: None) - self.assertRaises(ValueError, lc.start, -1) - - - # Make sure that LoopingCall.stop() prevents any subsequent calls. - def _stoppingTest(self, delay): - ran = [] - def foo(): - ran.append(None) - - clock = task.Clock() - lc = TestableLoopingCall(clock, foo) - lc.start(delay, now=False) - lc.stop() - self.failIf(ran) - self.failIf(clock.calls) - - - def testStopAtOnce(self): - return self._stoppingTest(0) - - - def testStoppingBeforeDelayedStart(self): - return self._stoppingTest(10) - - - def test_reset(self): - """ - Test that L{LoopingCall} can be reset. - """ - ran = [] - def foo(): - ran.append(None) - - c = task.Clock() - lc = TestableLoopingCall(c, foo) - lc.start(2, now=False) - c.advance(1) - lc.reset() - c.advance(1) - self.assertEqual(ran, []) - c.advance(1) - self.assertEqual(ran, [None]) - - - def test_reprFunction(self): - """ - L{LoopingCall.__repr__} includes the wrapped function's name. - """ - self.assertEqual(repr(task.LoopingCall(installReactor, 1, key=2)), - "LoopingCall(installReactor, *(1,), **{'key': 2})") - - - def test_reprMethod(self): - """ - L{LoopingCall.__repr__} includes the wrapped method's full name. - """ - self.assertEqual( - repr(task.LoopingCall(TestableLoopingCall.__init__)), - "LoopingCall(TestableLoopingCall.__init__, *(), **{})") - - - -class ReactorLoopTests(unittest.TestCase): - # Slightly inferior tests which exercise interactions with an actual - # reactor. - def testFailure(self): - def foo(x): - raise TestException(x) - - lc = task.LoopingCall(foo, "bar") - return self.assertFailure(lc.start(0.1), TestException) - - - def testFailAndStop(self): - def foo(x): - lc.stop() - raise TestException(x) - - lc = task.LoopingCall(foo, "bar") - return self.assertFailure(lc.start(0.1), TestException) - - - def testEveryIteration(self): - ran = [] - - def foo(): - ran.append(None) - if len(ran) > 5: - lc.stop() - - lc = task.LoopingCall(foo) - d = lc.start(0) - def stopped(ign): - self.assertEqual(len(ran), 6) - return d.addCallback(stopped) - - - def testStopAtOnceLater(self): - # Ensure that even when LoopingCall.stop() is called from a - # reactor callback, it still prevents any subsequent calls. - d = defer.Deferred() - def foo(): - d.errback(failure.DefaultException( - "This task also should never get called.")) - self._lc = task.LoopingCall(foo) - self._lc.start(1, now=False) - reactor.callLater(0, self._callback_for_testStopAtOnceLater, d) - return d - - - def _callback_for_testStopAtOnceLater(self, d): - self._lc.stop() - reactor.callLater(0, d.callback, "success") - - def testWaitDeferred(self): - # Tests if the callable isn't scheduled again before the returned - # deferred has fired. - timings = [0.2, 0.8] - clock = task.Clock() - - def foo(): - d = defer.Deferred() - d.addCallback(lambda _: lc.stop()) - clock.callLater(1, d.callback, None) - return d - - lc = TestableLoopingCall(clock, foo) - lc.start(0.2) - clock.pump(timings) - self.failIf(clock.calls) - - def testFailurePropagation(self): - # Tests if the failure of the errback of the deferred returned by the - # callable is propagated to the lc errback. - # - # To make sure this test does not hang trial when LoopingCall does not - # wait for the callable's deferred, it also checks there are no - # calls in the clock's callLater queue. - timings = [0.3] - clock = task.Clock() - - def foo(): - d = defer.Deferred() - clock.callLater(0.3, d.errback, TestException()) - return d - - lc = TestableLoopingCall(clock, foo) - d = lc.start(1) - self.assertFailure(d, TestException) - - clock.pump(timings) - self.failIf(clock.calls) - return d - - - def test_deferredWithCount(self): - """ - In the case that the function passed to L{LoopingCall.withCount} - returns a deferred, which does not fire before the next interval - elapses, the function should not be run again. And if a function call - is skipped in this fashion, the appropriate count should be - provided. - """ - testClock = task.Clock() - d = defer.Deferred() - deferredCounts = [] - - def countTracker(possibleCount): - # Keep a list of call counts - deferredCounts.append(possibleCount) - # Return a deferred, but only on the first request - if len(deferredCounts) == 1: - return d - else: - return None - - # Start a looping call for our countTracker function - # Set the increment to 0.2, and do not call the function on startup. - lc = task.LoopingCall.withCount(countTracker) - lc.clock = testClock - d = lc.start(0.2, now=False) - - # Confirm that nothing has happened yet. - self.assertEqual(deferredCounts, []) - - # Advance the clock by 0.2 and then 0.4; - testClock.pump([0.2, 0.4]) - # We should now have exactly one count (of 1 call) - self.assertEqual(len(deferredCounts), 1) - - # Fire the deferred, and advance the clock by another 0.2 - d.callback(None) - testClock.pump([0.2]) - # We should now have exactly 2 counts... - self.assertEqual(len(deferredCounts), 2) - # The first count should be 1 (one call) - # The second count should be 3 (calls were missed at about 0.6 and 0.8) - self.assertEqual(deferredCounts, [1, 3]) - - - -class DeferLaterTests(unittest.TestCase): - """ - Tests for L{task.deferLater}. - """ - def test_callback(self): - """ - The L{Deferred} returned by L{task.deferLater} is called back after - the specified delay with the result of the function passed in. - """ - results = [] - flag = object() - def callable(foo, bar): - results.append((foo, bar)) - return flag - - clock = task.Clock() - d = task.deferLater(clock, 3, callable, 'foo', bar='bar') - d.addCallback(self.assertIdentical, flag) - clock.advance(2) - self.assertEqual(results, []) - clock.advance(1) - self.assertEqual(results, [('foo', 'bar')]) - return d - - - def test_errback(self): - """ - The L{Deferred} returned by L{task.deferLater} is errbacked if the - supplied function raises an exception. - """ - def callable(): - raise TestException() - - clock = task.Clock() - d = task.deferLater(clock, 1, callable) - clock.advance(1) - return self.assertFailure(d, TestException) - - - def test_cancel(self): - """ - The L{Deferred} returned by L{task.deferLater} can be - cancelled to prevent the call from actually being performed. - """ - called = [] - clock = task.Clock() - d = task.deferLater(clock, 1, called.append, None) - d.cancel() - def cbCancelled(ignored): - # Make sure there are no calls outstanding. - self.assertEqual([], clock.getDelayedCalls()) - # And make sure the call didn't somehow happen already. - self.assertFalse(called) - self.assertFailure(d, defer.CancelledError) - d.addCallback(cbCancelled) - return d - - - -class _FakeReactor(object): - - def __init__(self): - self._running = False - self._clock = task.Clock() - self.callLater = self._clock.callLater - self.seconds = self._clock.seconds - self.getDelayedCalls = self._clock.getDelayedCalls - self._whenRunning = [] - self._shutdownTriggers = {'before': [], 'during': []} - - - def callWhenRunning(self, callable, *args, **kwargs): - if self._whenRunning is None: - callable(*args, **kwargs) - else: - self._whenRunning.append((callable, args, kwargs)) - - - def addSystemEventTrigger(self, phase, event, callable, *args): - assert phase in ('before', 'during') - assert event == 'shutdown' - self._shutdownTriggers[phase].append((callable, args)) - - - def run(self): - """ - Call timed events until there are no more or the reactor is stopped. - - @raise RuntimeError: When no timed events are left and the reactor is - still running. - """ - self._running = True - whenRunning = self._whenRunning - self._whenRunning = None - for callable, args, kwargs in whenRunning: - callable(*args, **kwargs) - while self._running: - calls = self.getDelayedCalls() - if not calls: - raise RuntimeError("No DelayedCalls left") - self._clock.advance(calls[0].getTime() - self.seconds()) - shutdownTriggers = self._shutdownTriggers - self._shutdownTriggers = None - for (trigger, args) in shutdownTriggers['before'] + shutdownTriggers['during']: - trigger(*args) - - - def stop(self): - """ - Stop the reactor. - """ - if not self._running: - raise error.ReactorNotRunning() - self._running = False - - - -class ReactTests(unittest.SynchronousTestCase): - """ - Tests for L{twisted.internet.task.react}. - """ - - def test_runsUntilAsyncCallback(self): - """ - L{task.react} runs the reactor until the L{Deferred} returned by the - function it is passed is called back, then stops it. - """ - timePassed = [] - def main(reactor): - finished = defer.Deferred() - reactor.callLater(1, timePassed.append, True) - reactor.callLater(2, finished.callback, None) - return finished - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, _reactor=r) - self.assertEqual(0, exitError.code) - self.assertEqual(timePassed, [True]) - self.assertEqual(r.seconds(), 2) - - - def test_runsUntilSyncCallback(self): - """ - L{task.react} returns quickly if the L{Deferred} returned by the - function it is passed has already been called back at the time it is - returned. - """ - def main(reactor): - return defer.succeed(None) - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, _reactor=r) - self.assertEqual(0, exitError.code) - self.assertEqual(r.seconds(), 0) - - - def test_runsUntilAsyncErrback(self): - """ - L{task.react} runs the reactor until the L{defer.Deferred} returned by - the function it is passed is errbacked, then it stops the reactor and - reports the error. - """ - class ExpectedException(Exception): - pass - - def main(reactor): - finished = defer.Deferred() - reactor.callLater(1, finished.errback, ExpectedException()) - return finished - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, _reactor=r) - - self.assertEqual(1, exitError.code) - - errors = self.flushLoggedErrors(ExpectedException) - self.assertEqual(len(errors), 1) - - - def test_runsUntilSyncErrback(self): - """ - L{task.react} returns quickly if the L{defer.Deferred} returned by the - function it is passed has already been errbacked at the time it is - returned. - """ - class ExpectedException(Exception): - pass - - def main(reactor): - return defer.fail(ExpectedException()) - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, _reactor=r) - self.assertEqual(1, exitError.code) - self.assertEqual(r.seconds(), 0) - errors = self.flushLoggedErrors(ExpectedException) - self.assertEqual(len(errors), 1) - - - def test_singleStopCallback(self): - """ - L{task.react} doesn't try to stop the reactor if the L{defer.Deferred} - the function it is passed is called back after the reactor has already - been stopped. - """ - def main(reactor): - reactor.callLater(1, reactor.stop) - finished = defer.Deferred() - reactor.addSystemEventTrigger( - 'during', 'shutdown', finished.callback, None) - return finished - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, _reactor=r) - self.assertEqual(r.seconds(), 1) - - self.assertEqual(0, exitError.code) - - - def test_singleStopErrback(self): - """ - L{task.react} doesn't try to stop the reactor if the L{defer.Deferred} - the function it is passed is errbacked after the reactor has already - been stopped. - """ - class ExpectedException(Exception): - pass - - def main(reactor): - reactor.callLater(1, reactor.stop) - finished = defer.Deferred() - reactor.addSystemEventTrigger( - 'during', 'shutdown', finished.errback, ExpectedException()) - return finished - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, _reactor=r) - - self.assertEqual(1, exitError.code) - - self.assertEqual(r.seconds(), 1) - errors = self.flushLoggedErrors(ExpectedException) - self.assertEqual(len(errors), 1) - - - def test_arguments(self): - """ - L{task.react} passes the elements of the list it is passed as - positional arguments to the function it is passed. - """ - args = [] - def main(reactor, x, y, z): - args.extend((x, y, z)) - return defer.succeed(None) - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, [1, 2, 3], _reactor=r) - self.assertEqual(0, exitError.code) - self.assertEqual(args, [1, 2, 3]) - - - def test_defaultReactor(self): - """ - L{twisted.internet.reactor} is used if no reactor argument is passed to - L{task.react}. - """ - def main(reactor): - self.passedReactor = reactor - return defer.succeed(None) - - reactor = _FakeReactor() - with NoReactor(): - installReactor(reactor) - exitError = self.assertRaises(SystemExit, task.react, main, []) - self.assertEqual(0, exitError.code) - self.assertIdentical(reactor, self.passedReactor) - - - def test_exitWithDefinedCode(self): - """ - L{task.react} forwards the exit code specified by the C{SystemExit} - error returned by the passed function, if any. - """ - def main(reactor): - return defer.fail(SystemExit(23)) - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, [], _reactor=r) - self.assertEqual(23, exitError.code) - - - def test_synchronousStop(self): - """ - L{task.react} handles when the reactor is stopped just before the - returned L{Deferred} fires. - """ - def main(reactor): - d = defer.Deferred() - def stop(): - reactor.stop() - d.callback(None) - reactor.callWhenRunning(stop) - return d - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, [], _reactor=r) - self.assertEqual(0, exitError.code) - - - def test_asynchronousStop(self): - """ - L{task.react} handles when the reactor is stopped and the - returned L{Deferred} doesn't fire. - """ - def main(reactor): - reactor.callLater(1, reactor.stop) - return defer.Deferred() - r = _FakeReactor() - exitError = self.assertRaises( - SystemExit, task.react, main, [], _reactor=r) - self.assertEqual(0, exitError.code) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tcp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tcp.py deleted file mode 100644 index e381209..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tcp.py +++ /dev/null @@ -1,1824 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for implementations of L{IReactorTCP}. -""" - -from __future__ import division, absolute_import - -import socket, random, errno -from functools import wraps - -from zope.interface import implementer - -from twisted.trial import unittest - -from twisted.python.log import msg, err -from twisted.internet import protocol, reactor, defer, interfaces -from twisted.internet import error -from twisted.internet.address import IPv4Address -from twisted.internet.interfaces import IHalfCloseableProtocol, IPullProducer -from twisted.protocols import policies -from twisted.test.proto_helpers import AccumulatingProtocol - - -def loopUntil(predicate, interval=0): - """ - Poor excuse for an event notification helper. This polls a condition and - calls back a Deferred when it is seen to be true. - - Do not use this function. - """ - from twisted.internet import task - d = defer.Deferred() - def check(): - res = predicate() - if res: - d.callback(res) - call = task.LoopingCall(check) - def stop(result): - call.stop() - return result - d.addCallback(stop) - d2 = call.start(interval) - d2.addErrback(d.errback) - return d - - - -class ClosingProtocol(protocol.Protocol): - - def connectionMade(self): - msg("ClosingProtocol.connectionMade") - self.transport.loseConnection() - - def connectionLost(self, reason): - msg("ClosingProtocol.connectionLost") - reason.trap(error.ConnectionDone) - - - -class ClosingFactory(protocol.ServerFactory): - """ - Factory that closes port immediately. - """ - - _cleanerUpper = None - - def buildProtocol(self, conn): - self._cleanerUpper = self.port.stopListening() - return ClosingProtocol() - - - def cleanUp(self): - """ - Clean-up for tests to wait for the port to stop listening. - """ - if self._cleanerUpper is None: - return self.port.stopListening() - return self._cleanerUpper - - - -class MyProtocolFactoryMixin(object): - """ - Mixin for factories which create L{AccumulatingProtocol} instances. - - @type protocolFactory: no-argument callable - @ivar protocolFactory: Factory for protocols - takes the place of the - typical C{protocol} attribute of factories (but that name is used by - this class for something else). - - @type protocolConnectionMade: L{NoneType} or L{defer.Deferred} - @ivar protocolConnectionMade: When an instance of L{AccumulatingProtocol} - is connected, if this is not C{None}, the L{Deferred} will be called - back with the protocol instance and the attribute set to C{None}. - - @type protocolConnectionLost: L{NoneType} or L{defer.Deferred} - @ivar protocolConnectionLost: When an instance of L{AccumulatingProtocol} - is created, this will be set as its C{closedDeferred} attribute and - then this attribute will be set to C{None} so the L{defer.Deferred} is - not used by more than one protocol. - - @ivar protocol: The most recently created L{AccumulatingProtocol} instance - which was returned from C{buildProtocol}. - - @type called: C{int} - @ivar called: A counter which is incremented each time C{buildProtocol} - is called. - - @ivar peerAddresses: A C{list} of the addresses passed to C{buildProtocol}. - """ - protocolFactory = AccumulatingProtocol - - protocolConnectionMade = None - protocolConnectionLost = None - protocol = None - called = 0 - - def __init__(self): - self.peerAddresses = [] - - - def buildProtocol(self, addr): - """ - Create a L{AccumulatingProtocol} and set it up to be able to perform - callbacks. - """ - self.peerAddresses.append(addr) - self.called += 1 - p = self.protocolFactory() - p.factory = self - p.closedDeferred = self.protocolConnectionLost - self.protocolConnectionLost = None - self.protocol = p - return p - - - -class MyServerFactory(MyProtocolFactoryMixin, protocol.ServerFactory): - """ - Server factory which creates L{AccumulatingProtocol} instances. - """ - - - -class MyClientFactory(MyProtocolFactoryMixin, protocol.ClientFactory): - """ - Client factory which creates L{AccumulatingProtocol} instances. - """ - failed = 0 - stopped = 0 - - def __init__(self): - MyProtocolFactoryMixin.__init__(self) - self.deferred = defer.Deferred() - self.failDeferred = defer.Deferred() - - def clientConnectionFailed(self, connector, reason): - self.failed = 1 - self.reason = reason - self.failDeferred.callback(None) - - def clientConnectionLost(self, connector, reason): - self.lostReason = reason - self.deferred.callback(None) - - def stopFactory(self): - self.stopped = 1 - - - -class ListeningTests(unittest.TestCase): - - def test_listen(self): - """ - L{IReactorTCP.listenTCP} returns an object which provides - L{IListeningPort}. - """ - f = MyServerFactory() - p1 = reactor.listenTCP(0, f, interface="127.0.0.1") - self.addCleanup(p1.stopListening) - self.failUnless(interfaces.IListeningPort.providedBy(p1)) - - - def testStopListening(self): - """ - The L{IListeningPort} returned by L{IReactorTCP.listenTCP} can be - stopped with its C{stopListening} method. After the L{Deferred} it - (optionally) returns has been called back, the port number can be bound - to a new server. - """ - f = MyServerFactory() - port = reactor.listenTCP(0, f, interface="127.0.0.1") - n = port.getHost().port - - def cbStopListening(ignored): - # Make sure we can rebind the port right away - port = reactor.listenTCP(n, f, interface="127.0.0.1") - return port.stopListening() - - d = defer.maybeDeferred(port.stopListening) - d.addCallback(cbStopListening) - return d - - - def testNumberedInterface(self): - f = MyServerFactory() - # listen only on the loopback interface - p1 = reactor.listenTCP(0, f, interface='127.0.0.1') - return p1.stopListening() - - def testPortRepr(self): - f = MyServerFactory() - p = reactor.listenTCP(0, f) - portNo = str(p.getHost().port) - self.failIf(repr(p).find(portNo) == -1) - def stoppedListening(ign): - self.failIf(repr(p).find(portNo) != -1) - d = defer.maybeDeferred(p.stopListening) - return d.addCallback(stoppedListening) - - - def test_serverRepr(self): - """ - Check that the repr string of the server transport get the good port - number if the server listens on 0. - """ - server = MyServerFactory() - serverConnMade = server.protocolConnectionMade = defer.Deferred() - port = reactor.listenTCP(0, server) - self.addCleanup(port.stopListening) - - client = MyClientFactory() - clientConnMade = client.protocolConnectionMade = defer.Deferred() - connector = reactor.connectTCP("127.0.0.1", - port.getHost().port, client) - self.addCleanup(connector.disconnect) - def check(result): - serverProto, clientProto = result - portNumber = port.getHost().port - self.assertEqual( - repr(serverProto.transport), - "" % (portNumber,)) - serverProto.transport.loseConnection() - clientProto.transport.loseConnection() - return defer.gatherResults([serverConnMade, clientConnMade] - ).addCallback(check) - - - def test_restartListening(self): - """ - Stop and then try to restart a L{tcp.Port}: after a restart, the - server should be able to handle client connections. - """ - serverFactory = MyServerFactory() - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - - def cbStopListening(ignored): - port.startListening() - - client = MyClientFactory() - serverFactory.protocolConnectionMade = defer.Deferred() - client.protocolConnectionMade = defer.Deferred() - connector = reactor.connectTCP("127.0.0.1", - port.getHost().port, client) - self.addCleanup(connector.disconnect) - return defer.gatherResults([serverFactory.protocolConnectionMade, - client.protocolConnectionMade] - ).addCallback(close) - - def close(result): - serverProto, clientProto = result - clientProto.transport.loseConnection() - serverProto.transport.loseConnection() - - d = defer.maybeDeferred(port.stopListening) - d.addCallback(cbStopListening) - return d - - - def test_exceptInStop(self): - """ - If the server factory raises an exception in C{stopFactory}, the - deferred returned by L{tcp.Port.stopListening} should fail with the - corresponding error. - """ - serverFactory = MyServerFactory() - def raiseException(): - raise RuntimeError("An error") - serverFactory.stopFactory = raiseException - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - - return self.assertFailure(port.stopListening(), RuntimeError) - - - def test_restartAfterExcept(self): - """ - Even if the server factory raise an exception in C{stopFactory}, the - corresponding C{tcp.Port} instance should be in a sane state and can - be restarted. - """ - serverFactory = MyServerFactory() - def raiseException(): - raise RuntimeError("An error") - serverFactory.stopFactory = raiseException - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - - def cbStopListening(ignored): - del serverFactory.stopFactory - port.startListening() - - client = MyClientFactory() - serverFactory.protocolConnectionMade = defer.Deferred() - client.protocolConnectionMade = defer.Deferred() - connector = reactor.connectTCP("127.0.0.1", - port.getHost().port, client) - self.addCleanup(connector.disconnect) - return defer.gatherResults([serverFactory.protocolConnectionMade, - client.protocolConnectionMade] - ).addCallback(close) - - def close(result): - serverProto, clientProto = result - clientProto.transport.loseConnection() - serverProto.transport.loseConnection() - - return self.assertFailure(port.stopListening(), RuntimeError - ).addCallback(cbStopListening) - - - def test_directConnectionLostCall(self): - """ - If C{connectionLost} is called directly on a port object, it succeeds - (and doesn't expect the presence of a C{deferred} attribute). - - C{connectionLost} is called by L{reactor.disconnectAll} at shutdown. - """ - serverFactory = MyServerFactory() - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - portNumber = port.getHost().port - port.connectionLost(None) - - client = MyClientFactory() - serverFactory.protocolConnectionMade = defer.Deferred() - client.protocolConnectionMade = defer.Deferred() - reactor.connectTCP("127.0.0.1", portNumber, client) - def check(ign): - client.reason.trap(error.ConnectionRefusedError) - return client.failDeferred.addCallback(check) - - - def test_exceptInConnectionLostCall(self): - """ - If C{connectionLost} is called directory on a port object and that the - server factory raises an exception in C{stopFactory}, the exception is - passed through to the caller. - - C{connectionLost} is called by L{reactor.disconnectAll} at shutdown. - """ - serverFactory = MyServerFactory() - def raiseException(): - raise RuntimeError("An error") - serverFactory.stopFactory = raiseException - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.assertRaises(RuntimeError, port.connectionLost, None) - - - -class LoopbackTests(unittest.TestCase): - """ - Test loopback connections. - """ - def test_closePortInProtocolFactory(self): - """ - A port created with L{IReactorTCP.listenTCP} can be connected to with - L{IReactorTCP.connectTCP}. - """ - f = ClosingFactory() - port = reactor.listenTCP(0, f, interface="127.0.0.1") - f.port = port - self.addCleanup(f.cleanUp) - portNumber = port.getHost().port - clientF = MyClientFactory() - reactor.connectTCP("127.0.0.1", portNumber, clientF) - def check(x): - self.assertTrue(clientF.protocol.made) - self.assertTrue(port.disconnected) - clientF.lostReason.trap(error.ConnectionDone) - return clientF.deferred.addCallback(check) - - def _trapCnxDone(self, obj): - getattr(obj, 'trap', lambda x: None)(error.ConnectionDone) - - - def _connectedClientAndServerTest(self, callback): - """ - Invoke the given callback with a client protocol and a server protocol - which have been connected to each other. - """ - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - - portNumber = port.getHost().port - clientF = MyClientFactory() - clientConnMade = defer.Deferred() - clientF.protocolConnectionMade = clientConnMade - reactor.connectTCP("127.0.0.1", portNumber, clientF) - - connsMade = defer.gatherResults([serverConnMade, clientConnMade]) - def connected(result): - serverProtocol, clientProtocol = result - callback(serverProtocol, clientProtocol) - serverProtocol.transport.loseConnection() - clientProtocol.transport.loseConnection() - connsMade.addCallback(connected) - return connsMade - - - def test_tcpNoDelay(self): - """ - The transport of a protocol connected with L{IReactorTCP.connectTCP} or - L{IReactor.TCP.listenTCP} can have its I{TCP_NODELAY} state inspected - and manipulated with L{ITCPTransport.getTcpNoDelay} and - L{ITCPTransport.setTcpNoDelay}. - """ - def check(serverProtocol, clientProtocol): - for p in [serverProtocol, clientProtocol]: - transport = p.transport - self.assertEqual(transport.getTcpNoDelay(), 0) - transport.setTcpNoDelay(1) - self.assertEqual(transport.getTcpNoDelay(), 1) - transport.setTcpNoDelay(0) - self.assertEqual(transport.getTcpNoDelay(), 0) - return self._connectedClientAndServerTest(check) - - - def test_tcpKeepAlive(self): - """ - The transport of a protocol connected with L{IReactorTCP.connectTCP} or - L{IReactor.TCP.listenTCP} can have its I{SO_KEEPALIVE} state inspected - and manipulated with L{ITCPTransport.getTcpKeepAlive} and - L{ITCPTransport.setTcpKeepAlive}. - """ - def check(serverProtocol, clientProtocol): - for p in [serverProtocol, clientProtocol]: - transport = p.transport - self.assertEqual(transport.getTcpKeepAlive(), 0) - transport.setTcpKeepAlive(1) - self.assertEqual(transport.getTcpKeepAlive(), 1) - transport.setTcpKeepAlive(0) - self.assertEqual(transport.getTcpKeepAlive(), 0) - return self._connectedClientAndServerTest(check) - - - def testFailing(self): - clientF = MyClientFactory() - # XXX we assume no one is listening on TCP port 69 - reactor.connectTCP("127.0.0.1", 69, clientF, timeout=5) - def check(ignored): - clientF.reason.trap(error.ConnectionRefusedError) - return clientF.failDeferred.addCallback(check) - - - def test_connectionRefusedErrorNumber(self): - """ - Assert that the error number of the ConnectionRefusedError is - ECONNREFUSED, and not some other socket related error. - """ - - # Bind a number of ports in the operating system. We will attempt - # to connect to these in turn immediately after closing them, in the - # hopes that no one else has bound them in the mean time. Any - # connection which succeeds is ignored and causes us to move on to - # the next port. As soon as a connection attempt fails, we move on - # to making an assertion about how it failed. If they all succeed, - # the test will fail. - - # It would be nice to have a simpler, reliable way to cause a - # connection failure from the platform. - # - # On Linux (2.6.15), connecting to port 0 always fails. FreeBSD - # (5.4) rejects the connection attempt with EADDRNOTAVAIL. - # - # On FreeBSD (5.4), listening on a port and then repeatedly - # connecting to it without ever accepting any connections eventually - # leads to an ECONNREFUSED. On Linux (2.6.15), a seemingly - # unbounded number of connections succeed. - - serverSockets = [] - for i in range(10): - serverSocket = socket.socket() - serverSocket.bind(('127.0.0.1', 0)) - serverSocket.listen(1) - serverSockets.append(serverSocket) - random.shuffle(serverSockets) - - clientCreator = protocol.ClientCreator(reactor, protocol.Protocol) - - def tryConnectFailure(): - def connected(proto): - """ - Darn. Kill it and try again, if there are any tries left. - """ - proto.transport.loseConnection() - if serverSockets: - return tryConnectFailure() - self.fail("Could not fail to connect - could not test errno for that case.") - - serverSocket = serverSockets.pop() - serverHost, serverPort = serverSocket.getsockname() - serverSocket.close() - - connectDeferred = clientCreator.connectTCP(serverHost, serverPort) - connectDeferred.addCallback(connected) - return connectDeferred - - refusedDeferred = tryConnectFailure() - self.assertFailure(refusedDeferred, error.ConnectionRefusedError) - def connRefused(exc): - self.assertEqual(exc.osError, errno.ECONNREFUSED) - refusedDeferred.addCallback(connRefused) - def cleanup(passthrough): - while serverSockets: - serverSockets.pop().close() - return passthrough - refusedDeferred.addBoth(cleanup) - return refusedDeferred - - - def test_connectByServiceFail(self): - """ - Connecting to a named service which does not exist raises - L{error.ServiceNameUnknownError}. - """ - self.assertRaises( - error.ServiceNameUnknownError, - reactor.connectTCP, - "127.0.0.1", "thisbetternotexist", MyClientFactory()) - - - def test_connectByService(self): - """ - L{IReactorTCP.connectTCP} accepts the name of a service instead of a - port number and connects to the port number associated with that - service, as defined by L{socket.getservbyname}. - """ - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - portNumber = port.getHost().port - clientFactory = MyClientFactory() - clientConnMade = defer.Deferred() - clientFactory.protocolConnectionMade = clientConnMade - - def fakeGetServicePortByName(serviceName, protocolName): - if serviceName == 'http' and protocolName == 'tcp': - return portNumber - return 10 - self.patch(socket, 'getservbyname', fakeGetServicePortByName) - - reactor.connectTCP('127.0.0.1', 'http', clientFactory) - - connMade = defer.gatherResults([serverConnMade, clientConnMade]) - def connected(result): - serverProtocol, clientProtocol = result - self.assertTrue( - serverFactory.called, - "Server factory was not called upon to build a protocol.") - serverProtocol.transport.loseConnection() - clientProtocol.transport.loseConnection() - connMade.addCallback(connected) - return connMade - - -class StartStopFactory(protocol.Factory): - - started = 0 - stopped = 0 - - def startFactory(self): - if self.started or self.stopped: - raise RuntimeError - self.started = 1 - - def stopFactory(self): - if not self.started or self.stopped: - raise RuntimeError - self.stopped = 1 - - -class ClientStartStopFactory(MyClientFactory): - - started = 0 - stopped = 0 - - def __init__(self, *a, **kw): - MyClientFactory.__init__(self, *a, **kw) - self.whenStopped = defer.Deferred() - - def startFactory(self): - if self.started or self.stopped: - raise RuntimeError - self.started = 1 - - def stopFactory(self): - if not self.started or self.stopped: - raise RuntimeError - self.stopped = 1 - self.whenStopped.callback(True) - - -class FactoryTests(unittest.TestCase): - """Tests for factories.""" - - def test_serverStartStop(self): - """ - The factory passed to L{IReactorTCP.listenTCP} should be started only - when it transitions from being used on no ports to being used on one - port and should be stopped only when it transitions from being used on - one port to being used on no ports. - """ - # Note - this test doesn't need to use listenTCP. It is exercising - # logic implemented in Factory.doStart and Factory.doStop, so it could - # just call that directly. Some other test can make sure that - # listenTCP and stopListening correctly call doStart and - # doStop. -exarkun - - f = StartStopFactory() - - # listen on port - p1 = reactor.listenTCP(0, f, interface='127.0.0.1') - self.addCleanup(p1.stopListening) - - self.assertEqual((f.started, f.stopped), (1, 0)) - - # listen on two more ports - p2 = reactor.listenTCP(0, f, interface='127.0.0.1') - p3 = reactor.listenTCP(0, f, interface='127.0.0.1') - - self.assertEqual((f.started, f.stopped), (1, 0)) - - # close two ports - d1 = defer.maybeDeferred(p1.stopListening) - d2 = defer.maybeDeferred(p2.stopListening) - closedDeferred = defer.gatherResults([d1, d2]) - def cbClosed(ignored): - self.assertEqual((f.started, f.stopped), (1, 0)) - # Close the last port - return p3.stopListening() - closedDeferred.addCallback(cbClosed) - - def cbClosedAll(ignored): - self.assertEqual((f.started, f.stopped), (1, 1)) - closedDeferred.addCallback(cbClosedAll) - return closedDeferred - - - def test_clientStartStop(self): - """ - The factory passed to L{IReactorTCP.connectTCP} should be started when - the connection attempt starts and stopped when it is over. - """ - f = ClosingFactory() - p = reactor.listenTCP(0, f, interface="127.0.0.1") - f.port = p - self.addCleanup(f.cleanUp) - portNumber = p.getHost().port - - factory = ClientStartStopFactory() - reactor.connectTCP("127.0.0.1", portNumber, factory) - self.assertTrue(factory.started) - return loopUntil(lambda: factory.stopped) - - - -class CannotBindTests(unittest.TestCase): - """ - Tests for correct behavior when a reactor cannot bind to the required TCP - port. - """ - - def test_cannotBind(self): - """ - L{IReactorTCP.listenTCP} raises L{error.CannotListenError} if the - address to listen on is already in use. - """ - f = MyServerFactory() - - p1 = reactor.listenTCP(0, f, interface='127.0.0.1') - self.addCleanup(p1.stopListening) - n = p1.getHost().port - dest = p1.getHost() - self.assertEqual(dest.type, "TCP") - self.assertEqual(dest.host, "127.0.0.1") - self.assertEqual(dest.port, n) - - # make sure new listen raises error - self.assertRaises(error.CannotListenError, - reactor.listenTCP, n, f, interface='127.0.0.1') - - - - def _fireWhenDoneFunc(self, d, f): - """Returns closure that when called calls f and then callbacks d. - """ - @wraps(f) - def newf(*args, **kw): - rtn = f(*args, **kw) - d.callback('') - return rtn - return newf - - - def test_clientBind(self): - """ - L{IReactorTCP.connectTCP} calls C{Factory.clientConnectionFailed} with - L{error.ConnectBindError} if the bind address specified is already in - use. - """ - theDeferred = defer.Deferred() - sf = MyServerFactory() - sf.startFactory = self._fireWhenDoneFunc(theDeferred, sf.startFactory) - p = reactor.listenTCP(0, sf, interface="127.0.0.1") - self.addCleanup(p.stopListening) - - def _connect1(results): - d = defer.Deferred() - cf1 = MyClientFactory() - cf1.buildProtocol = self._fireWhenDoneFunc(d, cf1.buildProtocol) - reactor.connectTCP("127.0.0.1", p.getHost().port, cf1, - bindAddress=("127.0.0.1", 0)) - d.addCallback(_conmade, cf1) - return d - - def _conmade(results, cf1): - d = defer.Deferred() - cf1.protocol.connectionMade = self._fireWhenDoneFunc( - d, cf1.protocol.connectionMade) - d.addCallback(_check1connect2, cf1) - return d - - def _check1connect2(results, cf1): - self.assertEqual(cf1.protocol.made, 1) - - d1 = defer.Deferred() - d2 = defer.Deferred() - port = cf1.protocol.transport.getHost().port - cf2 = MyClientFactory() - cf2.clientConnectionFailed = self._fireWhenDoneFunc( - d1, cf2.clientConnectionFailed) - cf2.stopFactory = self._fireWhenDoneFunc(d2, cf2.stopFactory) - reactor.connectTCP("127.0.0.1", p.getHost().port, cf2, - bindAddress=("127.0.0.1", port)) - d1.addCallback(_check2failed, cf1, cf2) - d2.addCallback(_check2stopped, cf1, cf2) - dl = defer.DeferredList([d1, d2]) - dl.addCallback(_stop, cf1, cf2) - return dl - - def _check2failed(results, cf1, cf2): - self.assertEqual(cf2.failed, 1) - cf2.reason.trap(error.ConnectBindError) - self.assertTrue(cf2.reason.check(error.ConnectBindError)) - return results - - def _check2stopped(results, cf1, cf2): - self.assertEqual(cf2.stopped, 1) - return results - - def _stop(results, cf1, cf2): - d = defer.Deferred() - d.addCallback(_check1cleanup, cf1) - cf1.stopFactory = self._fireWhenDoneFunc(d, cf1.stopFactory) - cf1.protocol.transport.loseConnection() - return d - - def _check1cleanup(results, cf1): - self.assertEqual(cf1.stopped, 1) - - theDeferred.addCallback(_connect1) - return theDeferred - - - -class MyOtherClientFactory(protocol.ClientFactory): - def buildProtocol(self, address): - self.address = address - self.protocol = AccumulatingProtocol() - return self.protocol - - - -class LocalRemoteAddressTests(unittest.TestCase): - """ - Tests for correct getHost/getPeer values and that the correct address is - passed to buildProtocol. - """ - def test_hostAddress(self): - """ - L{IListeningPort.getHost} returns the same address as a client - connection's L{ITCPTransport.getPeer}. - """ - serverFactory = MyServerFactory() - serverFactory.protocolConnectionLost = defer.Deferred() - serverConnectionLost = serverFactory.protocolConnectionLost - port = reactor.listenTCP(0, serverFactory, interface='127.0.0.1') - self.addCleanup(port.stopListening) - n = port.getHost().port - - clientFactory = MyClientFactory() - onConnection = clientFactory.protocolConnectionMade = defer.Deferred() - connector = reactor.connectTCP('127.0.0.1', n, clientFactory) - - def check(ignored): - self.assertEqual([port.getHost()], clientFactory.peerAddresses) - self.assertEqual( - port.getHost(), clientFactory.protocol.transport.getPeer()) - onConnection.addCallback(check) - - def cleanup(ignored): - # Clean up the client explicitly here so that tear down of - # the server side of the connection begins, then wait for - # the server side to actually disconnect. - connector.disconnect() - return serverConnectionLost - onConnection.addCallback(cleanup) - - return onConnection - - - -class WriterProtocol(protocol.Protocol): - def connectionMade(self): - # use everything ITransport claims to provide. If something here - # fails, the exception will be written to the log, but it will not - # directly flunk the test. The test will fail when maximum number of - # iterations have passed and the writer's factory.done has not yet - # been set. - self.transport.write(b"Hello Cleveland!\n") - seq = [b"Goodbye", b" cruel", b" world", b"\n"] - self.transport.writeSequence(seq) - peer = self.transport.getPeer() - if peer.type != "TCP": - msg("getPeer returned non-TCP socket: %s" % (peer,)) - self.factory.problem = 1 - us = self.transport.getHost() - if us.type != "TCP": - msg("getHost returned non-TCP socket: %s" % (us,)) - self.factory.problem = 1 - self.factory.done = 1 - - self.transport.loseConnection() - -class ReaderProtocol(protocol.Protocol): - def dataReceived(self, data): - self.factory.data += data - def connectionLost(self, reason): - self.factory.done = 1 - -class WriterClientFactory(protocol.ClientFactory): - def __init__(self): - self.done = 0 - self.data = b"" - def buildProtocol(self, addr): - p = ReaderProtocol() - p.factory = self - self.protocol = p - return p - -class WriteDataTests(unittest.TestCase): - """ - Test that connected TCP sockets can actually write data. Try to exercise - the entire ITransport interface. - """ - - def test_writer(self): - """ - L{ITCPTransport.write} and L{ITCPTransport.writeSequence} send bytes to - the other end of the connection. - """ - f = protocol.Factory() - f.protocol = WriterProtocol - f.done = 0 - f.problem = 0 - wrappedF = WiredFactory(f) - p = reactor.listenTCP(0, wrappedF, interface="127.0.0.1") - self.addCleanup(p.stopListening) - n = p.getHost().port - clientF = WriterClientFactory() - wrappedClientF = WiredFactory(clientF) - reactor.connectTCP("127.0.0.1", n, wrappedClientF) - - def check(ignored): - self.failUnless(f.done, "writer didn't finish, it probably died") - self.failUnless(f.problem == 0, "writer indicated an error") - self.failUnless(clientF.done, - "client didn't see connection dropped") - expected = b"".join([b"Hello Cleveland!\n", - b"Goodbye", b" cruel", b" world", b"\n"]) - self.failUnless(clientF.data == expected, - "client didn't receive all the data it expected") - d = defer.gatherResults([wrappedF.onDisconnect, - wrappedClientF.onDisconnect]) - return d.addCallback(check) - - - def test_writeAfterShutdownWithoutReading(self): - """ - A TCP transport which is written to after the connection has been shut - down should notify its protocol that the connection has been lost, even - if the TCP transport is not actively being monitored for read events - (ie, pauseProducing was called on it). - """ - # This is an unpleasant thing. Generally tests shouldn't skip or - # run based on the name of the reactor being used (most tests - # shouldn't care _at all_ what reactor is being used, in fact). The - # Gtk reactor cannot pass this test, though, because it fails to - # implement IReactorTCP entirely correctly. Gtk is quite old at - # this point, so it's more likely that gtkreactor will be deprecated - # and removed rather than fixed to handle this case correctly. - # Since this is a pre-existing (and very long-standing) issue with - # the Gtk reactor, there's no reason for it to prevent this test - # being added to exercise the other reactors, for which the behavior - # was also untested but at least works correctly (now). See #2833 - # for information on the status of gtkreactor. - if reactor.__class__.__name__ == 'IOCPReactor': - raise unittest.SkipTest( - "iocpreactor does not, in fact, stop reading immediately after " - "pauseProducing is called. This results in a bonus disconnection " - "notification. Under some circumstances, it might be possible to " - "not receive this notifications (specifically, pauseProducing, " - "deliver some data, proceed with this test).") - if reactor.__class__.__name__ == 'GtkReactor': - raise unittest.SkipTest( - "gtkreactor does not implement unclean disconnection " - "notification correctly. This might more properly be " - "a todo, but due to technical limitations it cannot be.") - - # Called back after the protocol for the client side of the connection - # has paused its transport, preventing it from reading, therefore - # preventing it from noticing the disconnection before the rest of the - # actions which are necessary to trigger the case this test is for have - # been taken. - clientPaused = defer.Deferred() - - # Called back when the protocol for the server side of the connection - # has received connection lost notification. - serverLost = defer.Deferred() - - class Disconnecter(protocol.Protocol): - """ - Protocol for the server side of the connection which disconnects - itself in a callback on clientPaused and publishes notification - when its connection is actually lost. - """ - def connectionMade(self): - """ - Set up a callback on clientPaused to lose the connection. - """ - msg('Disconnector.connectionMade') - def disconnect(ignored): - msg('Disconnector.connectionMade disconnect') - self.transport.loseConnection() - msg('loseConnection called') - clientPaused.addCallback(disconnect) - - def connectionLost(self, reason): - """ - Notify observers that the server side of the connection has - ended. - """ - msg('Disconnecter.connectionLost') - serverLost.callback(None) - msg('serverLost called back') - - # Create the server port to which a connection will be made. - server = protocol.ServerFactory() - server.protocol = Disconnecter - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - addr = port.getHost() - - @implementer(IPullProducer) - class Infinite(object): - """ - A producer which will write to its consumer as long as - resumeProducing is called. - - @ivar consumer: The L{IConsumer} which will be written to. - """ - - def __init__(self, consumer): - self.consumer = consumer - - def resumeProducing(self): - msg('Infinite.resumeProducing') - self.consumer.write(b'x') - msg('Infinite.resumeProducing wrote to consumer') - - def stopProducing(self): - msg('Infinite.stopProducing') - - - class UnreadingWriter(protocol.Protocol): - """ - Trivial protocol which pauses its transport immediately and then - writes some bytes to it. - """ - def connectionMade(self): - msg('UnreadingWriter.connectionMade') - self.transport.pauseProducing() - clientPaused.callback(None) - msg('clientPaused called back') - def write(ignored): - msg('UnreadingWriter.connectionMade write') - # This needs to be enough bytes to spill over into the - # userspace Twisted send buffer - if it all fits into - # the kernel, Twisted won't even poll for OUT events, - # which means it won't poll for any events at all, so - # the disconnection is never noticed. This is due to - # #1662. When #1662 is fixed, this test will likely - # need to be adjusted, otherwise connection lost - # notification will happen too soon and the test will - # probably begin to fail with ConnectionDone instead of - # ConnectionLost (in any case, it will no longer be - # entirely correct). - producer = Infinite(self.transport) - msg('UnreadingWriter.connectionMade write created producer') - self.transport.registerProducer(producer, False) - msg('UnreadingWriter.connectionMade write registered producer') - serverLost.addCallback(write) - - # Create the client and initiate the connection - client = MyClientFactory() - client.protocolFactory = UnreadingWriter - clientConnectionLost = client.deferred - def cbClientLost(ignored): - msg('cbClientLost') - return client.lostReason - clientConnectionLost.addCallback(cbClientLost) - msg('Connecting to %s:%s' % (addr.host, addr.port)) - reactor.connectTCP(addr.host, addr.port, client) - - # By the end of the test, the client should have received notification - # of unclean disconnection. - msg('Returning Deferred') - return self.assertFailure(clientConnectionLost, error.ConnectionLost) - - - -class ConnectionLosingProtocol(protocol.Protocol): - def connectionMade(self): - self.transport.write(b"1") - self.transport.loseConnection() - self.master._connectionMade() - self.master.ports.append(self.transport) - - - -class NoopProtocol(protocol.Protocol): - def connectionMade(self): - self.d = defer.Deferred() - self.master.serverConns.append(self.d) - - def connectionLost(self, reason): - self.d.callback(True) - - - -class ConnectionLostNotifyingProtocol(protocol.Protocol): - """ - Protocol which fires a Deferred which was previously passed to - its initializer when the connection is lost. - - @ivar onConnectionLost: The L{Deferred} which will be fired in - C{connectionLost}. - - @ivar lostConnectionReason: C{None} until the connection is lost, then a - reference to the reason passed to C{connectionLost}. - """ - def __init__(self, onConnectionLost): - self.lostConnectionReason = None - self.onConnectionLost = onConnectionLost - - - def connectionLost(self, reason): - self.lostConnectionReason = reason - self.onConnectionLost.callback(self) - - - -class HandleSavingProtocol(ConnectionLostNotifyingProtocol): - """ - Protocol which grabs the platform-specific socket handle and - saves it as an attribute on itself when the connection is - established. - """ - def makeConnection(self, transport): - """ - Save the platform-specific socket handle for future - introspection. - """ - self.handle = transport.getHandle() - return protocol.Protocol.makeConnection(self, transport) - - - -class ProperlyCloseFilesMixin: - """ - Tests for platform resources properly being cleaned up. - """ - def createServer(self, address, portNumber, factory): - """ - Bind a server port to which connections will be made. The server - should use the given protocol factory. - - @return: The L{IListeningPort} for the server created. - """ - raise NotImplementedError() - - - def connectClient(self, address, portNumber, clientCreator): - """ - Establish a connection to the given address using the given - L{ClientCreator} instance. - - @return: A Deferred which will fire with the connected protocol instance. - """ - raise NotImplementedError() - - - def getHandleExceptionType(self): - """ - Return the exception class which will be raised when an operation is - attempted on a closed platform handle. - """ - raise NotImplementedError() - - - def getHandleErrorCode(self): - """ - Return the errno expected to result from writing to a closed - platform socket handle. - """ - # These platforms have been seen to give EBADF: - # - # Linux 2.4.26, Linux 2.6.15, OS X 10.4, FreeBSD 5.4 - # Windows 2000 SP 4, Windows XP SP 2 - return errno.EBADF - - - def test_properlyCloseFiles(self): - """ - Test that lost connections properly have their underlying socket - resources cleaned up. - """ - onServerConnectionLost = defer.Deferred() - serverFactory = protocol.ServerFactory() - serverFactory.protocol = lambda: ConnectionLostNotifyingProtocol( - onServerConnectionLost) - serverPort = self.createServer('127.0.0.1', 0, serverFactory) - - onClientConnectionLost = defer.Deferred() - serverAddr = serverPort.getHost() - clientCreator = protocol.ClientCreator( - reactor, lambda: HandleSavingProtocol(onClientConnectionLost)) - clientDeferred = self.connectClient( - serverAddr.host, serverAddr.port, clientCreator) - - def clientConnected(client): - """ - Disconnect the client. Return a Deferred which fires when both - the client and the server have received disconnect notification. - """ - client.transport.write( - b'some bytes to make sure the connection is set up') - client.transport.loseConnection() - return defer.gatherResults([ - onClientConnectionLost, onServerConnectionLost]) - clientDeferred.addCallback(clientConnected) - - def clientDisconnected(result): - """ - Verify that the underlying platform socket handle has been - cleaned up. - """ - client, server = result - if not client.lostConnectionReason.check(error.ConnectionClosed): - err(client.lostConnectionReason, - "Client lost connection for unexpected reason") - if not server.lostConnectionReason.check(error.ConnectionClosed): - err(server.lostConnectionReason, - "Server lost connection for unexpected reason") - expectedErrorCode = self.getHandleErrorCode() - exception = self.assertRaises( - self.getHandleExceptionType(), client.handle.send, b'bytes') - self.assertEqual(exception.args[0], expectedErrorCode) - clientDeferred.addCallback(clientDisconnected) - - def cleanup(passthrough): - """ - Shut down the server port. Return a Deferred which fires when - this has completed. - """ - result = defer.maybeDeferred(serverPort.stopListening) - result.addCallback(lambda ign: passthrough) - return result - clientDeferred.addBoth(cleanup) - - return clientDeferred - - - -class ProperlyCloseFilesTests(unittest.TestCase, ProperlyCloseFilesMixin): - """ - Test that the sockets created by L{IReactorTCP.connectTCP} are cleaned up - when the connection they are associated with is closed. - """ - def createServer(self, address, portNumber, factory): - """ - Create a TCP server using L{IReactorTCP.listenTCP}. - """ - return reactor.listenTCP(portNumber, factory, interface=address) - - - def connectClient(self, address, portNumber, clientCreator): - """ - Create a TCP client using L{IReactorTCP.connectTCP}. - """ - return clientCreator.connectTCP(address, portNumber) - - - def getHandleExceptionType(self): - """ - Return L{socket.error} as the expected error type which will be - raised by a write to the low-level socket object after it has been - closed. - """ - return socket.error - - - -class WiredForDeferreds(policies.ProtocolWrapper): - def __init__(self, factory, wrappedProtocol): - policies.ProtocolWrapper.__init__(self, factory, wrappedProtocol) - - def connectionMade(self): - policies.ProtocolWrapper.connectionMade(self) - self.factory.onConnect.callback(None) - - def connectionLost(self, reason): - policies.ProtocolWrapper.connectionLost(self, reason) - self.factory.onDisconnect.callback(None) - - - -class WiredFactory(policies.WrappingFactory): - protocol = WiredForDeferreds - - def __init__(self, wrappedFactory): - policies.WrappingFactory.__init__(self, wrappedFactory) - self.onConnect = defer.Deferred() - self.onDisconnect = defer.Deferred() - - - -class AddressTests(unittest.TestCase): - """ - Tests for address-related interactions with client and server protocols. - """ - def setUp(self): - """ - Create a port and connected client/server pair which can be used - to test factory behavior related to addresses. - - @return: A L{defer.Deferred} which will be called back when both the - client and server protocols have received their connection made - callback. - """ - class RememberingWrapper(protocol.ClientFactory): - """ - Simple wrapper factory which records the addresses which are - passed to its L{buildProtocol} method and delegates actual - protocol creation to another factory. - - @ivar addresses: A list of the objects passed to buildProtocol. - @ivar factory: The wrapped factory to which protocol creation is - delegated. - """ - def __init__(self, factory): - self.addresses = [] - self.factory = factory - - # Only bother to pass on buildProtocol calls to the wrapped - # factory - doStart, doStop, etc aren't necessary for this test - # to pass. - def buildProtocol(self, addr): - """ - Append the given address to C{self.addresses} and forward - the call to C{self.factory}. - """ - self.addresses.append(addr) - return self.factory.buildProtocol(addr) - - # Make a server which we can receive connection and disconnection - # notification for, and which will record the address passed to its - # buildProtocol. - self.server = MyServerFactory() - self.serverConnMade = self.server.protocolConnectionMade = defer.Deferred() - self.serverConnLost = self.server.protocolConnectionLost = defer.Deferred() - # RememberingWrapper is a ClientFactory, but ClientFactory is-a - # ServerFactory, so this is okay. - self.serverWrapper = RememberingWrapper(self.server) - - # Do something similar for a client. - self.client = MyClientFactory() - self.clientConnMade = self.client.protocolConnectionMade = defer.Deferred() - self.clientConnLost = self.client.protocolConnectionLost = defer.Deferred() - self.clientWrapper = RememberingWrapper(self.client) - - self.port = reactor.listenTCP(0, self.serverWrapper, interface='127.0.0.1') - self.connector = reactor.connectTCP( - self.port.getHost().host, self.port.getHost().port, self.clientWrapper) - - return defer.gatherResults([self.serverConnMade, self.clientConnMade]) - - - def tearDown(self): - """ - Disconnect the client/server pair and shutdown the port created in - L{setUp}. - """ - self.connector.disconnect() - return defer.gatherResults([ - self.serverConnLost, self.clientConnLost, - defer.maybeDeferred(self.port.stopListening)]) - - - def test_buildProtocolClient(self): - """ - L{ClientFactory.buildProtocol} should be invoked with the address of - the server to which a connection has been established, which should - be the same as the address reported by the C{getHost} method of the - transport of the server protocol and as the C{getPeer} method of the - transport of the client protocol. - """ - serverHost = self.server.protocol.transport.getHost() - clientPeer = self.client.protocol.transport.getPeer() - - self.assertEqual( - self.clientWrapper.addresses, - [IPv4Address('TCP', serverHost.host, serverHost.port)]) - self.assertEqual( - self.clientWrapper.addresses, - [IPv4Address('TCP', clientPeer.host, clientPeer.port)]) - - - -class LargeBufferWriterProtocol(protocol.Protocol): - - # Win32 sockets cannot handle single huge chunks of bytes. Write one - # massive string to make sure Twisted deals with this fact. - - def connectionMade(self): - # write 60MB - self.transport.write(b'X'*self.factory.len) - self.factory.done = 1 - self.transport.loseConnection() - -class LargeBufferReaderProtocol(protocol.Protocol): - def dataReceived(self, data): - self.factory.len += len(data) - def connectionLost(self, reason): - self.factory.done = 1 - -class LargeBufferReaderClientFactory(protocol.ClientFactory): - def __init__(self): - self.done = 0 - self.len = 0 - def buildProtocol(self, addr): - p = LargeBufferReaderProtocol() - p.factory = self - self.protocol = p - return p - - -class FireOnClose(policies.ProtocolWrapper): - """A wrapper around a protocol that makes it fire a deferred when - connectionLost is called. - """ - def connectionLost(self, reason): - policies.ProtocolWrapper.connectionLost(self, reason) - self.factory.deferred.callback(None) - - -class FireOnCloseFactory(policies.WrappingFactory): - protocol = FireOnClose - - def __init__(self, wrappedFactory): - policies.WrappingFactory.__init__(self, wrappedFactory) - self.deferred = defer.Deferred() - - -class LargeBufferTests(unittest.TestCase): - """Test that buffering large amounts of data works. - """ - - datalen = 60*1024*1024 - def testWriter(self): - f = protocol.Factory() - f.protocol = LargeBufferWriterProtocol - f.done = 0 - f.problem = 0 - f.len = self.datalen - wrappedF = FireOnCloseFactory(f) - p = reactor.listenTCP(0, wrappedF, interface="127.0.0.1") - self.addCleanup(p.stopListening) - n = p.getHost().port - clientF = LargeBufferReaderClientFactory() - wrappedClientF = FireOnCloseFactory(clientF) - reactor.connectTCP("127.0.0.1", n, wrappedClientF) - - d = defer.gatherResults([wrappedF.deferred, wrappedClientF.deferred]) - def check(ignored): - self.failUnless(f.done, "writer didn't finish, it probably died") - self.failUnless(clientF.len == self.datalen, - "client didn't receive all the data it expected " - "(%d != %d)" % (clientF.len, self.datalen)) - self.failUnless(clientF.done, - "client didn't see connection dropped") - return d.addCallback(check) - - -@implementer(IHalfCloseableProtocol) -class MyHCProtocol(AccumulatingProtocol): - - - readHalfClosed = False - writeHalfClosed = False - - def readConnectionLost(self): - self.readHalfClosed = True - # Invoke notification logic from the base class to simplify testing. - if self.writeHalfClosed: - self.connectionLost(None) - - def writeConnectionLost(self): - self.writeHalfClosed = True - # Invoke notification logic from the base class to simplify testing. - if self.readHalfClosed: - self.connectionLost(None) - - -class MyHCFactory(protocol.ServerFactory): - - called = 0 - protocolConnectionMade = None - - def buildProtocol(self, addr): - self.called += 1 - p = MyHCProtocol() - p.factory = self - self.protocol = p - return p - - -class HalfCloseTests(unittest.TestCase): - """Test half-closing connections.""" - - def setUp(self): - self.f = f = MyHCFactory() - self.p = p = reactor.listenTCP(0, f, interface="127.0.0.1") - self.addCleanup(p.stopListening) - d = loopUntil(lambda :p.connected) - - self.cf = protocol.ClientCreator(reactor, MyHCProtocol) - - d.addCallback(lambda _: self.cf.connectTCP(p.getHost().host, - p.getHost().port)) - d.addCallback(self._setUp) - return d - - def _setUp(self, client): - self.client = client - self.clientProtoConnectionLost = self.client.closedDeferred = defer.Deferred() - self.assertEqual(self.client.transport.connected, 1) - # Wait for the server to notice there is a connection, too. - return loopUntil(lambda: getattr(self.f, 'protocol', None) is not None) - - def tearDown(self): - self.assertEqual(self.client.closed, 0) - self.client.transport.loseConnection() - d = defer.maybeDeferred(self.p.stopListening) - d.addCallback(lambda ign: self.clientProtoConnectionLost) - d.addCallback(self._tearDown) - return d - - def _tearDown(self, ignored): - self.assertEqual(self.client.closed, 1) - # because we did half-close, the server also needs to - # closed explicitly. - self.assertEqual(self.f.protocol.closed, 0) - d = defer.Deferred() - def _connectionLost(reason): - self.f.protocol.closed = 1 - d.callback(None) - self.f.protocol.connectionLost = _connectionLost - self.f.protocol.transport.loseConnection() - d.addCallback(lambda x:self.assertEqual(self.f.protocol.closed, 1)) - return d - - def testCloseWriteCloser(self): - client = self.client - f = self.f - t = client.transport - - t.write(b"hello") - d = loopUntil(lambda :len(t._tempDataBuffer) == 0) - def loseWrite(ignored): - t.loseWriteConnection() - return loopUntil(lambda :t._writeDisconnected) - def check(ignored): - self.assertEqual(client.closed, False) - self.assertEqual(client.writeHalfClosed, True) - self.assertEqual(client.readHalfClosed, False) - return loopUntil(lambda :f.protocol.readHalfClosed) - def write(ignored): - w = client.transport.write - w(b" world") - w(b"lalala fooled you") - self.assertEqual(0, len(client.transport._tempDataBuffer)) - self.assertEqual(f.protocol.data, b"hello") - self.assertEqual(f.protocol.closed, False) - self.assertEqual(f.protocol.readHalfClosed, True) - return d.addCallback(loseWrite).addCallback(check).addCallback(write) - - def testWriteCloseNotification(self): - f = self.f - f.protocol.transport.loseWriteConnection() - - d = defer.gatherResults([ - loopUntil(lambda :f.protocol.writeHalfClosed), - loopUntil(lambda :self.client.readHalfClosed)]) - d.addCallback(lambda _: self.assertEqual( - f.protocol.readHalfClosed, False)) - return d - - -class HalfCloseNoNotificationAndShutdownExceptionTests(unittest.TestCase): - - def setUp(self): - self.f = f = MyServerFactory() - self.f.protocolConnectionMade = defer.Deferred() - self.p = p = reactor.listenTCP(0, f, interface="127.0.0.1") - - # XXX we don't test server side yet since we don't do it yet - d = protocol.ClientCreator(reactor, AccumulatingProtocol).connectTCP( - p.getHost().host, p.getHost().port) - d.addCallback(self._gotClient) - return d - - def _gotClient(self, client): - self.client = client - # Now wait for the server to catch up - it doesn't matter if this - # Deferred has already fired and gone away, in that case we'll - # return None and not wait at all, which is precisely correct. - return self.f.protocolConnectionMade - - def tearDown(self): - self.client.transport.loseConnection() - return self.p.stopListening() - - def testNoNotification(self): - """ - TCP protocols support half-close connections, but not all of them - support being notified of write closes. In this case, test that - half-closing the connection causes the peer's connection to be - closed. - """ - self.client.transport.write(b"hello") - self.client.transport.loseWriteConnection() - self.f.protocol.closedDeferred = d = defer.Deferred() - self.client.closedDeferred = d2 = defer.Deferred() - d.addCallback(lambda x: - self.assertEqual(self.f.protocol.data, b'hello')) - d.addCallback(lambda x: self.assertEqual(self.f.protocol.closed, True)) - return defer.gatherResults([d, d2]) - - def testShutdownException(self): - """ - If the other side has already closed its connection, - loseWriteConnection should pass silently. - """ - self.f.protocol.transport.loseConnection() - self.client.transport.write(b"X") - self.client.transport.loseWriteConnection() - self.f.protocol.closedDeferred = d = defer.Deferred() - self.client.closedDeferred = d2 = defer.Deferred() - d.addCallback(lambda x: - self.assertEqual(self.f.protocol.closed, True)) - return defer.gatherResults([d, d2]) - - -class HalfCloseBuggyApplicationTests(unittest.TestCase): - """ - Test half-closing connections where notification code has bugs. - """ - - def setUp(self): - """ - Set up a server and connect a client to it. Return a Deferred which - only fires once this is done. - """ - self.serverFactory = MyHCFactory() - self.serverFactory.protocolConnectionMade = defer.Deferred() - self.port = reactor.listenTCP( - 0, self.serverFactory, interface="127.0.0.1") - self.addCleanup(self.port.stopListening) - addr = self.port.getHost() - creator = protocol.ClientCreator(reactor, MyHCProtocol) - clientDeferred = creator.connectTCP(addr.host, addr.port) - def setClient(clientProtocol): - self.clientProtocol = clientProtocol - clientDeferred.addCallback(setClient) - return defer.gatherResults([ - self.serverFactory.protocolConnectionMade, - clientDeferred]) - - - def aBug(self, *args): - """ - Fake implementation of a callback which illegally raises an - exception. - """ - raise RuntimeError("ONO I AM BUGGY CODE") - - - def _notificationRaisesTest(self): - """ - Helper for testing that an exception is logged by the time the - client protocol loses its connection. - """ - closed = self.clientProtocol.closedDeferred = defer.Deferred() - self.clientProtocol.transport.loseWriteConnection() - def check(ignored): - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - closed.addCallback(check) - return closed - - - def test_readNotificationRaises(self): - """ - If C{readConnectionLost} raises an exception when the transport - calls it to notify the protocol of that event, the exception should - be logged and the protocol should be disconnected completely. - """ - self.serverFactory.protocol.readConnectionLost = self.aBug - return self._notificationRaisesTest() - - - def test_writeNotificationRaises(self): - """ - If C{writeConnectionLost} raises an exception when the transport - calls it to notify the protocol of that event, the exception should - be logged and the protocol should be disconnected completely. - """ - self.clientProtocol.writeConnectionLost = self.aBug - return self._notificationRaisesTest() - - - -class LogTests(unittest.TestCase): - """ - Test logging facility of TCP base classes. - """ - - def test_logstrClientSetup(self): - """ - Check that the log customization of the client transport happens - once the client is connected. - """ - server = MyServerFactory() - - client = MyClientFactory() - client.protocolConnectionMade = defer.Deferred() - - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - - connector = reactor.connectTCP( - port.getHost().host, port.getHost().port, client) - self.addCleanup(connector.disconnect) - - # It should still have the default value - self.assertEqual(connector.transport.logstr, - "Uninitialized") - - def cb(ign): - self.assertEqual(connector.transport.logstr, - "AccumulatingProtocol,client") - client.protocolConnectionMade.addCallback(cb) - return client.protocolConnectionMade - - - -class PauseProducingTests(unittest.TestCase): - """ - Test some behaviors of pausing the production of a transport. - """ - - def test_pauseProducingInConnectionMade(self): - """ - In C{connectionMade} of a client protocol, C{pauseProducing} used to be - ignored: this test is here to ensure it's not ignored. - """ - server = MyServerFactory() - - client = MyClientFactory() - client.protocolConnectionMade = defer.Deferred() - - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - - connector = reactor.connectTCP( - port.getHost().host, port.getHost().port, client) - self.addCleanup(connector.disconnect) - - def checkInConnectionMade(proto): - tr = proto.transport - # The transport should already be monitored - self.assertIn(tr, reactor.getReaders() + - reactor.getWriters()) - proto.transport.pauseProducing() - self.assertNotIn(tr, reactor.getReaders() + - reactor.getWriters()) - d = defer.Deferred() - d.addCallback(checkAfterConnectionMade) - reactor.callLater(0, d.callback, proto) - return d - def checkAfterConnectionMade(proto): - tr = proto.transport - # The transport should still not be monitored - self.assertNotIn(tr, reactor.getReaders() + - reactor.getWriters()) - client.protocolConnectionMade.addCallback(checkInConnectionMade) - return client.protocolConnectionMade - - if not interfaces.IReactorFDSet.providedBy(reactor): - test_pauseProducingInConnectionMade.skip = "Reactor not providing IReactorFDSet" - - - -class CallBackOrderTests(unittest.TestCase): - """ - Test the order of reactor callbacks - """ - - def test_loseOrder(self): - """ - Check that Protocol.connectionLost is called before factory's - clientConnectionLost - """ - server = MyServerFactory() - server.protocolConnectionMade = (defer.Deferred() - .addCallback(lambda proto: self.addCleanup( - proto.transport.loseConnection))) - - client = MyClientFactory() - client.protocolConnectionLost = defer.Deferred() - client.protocolConnectionMade = defer.Deferred() - - def _cbCM(res): - """ - protocol.connectionMade callback - """ - reactor.callLater(0, client.protocol.transport.loseConnection) - - client.protocolConnectionMade.addCallback(_cbCM) - - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - - connector = reactor.connectTCP( - port.getHost().host, port.getHost().port, client) - self.addCleanup(connector.disconnect) - - def _cbCCL(res): - """ - factory.clientConnectionLost callback - """ - return 'CCL' - - def _cbCL(res): - """ - protocol.connectionLost callback - """ - return 'CL' - - def _cbGather(res): - self.assertEqual(res, ['CL', 'CCL']) - - d = defer.gatherResults([ - client.protocolConnectionLost.addCallback(_cbCL), - client.deferred.addCallback(_cbCCL)]) - return d.addCallback(_cbGather) - - - -try: - import resource -except ImportError: - pass -else: - numRounds = resource.getrlimit(resource.RLIMIT_NOFILE)[0] + 10 - ProperlyCloseFilesTests.numberRounds = numRounds diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tcp_internals.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tcp_internals.py deleted file mode 100644 index 08a402d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tcp_internals.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Whitebox tests for TCP APIs. -""" - -from __future__ import division, absolute_import - -import errno, socket, os - -try: - import resource -except ImportError: - resource = None - -from twisted.python.compat import _PY3 -from twisted.trial.unittest import TestCase - -from twisted.python import log -from twisted.internet.tcp import ECONNABORTED, ENOMEM, ENFILE, EMFILE, ENOBUFS, EINPROGRESS, Port -from twisted.internet.protocol import ServerFactory -from twisted.python.runtime import platform -from twisted.internet.defer import maybeDeferred, gatherResults -from twisted.internet import reactor, interfaces - - -class PlatformAssumptionsTests(TestCase): - """ - Test assumptions about platform behaviors. - """ - if _PY3: - skip = "Port when Python 3 supports twisted.internet.process (#5987)" - - socketLimit = 8192 - - def setUp(self): - self.openSockets = [] - if resource is not None: - # On some buggy platforms we might leak FDs, and the test will - # fail creating the initial two sockets we *do* want to - # succeed. So, we make the soft limit the current number of fds - # plus two more (for the two sockets we want to succeed). If we've - # leaked too many fds for that to work, there's nothing we can - # do. - from twisted.internet.process import _listOpenFDs - newLimit = len(_listOpenFDs()) + 2 - self.originalFileLimit = resource.getrlimit(resource.RLIMIT_NOFILE) - resource.setrlimit(resource.RLIMIT_NOFILE, (newLimit, self.originalFileLimit[1])) - self.socketLimit = newLimit + 100 - - - def tearDown(self): - while self.openSockets: - self.openSockets.pop().close() - if resource is not None: - # OS X implicitly lowers the hard limit in the setrlimit call - # above. Retrieve the new hard limit to pass in to this - # setrlimit call, so that it doesn't give us a permission denied - # error. - currentHardLimit = resource.getrlimit(resource.RLIMIT_NOFILE)[1] - newSoftLimit = min(self.originalFileLimit[0], currentHardLimit) - resource.setrlimit(resource.RLIMIT_NOFILE, (newSoftLimit, currentHardLimit)) - - - def socket(self): - """ - Create and return a new socket object, also tracking it so it can be - closed in the test tear down. - """ - s = socket.socket() - self.openSockets.append(s) - return s - - - def test_acceptOutOfFiles(self): - """ - Test that the platform accept(2) call fails with either L{EMFILE} or - L{ENOBUFS} when there are too many file descriptors open. - """ - # Make a server to which to connect - port = self.socket() - port.bind(('127.0.0.1', 0)) - serverPortNumber = port.getsockname()[1] - port.listen(5) - - # Make a client to use to connect to the server - client = self.socket() - client.setblocking(False) - - # Use up all the rest of the file descriptors. - for i in xrange(self.socketLimit): - try: - self.socket() - except socket.error as e: - if e.args[0] in (EMFILE, ENOBUFS): - # The desired state has been achieved. - break - else: - # Some unexpected error occurred. - raise - else: - self.fail("Could provoke neither EMFILE nor ENOBUFS from platform.") - - # Non-blocking connect is supposed to fail, but this is not true - # everywhere (e.g. freeBSD) - self.assertIn(client.connect_ex(('127.0.0.1', serverPortNumber)), - (0, EINPROGRESS)) - - # Make sure that the accept call fails in the way we expect. - exc = self.assertRaises(socket.error, port.accept) - self.assertIn(exc.args[0], (EMFILE, ENOBUFS)) - if platform.getType() == "win32": - test_acceptOutOfFiles.skip = ( - "Windows requires an unacceptably large amount of resources to " - "provoke this behavior in the naive manner.") - - - -class SelectReactorTests(TestCase): - """ - Tests for select-specific failure conditions. - """ - - def setUp(self): - self.ports = [] - self.messages = [] - log.addObserver(self.messages.append) - - - def tearDown(self): - log.removeObserver(self.messages.append) - return gatherResults([ - maybeDeferred(p.stopListening) - for p in self.ports]) - - - def port(self, portNumber, factory, interface): - """ - Create, start, and return a new L{Port}, also tracking it so it can - be stopped in the test tear down. - """ - p = Port(portNumber, factory, interface=interface) - p.startListening() - self.ports.append(p) - return p - - - def _acceptFailureTest(self, socketErrorNumber): - """ - Test behavior in the face of an exception from C{accept(2)}. - - On any exception which indicates the platform is unable or unwilling - to allocate further resources to us, the existing port should remain - listening, a message should be logged, and the exception should not - propagate outward from doRead. - - @param socketErrorNumber: The errno to simulate from accept. - """ - class FakeSocket(object): - """ - Pretend to be a socket in an overloaded system. - """ - def accept(self): - raise socket.error( - socketErrorNumber, os.strerror(socketErrorNumber)) - - factory = ServerFactory() - port = self.port(0, factory, interface='127.0.0.1') - originalSocket = port.socket - try: - port.socket = FakeSocket() - - port.doRead() - - expectedFormat = "Could not accept new connection (%s)" - expectedErrorCode = errno.errorcode[socketErrorNumber] - expectedMessage = expectedFormat % (expectedErrorCode,) - for msg in self.messages: - if msg.get('message') == (expectedMessage,): - break - else: - self.fail("Log event for failed accept not found in " - "%r" % (self.messages,)) - finally: - port.socket = originalSocket - - - def test_tooManyFilesFromAccept(self): - """ - C{accept(2)} can fail with C{EMFILE} when there are too many open file - descriptors in the process. Test that this doesn't negatively impact - any other existing connections. - - C{EMFILE} mainly occurs on Linux when the open file rlimit is - encountered. - """ - return self._acceptFailureTest(EMFILE) - - - def test_noBufferSpaceFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ENOBUFS}. - - This mainly occurs on Windows and FreeBSD, but may be possible on - Linux and other platforms as well. - """ - return self._acceptFailureTest(ENOBUFS) - - - def test_connectionAbortedFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ECONNABORTED}. - - It is not clear whether this is actually possible for TCP - connections on modern versions of Linux. - """ - return self._acceptFailureTest(ECONNABORTED) - - - def test_noFilesFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ENFILE}. - - This can occur on Linux when the system has exhausted (!) its supply - of inodes. - """ - return self._acceptFailureTest(ENFILE) - if platform.getType() == 'win32': - test_noFilesFromAccept.skip = "Windows accept(2) cannot generate ENFILE" - - - def test_noMemoryFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ENOMEM}. - - On Linux at least, this can sensibly occur, even in a Python program - (which eats memory like no ones business), when memory has become - fragmented or low memory has been filled (d_alloc calls - kmem_cache_alloc calls kmalloc - kmalloc only allocates out of low - memory). - """ - return self._acceptFailureTest(ENOMEM) - if platform.getType() == 'win32': - test_noMemoryFromAccept.skip = "Windows accept(2) cannot generate ENOMEM" - -if not interfaces.IReactorFDSet.providedBy(reactor): - skipMsg = 'This test only applies to reactors that implement IReactorFDset' - PlatformAssumptionsTests.skip = skipMsg - SelectReactorTests.skip = skipMsg - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_text.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_text.py deleted file mode 100644 index 7a0e914..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_text.py +++ /dev/null @@ -1,242 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.text}. -""" - -from cStringIO import StringIO - -from twisted.trial import unittest -from twisted.python import text - - -sampleText = \ -"""Every attempt to employ mathematical methods in the study of chemical -questions must be considered profoundly irrational and contrary to the -spirit of chemistry ... If mathematical analysis should ever hold a -prominent place in chemistry - an aberration which is happily almost -impossible - it would occasion a rapid and widespread degeneration of that -science. - - -- Auguste Comte, Philosophie Positive, Paris, 1838 -""" - - -class WrapTests(unittest.TestCase): - """ - Tests for L{text.greedyWrap}. - """ - def setUp(self): - self.lineWidth = 72 - self.sampleSplitText = sampleText.split() - self.output = text.wordWrap(sampleText, self.lineWidth) - - - def test_wordCount(self): - """ - Compare the number of words. - """ - words = [] - for line in self.output: - words.extend(line.split()) - wordCount = len(words) - sampleTextWordCount = len(self.sampleSplitText) - - self.assertEqual(wordCount, sampleTextWordCount) - - - def test_wordMatch(self): - """ - Compare the lists of words. - """ - words = [] - for line in self.output: - words.extend(line.split()) - - # Using assertEqual here prints out some - # rather too long lists. - self.failUnless(self.sampleSplitText == words) - - - def test_lineLength(self): - """ - Check the length of the lines. - """ - failures = [] - for line in self.output: - if not len(line) <= self.lineWidth: - failures.append(len(line)) - - if failures: - self.fail("%d of %d lines were too long.\n" - "%d < %s" % (len(failures), len(self.output), - self.lineWidth, failures)) - - def test_doubleNewline(self): - """ - Allow paragraphs delimited by two \ns. - """ - sampleText = "et\n\nphone\nhome." - result = text.wordWrap(sampleText, self.lineWidth) - self.assertEqual(result, ["et", "", "phone home.", ""]) - - - -class LineTests(unittest.TestCase): - """ - Tests for L{isMultiline} and L{endsInNewline}. - """ - def test_isMultiline(self): - """ - L{text.isMultiline} returns C{True} if the string has a newline in it. - """ - s = 'This code\n "breaks."' - m = text.isMultiline(s) - self.assertTrue(m) - - s = 'This code does not "break."' - m = text.isMultiline(s) - self.assertFalse(m) - - - def test_endsInNewline(self): - """ - L{text.endsInNewline} returns C{True} if the string ends in a newline. - """ - s = 'newline\n' - m = text.endsInNewline(s) - self.assertTrue(m) - - s = 'oldline' - m = text.endsInNewline(s) - self.assertFalse(m) - - - -class StringyStringTests(unittest.TestCase): - """ - Tests for L{text.stringyString}. - """ - def test_tuple(self): - """ - Tuple elements are displayed on separate lines. - """ - s = ('a', 'b') - m = text.stringyString(s) - self.assertEqual(m, '(a,\n b,)\n') - - - def test_dict(self): - """ - Dicts elements are displayed using C{str()}. - """ - s = {'a': 0} - m = text.stringyString(s) - self.assertEqual(m, '{a: 0}') - - - def test_list(self): - """ - List elements are displayed on separate lines using C{str()}. - """ - s = ['a', 'b'] - m = text.stringyString(s) - self.assertEqual(m, '[a,\n b,]\n') - - - -class SplitTests(unittest.TestCase): - """ - Tests for L{text.splitQuoted}. - """ - def test_oneWord(self): - """ - Splitting strings with one-word phrases. - """ - s = 'This code "works."' - r = text.splitQuoted(s) - self.assertEqual(['This', 'code', 'works.'], r) - - - def test_multiWord(self): - s = 'The "hairy monkey" likes pie.' - r = text.splitQuoted(s) - self.assertEqual(['The', 'hairy monkey', 'likes', 'pie.'], r) - - # Some of the many tests that would fail: - - #def test_preserveWhitespace(self): - # phrase = '"MANY SPACES"' - # s = 'With %s between.' % (phrase,) - # r = text.splitQuoted(s) - # self.assertEqual(['With', phrase, 'between.'], r) - - #def test_escapedSpace(self): - # s = r"One\ Phrase" - # r = text.splitQuoted(s) - # self.assertEqual(["One Phrase"], r) - - - -class StrFileTests(unittest.TestCase): - def setUp(self): - self.io = StringIO("this is a test string") - - def tearDown(self): - pass - - def test_1_f(self): - self.assertEqual(False, text.strFile("x", self.io)) - - def test_1_1(self): - self.assertEqual(True, text.strFile("t", self.io)) - - def test_1_2(self): - self.assertEqual(True, text.strFile("h", self.io)) - - def test_1_3(self): - self.assertEqual(True, text.strFile("i", self.io)) - - def test_1_4(self): - self.assertEqual(True, text.strFile("s", self.io)) - - def test_1_5(self): - self.assertEqual(True, text.strFile("n", self.io)) - - def test_1_6(self): - self.assertEqual(True, text.strFile("g", self.io)) - - def test_3_1(self): - self.assertEqual(True, text.strFile("thi", self.io)) - - def test_3_2(self): - self.assertEqual(True, text.strFile("his", self.io)) - - def test_3_3(self): - self.assertEqual(True, text.strFile("is ", self.io)) - - def test_3_4(self): - self.assertEqual(True, text.strFile("ing", self.io)) - - def test_3_f(self): - self.assertEqual(False, text.strFile("bla", self.io)) - - def test_large_1(self): - self.assertEqual(True, text.strFile("this is a test", self.io)) - - def test_large_2(self): - self.assertEqual(True, text.strFile("is a test string", self.io)) - - def test_large_f(self): - self.assertEqual(False, text.strFile("ds jhfsa k fdas", self.io)) - - def test_overlarge_f(self): - self.assertEqual(False, text.strFile("djhsakj dhsa fkhsa s,mdbnfsauiw bndasdf hreew", self.io)) - - def test_self(self): - self.assertEqual(True, text.strFile("this is a test string", self.io)) - - def test_insensitive(self): - self.assertEqual(True, text.strFile("ThIs is A test STRING", self.io, False)) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threadable.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threadable.py deleted file mode 100644 index 5be5638..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threadable.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.threadable}. -""" - -from __future__ import division, absolute_import - -import sys, pickle - -try: - import threading -except ImportError: - threadingSkip = "Platform lacks thread support" -else: - threadingSkip = None - -from twisted.python.compat import _PY3 -from twisted.trial import unittest - -from twisted.python import threadable - -class TestObject: - synchronized = ['aMethod'] - - x = -1 - y = 1 - - def aMethod(self): - for i in range(10): - self.x, self.y = self.y, self.x - self.z = self.x + self.y - assert self.z == 0, "z == %d, not 0 as expected" % (self.z,) - -threadable.synchronize(TestObject) - -class SynchronizationTests(unittest.SynchronousTestCase): - def setUp(self): - """ - Reduce the CPython check interval so that thread switches happen much - more often, hopefully exercising more possible race conditions. Also, - delay actual test startup until the reactor has been started. - """ - if _PY3: - if getattr(sys, 'getswitchinterval', None) is not None: - self.addCleanup(sys.setswitchinterval, sys.getswitchinterval()) - sys.setswitchinterval(0.0000001) - else: - if getattr(sys, 'getcheckinterval', None) is not None: - self.addCleanup(sys.setcheckinterval, sys.getcheckinterval()) - sys.setcheckinterval(7) - - - def test_synchronizedName(self): - """ - The name of a synchronized method is inaffected by the synchronization - decorator. - """ - self.assertEqual("aMethod", TestObject.aMethod.__name__) - - - def test_isInIOThread(self): - """ - L{threadable.isInIOThread} returns C{True} if and only if it is called - in the same thread as L{threadable.registerAsIOThread}. - """ - threadable.registerAsIOThread() - foreignResult = [] - t = threading.Thread( - target=lambda: foreignResult.append(threadable.isInIOThread())) - t.start() - t.join() - self.assertFalse( - foreignResult[0], "Non-IO thread reported as IO thread") - self.assertTrue( - threadable.isInIOThread(), "IO thread reported as not IO thread") - - - def testThreadedSynchronization(self): - o = TestObject() - - errors = [] - - def callMethodLots(): - try: - for i in range(1000): - o.aMethod() - except AssertionError as e: - errors.append(str(e)) - - threads = [] - for x in range(5): - t = threading.Thread(target=callMethodLots) - threads.append(t) - t.start() - - for t in threads: - t.join() - - if errors: - raise unittest.FailTest(errors) - - if threadingSkip is not None: - testThreadedSynchronization.skip = threadingSkip - test_isInIOThread.skip = threadingSkip - - - def testUnthreadedSynchronization(self): - o = TestObject() - for i in range(1000): - o.aMethod() - - - -class SerializationTests(unittest.SynchronousTestCase): - def testPickling(self): - lock = threadable.XLock() - lockType = type(lock) - lockPickle = pickle.dumps(lock) - newLock = pickle.loads(lockPickle) - self.assertTrue(isinstance(newLock, lockType)) - - if threadingSkip is not None: - testPickling.skip = threadingSkip - - - def testUnpickling(self): - lockPickle = b'ctwisted.python.threadable\nunpickle_lock\np0\n(tp1\nRp2\n.' - lock = pickle.loads(lockPickle) - newPickle = pickle.dumps(lock, 2) - pickle.loads(newPickle) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threadpool.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threadpool.py deleted file mode 100644 index fa871d0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threadpool.py +++ /dev/null @@ -1,625 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.threadpool} -""" - -from __future__ import division, absolute_import - -import pickle, time, weakref, gc, threading - -from twisted.python.compat import _PY3 -from twisted.trial import unittest -from twisted.python import threadpool, threadable, failure, context - -# -# See the end of this module for the remainder of the imports. -# - -class Synchronization(object): - failures = 0 - - def __init__(self, N, waiting): - self.N = N - self.waiting = waiting - self.lock = threading.Lock() - self.runs = [] - - def run(self): - # This is the testy part: this is supposed to be invoked - # serially from multiple threads. If that is actually the - # case, we will never fail to acquire this lock. If it is - # *not* the case, we might get here while someone else is - # holding the lock. - if self.lock.acquire(False): - if not len(self.runs) % 5: - time.sleep(0.0002) # Constant selected based on - # empirical data to maximize the - # chance of a quick failure if this - # code is broken. - self.lock.release() - else: - self.failures += 1 - - # This is just the only way I can think of to wake up the test - # method. It doesn't actually have anything to do with the - # test. - self.lock.acquire() - self.runs.append(None) - if len(self.runs) == self.N: - self.waiting.release() - self.lock.release() - - synchronized = ["run"] -threadable.synchronize(Synchronization) - - - -class ThreadPoolTests(unittest.SynchronousTestCase): - """ - Test threadpools. - """ - - def getTimeout(self): - """ - Return number of seconds to wait before giving up. - """ - return 5 # Really should be order of magnitude less - - - def _waitForLock(self, lock): - # We could just use range(), but then we use an extra 30MB of memory - # on Python 2: - if _PY3: - items = range(1000000) - else: - items = xrange(1000000) - for i in items: - if lock.acquire(False): - break - time.sleep(1e-5) - else: - self.fail("A long time passed without succeeding") - - - def test_attributes(self): - """ - L{ThreadPool.min} and L{ThreadPool.max} are set to the values passed to - L{ThreadPool.__init__}. - """ - pool = threadpool.ThreadPool(12, 22) - self.assertEqual(pool.min, 12) - self.assertEqual(pool.max, 22) - - - def test_start(self): - """ - L{ThreadPool.start} creates the minimum number of threads specified. - """ - pool = threadpool.ThreadPool(0, 5) - pool.start() - self.addCleanup(pool.stop) - self.assertEqual(len(pool.threads), 0) - - pool = threadpool.ThreadPool(3, 10) - self.assertEqual(len(pool.threads), 0) - pool.start() - self.addCleanup(pool.stop) - self.assertEqual(len(pool.threads), 3) - - - def test_adjustingWhenPoolStopped(self): - """ - L{ThreadPool.adjustPoolsize} only modifies the pool size and does not - start new workers while the pool is not running. - """ - pool = threadpool.ThreadPool(0, 5) - pool.start() - pool.stop() - pool.adjustPoolsize(2) - self.assertEqual(len(pool.threads), 0) - - - def test_threadCreationArguments(self): - """ - Test that creating threads in the threadpool with application-level - objects as arguments doesn't results in those objects never being - freed, with the thread maintaining a reference to them as long as it - exists. - """ - tp = threadpool.ThreadPool(0, 1) - tp.start() - self.addCleanup(tp.stop) - - # Sanity check - no threads should have been started yet. - self.assertEqual(tp.threads, []) - - # Here's our function - def worker(arg): - pass - # weakref needs an object subclass - class Dumb(object): - pass - # And here's the unique object - unique = Dumb() - - workerRef = weakref.ref(worker) - uniqueRef = weakref.ref(unique) - - # Put some work in - tp.callInThread(worker, unique) - - # Add an event to wait completion - event = threading.Event() - tp.callInThread(event.set) - event.wait(self.getTimeout()) - - del worker - del unique - gc.collect() - self.assertEqual(uniqueRef(), None) - self.assertEqual(workerRef(), None) - - - def test_threadCreationArgumentsCallInThreadWithCallback(self): - """ - As C{test_threadCreationArguments} above, but for - callInThreadWithCallback. - """ - - tp = threadpool.ThreadPool(0, 1) - tp.start() - self.addCleanup(tp.stop) - - # Sanity check - no threads should have been started yet. - self.assertEqual(tp.threads, []) - - # this holds references obtained in onResult - refdict = {} # name -> ref value - - onResultWait = threading.Event() - onResultDone = threading.Event() - - resultRef = [] - - # result callback - def onResult(success, result): - onResultWait.wait(self.getTimeout()) - refdict['workerRef'] = workerRef() - refdict['uniqueRef'] = uniqueRef() - onResultDone.set() - resultRef.append(weakref.ref(result)) - - # Here's our function - def worker(arg, test): - return Dumb() - - # weakref needs an object subclass - class Dumb(object): - pass - - # And here's the unique object - unique = Dumb() - - onResultRef = weakref.ref(onResult) - workerRef = weakref.ref(worker) - uniqueRef = weakref.ref(unique) - - # Put some work in - tp.callInThreadWithCallback(onResult, worker, unique, test=unique) - - del worker - del unique - gc.collect() - - # let onResult collect the refs - onResultWait.set() - # wait for onResult - onResultDone.wait(self.getTimeout()) - - self.assertEqual(uniqueRef(), None) - self.assertEqual(workerRef(), None) - - # XXX There's a race right here - has onResult in the worker thread - # returned and the locals in _worker holding it and the result been - # deleted yet? - - del onResult - gc.collect() - self.assertEqual(onResultRef(), None) - self.assertEqual(resultRef[0](), None) - - - def test_persistence(self): - """ - Threadpools can be pickled and unpickled, which should preserve the - number of threads and other parameters. - """ - pool = threadpool.ThreadPool(7, 20) - - self.assertEqual(pool.min, 7) - self.assertEqual(pool.max, 20) - - # check that unpickled threadpool has same number of threads - copy = pickle.loads(pickle.dumps(pool)) - - self.assertEqual(copy.min, 7) - self.assertEqual(copy.max, 20) - - - def _threadpoolTest(self, method): - """ - Test synchronization of calls made with C{method}, which should be - one of the mechanisms of the threadpool to execute work in threads. - """ - # This is a schizophrenic test: it seems to be trying to test - # both the callInThread()/dispatch() behavior of the ThreadPool as well - # as the serialization behavior of threadable.synchronize(). It - # would probably make more sense as two much simpler tests. - N = 10 - - tp = threadpool.ThreadPool() - tp.start() - self.addCleanup(tp.stop) - - waiting = threading.Lock() - waiting.acquire() - actor = Synchronization(N, waiting) - - for i in range(N): - method(tp, actor) - - self._waitForLock(waiting) - - self.failIf(actor.failures, "run() re-entered %d times" % - (actor.failures,)) - - - def test_callInThread(self): - """ - Call C{_threadpoolTest} with C{callInThread}. - """ - return self._threadpoolTest( - lambda tp, actor: tp.callInThread(actor.run)) - - - def test_callInThreadException(self): - """ - L{ThreadPool.callInThread} logs exceptions raised by the callable it - is passed. - """ - class NewError(Exception): - pass - - def raiseError(): - raise NewError() - - tp = threadpool.ThreadPool(0, 1) - tp.callInThread(raiseError) - tp.start() - tp.stop() - - errors = self.flushLoggedErrors(NewError) - self.assertEqual(len(errors), 1) - - - def test_callInThreadWithCallback(self): - """ - L{ThreadPool.callInThreadWithCallback} calls C{onResult} with a - two-tuple of C{(True, result)} where C{result} is the value returned - by the callable supplied. - """ - waiter = threading.Lock() - waiter.acquire() - - results = [] - - def onResult(success, result): - waiter.release() - results.append(success) - results.append(result) - - tp = threadpool.ThreadPool(0, 1) - tp.callInThreadWithCallback(onResult, lambda: "test") - tp.start() - - try: - self._waitForLock(waiter) - finally: - tp.stop() - - self.assertTrue(results[0]) - self.assertEqual(results[1], "test") - - - def test_callInThreadWithCallbackExceptionInCallback(self): - """ - L{ThreadPool.callInThreadWithCallback} calls C{onResult} with a - two-tuple of C{(False, failure)} where C{failure} represents the - exception raised by the callable supplied. - """ - class NewError(Exception): - pass - - def raiseError(): - raise NewError() - - waiter = threading.Lock() - waiter.acquire() - - results = [] - - def onResult(success, result): - waiter.release() - results.append(success) - results.append(result) - - tp = threadpool.ThreadPool(0, 1) - tp.callInThreadWithCallback(onResult, raiseError) - tp.start() - - try: - self._waitForLock(waiter) - finally: - tp.stop() - - self.assertFalse(results[0]) - self.assertTrue(isinstance(results[1], failure.Failure)) - self.assertTrue(issubclass(results[1].type, NewError)) - - - def test_callInThreadWithCallbackExceptionInOnResult(self): - """ - L{ThreadPool.callInThreadWithCallback} logs the exception raised by - C{onResult}. - """ - class NewError(Exception): - pass - - waiter = threading.Lock() - waiter.acquire() - - results = [] - - def onResult(success, result): - results.append(success) - results.append(result) - raise NewError() - - tp = threadpool.ThreadPool(0, 1) - tp.callInThreadWithCallback(onResult, lambda : None) - tp.callInThread(waiter.release) - tp.start() - - try: - self._waitForLock(waiter) - finally: - tp.stop() - - errors = self.flushLoggedErrors(NewError) - self.assertEqual(len(errors), 1) - - self.assertTrue(results[0]) - self.assertEqual(results[1], None) - - - def test_callbackThread(self): - """ - L{ThreadPool.callInThreadWithCallback} calls the function it is - given and the C{onResult} callback in the same thread. - """ - threadIds = [] - - event = threading.Event() - - def onResult(success, result): - threadIds.append(threading.currentThread().ident) - event.set() - - def func(): - threadIds.append(threading.currentThread().ident) - - tp = threadpool.ThreadPool(0, 1) - tp.callInThreadWithCallback(onResult, func) - tp.start() - self.addCleanup(tp.stop) - - event.wait(self.getTimeout()) - self.assertEqual(len(threadIds), 2) - self.assertEqual(threadIds[0], threadIds[1]) - - - def test_callbackContext(self): - """ - The context L{ThreadPool.callInThreadWithCallback} is invoked in is - shared by the context the callable and C{onResult} callback are - invoked in. - """ - myctx = context.theContextTracker.currentContext().contexts[-1] - myctx['testing'] = 'this must be present' - - contexts = [] - - event = threading.Event() - - def onResult(success, result): - ctx = context.theContextTracker.currentContext().contexts[-1] - contexts.append(ctx) - event.set() - - def func(): - ctx = context.theContextTracker.currentContext().contexts[-1] - contexts.append(ctx) - - tp = threadpool.ThreadPool(0, 1) - tp.callInThreadWithCallback(onResult, func) - tp.start() - self.addCleanup(tp.stop) - - event.wait(self.getTimeout()) - - self.assertEqual(len(contexts), 2) - self.assertEqual(myctx, contexts[0]) - self.assertEqual(myctx, contexts[1]) - - - def test_existingWork(self): - """ - Work added to the threadpool before its start should be executed once - the threadpool is started: this is ensured by trying to release a lock - previously acquired. - """ - waiter = threading.Lock() - waiter.acquire() - - tp = threadpool.ThreadPool(0, 1) - tp.callInThread(waiter.release) # before start() - tp.start() - - try: - self._waitForLock(waiter) - finally: - tp.stop() - - - def test_workerStateTransition(self): - """ - As the worker receives and completes work, it transitions between - the working and waiting states. - """ - pool = threadpool.ThreadPool(0, 1) - pool.start() - self.addCleanup(pool.stop) - - # sanity check - self.assertEqual(pool.workers, 0) - self.assertEqual(len(pool.waiters), 0) - self.assertEqual(len(pool.working), 0) - - # fire up a worker and give it some 'work' - threadWorking = threading.Event() - threadFinish = threading.Event() - - def _thread(): - threadWorking.set() - threadFinish.wait() - - pool.callInThread(_thread) - threadWorking.wait() - self.assertEqual(pool.workers, 1) - self.assertEqual(len(pool.waiters), 0) - self.assertEqual(len(pool.working), 1) - - # finish work, and spin until state changes - threadFinish.set() - while not len(pool.waiters): - time.sleep(0.0005) - - # make sure state changed correctly - self.assertEqual(len(pool.waiters), 1) - self.assertEqual(len(pool.working), 0) - - - def test_workerState(self): - """ - Upon entering a _workerState block, the threads unique identifier is - added to a stateList and is removed upon exiting the block. - """ - pool = threadpool.ThreadPool() - workerThread = object() - stateList = [] - with pool._workerState(stateList, workerThread): - self.assertIn(workerThread, stateList) - self.assertNotIn(workerThread, stateList) - - - def test_workerStateExceptionHandling(self): - """ - The _workerState block does not consume L{Exception}s or change the - L{Exception} that gets raised. - """ - pool = threadpool.ThreadPool() - workerThread = object() - stateList = [] - try: - with pool._workerState(stateList, workerThread): - self.assertIn(workerThread, stateList) - 1 / 0 - except ZeroDivisionError: - pass - except: - self.fail("_workerState shouldn't change raised exceptions") - else: - self.fail("_workerState shouldn't consume exceptions") - self.assertNotIn(workerThread, stateList) - - - -class RaceConditionTests(unittest.SynchronousTestCase): - - def getTimeout(self): - """ - Return number of seconds to wait before giving up. - """ - return 5 # Really should be order of magnitude less - - - def setUp(self): - self.event = threading.Event() - self.threadpool = threadpool.ThreadPool(0, 10) - self.threadpool.start() - - - def tearDown(self): - del self.event - self.threadpool.stop() - del self.threadpool - - - def test_synchronization(self): - """ - Test a race condition: ensure that actions run in the pool synchronize - with actions run in the main thread. - """ - timeout = self.getTimeout() - self.threadpool.callInThread(self.event.set) - self.event.wait(timeout) - self.event.clear() - for i in range(3): - self.threadpool.callInThread(self.event.wait) - self.threadpool.callInThread(self.event.set) - self.event.wait(timeout) - if not self.event.isSet(): - self.event.set() - self.fail("Actions not synchronized") - - - def test_singleThread(self): - """ - The submission of a new job to a thread pool in response to the - C{onResult} callback does not cause a new thread to be added to the - thread pool. - - This requires that the thread which calls C{onResult} to have first - marked itself as available so that when the new job is queued, that - thread may be considered to run it. This is desirable so that when - only N jobs are ever being executed in the thread pool at once only - N threads will ever be created. - """ - # Ensure no threads running - self.assertEqual(self.threadpool.workers, 0) - - event = threading.Event() - event.clear() - - def onResult(success, counter): - event.set() - - for i in range(10): - self.threadpool.callInThreadWithCallback( - onResult, lambda: None) - event.wait() - event.clear() - - self.assertEqual(self.threadpool.workers, 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threads.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threads.py deleted file mode 100644 index 89accc7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_threads.py +++ /dev/null @@ -1,421 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test methods in twisted.internet.threads and reactor thread APIs. -""" - -from __future__ import division, absolute_import - -import sys, os, time - -from twisted.trial import unittest - -from twisted.python.compat import _PY3 -from twisted.internet import reactor, defer, interfaces, threads, protocol, error -from twisted.python import failure, threadable, log, threadpool - -if _PY3: - xrange = range - - -class ReactorThreadsTests(unittest.TestCase): - """ - Tests for the reactor threading API. - """ - - def test_suggestThreadPoolSize(self): - """ - Try to change maximum number of threads. - """ - reactor.suggestThreadPoolSize(34) - self.assertEqual(reactor.threadpool.max, 34) - reactor.suggestThreadPoolSize(4) - self.assertEqual(reactor.threadpool.max, 4) - - - def _waitForThread(self): - """ - The reactor's threadpool is only available when the reactor is running, - so to have a sane behavior during the tests we make a dummy - L{threads.deferToThread} call. - """ - return threads.deferToThread(time.sleep, 0) - - - def test_callInThread(self): - """ - Test callInThread functionality: set a C{threading.Event}, and check - that it's not in the main thread. - """ - def cb(ign): - waiter = threading.Event() - result = [] - def threadedFunc(): - result.append(threadable.isInIOThread()) - waiter.set() - - reactor.callInThread(threadedFunc) - waiter.wait(120) - if not waiter.isSet(): - self.fail("Timed out waiting for event.") - else: - self.assertEqual(result, [False]) - return self._waitForThread().addCallback(cb) - - - def test_callFromThread(self): - """ - Test callFromThread functionality: from the main thread, and from - another thread. - """ - def cb(ign): - firedByReactorThread = defer.Deferred() - firedByOtherThread = defer.Deferred() - - def threadedFunc(): - reactor.callFromThread(firedByOtherThread.callback, None) - - reactor.callInThread(threadedFunc) - reactor.callFromThread(firedByReactorThread.callback, None) - - return defer.DeferredList( - [firedByReactorThread, firedByOtherThread], - fireOnOneErrback=True) - return self._waitForThread().addCallback(cb) - - - def test_wakerOverflow(self): - """ - Try to make an overflow on the reactor waker using callFromThread. - """ - def cb(ign): - self.failure = None - waiter = threading.Event() - def threadedFunction(): - # Hopefully a hundred thousand queued calls is enough to - # trigger the error condition - for i in xrange(100000): - try: - reactor.callFromThread(lambda: None) - except: - self.failure = failure.Failure() - break - waiter.set() - reactor.callInThread(threadedFunction) - waiter.wait(120) - if not waiter.isSet(): - self.fail("Timed out waiting for event") - if self.failure is not None: - return defer.fail(self.failure) - return self._waitForThread().addCallback(cb) - - def _testBlockingCallFromThread(self, reactorFunc): - """ - Utility method to test L{threads.blockingCallFromThread}. - """ - waiter = threading.Event() - results = [] - errors = [] - def cb1(ign): - def threadedFunc(): - try: - r = threads.blockingCallFromThread(reactor, reactorFunc) - except Exception as e: - errors.append(e) - else: - results.append(r) - waiter.set() - - reactor.callInThread(threadedFunc) - return threads.deferToThread(waiter.wait, self.getTimeout()) - - def cb2(ign): - if not waiter.isSet(): - self.fail("Timed out waiting for event") - return results, errors - - return self._waitForThread().addCallback(cb1).addBoth(cb2) - - def test_blockingCallFromThread(self): - """ - Test blockingCallFromThread facility: create a thread, call a function - in the reactor using L{threads.blockingCallFromThread}, and verify the - result returned. - """ - def reactorFunc(): - return defer.succeed("foo") - def cb(res): - self.assertEqual(res[0][0], "foo") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - def test_asyncBlockingCallFromThread(self): - """ - Test blockingCallFromThread as above, but be sure the resulting - Deferred is not already fired. - """ - def reactorFunc(): - d = defer.Deferred() - reactor.callLater(0.1, d.callback, "egg") - return d - def cb(res): - self.assertEqual(res[0][0], "egg") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - def test_errorBlockingCallFromThread(self): - """ - Test error report for blockingCallFromThread. - """ - def reactorFunc(): - return defer.fail(RuntimeError("bar")) - def cb(res): - self.assert_(isinstance(res[1][0], RuntimeError)) - self.assertEqual(res[1][0].args[0], "bar") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - def test_asyncErrorBlockingCallFromThread(self): - """ - Test error report for blockingCallFromThread as above, but be sure the - resulting Deferred is not already fired. - """ - def reactorFunc(): - d = defer.Deferred() - reactor.callLater(0.1, d.errback, RuntimeError("spam")) - return d - def cb(res): - self.assert_(isinstance(res[1][0], RuntimeError)) - self.assertEqual(res[1][0].args[0], "spam") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - -class Counter: - index = 0 - problem = 0 - - def add(self): - """A non thread-safe method.""" - next = self.index + 1 - # another thread could jump in here and increment self.index on us - if next != self.index + 1: - self.problem = 1 - raise ValueError - # or here, same issue but we wouldn't catch it. We'd overwrite - # their results, and the index will have lost a count. If - # several threads get in here, we will actually make the count - # go backwards when we overwrite it. - self.index = next - - - -class DeferredResultTests(unittest.TestCase): - """ - Test twisted.internet.threads. - """ - - def setUp(self): - reactor.suggestThreadPoolSize(8) - - - def tearDown(self): - reactor.suggestThreadPoolSize(0) - - - def test_callMultiple(self): - """ - L{threads.callMultipleInThread} calls multiple functions in a thread. - """ - L = [] - N = 10 - d = defer.Deferred() - - def finished(): - self.assertEqual(L, list(range(N))) - d.callback(None) - - threads.callMultipleInThread([ - (L.append, (i,), {}) for i in xrange(N) - ] + [(reactor.callFromThread, (finished,), {})]) - return d - - - def test_deferredResult(self): - """ - L{threads.deferToThread} executes the function passed, and correctly - handles the positional and keyword arguments given. - """ - d = threads.deferToThread(lambda x, y=5: x + y, 3, y=4) - d.addCallback(self.assertEqual, 7) - return d - - - def test_deferredFailure(self): - """ - Check that L{threads.deferToThread} return a failure object - with an appropriate exception instance when the called - function raises an exception. - """ - class NewError(Exception): - pass - def raiseError(): - raise NewError() - d = threads.deferToThread(raiseError) - return self.assertFailure(d, NewError) - - - def test_deferredFailureAfterSuccess(self): - """ - Check that a successfull L{threads.deferToThread} followed by a one - that raises an exception correctly result as a failure. - """ - # set up a condition that causes cReactor to hang. These conditions - # can also be set by other tests when the full test suite is run in - # alphabetical order (test_flow.FlowTest.testThreaded followed by - # test_internet.ReactorCoreTestCase.testStop, to be precise). By - # setting them up explicitly here, we can reproduce the hang in a - # single precise test case instead of depending upon side effects of - # other tests. - # - # alas, this test appears to flunk the default reactor too - - d = threads.deferToThread(lambda: None) - d.addCallback(lambda ign: threads.deferToThread(lambda: 1//0)) - return self.assertFailure(d, ZeroDivisionError) - - - -class DeferToThreadPoolTests(unittest.TestCase): - """ - Test L{twisted.internet.threads.deferToThreadPool}. - """ - - def setUp(self): - self.tp = threadpool.ThreadPool(0, 8) - self.tp.start() - - - def tearDown(self): - self.tp.stop() - - - def test_deferredResult(self): - """ - L{threads.deferToThreadPool} executes the function passed, and - correctly handles the positional and keyword arguments given. - """ - d = threads.deferToThreadPool(reactor, self.tp, - lambda x, y=5: x + y, 3, y=4) - d.addCallback(self.assertEqual, 7) - return d - - - def test_deferredFailure(self): - """ - Check that L{threads.deferToThreadPool} return a failure object with an - appropriate exception instance when the called function raises an - exception. - """ - class NewError(Exception): - pass - def raiseError(): - raise NewError() - d = threads.deferToThreadPool(reactor, self.tp, raiseError) - return self.assertFailure(d, NewError) - - - -_callBeforeStartupProgram = """ -import time -import %(reactor)s -%(reactor)s.install() - -from twisted.internet import reactor - -def threadedCall(): - print('threaded call') - -reactor.callInThread(threadedCall) - -# Spin very briefly to try to give the thread a chance to run, if it -# is going to. Is there a better way to achieve this behavior? -for i in range(100): - time.sleep(0.0) -""" - - -class ThreadStartupProcessProtocol(protocol.ProcessProtocol): - def __init__(self, finished): - self.finished = finished - self.out = [] - self.err = [] - - def outReceived(self, out): - self.out.append(out) - - def errReceived(self, err): - self.err.append(err) - - def processEnded(self, reason): - self.finished.callback((self.out, self.err, reason)) - - - -class StartupBehaviorTests(unittest.TestCase): - """ - Test cases for the behavior of the reactor threadpool near startup - boundary conditions. - - In particular, this asserts that no threaded calls are attempted - until the reactor starts up, that calls attempted before it starts - are in fact executed once it has started, and that in both cases, - the reactor properly cleans itself up (which is tested for - somewhat implicitly, by requiring a child process be able to exit, - something it cannot do unless the threadpool has been properly - torn down). - """ - - - def testCallBeforeStartupUnexecuted(self): - progname = self.mktemp() - progfile = open(progname, 'w') - progfile.write(_callBeforeStartupProgram % {'reactor': reactor.__module__}) - progfile.close() - - def programFinished(result): - (out, err, reason) = result - if reason.check(error.ProcessTerminated): - self.fail("Process did not exit cleanly (out: %s err: %s)" % (out, err)) - - if err: - log.msg("Unexpected output on standard error: %s" % (err,)) - self.failIf(out, "Expected no output, instead received:\n%s" % (out,)) - - def programTimeout(err): - err.trap(error.TimeoutError) - proto.signalProcess('KILL') - return err - - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - d = defer.Deferred().addCallbacks(programFinished, programTimeout) - proto = ThreadStartupProcessProtocol(d) - reactor.spawnProcess(proto, sys.executable, ('python', progname), env) - return d - - - -if interfaces.IReactorThreads(reactor, None) is None: - for cls in (ReactorThreadsTests, - DeferredResultTests, - StartupBehaviorTests): - cls.skip = "No thread support, nothing to test here." -else: - import threading - -if interfaces.IReactorProcess(reactor, None) is None: - for cls in (StartupBehaviorTests,): - cls.skip = "No process support, cannot run subprocess thread tests." diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tpfile.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tpfile.py deleted file mode 100644 index bba107e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_tpfile.py +++ /dev/null @@ -1,52 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.protocols import loopback -from twisted.protocols import basic -from twisted.internet import protocol, abstract - -import StringIO - -class BufferingServer(protocol.Protocol): - buffer = '' - def dataReceived(self, data): - self.buffer += data - -class FileSendingClient(protocol.Protocol): - def __init__(self, f): - self.f = f - - def connectionMade(self): - s = basic.FileSender() - d = s.beginFileTransfer(self.f, self.transport, lambda x: x) - d.addCallback(lambda r: self.transport.loseConnection()) - -class FileSenderTests(unittest.TestCase): - def testSendingFile(self): - testStr = 'xyz' * 100 + 'abc' * 100 + '123' * 100 - s = BufferingServer() - c = FileSendingClient(StringIO.StringIO(testStr)) - - d = loopback.loopbackTCP(s, c) - d.addCallback(lambda x : self.assertEqual(s.buffer, testStr)) - return d - - def testSendingEmptyFile(self): - fileSender = basic.FileSender() - consumer = abstract.FileDescriptor() - consumer.connected = 1 - emptyFile = StringIO.StringIO('') - - d = fileSender.beginFileTransfer(emptyFile, consumer, lambda x: x) - - # The producer will be immediately exhausted, and so immediately - # unregistered - self.assertEqual(consumer.producer, None) - - # Which means the Deferred from FileSender should have been called - self.failUnless(d.called, - 'producer unregistered with deferred being called') - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_twistd.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_twistd.py deleted file mode 100644 index 9253e88..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_twistd.py +++ /dev/null @@ -1,1746 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.application.app} and L{twisted.scripts.twistd}. -""" - -import errno -import inspect -import signal -import os -import sys -import StringIO - -try: - import pwd - import grp -except ImportError: - pwd = grp = None - -try: - import cPickle as pickle -except ImportError: - import pickle - -from zope.interface import implements -from zope.interface.verify import verifyObject - -from twisted.trial import unittest -from twisted.test.test_process import MockOS - -from twisted import plugin -from twisted.application.service import IServiceMaker -from twisted.application import service, app, reactors -from twisted.scripts import twistd -from twisted.python import log -from twisted.python.usage import UsageError -from twisted.python.log import ILogObserver -from twisted.python.components import Componentized -from twisted.internet.defer import Deferred -from twisted.internet.interfaces import IReactorDaemonize -from twisted.internet.test.modulehelpers import AlternateReactor -from twisted.python.fakepwd import UserDatabase -try: - from twisted.scripts import _twistd_unix -except ImportError: - _twistd_unix = None -else: - from twisted.scripts._twistd_unix import UnixApplicationRunner - from twisted.scripts._twistd_unix import UnixAppLogger - - -try: - from twisted.python import syslog -except ImportError: - syslog = None - - -try: - import profile -except ImportError: - profile = None - -try: - import hotshot - import hotshot.stats -except (ImportError, SystemExit): - # For some reasons, hotshot.stats seems to raise SystemExit on some - # distributions, probably when considered non-free. See the import of - # this module in twisted.application.app for more details. - hotshot = None - -try: - import pstats - import cProfile -except ImportError: - cProfile = None - -if getattr(os, 'setuid', None) is None: - setuidSkip = "Platform does not support --uid/--gid twistd options." -else: - setuidSkip = None - - - -def patchUserDatabase(patch, user, uid, group, gid): - """ - Patch L{pwd.getpwnam} so that it behaves as though only one user exists - and patch L{grp.getgrnam} so that it behaves as though only one group - exists. - - @param patch: A function like L{TestCase.patch} which will be used to - install the fake implementations. - - @type user: C{str} - @param user: The name of the single user which will exist. - - @type uid: C{int} - @param uid: The UID of the single user which will exist. - - @type group: C{str} - @param group: The name of the single user which will exist. - - @type gid: C{int} - @param gid: The GID of the single group which will exist. - """ - # Try not to be an unverified fake, but try not to depend on quirks of - # the system either (eg, run as a process with a uid and gid which - # equal each other, and so doesn't reliably test that uid is used where - # uid should be used and gid is used where gid should be used). -exarkun - pwent = pwd.getpwuid(os.getuid()) - grent = grp.getgrgid(os.getgid()) - - database = UserDatabase() - database.addUser( - user, pwent.pw_passwd, uid, pwent.pw_gid, - pwent.pw_gecos, pwent.pw_dir, pwent.pw_shell) - - def getgrnam(name): - result = list(grent) - result[result.index(grent.gr_name)] = group - result[result.index(grent.gr_gid)] = gid - result = tuple(result) - return {group: result}[name] - - patch(pwd, "getpwnam", database.getpwnam) - patch(grp, "getgrnam", getgrnam) - - - -class MockServiceMaker(object): - """ - A non-implementation of L{twisted.application.service.IServiceMaker}. - """ - tapname = 'ueoa' - - def makeService(self, options): - """ - Take a L{usage.Options} instance and return a - L{service.IService} provider. - """ - self.options = options - self.service = service.Service() - return self.service - - - -class CrippledAppLogger(app.AppLogger): - """ - @see: CrippledApplicationRunner. - """ - - def start(self, application): - pass - - - -class CrippledApplicationRunner(twistd._SomeApplicationRunner): - """ - An application runner that cripples the platform-specific runner and - nasty side-effect-having code so that we can use it without actually - running any environment-affecting code. - """ - loggerFactory = CrippledAppLogger - - def preApplication(self): - pass - - - def postApplication(self): - pass - - - -class ServerOptionsTests(unittest.TestCase): - """ - Non-platform-specific tests for the pltaform-specific ServerOptions class. - """ - def test_subCommands(self): - """ - subCommands is built from IServiceMaker plugins, and is sorted - alphabetically. - """ - class FakePlugin(object): - def __init__(self, name): - self.tapname = name - self._options = 'options for ' + name - self.description = 'description of ' + name - - def options(self): - return self._options - - apple = FakePlugin('apple') - banana = FakePlugin('banana') - coconut = FakePlugin('coconut') - donut = FakePlugin('donut') - - def getPlugins(interface): - self.assertEqual(interface, IServiceMaker) - yield coconut - yield banana - yield donut - yield apple - - config = twistd.ServerOptions() - self.assertEqual(config._getPlugins, plugin.getPlugins) - config._getPlugins = getPlugins - - # "subCommands is a list of 4-tuples of (command name, command - # shortcut, parser class, documentation)." - subCommands = config.subCommands - expectedOrder = [apple, banana, coconut, donut] - - for subCommand, expectedCommand in zip(subCommands, expectedOrder): - name, shortcut, parserClass, documentation = subCommand - self.assertEqual(name, expectedCommand.tapname) - self.assertEqual(shortcut, None) - self.assertEqual(parserClass(), expectedCommand._options), - self.assertEqual(documentation, expectedCommand.description) - - - def test_sortedReactorHelp(self): - """ - Reactor names are listed alphabetically by I{--help-reactors}. - """ - class FakeReactorInstaller(object): - def __init__(self, name): - self.shortName = 'name of ' + name - self.description = 'description of ' + name - - apple = FakeReactorInstaller('apple') - banana = FakeReactorInstaller('banana') - coconut = FakeReactorInstaller('coconut') - donut = FakeReactorInstaller('donut') - - def getReactorTypes(): - yield coconut - yield banana - yield donut - yield apple - - config = twistd.ServerOptions() - self.assertEqual(config._getReactorTypes, reactors.getReactorTypes) - config._getReactorTypes = getReactorTypes - config.messageOutput = StringIO.StringIO() - - self.assertRaises(SystemExit, config.parseOptions, ['--help-reactors']) - helpOutput = config.messageOutput.getvalue() - indexes = [] - for reactor in apple, banana, coconut, donut: - def getIndex(s): - self.assertIn(s, helpOutput) - indexes.append(helpOutput.index(s)) - - getIndex(reactor.shortName) - getIndex(reactor.description) - - self.assertEqual( - indexes, sorted(indexes), - 'reactor descriptions were not in alphabetical order: %r' % ( - helpOutput,)) - - - def test_postOptionsSubCommandCausesNoSave(self): - """ - postOptions should set no_save to True when a subcommand is used. - """ - config = twistd.ServerOptions() - config.subCommand = 'ueoa' - config.postOptions() - self.assertEqual(config['no_save'], True) - - - def test_postOptionsNoSubCommandSavesAsUsual(self): - """ - If no sub command is used, postOptions should not touch no_save. - """ - config = twistd.ServerOptions() - config.postOptions() - self.assertEqual(config['no_save'], False) - - - def test_listAllProfilers(self): - """ - All the profilers that can be used in L{app.AppProfiler} are listed in - the help output. - """ - config = twistd.ServerOptions() - helpOutput = str(config) - for profiler in app.AppProfiler.profilers: - self.assertIn(profiler, helpOutput) - - - def test_defaultUmask(self): - """ - The default value for the C{umask} option is C{None}. - """ - config = twistd.ServerOptions() - self.assertEqual(config['umask'], None) - - - def test_umask(self): - """ - The value given for the C{umask} option is parsed as an octal integer - literal. - """ - config = twistd.ServerOptions() - config.parseOptions(['--umask', '123']) - self.assertEqual(config['umask'], 83) - config.parseOptions(['--umask', '0123']) - self.assertEqual(config['umask'], 83) - - - def test_invalidUmask(self): - """ - If a value is given for the C{umask} option which cannot be parsed as - an integer, L{UsageError} is raised by L{ServerOptions.parseOptions}. - """ - config = twistd.ServerOptions() - self.assertRaises(UsageError, config.parseOptions, - ['--umask', 'abcdef']) - - if _twistd_unix is None: - msg = "twistd unix not available" - test_defaultUmask.skip = test_umask.skip = test_invalidUmask.skip = msg - - - def test_unimportableConfiguredLogObserver(self): - """ - C{--logger} with an unimportable module raises a L{UsageError}. - """ - config = twistd.ServerOptions() - e = self.assertRaises( - UsageError, config.parseOptions, - ['--logger', 'no.such.module.I.hope']) - self.assertTrue( - e.args[0].startswith( - "Logger 'no.such.module.I.hope' could not be imported: " - "'no.such.module.I.hope' does not name an object")) - self.assertNotIn('\n', e.args[0]) - - - def test_badAttributeWithConfiguredLogObserver(self): - """ - C{--logger} with a non-existent object raises a L{UsageError}. - """ - config = twistd.ServerOptions() - e = self.assertRaises(UsageError, config.parseOptions, - ["--logger", "twisted.test.test_twistd.FOOBAR"]) - self.assertTrue( - e.args[0].startswith( - "Logger 'twisted.test.test_twistd.FOOBAR' could not be " - "imported: 'module' object has no attribute 'FOOBAR'")) - self.assertNotIn('\n', e.args[0]) - - - -class TapFileTests(unittest.TestCase): - """ - Test twistd-related functionality that requires a tap file on disk. - """ - - def setUp(self): - """ - Create a trivial Application and put it in a tap file on disk. - """ - self.tapfile = self.mktemp() - f = file(self.tapfile, 'wb') - pickle.dump(service.Application("Hi!"), f) - f.close() - - - def test_createOrGetApplicationWithTapFile(self): - """ - Ensure that the createOrGetApplication call that 'twistd -f foo.tap' - makes will load the Application out of foo.tap. - """ - config = twistd.ServerOptions() - config.parseOptions(['-f', self.tapfile]) - application = CrippledApplicationRunner( - config).createOrGetApplication() - self.assertEqual(service.IService(application).name, 'Hi!') - - - -class TestLoggerFactory(object): - """ - A logger factory for L{TestApplicationRunner}. - """ - - def __init__(self, runner): - self.runner = runner - - - def start(self, application): - """ - Save the logging start on the C{runner} instance. - """ - self.runner.order.append("log") - self.runner.hadApplicationLogObserver = hasattr(self.runner, - 'application') - - - def stop(self): - """ - Don't log anything. - """ - - - -class TestApplicationRunner(app.ApplicationRunner): - """ - An ApplicationRunner which tracks the environment in which its methods are - called. - """ - - def __init__(self, options): - app.ApplicationRunner.__init__(self, options) - self.order = [] - self.logger = TestLoggerFactory(self) - - - def preApplication(self): - self.order.append("pre") - self.hadApplicationPreApplication = hasattr(self, 'application') - - - def postApplication(self): - self.order.append("post") - self.hadApplicationPostApplication = hasattr(self, 'application') - - - -class ApplicationRunnerTests(unittest.TestCase): - """ - Non-platform-specific tests for the platform-specific ApplicationRunner. - """ - def setUp(self): - config = twistd.ServerOptions() - self.serviceMaker = MockServiceMaker() - # Set up a config object like it's been parsed with a subcommand - config.loadedPlugins = {'test_command': self.serviceMaker} - config.subOptions = object() - config.subCommand = 'test_command' - self.config = config - - - def test_applicationRunnerGetsCorrectApplication(self): - """ - Ensure that a twistd plugin gets used in appropriate ways: it - is passed its Options instance, and the service it returns is - added to the application. - """ - arunner = CrippledApplicationRunner(self.config) - arunner.run() - - self.assertIdentical( - self.serviceMaker.options, self.config.subOptions, - "ServiceMaker.makeService needs to be passed the correct " - "sub Command object.") - self.assertIdentical( - self.serviceMaker.service, - service.IService(arunner.application).services[0], - "ServiceMaker.makeService's result needs to be set as a child " - "of the Application.") - - - def test_preAndPostApplication(self): - """ - Test thet preApplication and postApplication methods are - called by ApplicationRunner.run() when appropriate. - """ - s = TestApplicationRunner(self.config) - s.run() - self.assertFalse(s.hadApplicationPreApplication) - self.assertTrue(s.hadApplicationPostApplication) - self.assertTrue(s.hadApplicationLogObserver) - self.assertEqual(s.order, ["pre", "log", "post"]) - - - def _applicationStartsWithConfiguredID(self, argv, uid, gid): - """ - Assert that given a particular command line, an application is started - as a particular UID/GID. - - @param argv: A list of strings giving the options to parse. - @param uid: An integer giving the expected UID. - @param gid: An integer giving the expected GID. - """ - self.config.parseOptions(argv) - - events = [] - - class FakeUnixApplicationRunner(twistd._SomeApplicationRunner): - def setupEnvironment(self, chroot, rundir, nodaemon, umask, - pidfile): - events.append('environment') - - def shedPrivileges(self, euid, uid, gid): - events.append(('privileges', euid, uid, gid)) - - def startReactor(self, reactor, oldstdout, oldstderr): - events.append('reactor') - - def removePID(self, pidfile): - pass - - - class FakeService(object): - implements(service.IService, service.IProcess) - - processName = None - uid = None - gid = None - - def setName(self, name): - pass - - def setServiceParent(self, parent): - pass - - def disownServiceParent(self): - pass - - def privilegedStartService(self): - events.append('privilegedStartService') - - def startService(self): - events.append('startService') - - def stopService(self): - pass - - application = FakeService() - verifyObject(service.IService, application) - verifyObject(service.IProcess, application) - - runner = FakeUnixApplicationRunner(self.config) - runner.preApplication() - runner.application = application - runner.postApplication() - - self.assertEqual( - events, - ['environment', 'privilegedStartService', - ('privileges', False, uid, gid), 'startService', 'reactor']) - - - def test_applicationStartsWithConfiguredNumericIDs(self): - """ - L{postApplication} should change the UID and GID to the values - specified as numeric strings by the configuration after running - L{service.IService.privilegedStartService} and before running - L{service.IService.startService}. - """ - uid = 1234 - gid = 4321 - self._applicationStartsWithConfiguredID( - ["--uid", str(uid), "--gid", str(gid)], uid, gid) - test_applicationStartsWithConfiguredNumericIDs.skip = setuidSkip - - - def test_applicationStartsWithConfiguredNameIDs(self): - """ - L{postApplication} should change the UID and GID to the values - specified as user and group names by the configuration after running - L{service.IService.privilegedStartService} and before running - L{service.IService.startService}. - """ - user = "foo" - uid = 1234 - group = "bar" - gid = 4321 - patchUserDatabase(self.patch, user, uid, group, gid) - self._applicationStartsWithConfiguredID( - ["--uid", user, "--gid", group], uid, gid) - test_applicationStartsWithConfiguredNameIDs.skip = setuidSkip - - - def test_startReactorRunsTheReactor(self): - """ - L{startReactor} calls L{reactor.run}. - """ - reactor = DummyReactor() - runner = app.ApplicationRunner({ - "profile": False, - "profiler": "profile", - "debug": False}) - runner.startReactor(reactor, None, None) - self.assertTrue( - reactor.called, "startReactor did not call reactor.run()") - - - -class UnixApplicationRunnerSetupEnvironmentTests(unittest.TestCase): - """ - Tests for L{UnixApplicationRunner.setupEnvironment}. - - @ivar root: The root of the filesystem, or C{unset} if none has been - specified with a call to L{os.chroot} (patched for this TestCase with - L{UnixApplicationRunnerSetupEnvironmentTests.chroot}). - - @ivar cwd: The current working directory of the process, or C{unset} if - none has been specified with a call to L{os.chdir} (patched for this - TestCase with L{UnixApplicationRunnerSetupEnvironmentTests.chdir}). - - @ivar mask: The current file creation mask of the process, or C{unset} if - none has been specified with a call to L{os.umask} (patched for this - TestCase with L{UnixApplicationRunnerSetupEnvironmentTests.umask}). - - @ivar daemon: A boolean indicating whether daemonization has been performed - by a call to L{_twistd_unix.daemonize} (patched for this TestCase with - L{UnixApplicationRunnerSetupEnvironmentTests}. - """ - if _twistd_unix is None: - skip = "twistd unix not available" - - unset = object() - - def setUp(self): - self.root = self.unset - self.cwd = self.unset - self.mask = self.unset - self.daemon = False - self.pid = os.getpid() - self.patch(os, 'chroot', lambda path: setattr(self, 'root', path)) - self.patch(os, 'chdir', lambda path: setattr(self, 'cwd', path)) - self.patch(os, 'umask', lambda mask: setattr(self, 'mask', mask)) - self.runner = UnixApplicationRunner(twistd.ServerOptions()) - self.runner.daemonize = self.daemonize - - - def daemonize(self, reactor): - """ - Indicate that daemonization has happened and change the PID so that the - value written to the pidfile can be tested in the daemonization case. - """ - self.daemon = True - self.patch(os, 'getpid', lambda: self.pid + 1) - - - def test_chroot(self): - """ - L{UnixApplicationRunner.setupEnvironment} changes the root of the - filesystem if passed a non-C{None} value for the C{chroot} parameter. - """ - self.runner.setupEnvironment("/foo/bar", ".", True, None, None) - self.assertEqual(self.root, "/foo/bar") - - - def test_noChroot(self): - """ - L{UnixApplicationRunner.setupEnvironment} does not change the root of - the filesystem if passed C{None} for the C{chroot} parameter. - """ - self.runner.setupEnvironment(None, ".", True, None, None) - self.assertIdentical(self.root, self.unset) - - - def test_changeWorkingDirectory(self): - """ - L{UnixApplicationRunner.setupEnvironment} changes the working directory - of the process to the path given for the C{rundir} parameter. - """ - self.runner.setupEnvironment(None, "/foo/bar", True, None, None) - self.assertEqual(self.cwd, "/foo/bar") - - - def test_daemonize(self): - """ - L{UnixApplicationRunner.setupEnvironment} daemonizes the process if - C{False} is passed for the C{nodaemon} parameter. - """ - with AlternateReactor(FakeDaemonizingReactor()): - self.runner.setupEnvironment(None, ".", False, None, None) - self.assertTrue(self.daemon) - - - def test_noDaemonize(self): - """ - L{UnixApplicationRunner.setupEnvironment} does not daemonize the - process if C{True} is passed for the C{nodaemon} parameter. - """ - self.runner.setupEnvironment(None, ".", True, None, None) - self.assertFalse(self.daemon) - - - def test_nonDaemonPIDFile(self): - """ - L{UnixApplicationRunner.setupEnvironment} writes the process's PID to - the file specified by the C{pidfile} parameter. - """ - pidfile = self.mktemp() - self.runner.setupEnvironment(None, ".", True, None, pidfile) - fObj = file(pidfile) - pid = int(fObj.read()) - fObj.close() - self.assertEqual(pid, self.pid) - - - def test_daemonPIDFile(self): - """ - L{UnixApplicationRunner.setupEnvironment} writes the daemonized - process's PID to the file specified by the C{pidfile} parameter if - C{nodaemon} is C{False}. - """ - pidfile = self.mktemp() - with AlternateReactor(FakeDaemonizingReactor()): - self.runner.setupEnvironment(None, ".", False, None, pidfile) - fObj = file(pidfile) - pid = int(fObj.read()) - fObj.close() - self.assertEqual(pid, self.pid + 1) - - - def test_umask(self): - """ - L{UnixApplicationRunner.setupEnvironment} changes the process umask to - the value specified by the C{umask} parameter. - """ - with AlternateReactor(FakeDaemonizingReactor()): - self.runner.setupEnvironment(None, ".", False, 123, None) - self.assertEqual(self.mask, 123) - - - def test_noDaemonizeNoUmask(self): - """ - L{UnixApplicationRunner.setupEnvironment} doesn't change the process - umask if C{None} is passed for the C{umask} parameter and C{True} is - passed for the C{nodaemon} parameter. - """ - self.runner.setupEnvironment(None, ".", True, None, None) - self.assertIdentical(self.mask, self.unset) - - - def test_daemonizedNoUmask(self): - """ - L{UnixApplicationRunner.setupEnvironment} changes the process umask to - C{0077} if C{None} is passed for the C{umask} parameter and C{False} is - passed for the C{nodaemon} parameter. - """ - with AlternateReactor(FakeDaemonizingReactor()): - self.runner.setupEnvironment(None, ".", False, None, None) - self.assertEqual(self.mask, 0077) - - - -class UnixApplicationRunnerStartApplicationTests(unittest.TestCase): - """ - Tests for L{UnixApplicationRunner.startApplication}. - """ - if _twistd_unix is None: - skip = "twistd unix not available" - - - def test_setupEnvironment(self): - """ - L{UnixApplicationRunner.startApplication} calls - L{UnixApplicationRunner.setupEnvironment} with the chroot, rundir, - nodaemon, umask, and pidfile parameters from the configuration it is - constructed with. - """ - options = twistd.ServerOptions() - options.parseOptions([ - '--nodaemon', - '--umask', '0070', - '--chroot', '/foo/chroot', - '--rundir', '/foo/rundir', - '--pidfile', '/foo/pidfile']) - application = service.Application("test_setupEnvironment") - self.runner = UnixApplicationRunner(options) - - args = [] - def fakeSetupEnvironment(self, chroot, rundir, nodaemon, umask, - pidfile): - args.extend((chroot, rundir, nodaemon, umask, pidfile)) - - # Sanity check - self.assertEqual( - inspect.getargspec(self.runner.setupEnvironment), - inspect.getargspec(fakeSetupEnvironment)) - - self.patch(UnixApplicationRunner, 'setupEnvironment', - fakeSetupEnvironment) - self.patch(UnixApplicationRunner, 'shedPrivileges', - lambda *a, **kw: None) - self.patch(app, 'startApplication', lambda *a, **kw: None) - self.runner.startApplication(application) - - self.assertEqual( - args, - ['/foo/chroot', '/foo/rundir', True, 56, '/foo/pidfile']) - - - -class UnixApplicationRunnerRemovePIDTests(unittest.TestCase): - """ - Tests for L{UnixApplicationRunner.removePID}. - """ - if _twistd_unix is None: - skip = "twistd unix not available" - - - def test_removePID(self): - """ - L{UnixApplicationRunner.removePID} deletes the file the name of - which is passed to it. - """ - runner = UnixApplicationRunner({}) - path = self.mktemp() - os.makedirs(path) - pidfile = os.path.join(path, "foo.pid") - file(pidfile, "w").close() - runner.removePID(pidfile) - self.assertFalse(os.path.exists(pidfile)) - - - def test_removePIDErrors(self): - """ - Calling L{UnixApplicationRunner.removePID} with a non-existent filename - logs an OSError. - """ - runner = UnixApplicationRunner({}) - runner.removePID("fakepid") - errors = self.flushLoggedErrors(OSError) - self.assertEqual(len(errors), 1) - self.assertEqual(errors[0].value.errno, errno.ENOENT) - - - -class FakeNonDaemonizingReactor(object): - """ - A dummy reactor, providing C{beforeDaemonize} and C{afterDaemonize} - methods, but not announcing this, and logging whether the methods have been - called. - - @ivar _beforeDaemonizeCalled: if C{beforeDaemonize} has been called or not. - @type _beforeDaemonizeCalled: C{bool} - @ivar _afterDaemonizeCalled: if C{afterDaemonize} has been called or not. - @type _afterDaemonizeCalled: C{bool} - """ - - def __init__(self): - self._beforeDaemonizeCalled = False - self._afterDaemonizeCalled = False - - - def beforeDaemonize(self): - self._beforeDaemonizeCalled = True - - - def afterDaemonize(self): - self._afterDaemonizeCalled = True - - - def addSystemEventTrigger(self, *args, **kw): - """ - Skip event registration. - """ - - - -class FakeDaemonizingReactor(FakeNonDaemonizingReactor): - """ - A dummy reactor, providing C{beforeDaemonize} and C{afterDaemonize} - methods, announcing this, and logging whether the methods have been called. - """ - implements(IReactorDaemonize) - - - -class DummyReactor(object): - """ - A dummy reactor, only providing a C{run} method and checking that it - has been called. - - @ivar called: if C{run} has been called or not. - @type called: C{bool} - """ - called = False - - def run(self): - """ - A fake run method, checking that it's been called one and only time. - """ - if self.called: - raise RuntimeError("Already called") - self.called = True - - - -class AppProfilingTests(unittest.TestCase): - """ - Tests for L{app.AppProfiler}. - """ - - def test_profile(self): - """ - L{app.ProfileRunner.run} should call the C{run} method of the reactor - and save profile data in the specified file. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "profile" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("DummyReactor.run", data) - self.assertIn("function calls", data) - - if profile is None: - test_profile.skip = "profile module not available" - - - def _testStats(self, statsClass, profile): - out = StringIO.StringIO() - - # Patch before creating the pstats, because pstats binds self.stream to - # sys.stdout early in 2.5 and newer. - stdout = self.patch(sys, 'stdout', out) - - # If pstats.Stats can load the data and then reformat it, then the - # right thing probably happened. - stats = statsClass(profile) - stats.print_stats() - stdout.restore() - - data = out.getvalue() - self.assertIn("function calls", data) - self.assertIn("(run)", data) - - - def test_profileSaveStats(self): - """ - With the C{savestats} option specified, L{app.ProfileRunner.run} - should save the raw stats object instead of a summary output. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "profile" - config["savestats"] = True - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - self._testStats(pstats.Stats, config['profile']) - - if profile is None: - test_profileSaveStats.skip = "profile module not available" - - - def test_withoutProfile(self): - """ - When the C{profile} module is not present, L{app.ProfilerRunner.run} - should raise a C{SystemExit} exception. - """ - savedModules = sys.modules.copy() - - config = twistd.ServerOptions() - config["profiler"] = "profile" - profiler = app.AppProfiler(config) - - sys.modules["profile"] = None - try: - self.assertRaises(SystemExit, profiler.run, None) - finally: - sys.modules.clear() - sys.modules.update(savedModules) - - - def test_profilePrintStatsError(self): - """ - When an error happens during the print of the stats, C{sys.stdout} - should be restored to its initial value. - """ - class ErroneousProfile(profile.Profile): - def print_stats(self): - raise RuntimeError("Boom") - self.patch(profile, "Profile", ErroneousProfile) - - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "profile" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - oldStdout = sys.stdout - self.assertRaises(RuntimeError, profiler.run, reactor) - self.assertIdentical(sys.stdout, oldStdout) - - if profile is None: - test_profilePrintStatsError.skip = "profile module not available" - - - def test_hotshot(self): - """ - L{app.HotshotRunner.run} should call the C{run} method of the reactor - and save profile data in the specified file. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "hotshot" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("run", data) - self.assertIn("function calls", data) - - if hotshot is None: - test_hotshot.skip = "hotshot module not available" - - - def test_hotshotSaveStats(self): - """ - With the C{savestats} option specified, L{app.HotshotRunner.run} should - save the raw stats object instead of a summary output. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "hotshot" - config["savestats"] = True - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - self._testStats(hotshot.stats.load, config['profile']) - - if hotshot is None: - test_hotshotSaveStats.skip = "hotshot module not available" - - - def test_withoutHotshot(self): - """ - When the C{hotshot} module is not present, L{app.HotshotRunner.run} - should raise a C{SystemExit} exception and log the C{ImportError}. - """ - savedModules = sys.modules.copy() - sys.modules["hotshot"] = None - - config = twistd.ServerOptions() - config["profiler"] = "hotshot" - profiler = app.AppProfiler(config) - try: - self.assertRaises(SystemExit, profiler.run, None) - finally: - sys.modules.clear() - sys.modules.update(savedModules) - - - def test_hotshotPrintStatsError(self): - """ - When an error happens while printing the stats, C{sys.stdout} - should be restored to its initial value. - """ - class ErroneousStats(pstats.Stats): - def print_stats(self): - raise RuntimeError("Boom") - self.patch(pstats, "Stats", ErroneousStats) - - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "hotshot" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - oldStdout = sys.stdout - self.assertRaises(RuntimeError, profiler.run, reactor) - self.assertIdentical(sys.stdout, oldStdout) - - if hotshot is None: - test_hotshotPrintStatsError.skip = "hotshot module not available" - - - def test_cProfile(self): - """ - L{app.CProfileRunner.run} should call the C{run} method of the - reactor and save profile data in the specified file. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "cProfile" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("run", data) - self.assertIn("function calls", data) - - if cProfile is None: - test_cProfile.skip = "cProfile module not available" - - - def test_cProfileSaveStats(self): - """ - With the C{savestats} option specified, - L{app.CProfileRunner.run} should save the raw stats object - instead of a summary output. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "cProfile" - config["savestats"] = True - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - self._testStats(pstats.Stats, config['profile']) - - if cProfile is None: - test_cProfileSaveStats.skip = "cProfile module not available" - - - def test_withoutCProfile(self): - """ - When the C{cProfile} module is not present, - L{app.CProfileRunner.run} should raise a C{SystemExit} - exception and log the C{ImportError}. - """ - savedModules = sys.modules.copy() - sys.modules["cProfile"] = None - - config = twistd.ServerOptions() - config["profiler"] = "cProfile" - profiler = app.AppProfiler(config) - try: - self.assertRaises(SystemExit, profiler.run, None) - finally: - sys.modules.clear() - sys.modules.update(savedModules) - - - def test_unknownProfiler(self): - """ - Check that L{app.AppProfiler} raises L{SystemExit} when given an - unknown profiler name. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "foobar" - - error = self.assertRaises(SystemExit, app.AppProfiler, config) - self.assertEqual(str(error), "Unsupported profiler name: foobar") - - - def test_defaultProfiler(self): - """ - L{app.Profiler} defaults to the hotshot profiler if not specified. - """ - profiler = app.AppProfiler({}) - self.assertEqual(profiler.profiler, "hotshot") - - - def test_profilerNameCaseInsentive(self): - """ - The case of the profiler name passed to L{app.AppProfiler} is not - relevant. - """ - profiler = app.AppProfiler({"profiler": "HotShot"}) - self.assertEqual(profiler.profiler, "hotshot") - - - -def _patchFileLogObserver(patch): - """ - Patch L{log.FileLogObserver} to record every call and keep a reference to - the passed log file for tests. - - @param patch: a callback for patching (usually L{unittest.TestCase.patch}). - - @return: the list that keeps track of the log files. - @rtype: C{list} - """ - logFiles = [] - oldFileLobObserver = log.FileLogObserver - - def FileLogObserver(logFile): - logFiles.append(logFile) - return oldFileLobObserver(logFile) - - patch(log, 'FileLogObserver', FileLogObserver) - return logFiles - - - -def _setupSyslog(testCase): - """ - Make fake syslog, and return list to which prefix and then log - messages will be appended if it is used. - """ - logMessages = [] - - class fakesyslogobserver(object): - def __init__(self, prefix): - logMessages.append(prefix) - - def emit(self, eventDict): - logMessages.append(eventDict) - - testCase.patch(syslog, "SyslogObserver", fakesyslogobserver) - return logMessages - - - -class AppLoggerTests(unittest.TestCase): - """ - Tests for L{app.AppLogger}. - - @ivar observers: list of observers installed during the tests. - @type observers: C{list} - """ - - def setUp(self): - """ - Override L{log.addObserver} so that we can trace the observers - installed in C{self.observers}. - """ - self.observers = [] - - def startLoggingWithObserver(observer): - self.observers.append(observer) - log.addObserver(observer) - - self.patch(log, 'startLoggingWithObserver', startLoggingWithObserver) - - - def tearDown(self): - """ - Remove all installed observers. - """ - for observer in self.observers: - log.removeObserver(observer) - - - def _checkObserver(self, logs): - """ - Ensure that initial C{twistd} logs are written to the given list. - - @type logs: C{list} - @param logs: The list whose C{append} method was specified as the - initial log observer. - """ - self.assertEqual(self.observers, [logs.append]) - self.assertIn("starting up", logs[0]["message"][0]) - self.assertIn("reactor class", logs[1]["message"][0]) - - - def test_start(self): - """ - L{app.AppLogger.start} calls L{log.addObserver}, and then writes some - messages about twistd and the reactor. - """ - logger = app.AppLogger({}) - observer = [] - logger._getLogObserver = lambda: observer.append - logger.start(Componentized()) - self._checkObserver(observer) - - - def test_startUsesApplicationLogObserver(self): - """ - When the L{ILogObserver} component is available on the application, - that object will be used as the log observer instead of constructing a - new one. - """ - application = Componentized() - logs = [] - application.setComponent(ILogObserver, logs.append) - logger = app.AppLogger({}) - logger.start(application) - self._checkObserver(logs) - - - def _setupConfiguredLogger(self, application, extraLogArgs={}, - appLogger=app.AppLogger): - """ - Set up an AppLogger which exercises the C{logger} configuration option. - - @type application: L{Componentized} - @param application: The L{Application} object to pass to - L{app.AppLogger.start}. - @type extraLogArgs: C{dict} - @param extraLogArgs: extra values to pass to AppLogger. - @type appLogger: L{AppLogger} class, or a subclass - @param appLogger: factory for L{AppLogger} instances. - - @rtype: C{list} - @return: The logs accumulated by the log observer. - """ - logs = [] - logArgs = {"logger": lambda: logs.append} - logArgs.update(extraLogArgs) - logger = appLogger(logArgs) - logger.start(application) - return logs - - - def test_startUsesConfiguredLogObserver(self): - """ - When the C{logger} key is specified in the configuration dictionary - (i.e., when C{--logger} is passed to twistd), the initial log observer - will be the log observer returned from the callable which the value - refers to in FQPN form. - """ - application = Componentized() - self._checkObserver(self._setupConfiguredLogger(application)) - - - def test_configuredLogObserverBeatsComponent(self): - """ - C{--logger} takes precedence over a ILogObserver component set on - Application. - """ - nonlogs = [] - application = Componentized() - application.setComponent(ILogObserver, nonlogs.append) - self._checkObserver(self._setupConfiguredLogger(application)) - self.assertEqual(nonlogs, []) - - - def test_configuredLogObserverBeatsSyslog(self): - """ - C{--logger} takes precedence over a C{--syslog} command line - argument. - """ - logs = _setupSyslog(self) - application = Componentized() - self._checkObserver(self._setupConfiguredLogger(application, - {"syslog": True}, - UnixAppLogger)) - self.assertEqual(logs, []) - - if _twistd_unix is None or syslog is None: - test_configuredLogObserverBeatsSyslog.skip = ( - "Not on POSIX, or syslog not available." - ) - - - def test_configuredLogObserverBeatsLogfile(self): - """ - C{--logger} takes precedence over a C{--logfile} command line - argument. - """ - application = Componentized() - path = self.mktemp() - self._checkObserver(self._setupConfiguredLogger(application, - {"logfile": "path"})) - self.assertFalse(os.path.exists(path)) - - - def test_getLogObserverStdout(self): - """ - When logfile is empty or set to C{-}, L{app.AppLogger._getLogObserver} - returns a log observer pointing at C{sys.stdout}. - """ - logger = app.AppLogger({"logfile": "-"}) - logFiles = _patchFileLogObserver(self.patch) - - logger._getLogObserver() - - self.assertEqual(len(logFiles), 1) - self.assertIdentical(logFiles[0], sys.stdout) - - logger = app.AppLogger({"logfile": ""}) - logger._getLogObserver() - - self.assertEqual(len(logFiles), 2) - self.assertIdentical(logFiles[1], sys.stdout) - - - def test_getLogObserverFile(self): - """ - When passing the C{logfile} option, L{app.AppLogger._getLogObserver} - returns a log observer pointing at the specified path. - """ - logFiles = _patchFileLogObserver(self.patch) - filename = self.mktemp() - logger = app.AppLogger({"logfile": filename}) - - logger._getLogObserver() - - self.assertEqual(len(logFiles), 1) - self.assertEqual(logFiles[0].path, - os.path.abspath(filename)) - - - def test_stop(self): - """ - L{app.AppLogger.stop} removes the observer created in C{start}, and - reinitialize its C{_observer} so that if C{stop} is called several - times it doesn't break. - """ - removed = [] - observer = object() - - def remove(observer): - removed.append(observer) - - self.patch(log, 'removeObserver', remove) - logger = app.AppLogger({}) - logger._observer = observer - logger.stop() - self.assertEqual(removed, [observer]) - logger.stop() - self.assertEqual(removed, [observer]) - self.assertIdentical(logger._observer, None) - - - -class UnixAppLoggerTests(unittest.TestCase): - """ - Tests for L{UnixAppLogger}. - - @ivar signals: list of signal handlers installed. - @type signals: C{list} - """ - if _twistd_unix is None: - skip = "twistd unix not available" - - - def setUp(self): - """ - Fake C{signal.signal} for not installing the handlers but saving them - in C{self.signals}. - """ - self.signals = [] - - def fakeSignal(sig, f): - self.signals.append((sig, f)) - - self.patch(signal, "signal", fakeSignal) - - - def test_getLogObserverStdout(self): - """ - When non-daemonized and C{logfile} is empty or set to C{-}, - L{UnixAppLogger._getLogObserver} returns a log observer pointing at - C{sys.stdout}. - """ - logFiles = _patchFileLogObserver(self.patch) - - logger = UnixAppLogger({"logfile": "-", "nodaemon": True}) - logger._getLogObserver() - self.assertEqual(len(logFiles), 1) - self.assertIdentical(logFiles[0], sys.stdout) - - logger = UnixAppLogger({"logfile": "", "nodaemon": True}) - logger._getLogObserver() - self.assertEqual(len(logFiles), 2) - self.assertIdentical(logFiles[1], sys.stdout) - - - def test_getLogObserverStdoutDaemon(self): - """ - When daemonized and C{logfile} is set to C{-}, - L{UnixAppLogger._getLogObserver} raises C{SystemExit}. - """ - logger = UnixAppLogger({"logfile": "-", "nodaemon": False}) - error = self.assertRaises(SystemExit, logger._getLogObserver) - self.assertEqual(str(error), "Daemons cannot log to stdout, exiting!") - - - def test_getLogObserverFile(self): - """ - When C{logfile} contains a file name, L{app.AppLogger._getLogObserver} - returns a log observer pointing at the specified path, and a signal - handler rotating the log is installed. - """ - logFiles = _patchFileLogObserver(self.patch) - filename = self.mktemp() - logger = UnixAppLogger({"logfile": filename}) - logger._getLogObserver() - - self.assertEqual(len(logFiles), 1) - self.assertEqual(logFiles[0].path, os.path.abspath(filename)) - - self.assertEqual(len(self.signals), 1) - self.assertEqual(self.signals[0][0], signal.SIGUSR1) - - d = Deferred() - - def rotate(): - d.callback(None) - - logFiles[0].rotate = rotate - - rotateLog = self.signals[0][1] - rotateLog(None, None) - return d - - - def test_getLogObserverDontOverrideSignalHandler(self): - """ - If a signal handler is already installed, - L{UnixAppLogger._getLogObserver} doesn't override it. - """ - def fakeGetSignal(sig): - self.assertEqual(sig, signal.SIGUSR1) - return object() - self.patch(signal, "getsignal", fakeGetSignal) - filename = self.mktemp() - logger = UnixAppLogger({"logfile": filename}) - logger._getLogObserver() - - self.assertEqual(self.signals, []) - - - def test_getLogObserverDefaultFile(self): - """ - When daemonized and C{logfile} is empty, the observer returned by - L{UnixAppLogger._getLogObserver} points at C{twistd.log} in the current - directory. - """ - logFiles = _patchFileLogObserver(self.patch) - logger = UnixAppLogger({"logfile": "", "nodaemon": False}) - logger._getLogObserver() - - self.assertEqual(len(logFiles), 1) - self.assertEqual(logFiles[0].path, os.path.abspath("twistd.log")) - - - def test_getLogObserverSyslog(self): - """ - If C{syslog} is set to C{True}, L{UnixAppLogger._getLogObserver} starts - a L{syslog.SyslogObserver} with given C{prefix}. - """ - logs = _setupSyslog(self) - logger = UnixAppLogger({"syslog": True, "prefix": "test-prefix"}) - observer = logger._getLogObserver() - self.assertEqual(logs, ["test-prefix"]) - observer({"a": "b"}) - self.assertEqual(logs, ["test-prefix", {"a": "b"}]) - - if syslog is None: - test_getLogObserverSyslog.skip = "Syslog not available" - - - -class DaemonizeTests(unittest.TestCase): - """ - Tests for L{_twistd_unix.UnixApplicationRunner} daemonization. - """ - - def setUp(self): - self.mockos = MockOS() - self.config = twistd.ServerOptions() - self.patch(_twistd_unix, 'os', self.mockos) - self.runner = _twistd_unix.UnixApplicationRunner(self.config) - self.runner.application = service.Application("Hi!") - self.runner.oldstdout = sys.stdout - self.runner.oldstderr = sys.stderr - self.runner.startReactor = lambda *args: None - - - def test_success(self): - """ - When double fork succeeded in C{daemonize}, the child process writes - B{0} to the status pipe. - """ - with AlternateReactor(FakeDaemonizingReactor()): - self.runner.postApplication() - self.assertEqual( - self.mockos.actions, - [('chdir', '.'), ('umask', 077), ('fork', True), 'setsid', - ('fork', True), ('write', -2, '0'), ('unlink', 'twistd.pid')]) - self.assertEqual(self.mockos.closed, [-3, -2]) - - - def test_successInParent(self): - """ - The parent process initiating the C{daemonize} call reads data from the - status pipe and then exit the process. - """ - self.mockos.child = False - self.mockos.readData = "0" - with AlternateReactor(FakeDaemonizingReactor()): - self.assertRaises(SystemError, self.runner.postApplication) - self.assertEqual( - self.mockos.actions, - [('chdir', '.'), ('umask', 077), ('fork', True), - ('read', -1, 100), ('exit', 0), ('unlink', 'twistd.pid')]) - self.assertEqual(self.mockos.closed, [-1]) - - - def test_successEINTR(self): - """ - If the C{os.write} call to the status pipe raises an B{EINTR} error, - the process child retries to write. - """ - written = [] - - def raisingWrite(fd, data): - written.append((fd, data)) - if len(written) == 1: - raise IOError(errno.EINTR) - - self.mockos.write = raisingWrite - with AlternateReactor(FakeDaemonizingReactor()): - self.runner.postApplication() - self.assertEqual( - self.mockos.actions, - [('chdir', '.'), ('umask', 077), ('fork', True), 'setsid', - ('fork', True), ('unlink', 'twistd.pid')]) - self.assertEqual(self.mockos.closed, [-3, -2]) - self.assertEqual([(-2, '0'), (-2, '0')], written) - - - def test_successInParentEINTR(self): - """ - If the C{os.read} call on the status pipe raises an B{EINTR} error, the - parent child retries to read. - """ - read = [] - - def raisingRead(fd, size): - read.append((fd, size)) - if len(read) == 1: - raise IOError(errno.EINTR) - return "0" - - self.mockos.read = raisingRead - self.mockos.child = False - with AlternateReactor(FakeDaemonizingReactor()): - self.assertRaises(SystemError, self.runner.postApplication) - self.assertEqual( - self.mockos.actions, - [('chdir', '.'), ('umask', 077), ('fork', True), - ('exit', 0), ('unlink', 'twistd.pid')]) - self.assertEqual(self.mockos.closed, [-1]) - self.assertEqual([(-1, 100), (-1, 100)], read) - - - def test_error(self): - """ - If an error happens during daemonization, the child process writes the - exception error to the status pipe. - """ - - class FakeService(service.Service): - - def startService(self): - raise RuntimeError("Something is wrong") - - errorService = FakeService() - errorService.setServiceParent(self.runner.application) - - with AlternateReactor(FakeDaemonizingReactor()): - self.assertRaises(RuntimeError, self.runner.postApplication) - self.assertEqual( - self.mockos.actions, - [('chdir', '.'), ('umask', 077), ('fork', True), 'setsid', - ('fork', True), ('write', -2, '1 Something is wrong'), - ('unlink', 'twistd.pid')]) - self.assertEqual(self.mockos.closed, [-3, -2]) - - - def test_errorInParent(self): - """ - When the child writes an error message to the status pipe during - daemonization, the parent writes the message to C{stderr} and exits - with non-zero status code. - """ - self.mockos.child = False - self.mockos.readData = "1: An identified error" - errorIO = StringIO.StringIO() - self.patch(sys, '__stderr__', errorIO) - with AlternateReactor(FakeDaemonizingReactor()): - self.assertRaises(SystemError, self.runner.postApplication) - self.assertEqual( - errorIO.getvalue(), - "An error has occurred: ' An identified error'\n" - "Please look at log file for more information.\n") - self.assertEqual( - self.mockos.actions, - [('chdir', '.'), ('umask', 077), ('fork', True), - ('read', -1, 100), ('exit', 1), ('unlink', 'twistd.pid')]) - self.assertEqual(self.mockos.closed, [-1]) - - - def test_errorMessageTruncated(self): - """ - If an error in daemonize gives a too big error message, it's truncated - by the child. - """ - - class FakeService(service.Service): - - def startService(self): - raise RuntimeError("x" * 200) - - errorService = FakeService() - errorService.setServiceParent(self.runner.application) - - with AlternateReactor(FakeDaemonizingReactor()): - self.assertRaises(RuntimeError, self.runner.postApplication) - self.assertEqual( - self.mockos.actions, - [('chdir', '.'), ('umask', 077), ('fork', True), 'setsid', - ('fork', True), ('write', -2, '1 ' + 'x' * 98), - ('unlink', 'twistd.pid')]) - self.assertEqual(self.mockos.closed, [-3, -2]) - - - def test_hooksCalled(self): - """ - C{daemonize} indeed calls L{IReactorDaemonize.beforeDaemonize} and - L{IReactorDaemonize.afterDaemonize} if the reactor implements - L{IReactorDaemonize}. - """ - reactor = FakeDaemonizingReactor() - self.runner.daemonize(reactor) - self.assertTrue(reactor._beforeDaemonizeCalled) - self.assertTrue(reactor._afterDaemonizeCalled) - - - def test_hooksNotCalled(self): - """ - C{daemonize} does NOT call L{IReactorDaemonize.beforeDaemonize} or - L{IReactorDaemonize.afterDaemonize} if the reactor does NOT implement - L{IReactorDaemonize}. - """ - reactor = FakeNonDaemonizingReactor() - self.runner.daemonize(reactor) - self.assertFalse(reactor._beforeDaemonizeCalled) - self.assertFalse(reactor._afterDaemonizeCalled) - - - -if _twistd_unix is None: - DaemonizeTests.skip = "twistd unix support not available" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_twisted.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_twisted.py deleted file mode 100644 index f7c7de0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_twisted.py +++ /dev/null @@ -1,702 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for miscellaneous behaviors of the top-level L{twisted} package (ie, for -the code in C{twisted/__init__.py}. -""" - -from __future__ import division, absolute_import - -import re -import sys -from types import ModuleType, FunctionType - -from twisted import _checkRequirements -from twisted.python import reflect -from twisted.python.compat import _PY3 -from twisted.trial.unittest import TestCase - - -# This is somewhat generally useful and should probably be part of a public API -# somewhere. See #5977. -class SetAsideModule(object): - """ - L{SetAsideModule} is a context manager for temporarily removing a module - from C{sys.modules}. - - @ivar name: The name of the module to remove. - """ - def __init__(self, name): - self.name = name - - - def _unimport(self, name): - """ - Find the given module and all of its hierarchically inferior modules in - C{sys.modules}, remove them from it, and return whatever was found. - """ - modules = dict([ - (moduleName, module) - for (moduleName, module) - in list(sys.modules.items()) - if (moduleName == self.name or - moduleName.startswith(self.name + "."))]) - for name in modules: - del sys.modules[name] - return modules - - - def __enter__(self): - self.modules = self._unimport(self.name) - - - def __exit__(self, excType, excValue, traceback): - self._unimport(self.name) - sys.modules.update(self.modules) - - - -# Copied from 2.7 stdlib. Delete after Python 2.6 is no longer a -# requirement. See #5976. -class _AssertRaisesContext(object): - """A context manager used to implement TestCase.assertRaises* methods.""" - - def __init__(self, expected, test_case, expected_regexp=None): - self.expected = expected - self.failureException = test_case.failureException - self.expected_regexp = expected_regexp - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, tb): - if exc_type is None: - try: - exc_name = self.expected.__name__ - except AttributeError: - exc_name = str(self.expected) - raise self.failureException( - "{0} not raised".format(exc_name)) - if not issubclass(exc_type, self.expected): - # let unexpected exceptions pass through - return False - self.exception = exc_value # store for later retrieval - if self.expected_regexp is None: - return True - - expected_regexp = self.expected_regexp - if isinstance(expected_regexp, basestring): - expected_regexp = re.compile(expected_regexp) - if not expected_regexp.search(str(exc_value)): - raise self.failureException('"%s" does not match "%s"' % - (expected_regexp.pattern, str(exc_value))) - return True - - - -def _install(modules): - """ - Take a mapping defining a package and turn it into real C{ModuleType} - instances in C{sys.modules}. - - Consider these example:: - - a = {"foo": "bar"} - b = {"twisted": {"__version__": "42.6"}} - c = {"twisted": {"plugin": {"getPlugins": stub}}} - - C{_install(a)} will place an item into C{sys.modules} with C{"foo"} as the - key and C{"bar" as the value. - - C{_install(b)} will place an item into C{sys.modules} with C{"twisted"} as - the key. The value will be a new module object. The module will have a - C{"__version__"} attribute with C{"42.6"} as the value. - - C{_install(c)} will place an item into C{sys.modules} with C{"twisted"} as - the key. The value will be a new module object with a C{"plugin"} - attribute. An item will also be placed into C{sys.modules} with the key - C{"twisted.plugin"} which refers to that module object. That module will - have an attribute C{"getPlugins"} with a value of C{stub}. - - @param modules: A mapping from names to definitions of modules. The names - are native strings like C{"twisted"} or C{"unittest"}. Values may be - arbitrary objects. Any value which is not a dictionary will be added to - C{sys.modules} unmodified. Any dictionary value indicates the value is - a new module and its items define the attributes of that module. The - definition of this structure is recursive, so a value in the dictionary - may be a dictionary to trigger another level of processing. - - @return: C{None} - """ - result = {} - _makePackages(None, modules, result) - sys.modules.update(result) - - - -def _makePackages(parent, attributes, result): - """ - Construct module objects (for either modules or packages). - - @param parent: C{None} or a module object which is the Python package - containing all of the modules being created by this function call. Its - name will be prepended to the name of all created modules. - - @param attributes: A mapping giving the attributes of the particular module - object this call is creating. - - @param result: A mapping which is populated with all created module names. - This is suitable for use in updating C{sys.modules}. - - @return: A mapping of all of the attributes created by this call. This is - suitable for populating the dictionary of C{parent}. - - @see: L{_install}. - """ - attrs = {} - for (name, value) in list(attributes.items()): - if parent is None: - if isinstance(value, dict): - module = ModuleType(name) - module.__dict__.update(_makePackages(module, value, result)) - result[name] = module - else: - result[name] = value - else: - if isinstance(value, dict): - module = ModuleType(parent.__name__ + '.' + name) - module.__dict__.update(_makePackages(module, value, result)) - result[parent.__name__ + '.' + name] = module - attrs[name] = module - else: - attrs[name] = value - return attrs - - - -class RequirementsTests(TestCase): - """ - Tests for the import-time requirements checking. - - @ivar unsupportedPythonVersion: The newest version of Python 2.x which is - not supported by Twisted. - @type unsupportedPythonVersion: C{tuple} - - @ivar supportedPythonVersion: The oldest version of Python 2.x which is - supported by Twisted. - @type supportedPythonVersion: C{tuple} - - @ivar supportedZopeInterfaceVersion: The oldest version of C{zope.interface} - which is supported by Twisted. - @type supportedZopeInterfaceVersion: C{tuple} - """ - unsupportedPythonVersion = (2, 5) - supportedPythonVersion = (2, 6) - - if _PY3: - supportedZopeInterfaceVersion = (4, 0, 0) - else: - supportedZopeInterfaceVersion = (3, 6, 0) - - # Copied from 2.7 stdlib. Delete after Python 2.6 is no longer a - # requirement. See #5976. - def assertRaises(self, excClass, callableObj=None, *args, **kwargs): - """Fail unless an exception of class excClass is thrown - by callableObj when invoked with arguments args and keyword - arguments kwargs. If a different type of exception is - thrown, it will not be caught, and the test case will be - deemed to have suffered an error, exactly as for an - unexpected exception. - - If called with callableObj omitted or None, will return a - context object used like this:: - - with self.assertRaises(SomeException): - do_something() - - The context manager keeps a reference to the exception as - the 'exception' attribute. This allows you to inspect the - exception after the assertion:: - - with self.assertRaises(SomeException) as cm: - do_something() - the_exception = cm.exception - self.assertEqual(the_exception.error_code, 3) - """ - context = _AssertRaisesContext(excClass, self) - if callableObj is None: - return context - with context: - callableObj(*args, **kwargs) - - - def setUp(self): - """ - Save the original value of C{sys.version_info} so it can be restored - after the tests mess with it. - """ - self.version = sys.version_info - - - def tearDown(self): - """ - Restore the original values saved in L{setUp}. - """ - sys.version_info = self.version - - - def test_oldPython(self): - """ - L{_checkRequirements} raises L{ImportError} when run on a version of - Python that is too old. - """ - sys.version_info = self.unsupportedPythonVersion - with self.assertRaises(ImportError) as raised: - _checkRequirements() - self.assertEqual( - "Twisted requires Python %d.%d or later." % self.supportedPythonVersion, - str(raised.exception)) - - - def test_newPython(self): - """ - L{_checkRequirements} returns C{None} when run on a version of Python - that is sufficiently new. - """ - sys.version_info = self.supportedPythonVersion - self.assertEqual(None, _checkRequirements()) - - - def test_missingZopeNamespace(self): - """ - L{_checkRequirements} raises L{ImportError} when the C{zope} namespace - package is not installed. - """ - with SetAsideModule("zope"): - # After an import for a module fails, it gets a None value in - # sys.modules as a cache of that negative result. Future import - # attempts see it and fail fast without checking the system again. - sys.modules["zope"] = None - with self.assertRaises(ImportError) as raised: - _checkRequirements() - self.assertEqual( - "Twisted requires zope.interface %d.%d.%d or later: no module " - "named zope.interface." % self.supportedZopeInterfaceVersion, - str(raised.exception)) - - - def test_missingZopeInterface(self): - """ - L{_checkRequirements} raises L{ImportError} when the C{zope.interface} - package is not installed. - """ - with SetAsideModule("zope"): - # Create a minimal module to represent the zope namespace package, - # but don't give it an "interface" attribute. - sys.modules["zope"] = ModuleType("zope") - with self.assertRaises(ImportError) as raised: - _checkRequirements() - self.assertEqual( - "Twisted requires zope.interface %d.%d.%d or later: no module " - "named zope.interface." % self.supportedZopeInterfaceVersion, - str(raised.exception)) - - - def test_setupNoCheckRequirements(self): - """ - L{_checkRequirements} doesn't check for C{zope.interface} compliance - when C{setuptools._TWISTED_NO_CHECK_REQUIREMENTS} is set. - """ - with SetAsideModule("setuptools"): - setuptools = ModuleType("setuptools") - setuptools._TWISTED_NO_CHECK_REQUIREMENTS = True - sys.modules["setuptools"] = setuptools - with SetAsideModule("zope"): - sys.modules["zope"] = None - _checkRequirements() - - - def test_setupCheckRequirements(self): - """ - L{_checkRequirements} checks for C{zope.interface} compliance when - C{setuptools} is imported but the C{_TWISTED_NO_CHECK_REQUIREMENTS} is - not set. - """ - with SetAsideModule("setuptools"): - sys.modules["setuptools"] = ModuleType("setuptools") - with SetAsideModule("zope"): - sys.modules["zope"] = None - self.assertRaises(ImportError, _checkRequirements) - - - def test_noSetupCheckRequirements(self): - """ - L{_checkRequirements} checks for C{zope.interface} compliance when - C{setuptools} is not imported. - """ - with SetAsideModule("setuptools"): - sys.modules["setuptools"] = None - with SetAsideModule("zope"): - sys.modules["zope"] = None - self.assertRaises(ImportError, _checkRequirements) - - - if _PY3: - # Python 3 requires a version that isn't tripped up by the __qualname__ - # special attribute. - - def test_oldZopeInterface(self): - """ - If the installed version of C{zope.interface} does not support the - C{implementer} class decorator, L{_checkRequirements} raises - L{ImportError} with a message explaining a newer version is - required. - """ - with SetAsideModule("zope"): - _install(_zope38) - with self.assertRaises(ImportError) as raised: - _checkRequirements() - self.assertEqual( - "Twisted requires zope.interface 4.0.0 or later.", - str(raised.exception)) - - - def test_newZopeInterface(self): - """ - If the installed version of C{zope.interface} does support the - C{implementer} class decorator, L{_checkRequirements} returns - C{None}. - """ - with SetAsideModule("zope"): - _install(_zope40) - self.assertEqual(None, _checkRequirements()) - - else: - # Python 2 only requires a version that supports the class decorator - # version of declarations. - - def test_oldZopeInterface(self): - """ - L{_checkRequirements} raises L{ImportError} when the C{zope.interface} - package installed is old enough that C{implementer_only} is not included - (added in zope.interface 3.6). - """ - with SetAsideModule("zope"): - _install(_zope35) - with self.assertRaises(ImportError) as raised: - _checkRequirements() - self.assertEqual( - "Twisted requires zope.interface 3.6.0 or later.", - str(raised.exception)) - - - def test_newZopeInterface(self): - """ - L{_checkRequirements} returns C{None} when C{zope.interface} is - installed and new enough. - """ - with SetAsideModule("zope"): - _install(_zope36) - self.assertEqual(None, _checkRequirements()) - - - -class MakePackagesTests(TestCase): - """ - Tests for L{_makePackages}, a helper for populating C{sys.modules} with - fictional modules. - """ - def test_nonModule(self): - """ - A non-C{dict} value in the attributes dictionary passed to L{_makePackages} - is preserved unchanged in the return value. - """ - modules = {} - _makePackages(None, dict(reactor='reactor'), modules) - self.assertEqual(modules, dict(reactor='reactor')) - - - def test_moduleWithAttribute(self): - """ - A C{dict} value in the attributes dictionary passed to L{_makePackages} - is turned into a L{ModuleType} instance with attributes populated from - the items of that C{dict} value. - """ - modules = {} - _makePackages(None, dict(twisted=dict(version='123')), modules) - self.assertTrue(isinstance(modules, dict)) - self.assertTrue(isinstance(modules['twisted'], ModuleType)) - self.assertEqual('twisted', modules['twisted'].__name__) - self.assertEqual('123', modules['twisted'].version) - - - def test_packageWithModule(self): - """ - Processing of the attributes dictionary is recursive, so a C{dict} value - it contains may itself contain a C{dict} value to the same effect. - """ - modules = {} - _makePackages(None, dict(twisted=dict(web=dict(version='321'))), modules) - self.assertTrue(isinstance(modules, dict)) - self.assertTrue(isinstance(modules['twisted'], ModuleType)) - self.assertEqual('twisted', modules['twisted'].__name__) - self.assertTrue(isinstance(modules['twisted'].web, ModuleType)) - self.assertEqual('twisted.web', modules['twisted'].web.__name__) - self.assertEqual('321', modules['twisted'].web.version) - - - -def _functionOnlyImplementer(*interfaces): - """ - A fake implementation of L{zope.interface.implementer} which always behaves - like the version of that function provided by zope.interface 3.5 and older. - """ - def check(obj): - """ - If the decorated object is not a function, raise an exception. - """ - if not isinstance(obj, FunctionType): - raise TypeError( - "Can't use implementer with classes. " - "Use one of the class-declaration functions instead.") - return check - - - -def _classSupportingImplementer(*interfaces): - """ - A fake implementation of L{zope.interface.implementer} which always - succeeds. For the use it is put to, this is like the version of that - function provided by zope.interface 3.6 and newer. - """ - def check(obj): - """ - Do nothing at all. - """ - return check - - - -class _SuccessInterface(object): - """ - A fake implementation of L{zope.interface.Interface} with no behavior. For - the use it is put to, this is equivalent to the behavior of the C{Interface} - provided by all versions of zope.interface. - """ - - -# Definition of a module somewhat like zope.interface 3.5. -_zope35 = { - 'zope': { - 'interface': { - 'Interface': _SuccessInterface, - 'implementer': _functionOnlyImplementer, - }, - }, - } - - -# Definition of a module somewhat like zope.interface 3.6. -_zope36 = { - 'zope': { - 'interface': { - 'Interface': _SuccessInterface, - 'implementer': _classSupportingImplementer, - }, - }, - } - - -class _Zope38OnPython3Module(object): - """ - A pseudo-module which raises an exception when its C{interface} attribute is - accessed. This is like the behavior of zope.interface 3.8 and earlier when - used with Python 3.3. - """ - __path__ = [] - __name__ = 'zope' - - @property - def interface(self): - raise Exception( - "zope.interface.exceptions.InvalidInterface: " - "Concrete attribute, __qualname__") - -# Definition of a module somewhat like zope.interface 3.8 when it is used on Python 3. -_zope38 = { - 'zope': _Zope38OnPython3Module(), - } - -# Definition of a module somewhat like zope.interface 4.0. -_zope40 = { - 'zope': { - 'interface': { - 'Interface': _SuccessInterface, - 'implementer': _classSupportingImplementer, - }, - }, - } - - -class ZopeInterfaceTestsMixin(object): - """ - Verify the C{zope.interface} fakes, only possible when a specific version of - the real C{zope.interface} package is installed on the system. - - Subclass this and override C{install} to properly install and then remove - the given version of C{zope.interface}. - """ - def test_zope35(self): - """ - Version 3.5 of L{zope.interface} has a C{implementer} method which - cannot be used as a class decorator. - """ - with SetAsideModule("zope"): - self.install((3, 5)) - from zope.interface import Interface, implementer - class IDummy(Interface): - pass - try: - @implementer(IDummy) - class Dummy(object): - pass - except TypeError as exc: - self.assertEqual( - "Can't use implementer with classes. " - "Use one of the class-declaration functions instead.", - str(exc)) - - - def test_zope36(self): - """ - Version 3.6 of L{zope.interface} has a C{implementer} method which can - be used as a class decorator. - """ - with SetAsideModule("zope"): - self.install((3, 6)) - from zope.interface import Interface, implementer - class IDummy(Interface): - pass - @implementer(IDummy) - class Dummy(object): - pass - - if _PY3: - def test_zope38(self): - """ - Version 3.8 of L{zope.interface} does not even import on Python 3. - """ - with SetAsideModule("zope"): - self.install((3, 8)) - try: - from zope import interface - # It is imported just to check errors at import so we - # silence the linter. - interface - except Exception as exc: - self.assertEqual( - "zope.interface.exceptions.InvalidInterface: " - "Concrete attribute, __qualname__", - str(exc)) - else: - self.fail( - "InvalidInterface was not raised by zope.interface import") - - - def test_zope40(self): - """ - Version 4.0 of L{zope.interface} can import on Python 3 and, also on - Python 3, has an C{Interface} class which can be subclassed. - """ - with SetAsideModule("zope"): - self.install((4, 0)) - from zope.interface import Interface - class IDummy(Interface): - pass - - -class FakeZopeInterfaceTests(TestCase, ZopeInterfaceTestsMixin): - """ - Apply the zope.interface tests to the fakes implemented in this module. - """ - versions = { - (3, 5): _zope35, - (3, 6): _zope36, - (3, 8): _zope38, - (4, 0): _zope40, - } - - def install(self, version): - """ - Grab one of the fake module implementations and install it into - C{sys.modules} for use by the test. - """ - _install(self.versions[version]) - - -# Python 2.6 stdlib unittest does not support skipping. Use trial's -# SynchronousTestCase instead. When Python 2.6 support is dropped, this can -# switch back to using the stdlib TestCase with its skip support. -if sys.version_info[:2] == (2, 6): - from twisted.trial.unittest import SkipTest, SynchronousTestCase as TestCase -else: - from unittest import SkipTest - -class RealZopeInterfaceTests(TestCase, ZopeInterfaceTestsMixin): - """ - Apply whichever tests from L{ZopeInterfaceTestsMixin} are applicable to the - system-installed version of zope.interface. - """ - def install(self, version): - """ - Check to see if the system-installed version of zope.interface matches - the version requested. If so, do nothing. If not, skip the test (if - the desired version is not installed, there is no way to test its - behavior). If the version of zope.interface cannot be determined - (because pkg_resources is not installed), skip the test. - """ - # Use an unrelated, but unreliable, route to try to determine what - # version of zope.interface is installed on the system. It's sort of - # okay to use this unreliable scheme here, since if it fails it only - # means we won't be able to run the tests. Hopefully someone else - # managed to run the tests somewhere else. - try: - import pkg_resources - except ImportError as e: - raise SkipTest( - "Cannot determine system version of zope.interface: %s" % (e,)) - else: - try: - pkg = pkg_resources.get_distribution("zope.interface") - except pkg_resources.DistributionNotFound as e: - raise SkipTest( - "Cannot determine system version of zope.interface: %s" % ( - e,)) - installed = pkg.version - versionTuple = tuple( - int(part) for part in installed.split('.')[:len(version)]) - if versionTuple == version: - pass - else: - raise SkipTest("Mismatched system version of zope.interface") - - - -class LoreDeprecationTests(TestCase): - """ - Contains tests to make sure Lore is marked as deprecated. - """ - if _PY3: - skip = "Lore is not being ported to Python 3." - - def test_loreDeprecation(self): - """ - L{twisted.lore} is deprecated since Twisted 14.0. - """ - reflect.namedAny("twisted.lore") - warningsShown = self.flushWarnings() - self.assertEqual(1, len(warningsShown)) - self.assertEqual( - "twisted.lore was deprecated in Twisted 14.0.0: " - "Use Sphinx instead.", warningsShown[0]['message']) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_udp.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_udp.py deleted file mode 100644 index 6cf4583..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_udp.py +++ /dev/null @@ -1,701 +0,0 @@ -# -*- test-case-name: twisted.test.test_udp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for implementations of L{IReactorUDP} and L{IReactorMulticast}. -""" - -from __future__ import division, absolute_import - -from twisted.trial import unittest - -from twisted.python.compat import intToBytes -from twisted.internet.defer import Deferred, gatherResults, maybeDeferred -from twisted.internet import protocol, reactor, error, defer, interfaces, udp -from twisted.python import runtime - - -class Mixin: - - started = 0 - stopped = 0 - - startedDeferred = None - - def __init__(self): - self.packets = [] - - def startProtocol(self): - self.started = 1 - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.callback(None) - - def stopProtocol(self): - self.stopped = 1 - - -class Server(Mixin, protocol.DatagramProtocol): - packetReceived = None - refused = 0 - - - def datagramReceived(self, data, addr): - self.packets.append((data, addr)) - if self.packetReceived is not None: - d, self.packetReceived = self.packetReceived, None - d.callback(None) - - - -class Client(Mixin, protocol.ConnectedDatagramProtocol): - - packetReceived = None - refused = 0 - - def datagramReceived(self, data): - self.packets.append(data) - if self.packetReceived is not None: - d, self.packetReceived = self.packetReceived, None - d.callback(None) - - def connectionFailed(self, failure): - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.errback(failure) - self.failure = failure - - def connectionRefused(self): - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.errback(error.ConnectionRefusedError("yup")) - self.refused = 1 - - -class GoodClient(Server): - - def connectionRefused(self): - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.errback(error.ConnectionRefusedError("yup")) - self.refused = 1 - - - -class BadClientError(Exception): - """ - Raised by BadClient at the end of every datagramReceived call to try and - screw stuff up. - """ - - - -class BadClient(protocol.DatagramProtocol): - """ - A DatagramProtocol which always raises an exception from datagramReceived. - Used to test error handling behavior in the reactor for that method. - """ - d = None - - def setDeferred(self, d): - """ - Set the Deferred which will be called back when datagramReceived is - called. - """ - self.d = d - - - def datagramReceived(self, bytes, addr): - if self.d is not None: - d, self.d = self.d, None - d.callback(bytes) - raise BadClientError("Application code is very buggy!") - - - -class UDPTests(unittest.TestCase): - - def test_oldAddress(self): - """ - The C{type} of the host address of a listening L{DatagramProtocol}'s - transport is C{"UDP"}. - """ - server = Server() - d = server.startedDeferred = defer.Deferred() - p = reactor.listenUDP(0, server, interface="127.0.0.1") - def cbStarted(ignored): - addr = p.getHost() - self.assertEqual(addr.type, 'UDP') - return p.stopListening() - return d.addCallback(cbStarted) - - - def test_startStop(self): - """ - The L{DatagramProtocol}'s C{startProtocol} and C{stopProtocol} - methods are called when its transports starts and stops listening, - respectively. - """ - server = Server() - d = server.startedDeferred = defer.Deferred() - port1 = reactor.listenUDP(0, server, interface="127.0.0.1") - def cbStarted(ignored): - self.assertEqual(server.started, 1) - self.assertEqual(server.stopped, 0) - return port1.stopListening() - def cbStopped(ignored): - self.assertEqual(server.stopped, 1) - return d.addCallback(cbStarted).addCallback(cbStopped) - - - def test_rebind(self): - """ - Re-listening with the same L{DatagramProtocol} re-invokes the - C{startProtocol} callback. - """ - server = Server() - d = server.startedDeferred = defer.Deferred() - p = reactor.listenUDP(0, server, interface="127.0.0.1") - - def cbStarted(ignored, port): - return port.stopListening() - - def cbStopped(ignored): - d = server.startedDeferred = defer.Deferred() - p = reactor.listenUDP(0, server, interface="127.0.0.1") - return d.addCallback(cbStarted, p) - - return d.addCallback(cbStarted, p) - - - def test_bindError(self): - """ - A L{CannotListenError} exception is raised when attempting to bind a - second protocol instance to an already bound port - """ - server = Server() - d = server.startedDeferred = defer.Deferred() - port = reactor.listenUDP(0, server, interface='127.0.0.1') - - def cbStarted(ignored): - self.assertEqual(port.getHost(), server.transport.getHost()) - server2 = Server() - self.assertRaises( - error.CannotListenError, - reactor.listenUDP, port.getHost().port, server2, - interface='127.0.0.1') - d.addCallback(cbStarted) - - def cbFinished(ignored): - return port.stopListening() - d.addCallback(cbFinished) - return d - - - def test_sendPackets(self): - """ - Datagrams can be sent with the transport's C{write} method and - received via the C{datagramReceived} callback method. - """ - server = Server() - serverStarted = server.startedDeferred = defer.Deferred() - port1 = reactor.listenUDP(0, server, interface="127.0.0.1") - - client = GoodClient() - clientStarted = client.startedDeferred = defer.Deferred() - - def cbServerStarted(ignored): - self.port2 = reactor.listenUDP(0, client, interface="127.0.0.1") - return clientStarted - - d = serverStarted.addCallback(cbServerStarted) - - def cbClientStarted(ignored): - client.transport.connect("127.0.0.1", - server.transport.getHost().port) - cAddr = client.transport.getHost() - sAddr = server.transport.getHost() - - serverSend = client.packetReceived = defer.Deferred() - server.transport.write(b"hello", (cAddr.host, cAddr.port)) - - clientWrites = [ - (b"a",), - (b"b", None), - (b"c", (sAddr.host, sAddr.port))] - - def cbClientSend(ignored): - if clientWrites: - nextClientWrite = server.packetReceived = defer.Deferred() - nextClientWrite.addCallback(cbClientSend) - client.transport.write(*clientWrites.pop(0)) - return nextClientWrite - - # No one will ever call .errback on either of these Deferreds, - # but there is a non-trivial amount of test code which might - # cause them to fail somehow. So fireOnOneErrback=True. - return defer.DeferredList([ - cbClientSend(None), - serverSend], - fireOnOneErrback=True) - - d.addCallback(cbClientStarted) - - def cbSendsFinished(ignored): - cAddr = client.transport.getHost() - sAddr = server.transport.getHost() - self.assertEqual( - client.packets, - [(b"hello", (sAddr.host, sAddr.port))]) - clientAddr = (cAddr.host, cAddr.port) - self.assertEqual( - server.packets, - [(b"a", clientAddr), - (b"b", clientAddr), - (b"c", clientAddr)]) - - d.addCallback(cbSendsFinished) - - def cbFinished(ignored): - return defer.DeferredList([ - defer.maybeDeferred(port1.stopListening), - defer.maybeDeferred(self.port2.stopListening)], - fireOnOneErrback=True) - - d.addCallback(cbFinished) - return d - - - - def test_connectionRefused(self): - """ - A L{ConnectionRefusedError} exception is raised when a connection - attempt is actively refused by the other end. - - Note: This test assumes no one is listening on port 80 UDP. - """ - client = GoodClient() - clientStarted = client.startedDeferred = defer.Deferred() - port = reactor.listenUDP(0, client, interface="127.0.0.1") - - server = Server() - serverStarted = server.startedDeferred = defer.Deferred() - port2 = reactor.listenUDP(0, server, interface="127.0.0.1") - - d = defer.DeferredList( - [clientStarted, serverStarted], - fireOnOneErrback=True) - - def cbStarted(ignored): - connectionRefused = client.startedDeferred = defer.Deferred() - client.transport.connect("127.0.0.1", 80) - - for i in range(10): - client.transport.write(intToBytes(i)) - server.transport.write(intToBytes(i), ("127.0.0.1", 80)) - - return self.assertFailure( - connectionRefused, - error.ConnectionRefusedError) - - d.addCallback(cbStarted) - - def cbFinished(ignored): - return defer.DeferredList([ - defer.maybeDeferred(port.stopListening), - defer.maybeDeferred(port2.stopListening)], - fireOnOneErrback=True) - - d.addCallback(cbFinished) - return d - - - def test_badConnect(self): - """ - A call to the transport's connect method fails with an - L{InvalidAddressError} when a non-IP address is passed as the host - value. - - A call to a transport's connect method fails with a L{RuntimeError} - when the transport is already connected. - """ - client = GoodClient() - port = reactor.listenUDP(0, client, interface="127.0.0.1") - self.assertRaises(error.InvalidAddressError, client.transport.connect, - "localhost", 80) - client.transport.connect("127.0.0.1", 80) - self.assertRaises(RuntimeError, client.transport.connect, - "127.0.0.1", 80) - return port.stopListening() - - - - def test_datagramReceivedError(self): - """ - When datagramReceived raises an exception it is logged but the port - is not disconnected. - """ - finalDeferred = defer.Deferred() - - def cbCompleted(ign): - """ - Flush the exceptions which the reactor should have logged and make - sure they're actually there. - """ - errs = self.flushLoggedErrors(BadClientError) - self.assertEqual(len(errs), 2, "Incorrectly found %d errors, expected 2" % (len(errs),)) - finalDeferred.addCallback(cbCompleted) - - client = BadClient() - port = reactor.listenUDP(0, client, interface='127.0.0.1') - - def cbCleanup(result): - """ - Disconnect the port we started and pass on whatever was given to us - in case it was a Failure. - """ - return defer.maybeDeferred(port.stopListening).addBoth(lambda ign: result) - finalDeferred.addBoth(cbCleanup) - - addr = port.getHost() - - # UDP is not reliable. Try to send as many as 60 packets before giving - # up. Conceivably, all sixty could be lost, but they probably won't be - # unless all UDP traffic is being dropped, and then the rest of these - # UDP tests will likely fail as well. Ideally, this test (and probably - # others) wouldn't even use actual UDP traffic: instead, they would - # stub out the socket with a fake one which could be made to behave in - # whatever way the test desires. Unfortunately, this is hard because - # of differences in various reactor implementations. - attempts = list(range(60)) - succeededAttempts = [] - - def makeAttempt(): - """ - Send one packet to the listening BadClient. Set up a 0.1 second - timeout to do re-transmits in case the packet is dropped. When two - packets have been received by the BadClient, stop sending and let - the finalDeferred's callbacks do some assertions. - """ - if not attempts: - try: - self.fail("Not enough packets received") - except: - finalDeferred.errback() - - self.failIfIdentical(client.transport, None, "UDP Protocol lost its transport") - - packet = intToBytes(attempts.pop(0)) - packetDeferred = defer.Deferred() - client.setDeferred(packetDeferred) - client.transport.write(packet, (addr.host, addr.port)) - - def cbPacketReceived(packet): - """ - A packet arrived. Cancel the timeout for it, record it, and - maybe finish the test. - """ - timeoutCall.cancel() - succeededAttempts.append(packet) - if len(succeededAttempts) == 2: - # The second error has not yet been logged, since the - # exception which causes it hasn't even been raised yet. - # Give the datagramReceived call a chance to finish, then - # let the test finish asserting things. - reactor.callLater(0, finalDeferred.callback, None) - else: - makeAttempt() - - def ebPacketTimeout(err): - """ - The packet wasn't received quickly enough. Try sending another - one. It doesn't matter if the packet for which this was the - timeout eventually arrives: makeAttempt throws away the - Deferred on which this function is the errback, so when - datagramReceived callbacks, so it won't be on this Deferred, so - it won't raise an AlreadyCalledError. - """ - makeAttempt() - - packetDeferred.addCallbacks(cbPacketReceived, ebPacketTimeout) - packetDeferred.addErrback(finalDeferred.errback) - - timeoutCall = reactor.callLater( - 0.1, packetDeferred.errback, - error.TimeoutError( - "Timed out in testDatagramReceivedError")) - - makeAttempt() - return finalDeferred - - - def test_NoWarningOnBroadcast(self): - """ - C{''} is an alternative way to say C{'255.255.255.255'} - ({socket.gethostbyname("")} returns C{'255.255.255.255'}), - so because it becomes a valid IP address, no deprecation warning about - passing hostnames to L{twisted.internet.udp.Port.write} needs to be - emitted by C{write()} in this case. - """ - class fakeSocket: - def sendto(self, foo, bar): - pass - - p = udp.Port(0, Server()) - p.socket = fakeSocket() - p.write(b"test", ("", 1234)) - - warnings = self.flushWarnings([self.test_NoWarningOnBroadcast]) - self.assertEqual(len(warnings), 0) - - - -class ReactorShutdownInteractionTests(unittest.TestCase): - """Test reactor shutdown interaction""" - - def setUp(self): - """Start a UDP port""" - self.server = Server() - self.port = reactor.listenUDP(0, self.server, interface='127.0.0.1') - - def tearDown(self): - """Stop the UDP port""" - return self.port.stopListening() - - def testShutdownFromDatagramReceived(self): - """Test reactor shutdown while in a recvfrom() loop""" - - # udp.Port's doRead calls recvfrom() in a loop, as an optimization. - # It is important this loop terminate under various conditions. - # Previously, if datagramReceived synchronously invoked - # reactor.stop(), under certain reactors, the Port's socket would - # synchronously disappear, causing an AttributeError inside that - # loop. This was mishandled, causing the loop to spin forever. - # This test is primarily to ensure that the loop never spins - # forever. - - finished = defer.Deferred() - pr = self.server.packetReceived = defer.Deferred() - - def pktRece(ignored): - # Simulate reactor.stop() behavior :( - self.server.transport.connectionLost() - # Then delay this Deferred chain until the protocol has been - # disconnected, as the reactor should do in an error condition - # such as we are inducing. This is very much a whitebox test. - reactor.callLater(0, finished.callback, None) - pr.addCallback(pktRece) - - def flushErrors(ignored): - # We are breaking abstraction and calling private APIs, any - # number of horrible errors might occur. As long as the reactor - # doesn't hang, this test is satisfied. (There may be room for - # another, stricter test.) - self.flushLoggedErrors() - finished.addCallback(flushErrors) - self.server.transport.write(b'\0' * 64, ('127.0.0.1', - self.server.transport.getHost().port)) - return finished - - - -class MulticastTests(unittest.TestCase): - - def setUp(self): - self.server = Server() - self.client = Client() - # multicast won't work if we listen over loopback, apparently - self.port1 = reactor.listenMulticast(0, self.server) - self.port2 = reactor.listenMulticast(0, self.client) - self.client.transport.connect( - "127.0.0.1", self.server.transport.getHost().port) - - - def tearDown(self): - return gatherResults([ - maybeDeferred(self.port1.stopListening), - maybeDeferred(self.port2.stopListening)]) - - - def testTTL(self): - for o in self.client, self.server: - self.assertEqual(o.transport.getTTL(), 1) - o.transport.setTTL(2) - self.assertEqual(o.transport.getTTL(), 2) - - - def test_loopback(self): - """ - Test that after loopback mode has been set, multicast packets are - delivered to their sender. - """ - self.assertEqual(self.server.transport.getLoopbackMode(), 1) - addr = self.server.transport.getHost() - joined = self.server.transport.joinGroup("225.0.0.250") - - def cbJoined(ignored): - d = self.server.packetReceived = Deferred() - self.server.transport.write(b"hello", ("225.0.0.250", addr.port)) - return d - joined.addCallback(cbJoined) - - def cbPacket(ignored): - self.assertEqual(len(self.server.packets), 1) - self.server.transport.setLoopbackMode(0) - self.assertEqual(self.server.transport.getLoopbackMode(), 0) - self.server.transport.write(b"hello", ("225.0.0.250", addr.port)) - - # This is fairly lame. - d = Deferred() - reactor.callLater(0, d.callback, None) - return d - joined.addCallback(cbPacket) - - def cbNoPacket(ignored): - self.assertEqual(len(self.server.packets), 1) - joined.addCallback(cbNoPacket) - - return joined - - - def test_interface(self): - """ - Test C{getOutgoingInterface} and C{setOutgoingInterface}. - """ - self.assertEqual( - self.client.transport.getOutgoingInterface(), "0.0.0.0") - self.assertEqual( - self.server.transport.getOutgoingInterface(), "0.0.0.0") - - d1 = self.client.transport.setOutgoingInterface("127.0.0.1") - d2 = self.server.transport.setOutgoingInterface("127.0.0.1") - result = gatherResults([d1, d2]) - - def cbInterfaces(ignored): - self.assertEqual( - self.client.transport.getOutgoingInterface(), "127.0.0.1") - self.assertEqual( - self.server.transport.getOutgoingInterface(), "127.0.0.1") - result.addCallback(cbInterfaces) - return result - - - def test_joinLeave(self): - """ - Test that multicast a group can be joined and left. - """ - d = self.client.transport.joinGroup("225.0.0.250") - - def clientJoined(ignored): - return self.client.transport.leaveGroup("225.0.0.250") - d.addCallback(clientJoined) - - def clientLeft(ignored): - return self.server.transport.joinGroup("225.0.0.250") - d.addCallback(clientLeft) - - def serverJoined(ignored): - return self.server.transport.leaveGroup("225.0.0.250") - d.addCallback(serverJoined) - - return d - - - def test_joinFailure(self): - """ - Test that an attempt to join an address which is not a multicast - address fails with L{error.MulticastJoinError}. - """ - # 127.0.0.1 is not a multicast address, so joining it should fail. - return self.assertFailure( - self.client.transport.joinGroup("127.0.0.1"), - error.MulticastJoinError) - if runtime.platform.isWindows() and not runtime.platform.isVista(): - # FIXME: https://twistedmatrix.com/trac/ticket/7780 - test_joinFailure.skip = ( - "Windows' UDP multicast is not yet fully supported.") - - - def test_multicast(self): - """ - Test that a multicast group can be joined and messages sent to and - received from it. - """ - c = Server() - p = reactor.listenMulticast(0, c) - addr = self.server.transport.getHost() - - joined = self.server.transport.joinGroup("225.0.0.250") - - def cbJoined(ignored): - d = self.server.packetReceived = Deferred() - c.transport.write(b"hello world", ("225.0.0.250", addr.port)) - return d - joined.addCallback(cbJoined) - - def cbPacket(ignored): - self.assertEqual(self.server.packets[0][0], b"hello world") - joined.addCallback(cbPacket) - - def cleanup(passthrough): - result = maybeDeferred(p.stopListening) - result.addCallback(lambda ign: passthrough) - return result - joined.addCallback(cleanup) - - return joined - - - def test_multiListen(self): - """ - Test that multiple sockets can listen on the same multicast port and - that they both receive multicast messages directed to that address. - """ - firstClient = Server() - firstPort = reactor.listenMulticast( - 0, firstClient, listenMultiple=True) - - portno = firstPort.getHost().port - - secondClient = Server() - secondPort = reactor.listenMulticast( - portno, secondClient, listenMultiple=True) - - theGroup = "225.0.0.250" - joined = gatherResults([self.server.transport.joinGroup(theGroup), - firstPort.joinGroup(theGroup), - secondPort.joinGroup(theGroup)]) - - - def serverJoined(ignored): - d1 = firstClient.packetReceived = Deferred() - d2 = secondClient.packetReceived = Deferred() - firstClient.transport.write(b"hello world", (theGroup, portno)) - return gatherResults([d1, d2]) - joined.addCallback(serverJoined) - - def gotPackets(ignored): - self.assertEqual(firstClient.packets[0][0], b"hello world") - self.assertEqual(secondClient.packets[0][0], b"hello world") - joined.addCallback(gotPackets) - - def cleanup(passthrough): - result = gatherResults([ - maybeDeferred(firstPort.stopListening), - maybeDeferred(secondPort.stopListening)]) - result.addCallback(lambda ign: passthrough) - return result - joined.addBoth(cleanup) - return joined - if runtime.platform.isWindows(): - test_multiListen.skip = ("on non-linux platforms it appears multiple " - "processes can listen, but not multiple sockets " - "in same process?") - - -if not interfaces.IReactorUDP(reactor, None): - UDPTests.skip = "This reactor does not support UDP" - ReactorShutdownInteractionTests.skip = "This reactor does not support UDP" -if not interfaces.IReactorMulticast(reactor, None): - MulticastTests.skip = "This reactor does not support multicast" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_unix.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_unix.py deleted file mode 100644 index c2f39ab..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_unix.py +++ /dev/null @@ -1,405 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for implementations of L{IReactorUNIX} and L{IReactorUNIXDatagram}. -""" - -import os, sys, types -import socket - -from twisted.internet import interfaces, reactor, protocol, error, address, defer, utils -from twisted.python import lockfile -from twisted.trial import unittest - -from twisted.test.test_tcp import MyServerFactory, MyClientFactory - - -class FailedConnectionClientFactory(protocol.ClientFactory): - def __init__(self, onFail): - self.onFail = onFail - - def clientConnectionFailed(self, connector, reason): - self.onFail.errback(reason) - - - -class UnixSocketTests(unittest.TestCase): - """ - Test unix sockets. - """ - def test_peerBind(self): - """ - The address passed to the server factory's C{buildProtocol} method and - the address returned by the connected protocol's transport's C{getPeer} - method match the address the client socket is bound to. - """ - filename = self.mktemp() - peername = self.mktemp() - serverFactory = MyServerFactory() - connMade = serverFactory.protocolConnectionMade = defer.Deferred() - unixPort = reactor.listenUNIX(filename, serverFactory) - self.addCleanup(unixPort.stopListening) - unixSocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.addCleanup(unixSocket.close) - unixSocket.bind(peername) - unixSocket.connect(filename) - def cbConnMade(proto): - expected = address.UNIXAddress(peername) - self.assertEqual(serverFactory.peerAddresses, [expected]) - self.assertEqual(proto.transport.getPeer(), expected) - connMade.addCallback(cbConnMade) - return connMade - - - def test_dumber(self): - """ - L{IReactorUNIX.connectUNIX} can be used to connect a client to a server - started with L{IReactorUNIX.listenUNIX}. - """ - filename = self.mktemp() - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - unixPort = reactor.listenUNIX(filename, serverFactory) - self.addCleanup(unixPort.stopListening) - clientFactory = MyClientFactory() - clientConnMade = defer.Deferred() - clientFactory.protocolConnectionMade = clientConnMade - reactor.connectUNIX(filename, clientFactory) - d = defer.gatherResults([serverConnMade, clientConnMade]) - def allConnected((serverProtocol, clientProtocol)): - - # Incidental assertion which may or may not be redundant with some - # other test. This probably deserves its own test method. - self.assertEqual(clientFactory.peerAddresses, - [address.UNIXAddress(filename)]) - - clientProtocol.transport.loseConnection() - serverProtocol.transport.loseConnection() - d.addCallback(allConnected) - return d - - - def test_pidFile(self): - """ - A lockfile is created and locked when L{IReactorUNIX.listenUNIX} is - called and released when the Deferred returned by the L{IListeningPort} - provider's C{stopListening} method is called back. - """ - filename = self.mktemp() - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - unixPort = reactor.listenUNIX(filename, serverFactory, wantPID=True) - self.assertTrue(lockfile.isLocked(filename + ".lock")) - - # XXX This part would test something about the checkPID parameter, but - # it doesn't actually. It should be rewritten to test the several - # different possible behaviors. -exarkun - clientFactory = MyClientFactory() - clientConnMade = defer.Deferred() - clientFactory.protocolConnectionMade = clientConnMade - reactor.connectUNIX(filename, clientFactory, checkPID=1) - - d = defer.gatherResults([serverConnMade, clientConnMade]) - def _portStuff((serverProtocol, clientProto)): - - # Incidental assertion which may or may not be redundant with some - # other test. This probably deserves its own test method. - self.assertEqual(clientFactory.peerAddresses, - [address.UNIXAddress(filename)]) - - clientProto.transport.loseConnection() - serverProtocol.transport.loseConnection() - return unixPort.stopListening() - d.addCallback(_portStuff) - - def _check(ignored): - self.failIf(lockfile.isLocked(filename + ".lock"), 'locked') - d.addCallback(_check) - return d - - - def test_socketLocking(self): - """ - L{IReactorUNIX.listenUNIX} raises L{error.CannotListenError} if passed - the name of a file on which a server is already listening. - """ - filename = self.mktemp() - serverFactory = MyServerFactory() - unixPort = reactor.listenUNIX(filename, serverFactory, wantPID=True) - - self.assertRaises( - error.CannotListenError, - reactor.listenUNIX, filename, serverFactory, wantPID=True) - - def stoppedListening(ign): - unixPort = reactor.listenUNIX(filename, serverFactory, wantPID=True) - return unixPort.stopListening() - - return unixPort.stopListening().addCallback(stoppedListening) - - - def _uncleanSocketTest(self, callback): - self.filename = self.mktemp() - source = ("from twisted.internet import protocol, reactor\n" - "reactor.listenUNIX(%r, protocol.ServerFactory(), wantPID=True)\n") % (self.filename,) - env = {'PYTHONPATH': os.pathsep.join(sys.path)} - - d = utils.getProcessValue(sys.executable, ("-u", "-c", source), env=env) - d.addCallback(callback) - return d - - - def test_uncleanServerSocketLocking(self): - """ - If passed C{True} for the C{wantPID} parameter, a server can be started - listening with L{IReactorUNIX.listenUNIX} when passed the name of a - file on which a previous server which has not exited cleanly has been - listening using the C{wantPID} option. - """ - def ranStupidChild(ign): - # If this next call succeeds, our lock handling is correct. - p = reactor.listenUNIX(self.filename, MyServerFactory(), wantPID=True) - return p.stopListening() - return self._uncleanSocketTest(ranStupidChild) - - - def test_connectToUncleanServer(self): - """ - If passed C{True} for the C{checkPID} parameter, a client connection - attempt made with L{IReactorUNIX.connectUNIX} fails with - L{error.BadFileError}. - """ - def ranStupidChild(ign): - d = defer.Deferred() - f = FailedConnectionClientFactory(d) - reactor.connectUNIX(self.filename, f, checkPID=True) - return self.assertFailure(d, error.BadFileError) - return self._uncleanSocketTest(ranStupidChild) - - - def _reprTest(self, serverFactory, factoryName): - """ - Test the C{__str__} and C{__repr__} implementations of a UNIX port when - used with the given factory. - """ - filename = self.mktemp() - unixPort = reactor.listenUNIX(filename, serverFactory) - - connectedString = "<%s on %r>" % (factoryName, filename) - self.assertEqual(repr(unixPort), connectedString) - self.assertEqual(str(unixPort), connectedString) - - d = defer.maybeDeferred(unixPort.stopListening) - def stoppedListening(ign): - unconnectedString = "<%s (not listening)>" % (factoryName,) - self.assertEqual(repr(unixPort), unconnectedString) - self.assertEqual(str(unixPort), unconnectedString) - d.addCallback(stoppedListening) - return d - - - def test_reprWithClassicFactory(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIX.listenUNIX} contains the name of the classic factory - class being used and the filename on which the port is listening or - indicates that the port is not listening. - """ - class ClassicFactory: - def doStart(self): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(ClassicFactory, types.ClassType) - - return self._reprTest( - ClassicFactory(), "twisted.test.test_unix.ClassicFactory") - - - def test_reprWithNewStyleFactory(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIX.listenUNIX} contains the name of the new-style factory - class being used and the filename on which the port is listening or - indicates that the port is not listening. - """ - class NewStyleFactory(object): - def doStart(self): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(NewStyleFactory, type) - - return self._reprTest( - NewStyleFactory(), "twisted.test.test_unix.NewStyleFactory") - - - -class ClientProto(protocol.ConnectedDatagramProtocol): - started = stopped = False - gotback = None - - def __init__(self): - self.deferredStarted = defer.Deferred() - self.deferredGotBack = defer.Deferred() - - def stopProtocol(self): - self.stopped = True - - def startProtocol(self): - self.started = True - self.deferredStarted.callback(None) - - def datagramReceived(self, data): - self.gotback = data - self.deferredGotBack.callback(None) - -class ServerProto(protocol.DatagramProtocol): - started = stopped = False - gotwhat = gotfrom = None - - def __init__(self): - self.deferredStarted = defer.Deferred() - self.deferredGotWhat = defer.Deferred() - - def stopProtocol(self): - self.stopped = True - - def startProtocol(self): - self.started = True - self.deferredStarted.callback(None) - - def datagramReceived(self, data, addr): - self.gotfrom = addr - self.transport.write("hi back", addr) - self.gotwhat = data - self.deferredGotWhat.callback(None) - - - -class DatagramUnixSocketTests(unittest.TestCase): - """ - Test datagram UNIX sockets. - """ - def test_exchange(self): - """ - Test that a datagram can be sent to and received by a server and vice - versa. - """ - clientaddr = self.mktemp() - serveraddr = self.mktemp() - sp = ServerProto() - cp = ClientProto() - s = reactor.listenUNIXDatagram(serveraddr, sp) - self.addCleanup(s.stopListening) - c = reactor.connectUNIXDatagram(serveraddr, cp, bindAddress=clientaddr) - self.addCleanup(c.stopListening) - - d = defer.gatherResults([sp.deferredStarted, cp.deferredStarted]) - def write(ignored): - cp.transport.write("hi") - return defer.gatherResults([sp.deferredGotWhat, - cp.deferredGotBack]) - - def _cbTestExchange(ignored): - self.assertEqual("hi", sp.gotwhat) - self.assertEqual(clientaddr, sp.gotfrom) - self.assertEqual("hi back", cp.gotback) - - d.addCallback(write) - d.addCallback(_cbTestExchange) - return d - - - def test_cannotListen(self): - """ - L{IReactorUNIXDatagram.listenUNIXDatagram} raises - L{error.CannotListenError} if the unix socket specified is already in - use. - """ - addr = self.mktemp() - p = ServerProto() - s = reactor.listenUNIXDatagram(addr, p) - self.failUnlessRaises(error.CannotListenError, reactor.listenUNIXDatagram, addr, p) - s.stopListening() - os.unlink(addr) - - # test connecting to bound and connected (somewhere else) address - - def _reprTest(self, serverProto, protocolName): - """ - Test the C{__str__} and C{__repr__} implementations of a UNIX datagram - port when used with the given protocol. - """ - filename = self.mktemp() - unixPort = reactor.listenUNIXDatagram(filename, serverProto) - - connectedString = "<%s on %r>" % (protocolName, filename) - self.assertEqual(repr(unixPort), connectedString) - self.assertEqual(str(unixPort), connectedString) - - stopDeferred = defer.maybeDeferred(unixPort.stopListening) - def stoppedListening(ign): - unconnectedString = "<%s (not listening)>" % (protocolName,) - self.assertEqual(repr(unixPort), unconnectedString) - self.assertEqual(str(unixPort), unconnectedString) - stopDeferred.addCallback(stoppedListening) - return stopDeferred - - - def test_reprWithClassicProtocol(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIXDatagram.listenUNIXDatagram} contains the name of the - classic protocol class being used and the filename on which the port is - listening or indicates that the port is not listening. - """ - class ClassicProtocol: - def makeConnection(self, transport): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(ClassicProtocol, types.ClassType) - - return self._reprTest( - ClassicProtocol(), "twisted.test.test_unix.ClassicProtocol") - - - def test_reprWithNewStyleProtocol(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIXDatagram.listenUNIXDatagram} contains the name of the - new-style protocol class being used and the filename on which the port - is listening or indicates that the port is not listening. - """ - class NewStyleProtocol(object): - def makeConnection(self, transport): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(NewStyleProtocol, type) - - return self._reprTest( - NewStyleProtocol(), "twisted.test.test_unix.NewStyleProtocol") - - - -if not interfaces.IReactorUNIX(reactor, None): - UnixSocketTests.skip = "This reactor does not support UNIX domain sockets" -if not interfaces.IReactorUNIXDatagram(reactor, None): - DatagramUnixSocketTests.skip = "This reactor does not support UNIX datagram sockets" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_usage.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_usage.py deleted file mode 100644 index 28f2091..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/test_usage.py +++ /dev/null @@ -1,715 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.usage}, a command line option parsing library. -""" - -from __future__ import division, absolute_import - -from twisted.trial import unittest -from twisted.python import usage - - -class WellBehaved(usage.Options): - optParameters = [['long', 'w', 'default', 'and a docstring'], - ['another', 'n', 'no docstring'], - ['longonly', None, 'noshort'], - ['shortless', None, 'except', - 'this one got docstring'], - ] - optFlags = [['aflag', 'f', - """ - - flagallicious docstringness for this here - - """], - ['flout', 'o'], - ] - - def opt_myflag(self): - self.opts['myflag'] = "PONY!" - - - def opt_myparam(self, value): - self.opts['myparam'] = "%s WITH A PONY!" % (value,) - - - -class ParseCorrectnessTests(unittest.TestCase): - """ - Test L{usage.Options.parseOptions} for correct values under - good conditions. - """ - def setUp(self): - """ - Instantiate and parseOptions a well-behaved Options class. - """ - - self.niceArgV = ("--long Alpha -n Beta " - "--shortless Gamma -f --myflag " - "--myparam Tofu").split() - - self.nice = WellBehaved() - - self.nice.parseOptions(self.niceArgV) - - def test_checkParameters(self): - """ - Parameters have correct values. - """ - self.assertEqual(self.nice.opts['long'], "Alpha") - self.assertEqual(self.nice.opts['another'], "Beta") - self.assertEqual(self.nice.opts['longonly'], "noshort") - self.assertEqual(self.nice.opts['shortless'], "Gamma") - - def test_checkFlags(self): - """ - Flags have correct values. - """ - self.assertEqual(self.nice.opts['aflag'], 1) - self.assertEqual(self.nice.opts['flout'], 0) - - def test_checkCustoms(self): - """ - Custom flags and parameters have correct values. - """ - self.assertEqual(self.nice.opts['myflag'], "PONY!") - self.assertEqual(self.nice.opts['myparam'], "Tofu WITH A PONY!") - - - -class TypedOptions(usage.Options): - optParameters = [ - ['fooint', None, 392, 'Foo int', int], - ['foofloat', None, 4.23, 'Foo float', float], - ['eggint', None, None, 'Egg int without default', int], - ['eggfloat', None, None, 'Egg float without default', float], - ] - - def opt_under_score(self, value): - """ - This option has an underscore in its name to exercise the _ to - - translation. - """ - self.underscoreValue = value - opt_u = opt_under_score - - - -class TypedTests(unittest.TestCase): - """ - Test L{usage.Options.parseOptions} for options with forced types. - """ - def setUp(self): - self.usage = TypedOptions() - - def test_defaultValues(self): - """ - Default values are parsed. - """ - argV = [] - self.usage.parseOptions(argV) - self.assertEqual(self.usage.opts['fooint'], 392) - self.assert_(isinstance(self.usage.opts['fooint'], int)) - self.assertEqual(self.usage.opts['foofloat'], 4.23) - self.assert_(isinstance(self.usage.opts['foofloat'], float)) - self.assertEqual(self.usage.opts['eggint'], None) - self.assertEqual(self.usage.opts['eggfloat'], None) - - - def test_parsingValues(self): - """ - int and float values are parsed. - """ - argV = ("--fooint 912 --foofloat -823.1 " - "--eggint 32 --eggfloat 21").split() - self.usage.parseOptions(argV) - self.assertEqual(self.usage.opts['fooint'], 912) - self.assert_(isinstance(self.usage.opts['fooint'], int)) - self.assertEqual(self.usage.opts['foofloat'], -823.1) - self.assert_(isinstance(self.usage.opts['foofloat'], float)) - self.assertEqual(self.usage.opts['eggint'], 32) - self.assert_(isinstance(self.usage.opts['eggint'], int)) - self.assertEqual(self.usage.opts['eggfloat'], 21.) - self.assert_(isinstance(self.usage.opts['eggfloat'], float)) - - - def test_underscoreOption(self): - """ - A dash in an option name is translated to an underscore before being - dispatched to a handler. - """ - self.usage.parseOptions(['--under-score', 'foo']) - self.assertEqual(self.usage.underscoreValue, 'foo') - - - def test_underscoreOptionAlias(self): - """ - An option name with a dash in it can have an alias. - """ - self.usage.parseOptions(['-u', 'bar']) - self.assertEqual(self.usage.underscoreValue, 'bar') - - - def test_invalidValues(self): - """ - Passing wrong values raises an error. - """ - argV = "--fooint egg".split() - self.assertRaises(usage.UsageError, self.usage.parseOptions, argV) - - - -class WrongTypedOptions(usage.Options): - optParameters = [ - ['barwrong', None, None, 'Bar with wrong coerce', 'he'] - ] - - -class WeirdCallableOptions(usage.Options): - def _bar(value): - raise RuntimeError("Ouch") - def _foo(value): - raise ValueError("Yay") - optParameters = [ - ['barwrong', None, None, 'Bar with strange callable', _bar], - ['foowrong', None, None, 'Foo with strange callable', _foo] - ] - - -class WrongTypedTests(unittest.TestCase): - """ - Test L{usage.Options.parseOptions} for wrong coerce options. - """ - def test_nonCallable(self): - """ - Using a non-callable type fails. - """ - us = WrongTypedOptions() - argV = "--barwrong egg".split() - self.assertRaises(TypeError, us.parseOptions, argV) - - def test_notCalledInDefault(self): - """ - The coerce functions are not called if no values are provided. - """ - us = WeirdCallableOptions() - argV = [] - us.parseOptions(argV) - - def test_weirdCallable(self): - """ - Errors raised by coerce functions are handled properly. - """ - us = WeirdCallableOptions() - argV = "--foowrong blah".split() - # ValueError is swallowed as UsageError - e = self.assertRaises(usage.UsageError, us.parseOptions, argV) - self.assertEqual(str(e), "Parameter type enforcement failed: Yay") - - us = WeirdCallableOptions() - argV = "--barwrong blah".split() - # RuntimeError is not swallowed - self.assertRaises(RuntimeError, us.parseOptions, argV) - - -class OutputTests(unittest.TestCase): - def test_uppercasing(self): - """ - Error output case adjustment does not mangle options - """ - opt = WellBehaved() - e = self.assertRaises(usage.UsageError, - opt.parseOptions, ['-Z']) - self.assertEqual(str(e), 'option -Z not recognized') - - -class InquisitionOptions(usage.Options): - optFlags = [ - ('expect', 'e'), - ] - optParameters = [ - ('torture-device', 't', - 'comfy-chair', - 'set preferred torture device'), - ] - - -class HolyQuestOptions(usage.Options): - optFlags = [('horseback', 'h', - 'use a horse'), - ('for-grail', 'g'), - ] - - -class SubCommandOptions(usage.Options): - optFlags = [('europian-swallow', None, - 'set default swallow type to Europian'), - ] - subCommands = [ - ('inquisition', 'inquest', InquisitionOptions, - 'Perform an inquisition'), - ('holyquest', 'quest', HolyQuestOptions, - 'Embark upon a holy quest'), - ] - - -class SubCommandTests(unittest.TestCase): - """ - Test L{usage.Options.parseOptions} for options with subcommands. - """ - def test_simpleSubcommand(self): - """ - A subcommand is recognized. - """ - o = SubCommandOptions() - o.parseOptions(['--europian-swallow', 'inquisition']) - self.assertEqual(o['europian-swallow'], True) - self.assertEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.assertEqual(o.subOptions['expect'], False) - self.assertEqual(o.subOptions['torture-device'], 'comfy-chair') - - def test_subcommandWithFlagsAndOptions(self): - """ - Flags and options of a subcommand are assigned. - """ - o = SubCommandOptions() - o.parseOptions(['inquisition', '--expect', '--torture-device=feather']) - self.assertEqual(o['europian-swallow'], False) - self.assertEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.assertEqual(o.subOptions['expect'], True) - self.assertEqual(o.subOptions['torture-device'], 'feather') - - def test_subcommandAliasWithFlagsAndOptions(self): - """ - Flags and options of a subcommand alias are assigned. - """ - o = SubCommandOptions() - o.parseOptions(['inquest', '--expect', '--torture-device=feather']) - self.assertEqual(o['europian-swallow'], False) - self.assertEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.assertEqual(o.subOptions['expect'], True) - self.assertEqual(o.subOptions['torture-device'], 'feather') - - def test_anotherSubcommandWithFlagsAndOptions(self): - """ - Flags and options of another subcommand are assigned. - """ - o = SubCommandOptions() - o.parseOptions(['holyquest', '--for-grail']) - self.assertEqual(o['europian-swallow'], False) - self.assertEqual(o.subCommand, 'holyquest') - self.failUnless(isinstance(o.subOptions, HolyQuestOptions)) - self.assertEqual(o.subOptions['horseback'], False) - self.assertEqual(o.subOptions['for-grail'], True) - - def test_noSubcommand(self): - """ - If no subcommand is specified and no default subcommand is assigned, - a subcommand will not be implied. - """ - o = SubCommandOptions() - o.parseOptions(['--europian-swallow']) - self.assertEqual(o['europian-swallow'], True) - self.assertEqual(o.subCommand, None) - self.failIf(hasattr(o, 'subOptions')) - - def test_defaultSubcommand(self): - """ - Flags and options in the default subcommand are assigned. - """ - o = SubCommandOptions() - o.defaultSubCommand = 'inquest' - o.parseOptions(['--europian-swallow']) - self.assertEqual(o['europian-swallow'], True) - self.assertEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.assertEqual(o.subOptions['expect'], False) - self.assertEqual(o.subOptions['torture-device'], 'comfy-chair') - - def test_subCommandParseOptionsHasParent(self): - """ - The parseOptions method from the Options object specified for the - given subcommand is called. - """ - class SubOpt(usage.Options): - def parseOptions(self, *a, **kw): - self.sawParent = self.parent - usage.Options.parseOptions(self, *a, **kw) - class Opt(usage.Options): - subCommands = [ - ('foo', 'f', SubOpt, 'bar'), - ] - o = Opt() - o.parseOptions(['foo']) - self.failUnless(hasattr(o.subOptions, 'sawParent')) - self.assertEqual(o.subOptions.sawParent , o) - - def test_subCommandInTwoPlaces(self): - """ - The .parent pointer is correct even when the same Options class is - used twice. - """ - class SubOpt(usage.Options): - pass - class OptFoo(usage.Options): - subCommands = [ - ('foo', 'f', SubOpt, 'quux'), - ] - class OptBar(usage.Options): - subCommands = [ - ('bar', 'b', SubOpt, 'quux'), - ] - oFoo = OptFoo() - oFoo.parseOptions(['foo']) - oBar=OptBar() - oBar.parseOptions(['bar']) - self.failUnless(hasattr(oFoo.subOptions, 'parent')) - self.failUnless(hasattr(oBar.subOptions, 'parent')) - self.failUnlessIdentical(oFoo.subOptions.parent, oFoo) - self.failUnlessIdentical(oBar.subOptions.parent, oBar) - - -class HelpStringTests(unittest.TestCase): - """ - Test generated help strings. - """ - def setUp(self): - """ - Instantiate a well-behaved Options class. - """ - - self.niceArgV = ("--long Alpha -n Beta " - "--shortless Gamma -f --myflag " - "--myparam Tofu").split() - - self.nice = WellBehaved() - - def test_noGoBoom(self): - """ - __str__ shouldn't go boom. - """ - try: - self.nice.__str__() - except Exception as e: - self.fail(e) - - def test_whitespaceStripFlagsAndParameters(self): - """ - Extra whitespace in flag and parameters docs is stripped. - """ - # We test this by making sure aflag and it's help string are on the - # same line. - lines = [s for s in str(self.nice).splitlines() if s.find("aflag")>=0] - self.failUnless(len(lines) > 0) - self.failUnless(lines[0].find("flagallicious") >= 0) - - -class PortCoerceTests(unittest.TestCase): - """ - Test the behavior of L{usage.portCoerce}. - """ - def test_validCoerce(self): - """ - Test the answers with valid input. - """ - self.assertEqual(0, usage.portCoerce("0")) - self.assertEqual(3210, usage.portCoerce("3210")) - self.assertEqual(65535, usage.portCoerce("65535")) - - def test_errorCoerce(self): - """ - Test error path. - """ - self.assertRaises(ValueError, usage.portCoerce, "") - self.assertRaises(ValueError, usage.portCoerce, "-21") - self.assertRaises(ValueError, usage.portCoerce, "212189") - self.assertRaises(ValueError, usage.portCoerce, "foo") - - - -class ZshCompleterTests(unittest.TestCase): - """ - Test the behavior of the various L{twisted.usage.Completer} classes - for producing output usable by zsh tab-completion system. - """ - def test_completer(self): - """ - Completer produces zsh shell-code that produces no completion matches. - """ - c = usage.Completer() - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option:') - - c = usage.Completer(descr='some action', repeat=True) - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, '*:some action:') - - - def test_files(self): - """ - CompleteFiles produces zsh shell-code that completes file names - according to a glob. - """ - c = usage.CompleteFiles() - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option (*):_files -g "*"') - - c = usage.CompleteFiles('*.py') - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option (*.py):_files -g "*.py"') - - c = usage.CompleteFiles('*.py', descr="some action", repeat=True) - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, '*:some action (*.py):_files -g "*.py"') - - - def test_dirs(self): - """ - CompleteDirs produces zsh shell-code that completes directory names. - """ - c = usage.CompleteDirs() - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option:_directories') - - c = usage.CompleteDirs(descr="some action", repeat=True) - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, '*:some action:_directories') - - - def test_list(self): - """ - CompleteList produces zsh shell-code that completes words from a fixed - list of possibilities. - """ - c = usage.CompleteList('ABC') - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option:(A B C)') - - c = usage.CompleteList(['1', '2', '3']) - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option:(1 2 3)') - - c = usage.CompleteList(['1', '2', '3'], descr='some action', - repeat=True) - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, '*:some action:(1 2 3)') - - - def test_multiList(self): - """ - CompleteMultiList produces zsh shell-code that completes multiple - comma-separated words from a fixed list of possibilities. - """ - c = usage.CompleteMultiList('ABC') - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option:_values -s , \'some-option\' A B C') - - c = usage.CompleteMultiList(['1','2','3']) - got = c._shellCode('some-option', usage._ZSH) - self.assertEqual(got, ':some-option:_values -s , \'some-option\' 1 2 3') - - c = usage.CompleteMultiList(['1','2','3'], descr='some action', - repeat=True) - got = c._shellCode('some-option', usage._ZSH) - expected = '*:some action:_values -s , \'some action\' 1 2 3' - self.assertEqual(got, expected) - - - def test_usernames(self): - """ - CompleteUsernames produces zsh shell-code that completes system - usernames. - """ - c = usage.CompleteUsernames() - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, ':some-option:_users') - - c = usage.CompleteUsernames(descr='some action', repeat=True) - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, '*:some action:_users') - - - def test_groups(self): - """ - CompleteGroups produces zsh shell-code that completes system group - names. - """ - c = usage.CompleteGroups() - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, ':group:_groups') - - c = usage.CompleteGroups(descr='some action', repeat=True) - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, '*:some action:_groups') - - - def test_hostnames(self): - """ - CompleteHostnames produces zsh shell-code that completes hostnames. - """ - c = usage.CompleteHostnames() - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, ':some-option:_hosts') - - c = usage.CompleteHostnames(descr='some action', repeat=True) - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, '*:some action:_hosts') - - - def test_userAtHost(self): - """ - CompleteUserAtHost produces zsh shell-code that completes hostnames or - a word of the form @. - """ - c = usage.CompleteUserAtHost() - out = c._shellCode('some-option', usage._ZSH) - self.assertTrue(out.startswith(':host | user@host:')) - - c = usage.CompleteUserAtHost(descr='some action', repeat=True) - out = c._shellCode('some-option', usage._ZSH) - self.assertTrue(out.startswith('*:some action:')) - - - def test_netInterfaces(self): - """ - CompleteNetInterfaces produces zsh shell-code that completes system - network interface names. - """ - c = usage.CompleteNetInterfaces() - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, ':some-option:_net_interfaces') - - c = usage.CompleteNetInterfaces(descr='some action', repeat=True) - out = c._shellCode('some-option', usage._ZSH) - self.assertEqual(out, '*:some action:_net_interfaces') - - - -class CompleterNotImplementedTests(unittest.TestCase): - """ - Using an unknown shell constant with the various Completer() classes - should raise NotImplementedError - """ - def test_unknownShell(self): - """ - Using an unknown shellType should raise NotImplementedError - """ - classes = [usage.Completer, usage.CompleteFiles, - usage.CompleteDirs, usage.CompleteList, - usage.CompleteMultiList, usage.CompleteUsernames, - usage.CompleteGroups, usage.CompleteHostnames, - usage.CompleteUserAtHost, usage.CompleteNetInterfaces] - - for cls in classes: - try: - action = cls() - except: - action = cls(None) - self.assertRaises(NotImplementedError, action._shellCode, - None, "bad_shell_type") - - - -class FlagFunctionTests(unittest.TestCase): - """ - Tests for L{usage.flagFunction}. - """ - - class SomeClass(object): - """ - Dummy class for L{usage.flagFunction} tests. - """ - def oneArg(self, a): - """ - A one argument method to be tested by L{usage.flagFunction}. - - @param a: a useless argument to satisfy the function's signature. - """ - - def noArg(self): - """ - A no argument method to be tested by L{usage.flagFunction}. - """ - - def manyArgs(self, a, b, c): - """ - A multipe arguments method to be tested by L{usage.flagFunction}. - - @param a: a useless argument to satisfy the function's signature. - @param b: a useless argument to satisfy the function's signature. - @param c: a useless argument to satisfy the function's signature. - """ - - - def test_hasArg(self): - """ - L{usage.flagFunction} returns C{False} if the method checked allows - exactly one argument. - """ - self.assertIs(False, usage.flagFunction(self.SomeClass().oneArg)) - - - def test_noArg(self): - """ - L{usage.flagFunction} returns C{True} if the method checked allows - exactly no argument. - """ - self.assertIs(True, usage.flagFunction(self.SomeClass().noArg)) - - - def test_tooManyArguments(self): - """ - L{usage.flagFunction} raises L{usage.UsageError} if the method checked - allows more than one argument. - """ - exc = self.assertRaises( - usage.UsageError, usage.flagFunction, self.SomeClass().manyArgs) - self.assertEqual("Invalid Option function for manyArgs", str(exc)) - - - def test_tooManyArgumentsAndSpecificErrorMessage(self): - """ - L{usage.flagFunction} uses the given method name in the error message - raised when the method allows too many arguments. - """ - exc = self.assertRaises( - usage.UsageError, - usage.flagFunction, self.SomeClass().manyArgs, "flubuduf") - self.assertEqual("Invalid Option function for flubuduf", str(exc)) - - - -class OptionsInternalTests(unittest.TestCase): - """ - Tests internal behavior of C{usage.Options}. - """ - - def test_optionsAliasesOrder(self): - """ - Options which are synonyms to another option are aliases towards the - longest option name. - """ - class Opts(usage.Options): - def opt_very_very_long(self): - """ - This is a option method with a very long name, that is going to - be aliased. - """ - - opt_short = opt_very_very_long - opt_s = opt_very_very_long - - opts = Opts() - - self.assertEqual( - dict.fromkeys( - ["s", "short", "very-very-long"], "very-very-long"), { - "s": opts.synonyms["s"], - "short": opts.synonyms["short"], - "very-very-long": opts.synonyms["very-very-long"], - }) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/testutils.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/testutils.py deleted file mode 100644 index 045cb25..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/test/testutils.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -I{Private} test utilities for use throughout Twisted's test suite. Unlike -C{proto_helpers}, this is no exception to the -don't-use-it-outside-Twisted-we-won't-maintain-compatibility rule! - -@note: Maintainers be aware: things in this module should be gradually promoted - to more full-featured test helpers and exposed as public API as your - maintenance time permits. In order to be public API though, they need - their own test cases. -""" - -from io import BytesIO - -from xml.dom import minidom as dom - -from twisted.internet.protocol import FileWrapper - -class IOPump: - """Utility to pump data between clients and servers for protocol testing. - - Perhaps this is a utility worthy of being in protocol.py? - """ - def __init__(self, client, server, clientIO, serverIO): - self.client = client - self.server = server - self.clientIO = clientIO - self.serverIO = serverIO - - def flush(self): - "Pump until there is no more input or output." - while self.pump(): - pass - - def pump(self): - """Move data back and forth. - - Returns whether any data was moved. - """ - self.clientIO.seek(0) - self.serverIO.seek(0) - cData = self.clientIO.read() - sData = self.serverIO.read() - self.clientIO.seek(0) - self.serverIO.seek(0) - self.clientIO.truncate() - self.serverIO.truncate() - for byte in cData: - self.server.dataReceived(byte) - for byte in sData: - self.client.dataReceived(byte) - if cData or sData: - return 1 - else: - return 0 - - -def returnConnected(server, client): - """Take two Protocol instances and connect them. - """ - cio = BytesIO() - sio = BytesIO() - client.makeConnection(FileWrapper(cio)) - server.makeConnection(FileWrapper(sio)) - pump = IOPump(client, server, cio, sio) - # Challenge-response authentication: - pump.flush() - # Uh... - pump.flush() - return pump - - - -class XMLAssertionMixin(object): - """ - Test mixin defining a method for comparing serialized XML documents. - - Must be mixed in to a L{test case}. - """ - - def assertXMLEqual(self, first, second): - """ - Verify that two strings represent the same XML document. - - @param first: An XML string. - @type first: L{bytes} - - @param second: An XML string that should match C{first}. - @type second: L{bytes} - """ - self.assertEqual( - dom.parseString(first).toxml(), - dom.parseString(second).toxml()) - - - -class _Equal(object): - """ - A class the instances of which are equal to anything and everything. - """ - def __eq__(self, other): - return True - - - def __ne__(self, other): - return False - - - -class _NotEqual(object): - """ - A class the instances of which are equal to nothing. - """ - def __eq__(self, other): - return False - - - def __ne__(self, other): - return True - - - -class ComparisonTestsMixin(object): - """ - A mixin which defines a method for making assertions about the correctness - of an implementation of C{==} and C{!=}. - - Use this to unit test objects which follow the common convention for C{==} - and C{!=}: - - - The object compares equal to itself - - The object cooperates with unrecognized types to allow them to - implement the comparison - - The object implements not-equal as the opposite of equal - """ - def assertNormalEqualityImplementation(self, firstValueOne, secondValueOne, - valueTwo): - """ - Assert that C{firstValueOne} is equal to C{secondValueOne} but not - equal to C{valueOne} and that it defines equality cooperatively with - other types it doesn't know about. - - @param firstValueOne: An object which is expected to compare as equal to - C{secondValueOne} and not equal to C{valueTwo}. - - @param secondValueOne: A different object than C{firstValueOne} but - which is expected to compare equal to that object. - - @param valueTwo: An object which is expected to compare as not equal to - C{firstValueOne}. - """ - # This doesn't use assertEqual and assertNotEqual because the exact - # operator those functions use is not very well defined. The point - # of these assertions is to check the results of the use of specific - # operators (precisely to ensure that using different permutations - # (eg "x == y" or "not (x != y)") which should yield the same results - # actually does yield the same result). -exarkun - self.assertTrue(firstValueOne == firstValueOne) - self.assertTrue(firstValueOne == secondValueOne) - self.assertFalse(firstValueOne == valueTwo) - self.assertFalse(firstValueOne != firstValueOne) - self.assertFalse(firstValueOne != secondValueOne) - self.assertTrue(firstValueOne != valueTwo) - self.assertTrue(firstValueOne == _Equal()) - self.assertFalse(firstValueOne != _Equal()) - self.assertFalse(firstValueOne == _NotEqual()) - self.assertTrue(firstValueOne != _NotEqual()) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/topfiles/CREDITS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/topfiles/CREDITS deleted file mode 100644 index a4eeece..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/topfiles/CREDITS +++ /dev/null @@ -1,60 +0,0 @@ -The Matrix - -- Glyph "Glyph" Lefkowitz - electric violin -- Sean "Riley" Riley - grand piano -- Allen "Dash" Short - vocals and guitar -- Christopher "Radix" Armstrong - percussion -- Paul "z3p" Swartz - oboe -- Jürgen "snibril" Hermann - synthesizer -- Moshe "vertical" Zadka - accordion -- Benjamin Bruheim - kazoo -- Travis B. "Nafai" Hartwell - keyboards -- Itamar "itamar" Shtull-Trauring - alto recorder -- Andrew "spiv" Bennetts - glockenspiel -- Kevin "Acapnotic" Turner - trombone -- Donovan "fzZzy" Preston - bass and harmonium -- Jp "exarkun" Calderone - geopolitical sociographic dissonance engine -- Gavin "skreech" Cooper - torque wrench -- Jonathan "jml" Lange - pipe organ -- Bob "etrepum" Ippolito - low frequency oscillator -- Pavel "PenguinOfDoom" Pergamenshchik - electronic balalaika -- Jonathan D. "slyphon" Simms - theramin and drums -- Brian "warner" Warner - hertzian field renderer -- Mary Gardiner - krummhorn -- Eric "teratorn" Mangold - serpentine bassoon -- Tommi "Tv" Virtanen - didgeridoo -- Justin "justinj" Johnson - bass mandolin -- Ralph "ralphm" Meijer - vocals and timbales -- David "dreid" Reid - banjo - -Extras - -- Jerry Hebert -- Nick Moffit -- Jeremy Fincher diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/topfiles/ChangeLog.Old b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/topfiles/ChangeLog.Old deleted file mode 100644 index 30594b2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/topfiles/ChangeLog.Old +++ /dev/null @@ -1,3888 +0,0 @@ -2005-03-12 Jp Calderone - - * twisted/scripts/mktap.py, twisted/scripts/twistd.py, - twisted/application/app.py: Changed UID and GID defaults for Process - to None. Changed mktap behavior to not specify UID and GID if they - are not given on the command line. Changed application startup to - not change UID or GID if they are not given. Changed twistd to add - UID and GID setting command line arguments. - -2005-02-10 Jp Calderone - - * twisted/internet/defer.py: DeferredLock, DeferredSemaphore, and - DeferredQueue added. - - * twisted/test/test_defer.py: Tests for above mentioned three new - classes. - -2004-11-27 Brian Warner - - * util.py (SignalStateManager.save): don't save signal handlers - for SIGKILL and SIGSTOP, since we can't set them anyway. - Python2.4c1 raises an error when you try. - -2004-11-07 Brian Warner - - * twisted/test/test_internet.py: correctly check for SSL support. - Improve timeout for testCallLater and testGetDelayedCalls to avoid - spurious failures on slow test systems. Close sockets in - PortStringification to fix trial warnings. - - * twisted/internet/ssl.py: add a comment describing the correct - way to import twisted.internet.ssl (since it might partially fail - if OpenSSL is not available) - -2004-11-06 Jp Calderone - - * twisted/trial/assertions.py: assertRaises/failUnlessRaises now - returns the caught exception to allow tests to inspect the contents. - -2004-11-02 Brian Warner - - * loopback.py (loopbackTCP): use trial's spinWhile and spinUntil - primitives instead of doing reactor.iterate() ourselves. Make sure - to wait for everything before finishing. - -2004-10-26 Cory Dodt - - * twisted/python/{which,process}.py, - twisted/test/{test_wprocess,wprocess_for_testing}.py, - twisted/internet/{default,error,wprocess,process}.py: back out - wprocess due to test failures in wprocess and new trial. Resolves - issue 760. - -2004-10-24 Itamar Shtull-Trauring - - * TCP: Half-close of write and read for TCP connections, including - protocol notification for protocols that implement - IHalfCloseableProtocol. - -2004-10-07 Jp Calderone - - * Transports: Add a maximum to the number of bytes that will be - held in the write buffer even after they have been sent. This - puts a maximum on the cost of writing faster than the network - can accommodate. - -2004-10-06 Itamar Shtull-Trauring - - * Transports: New TCP/SSL/etc. buffering algorithm. All writes are - now stored until next iteration before being written, and many - small writes are not expensive. - -2004-09-30 Brian Warner - - * glib2reactor.py: new reactor that uses just glib2, not gtk2. - This one doesn't require a DISPLAY, and cannot be used for GUI - apps. - - * gtk2reactor.py: import gobject *after* pygtk.require, to make - sure we get the same versions of both - -2004-09-18 Christopher Armstrong - - * twisted/internet/defer.py: Add deferredGenerator and - waitForDeferred. This lets you write kinda-sorta - synchronous-looking code that uses Deferreds. See the - waitForDeferred docstring. - -2004-09-11 Cory Dodt - - * twisted/python/{which,process}.py, - twisted/test/{test_wprocess,wprocess_for_testing}.py, - twisted/internet/{default,error,wprocess,process}.py: merge the - "wprocess" branch which uses Trent Mick's process.py to enable - spawnProcess in the default reactor on Windows - -2004-08-24 Brian Warner - - * twisted/application/internet.py (TimerService): make it possible - to restart a stopped TimerService. Threw out a lot of (apparently) - unnecessary code in the process. Make sure it gets pickled in a - not-running state too. - * twisted/test/test_application.py (TestInternet2.testTimer): test - the changes, and update the way the test peeks inside TimerService - -2004-07-18 Paul Swartz - - * twisted/internet/utils.py: By passing errortoo=1, you can get - stderr from getProcessOutput - -2004-07-18 Paul Swartz - - * twisted/conch/unix.py: if the utmp module is available, record - user logins/logouts into utmp/wtmp. - -2004-06-25 Paul Swartz - * twisted/conch/checkers.py: Use functionality of crypt module instead - of an external module. - -2004-06-25 Jp Calderone - - * twisted/spread/banana.py: Disabled automatic import and use of - cBanana. PB will now use the pure-Python version of banana unless - cBanana is manually installed by the application. - -2004-06-12 Paul Swartz - - * twisted/conch/client: added -r flag to reconnect to the server if - the connection is lost (closes 623). - -2004-06-06 Dave Peticolas - - * twisted/test/test_enterprise.py: test open callback and - connect/disconnect. - - * twisted/enterprise/adbapi.py: add open callback support - and disconnect() method. Issue 480. - -2004-06-05 Dave Peticolas - - * twisted/enterprise/adbapi.py: Don't log sql exceptions (issue 631). - Remove deprecated api. - - * twisted/news/database.py: do not use adbapi.Augmentation - -2004-06-03 Itamar Shtull-Trauring - - * twisted/internet/gtk2reactor.py: The choice between glib event - loop and gtk+ event loop is determined by argument at reactor - install time. - -2004-05-31 Dave Peticolas - - * twisted/enterprise/sqlreflector.py: don't use Augmentation - - * twisted/enterprise/populate.sql: remove - - * twisted/enterprise/schema.sql: remove - - * twisted/enterprise/row.py: remove deprecated classes - - * twisted/enterprise/dbgadgets.py: remove - - * twisted/enterprise/dbcred.py: remove - - * twisted/test/test_enterprise.py: Fix Firebird test case. - -2004-05-21 Itamar Shtull-Trauring - - * twisted/internet/gtk2reactor.py: use glib event loop directly - instead of gtk2's event loop if possible. - -2004-05-04 Jp Calderone - - * twisted.news, twisted.protocols.nntp: Moved back into trunk - pending an alternate split-up strategy. - -2004-05-04 Itamar Shtull-Trauring - - * twisted.internet.reactor.listenUDP: transport.write() on UDP - ports no longer supports unresolved hostnames (though deprecated - support still exists). - -2004-4-18 Christopher Armstrong - - * twisted/lore/nevowlore.py, twisted/plugins.tml: Added Nevow - support for lore. See docstring of twisted.lore.nevowlore. - -2004-4-18 Christopher Armstrong - - * twisted.news, twisted.protocols.nntp: Moved into a third party - package. Deprecated backwards-compatibility exists by importing - from the third-party package if available. - -2004-4-11 Paul Swartz - - * twisted.conch: refactored the Conch client to separate connecting - to a server from user authentication from client-specific actions. - -2004-03-23 Andrew Bennetts - - * twisted.protocols.http: Small optimisation to HTTP implementation. - This changes return value of toChunk to a tuple of strings, rather - than one string. - -2004-4-3 Paul Swartz - - * twisted.python.lockfile: added lockfile support, based on - liblockfile. - * twisted.internet.unix.Port: added a wantPID kwarg. If True, it - checks for and gets a lockfile for the UNIX socket. - * twisted.internet.unix.Connector: added a checkPID kwarg. If True, - it checks that the lockfile for the socket is current. - -2004-03-23 Pavel Pergamenshchik - - * twisted.internet.iocp: Support for Windows IO Completion Ports. - Use with "--reactor=iocp" parameter to twistd or trial. - -2004-03-20 Itamar Shtull-Trauring - - * twisted.internet: getHost(), getPeer(), buildProtocol() etc. - all use address objects from twisted.internet.address. - - * twisted/internet/udp.py: Connected UDP support is now part of - the standard listenUDP-resulting UDP transport using a connect() - method. - -2004-03-18 Jp Calderone - - * twisted/application/internet.py: Changed TimerService to - log errors from the function it calls. - - * twisted/application/test_application.py: Added test case - for logging of exceptions from functions TimerService calls. - -2004-03-07 Christopher Armstrong - - * .: Releasing Twisted 1.2.1alpha1. - -2004-03-03 Christopher Armstrong - - * twisted/web/server.py: Fix UnsupportedMethod so that users' - allowedMethods are actually honored. - - * twisted/web/resource.py: (Resource.render) If the resource has - an 'allowedMethods' attribute, pass it to UnsupportedMethod. - -2004-02-27 Andrew Bennetts - - * twisted/internet/defer.py: Add consumeErrors flag to DeferredList. - This takes care of the most common use-case for the recently - deprecated addDeferred method. - -2004-02-28 Dave Peticolas - - * setup.py: install tap2rpm as a bin script - - * twisted/test/test_enterprise.py: Test Firebird db. Fix typos. - -2004-02-27 Andrew Bennetts - - * twisted/internet/defer.py: Deprecated DeferredList.addDeferred. It - isn't as useful as it looks, and can have surprising behaviour. - -2004-02-25 Christopher Armstrong - - * twisted/protocols/dns.py: Fixed a bug in TCP support: It - wouldn't process any messages after the first, causing AXFR - queries to be totally broken (in addition to other problems in the - implementation of AXFR). - - * twisted/names/client.py: Fixed the AXFR client (lookupZone), - thanks to DJB's wonderful documentation of the horribleness of - DNS. - -2004-02-25 Christopher Armstrong - - * .: Releasing Twisted 1.2.0 final! Same as rc3. - -2004-02-24 Christopher Armstrong - - * .: Releasing Twisted 1.2.0rc3 (same as rc2, with cBanana bug - fixed). - -2004-02-19 Kevin Turner - - * twisted/application/service.py (IService.disownServiceParent) - (IServiceCollection.removeService): These may return Deferred if they - have asynchronous side effects. - -2004-02-18 Christopher Armstrong - - * .: Releasing Twisted 1.2.0rc2. Brown-paper bag release bug. - -2004-02-17 Christopher Armstrong - - * .: Releasing Twisted 1.2.0rc1. - -2004-02-13 Brian Warner - - * doc/howto/faq.xhtml: add entry on transport.getPeer() - -2004-01-31 Christopher Armstrong - - * .: Releasing Twisted 1.1.2alpha2 (problem with Debian packaging). - -2004-01-30 Christopher Armstrong - - * .: Releasing Twisted 1.1.2alpha1. - -2004-01-23 Christopher Armstrong - - * twisted/scripts/trial.py: trial now supports a --coverage - option, requiring Python 2.3.3. Give it a directory name (relative - to _trial_temp) to put code-coverage info in. It uses the stdlib - 'trace' module. - -2004-01-21 Pavel Pergamenshchik - - * twisted/protocols/stateful.py: A new way to write protocols! - Current state is encoded as a pair (func, len). As soon as len - of data arrives, func is called with that amount of data. New - state is returned from func. - * twisted/test/test_stateful.py: Tests and an example, an - Int32StringReceiver implementation. - -2004-01-18 Christopher Armstrong - - * twisted/web/resource.py: The default render method of Resource - now supports delegating to methods of the form "render_*" where - "*" is the HTTP method that was used to make the - request. Examples: request_GET, request_HEAD, request_CONNECT, and - so on. This won't break any existing code - when people want to - use the better API, they can stop overriding 'render' and instead - override individual render_* methods. - -2004-01-13 Itamar Shtull-Trauring - - * twisted/web/soap.py: Beginning of client SOAP support. - -2004-01-10 Andrew Bennetts - - * twisted/protocols/ftp.py: Added support for partial downloads - and uploads to FTPClient (see the offset parameter of retrieveFile). - -2004-01-09 Jp Calderone - - * twisted/protocols/imap4.py: Add IMessageCopier interface to allow - for optimized implementations of message copying. - -2004-01-06 Brian Warner - - * twisted/internet/default.py (PosixReactorBase.spawnProcess): add - a 'childFDs' argument which allows the child's file descriptors to - be arbitrarily mapped to parent FDs or pipes. This allows you to - set up additional pipes into the child (say for a GPG passphrase - or separate status information). - - * twisted/internet/process.py (Process): add childFDs, split out - ProcessReader and ProcessWriter (so that Process itself is no - longer also reading stdout). - - * twisted/internet/protocol.py (ProcessProtocol): add new - childDataReceived and childConnectionLost methods, which default - to invoking the old methods for backwards compatibility - - * twisted/test/test_process.py (FDTest): add test for childFDs - mapping. Also add timeouts to most tests, and make all - reactor.iterate() loops wait 10ms between iterations to avoid - spamming the CPU quite so badly. Closes issue435. - * twisted/test/process_fds.py: new child process for FDTest - - * doc/howto/process.xhtml: document childFDs argument, add example - -2004-01-04 Itamar Shtull-Trauring - - * twisted/internet/gladereactor.py: logs all network traffic for - TCP/SSL/Unix sockets, allowing traffic to be displayed. - -2004-01-04 Dave Peticolas - - * twisted/test/test_enterprise.py: test deleting rows not in cache - - * twisted/enterprise/reflector.py: deleted rows don't have to be - in cache - - * doc/examples/row_example.py: use KeyFactory from row_util - - * doc/examples/row_util.py: add KeyFactory - -2003-12-31 Brian Warner - - * twisted/internet/defer.py (Deferred.setTimeout): if the Deferred - has already been called, don't bother with the timeout. This - happens when trial.util.deferredResult is used with a timeout - argument and the Deferred was created by defer.succeed(). - * twisted/test/test_defer.py - (DeferredTestCase.testImmediateSuccess2): test for same - -2003-12-31 Jp Calderone - - * twisted/protocols/ident.py: Client and server ident implementation - * twisted/test/test_ident.py: Test cases for ident protocol - -2003-12-29 Jp Calderone - - * twisted/spread/pb.py: Changed PBServerFactory to use "protocol" - instance attribute for Broker creation. - -2003-12-26 Itamar Shtull-Trauring - - * twisted/web/server.py: display of tracebacks on web pages can - now be disabled by setting displayTracebacks to False on the Site - or by using applicable tap option. Woven does not yet use - this attribute. - -2003-12-23 Itamar Shtull-Trauring - - * twisted/web/client.py: if Host header is passed, use that - instead of extracting from request URL. - -2003-12-14 Dave Peticolas - - * twisted/test/test_enterprise.py: Frederico Di Gregorio's patch - adding a psycopg test case. - -2003-12-09 Christopher Armstrong - - * .: Releasing Twisted 1.1.1, based on rc4. - -2003-12-06 Itamar Shtull-Trauring - - * twisted/internet/wxreactor.py: Added experimental wxPython reactor, - which seems to work better than the twisted.internet.wxsupport. - -2003-12-05 Paul Swartz - - * twisted/conch/ssh/filetransfer.py, session.py: added SFTPv3 support - to the Conch server. - -2003-12-04 Christopher Armstrong - - * .: Releasing Twisted 1.1.1rc4, based on rc2. rc3 never happened! - -2003-12-04 Brian Warner - - * twisted/persisted/sob.py (Persistent): fix misspelled class name, - add compatibility binding to "Persistant" (sic). - - * twisted/test/test_sob.py: use Persistent - * twisted/application/service.py (Application): use Persistent - -2003-12-03 Jp Calderone - - * twisted/protocols/imap4.py: Added support for the - IDLE command (RFC 2177). - -2003-12-03 Jp Calderone - - * twisted/python/log.py: Added exception handling to - log publishing code. Observers which raise exceptions - will now be removed from the observer list. - -2003-12-02 Jp Calderone - - * .: Releasing Twisted 1.1.1rc3. - -2003-12-01 Christopher Armstrong - - * .: Releasing Twisted 1.1.1rc2 (from CVS HEAD). - -2003-12-01 Jp Calderone - - * twisted/python/runtime.py: Added seconds method to Platform - class. - - * twisted/internet/base.py, twisted/internet/task.py: Changed - use of time.time() to use Platform.seconds() instead. - -2003-11-24 Jp Calderone - - * twisted/internet/abstract.py: Changed FileDescriptor's - registerProducer method to immediately call the given producer's - stopProducing method if the FileDescriptor is in the process of - or has finished disconnecting. - -2003-11-24 Jp Calderone - - * twisted/protocols/imap4.py: Fix incorrect behavior of closing the - mailbox in response to an EXPUNGE command. - -2003-11-21 Jp Calderone - - * twisted/trial/runner.py: Added missing calls to setUpClass and - tearDownClass in SingletonRunner. - -2003-11-21 Christopher Armstrong - - * .: Releasing Twisted 1.1.1rc1. - -2003-11-20 Jp Calderone - - * twisted/protocols/imap4.py: Fixed incorrect generation of - INTERNALDATE information. - -2003-11-20 Jp Calderone - - * twisted/internet/abstract.py: Added an assert to - FileDescriptor.resumeProducing to prevent it from being - called when the transport is no longer connected. - -2003-11-20 Jp Calderone - - * twisted/internet/tasks.py: LoopingCall added. - -2003-10-14 Itamar Shtull-Trauring - - * twisted/internet/tasks.py: Deprecated scheduling API removed. - -2003-11-18 Jonathan Simms - - * twisted/protocols/ftp.py: refactored to add cred support, - pipelining, security. - * twisted/test/test_ftp.py: tests for the new ftp - -2003-11-18 Sam Jordan - - * twisted/protocols/msn.py: support for MSNP8 - * doc/examples/msn_example.py: small msn example - -2003-11-13 Paul Swartz - - * twisted/conch/ssh/agent.py: support for the OpenSSH agent protocol - * twisted/conch/ssh/connection.py: fix broken channel retrieval code - * twisted/conch/ssh/userauth.py: refactoring to allow use of the agent - * twisted/conch/ssj/transport.py: fix intermittent test failure - * twisted/internet/protocol.py: add UNIX socket support to - ClientCreator - * twisted/scripts/conch.py: use the key agent if available, also - agent forwarding - -2003-11-07 Brian Warner - - * twisted/application/app.py (getApplication): provide a more - constructive error message when a .tac file doesn't define - 'application'. Closes issue387. - -2003-11-01 Paul Swartz - - * twisted/conch/ssh/common.py: use GMPy for faster math if it's - available - -2003-10-24 Christopher Armstrong - - * .: Releasing Twisted 1.1.0 final. Same codebase as rc2. - -2003-10-24 Brian Warner - - * doc/howto/test-standard.xhtml: Add section on how to clean up. - - * twisted/test/test_conch.py: improve post-test cleanup. Addresses - problems seen in issue343. - - * twisted/internet/base.py (ReactorBase.callLater): prefix - "internal" parameter names with an underscore, to avoid colliding - with named parameters in the user's callback invocation. Closes - issue347. - (ReactorBase.addSystemEventTrigger) - (ReactorBase.callWhenRunning) - (ReactorBase.callInThread): same - * doc/howto/coding-standard.xhtml (Callback Arguments): explain why - -2003-10-22 Christopher Armstrong - - * .: Releasing Twisted 1.1.0rc2. - -2003-10-21 Andrew Bennetts - - * twisted/lore/tree.py, twisted/lore/lint.py, - doc/howto/stylesheet.css: add a plain 'listing' class, for file - listings that aren't python source or HTML. This has slightly changed - the classes in the generated HTML, so custom stylesheets may need - updating. - -2003-10-16 Christopher Armstrong - - * .: Releasing Twisted 1.1.0alpha3. - -2003-10-16 Brian Warner - - * doc/howto/pb-cred.xhtml: update for newcred. Closes issue172. - -2003-10-15 Brian Warner - - * twisted/internet/base.py: add optional debug code, enabled with - base.DelayedCall.debug=True . If active, the call stack which - invoked reactor.callLater will be recorded in each DelayedCall. If - an exception happens when the timer function is run, the creator - stack will be logged in addition to the usual log.deferr(). - - * twisted/internet/defer.py: add some optional debug code, enabled - with defer.Deferred.debug=True . If active, it will record a stack - trace when the Deferred is created, and another when it is first - invoked. AlreadyCalledErrors will be given these two stack traces, - making it slightly easier to find the source of the problem. - -2003-10-15 Christopher Armstrong - - * .: Releasing Twisted 1.1.0alpha2 (alpha1 was dead in the water). - -2003-10-15 Brian Warner - - * setup.py: remove cReactor/ to the sandbox. Closes issue318. - -2003-10-14 Itamar Shtull-Trauring - - * twisted/web/static.py: registry no longer has support for - getting services based on their interfaces. - -2003-10-14 Christopher Armstrong - - * .: Releasing Twisted 1.1.0alpha1. - -2003-10-13 Bob Ippolito - - * doc/howto/choosing-reactor.xhtml: - Added cfreactor/Cocoa information. - - * doc/examples/cocoaDemo: - Removed, replaced by doc/examples/Cocoa cfreactor demos. - - * doc/examples/Cocoa: - Moved from sandbox/etrepum/examples/PyObjC, cleaned up. - - * twisted/internet/cfsupport, twisted/internet/cfreactor.py: - Moved from sandbox/etrepum, cleaned up. - - * twisted/application/app.py: - Added 'cf' -> twisted.internet.cfreactor to reactorTypes - - * setup.py: - sys.platform=='darwin' - build cfsupport, do not build cReactor. - - * INSTALL: - Changed URL of pimp repository to shorter version. - -2003-10-12 Jp Calderone - - * bin/tktwistd, twisted/scripts/tktwistd.py, doc/man/tktwistd.1: - Removed. - -2003-10-12 Itamar Shtull-Trauring - - * twisted/spread/pb.py: Perspective Broker no longer sends - detailed tracebacks over the wire unless the "unsafeTracebacks" - attribute is set of the factory. - -2003-10-02 Jp Calderone - - * setup.py, twisted/test/test_dir.py, twisted/python/_c_dir.c: - Removed _c_dir extension module for portability and maintenance - reasons. - -2003-10-03 Moshe Zadka - - * twisted/spread/util.py twisted/test/test_spread.py: Fix issue - 286 - -2003-10-01 Brian Warner - - * twisted/web/client.py (HTTPDownloader): accept either a filename - or a file-like object (it must respond to .write and .close, and - partial requests will not be used with file-like objects). errback - the deferred if an IOError occurs in .open, .write. or .close, - usually something like "permission denied" or "file system full". - Closes issue234. - * twisted/test/test_webclient.py (WebClientTestCase.write): verify - that the errback gets called - - * twisted/scripts/trial.py (run): add --until-failure option to - re-run the test until something fails. Closes issue87. - -2003-09-30 Brian Warner - - * twisted/test/test_conch.py (testOurServerOpenSSHClient): replace - reactor.run() with .iterate calls: when using .run, exceptions in - the server cause a hang. - -2003-9-29 Moshe Zadka - - * twisted/tap/procmon.py twisted/plugins.tml: remove procmon - tap. It was crufty and hard to port properly to new application. - -2003-09-29 Brian Warner - - * twisted/scripts/trial.py (Options.opt_reactor): make trial - accept the same reactor-name abbreviations as twistd does. Closes - issue69. - (top): add test-case-name tag - - * doc/man/trial.1: document the change - -2003-09-28 Christopher Armstrong - - * .: Releasing Twisted 1.0.8alpha3. - -2003-09-27 Cory Dodt - - * win32/main.aap win32/pyx.x-foo.iss.template win32/README.win32: - Be nice to people who don't install Python for "All Users" on win32. - -2003-9-18 Moshe Zadka - - * twisted/application/strports.py twisted/test/test_strports.py: - New API/mini-language for defining ports - -2003-9-18 Moshe Zadka - - * twisted/web/spider.py: removed, it was unmaintained. - -2003-09-19 Christopher Armstrong - - * twisted/names/authority.py twisted/test/test_names.py - twisted/protocols/dns.py: Client and server support for TTLs on - all records. All Record_* types now take a ttl= keyword - argument. You can pass the ttl= argument to all the record classes - in your pyzones, too. - -2003-09-19 Moshe Zadka - - * twisted/application/__init__.py twisted/application/app.py - twisted/application/compat.py twisted/application/internet.py - twisted/application/service.py twisted/scripts/twistd.py - twisted/scripts/twistw.py twisted/scripts/mktap.py - twisted/scripts/tapconvert.py bin/twistw: Update to new-style - applications. - -2003-09-19 Jp Calderone - - * twisted/names/client.py: Instantiation of theResolver global made - lazy. As a result importing it directly will now fail if it has not - yet been created. It should not be used directly anymore; instead, - use the module-scope lookup methods, or instantiate your own - resolver. - - * twisted/mail/relaymanager.py: Instantiation of MXCalculator made - lazy. - -2003-09-18 Stephen Thorne - - * twisted/web/distrib.py: Removed dependancy on twisted.web.widgets, and - instead using woven. - -2003-09-18 Stephen Thorne - - * doc/howto/woven-reference.html: Added this new documentation file. - * doc/howto/index.html: Added woven-reference to index - * admin/: Added woven-reference.tex to book.tex - -2003-09-18 Stephen Thorne - - * twisted/web/woven/widgets.py: Stop the 'Option' widget from having a - name="" attribute. Closes issue255. - -2003-09-16 Christopher Armstrong - - * .: Releasing Twisted 1.0.8alpha1. - - * .: Releasing Twisted 1.0.8alpha2 (Fixed Debian packages). - -2003-09-13 Christopher Armstrong - - * .: Releasing Twisted 1.0.7 (no code changes since 1.0.7rc1). - - * twisted/web/vhost.py: Un-gobble the path segment that a vhost eats - when the resource we're wrapping isLeaf. Potentially closes issue125. - -2003-09-12 Itamar Shtull-Trauring - - * twisted/web/microdom.py: lenient mode correctly handles - # tidy does this, for example. - prefix = "" - oldvalue = c.value - match = self.COMMENT.match(oldvalue) - if match: - prefix = match.group() - oldvalue = oldvalue[len(prefix):] - - # now see if contents are actual node and comment or CDATA - try: - e = parseString("%s" % oldvalue).childNodes[0] - except (ParseError, MismatchedTags): - return - if len(e.childNodes) != 1: - return - e = e.firstChild() - if isinstance(e, (CDATASection, Comment)): - el.childNodes = [] - if prefix: - el.childNodes.append(Text(prefix)) - el.childNodes.append(e) - - def gotDoctype(self, doctype): - self._mddoctype = doctype - - def gotTagStart(self, name, attributes): - # print ' '*self.indentlevel, 'start tag',name - # self.indentlevel += 1 - parent = self._getparent() - if (self.beExtremelyLenient and isinstance(parent, Element)): - parentName = parent.tagName - myName = name - if self.caseInsensitive: - parentName = parentName.lower() - myName = myName.lower() - if myName in self.laterClosers.get(parentName, []): - self.gotTagEnd(parent.tagName) - parent = self._getparent() - attributes = _unescapeDict(attributes) - namespaces = self.nsstack[-1][0] - newspaces = {} - for k, v in attributes.items(): - if k.startswith('xmlns'): - spacenames = k.split(':',1) - if len(spacenames) == 2: - newspaces[spacenames[1]] = v - else: - newspaces[''] = v - del attributes[k] - if newspaces: - namespaces = namespaces.copy() - namespaces.update(newspaces) - for k, v in attributes.items(): - ksplit = k.split(':', 1) - if len(ksplit) == 2: - pfx, tv = ksplit - if pfx != 'xml' and pfx in namespaces: - attributes[namespaces[pfx], tv] = v - del attributes[k] - el = Element(name, attributes, parent, - self.filename, self.saveMark(), - caseInsensitive=self.caseInsensitive, - preserveCase=self.preserveCase, - namespace=namespaces.get('')) - revspaces = _reverseDict(newspaces) - el.addPrefixes(revspaces) - - if newspaces: - rscopy = self.nsstack[-1][2].copy() - rscopy.update(revspaces) - self.nsstack.append((namespaces, el, rscopy)) - self.elementstack.append(el) - if parent: - parent.appendChild(el) - if (self.beExtremelyLenient and el.tagName in self.soonClosers): - self.gotTagEnd(name) - - def _gotStandalone(self, factory, data): - parent = self._getparent() - te = factory(data, parent) - if parent: - parent.appendChild(te) - elif self.beExtremelyLenient: - self.documents.append(te) - - def gotText(self, data): - if data.strip() or self.shouldPreserveSpace(): - self._gotStandalone(Text, data) - - def gotComment(self, data): - self._gotStandalone(Comment, data) - - def gotEntityReference(self, entityRef): - self._gotStandalone(EntityReference, entityRef) - - def gotCData(self, cdata): - self._gotStandalone(CDATASection, cdata) - - def gotTagEnd(self, name): - # print ' '*self.indentlevel, 'end tag',name - # self.indentlevel -= 1 - if not self.elementstack: - if self.beExtremelyLenient: - return - raise MismatchedTags(*((self.filename, "NOTHING", name) - +self.saveMark()+(0,0))) - el = self.elementstack.pop() - pfxdix = self.nsstack[-1][2] - if self.nsstack[-1][1] is el: - nstuple = self.nsstack.pop() - else: - nstuple = None - if self.caseInsensitive: - tn = el.tagName.lower() - cname = name.lower() - else: - tn = el.tagName - cname = name - - nsplit = name.split(':',1) - if len(nsplit) == 2: - pfx, newname = nsplit - ns = pfxdix.get(pfx,None) - if ns is not None: - if el.namespace != ns: - if not self.beExtremelyLenient: - raise MismatchedTags(*((self.filename, el.tagName, name) - +self.saveMark()+el._markpos)) - if not (tn == cname): - if self.beExtremelyLenient: - if self.elementstack: - lastEl = self.elementstack[0] - for idx in xrange(len(self.elementstack)): - if self.elementstack[-(idx+1)].tagName == cname: - self.elementstack[-(idx+1)].endTag(name) - break - else: - # this was a garbage close tag; wait for a real one - self.elementstack.append(el) - if nstuple is not None: - self.nsstack.append(nstuple) - return - del self.elementstack[-(idx+1):] - if not self.elementstack: - self.documents.append(lastEl) - return - else: - raise MismatchedTags(*((self.filename, el.tagName, name) - +self.saveMark()+el._markpos)) - el.endTag(name) - if not self.elementstack: - self.documents.append(el) - if self.beExtremelyLenient and el.tagName == "script": - self._fixScriptElement(el) - - def connectionLost(self, reason): - XMLParser.connectionLost(self, reason) # This can cause more events! - if self.elementstack: - if self.beExtremelyLenient: - self.documents.append(self.elementstack[0]) - else: - raise MismatchedTags(*((self.filename, self.elementstack[-1], - "END_OF_FILE") - +self.saveMark() - +self.elementstack[-1]._markpos)) - - -def parse(readable, *args, **kwargs): - """Parse HTML or XML readable.""" - if not hasattr(readable, "read"): - readable = open(readable, "rb") - mdp = MicroDOMParser(*args, **kwargs) - mdp.filename = getattr(readable, "name", "") - mdp.makeConnection(None) - if hasattr(readable,"getvalue"): - mdp.dataReceived(readable.getvalue()) - else: - r = readable.read(1024) - while r: - mdp.dataReceived(r) - r = readable.read(1024) - mdp.connectionLost(None) - - if not mdp.documents: - raise ParseError(mdp.filename, 0, 0, "No top-level Nodes in document") - - if mdp.beExtremelyLenient: - if len(mdp.documents) == 1: - d = mdp.documents[0] - if not isinstance(d, Element): - el = Element("html") - el.appendChild(d) - d = el - else: - d = Element("html") - for child in mdp.documents: - d.appendChild(child) - else: - d = mdp.documents[0] - doc = Document(d) - doc.doctype = mdp._mddoctype - return doc - -def parseString(st, *args, **kw): - if isinstance(st, UnicodeType): - # this isn't particularly ideal, but it does work. - return parse(StringIO(st.encode('UTF-16')), *args, **kw) - return parse(StringIO(st), *args, **kw) - - -def parseXML(readable): - """Parse an XML readable object.""" - return parse(readable, caseInsensitive=0, preserveCase=1) - - -def parseXMLString(st): - """Parse an XML readable object.""" - return parseString(st, caseInsensitive=0, preserveCase=1) - - -# Utility - -class lmx: - """Easy creation of XML.""" - - def __init__(self, node='div'): - if isinstance(node, StringTypes): - node = Element(node) - self.node = node - - def __getattr__(self, name): - if name[0] == '_': - raise AttributeError("no private attrs") - return lambda **kw: self.add(name,**kw) - - def __setitem__(self, key, val): - self.node.setAttribute(key, val) - - def __getitem__(self, key): - return self.node.getAttribute(key) - - def text(self, txt, raw=0): - nn = Text(txt, raw=raw) - self.node.appendChild(nn) - return self - - def add(self, tagName, **kw): - newNode = Element(tagName, caseInsensitive=0, preserveCase=0) - self.node.appendChild(newNode) - xf = lmx(newNode) - for k, v in kw.items(): - if k[0] == '_': - k = k[1:] - xf[k]=v - return xf diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/proxy.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/proxy.py deleted file mode 100644 index 9e69293..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/proxy.py +++ /dev/null @@ -1,303 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_proxy -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Simplistic HTTP proxy support. - -This comes in two main variants - the Proxy and the ReverseProxy. - -When a Proxy is in use, a browser trying to connect to a server (say, -www.yahoo.com) will be intercepted by the Proxy, and the proxy will covertly -connect to the server, and return the result. - -When a ReverseProxy is in use, the client connects directly to the ReverseProxy -(say, www.yahoo.com) which farms off the request to one of a pool of servers, -and returns the result. - -Normally, a Proxy is used on the client end of an Internet connection, while a -ReverseProxy is used on the server end. -""" - -import urlparse -from urllib import quote as urlquote - -from twisted.internet import reactor -from twisted.internet.protocol import ClientFactory -from twisted.web.resource import Resource -from twisted.web.server import NOT_DONE_YET -from twisted.web.http import HTTPClient, Request, HTTPChannel - - - -class ProxyClient(HTTPClient): - """ - Used by ProxyClientFactory to implement a simple web proxy. - - @ivar _finished: A flag which indicates whether or not the original request - has been finished yet. - """ - _finished = False - - def __init__(self, command, rest, version, headers, data, father): - self.father = father - self.command = command - self.rest = rest - if "proxy-connection" in headers: - del headers["proxy-connection"] - headers["connection"] = "close" - headers.pop('keep-alive', None) - self.headers = headers - self.data = data - - - def connectionMade(self): - self.sendCommand(self.command, self.rest) - for header, value in self.headers.items(): - self.sendHeader(header, value) - self.endHeaders() - self.transport.write(self.data) - - - def handleStatus(self, version, code, message): - self.father.setResponseCode(int(code), message) - - - def handleHeader(self, key, value): - # t.web.server.Request sets default values for these headers in its - # 'process' method. When these headers are received from the remote - # server, they ought to override the defaults, rather than append to - # them. - if key.lower() in ['server', 'date', 'content-type']: - self.father.responseHeaders.setRawHeaders(key, [value]) - else: - self.father.responseHeaders.addRawHeader(key, value) - - - def handleResponsePart(self, buffer): - self.father.write(buffer) - - - def handleResponseEnd(self): - """ - Finish the original request, indicating that the response has been - completely written to it, and disconnect the outgoing transport. - """ - if not self._finished: - self._finished = True - self.father.finish() - self.transport.loseConnection() - - - -class ProxyClientFactory(ClientFactory): - """ - Used by ProxyRequest to implement a simple web proxy. - """ - - protocol = ProxyClient - - - def __init__(self, command, rest, version, headers, data, father): - self.father = father - self.command = command - self.rest = rest - self.headers = headers - self.data = data - self.version = version - - - def buildProtocol(self, addr): - return self.protocol(self.command, self.rest, self.version, - self.headers, self.data, self.father) - - - def clientConnectionFailed(self, connector, reason): - """ - Report a connection failure in a response to the incoming request as - an error. - """ - self.father.setResponseCode(501, "Gateway error") - self.father.responseHeaders.addRawHeader("Content-Type", "text/html") - self.father.write("

Could not connect

") - self.father.finish() - - - -class ProxyRequest(Request): - """ - Used by Proxy to implement a simple web proxy. - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - protocols = {'http': ProxyClientFactory} - ports = {'http': 80} - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - - - def process(self): - parsed = urlparse.urlparse(self.uri) - protocol = parsed[0] - host = parsed[1] - port = self.ports[protocol] - if ':' in host: - host, port = host.split(':') - port = int(port) - rest = urlparse.urlunparse(('', '') + parsed[2:]) - if not rest: - rest = rest + '/' - class_ = self.protocols[protocol] - headers = self.getAllHeaders().copy() - if 'host' not in headers: - headers['host'] = host - self.content.seek(0, 0) - s = self.content.read() - clientFactory = class_(self.method, rest, self.clientproto, headers, - s, self) - self.reactor.connectTCP(host, port, clientFactory) - - - -class Proxy(HTTPChannel): - """ - This class implements a simple web proxy. - - Since it inherits from L{twisted.web.http.HTTPChannel}, to use it you - should do something like this:: - - from twisted.web import http - f = http.HTTPFactory() - f.protocol = Proxy - - Make the HTTPFactory a listener on a port as per usual, and you have - a fully-functioning web proxy! - """ - - requestFactory = ProxyRequest - - - -class ReverseProxyRequest(Request): - """ - Used by ReverseProxy to implement a simple reverse proxy. - - @ivar proxyClientFactoryClass: a proxy client factory class, used to create - new connections. - @type proxyClientFactoryClass: L{ClientFactory} - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - proxyClientFactoryClass = ProxyClientFactory - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - - - def process(self): - """ - Handle this request by connecting to the proxied server and forwarding - it there, then forwarding the response back as the response to this - request. - """ - self.requestHeaders.setRawHeaders(b"host", [self.factory.host]) - clientFactory = self.proxyClientFactoryClass( - self.method, self.uri, self.clientproto, self.getAllHeaders(), - self.content.read(), self) - self.reactor.connectTCP(self.factory.host, self.factory.port, - clientFactory) - - - -class ReverseProxy(HTTPChannel): - """ - Implements a simple reverse proxy. - - For details of usage, see the file examples/reverse-proxy.py. - """ - - requestFactory = ReverseProxyRequest - - - -class ReverseProxyResource(Resource): - """ - Resource that renders the results gotten from another server - - Put this resource in the tree to cause everything below it to be relayed - to a different server. - - @ivar proxyClientFactoryClass: a proxy client factory class, used to create - new connections. - @type proxyClientFactoryClass: L{ClientFactory} - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - proxyClientFactoryClass = ProxyClientFactory - - - def __init__(self, host, port, path, reactor=reactor): - """ - @param host: the host of the web server to proxy. - @type host: C{str} - - @param port: the port of the web server to proxy. - @type port: C{port} - - @param path: the base path to fetch data from. Note that you shouldn't - put any trailing slashes in it, it will be added automatically in - request. For example, if you put B{/foo}, a request on B{/bar} will - be proxied to B{/foo/bar}. Any required encoding of special - characters (such as " " or "/") should have been done already. - - @type path: C{str} - """ - Resource.__init__(self) - self.host = host - self.port = port - self.path = path - self.reactor = reactor - - - def getChild(self, path, request): - """ - Create and return a proxy resource with the same proxy configuration - as this one, except that its path also contains the segment given by - C{path} at the end. - """ - return ReverseProxyResource( - self.host, self.port, self.path + '/' + urlquote(path, safe=""), - self.reactor) - - - def render(self, request): - """ - Render a request by forwarding it to the proxied server. - """ - # RFC 2616 tells us that we can omit the port if it's the default port, - # but we have to provide it otherwise - if self.port == 80: - host = self.host - else: - host = "%s:%d" % (self.host, self.port) - request.requestHeaders.setRawHeaders(b"host", [host]) - request.content.seek(0, 0) - qs = urlparse.urlparse(request.uri)[4] - if qs: - rest = self.path + '?' + qs - else: - rest = self.path - clientFactory = self.proxyClientFactoryClass( - request.method, rest, request.clientproto, - request.getAllHeaders(), request.content.read(), request) - self.reactor.connectTCP(self.host, self.port, clientFactory) - return NOT_DONE_YET diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/resource.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/resource.py deleted file mode 100644 index ea9caac..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/resource.py +++ /dev/null @@ -1,407 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Implementation of the lowest-level Resource class. -""" - -from __future__ import division, absolute_import - -__all__ = [ - 'IResource', 'getChildForRequest', - 'Resource', 'ErrorPage', 'NoResource', 'ForbiddenResource', - 'EncodingResourceWrapper'] - -import warnings - -from zope.interface import Attribute, Interface, implementer - -from twisted.python.compat import nativeString, unicode -from twisted.python.reflect import prefixedMethodNames -from twisted.python.components import proxyForInterface - -from twisted.web._responses import FORBIDDEN, NOT_FOUND -from twisted.web.error import UnsupportedMethod - - - -class IResource(Interface): - """ - A web resource. - """ - - isLeaf = Attribute( - """ - Signal if this IResource implementor is a "leaf node" or not. If True, - getChildWithDefault will not be called on this Resource. - """) - - - def getChildWithDefault(name, request): - """ - Return a child with the given name for the given request. - This is the external interface used by the Resource publishing - machinery. If implementing IResource without subclassing - Resource, it must be provided. However, if subclassing Resource, - getChild overridden instead. - - @param name: A single path component from a requested URL. For example, - a request for I{http://example.com/foo/bar} will result in calls to - this method with C{b"foo"} and C{b"bar"} as values for this - argument. - @type name: C{bytes} - - @param request: A representation of all of the information about the - request that is being made for this child. - @type request: L{twisted.web.server.Request} - """ - - - def putChild(path, child): - """ - Put a child IResource implementor at the given path. - - @param path: A single path component, to be interpreted relative to the - path this resource is found at, at which to put the given child. - For example, if resource A can be found at I{http://example.com/foo} - then a call like C{A.putChild(b"bar", B)} will make resource B - available at I{http://example.com/foo/bar}. - @type path: C{bytes} - """ - - - def render(request): - """ - Render a request. This is called on the leaf resource for a request. - - @return: Either C{server.NOT_DONE_YET} to indicate an asynchronous or a - C{bytes} instance to write as the response to the request. If - C{NOT_DONE_YET} is returned, at some point later (for example, in a - Deferred callback) call C{request.write(b"")} to write data to - the request, and C{request.finish()} to send the data to the - browser. - - @raise twisted.web.error.UnsupportedMethod: If the HTTP verb - requested is not supported by this resource. - """ - - - -def getChildForRequest(resource, request): - """ - Traverse resource tree to find who will handle the request. - """ - while request.postpath and not resource.isLeaf: - pathElement = request.postpath.pop(0) - request.prepath.append(pathElement) - resource = resource.getChildWithDefault(pathElement, request) - return resource - - - -@implementer(IResource) -class Resource: - """ - Define a web-accessible resource. - - This serves 2 main purposes; one is to provide a standard representation - for what HTTP specification calls an 'entity', and the other is to provide - an abstract directory structure for URL retrieval. - """ - entityType = IResource - - server = None - - def __init__(self): - """ - Initialize. - """ - self.children = {} - - isLeaf = 0 - - ### Abstract Collection Interface - - def listStaticNames(self): - return list(self.children.keys()) - - def listStaticEntities(self): - return list(self.children.items()) - - def listNames(self): - return list(self.listStaticNames()) + self.listDynamicNames() - - def listEntities(self): - return list(self.listStaticEntities()) + self.listDynamicEntities() - - def listDynamicNames(self): - return [] - - def listDynamicEntities(self, request=None): - return [] - - def getStaticEntity(self, name): - return self.children.get(name) - - def getDynamicEntity(self, name, request): - if not self.children.has_key(name): - return self.getChild(name, request) - else: - return None - - def delEntity(self, name): - del self.children[name] - - def reallyPutEntity(self, name, entity): - self.children[name] = entity - - # Concrete HTTP interface - - def getChild(self, path, request): - """ - Retrieve a 'child' resource from me. - - Implement this to create dynamic resource generation -- resources which - are always available may be registered with self.putChild(). - - This will not be called if the class-level variable 'isLeaf' is set in - your subclass; instead, the 'postpath' attribute of the request will be - left as a list of the remaining path elements. - - For example, the URL /foo/bar/baz will normally be:: - - | site.resource.getChild('foo').getChild('bar').getChild('baz'). - - However, if the resource returned by 'bar' has isLeaf set to true, then - the getChild call will never be made on it. - - Parameters and return value have the same meaning and requirements as - those defined by L{IResource.getChildWithDefault}. - """ - return NoResource("No such child resource.") - - - def getChildWithDefault(self, path, request): - """ - Retrieve a static or dynamically generated child resource from me. - - First checks if a resource was added manually by putChild, and then - call getChild to check for dynamic resources. Only override if you want - to affect behaviour of all child lookups, rather than just dynamic - ones. - - This will check to see if I have a pre-registered child resource of the - given name, and call getChild if I do not. - - @see: L{IResource.getChildWithDefault} - """ - if path in self.children: - return self.children[path] - return self.getChild(path, request) - - - def getChildForRequest(self, request): - warnings.warn("Please use module level getChildForRequest.", DeprecationWarning, 2) - return getChildForRequest(self, request) - - - def putChild(self, path, child): - """ - Register a static child. - - You almost certainly don't want '/' in your path. If you - intended to have the root of a folder, e.g. /foo/, you want - path to be ''. - - @see: L{IResource.putChild} - """ - self.children[path] = child - child.server = self.server - - - def render(self, request): - """ - Render a given resource. See L{IResource}'s render method. - - I delegate to methods of self with the form 'render_METHOD' - where METHOD is the HTTP that was used to make the - request. Examples: render_GET, render_HEAD, render_POST, and - so on. Generally you should implement those methods instead of - overriding this one. - - render_METHOD methods are expected to return a byte string which will be - the rendered page, unless the return value is C{server.NOT_DONE_YET}, in - which case it is this class's responsibility to write the results using - C{request.write(data)} and then call C{request.finish()}. - - Old code that overrides render() directly is likewise expected - to return a byte string or NOT_DONE_YET. - - @see: L{IResource.render} - """ - m = getattr(self, 'render_' + nativeString(request.method), None) - if not m: - try: - allowedMethods = self.allowedMethods - except AttributeError: - allowedMethods = _computeAllowedMethods(self) - raise UnsupportedMethod(allowedMethods) - return m(request) - - - def render_HEAD(self, request): - """ - Default handling of HEAD method. - - I just return self.render_GET(request). When method is HEAD, - the framework will handle this correctly. - """ - return self.render_GET(request) - - - -def _computeAllowedMethods(resource): - """ - Compute the allowed methods on a C{Resource} based on defined render_FOO - methods. Used when raising C{UnsupportedMethod} but C{Resource} does - not define C{allowedMethods} attribute. - """ - allowedMethods = [] - for name in prefixedMethodNames(resource.__class__, "render_"): - # Potentially there should be an API for encode('ascii') in this - # situation - an API for taking a Python native string (bytes on Python - # 2, text on Python 3) and returning a socket-compatible string type. - allowedMethods.append(name.encode('ascii')) - return allowedMethods - - - -class ErrorPage(Resource): - """ - L{ErrorPage} is a resource which responds with a particular - (parameterized) status and a body consisting of HTML containing some - descriptive text. This is useful for rendering simple error pages. - - @ivar template: A native string which will have a dictionary interpolated - into it to generate the response body. The dictionary has the following - keys: - - - C{"code"}: The status code passed to L{ErrorPage.__init__}. - - C{"brief"}: The brief description passed to L{ErrorPage.__init__}. - - C{"detail"}: The detailed description passed to - L{ErrorPage.__init__}. - - @ivar code: An integer status code which will be used for the response. - @type code: C{int} - - @ivar brief: A short string which will be included in the response body as - the page title. - @type brief: C{str} - - @ivar detail: A longer string which will be included in the response body. - @type detail: C{str} - """ - - template = """ - - %(code)s - %(brief)s - -

%(brief)s

-

%(detail)s

- - -""" - - def __init__(self, status, brief, detail): - Resource.__init__(self) - self.code = status - self.brief = brief - self.detail = detail - - - def render(self, request): - request.setResponseCode(self.code) - request.setHeader(b"content-type", b"text/html; charset=utf-8") - interpolated = self.template % dict( - code=self.code, brief=self.brief, detail=self.detail) - if isinstance(interpolated, unicode): - return interpolated.encode('utf-8') - return interpolated - - - def getChild(self, chnam, request): - return self - - - -class NoResource(ErrorPage): - """ - L{NoResource} is a specialization of L{ErrorPage} which returns the HTTP - response code I{NOT FOUND}. - """ - def __init__(self, message="Sorry. No luck finding that resource."): - ErrorPage.__init__(self, NOT_FOUND, "No Such Resource", message) - - - -class ForbiddenResource(ErrorPage): - """ - L{ForbiddenResource} is a specialization of L{ErrorPage} which returns the - I{FORBIDDEN} HTTP response code. - """ - def __init__(self, message="Sorry, resource is forbidden."): - ErrorPage.__init__(self, FORBIDDEN, "Forbidden Resource", message) - - - -class _IEncodingResource(Interface): - """ - A resource which knows about L{_IRequestEncoderFactory}. - - @since: 12.3 - """ - - def getEncoder(request): - """ - Parse the request and return an encoder if applicable, using - L{_IRequestEncoderFactory.encoderForRequest}. - - @return: A L{_IRequestEncoder}, or C{None}. - """ - - - -@implementer(_IEncodingResource) -class EncodingResourceWrapper(proxyForInterface(IResource)): - """ - Wrap a L{IResource}, potentially applying an encoding to the response body - generated. - - Note that the returned children resources won't be wrapped, so you have to - explicitly wrap them if you want the encoding to be applied. - - @ivar encoders: A list of - L{_IRequestEncoderFactory} - returning L{_IRequestEncoder} that - may transform the data passed to C{Request.write}. The list must be - sorted in order of priority: the first encoder factory handling the - request will prevent the others from doing the same. - @type encoders: C{list}. - - @since: 12.3 - """ - - def __init__(self, original, encoders): - super(EncodingResourceWrapper, self).__init__(original) - self._encoders = encoders - - - def getEncoder(self, request): - """ - Browser the list of encoders looking for one applicable encoder. - """ - for encoderFactory in self._encoders: - encoder = encoderFactory.encoderForRequest(request) - if encoder is not None: - return encoder diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/rewrite.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/rewrite.py deleted file mode 100644 index b5366b4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/rewrite.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.web import resource - -class RewriterResource(resource.Resource): - - def __init__(self, orig, *rewriteRules): - resource.Resource.__init__(self) - self.resource = orig - self.rewriteRules = list(rewriteRules) - - def _rewrite(self, request): - for rewriteRule in self.rewriteRules: - rewriteRule(request) - - def getChild(self, path, request): - request.postpath.insert(0, path) - request.prepath.pop() - self._rewrite(request) - path = request.postpath.pop(0) - request.prepath.append(path) - return self.resource.getChildWithDefault(path, request) - - def render(self, request): - self._rewrite(request) - return self.resource.render(request) - - -def tildeToUsers(request): - if request.postpath and request.postpath[0][:1]=='~': - request.postpath[:1] = ['users', request.postpath[0][1:]] - request.path = '/'+'/'.join(request.prepath+request.postpath) - -def alias(aliasPath, sourcePath): - """ - I am not a very good aliaser. But I'm the best I can be. If I'm - aliasing to a Resource that generates links, and it uses any parts - of request.prepath to do so, the links will not be relative to the - aliased path, but rather to the aliased-to path. That I can't - alias static.File directory listings that nicely. However, I can - still be useful, as many resources will play nice. - """ - sourcePath = sourcePath.split('/') - aliasPath = aliasPath.split('/') - def rewriter(request): - if request.postpath[:len(aliasPath)] == aliasPath: - after = request.postpath[len(aliasPath):] - request.postpath = sourcePath + after - request.path = '/'+'/'.join(request.prepath+request.postpath) - return rewriter diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/script.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/script.py deleted file mode 100644 index 9b4df9d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/script.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_script -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -I contain PythonScript, which is a very simple python script resource. -""" - -from __future__ import division, absolute_import - -import os, traceback - -from twisted import copyright -from twisted.python.filepath import _coerceToFilesystemEncoding -from twisted.python.compat import execfile, networkString, NativeStringIO, _PY3 -from twisted.web import http, server, static, resource, html - - -rpyNoResource = """

You forgot to assign to the variable "resource" in your script. For example:

-
-# MyCoolWebApp.rpy
-
-import mygreatresource
-
-resource = mygreatresource.MyGreatResource()
-
-""" - -class AlreadyCached(Exception): - """ - This exception is raised when a path has already been cached. - """ - -class CacheScanner: - def __init__(self, path, registry): - self.path = path - self.registry = registry - self.doCache = 0 - - def cache(self): - c = self.registry.getCachedPath(self.path) - if c is not None: - raise AlreadyCached(c) - self.recache() - - def recache(self): - self.doCache = 1 - -noRsrc = resource.ErrorPage(500, "Whoops! Internal Error", rpyNoResource) - -def ResourceScript(path, registry): - """ - I am a normal py file which must define a 'resource' global, which should - be an instance of (a subclass of) web.resource.Resource; it will be - renderred. - """ - cs = CacheScanner(path, registry) - glob = {'__file__': _coerceToFilesystemEncoding("", path), - 'resource': noRsrc, - 'registry': registry, - 'cache': cs.cache, - 'recache': cs.recache} - try: - execfile(path, glob, glob) - except AlreadyCached as ac: - return ac.args[0] - rsrc = glob['resource'] - if cs.doCache and rsrc is not noRsrc: - registry.cachePath(path, rsrc) - return rsrc - - - -def ResourceTemplate(path, registry): - from quixote import ptl_compile - - glob = {'__file__': _coerceToFilesystemEncoding("", path), - 'resource': resource.ErrorPage(500, "Whoops! Internal Error", - rpyNoResource), - 'registry': registry} - - e = ptl_compile.compile_template(open(path), path) - code = compile(e, "", "exec") - eval(code, glob, glob) - return glob['resource'] - - - -class ResourceScriptWrapper(resource.Resource): - - def __init__(self, path, registry=None): - resource.Resource.__init__(self) - self.path = path - self.registry = registry or static.Registry() - - def render(self, request): - res = ResourceScript(self.path, self.registry) - return res.render(request) - - def getChildWithDefault(self, path, request): - res = ResourceScript(self.path, self.registry) - return res.getChildWithDefault(path, request) - - - -class ResourceScriptDirectory(resource.Resource): - """ - L{ResourceScriptDirectory} is a resource which serves scripts from a - filesystem directory. File children of a L{ResourceScriptDirectory} will - be served using L{ResourceScript}. Directory children will be served using - another L{ResourceScriptDirectory}. - - @ivar path: A C{str} giving the filesystem path in which children will be - looked up. - - @ivar registry: A L{static.Registry} instance which will be used to decide - how to interpret scripts found as children of this resource. - """ - def __init__(self, pathname, registry=None): - resource.Resource.__init__(self) - self.path = pathname - self.registry = registry or static.Registry() - - def getChild(self, path, request): - fn = os.path.join(self.path, path) - - if os.path.isdir(fn): - return ResourceScriptDirectory(fn, self.registry) - if os.path.exists(fn): - return ResourceScript(fn, self.registry) - return resource.NoResource() - - def render(self, request): - return resource.NoResource().render(request) - - - -class PythonScript(resource.Resource): - """ - I am an extremely simple dynamic resource; an embedded python script. - - This will execute a file (usually of the extension '.epy') as Python code, - internal to the webserver. - """ - isLeaf = True - - def __init__(self, filename, registry): - """ - Initialize me with a script name. - """ - self.filename = filename - self.registry = registry - - def render(self, request): - """ - Render me to a web client. - - Load my file, execute it in a special namespace (with 'request' and - '__file__' global vars) and finish the request. Output to the web-page - will NOT be handled with print - standard output goes to the log - but - with request.write. - """ - request.setHeader(b"x-powered-by", networkString("Twisted/%s" % copyright.version)) - namespace = {'request': request, - '__file__': _coerceToFilesystemEncoding("", self.filename), - 'registry': self.registry} - try: - execfile(self.filename, namespace, namespace) - except IOError as e: - if e.errno == 2: #file not found - request.setResponseCode(http.NOT_FOUND) - request.write(resource.NoResource("File not found.").render(request)) - except: - io = NativeStringIO() - traceback.print_exc(file=io) - output = html.PRE(io.getvalue()) - if _PY3: - output = output.encode("utf8") - request.write(output) - request.finish() - return server.NOT_DONE_YET diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/server.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/server.py deleted file mode 100644 index 966b24b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/server.py +++ /dev/null @@ -1,710 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This is a web-server which integrates with the twisted.internet -infrastructure. -""" - -from __future__ import division, absolute_import - -import copy -import os -try: - from urllib import quote -except ImportError: - from urllib.parse import quote as _quote - - def quote(string, *args, **kwargs): - return _quote(string.decode('charmap'), *args, **kwargs).encode('charmap') - -import zlib - -from zope.interface import implementer - -from twisted.python.compat import _PY3, networkString, nativeString, intToBytes -if _PY3: - class Copyable: - """ - Fake mixin, until twisted.spread is ported. - """ -else: - from twisted.spread.pb import Copyable, ViewPoint -from twisted.internet import address -from twisted.web import iweb, http, html -from twisted.web.http import unquote -from twisted.python import log, reflect, failure, components -from twisted import copyright -# Re-enable as part of #6178 when twisted.web.util is ported to Python 3: -if not _PY3: - from twisted.web import util as webutil -from twisted.web import resource -from twisted.web.error import UnsupportedMethod - -from twisted.python.versions import Version -from twisted.python.deprecate import deprecatedModuleAttribute - -if _PY3: - # cgi.escape is deprecated in Python 3. - from html import escape -else: - from cgi import escape - - -NOT_DONE_YET = 1 - -__all__ = [ - 'supportedMethods', - 'Request', - 'Session', - 'Site', - 'version', - 'NOT_DONE_YET', - 'GzipEncoderFactory' -] - - -# backwards compatibility -deprecatedModuleAttribute( - Version("Twisted", 12, 1, 0), - "Please use twisted.web.http.datetimeToString instead", - "twisted.web.server", - "date_time_string") -deprecatedModuleAttribute( - Version("Twisted", 12, 1, 0), - "Please use twisted.web.http.stringToDatetime instead", - "twisted.web.server", - "string_date_time") -date_time_string = http.datetimeToString -string_date_time = http.stringToDatetime - -# Support for other methods may be implemented on a per-resource basis. -supportedMethods = ('GET', 'HEAD', 'POST') - - -def _addressToTuple(addr): - if isinstance(addr, address.IPv4Address): - return ('INET', addr.host, addr.port) - elif isinstance(addr, address.UNIXAddress): - return ('UNIX', addr.name) - else: - return tuple(addr) - - - -@implementer(iweb.IRequest) -class Request(Copyable, http.Request, components.Componentized): - """ - An HTTP request. - - @ivar defaultContentType: A C{bytes} giving the default I{Content-Type} - value to send in responses if no other value is set. C{None} disables - the default. - """ - - defaultContentType = b"text/html" - - site = None - appRootURL = None - __pychecker__ = 'unusednames=issuer' - _inFakeHead = False - _encoder = None - - def __init__(self, *args, **kw): - http.Request.__init__(self, *args, **kw) - components.Componentized.__init__(self) - - def getStateToCopyFor(self, issuer): - x = self.__dict__.copy() - del x['transport'] - # XXX refactor this attribute out; it's from protocol - # del x['server'] - del x['channel'] - del x['content'] - del x['site'] - self.content.seek(0, 0) - x['content_data'] = self.content.read() - x['remote'] = ViewPoint(issuer, self) - - # Address objects aren't jellyable - x['host'] = _addressToTuple(x['host']) - x['client'] = _addressToTuple(x['client']) - - # Header objects also aren't jellyable. - x['requestHeaders'] = list(x['requestHeaders'].getAllRawHeaders()) - - return x - - # HTML generation helpers - - def sibLink(self, name): - """ - Return the text that links to a sibling of the requested resource. - """ - if self.postpath: - return (len(self.postpath)*b"../") + name - else: - return name - - - def childLink(self, name): - """ - Return the text that links to a child of the requested resource. - """ - lpp = len(self.postpath) - if lpp > 1: - return ((lpp-1)*b"../") + name - elif lpp == 1: - return name - else: # lpp == 0 - if len(self.prepath) and self.prepath[-1]: - return self.prepath[-1] + b'/' + name - else: - return name - - - def process(self): - """ - Process a request. - """ - - # get site from channel - self.site = self.channel.site - - # set various default headers - self.setHeader(b'server', version) - self.setHeader(b'date', http.datetimeToString()) - - # Resource Identification - self.prepath = [] - self.postpath = list(map(unquote, self.path[1:].split(b'/'))) - - try: - resrc = self.site.getResourceFor(self) - if resource._IEncodingResource.providedBy(resrc): - encoder = resrc.getEncoder(self) - if encoder is not None: - self._encoder = encoder - self.render(resrc) - except: - self.processingFailed(failure.Failure()) - - - def write(self, data): - """ - Write data to the transport (if not responding to a HEAD request). - - @param data: A string to write to the response. - """ - if not self.startedWriting: - # Before doing the first write, check to see if a default - # Content-Type header should be supplied. - modified = self.code != http.NOT_MODIFIED - contentType = self.responseHeaders.getRawHeaders(b'content-type') - if modified and contentType is None and self.defaultContentType is not None: - self.responseHeaders.setRawHeaders( - b'content-type', [self.defaultContentType]) - - # Only let the write happen if we're not generating a HEAD response by - # faking out the request method. Note, if we are doing that, - # startedWriting will never be true, and the above logic may run - # multiple times. It will only actually change the responseHeaders once - # though, so it's still okay. - if not self._inFakeHead: - if self._encoder: - data = self._encoder.encode(data) - http.Request.write(self, data) - - - def finish(self): - """ - Override C{http.Request.finish} for possible encoding. - """ - if self._encoder: - data = self._encoder.finish() - if data: - http.Request.write(self, data) - return http.Request.finish(self) - - - def render(self, resrc): - """ - Ask a resource to render itself. - - @param resrc: a L{twisted.web.resource.IResource}. - """ - try: - body = resrc.render(self) - except UnsupportedMethod as e: - allowedMethods = e.allowedMethods - if (self.method == b"HEAD") and (b"GET" in allowedMethods): - # We must support HEAD (RFC 2616, 5.1.1). If the - # resource doesn't, fake it by giving the resource - # a 'GET' request and then return only the headers, - # not the body. - log.msg("Using GET to fake a HEAD request for %s" % - (resrc,)) - self.method = b"GET" - self._inFakeHead = True - body = resrc.render(self) - - if body is NOT_DONE_YET: - log.msg("Tried to fake a HEAD request for %s, but " - "it got away from me." % resrc) - # Oh well, I guess we won't include the content length. - else: - self.setHeader(b'content-length', intToBytes(len(body))) - - self._inFakeHead = False - self.method = b"HEAD" - self.write(b'') - self.finish() - return - - if self.method in (supportedMethods): - # We MUST include an Allow header - # (RFC 2616, 10.4.6 and 14.7) - self.setHeader('Allow', ', '.join(allowedMethods)) - s = ('''Your browser approached me (at %(URI)s) with''' - ''' the method "%(method)s". I only allow''' - ''' the method%(plural)s %(allowed)s here.''' % { - 'URI': escape(self.uri), - 'method': self.method, - 'plural': ((len(allowedMethods) > 1) and 's') or '', - 'allowed': ', '.join(allowedMethods) - }) - epage = resource.ErrorPage(http.NOT_ALLOWED, - "Method Not Allowed", s) - body = epage.render(self) - else: - epage = resource.ErrorPage( - http.NOT_IMPLEMENTED, "Huh?", - "I don't know how to treat a %s request." % - (escape(self.method.decode("charmap")),)) - body = epage.render(self) - # end except UnsupportedMethod - - if body == NOT_DONE_YET: - return - if not isinstance(body, bytes): - body = resource.ErrorPage( - http.INTERNAL_SERVER_ERROR, - "Request did not return bytes", - "Request: " + html.PRE(reflect.safe_repr(self)) + "
" + - "Resource: " + html.PRE(reflect.safe_repr(resrc)) + "
" + - "Value: " + html.PRE(reflect.safe_repr(body))).render(self) - - if self.method == b"HEAD": - if len(body) > 0: - # This is a Bad Thing (RFC 2616, 9.4) - log.msg("Warning: HEAD request %s for resource %s is" - " returning a message body." - " I think I'll eat it." - % (self, resrc)) - self.setHeader(b'content-length', - intToBytes(len(body))) - self.write(b'') - else: - self.setHeader(b'content-length', - intToBytes(len(body))) - self.write(body) - self.finish() - - def processingFailed(self, reason): - log.err(reason) - # Re-enable on Python 3 as part of #6178: - if not _PY3 and self.site.displayTracebacks: - body = ("web.Server Traceback (most recent call last)" - "web.Server Traceback (most recent call last):\n\n" - "%s\n\n\n" - % webutil.formatFailure(reason)) - else: - body = (b"Processing Failed" - b"Processing Failed") - - self.setResponseCode(http.INTERNAL_SERVER_ERROR) - self.setHeader(b'content-type', b"text/html") - self.setHeader(b'content-length', intToBytes(len(body))) - self.write(body) - self.finish() - return reason - - def view_write(self, issuer, data): - """Remote version of write; same interface. - """ - self.write(data) - - def view_finish(self, issuer): - """Remote version of finish; same interface. - """ - self.finish() - - def view_addCookie(self, issuer, k, v, **kwargs): - """Remote version of addCookie; same interface. - """ - self.addCookie(k, v, **kwargs) - - def view_setHeader(self, issuer, k, v): - """Remote version of setHeader; same interface. - """ - self.setHeader(k, v) - - def view_setLastModified(self, issuer, when): - """Remote version of setLastModified; same interface. - """ - self.setLastModified(when) - - def view_setETag(self, issuer, tag): - """Remote version of setETag; same interface. - """ - self.setETag(tag) - - - def view_setResponseCode(self, issuer, code, message=None): - """ - Remote version of setResponseCode; same interface. - """ - self.setResponseCode(code, message) - - - def view_registerProducer(self, issuer, producer, streaming): - """Remote version of registerProducer; same interface. - (requires a remote producer.) - """ - self.registerProducer(_RemoteProducerWrapper(producer), streaming) - - def view_unregisterProducer(self, issuer): - self.unregisterProducer() - - ### these calls remain local - - session = None - - def getSession(self, sessionInterface = None): - # Session management - if not self.session: - cookiename = b"_".join([b'TWISTED_SESSION'] + self.sitepath) - sessionCookie = self.getCookie(cookiename) - if sessionCookie: - try: - self.session = self.site.getSession(sessionCookie) - except KeyError: - pass - # if it still hasn't been set, fix it up. - if not self.session: - self.session = self.site.makeSession() - self.addCookie(cookiename, self.session.uid, path=b'/') - self.session.touch() - if sessionInterface: - return self.session.getComponent(sessionInterface) - return self.session - - def _prePathURL(self, prepath): - port = self.getHost().port - if self.isSecure(): - default = 443 - else: - default = 80 - if port == default: - hostport = '' - else: - hostport = ':%d' % port - prefix = networkString('http%s://%s%s/' % ( - self.isSecure() and 's' or '', - nativeString(self.getRequestHostname()), - hostport)) - path = b'/'.join([quote(segment, safe=b'') for segment in prepath]) - return prefix + path - - def prePathURL(self): - return self._prePathURL(self.prepath) - - def URLPath(self): - from twisted.python import urlpath - return urlpath.URLPath.fromRequest(self) - - def rememberRootURL(self): - """ - Remember the currently-processed part of the URL for later - recalling. - """ - url = self._prePathURL(self.prepath[:-1]) - self.appRootURL = url - - def getRootURL(self): - """ - Get a previously-remembered URL. - """ - return self.appRootURL - - - -@implementer(iweb._IRequestEncoderFactory) -class GzipEncoderFactory(object): - """ - @cvar compressLevel: The compression level used by the compressor, default - to 9 (highest). - - @since: 12.3 - """ - - compressLevel = 9 - - def encoderForRequest(self, request): - """ - Check the headers if the client accepts gzip encoding, and encodes the - request if so. - """ - acceptHeaders = request.requestHeaders.getRawHeaders( - 'accept-encoding', []) - supported = ','.join(acceptHeaders).split(',') - if 'gzip' in supported: - encoding = request.responseHeaders.getRawHeaders( - 'content-encoding') - if encoding: - encoding = '%s,gzip' % ','.join(encoding) - else: - encoding = 'gzip' - - request.responseHeaders.setRawHeaders('content-encoding', - [encoding]) - return _GzipEncoder(self.compressLevel, request) - - - -@implementer(iweb._IRequestEncoder) -class _GzipEncoder(object): - """ - An encoder which supports gzip. - - @ivar _zlibCompressor: The zlib compressor instance used to compress the - stream. - - @ivar _request: A reference to the originating request. - - @since: 12.3 - """ - - _zlibCompressor = None - - def __init__(self, compressLevel, request): - self._zlibCompressor = zlib.compressobj( - compressLevel, zlib.DEFLATED, 16 + zlib.MAX_WBITS) - self._request = request - - - def encode(self, data): - """ - Write to the request, automatically compressing data on the fly. - """ - if not self._request.startedWriting: - # Remove the content-length header, we can't honor it - # because we compress on the fly. - self._request.responseHeaders.removeHeader(b'content-length') - return self._zlibCompressor.compress(data) - - - def finish(self): - """ - Finish handling the request request, flushing any data from the zlib - buffer. - """ - remain = self._zlibCompressor.flush() - self._zlibCompressor = None - return remain - - - -class _RemoteProducerWrapper: - def __init__(self, remote): - self.resumeProducing = remote.remoteMethod("resumeProducing") - self.pauseProducing = remote.remoteMethod("pauseProducing") - self.stopProducing = remote.remoteMethod("stopProducing") - - -class Session(components.Componentized): - """ - A user's session with a system. - - This utility class contains no functionality, but is used to - represent a session. - - @ivar uid: A unique identifier for the session, C{bytes}. - @ivar _reactor: An object providing L{IReactorTime} to use for scheduling - expiration. - @ivar sessionTimeout: timeout of a session, in seconds. - """ - sessionTimeout = 900 - - _expireCall = None - - def __init__(self, site, uid, reactor=None): - """ - Initialize a session with a unique ID for that session. - """ - components.Componentized.__init__(self) - - if reactor is None: - from twisted.internet import reactor - self._reactor = reactor - - self.site = site - self.uid = uid - self.expireCallbacks = [] - self.touch() - self.sessionNamespaces = {} - - - def startCheckingExpiration(self): - """ - Start expiration tracking. - - @return: C{None} - """ - self._expireCall = self._reactor.callLater( - self.sessionTimeout, self.expire) - - - def notifyOnExpire(self, callback): - """ - Call this callback when the session expires or logs out. - """ - self.expireCallbacks.append(callback) - - - def expire(self): - """ - Expire/logout of the session. - """ - del self.site.sessions[self.uid] - for c in self.expireCallbacks: - c() - self.expireCallbacks = [] - if self._expireCall and self._expireCall.active(): - self._expireCall.cancel() - # Break reference cycle. - self._expireCall = None - - - def touch(self): - """ - Notify session modification. - """ - self.lastModified = self._reactor.seconds() - if self._expireCall is not None: - self._expireCall.reset(self.sessionTimeout) - - -version = networkString("TwistedWeb/%s" % (copyright.version,)) - - -class Site(http.HTTPFactory): - """ - A web site: manage log, sessions, and resources. - - @ivar counter: increment value used for generating unique sessions ID. - @ivar requestFactory: A factory which is called with (channel, queued) - and creates L{Request} instances. Default to L{Request}. - @ivar displayTracebacks: if set, Twisted internal errors are displayed on - rendered pages. Default to C{True}. - @ivar sessionFactory: factory for sessions objects. Default to L{Session}. - @ivar sessionCheckTime: Deprecated. See L{Session.sessionTimeout} instead. - """ - counter = 0 - requestFactory = Request - displayTracebacks = True - sessionFactory = Session - sessionCheckTime = 1800 - - def __init__(self, resource, requestFactory=None, *args, **kwargs): - """ - @param resource: The root of the resource hierarchy. All request - traversal for requests received by this factory will begin at this - resource. - @type resource: L{IResource} provider - @param requestFactory: Overwrite for default requestFactory. - @type requestFactory: C{callable} or C{class}. - - @see: L{twisted.web.http.HTTPFactory.__init__} - """ - http.HTTPFactory.__init__(self, *args, **kwargs) - self.sessions = {} - self.resource = resource - if requestFactory is not None: - self.requestFactory = requestFactory - - def _openLogFile(self, path): - from twisted.python import logfile - return logfile.LogFile(os.path.basename(path), os.path.dirname(path)) - - def __getstate__(self): - d = self.__dict__.copy() - d['sessions'] = {} - return d - - def _mkuid(self): - """ - (internal) Generate an opaque, unique ID for a user's session. - """ - from hashlib import md5 - import random - self.counter = self.counter + 1 - return md5(networkString( - "%s_%s" % (str(random.random()) , str(self.counter))) - ).hexdigest() - - def makeSession(self): - """ - Generate a new Session instance, and store it for future reference. - """ - uid = self._mkuid() - session = self.sessions[uid] = self.sessionFactory(self, uid) - session.startCheckingExpiration() - return session - - def getSession(self, uid): - """ - Get a previously generated session, by its unique ID. - This raises a KeyError if the session is not found. - """ - return self.sessions[uid] - - def buildProtocol(self, addr): - """ - Generate a channel attached to this site. - """ - channel = http.HTTPFactory.buildProtocol(self, addr) - channel.requestFactory = self.requestFactory - channel.site = self - return channel - - isLeaf = 0 - - def render(self, request): - """ - Redirect because a Site is always a directory. - """ - request.redirect(request.prePathURL() + b'/') - request.finish() - - def getChildWithDefault(self, pathEl, request): - """ - Emulate a resource's getChild method. - """ - request.site = self - return self.resource.getChildWithDefault(pathEl, request) - - def getResourceFor(self, request): - """ - Get a resource for a request. - - This iterates through the resource heirarchy, calling - getChildWithDefault on each resource it finds for a path element, - stopping when it hits an element where isLeaf is true. - """ - request.site = self - # Sitepath is used to determine cookie names between distributed - # servers and disconnected sites. - request.sitepath = copy.copy(request.prepath) - return resource.getChildForRequest(self.resource, request) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/soap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/soap.py deleted file mode 100644 index fc15e03..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/soap.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_soap -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -SOAP support for twisted.web. - -Requires SOAPpy 0.10.1 or later. - -Maintainer: Itamar Shtull-Trauring - -Future plans: -SOAPContext support of some kind. -Pluggable method lookup policies. -""" - -# SOAPpy -import SOAPpy - -# twisted imports -from twisted.web import server, resource, client -from twisted.internet import defer - - -class SOAPPublisher(resource.Resource): - """Publish SOAP methods. - - By default, publish methods beginning with 'soap_'. If the method - has an attribute 'useKeywords', it well get the arguments passed - as keyword args. - """ - - isLeaf = 1 - - # override to change the encoding used for responses - encoding = "UTF-8" - - def lookupFunction(self, functionName): - """Lookup published SOAP function. - - Override in subclasses. Default behaviour - publish methods - starting with soap_. - - @return: callable or None if not found. - """ - return getattr(self, "soap_%s" % functionName, None) - - def render(self, request): - """Handle a SOAP command.""" - data = request.content.read() - - p, header, body, attrs = SOAPpy.parseSOAPRPC(data, 1, 1, 1) - - methodName, args, kwargs = p._name, p._aslist, p._asdict - - # deal with changes in SOAPpy 0.11 - if callable(args): - args = args() - if callable(kwargs): - kwargs = kwargs() - - function = self.lookupFunction(methodName) - - if not function: - self._methodNotFound(request, methodName) - return server.NOT_DONE_YET - else: - if hasattr(function, "useKeywords"): - keywords = {} - for k, v in kwargs.items(): - keywords[str(k)] = v - d = defer.maybeDeferred(function, **keywords) - else: - d = defer.maybeDeferred(function, *args) - - d.addCallback(self._gotResult, request, methodName) - d.addErrback(self._gotError, request, methodName) - return server.NOT_DONE_YET - - def _methodNotFound(self, request, methodName): - response = SOAPpy.buildSOAP(SOAPpy.faultType("%s:Client" % - SOAPpy.NS.ENV_T, "Method %s not found" % methodName), - encoding=self.encoding) - self._sendResponse(request, response, status=500) - - def _gotResult(self, result, request, methodName): - if not isinstance(result, SOAPpy.voidType): - result = {"Result": result} - response = SOAPpy.buildSOAP(kw={'%sResponse' % methodName: result}, - encoding=self.encoding) - self._sendResponse(request, response) - - def _gotError(self, failure, request, methodName): - e = failure.value - if isinstance(e, SOAPpy.faultType): - fault = e - else: - fault = SOAPpy.faultType("%s:Server" % SOAPpy.NS.ENV_T, - "Method %s failed." % methodName) - response = SOAPpy.buildSOAP(fault, encoding=self.encoding) - self._sendResponse(request, response, status=500) - - def _sendResponse(self, request, response, status=200): - request.setResponseCode(status) - - if self.encoding is not None: - mimeType = 'text/xml; charset="%s"' % self.encoding - else: - mimeType = "text/xml" - request.setHeader("Content-type", mimeType) - request.setHeader("Content-length", str(len(response))) - request.write(response) - request.finish() - - -class Proxy: - """A Proxy for making remote SOAP calls. - - Pass the URL of the remote SOAP server to the constructor. - - Use proxy.callRemote('foobar', 1, 2) to call remote method - 'foobar' with args 1 and 2, proxy.callRemote('foobar', x=1) - will call foobar with named argument 'x'. - """ - - # at some point this should have encoding etc. kwargs - def __init__(self, url, namespace=None, header=None): - self.url = url - self.namespace = namespace - self.header = header - - def _cbGotResult(self, result): - result = SOAPpy.parseSOAPRPC(result) - if hasattr(result, 'Result'): - return result.Result - elif len(result) == 1: - ## SOAPpy 0.11.6 wraps the return results in a containing structure. - ## This check added to make Proxy behaviour emulate SOAPProxy, which - ## flattens the structure by default. - ## This behaviour is OK because even singleton lists are wrapped in - ## another singleton structType, which is almost always useless. - return result[0] - else: - return result - - def callRemote(self, method, *args, **kwargs): - payload = SOAPpy.buildSOAP(args=args, kw=kwargs, method=method, - header=self.header, namespace=self.namespace) - return client.getPage(self.url, postdata=payload, method="POST", - headers={'content-type': 'text/xml', - 'SOAPAction': method} - ).addCallback(self._cbGotResult) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/static.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/static.py deleted file mode 100644 index d450166..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/static.py +++ /dev/null @@ -1,1017 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_static -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Static resources for L{twisted.web}. -""" - -from __future__ import division, absolute_import - -import os -import warnings -import itertools -import time -import errno -import mimetypes - -from zope.interface import implementer - -from twisted.web import server -from twisted.web import resource -from twisted.web import http -from twisted.web.util import redirectTo - -from twisted.python.compat import networkString, intToBytes, nativeString, _PY3 - -from twisted.python import components, filepath, log -from twisted.internet import abstract, interfaces -from twisted.python.util import InsensitiveDict -from twisted.python.runtime import platformType - -if _PY3: - from urllib.parse import quote, unquote - from html import escape -else: - from urllib import quote, unquote - from cgi import escape - -dangerousPathError = resource.NoResource("Invalid request URL.") - -def isDangerous(path): - return path == b'..' or b'/' in path or networkString(os.sep) in path - - -class Data(resource.Resource): - """ - This is a static, in-memory resource. - """ - - def __init__(self, data, type): - resource.Resource.__init__(self) - self.data = data - self.type = type - - - def render_GET(self, request): - request.setHeader(b"content-type", networkString(self.type)) - request.setHeader(b"content-length", intToBytes(len(self.data))) - if request.method == b"HEAD": - return b'' - return self.data - render_HEAD = render_GET - - -def addSlash(request): - qs = '' - qindex = request.uri.find('?') - if qindex != -1: - qs = request.uri[qindex:] - - return "http%s://%s%s/%s" % ( - request.isSecure() and 's' or '', - request.getHeader("host"), - (request.uri.split('?')[0]), - qs) - -class Redirect(resource.Resource): - def __init__(self, request): - resource.Resource.__init__(self) - self.url = addSlash(request) - - def render(self, request): - return redirectTo(self.url, request) - - -class Registry(components.Componentized): - """ - I am a Componentized object that will be made available to internal Twisted - file-based dynamic web content such as .rpy and .epy scripts. - """ - - def __init__(self): - components.Componentized.__init__(self) - self._pathCache = {} - - def cachePath(self, path, rsrc): - self._pathCache[path] = rsrc - - def getCachedPath(self, path): - return self._pathCache.get(path) - - -def loadMimeTypes(mimetype_locations=None, init=mimetypes.init): - """ - Produces a mapping of extensions (with leading dot) to MIME types. - - It does this by calling the C{init} function of the L{mimetypes} module. - This will have the side effect of modifying the global MIME types cache - in that module. - - Multiple file locations containing mime-types can be passed as a list. - The files will be sourced in that order, overriding mime-types from the - files sourced beforehand, but only if a new entry explicitly overrides - the current entry. - - @param mimetype_locations: Optional. List of paths to C{mime.types} style - files that should be used. - @type mimetype_locations: iterable of paths or C{None} - @param init: The init function to call. Defaults to the global C{init} - function of the C{mimetypes} module. For internal use (testing) only. - @type init: callable - """ - init(mimetype_locations) - mimetypes.types_map.update( - { - '.conf': 'text/plain', - '.diff': 'text/plain', - '.flac': 'audio/x-flac', - '.java': 'text/plain', - '.oz': 'text/x-oz', - '.swf': 'application/x-shockwave-flash', - '.wml': 'text/vnd.wap.wml', - '.xul': 'application/vnd.mozilla.xul+xml', - '.patch': 'text/plain' - } - ) - return mimetypes.types_map - - -def getTypeAndEncoding(filename, types, encodings, defaultType): - p, ext = filepath.FilePath(filename).splitext() - ext = filepath._coerceToFilesystemEncoding('', ext.lower()) - if ext in encodings: - enc = encodings[ext] - ext = os.path.splitext(p)[1].lower() - else: - enc = None - type = types.get(ext, defaultType) - return type, enc - - - -class File(resource.Resource, filepath.FilePath): - """ - File is a resource that represents a plain non-interpreted file - (although it can look for an extension like .rpy or .cgi and hand the - file to a processor for interpretation if you wish). Its constructor - takes a file path. - - Alternatively, you can give a directory path to the constructor. In this - case the resource will represent that directory, and its children will - be files underneath that directory. This provides access to an entire - filesystem tree with a single Resource. - - If you map the URL 'http://server/FILE' to a resource created as - File('/tmp'), then http://server/FILE/ will return an HTML-formatted - listing of the /tmp/ directory, and http://server/FILE/foo/bar.html will - return the contents of /tmp/foo/bar.html . - - @cvar childNotFound: L{Resource} used to render 404 Not Found error pages. - @cvar forbidden: L{Resource} used to render 403 Forbidden error pages. - """ - - contentTypes = loadMimeTypes() - - contentEncodings = { - ".gz" : "gzip", - ".bz2": "bzip2" - } - - processors = {} - - indexNames = ["index", "index.html", "index.htm", "index.rpy"] - - type = None - - def __init__(self, path, defaultType="text/html", ignoredExts=(), registry=None, allowExt=0): - """ - Create a file with the given path. - - @param path: The filename of the file from which this L{File} will - serve data. - @type path: C{str} - - @param defaultType: A I{major/minor}-style MIME type specifier - indicating the I{Content-Type} with which this L{File}'s data - will be served if a MIME type cannot be determined based on - C{path}'s extension. - @type defaultType: C{str} - - @param ignoredExts: A sequence giving the extensions of paths in the - filesystem which will be ignored for the purposes of child - lookup. For example, if C{ignoredExts} is C{(".bar",)} and - C{path} is a directory containing a file named C{"foo.bar"}, a - request for the C{"foo"} child of this resource will succeed - with a L{File} pointing to C{"foo.bar"}. - - @param registry: The registry object being used to handle this - request. If C{None}, one will be created. - @type registry: L{Registry} - - @param allowExt: Ignored parameter, only present for backwards - compatibility. Do not pass a value for this parameter. - """ - resource.Resource.__init__(self) - filepath.FilePath.__init__(self, path) - self.defaultType = defaultType - if ignoredExts in (0, 1) or allowExt: - warnings.warn("ignoredExts should receive a list, not a boolean") - if ignoredExts or allowExt: - self.ignoredExts = [b'*'] - else: - self.ignoredExts = [] - else: - self.ignoredExts = list(ignoredExts) - self.registry = registry or Registry() - - - def ignoreExt(self, ext): - """Ignore the given extension. - - Serve file.ext if file is requested - """ - self.ignoredExts.append(ext) - - childNotFound = resource.NoResource("File not found.") - forbidden = resource.ForbiddenResource() - - def directoryListing(self): - return DirectoryLister(self.path, - self.listNames(), - self.contentTypes, - self.contentEncodings, - self.defaultType) - - - def getChild(self, path, request): - """ - If this L{File}'s path refers to a directory, return a L{File} - referring to the file named C{path} in that directory. - - If C{path} is the empty string, return a L{DirectoryLister} instead. - """ - self.restat(reraise=False) - - if not self.isdir(): - return self.childNotFound - - if path: - try: - fpath = self.child(path) - except filepath.InsecurePath: - return self.childNotFound - else: - fpath = self.childSearchPreauth(*self.indexNames) - if fpath is None: - return self.directoryListing() - - if not fpath.exists(): - fpath = fpath.siblingExtensionSearch(*self.ignoredExts) - if fpath is None: - return self.childNotFound - - if platformType == "win32": - # don't want .RPY to be different than .rpy, since that would allow - # source disclosure. - processor = InsensitiveDict(self.processors).get(fpath.splitext()[1]) - else: - processor = self.processors.get(fpath.splitext()[1]) - if processor: - return resource.IResource(processor(fpath.path, self.registry)) - return self.createSimilarFile(fpath.path) - - - # methods to allow subclasses to e.g. decrypt files on the fly: - def openForReading(self): - """Open a file and return it.""" - return self.open() - - - def getFileSize(self): - """Return file size.""" - return self.getsize() - - - def _parseRangeHeader(self, range): - """ - Parse the value of a Range header into (start, stop) pairs. - - In a given pair, either of start or stop can be None, signifying that - no value was provided, but not both. - - @return: A list C{[(start, stop)]} of pairs of length at least one. - - @raise ValueError: if the header is syntactically invalid or if the - Bytes-Unit is anything other than 'bytes'. - """ - try: - kind, value = range.split(b'=', 1) - except ValueError: - raise ValueError("Missing '=' separator") - kind = kind.strip() - if kind != b'bytes': - raise ValueError("Unsupported Bytes-Unit: %r" % (kind,)) - unparsedRanges = list(filter(None, map(bytes.strip, value.split(b',')))) - parsedRanges = [] - for byteRange in unparsedRanges: - try: - start, end = byteRange.split(b'-', 1) - except ValueError: - raise ValueError("Invalid Byte-Range: %r" % (byteRange,)) - if start: - try: - start = int(start) - except ValueError: - raise ValueError("Invalid Byte-Range: %r" % (byteRange,)) - else: - start = None - if end: - try: - end = int(end) - except ValueError: - raise ValueError("Invalid Byte-Range: %r" % (byteRange,)) - else: - end = None - if start is not None: - if end is not None and start > end: - # Start must be less than or equal to end or it is invalid. - raise ValueError("Invalid Byte-Range: %r" % (byteRange,)) - elif end is None: - # One or both of start and end must be specified. Omitting - # both is invalid. - raise ValueError("Invalid Byte-Range: %r" % (byteRange,)) - parsedRanges.append((start, end)) - return parsedRanges - - - def _rangeToOffsetAndSize(self, start, end): - """ - Convert a start and end from a Range header to an offset and size. - - This method checks that the resulting range overlaps with the resource - being served (and so has the value of C{getFileSize()} as an indirect - input). - - Either but not both of start or end can be C{None}: - - - Omitted start means that the end value is actually a start value - relative to the end of the resource. - - - Omitted end means the end of the resource should be the end of - the range. - - End is interpreted as inclusive, as per RFC 2616. - - If this range doesn't overlap with any of this resource, C{(0, 0)} is - returned, which is not otherwise a value return value. - - @param start: The start value from the header, or C{None} if one was - not present. - @param end: The end value from the header, or C{None} if one was not - present. - @return: C{(offset, size)} where offset is how far into this resource - this resource the range begins and size is how long the range is, - or C{(0, 0)} if the range does not overlap this resource. - """ - size = self.getFileSize() - if start is None: - start = size - end - end = size - elif end is None: - end = size - elif end < size: - end += 1 - elif end > size: - end = size - if start >= size: - start = end = 0 - return start, (end - start) - - - def _contentRange(self, offset, size): - """ - Return a string suitable for the value of a Content-Range header for a - range with the given offset and size. - - The offset and size are not sanity checked in any way. - - @param offset: How far into this resource the range begins. - @param size: How long the range is. - @return: The value as appropriate for the value of a Content-Range - header. - """ - return networkString('bytes %d-%d/%d' % ( - offset, offset + size - 1, self.getFileSize())) - - - def _doSingleRangeRequest(self, request, startAndEnd): - """ - Set up the response for Range headers that specify a single range. - - This method checks if the request is satisfiable and sets the response - code and Content-Range header appropriately. The return value - indicates which part of the resource to return. - - @param request: The Request object. - @param startAndEnd: A 2-tuple of start of the byte range as specified by - the header and the end of the byte range as specified by the header. - At most one of the start and end may be C{None}. - @return: A 2-tuple of the offset and size of the range to return. - offset == size == 0 indicates that the request is not satisfiable. - """ - start, end = startAndEnd - offset, size = self._rangeToOffsetAndSize(start, end) - if offset == size == 0: - # This range doesn't overlap with any of this resource, so the - # request is unsatisfiable. - request.setResponseCode(http.REQUESTED_RANGE_NOT_SATISFIABLE) - request.setHeader( - b'content-range', networkString('bytes */%d' % (self.getFileSize(),))) - else: - request.setResponseCode(http.PARTIAL_CONTENT) - request.setHeader( - b'content-range', self._contentRange(offset, size)) - return offset, size - - - def _doMultipleRangeRequest(self, request, byteRanges): - """ - Set up the response for Range headers that specify a single range. - - This method checks if the request is satisfiable and sets the response - code and Content-Type and Content-Length headers appropriately. The - return value, which is a little complicated, indicates which parts of - the resource to return and the boundaries that should separate the - parts. - - In detail, the return value is a tuple rangeInfo C{rangeInfo} is a - list of 3-tuples C{(partSeparator, partOffset, partSize)}. The - response to this request should be, for each element of C{rangeInfo}, - C{partSeparator} followed by C{partSize} bytes of the resource - starting at C{partOffset}. Each C{partSeparator} includes the - MIME-style boundary and the part-specific Content-type and - Content-range headers. It is convenient to return the separator as a - concrete string from this method, because this method needs to compute - the number of bytes that will make up the response to be able to set - the Content-Length header of the response accurately. - - @param request: The Request object. - @param byteRanges: A list of C{(start, end)} values as specified by - the header. For each range, at most one of C{start} and C{end} - may be C{None}. - @return: See above. - """ - matchingRangeFound = False - rangeInfo = [] - contentLength = 0 - boundary = networkString("%x%x" % (int(time.time()*1000000), os.getpid())) - if self.type: - contentType = self.type - else: - contentType = b'bytes' # It's what Apache does... - for start, end in byteRanges: - partOffset, partSize = self._rangeToOffsetAndSize(start, end) - if partOffset == partSize == 0: - continue - contentLength += partSize - matchingRangeFound = True - partContentRange = self._contentRange(partOffset, partSize) - partSeparator = networkString(( - "\r\n" - "--%s\r\n" - "Content-type: %s\r\n" - "Content-range: %s\r\n" - "\r\n") % (nativeString(boundary), nativeString(contentType), nativeString(partContentRange))) - contentLength += len(partSeparator) - rangeInfo.append((partSeparator, partOffset, partSize)) - if not matchingRangeFound: - request.setResponseCode(http.REQUESTED_RANGE_NOT_SATISFIABLE) - request.setHeader( - b'content-length', b'0') - request.setHeader( - b'content-range', networkString('bytes */%d' % (self.getFileSize(),))) - return [], b'' - finalBoundary = b"\r\n--" + boundary + b"--\r\n" - rangeInfo.append((finalBoundary, 0, 0)) - request.setResponseCode(http.PARTIAL_CONTENT) - request.setHeader( - b'content-type', networkString('multipart/byteranges; boundary="%s"' % (nativeString(boundary),))) - request.setHeader( - b'content-length', intToBytes(contentLength + len(finalBoundary))) - return rangeInfo - - - def _setContentHeaders(self, request, size=None): - """ - Set the Content-length and Content-type headers for this request. - - This method is not appropriate for requests for multiple byte ranges; - L{_doMultipleRangeRequest} will set these headers in that case. - - @param request: The L{Request} object. - @param size: The size of the response. If not specified, default to - C{self.getFileSize()}. - """ - if size is None: - size = self.getFileSize() - request.setHeader(b'content-length', intToBytes(size)) - if self.type: - request.setHeader(b'content-type', networkString(self.type)) - if self.encoding: - request.setHeader(b'content-encoding', networkString(self.encoding)) - - - def makeProducer(self, request, fileForReading): - """ - Make a L{StaticProducer} that will produce the body of this response. - - This method will also set the response code and Content-* headers. - - @param request: The L{Request} object. - @param fileForReading: The file object containing the resource. - @return: A L{StaticProducer}. Calling C{.start()} on this will begin - producing the response. - """ - byteRange = request.getHeader(b'range') - if byteRange is None: - self._setContentHeaders(request) - request.setResponseCode(http.OK) - return NoRangeStaticProducer(request, fileForReading) - try: - parsedRanges = self._parseRangeHeader(byteRange) - except ValueError: - log.msg("Ignoring malformed Range header %r" % (byteRange.decode(),)) - self._setContentHeaders(request) - request.setResponseCode(http.OK) - return NoRangeStaticProducer(request, fileForReading) - - if len(parsedRanges) == 1: - offset, size = self._doSingleRangeRequest( - request, parsedRanges[0]) - self._setContentHeaders(request, size) - return SingleRangeStaticProducer( - request, fileForReading, offset, size) - else: - rangeInfo = self._doMultipleRangeRequest(request, parsedRanges) - return MultipleRangeStaticProducer( - request, fileForReading, rangeInfo) - - - def render_GET(self, request): - """ - Begin sending the contents of this L{File} (or a subset of the - contents, based on the 'range' header) to the given request. - """ - self.restat(False) - - if self.type is None: - self.type, self.encoding = getTypeAndEncoding(self.basename(), - self.contentTypes, - self.contentEncodings, - self.defaultType) - - if not self.exists(): - return self.childNotFound.render(request) - - if self.isdir(): - return self.redirect(request) - - request.setHeader(b'accept-ranges', b'bytes') - - try: - fileForReading = self.openForReading() - except IOError as e: - if e.errno == errno.EACCES: - return self.forbidden.render(request) - else: - raise - - if request.setLastModified(self.getModificationTime()) is http.CACHED: - # `setLastModified` also sets the response code for us, so if the - # request is cached, we close the file now that we've made sure that - # the request would otherwise succeed and return an empty body. - fileForReading.close() - return b'' - - if request.method == b'HEAD': - # Set the content headers here, rather than making a producer. - self._setContentHeaders(request) - # We've opened the file to make sure it's accessible, so close it - # now that we don't need it. - fileForReading.close() - return b'' - - producer = self.makeProducer(request, fileForReading) - producer.start() - - # and make sure the connection doesn't get closed - return server.NOT_DONE_YET - render_HEAD = render_GET - - - def redirect(self, request): - return redirectTo(addSlash(request), request) - - - def listNames(self): - if not self.isdir(): - return [] - directory = self.listdir() - directory.sort() - return directory - - def listEntities(self): - return list(map(lambda fileName, self=self: self.createSimilarFile(os.path.join(self.path, fileName)), self.listNames())) - - - def createSimilarFile(self, path): - f = self.__class__(path, self.defaultType, self.ignoredExts, self.registry) - # refactoring by steps, here - constructor should almost certainly take these - f.processors = self.processors - f.indexNames = self.indexNames[:] - f.childNotFound = self.childNotFound - return f - - - -@implementer(interfaces.IPullProducer) -class StaticProducer(object): - """ - Superclass for classes that implement the business of producing. - - @ivar request: The L{IRequest} to write the contents of the file to. - @ivar fileObject: The file the contents of which to write to the request. - """ - - bufferSize = abstract.FileDescriptor.bufferSize - - - def __init__(self, request, fileObject): - """ - Initialize the instance. - """ - self.request = request - self.fileObject = fileObject - - - def start(self): - raise NotImplementedError(self.start) - - - def resumeProducing(self): - raise NotImplementedError(self.resumeProducing) - - - def stopProducing(self): - """ - Stop producing data. - - L{IPullProducer.stopProducing} is called when our consumer has died, - and subclasses also call this method when they are done producing - data. - """ - self.fileObject.close() - self.request = None - - - -class NoRangeStaticProducer(StaticProducer): - """ - A L{StaticProducer} that writes the entire file to the request. - """ - - def start(self): - self.request.registerProducer(self, False) - - - def resumeProducing(self): - if not self.request: - return - data = self.fileObject.read(self.bufferSize) - if data: - # this .write will spin the reactor, calling .doWrite and then - # .resumeProducing again, so be prepared for a re-entrant call - self.request.write(data) - else: - self.request.unregisterProducer() - self.request.finish() - self.stopProducing() - - - -class SingleRangeStaticProducer(StaticProducer): - """ - A L{StaticProducer} that writes a single chunk of a file to the request. - """ - - def __init__(self, request, fileObject, offset, size): - """ - Initialize the instance. - - @param request: See L{StaticProducer}. - @param fileObject: See L{StaticProducer}. - @param offset: The offset into the file of the chunk to be written. - @param size: The size of the chunk to write. - """ - StaticProducer.__init__(self, request, fileObject) - self.offset = offset - self.size = size - - - def start(self): - self.fileObject.seek(self.offset) - self.bytesWritten = 0 - self.request.registerProducer(self, 0) - - - def resumeProducing(self): - if not self.request: - return - data = self.fileObject.read( - min(self.bufferSize, self.size - self.bytesWritten)) - if data: - self.bytesWritten += len(data) - # this .write will spin the reactor, calling .doWrite and then - # .resumeProducing again, so be prepared for a re-entrant call - self.request.write(data) - if self.request and self.bytesWritten == self.size: - self.request.unregisterProducer() - self.request.finish() - self.stopProducing() - - - -class MultipleRangeStaticProducer(StaticProducer): - """ - A L{StaticProducer} that writes several chunks of a file to the request. - """ - - def __init__(self, request, fileObject, rangeInfo): - """ - Initialize the instance. - - @param request: See L{StaticProducer}. - @param fileObject: See L{StaticProducer}. - @param rangeInfo: A list of tuples C{[(boundary, offset, size)]} - where: - - C{boundary} will be written to the request first. - - C{offset} the offset into the file of chunk to write. - - C{size} the size of the chunk to write. - """ - StaticProducer.__init__(self, request, fileObject) - self.rangeInfo = rangeInfo - - - def start(self): - self.rangeIter = iter(self.rangeInfo) - self._nextRange() - self.request.registerProducer(self, 0) - - - def _nextRange(self): - self.partBoundary, partOffset, self._partSize = next(self.rangeIter) - self._partBytesWritten = 0 - self.fileObject.seek(partOffset) - - - def resumeProducing(self): - if not self.request: - return - data = [] - dataLength = 0 - done = False - while dataLength < self.bufferSize: - if self.partBoundary: - dataLength += len(self.partBoundary) - data.append(self.partBoundary) - self.partBoundary = None - p = self.fileObject.read( - min(self.bufferSize - dataLength, - self._partSize - self._partBytesWritten)) - self._partBytesWritten += len(p) - dataLength += len(p) - data.append(p) - if self.request and self._partBytesWritten == self._partSize: - try: - self._nextRange() - except StopIteration: - done = True - break - self.request.write(b''.join(data)) - if done: - self.request.unregisterProducer() - self.request.finish() - self.stopProducing() - - - -class ASISProcessor(resource.Resource): - """ - Serve files exactly as responses without generating a status-line or any - headers. Inspired by Apache's mod_asis. - """ - - def __init__(self, path, registry=None): - resource.Resource.__init__(self) - self.path = path - self.registry = registry or Registry() - - - def render(self, request): - request.startedWriting = 1 - res = File(self.path, registry=self.registry) - return res.render(request) - - - -def formatFileSize(size): - """ - Format the given file size in bytes to human readable format. - """ - if size < 1024: - return '%iB' % size - elif size < (1024 ** 2): - return '%iK' % (size / 1024) - elif size < (1024 ** 3): - return '%iM' % (size / (1024 ** 2)) - else: - return '%iG' % (size / (1024 ** 3)) - - - -class DirectoryLister(resource.Resource): - """ - Print the content of a directory. - - @ivar template: page template used to render the content of the directory. - It must contain the format keys B{header} and B{tableContent}. - @type template: C{str} - - @ivar linePattern: template used to render one line in the listing table. - It must contain the format keys B{class}, B{href}, B{text}, B{size}, - B{type} and B{encoding}. - @type linePattern: C{str} - - @ivar contentEncodings: a mapping of extensions to encoding types. - @type contentEncodings: C{dict} - - @ivar defaultType: default type used when no mimetype is detected. - @type defaultType: C{str} - - @ivar dirs: filtered content of C{path}, if the whole content should not be - displayed (default to C{None}, which means the actual content of - C{path} is printed). - @type dirs: C{NoneType} or C{list} - - @ivar path: directory which content should be listed. - @type path: C{str} - """ - - template = """ - -%(header)s - - - - -

%(header)s

- -
NameModifiedSize

- - - - - - - - - -%(tableContent)s - -
FilenameSizeContent typeContent encoding
- - - -""" - - linePattern = """ - %(text)s - %(size)s - %(type)s - %(encoding)s - -""" - - def __init__(self, pathname, dirs=None, - contentTypes=File.contentTypes, - contentEncodings=File.contentEncodings, - defaultType='text/html'): - resource.Resource.__init__(self) - self.contentTypes = contentTypes - self.contentEncodings = contentEncodings - self.defaultType = defaultType - # dirs allows usage of the File to specify what gets listed - self.dirs = dirs - self.path = pathname - - - def _getFilesAndDirectories(self, directory): - """ - Helper returning files and directories in given directory listing, with - attributes to be used to build a table content with - C{self.linePattern}. - - @return: tuple of (directories, files) - @rtype: C{tuple} of C{list} - """ - files = [] - dirs = [] - - for path in directory: - if _PY3: - if isinstance(path, bytes): - path = path.decode("utf8") - - url = quote(path, "/") - escapedPath = escape(path) - childPath = filepath.FilePath(self.path).child(path) - - if childPath.isdir(): - dirs.append({'text': escapedPath + "/", 'href': url + "/", - 'size': '', 'type': '[Directory]', - 'encoding': ''}) - else: - mimetype, encoding = getTypeAndEncoding(path, self.contentTypes, - self.contentEncodings, - self.defaultType) - try: - size = childPath.getsize() - except OSError: - continue - files.append({ - 'text': escapedPath, "href": url, - 'type': '[%s]' % mimetype, - 'encoding': (encoding and '[%s]' % encoding or ''), - 'size': formatFileSize(size)}) - return dirs, files - - - def _buildTableContent(self, elements): - """ - Build a table content using C{self.linePattern} and giving elements odd - and even classes. - """ - tableContent = [] - rowClasses = itertools.cycle(['odd', 'even']) - for element, rowClass in zip(elements, rowClasses): - element["class"] = rowClass - tableContent.append(self.linePattern % element) - return tableContent - - - def render(self, request): - """ - Render a listing of the content of C{self.path}. - """ - request.setHeader(b"content-type", b"text/html; charset=utf-8") - if self.dirs is None: - directory = os.listdir(self.path) - directory.sort() - else: - directory = self.dirs - - dirs, files = self._getFilesAndDirectories(directory) - - tableContent = "".join(self._buildTableContent(dirs + files)) - - header = "Directory listing for %s" % ( - escape(unquote(nativeString(request.uri))),) - - done = self.template % {"header": header, "tableContent": tableContent} - if _PY3: - done = done.encode("utf8") - - return done - - - def __repr__(self): - return '' % self.path - - __str__ = __repr__ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/sux.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/sux.py deleted file mode 100644 index 0d86ed6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/sux.py +++ /dev/null @@ -1,636 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xml -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -*S*mall, *U*ncomplicated *X*ML. - -This is a very simple implementation of XML/HTML as a network -protocol. It is not at all clever. Its main features are that it -does not: - - - support namespaces - - mung mnemonic entity references - - validate - - perform *any* external actions (such as fetching URLs or writing files) - under *any* circumstances - - has lots and lots of horrible hacks for supporting broken HTML (as an - option, they're not on by default). -""" - -from twisted.internet.protocol import Protocol -from twisted.python.reflect import prefixedMethodNames - - - -# Elements of the three-tuples in the state table. -BEGIN_HANDLER = 0 -DO_HANDLER = 1 -END_HANDLER = 2 - -identChars = '.-_:' -lenientIdentChars = identChars + ';+#/%~' - -def nop(*args, **kw): - "Do nothing." - - -def unionlist(*args): - l = [] - for x in args: - l.extend(x) - d = dict([(x, 1) for x in l]) - return d.keys() - - -def zipfndict(*args, **kw): - default = kw.get('default', nop) - d = {} - for key in unionlist(*[fndict.keys() for fndict in args]): - d[key] = tuple([x.get(key, default) for x in args]) - return d - - -def prefixedMethodClassDict(clazz, prefix): - return dict([(name, getattr(clazz, prefix + name)) for name in prefixedMethodNames(clazz, prefix)]) - - -def prefixedMethodObjDict(obj, prefix): - return dict([(name, getattr(obj, prefix + name)) for name in prefixedMethodNames(obj.__class__, prefix)]) - - -class ParseError(Exception): - - def __init__(self, filename, line, col, message): - self.filename = filename - self.line = line - self.col = col - self.message = message - - def __str__(self): - return "%s:%s:%s: %s" % (self.filename, self.line, self.col, - self.message) - -class XMLParser(Protocol): - - state = None - encodings = None - filename = "" - beExtremelyLenient = 0 - _prepend = None - - # _leadingBodyData will sometimes be set before switching to the - # 'bodydata' state, when we "accidentally" read a byte of bodydata - # in a different state. - _leadingBodyData = None - - def connectionMade(self): - self.lineno = 1 - self.colno = 0 - self.encodings = [] - - def saveMark(self): - '''Get the line number and column of the last character parsed''' - # This gets replaced during dataReceived, restored afterwards - return (self.lineno, self.colno) - - def _parseError(self, message): - raise ParseError(*((self.filename,)+self.saveMark()+(message,))) - - def _buildStateTable(self): - '''Return a dictionary of begin, do, end state function tuples''' - # _buildStateTable leaves something to be desired but it does what it - # does.. probably slowly, so I'm doing some evil caching so it doesn't - # get called more than once per class. - stateTable = getattr(self.__class__, '__stateTable', None) - if stateTable is None: - stateTable = self.__class__.__stateTable = zipfndict( - *[prefixedMethodObjDict(self, prefix) - for prefix in ('begin_', 'do_', 'end_')]) - return stateTable - - def _decode(self, data): - if 'UTF-16' in self.encodings or 'UCS-2' in self.encodings: - assert not len(data) & 1, 'UTF-16 must come in pairs for now' - if self._prepend: - data = self._prepend + data - for encoding in self.encodings: - data = unicode(data, encoding) - return data - - def maybeBodyData(self): - if self.endtag: - return 'bodydata' - - # Get ready for fun! We're going to allow - # to work! - # We do this by making everything between a Text - # BUT - # -radix - - if (self.tagName == 'script' and 'src' not in self.tagAttributes): - # we do this ourselves rather than having begin_waitforendscript - # because that can get called multiple times and we don't want - # bodydata to get reset other than the first time. - self.begin_bodydata(None) - return 'waitforendscript' - return 'bodydata' - - - - def dataReceived(self, data): - stateTable = self._buildStateTable() - if not self.state: - # all UTF-16 starts with this string - if data.startswith('\xff\xfe'): - self._prepend = '\xff\xfe' - self.encodings.append('UTF-16') - data = data[2:] - elif data.startswith('\xfe\xff'): - self._prepend = '\xfe\xff' - self.encodings.append('UTF-16') - data = data[2:] - self.state = 'begin' - if self.encodings: - data = self._decode(data) - # bring state, lineno, colno into local scope - lineno, colno = self.lineno, self.colno - curState = self.state - # replace saveMark with a nested scope function - _saveMark = self.saveMark - def saveMark(): - return (lineno, colno) - self.saveMark = saveMark - # fetch functions from the stateTable - beginFn, doFn, endFn = stateTable[curState] - try: - for byte in data: - # do newline stuff - if byte == '\n': - lineno += 1 - colno = 0 - else: - colno += 1 - newState = doFn(byte) - if newState is not None and newState != curState: - # this is the endFn from the previous state - endFn() - curState = newState - beginFn, doFn, endFn = stateTable[curState] - beginFn(byte) - finally: - self.saveMark = _saveMark - self.lineno, self.colno = lineno, colno - # state doesn't make sense if there's an exception.. - self.state = curState - - - def connectionLost(self, reason): - """ - End the last state we were in. - """ - stateTable = self._buildStateTable() - stateTable[self.state][END_HANDLER]() - - - # state methods - - def do_begin(self, byte): - if byte.isspace(): - return - if byte != '<': - if self.beExtremelyLenient: - self._leadingBodyData = byte - return 'bodydata' - self._parseError("First char of document [%r] wasn't <" % (byte,)) - return 'tagstart' - - def begin_comment(self, byte): - self.commentbuf = '' - - def do_comment(self, byte): - self.commentbuf += byte - if self.commentbuf.endswith('-->'): - self.gotComment(self.commentbuf[:-3]) - return 'bodydata' - - def begin_tagstart(self, byte): - self.tagName = '' # name of the tag - self.tagAttributes = {} # attributes of the tag - self.termtag = 0 # is the tag self-terminating - self.endtag = 0 - - def do_tagstart(self, byte): - if byte.isalnum() or byte in identChars: - self.tagName += byte - if self.tagName == '!--': - return 'comment' - elif byte.isspace(): - if self.tagName: - if self.endtag: - # properly strict thing to do here is probably to only - # accept whitespace - return 'waitforgt' - return 'attrs' - else: - self._parseError("Whitespace before tag-name") - elif byte == '>': - if self.endtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - else: - self.gotTagStart(self.tagName, {}) - return (not self.beExtremelyLenient) and 'bodydata' or self.maybeBodyData() - elif byte == '/': - if self.tagName: - return 'afterslash' - else: - self.endtag = 1 - elif byte in '!?': - if self.tagName: - if not self.beExtremelyLenient: - self._parseError("Invalid character in tag-name") - else: - self.tagName += byte - self.termtag = 1 - elif byte == '[': - if self.tagName == '!': - return 'expectcdata' - else: - self._parseError("Invalid '[' in tag-name") - else: - if self.beExtremelyLenient: - self.bodydata = '<' - return 'unentity' - self._parseError('Invalid tag character: %r'% byte) - - def begin_unentity(self, byte): - self.bodydata += byte - - def do_unentity(self, byte): - self.bodydata += byte - return 'bodydata' - - def end_unentity(self): - self.gotText(self.bodydata) - - def begin_expectcdata(self, byte): - self.cdatabuf = byte - - def do_expectcdata(self, byte): - self.cdatabuf += byte - cdb = self.cdatabuf - cd = '[CDATA[' - if len(cd) > len(cdb): - if cd.startswith(cdb): - return - elif self.beExtremelyLenient: - ## WHAT THE CRAP!? MSWord9 generates HTML that includes these - ## bizarre chunks, so I've gotta ignore - ## 'em as best I can. this should really be a separate parse - ## state but I don't even have any idea what these _are_. - return 'waitforgt' - else: - self._parseError("Mal-formed CDATA header") - if cd == cdb: - self.cdatabuf = '' - return 'cdata' - self._parseError("Mal-formed CDATA header") - - def do_cdata(self, byte): - self.cdatabuf += byte - if self.cdatabuf.endswith("]]>"): - self.cdatabuf = self.cdatabuf[:-3] - return 'bodydata' - - def end_cdata(self): - self.gotCData(self.cdatabuf) - self.cdatabuf = '' - - def do_attrs(self, byte): - if byte.isalnum() or byte in identChars: - # XXX FIXME really handle !DOCTYPE at some point - if self.tagName == '!DOCTYPE': - return 'doctype' - if self.tagName[0] in '!?': - return 'waitforgt' - return 'attrname' - elif byte.isspace(): - return - elif byte == '>': - self.gotTagStart(self.tagName, self.tagAttributes) - return (not self.beExtremelyLenient) and 'bodydata' or self.maybeBodyData() - elif byte == '/': - return 'afterslash' - elif self.beExtremelyLenient: - # discard and move on? Only case I've seen of this so far was: - # - return - self._parseError("Unexpected character: %r" % byte) - - def begin_doctype(self, byte): - self.doctype = byte - - def do_doctype(self, byte): - if byte == '>': - return 'bodydata' - self.doctype += byte - - def end_doctype(self): - self.gotDoctype(self.doctype) - self.doctype = None - - def do_waitforgt(self, byte): - if byte == '>': - if self.endtag or not self.beExtremelyLenient: - return 'bodydata' - return self.maybeBodyData() - - def begin_attrname(self, byte): - self.attrname = byte - self._attrname_termtag = 0 - - def do_attrname(self, byte): - if byte.isalnum() or byte in identChars: - self.attrname += byte - return - elif byte == '=': - return 'beforeattrval' - elif byte.isspace(): - return 'beforeeq' - elif self.beExtremelyLenient: - if byte in '"\'': - return 'attrval' - if byte in lenientIdentChars or byte.isalnum(): - self.attrname += byte - return - if byte == '/': - self._attrname_termtag = 1 - return - if byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if self._attrname_termtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - # something is really broken. let's leave this attribute where it - # is and move on to the next thing - return - self._parseError("Invalid attribute name: %r %r" % (self.attrname, byte)) - - def do_beforeattrval(self, byte): - if byte in '"\'': - return 'attrval' - elif byte.isspace(): - return - elif self.beExtremelyLenient: - if byte in lenientIdentChars or byte.isalnum(): - return 'messyattr' - if byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - return self.maybeBodyData() - if byte == '\\': - # I saw this in actual HTML once: - # SM - return - self._parseError("Invalid initial attribute value: %r; Attribute values must be quoted." % byte) - - attrname = '' - attrval = '' - - def begin_beforeeq(self,byte): - self._beforeeq_termtag = 0 - - def do_beforeeq(self, byte): - if byte == '=': - return 'beforeattrval' - elif byte.isspace(): - return - elif self.beExtremelyLenient: - if byte.isalnum() or byte in identChars: - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - return 'attrname' - elif byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if self._beforeeq_termtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - elif byte == '/': - self._beforeeq_termtag = 1 - return - self._parseError("Invalid attribute") - - def begin_attrval(self, byte): - self.quotetype = byte - self.attrval = '' - - def do_attrval(self, byte): - if byte == self.quotetype: - return 'attrs' - self.attrval += byte - - def end_attrval(self): - self.tagAttributes[self.attrname] = self.attrval - self.attrname = self.attrval = '' - - def begin_messyattr(self, byte): - self.attrval = byte - - def do_messyattr(self, byte): - if byte.isspace(): - return 'attrs' - elif byte == '>': - endTag = 0 - if self.attrval.endswith('/'): - endTag = 1 - self.attrval = self.attrval[:-1] - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if endTag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - else: - self.attrval += byte - - def end_messyattr(self): - if self.attrval: - self.tagAttributes[self.attrname] = self.attrval - - def begin_afterslash(self, byte): - self._after_slash_closed = 0 - - def do_afterslash(self, byte): - # this state is only after a self-terminating slash, e.g. - if self._after_slash_closed: - self._parseError("Mal-formed")#XXX When does this happen?? - if byte != '>': - if self.beExtremelyLenient: - return - else: - self._parseError("No data allowed after '/'") - self._after_slash_closed = 1 - self.gotTagStart(self.tagName, self.tagAttributes) - self.gotTagEnd(self.tagName) - # don't need maybeBodyData here because there better not be - # any javascript code after a , we need to - # remember all the data we've been through so we can append it - # to bodydata - self.temptagdata += byte - - # 1 - if byte == '/': - self.endtag = True - elif not self.endtag: - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - # 2 - elif byte.isalnum() or byte in identChars: - self.tagName += byte - if not 'script'.startswith(self.tagName): - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - elif self.tagName == 'script': - self.gotText(self.bodydata) - self.gotTagEnd(self.tagName) - return 'waitforgt' - # 3 - elif byte.isspace(): - return 'waitscriptendtag' - # 4 - else: - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - - - def begin_entityref(self, byte): - self.erefbuf = '' - self.erefextra = '' # extra bit for lenient mode - - def do_entityref(self, byte): - if byte.isspace() or byte == "<": - if self.beExtremelyLenient: - # '&foo' probably was '&foo' - if self.erefbuf and self.erefbuf != "amp": - self.erefextra = self.erefbuf - self.erefbuf = "amp" - if byte == "<": - return "tagstart" - else: - self.erefextra += byte - return 'spacebodydata' - self._parseError("Bad entity reference") - elif byte != ';': - self.erefbuf += byte - else: - return 'bodydata' - - def end_entityref(self): - self.gotEntityReference(self.erefbuf) - - # hacky support for space after & in entityref in beExtremelyLenient - # state should only happen in that case - def begin_spacebodydata(self, byte): - self.bodydata = self.erefextra - self.erefextra = None - do_spacebodydata = do_bodydata - end_spacebodydata = end_bodydata - - # Sorta SAX-ish API - - def gotTagStart(self, name, attributes): - '''Encountered an opening tag. - - Default behaviour is to print.''' - print 'begin', name, attributes - - def gotText(self, data): - '''Encountered text - - Default behaviour is to print.''' - print 'text:', repr(data) - - def gotEntityReference(self, entityRef): - '''Encountered mnemonic entity reference - - Default behaviour is to print.''' - print 'entityRef: &%s;' % entityRef - - def gotComment(self, comment): - '''Encountered comment. - - Default behaviour is to ignore.''' - pass - - def gotCData(self, cdata): - '''Encountered CDATA - - Default behaviour is to call the gotText method''' - self.gotText(cdata) - - def gotDoctype(self, doctype): - """Encountered DOCTYPE - - This is really grotty: it basically just gives you everything between - '' as an argument. - """ - print '!DOCTYPE', repr(doctype) - - def gotTagEnd(self, name): - '''Encountered closing tag - - Default behaviour is to print.''' - print 'end', name diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/tap.py deleted file mode 100644 index 60abaf6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/tap.py +++ /dev/null @@ -1,232 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for creating a service which runs a web server. -""" - -import os - -# Twisted Imports -from twisted.web import server, static, twcgi, script, demo, distrib, wsgi -from twisted.internet import interfaces, reactor -from twisted.python import usage, reflect, threadpool -from twisted.spread import pb -from twisted.application import internet, service, strports - - -class Options(usage.Options): - """ - Define the options accepted by the I{twistd web} plugin. - """ - synopsis = "[web options]" - - optParameters = [["port", "p", None, "strports description of the port to " - "start the server on."], - ["logfile", "l", None, "Path to web CLF (Combined Log Format) log file."], - ["https", None, None, "Port to listen on for Secure HTTP."], - ["certificate", "c", "server.pem", "SSL certificate to use for HTTPS. "], - ["privkey", "k", "server.pem", "SSL certificate to use for HTTPS."], - ] - - optFlags = [["personal", "", - "Instead of generating a webserver, generate a " - "ResourcePublisher which listens on the port given by " - "--port, or ~/%s " % (distrib.UserDirectory.userSocketName,) + - "if --port is not specified."], - ["notracebacks", "n", "Do not display tracebacks in broken web pages. " + - "Displaying tracebacks to users may be security risk!"], - ] - - compData = usage.Completions( - optActions={"logfile" : usage.CompleteFiles("*.log"), - "certificate" : usage.CompleteFiles("*.pem"), - "privkey" : usage.CompleteFiles("*.pem")} - ) - - longdesc = """\ -This starts a webserver. If you specify no arguments, it will be a -demo webserver that has the Test class from twisted.web.demo in it.""" - - def __init__(self): - usage.Options.__init__(self) - self['indexes'] = [] - self['root'] = None - - - def opt_index(self, indexName): - """ - Add the name of a file used to check for directory indexes. - [default: index, index.html] - """ - self['indexes'].append(indexName) - - opt_i = opt_index - - - def opt_user(self): - """ - Makes a server with ~/public_html and ~/.twistd-web-pb support for - users. - """ - self['root'] = distrib.UserDirectory() - - opt_u = opt_user - - - def opt_path(self, path): - """ - is either a specific file or a directory to be set as the root - of the web server. Use this if you have a directory full of HTML, cgi, - epy, or rpy files or any other files that you want to be served up raw. - """ - self['root'] = static.File(os.path.abspath(path)) - self['root'].processors = { - '.cgi': twcgi.CGIScript, - '.epy': script.PythonScript, - '.rpy': script.ResourceScript, - } - - - def opt_processor(self, proc): - """ - `ext=class' where `class' is added as a Processor for files ending - with `ext'. - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --processor after --path.") - ext, klass = proc.split('=', 1) - self['root'].processors[ext] = reflect.namedClass(klass) - - - def opt_class(self, className): - """ - Create a Resource subclass with a zero-argument constructor. - """ - classObj = reflect.namedClass(className) - self['root'] = classObj() - - - def opt_resource_script(self, name): - """ - An .rpy file to be used as the root resource of the webserver. - """ - self['root'] = script.ResourceScriptWrapper(name) - - - def opt_wsgi(self, name): - """ - The FQPN of a WSGI application object to serve as the root resource of - the webserver. - """ - try: - application = reflect.namedAny(name) - except (AttributeError, ValueError): - raise usage.UsageError("No such WSGI application: %r" % (name,)) - pool = threadpool.ThreadPool() - reactor.callWhenRunning(pool.start) - reactor.addSystemEventTrigger('after', 'shutdown', pool.stop) - self['root'] = wsgi.WSGIResource(reactor, pool, application) - - - def opt_mime_type(self, defaultType): - """ - Specify the default mime-type for static files. - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --mime_type after --path.") - self['root'].defaultType = defaultType - opt_m = opt_mime_type - - - def opt_allow_ignore_ext(self): - """ - Specify whether or not a request for 'foo' should return 'foo.ext' - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --allow_ignore_ext " - "after --path.") - self['root'].ignoreExt('*') - - - def opt_ignore_ext(self, ext): - """ - Specify an extension to ignore. These will be processed in order. - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --ignore_ext " - "after --path.") - self['root'].ignoreExt(ext) - - - def postOptions(self): - """ - Set up conditional defaults and check for dependencies. - - If SSL is not available but an HTTPS server was configured, raise a - L{UsageError} indicating that this is not possible. - - If no server port was supplied, select a default appropriate for the - other options supplied. - """ - if self['https']: - try: - reflect.namedModule('OpenSSL.SSL') - except ImportError: - raise usage.UsageError("SSL support not installed") - if self['port'] is None: - if self['personal']: - path = os.path.expanduser( - os.path.join('~', distrib.UserDirectory.userSocketName)) - self['port'] = 'unix:' + path - else: - self['port'] = 'tcp:8080' - - - -def makePersonalServerFactory(site): - """ - Create and return a factory which will respond to I{distrib} requests - against the given site. - - @type site: L{twisted.web.server.Site} - @rtype: L{twisted.internet.protocol.Factory} - """ - return pb.PBServerFactory(distrib.ResourcePublisher(site)) - - - -def makeService(config): - s = service.MultiService() - if config['root']: - root = config['root'] - if config['indexes']: - config['root'].indexNames = config['indexes'] - else: - # This really ought to be web.Admin or something - root = demo.Test() - - if isinstance(root, static.File): - root.registry.setComponent(interfaces.IServiceCollection, s) - - if config['logfile']: - site = server.Site(root, logPath=config['logfile']) - else: - site = server.Site(root) - - site.displayTracebacks = not config["notracebacks"] - - if config['personal']: - personal = strports.service( - config['port'], makePersonalServerFactory(site)) - personal.setServiceParent(s) - else: - if config['https']: - from twisted.internet.ssl import DefaultOpenSSLContextFactory - i = internet.SSLServer(int(config['https']), site, - DefaultOpenSSLContextFactory(config['privkey'], - config['certificate'])) - i.setServiceParent(s) - strports.service(config['port'], site).setServiceParent(s) - - return s diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/template.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/template.py deleted file mode 100644 index 224a192..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/template.py +++ /dev/null @@ -1,566 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_template -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -HTML rendering for twisted.web. - -@var VALID_HTML_TAG_NAMES: A list of recognized HTML tag names, used by the - L{tag} object. - -@var TEMPLATE_NAMESPACE: The XML namespace used to identify attributes and - elements used by the templating system, which should be removed from the - final output document. - -@var tags: A convenience object which can produce L{Tag} objects on demand via - attribute access. For example: C{tags.div} is equivalent to C{Tag("div")}. - Tags not specified in L{VALID_HTML_TAG_NAMES} will result in an - L{AttributeError}. -""" - -__all__ = [ - 'TEMPLATE_NAMESPACE', 'VALID_HTML_TAG_NAMES', 'Element', 'TagLoader', - 'XMLString', 'XMLFile', 'renderer', 'flatten', 'flattenString', 'tags', - 'Comment', 'CDATA', 'Tag', 'slot', 'CharRef', 'renderElement' - ] - -import warnings -from zope.interface import implements - -from cStringIO import StringIO -from xml.sax import make_parser, handler - -from twisted.web._stan import Tag, slot, Comment, CDATA, CharRef -from twisted.python.filepath import FilePath - -TEMPLATE_NAMESPACE = 'http://twistedmatrix.com/ns/twisted.web.template/0.1' - -from twisted.web.iweb import ITemplateLoader -from twisted.python import log - -# Go read the definition of NOT_DONE_YET. For lulz. This is totally -# equivalent. And this turns out to be necessary, because trying to import -# NOT_DONE_YET in this module causes a circular import which we cannot escape -# from. From which we cannot escape. Etc. glyph is okay with this solution for -# now, and so am I, as long as this comment stays to explain to future -# maintainers what it means. ~ C. -# -# See http://twistedmatrix.com/trac/ticket/5557 for progress on fixing this. -NOT_DONE_YET = 1 - -class _NSContext(object): - """ - A mapping from XML namespaces onto their prefixes in the document. - """ - - def __init__(self, parent=None): - """ - Pull out the parent's namespaces, if there's no parent then default to - XML. - """ - self.parent = parent - if parent is not None: - self.nss = dict(parent.nss) - else: - self.nss = {'http://www.w3.org/XML/1998/namespace':'xml'} - - - def get(self, k, d=None): - """ - Get a prefix for a namespace. - - @param d: The default prefix value. - """ - return self.nss.get(k, d) - - - def __setitem__(self, k, v): - """ - Proxy through to setting the prefix for the namespace. - """ - self.nss.__setitem__(k, v) - - - def __getitem__(self, k): - """ - Proxy through to getting the prefix for the namespace. - """ - return self.nss.__getitem__(k) - - - -class _ToStan(handler.ContentHandler, handler.EntityResolver): - """ - A SAX parser which converts an XML document to the Twisted STAN - Document Object Model. - """ - - def __init__(self, sourceFilename): - """ - @param sourceFilename: the filename to load the XML out of. - """ - self.sourceFilename = sourceFilename - self.prefixMap = _NSContext() - self.inCDATA = False - - - def setDocumentLocator(self, locator): - """ - Set the document locator, which knows about line and character numbers. - """ - self.locator = locator - - - def startDocument(self): - """ - Initialise the document. - """ - self.document = [] - self.current = self.document - self.stack = [] - self.xmlnsAttrs = [] - - - def endDocument(self): - """ - Document ended. - """ - - - def processingInstruction(self, target, data): - """ - Processing instructions are ignored. - """ - - - def startPrefixMapping(self, prefix, uri): - """ - Set up the prefix mapping, which maps fully qualified namespace URIs - onto namespace prefixes. - - This gets called before startElementNS whenever an C{xmlns} attribute - is seen. - """ - - self.prefixMap = _NSContext(self.prefixMap) - self.prefixMap[uri] = prefix - - # Ignore the template namespace; we'll replace those during parsing. - if uri == TEMPLATE_NAMESPACE: - return - - # Add to a list that will be applied once we have the element. - if prefix is None: - self.xmlnsAttrs.append(('xmlns',uri)) - else: - self.xmlnsAttrs.append(('xmlns:%s'%prefix,uri)) - - - def endPrefixMapping(self, prefix): - """ - "Pops the stack" on the prefix mapping. - - Gets called after endElementNS. - """ - self.prefixMap = self.prefixMap.parent - - - def startElementNS(self, namespaceAndName, qname, attrs): - """ - Gets called when we encounter a new xmlns attribute. - - @param namespaceAndName: a (namespace, name) tuple, where name - determines which type of action to take, if the namespace matches - L{TEMPLATE_NAMESPACE}. - @param qname: ignored. - @param attrs: attributes on the element being started. - """ - - filename = self.sourceFilename - lineNumber = self.locator.getLineNumber() - columnNumber = self.locator.getColumnNumber() - - ns, name = namespaceAndName - if ns == TEMPLATE_NAMESPACE: - if name == 'transparent': - name = '' - elif name == 'slot': - try: - # Try to get the default value for the slot - default = attrs[(None, 'default')] - except KeyError: - # If there wasn't one, then use None to indicate no - # default. - default = None - el = slot( - attrs[(None, 'name')], default=default, - filename=filename, lineNumber=lineNumber, - columnNumber=columnNumber) - self.stack.append(el) - self.current.append(el) - self.current = el.children - return - - render = None - - attrs = dict(attrs) - for k, v in attrs.items(): - attrNS, justTheName = k - if attrNS != TEMPLATE_NAMESPACE: - continue - if justTheName == 'render': - render = v - del attrs[k] - - # nonTemplateAttrs is a dictionary mapping attributes that are *not* in - # TEMPLATE_NAMESPACE to their values. Those in TEMPLATE_NAMESPACE were - # just removed from 'attrs' in the loop immediately above. The key in - # nonTemplateAttrs is either simply the attribute name (if it was not - # specified as having a namespace in the template) or prefix:name, - # preserving the xml namespace prefix given in the document. - - nonTemplateAttrs = {} - for (attrNs, attrName), v in attrs.items(): - nsPrefix = self.prefixMap.get(attrNs) - if nsPrefix is None: - attrKey = attrName - else: - attrKey = '%s:%s' % (nsPrefix, attrName) - nonTemplateAttrs[attrKey] = v - - if ns == TEMPLATE_NAMESPACE and name == 'attr': - if not self.stack: - # TODO: define a better exception for this? - raise AssertionError( - '<{%s}attr> as top-level element' % (TEMPLATE_NAMESPACE,)) - if 'name' not in nonTemplateAttrs: - # TODO: same here - raise AssertionError( - '<{%s}attr> requires a name attribute' % (TEMPLATE_NAMESPACE,)) - el = Tag('', render=render, filename=filename, - lineNumber=lineNumber, columnNumber=columnNumber) - self.stack[-1].attributes[nonTemplateAttrs['name']] = el - self.stack.append(el) - self.current = el.children - return - - # Apply any xmlns attributes - if self.xmlnsAttrs: - nonTemplateAttrs.update(dict(self.xmlnsAttrs)) - self.xmlnsAttrs = [] - - # Add the prefix that was used in the parsed template for non-template - # namespaces (which will not be consumed anyway). - if ns != TEMPLATE_NAMESPACE and ns is not None: - prefix = self.prefixMap[ns] - if prefix is not None: - name = '%s:%s' % (self.prefixMap[ns],name) - el = Tag( - name, attributes=dict(nonTemplateAttrs), render=render, - filename=filename, lineNumber=lineNumber, - columnNumber=columnNumber) - self.stack.append(el) - self.current.append(el) - self.current = el.children - - - def characters(self, ch): - """ - Called when we receive some characters. CDATA characters get passed - through as is. - - @type ch: C{string} - """ - if self.inCDATA: - self.stack[-1].append(ch) - return - self.current.append(ch) - - - def endElementNS(self, name, qname): - """ - A namespace tag is closed. Pop the stack, if there's anything left in - it, otherwise return to the document's namespace. - """ - self.stack.pop() - if self.stack: - self.current = self.stack[-1].children - else: - self.current = self.document - - - def startDTD(self, name, publicId, systemId): - """ - DTDs are ignored. - """ - - - def endDTD(self, *args): - """ - DTDs are ignored. - """ - - - def startCDATA(self): - """ - We're starting to be in a CDATA element, make a note of this. - """ - self.inCDATA = True - self.stack.append([]) - - - def endCDATA(self): - """ - We're no longer in a CDATA element. Collect up the characters we've - parsed and put them in a new CDATA object. - """ - self.inCDATA = False - comment = ''.join(self.stack.pop()) - self.current.append(CDATA(comment)) - - - def comment(self, content): - """ - Add an XML comment which we've encountered. - """ - self.current.append(Comment(content)) - - - -def _flatsaxParse(fl): - """ - Perform a SAX parse of an XML document with the _ToStan class. - - @param fl: The XML document to be parsed. - @type fl: A file object or filename. - - @return: a C{list} of Stan objects. - """ - parser = make_parser() - parser.setFeature(handler.feature_validation, 0) - parser.setFeature(handler.feature_namespaces, 1) - parser.setFeature(handler.feature_external_ges, 0) - parser.setFeature(handler.feature_external_pes, 0) - - s = _ToStan(getattr(fl, "name", None)) - parser.setContentHandler(s) - parser.setEntityResolver(s) - parser.setProperty(handler.property_lexical_handler, s) - - parser.parse(fl) - - return s.document - - -class TagLoader(object): - """ - An L{ITemplateLoader} that loads existing L{IRenderable} providers. - - @ivar tag: The object which will be loaded. - @type tag: An L{IRenderable} provider. - """ - implements(ITemplateLoader) - - def __init__(self, tag): - """ - @param tag: The object which will be loaded. - @type tag: An L{IRenderable} provider. - """ - self.tag = tag - - - def load(self): - return [self.tag] - - - -class XMLString(object): - """ - An L{ITemplateLoader} that loads and parses XML from a string. - - @ivar _loadedTemplate: The loaded document. - @type _loadedTemplate: a C{list} of Stan objects. - """ - implements(ITemplateLoader) - - def __init__(self, s): - """ - Run the parser on a StringIO copy of the string. - - @param s: The string from which to load the XML. - @type s: C{str} - """ - self._loadedTemplate = _flatsaxParse(StringIO(s)) - - - def load(self): - """ - Return the document. - - @return: the loaded document. - @rtype: a C{list} of Stan objects. - """ - return self._loadedTemplate - - - -class XMLFile(object): - """ - An L{ITemplateLoader} that loads and parses XML from a file. - - @ivar _loadedTemplate: The loaded document, or C{None}, if not loaded. - @type _loadedTemplate: a C{list} of Stan objects, or C{None}. - - @ivar _path: The L{FilePath}, file object, or filename that is being - loaded from. - """ - implements(ITemplateLoader) - - def __init__(self, path): - """ - Run the parser on a file. - - @param path: The file from which to load the XML. - @type path: L{FilePath} - """ - if not isinstance(path, FilePath): - warnings.warn( - "Passing filenames or file objects to XMLFile is deprecated " - "since Twisted 12.1. Pass a FilePath instead.", - category=DeprecationWarning, stacklevel=2) - self._loadedTemplate = None - self._path = path - - - def _loadDoc(self): - """ - Read and parse the XML. - - @return: the loaded document. - @rtype: a C{list} of Stan objects. - """ - if not isinstance(self._path, FilePath): - return _flatsaxParse(self._path) - else: - f = self._path.open('r') - try: - return _flatsaxParse(f) - finally: - f.close() - - - def __repr__(self): - return '' % (self._path,) - - - def load(self): - """ - Return the document, first loading it if necessary. - - @return: the loaded document. - @rtype: a C{list} of Stan objects. - """ - if self._loadedTemplate is None: - self._loadedTemplate = self._loadDoc() - return self._loadedTemplate - - - -# Last updated October 2011, using W3Schools as a reference. Link: -# http://www.w3schools.com/html5/html5_reference.asp -# Note that is explicitly omitted; its semantics do not work with -# t.w.template and it is officially deprecated. -VALID_HTML_TAG_NAMES = set([ - 'a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', - 'audio', 'b', 'base', 'basefont', 'bdi', 'bdo', 'big', 'blockquote', - 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', - 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', - 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', - 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', - 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'iframe', - 'img', 'input', 'ins', 'isindex', 'keygen', 'kbd', 'label', 'legend', - 'li', 'link', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noframes', - 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', - 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', - 'section', 'select', 'small', 'source', 'span', 'strike', 'strong', - 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', - 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'tt', 'u', 'ul', 'var', - 'video', 'wbr', -]) - - - -class _TagFactory(object): - """ - A factory for L{Tag} objects; the implementation of the L{tags} object. - - This allows for the syntactic convenience of C{from twisted.web.html import - tags; tags.a(href="linked-page.html")}, where 'a' can be basically any HTML - tag. - - The class is not exposed publicly because you only ever need one of these, - and we already made it for you. - - @see: L{tags} - """ - def __getattr__(self, tagName): - if tagName == 'transparent': - return Tag('') - # allow for E.del as E.del_ - tagName = tagName.rstrip('_') - if tagName not in VALID_HTML_TAG_NAMES: - raise AttributeError('unknown tag %r' % (tagName,)) - return Tag(tagName) - - - -tags = _TagFactory() - - - -def renderElement(request, element, - doctype='<!DOCTYPE html>', _failElement=None): - """ - Render an element or other C{IRenderable}. - - @param request: The C{Request} being rendered to. - @param element: An C{IRenderable} which will be rendered. - @param doctype: A C{str} which will be written as the first line of - the request, or C{None} to disable writing of a doctype. The C{string} - should not include a trailing newline and will default to the HTML5 - doctype C{'<!DOCTYPE html>'}. - - @returns: NOT_DONE_YET - - @since: 12.1 - """ - if doctype is not None: - request.write(doctype) - request.write('\n') - - if _failElement is None: - _failElement = twisted.web.util.FailureElement - - d = flatten(request, element, request.write) - - def eb(failure): - log.err(failure, "An error occurred while rendering the response.") - if request.site.displayTracebacks: - return flatten(request, _failElement(failure), request.write) - else: - request.write( - ('<div style="font-size:800%;' - 'background-color:#FFF;' - 'color:#F00' - '">An error occurred while rendering the response.</div>')) - - d.addErrback(eb) - d.addBoth(lambda _: request.finish()) - return NOT_DONE_YET - - - -from twisted.web._element import Element, renderer -from twisted.web._flatten import flatten, flattenString -import twisted.web.util diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/__init__.py deleted file mode 100644 index cdbb14e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web}. -""" - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/_util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/_util.py deleted file mode 100644 index 5570454..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/_util.py +++ /dev/null @@ -1,97 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -General helpers for L{twisted.web} unit tests. -""" - -from __future__ import division, absolute_import - -from twisted.internet.defer import succeed -from twisted.web import server -from twisted.trial.unittest import TestCase -from twisted.python.failure import Failure -from twisted.python.compat import _PY3 - -if not _PY3: - # TODO: Remove when twisted.web.template and _flatten is ported - # https://tm.tl/#7811 - from twisted.web._flatten import flattenString - from twisted.web.error import FlattenerError - - - -def _render(resource, request): - result = resource.render(request) - if isinstance(result, bytes): - request.write(result) - request.finish() - return succeed(None) - elif result is server.NOT_DONE_YET: - if request.finished: - return succeed(None) - else: - return request.notifyFinish() - else: - raise ValueError("Unexpected return value: %r" % (result,)) - - - -class FlattenTestCase(TestCase): - """ - A test case that assists with testing L{twisted.web._flatten}. - """ - def assertFlattensTo(self, root, target): - """ - Assert that a root element, when flattened, is equal to a string. - """ - d = flattenString(None, root) - d.addCallback(lambda s: self.assertEqual(s, target)) - return d - - - def assertFlattensImmediately(self, root, target): - """ - Assert that a root element, when flattened, is equal to a string, and - performs no asynchronus Deferred anything. - - This version is more convenient in tests which wish to make multiple - assertions about flattening, since it can be called multiple times - without having to add multiple callbacks. - - @return: the result of rendering L{root}, which should be equivalent to - L{target}. - @rtype: L{bytes} - """ - results = [] - it = self.assertFlattensTo(root, target) - it.addBoth(results.append) - # Do our best to clean it up if something goes wrong. - self.addCleanup(it.cancel) - if not results: - self.fail("Rendering did not complete immediately.") - result = results[0] - if isinstance(result, Failure): - result.raiseException() - return results[0] - - - def assertFlatteningRaises(self, root, exn): - """ - Assert flattening a root element raises a particular exception. - """ - d = self.assertFailure(self.assertFlattensTo(root, ''), FlattenerError) - d.addCallback(lambda exc: self.assertIsInstance(exc._exception, exn)) - return d - - -__all__ = ["_render", "FlattenTestCase"] - -if _PY3: - __all3__ = ["_render"] - for name in __all__[:]: - if name not in __all3__: - __all__.remove(name) - del globals()[name] - del name, __all3__ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/requesthelper.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/requesthelper.py deleted file mode 100644 index cf608f3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/requesthelper.py +++ /dev/null @@ -1,286 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Helpers related to HTTP requests, used by tests. -""" - -from __future__ import division, absolute_import - -__all__ = ['DummyChannel', 'DummyRequest'] - -from io import BytesIO - -from zope.interface import implementer - -from twisted.python.deprecate import deprecated -from twisted.python.versions import Version -from twisted.internet.defer import Deferred -from twisted.internet.address import IPv4Address -from twisted.internet.interfaces import ISSLTransport - -from twisted.web.http_headers import Headers -from twisted.web.resource import Resource -from twisted.web.server import NOT_DONE_YET, Session, Site - - -class DummyChannel: - class TCP: - port = 80 - disconnected = False - - def __init__(self): - self.written = BytesIO() - self.producers = [] - - def getPeer(self): - return IPv4Address("TCP", '192.168.1.1', 12344) - - def write(self, data): - if not isinstance(data, bytes): - raise TypeError("Can only write bytes to a transport, not %r" % (data,)) - self.written.write(data) - - def writeSequence(self, iovec): - for data in iovec: - self.write(data) - - def getHost(self): - return IPv4Address("TCP", '10.0.0.1', self.port) - - def registerProducer(self, producer, streaming): - self.producers.append((producer, streaming)) - - def loseConnection(self): - self.disconnected = True - - - @implementer(ISSLTransport) - class SSL(TCP): - pass - - site = Site(Resource()) - - def __init__(self): - self.transport = self.TCP() - - - def requestDone(self, request): - pass - - - -class DummyRequest(object): - """ - Represents a dummy or fake request. - - @ivar _finishedDeferreds: C{None} or a C{list} of L{Deferreds} which will - be called back with C{None} when C{finish} is called or which will be - errbacked if C{processingFailed} is called. - - @type headers: C{dict} - @ivar headers: A mapping of header name to header value for all request - headers. - - @type outgoingHeaders: C{dict} - @ivar outgoingHeaders: A mapping of header name to header value for all - response headers. - - @type responseCode: C{int} - @ivar responseCode: The response code which was passed to - C{setResponseCode}. - - @type written: C{list} of C{bytes} - @ivar written: The bytes which have been written to the request. - """ - uri = b'http://dummy/' - method = b'GET' - client = None - - def registerProducer(self, prod,s): - self.go = 1 - while self.go: - prod.resumeProducing() - - def unregisterProducer(self): - self.go = 0 - - - def __init__(self, postpath, session=None): - self.sitepath = [] - self.written = [] - self.finished = 0 - self.postpath = postpath - self.prepath = [] - self.session = None - self.protoSession = session or Session(0, self) - self.args = {} - self.outgoingHeaders = {} - self.requestHeaders = Headers() - self.responseHeaders = Headers() - self.responseCode = None - self.headers = {} - self._finishedDeferreds = [] - self._serverName = b"dummy" - self.clientproto = b"HTTP/1.0" - - def getHeader(self, name): - """ - Retrieve the value of a request header. - - @type name: C{bytes} - @param name: The name of the request header for which to retrieve the - value. Header names are compared case-insensitively. - - @rtype: C{bytes} or L{NoneType} - @return: The value of the specified request header. - """ - return self.headers.get(name.lower(), None) - - - def getAllHeaders(self): - """ - Retrieve all the values of the request headers as a dictionary. - - @return: The entire C{headers} L{dict}. - """ - return self.headers - - - def setHeader(self, name, value): - """TODO: make this assert on write() if the header is content-length - """ - self.outgoingHeaders[name.lower()] = value - - def getSession(self): - if self.session: - return self.session - assert not self.written, "Session cannot be requested after data has been written." - self.session = self.protoSession - return self.session - - - def render(self, resource): - """ - Render the given resource as a response to this request. - - This implementation only handles a few of the most common behaviors of - resources. It can handle a render method that returns a string or - C{NOT_DONE_YET}. It doesn't know anything about the semantics of - request methods (eg HEAD) nor how to set any particular headers. - Basically, it's largely broken, but sufficient for some tests at least. - It should B{not} be expanded to do all the same stuff L{Request} does. - Instead, L{DummyRequest} should be phased out and L{Request} (or some - other real code factored in a different way) used. - """ - result = resource.render(self) - if result is NOT_DONE_YET: - return - self.write(result) - self.finish() - - - def write(self, data): - if not isinstance(data, bytes): - raise TypeError("write() only accepts bytes") - self.written.append(data) - - def notifyFinish(self): - """ - Return a L{Deferred} which is called back with C{None} when the request - is finished. This will probably only work if you haven't called - C{finish} yet. - """ - finished = Deferred() - self._finishedDeferreds.append(finished) - return finished - - - def finish(self): - """ - Record that the request is finished and callback and L{Deferred}s - waiting for notification of this. - """ - self.finished = self.finished + 1 - if self._finishedDeferreds is not None: - observers = self._finishedDeferreds - self._finishedDeferreds = None - for obs in observers: - obs.callback(None) - - - def processingFailed(self, reason): - """ - Errback and L{Deferreds} waiting for finish notification. - """ - if self._finishedDeferreds is not None: - observers = self._finishedDeferreds - self._finishedDeferreds = None - for obs in observers: - obs.errback(reason) - - - def addArg(self, name, value): - self.args[name] = [value] - - - def setResponseCode(self, code, message=None): - """ - Set the HTTP status response code, but takes care that this is called - before any data is written. - """ - assert not self.written, "Response code cannot be set after data has been written: %s." % "@@@@".join(self.written) - self.responseCode = code - self.responseMessage = message - - - def setLastModified(self, when): - assert not self.written, "Last-Modified cannot be set after data has been written: %s." % "@@@@".join(self.written) - - - def setETag(self, tag): - assert not self.written, "ETag cannot be set after data has been written: %s." % "@@@@".join(self.written) - - - def getClientIP(self): - """ - Return the IPv4 address of the client which made this request, if there - is one, otherwise C{None}. - """ - if isinstance(self.client, IPv4Address): - return self.client.host - return None - - - def getRequestHostname(self): - """ - Get a dummy hostname associated to the HTTP request. - - @rtype: C{bytes} - @returns: a dummy hostname - """ - return self._serverName - - - def getHost(self): - """ - Get a dummy transport's host. - - @rtype: C{IPv4Address} - @returns: a dummy transport's host - """ - return IPv4Address('TCP', '127.0.0.1', 80) - - - def getClient(self): - """ - Get the client's IP address, if it has one. - - @return: The same value as C{getClientIP}. - @rtype: L{bytes} - """ - return self.getClientIP() - -DummyRequest.getClient = deprecated( - Version("Twisted", 15, 0, 0), - "Twisted Names to resolve hostnames")(DummyRequest.getClient) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_agent.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_agent.py deleted file mode 100644 index e694653..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_agent.py +++ /dev/null @@ -1,2892 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.client.Agent} and related new client APIs. -""" - -import cookielib -import zlib -from StringIO import StringIO - -from zope.interface.verify import verifyObject - -from twisted.trial.unittest import TestCase -from twisted.web import client, error, http_headers -from twisted.web._newclient import RequestNotSent, RequestTransmissionFailed -from twisted.web._newclient import ResponseNeverReceived, ResponseFailed -from twisted.web._newclient import PotentialDataLoss -from twisted.internet import defer, task -from twisted.python.failure import Failure -from twisted.python.components import proxyForInterface -from twisted.test.proto_helpers import StringTransport, MemoryReactorClock -from twisted.internet.task import Clock -from twisted.internet.error import ConnectionRefusedError, ConnectionDone -from twisted.internet.error import ConnectionLost -from twisted.internet.protocol import Protocol, Factory -from twisted.internet.defer import Deferred, succeed, CancelledError -from twisted.internet.endpoints import TCP4ClientEndpoint, SSL4ClientEndpoint - -from twisted.web.client import (FileBodyProducer, Request, HTTPConnectionPool, - ResponseDone, _HTTP11ClientFactory, URI) - -from twisted.web.iweb import ( - UNKNOWN_LENGTH, IAgent, IBodyProducer, IResponse, IAgentEndpointFactory, - ) -from twisted.web.http_headers import Headers -from twisted.web._newclient import HTTP11ClientProtocol, Response - -from twisted.internet.interfaces import IOpenSSLClientConnectionCreator -from zope.interface.declarations import implementer -from twisted.web.iweb import IPolicyForHTTPS -from twisted.python.deprecate import getDeprecationWarningString -from twisted.python.versions import Version -from twisted.web.client import BrowserLikePolicyForHTTPS -from twisted.web.error import SchemeNotSupported - -try: - from twisted.internet import ssl - from twisted.protocols.tls import TLSMemoryBIOFactory, TLSMemoryBIOProtocol -except ImportError: - ssl = None -else: - from twisted.internet._sslverify import ClientTLSOptions, IOpenSSLTrustRoot - - - -class StubHTTPProtocol(Protocol): - """ - A protocol like L{HTTP11ClientProtocol} but which does not actually know - HTTP/1.1 and only collects requests in a list. - - @ivar requests: A C{list} of two-tuples. Each time a request is made, a - tuple consisting of the request and the L{Deferred} returned from the - request method is appended to this list. - """ - def __init__(self): - self.requests = [] - self.state = 'QUIESCENT' - - - def request(self, request): - """ - Capture the given request for later inspection. - - @return: A L{Deferred} which this code will never fire. - """ - result = Deferred() - self.requests.append((request, result)) - return result - - - -class FileConsumer(object): - def __init__(self, outputFile): - self.outputFile = outputFile - - - def write(self, bytes): - self.outputFile.write(bytes) - - - -class FileBodyProducerTests(TestCase): - """ - Tests for the L{FileBodyProducer} which reads bytes from a file and writes - them to an L{IConsumer}. - """ - def _termination(self): - """ - This method can be used as the C{terminationPredicateFactory} for a - L{Cooperator}. It returns a predicate which immediately returns - C{False}, indicating that no more work should be done this iteration. - This has the result of only allowing one iteration of a cooperative - task to be run per L{Cooperator} iteration. - """ - return lambda: True - - - def setUp(self): - """ - Create a L{Cooperator} hooked up to an easily controlled, deterministic - scheduler to use with L{FileBodyProducer}. - """ - self._scheduled = [] - self.cooperator = task.Cooperator( - self._termination, self._scheduled.append) - - - def test_interface(self): - """ - L{FileBodyProducer} instances provide L{IBodyProducer}. - """ - self.assertTrue(verifyObject( - IBodyProducer, FileBodyProducer(StringIO("")))) - - - def test_unknownLength(self): - """ - If the L{FileBodyProducer} is constructed with a file-like object - without either a C{seek} or C{tell} method, its C{length} attribute is - set to C{UNKNOWN_LENGTH}. - """ - class HasSeek(object): - def seek(self, offset, whence): - pass - - class HasTell(object): - def tell(self): - pass - - producer = FileBodyProducer(HasSeek()) - self.assertEqual(UNKNOWN_LENGTH, producer.length) - producer = FileBodyProducer(HasTell()) - self.assertEqual(UNKNOWN_LENGTH, producer.length) - - - def test_knownLength(self): - """ - If the L{FileBodyProducer} is constructed with a file-like object with - both C{seek} and C{tell} methods, its C{length} attribute is set to the - size of the file as determined by those methods. - """ - inputBytes = "here are some bytes" - inputFile = StringIO(inputBytes) - inputFile.seek(5) - producer = FileBodyProducer(inputFile) - self.assertEqual(len(inputBytes) - 5, producer.length) - self.assertEqual(inputFile.tell(), 5) - - - def test_defaultCooperator(self): - """ - If no L{Cooperator} instance is passed to L{FileBodyProducer}, the - global cooperator is used. - """ - producer = FileBodyProducer(StringIO("")) - self.assertEqual(task.cooperate, producer._cooperate) - - - def test_startProducing(self): - """ - L{FileBodyProducer.startProducing} starts writing bytes from the input - file to the given L{IConsumer} and returns a L{Deferred} which fires - when they have all been written. - """ - expectedResult = "hello, world" - readSize = 3 - output = StringIO() - consumer = FileConsumer(output) - producer = FileBodyProducer( - StringIO(expectedResult), self.cooperator, readSize) - complete = producer.startProducing(consumer) - for i in range(len(expectedResult) // readSize + 1): - self._scheduled.pop(0)() - self.assertEqual([], self._scheduled) - self.assertEqual(expectedResult, output.getvalue()) - self.assertEqual(None, self.successResultOf(complete)) - - - def test_inputClosedAtEOF(self): - """ - When L{FileBodyProducer} reaches end-of-file on the input file given to - it, the input file is closed. - """ - readSize = 4 - inputBytes = "some friendly bytes" - inputFile = StringIO(inputBytes) - producer = FileBodyProducer(inputFile, self.cooperator, readSize) - consumer = FileConsumer(StringIO()) - producer.startProducing(consumer) - for i in range(len(inputBytes) // readSize + 2): - self._scheduled.pop(0)() - self.assertTrue(inputFile.closed) - - - def test_failedReadWhileProducing(self): - """ - If a read from the input file fails while producing bytes to the - consumer, the L{Deferred} returned by - L{FileBodyProducer.startProducing} fires with a L{Failure} wrapping - that exception. - """ - class BrokenFile(object): - def read(self, count): - raise IOError("Simulated bad thing") - producer = FileBodyProducer(BrokenFile(), self.cooperator) - complete = producer.startProducing(FileConsumer(StringIO())) - self._scheduled.pop(0)() - self.failureResultOf(complete).trap(IOError) - - - def test_stopProducing(self): - """ - L{FileBodyProducer.stopProducing} stops the underlying L{IPullProducer} - and the cooperative task responsible for calling C{resumeProducing} and - closes the input file but does not cause the L{Deferred} returned by - C{startProducing} to fire. - """ - expectedResult = "hello, world" - readSize = 3 - output = StringIO() - consumer = FileConsumer(output) - inputFile = StringIO(expectedResult) - producer = FileBodyProducer( - inputFile, self.cooperator, readSize) - complete = producer.startProducing(consumer) - producer.stopProducing() - self.assertTrue(inputFile.closed) - self._scheduled.pop(0)() - self.assertEqual("", output.getvalue()) - self.assertNoResult(complete) - - - def test_pauseProducing(self): - """ - L{FileBodyProducer.pauseProducing} temporarily suspends writing bytes - from the input file to the given L{IConsumer}. - """ - expectedResult = "hello, world" - readSize = 5 - output = StringIO() - consumer = FileConsumer(output) - producer = FileBodyProducer( - StringIO(expectedResult), self.cooperator, readSize) - complete = producer.startProducing(consumer) - self._scheduled.pop(0)() - self.assertEqual(output.getvalue(), expectedResult[:5]) - producer.pauseProducing() - - # Sort of depends on an implementation detail of Cooperator: even - # though the only task is paused, there's still a scheduled call. If - # this were to go away because Cooperator became smart enough to cancel - # this call in this case, that would be fine. - self._scheduled.pop(0)() - - # Since the producer is paused, no new data should be here. - self.assertEqual(output.getvalue(), expectedResult[:5]) - self.assertEqual([], self._scheduled) - self.assertNoResult(complete) - - - def test_resumeProducing(self): - """ - L{FileBodyProducer.resumeProducing} re-commences writing bytes from the - input file to the given L{IConsumer} after it was previously paused - with L{FileBodyProducer.pauseProducing}. - """ - expectedResult = "hello, world" - readSize = 5 - output = StringIO() - consumer = FileConsumer(output) - producer = FileBodyProducer( - StringIO(expectedResult), self.cooperator, readSize) - producer.startProducing(consumer) - self._scheduled.pop(0)() - self.assertEqual(expectedResult[:readSize], output.getvalue()) - producer.pauseProducing() - producer.resumeProducing() - self._scheduled.pop(0)() - self.assertEqual(expectedResult[:readSize * 2], output.getvalue()) - - - -class FakeReactorAndConnectMixin: - """ - A test mixin providing a testable C{Reactor} class and a dummy C{connect} - method which allows instances to pretend to be endpoints. - """ - Reactor = MemoryReactorClock - - @implementer(IPolicyForHTTPS) - class StubPolicy(object): - """ - A stub policy for HTTPS URIs which allows HTTPS tests to run even if - pyOpenSSL isn't installed. - """ - def creatorForNetloc(self, hostname, port): - """ - Don't actually do anything. - - @param hostname: ignored - - @param port: ignored - """ - - class StubEndpoint(object): - """ - Endpoint that wraps existing endpoint, substitutes StubHTTPProtocol, and - resulting protocol instances are attached to the given test case. - """ - - def __init__(self, endpoint, testCase): - self.endpoint = endpoint - self.testCase = testCase - self.factory = _HTTP11ClientFactory(lambda p: None) - self.protocol = StubHTTPProtocol() - self.factory.buildProtocol = lambda addr: self.protocol - - def connect(self, ignoredFactory): - self.testCase.protocol = self.protocol - self.endpoint.connect(self.factory) - return succeed(self.protocol) - - - def buildAgentForWrapperTest(self, reactor): - """ - Return an Agent suitable for use in tests that wrap the Agent and want - both a fake reactor and StubHTTPProtocol. - """ - agent = client.Agent(reactor, self.StubPolicy()) - _oldGetEndpoint = agent._getEndpoint - agent._getEndpoint = lambda *args: ( - self.StubEndpoint(_oldGetEndpoint(*args), self)) - return agent - - - def connect(self, factory): - """ - Fake implementation of an endpoint which synchronously - succeeds with an instance of L{StubHTTPProtocol} for ease of - testing. - """ - protocol = StubHTTPProtocol() - protocol.makeConnection(None) - self.protocol = protocol - return succeed(protocol) - - - -class DummyEndpoint(object): - """ - An endpoint that uses a fake transport. - """ - - def connect(self, factory): - protocol = factory.buildProtocol(None) - protocol.makeConnection(StringTransport()) - return succeed(protocol) - - - -class BadEndpoint(object): - """ - An endpoint that shouldn't be called. - """ - - def connect(self, factory): - raise RuntimeError("This endpoint should not have been used.") - - -class DummyFactory(Factory): - """ - Create C{StubHTTPProtocol} instances. - """ - def __init__(self, quiescentCallback): - pass - - protocol = StubHTTPProtocol - - - -class HTTPConnectionPoolTests(TestCase, FakeReactorAndConnectMixin): - """ - Tests for the L{HTTPConnectionPool} class. - """ - def setUp(self): - self.fakeReactor = self.Reactor() - self.pool = HTTPConnectionPool(self.fakeReactor) - self.pool._factory = DummyFactory - # The retry code path is tested in HTTPConnectionPoolRetryTests: - self.pool.retryAutomatically = False - - - def test_getReturnsNewIfCacheEmpty(self): - """ - If there are no cached connections, - L{HTTPConnectionPool.getConnection} returns a new connection. - """ - self.assertEqual(self.pool._connections, {}) - - def gotConnection(conn): - self.assertIsInstance(conn, StubHTTPProtocol) - # The new connection is not stored in the pool: - self.assertNotIn(conn, self.pool._connections.values()) - - unknownKey = 12245 - d = self.pool.getConnection(unknownKey, DummyEndpoint()) - return d.addCallback(gotConnection) - - - def test_putStartsTimeout(self): - """ - If a connection is put back to the pool, a 240-sec timeout is started. - - When the timeout hits, the connection is closed and removed from the - pool. - """ - # We start out with one cached connection: - protocol = StubHTTPProtocol() - protocol.makeConnection(StringTransport()) - self.pool._putConnection(("http", "example.com", 80), protocol) - - # Connection is in pool, still not closed: - self.assertEqual(protocol.transport.disconnecting, False) - self.assertIn(protocol, - self.pool._connections[("http", "example.com", 80)]) - - # Advance 239 seconds, still not closed: - self.fakeReactor.advance(239) - self.assertEqual(protocol.transport.disconnecting, False) - self.assertIn(protocol, - self.pool._connections[("http", "example.com", 80)]) - self.assertIn(protocol, self.pool._timeouts) - - # Advance past 240 seconds, connection will be closed: - self.fakeReactor.advance(1.1) - self.assertEqual(protocol.transport.disconnecting, True) - self.assertNotIn(protocol, - self.pool._connections[("http", "example.com", 80)]) - self.assertNotIn(protocol, self.pool._timeouts) - - - def test_putExceedsMaxPersistent(self): - """ - If an idle connection is put back in the cache and the max number of - persistent connections has been exceeded, one of the connections is - closed and removed from the cache. - """ - pool = self.pool - - # We start out with two cached connection, the max: - origCached = [StubHTTPProtocol(), StubHTTPProtocol()] - for p in origCached: - p.makeConnection(StringTransport()) - pool._putConnection(("http", "example.com", 80), p) - self.assertEqual(pool._connections[("http", "example.com", 80)], - origCached) - timeouts = pool._timeouts.copy() - - # Now we add another one: - newProtocol = StubHTTPProtocol() - newProtocol.makeConnection(StringTransport()) - pool._putConnection(("http", "example.com", 80), newProtocol) - - # The oldest cached connections will be removed and disconnected: - newCached = pool._connections[("http", "example.com", 80)] - self.assertEqual(len(newCached), 2) - self.assertEqual(newCached, [origCached[1], newProtocol]) - self.assertEqual([p.transport.disconnecting for p in newCached], - [False, False]) - self.assertEqual(origCached[0].transport.disconnecting, True) - self.assertTrue(timeouts[origCached[0]].cancelled) - self.assertNotIn(origCached[0], pool._timeouts) - - - def test_maxPersistentPerHost(self): - """ - C{maxPersistentPerHost} is enforced per C{(scheme, host, port)}: - different keys have different max connections. - """ - def addProtocol(scheme, host, port): - p = StubHTTPProtocol() - p.makeConnection(StringTransport()) - self.pool._putConnection((scheme, host, port), p) - return p - persistent = [] - persistent.append(addProtocol("http", "example.com", 80)) - persistent.append(addProtocol("http", "example.com", 80)) - addProtocol("https", "example.com", 443) - addProtocol("http", "www2.example.com", 80) - - self.assertEqual( - self.pool._connections[("http", "example.com", 80)], persistent) - self.assertEqual( - len(self.pool._connections[("https", "example.com", 443)]), 1) - self.assertEqual( - len(self.pool._connections[("http", "www2.example.com", 80)]), 1) - - - def test_getCachedConnection(self): - """ - Getting an address which has a cached connection returns the cached - connection, removes it from the cache and cancels its timeout. - """ - # We start out with one cached connection: - protocol = StubHTTPProtocol() - protocol.makeConnection(StringTransport()) - self.pool._putConnection(("http", "example.com", 80), protocol) - - def gotConnection(conn): - # We got the cached connection: - self.assertIdentical(protocol, conn) - self.assertNotIn( - conn, self.pool._connections[("http", "example.com", 80)]) - # And the timeout was cancelled: - self.fakeReactor.advance(241) - self.assertEqual(conn.transport.disconnecting, False) - self.assertNotIn(conn, self.pool._timeouts) - - return self.pool.getConnection(("http", "example.com", 80), - BadEndpoint(), - ).addCallback(gotConnection) - - - def test_newConnection(self): - """ - The pool's C{_newConnection} method constructs a new connection. - """ - # We start out with one cached connection: - protocol = StubHTTPProtocol() - protocol.makeConnection(StringTransport()) - key = 12245 - self.pool._putConnection(key, protocol) - - def gotConnection(newConnection): - # We got a new connection: - self.assertNotIdentical(protocol, newConnection) - # And the old connection is still there: - self.assertIn(protocol, self.pool._connections[key]) - # While the new connection is not: - self.assertNotIn(newConnection, self.pool._connections.values()) - - d = self.pool._newConnection(key, DummyEndpoint()) - return d.addCallback(gotConnection) - - - def test_getSkipsDisconnected(self): - """ - When getting connections out of the cache, disconnected connections - are removed and not returned. - """ - pool = self.pool - key = ("http", "example.com", 80) - - # We start out with two cached connection, the max: - origCached = [StubHTTPProtocol(), StubHTTPProtocol()] - for p in origCached: - p.makeConnection(StringTransport()) - pool._putConnection(key, p) - self.assertEqual(pool._connections[key], origCached) - - # We close the first one: - origCached[0].state = "DISCONNECTED" - - # Now, when we retrive connections we should get the *second* one: - result = [] - self.pool.getConnection(key, - BadEndpoint()).addCallback(result.append) - self.assertIdentical(result[0], origCached[1]) - - # And both the disconnected and removed connections should be out of - # the cache: - self.assertEqual(pool._connections[key], []) - self.assertEqual(pool._timeouts, {}) - - - def test_putNotQuiescent(self): - """ - If a non-quiescent connection is put back in the cache, an error is - logged. - """ - protocol = StubHTTPProtocol() - # By default state is QUIESCENT - self.assertEqual(protocol.state, "QUIESCENT") - - protocol.state = "NOTQUIESCENT" - self.pool._putConnection(("http", "example.com", 80), protocol) - exc, = self.flushLoggedErrors(RuntimeError) - self.assertEqual( - exc.value.args[0], - "BUG: Non-quiescent protocol added to connection pool.") - self.assertIdentical(None, self.pool._connections.get( - ("http", "example.com", 80))) - - - def test_getUsesQuiescentCallback(self): - """ - When L{HTTPConnectionPool.getConnection} connects, it returns a - C{Deferred} that fires with an instance of L{HTTP11ClientProtocol} - that has the correct quiescent callback attached. When this callback - is called the protocol is returned to the cache correctly, using the - right key. - """ - class StringEndpoint(object): - def connect(self, factory): - p = factory.buildProtocol(None) - p.makeConnection(StringTransport()) - return succeed(p) - - pool = HTTPConnectionPool(self.fakeReactor, True) - pool.retryAutomatically = False - result = [] - key = "a key" - pool.getConnection( - key, StringEndpoint()).addCallback( - result.append) - protocol = result[0] - self.assertIsInstance(protocol, HTTP11ClientProtocol) - - # Now that we have protocol instance, lets try to put it back in the - # pool: - protocol._state = "QUIESCENT" - protocol._quiescentCallback(protocol) - - # If we try to retrive a connection to same destination again, we - # should get the same protocol, because it should've been added back - # to the pool: - result2 = [] - pool.getConnection( - key, StringEndpoint()).addCallback( - result2.append) - self.assertIdentical(result2[0], protocol) - - - def test_closeCachedConnections(self): - """ - L{HTTPConnectionPool.closeCachedConnections} closes all cached - connections and removes them from the cache. It returns a Deferred - that fires when they have all lost their connections. - """ - persistent = [] - def addProtocol(scheme, host, port): - p = HTTP11ClientProtocol() - p.makeConnection(StringTransport()) - self.pool._putConnection((scheme, host, port), p) - persistent.append(p) - addProtocol("http", "example.com", 80) - addProtocol("http", "www2.example.com", 80) - doneDeferred = self.pool.closeCachedConnections() - - # Connections have begun disconnecting: - for p in persistent: - self.assertEqual(p.transport.disconnecting, True) - self.assertEqual(self.pool._connections, {}) - # All timeouts were cancelled and removed: - for dc in self.fakeReactor.getDelayedCalls(): - self.assertEqual(dc.cancelled, True) - self.assertEqual(self.pool._timeouts, {}) - - # Returned Deferred fires when all connections have been closed: - result = [] - doneDeferred.addCallback(result.append) - self.assertEqual(result, []) - persistent[0].connectionLost(Failure(ConnectionDone())) - self.assertEqual(result, []) - persistent[1].connectionLost(Failure(ConnectionDone())) - self.assertEqual(result, [None]) - - - def test_cancelGetConnectionCancelsEndpointConnect(self): - """ - Cancelling the C{Deferred} returned from - L{HTTPConnectionPool.getConnection} cancels the C{Deferred} returned - by opening a new connection with the given endpoint. - """ - self.assertEqual(self.pool._connections, {}) - connectionResult = Deferred() - - class Endpoint: - def connect(self, factory): - return connectionResult - - d = self.pool.getConnection(12345, Endpoint()) - d.cancel() - self.assertEqual(self.failureResultOf(connectionResult).type, - CancelledError) - - - -class AgentTestsMixin(object): - """ - Tests for any L{IAgent} implementation. - """ - def test_interface(self): - """ - The agent object provides L{IAgent}. - """ - self.assertTrue(verifyObject(IAgent, self.makeAgent())) - - - -@implementer(IAgentEndpointFactory) -class StubEndpointFactory(object): - """ - A stub L{IAgentEndpointFactory} for use in testing. - """ - def endpointForURI(self, uri): - """ - Testing implementation. - - @param uri: A L{URI}. - - @return: C{(scheme, host, port)} of passed in URI; violation of - interface but useful for testing. - @rtype: L{tuple} - """ - return (uri.scheme, uri.host, uri.port) - - - -class AgentTests(TestCase, FakeReactorAndConnectMixin, AgentTestsMixin): - """ - Tests for the new HTTP client API provided by L{Agent}. - """ - def makeAgent(self): - """ - @return: a new L{twisted.web.client.Agent} instance - """ - return client.Agent(self.reactor) - - - def setUp(self): - """ - Create an L{Agent} wrapped around a fake reactor. - """ - self.reactor = self.Reactor() - self.agent = self.makeAgent() - - - def test_defaultPool(self): - """ - If no pool is passed in, the L{Agent} creates a non-persistent pool. - """ - agent = client.Agent(self.reactor) - self.assertIsInstance(agent._pool, HTTPConnectionPool) - self.assertEqual(agent._pool.persistent, False) - self.assertIdentical(agent._reactor, agent._pool._reactor) - - - def test_persistent(self): - """ - If C{persistent} is set to C{True} on the L{HTTPConnectionPool} (the - default), C{Request}s are created with their C{persistent} flag set to - C{True}. - """ - pool = HTTPConnectionPool(self.reactor) - agent = client.Agent(self.reactor, pool=pool) - agent._getEndpoint = lambda *args: self - agent.request("GET", "http://127.0.0.1") - self.assertEqual(self.protocol.requests[0][0].persistent, True) - - - def test_nonPersistent(self): - """ - If C{persistent} is set to C{False} when creating the - L{HTTPConnectionPool}, C{Request}s are created with their - C{persistent} flag set to C{False}. - - Elsewhere in the tests for the underlying HTTP code we ensure that - this will result in the disconnection of the HTTP protocol once the - request is done, so that the connection will not be returned to the - pool. - """ - pool = HTTPConnectionPool(self.reactor, persistent=False) - agent = client.Agent(self.reactor, pool=pool) - agent._getEndpoint = lambda *args: self - agent.request("GET", "http://127.0.0.1") - self.assertEqual(self.protocol.requests[0][0].persistent, False) - - - def test_connectUsesConnectionPool(self): - """ - When a connection is made by the Agent, it uses its pool's - C{getConnection} method to do so, with the endpoint returned by - C{self._getEndpoint}. The key used is C{(scheme, host, port)}. - """ - endpoint = DummyEndpoint() - class MyAgent(client.Agent): - def _getEndpoint(this, uri): - self.assertEqual((uri.scheme, uri.host, uri.port), - ("http", "foo", 80)) - return endpoint - - class DummyPool(object): - connected = False - persistent = False - def getConnection(this, key, ep): - this.connected = True - self.assertEqual(ep, endpoint) - # This is the key the default Agent uses, others will have - # different keys: - self.assertEqual(key, ("http", "foo", 80)) - return defer.succeed(StubHTTPProtocol()) - - pool = DummyPool() - agent = MyAgent(self.reactor, pool=pool) - self.assertIdentical(pool, agent._pool) - - headers = http_headers.Headers() - headers.addRawHeader("host", "foo") - bodyProducer = object() - agent.request('GET', 'http://foo/', - bodyProducer=bodyProducer, headers=headers) - self.assertEqual(agent._pool.connected, True) - - - def test_unsupportedScheme(self): - """ - L{Agent.request} returns a L{Deferred} which fails with - L{SchemeNotSupported} if the scheme of the URI passed to it is not - C{'http'}. - """ - return self.assertFailure( - self.agent.request('GET', 'mailto:alice@example.com'), - SchemeNotSupported) - - - def test_connectionFailed(self): - """ - The L{Deferred} returned by L{Agent.request} fires with a L{Failure} if - the TCP connection attempt fails. - """ - result = self.agent.request('GET', 'http://foo/') - # Cause the connection to be refused - host, port, factory = self.reactor.tcpClients.pop()[:3] - factory.clientConnectionFailed(None, Failure(ConnectionRefusedError())) - return self.assertFailure(result, ConnectionRefusedError) - - - def test_connectHTTP(self): - """ - L{Agent._getEndpoint} return a C{TCP4ClientEndpoint} when passed a - scheme of C{'http'}. - """ - expectedHost = 'example.com' - expectedPort = 1234 - endpoint = self.agent._getEndpoint( - URI.fromBytes(b'http://%s:%s/' % (expectedHost, expectedPort))) - self.assertEqual(endpoint._host, expectedHost) - self.assertEqual(endpoint._port, expectedPort) - self.assertIsInstance(endpoint, TCP4ClientEndpoint) - - - def test_connectHTTPSCustomContextFactory(self): - """ - If a context factory is passed to L{Agent.__init__} it will be used to - determine the SSL parameters for HTTPS requests. When an HTTPS request - is made, the hostname and port number of the request URL will be passed - to the context factory's C{getContext} method. The resulting context - object will be used to establish the SSL connection. - """ - expectedHost = 'example.org' - expectedPort = 20443 - expectedContext = object() - - contextArgs = [] - class StubWebContextFactory(object): - def getContext(self, hostname, port): - contextArgs.append((hostname, port)) - return expectedContext - - agent = client.Agent(self.reactor, StubWebContextFactory()) - endpoint = agent._getEndpoint( - URI.fromBytes(b'https://%s:%s/' % (expectedHost, expectedPort))) - contextFactory = endpoint._sslContextFactory - context = contextFactory.getContext() - self.assertEqual(context, expectedContext) - self.assertEqual(contextArgs, [(expectedHost, expectedPort)]) - - - def test_hostProvided(self): - """ - If C{None} is passed to L{Agent.request} for the C{headers} parameter, - a L{Headers} instance is created for the request and a I{Host} header - added to it. - """ - self.agent._getEndpoint = lambda *args: self - self.agent.request( - 'GET', 'http://example.com/foo?bar') - - req, res = self.protocol.requests.pop() - self.assertEqual(req.headers.getRawHeaders('host'), ['example.com']) - - - def test_hostOverride(self): - """ - If the headers passed to L{Agent.request} includes a value for the - I{Host} header, that value takes precedence over the one which would - otherwise be automatically provided. - """ - headers = http_headers.Headers({'foo': ['bar'], 'host': ['quux']}) - self.agent._getEndpoint = lambda *args: self - self.agent.request( - 'GET', 'http://example.com/foo?bar', headers) - - req, res = self.protocol.requests.pop() - self.assertEqual(req.headers.getRawHeaders('host'), ['quux']) - - - def test_headersUnmodified(self): - """ - If a I{Host} header must be added to the request, the L{Headers} - instance passed to L{Agent.request} is not modified. - """ - headers = http_headers.Headers() - self.agent._getEndpoint = lambda *args: self - self.agent.request( - 'GET', 'http://example.com/foo', headers) - - protocol = self.protocol - - # The request should have been issued. - self.assertEqual(len(protocol.requests), 1) - # And the headers object passed in should not have changed. - self.assertEqual(headers, http_headers.Headers()) - - - def test_hostValueStandardHTTP(self): - """ - When passed a scheme of C{'http'} and a port of C{80}, - L{Agent._computeHostValue} returns a string giving just - the host name passed to it. - """ - self.assertEqual( - self.agent._computeHostValue('http', 'example.com', 80), - 'example.com') - - - def test_hostValueNonStandardHTTP(self): - """ - When passed a scheme of C{'http'} and a port other than C{80}, - L{Agent._computeHostValue} returns a string giving the - host passed to it joined together with the port number by C{":"}. - """ - self.assertEqual( - self.agent._computeHostValue('http', 'example.com', 54321), - 'example.com:54321') - - - def test_hostValueStandardHTTPS(self): - """ - When passed a scheme of C{'https'} and a port of C{443}, - L{Agent._computeHostValue} returns a string giving just - the host name passed to it. - """ - self.assertEqual( - self.agent._computeHostValue('https', 'example.com', 443), - 'example.com') - - - def test_hostValueNonStandardHTTPS(self): - """ - When passed a scheme of C{'https'} and a port other than C{443}, - L{Agent._computeHostValue} returns a string giving the - host passed to it joined together with the port number by C{":"}. - """ - self.assertEqual( - self.agent._computeHostValue('https', 'example.com', 54321), - 'example.com:54321') - - - def test_request(self): - """ - L{Agent.request} establishes a new connection to the host indicated by - the host part of the URI passed to it and issues a request using the - method, the path portion of the URI, the headers, and the body producer - passed to it. It returns a L{Deferred} which fires with an - L{IResponse} from the server. - """ - self.agent._getEndpoint = lambda *args: self - - headers = http_headers.Headers({'foo': ['bar']}) - # Just going to check the body for identity, so it doesn't need to be - # real. - body = object() - self.agent.request( - 'GET', 'http://example.com:1234/foo?bar', headers, body) - - protocol = self.protocol - - # The request should be issued. - self.assertEqual(len(protocol.requests), 1) - req, res = protocol.requests.pop() - self.assertIsInstance(req, Request) - self.assertEqual(req.method, 'GET') - self.assertEqual(req.uri, '/foo?bar') - self.assertEqual( - req.headers, - http_headers.Headers({'foo': ['bar'], - 'host': ['example.com:1234']})) - self.assertIdentical(req.bodyProducer, body) - - - def test_connectTimeout(self): - """ - L{Agent} takes a C{connectTimeout} argument which is forwarded to the - following C{connectTCP} agent. - """ - agent = client.Agent(self.reactor, connectTimeout=5) - agent.request('GET', 'http://foo/') - timeout = self.reactor.tcpClients.pop()[3] - self.assertEqual(5, timeout) - - - def test_connectSSLTimeout(self): - """ - L{Agent} takes a C{connectTimeout} argument which is forwarded to the - following C{connectSSL} call. - """ - agent = client.Agent(self.reactor, self.StubPolicy(), connectTimeout=5) - agent.request('GET', 'https://foo/') - timeout = self.reactor.sslClients.pop()[4] - self.assertEqual(5, timeout) - - - def test_bindAddress(self): - """ - L{Agent} takes a C{bindAddress} argument which is forwarded to the - following C{connectTCP} call. - """ - agent = client.Agent(self.reactor, bindAddress='192.168.0.1') - agent.request('GET', 'http://foo/') - address = self.reactor.tcpClients.pop()[4] - self.assertEqual('192.168.0.1', address) - - - def test_bindAddressSSL(self): - """ - L{Agent} takes a C{bindAddress} argument which is forwarded to the - following C{connectSSL} call. - """ - agent = client.Agent(self.reactor, self.StubPolicy(), - bindAddress='192.168.0.1') - agent.request('GET', 'https://foo/') - address = self.reactor.sslClients.pop()[5] - self.assertEqual('192.168.0.1', address) - - - def test_responseIncludesRequest(self): - """ - L{Response}s returned by L{Agent.request} have a reference to the - L{Request} that was originally issued. - """ - uri = b'http://example.com/' - agent = self.buildAgentForWrapperTest(self.reactor) - d = agent.request('GET', uri) - - # The request should be issued. - self.assertEqual(len(self.protocol.requests), 1) - req, res = self.protocol.requests.pop() - self.assertIsInstance(req, Request) - - resp = client.Response._construct( - ('HTTP', 1, 1), - 200, - 'OK', - client.Headers({}), - None, - req) - res.callback(resp) - - response = self.successResultOf(d) - self.assertEqual( - (response.request.method, response.request.absoluteURI, - response.request.headers), - (req.method, req.absoluteURI, req.headers)) - - - def test_requestAbsoluteURI(self): - """ - L{Request.absoluteURI} is the absolute URI of the request. - """ - uri = b'http://example.com/foo;1234?bar#frag' - agent = self.buildAgentForWrapperTest(self.reactor) - agent.request(b'GET', uri) - - # The request should be issued. - self.assertEqual(len(self.protocol.requests), 1) - req, res = self.protocol.requests.pop() - self.assertIsInstance(req, Request) - self.assertEquals(req.absoluteURI, uri) - - - def test_requestMissingAbsoluteURI(self): - """ - L{Request.absoluteURI} is C{None} if L{Request._parsedURI} is C{None}. - """ - request = client.Request(b'FOO', b'/', client.Headers(), None) - self.assertIdentical(request.absoluteURI, None) - - - def test_endpointFactory(self): - """ - L{Agent.usingEndpointFactory} creates an L{Agent} that uses the given - factory to create endpoints. - """ - factory = StubEndpointFactory() - agent = client.Agent.usingEndpointFactory( - None, endpointFactory=factory) - uri = URI.fromBytes(b'http://example.com/') - returnedEndpoint = agent._getEndpoint(uri) - self.assertEqual(returnedEndpoint, (b"http", b"example.com", 80)) - - - def test_endpointFactoryDefaultPool(self): - """ - If no pool is passed in to L{Agent.usingEndpointFactory}, a default - pool is constructed with no persistent connections. - """ - agent = client.Agent.usingEndpointFactory( - self.reactor, StubEndpointFactory()) - pool = agent._pool - self.assertEqual((pool.__class__, pool.persistent, pool._reactor), - (HTTPConnectionPool, False, agent._reactor)) - - - def test_endpointFactoryPool(self): - """ - If a pool is passed in to L{Agent.usingEndpointFactory} it is used as - the L{Agent} pool. - """ - pool = object() - agent = client.Agent.usingEndpointFactory( - self.reactor, StubEndpointFactory(), pool) - self.assertIs(pool, agent._pool) - - - -class AgentHTTPSTests(TestCase, FakeReactorAndConnectMixin): - """ - Tests for the new HTTP client API that depends on SSL. - """ - if ssl is None: - skip = "SSL not present, cannot run SSL tests" - - - def makeEndpoint(self, host='example.com', port=443): - """ - Create an L{Agent} with an https scheme and return its endpoint - created according to the arguments. - - @param host: The host for the endpoint. - @type host: L{bytes} - - @param port: The port for the endpoint. - @type port: L{int} - - @return: An endpoint of an L{Agent} constructed according to args. - @rtype: L{SSL4ClientEndpoint} - """ - return client.Agent(self.Reactor())._getEndpoint( - URI.fromBytes(b'https://%s:%s/' % (host, port))) - - - def test_endpointType(self): - """ - L{Agent._getEndpoint} return a L{SSL4ClientEndpoint} when passed a - scheme of C{'https'}. - """ - self.assertIsInstance(self.makeEndpoint(), SSL4ClientEndpoint) - - - def test_hostArgumentIsRespected(self): - """ - If a host is passed, the endpoint respects it. - """ - expectedHost = 'example.com' - endpoint = self.makeEndpoint(host=expectedHost) - self.assertEqual(endpoint._host, expectedHost) - - - def test_portArgumentIsRespected(self): - """ - If a port is passed, the endpoint respects it. - """ - expectedPort = 4321 - endpoint = self.makeEndpoint(port=expectedPort) - self.assertEqual(endpoint._port, expectedPort) - - - def test_contextFactoryType(self): - """ - L{Agent} wraps its connection creator creator and uses modern TLS APIs. - """ - endpoint = self.makeEndpoint() - contextFactory = endpoint._sslContextFactory - self.assertIsInstance(contextFactory, ClientTLSOptions) - self.assertEqual(contextFactory._hostname, u"example.com") - - - def test_connectHTTPSCustomConnectionCreator(self): - """ - If a custom L{WebClientConnectionCreator}-like object is passed to - L{Agent.__init__} it will be used to determine the SSL parameters for - HTTPS requests. When an HTTPS request is made, the hostname and port - number of the request URL will be passed to the connection creator's - C{creatorForNetloc} method. The resulting context object will be used - to establish the SSL connection. - """ - expectedHost = b'example.org' - expectedPort = 20443 - class JustEnoughConnection(object): - handshakeStarted = False - connectState = False - def do_handshake(self): - """ - The handshake started. Record that fact. - """ - self.handshakeStarted = True - def set_connect_state(self): - """ - The connection started. Record that fact. - """ - self.connectState = True - - contextArgs = [] - - @implementer(IOpenSSLClientConnectionCreator) - class JustEnoughCreator(object): - def __init__(self, hostname, port): - self.hostname = hostname - self.port = port - - def clientConnectionForTLS(self, tlsProtocol): - """ - Implement L{IOpenSSLClientConnectionCreator}. - - @param tlsProtocol: The TLS protocol. - @type tlsProtocol: L{TLSMemoryBIOProtocol} - - @return: C{expectedConnection} - """ - contextArgs.append((tlsProtocol, self.hostname, self.port)) - return expectedConnection - - expectedConnection = JustEnoughConnection() - @implementer(IPolicyForHTTPS) - class StubBrowserLikePolicyForHTTPS(object): - def creatorForNetloc(self, hostname, port): - """ - Emulate L{BrowserLikePolicyForHTTPS}. - - @param hostname: The hostname to verify. - @type hostname: L{bytes} - - @param port: The port number. - @type port: L{int} - - @return: a stub L{IOpenSSLClientConnectionCreator} - @rtype: L{JustEnoughCreator} - """ - return JustEnoughCreator(hostname, port) - - expectedCreatorCreator = StubBrowserLikePolicyForHTTPS() - reactor = self.Reactor() - agent = client.Agent(reactor, expectedCreatorCreator) - endpoint = agent._getEndpoint( - URI.fromBytes(b'https://%s:%s/' % (expectedHost, expectedPort))) - endpoint.connect(Factory.forProtocol(Protocol)) - passedFactory = reactor.sslClients[-1][2] - passedContextFactory = reactor.sslClients[-1][3] - tlsFactory = TLSMemoryBIOFactory( - passedContextFactory, True, passedFactory - ) - tlsProtocol = tlsFactory.buildProtocol(None) - tlsProtocol.makeConnection(StringTransport()) - tls = contextArgs[0][0] - self.assertIsInstance(tls, TLSMemoryBIOProtocol) - self.assertEqual(contextArgs[0][1:], (expectedHost, expectedPort)) - self.assertTrue(expectedConnection.handshakeStarted) - self.assertTrue(expectedConnection.connectState) - - - def test_deprecatedDuckPolicy(self): - """ - Passing something that duck-types I{like} a L{web client context - factory <twisted.web.client.WebClientContextFactory>} - something that - does not provide L{IPolicyForHTTPS} - to L{Agent} emits a - L{DeprecationWarning} even if you don't actually C{import - WebClientContextFactory} to do it. - """ - def warnMe(): - client.Agent(MemoryReactorClock(), - "does-not-provide-IPolicyForHTTPS") - warnMe() - warnings = self.flushWarnings([warnMe]) - self.assertEqual(len(warnings), 1) - [warning] = warnings - self.assertEqual(warning['category'], DeprecationWarning) - self.assertEqual( - warning['message'], - "'does-not-provide-IPolicyForHTTPS' was passed as the HTTPS " - "policy for an Agent, but it does not provide IPolicyForHTTPS. " - "Since Twisted 14.0, you must pass a provider of IPolicyForHTTPS." - ) - - - def test_alternateTrustRoot(self): - """ - L{BrowserLikePolicyForHTTPS.creatorForNetloc} returns an - L{IOpenSSLClientConnectionCreator} provider which will add certificates - from the given trust root. - """ - @implementer(IOpenSSLTrustRoot) - class CustomOpenSSLTrustRoot(object): - called = False - context = None - def _addCACertsToContext(self, context): - self.called = True - self.context = context - trustRoot = CustomOpenSSLTrustRoot() - policy = BrowserLikePolicyForHTTPS(trustRoot=trustRoot) - creator = policy.creatorForNetloc(b"thingy", 4321) - self.assertTrue(trustRoot.called) - connection = creator.clientConnectionForTLS(None) - self.assertIs(trustRoot.context, connection.get_context()) - - - -class WebClientContextFactoryTests(TestCase): - """ - Tests for the context factory wrapper for web clients - L{twisted.web.client.WebClientContextFactory}. - """ - - def setUp(self): - """ - Get WebClientContextFactory while quashing its deprecation warning. - """ - from twisted.web.client import WebClientContextFactory - self.warned = self.flushWarnings([WebClientContextFactoryTests.setUp]) - self.webClientContextFactory = WebClientContextFactory - - - def test_deprecated(self): - """ - L{twisted.web.client.WebClientContextFactory} is deprecated. Importing - it displays a warning. - """ - self.assertEqual(len(self.warned), 1) - [warning] = self.warned - self.assertEqual(warning['category'], DeprecationWarning) - self.assertEqual( - warning['message'], - getDeprecationWarningString( - self.webClientContextFactory, Version("Twisted", 14, 0, 0), - replacement=BrowserLikePolicyForHTTPS, - ) - - # See https://twistedmatrix.com/trac/ticket/7242 - .replace(";", ":") - ) - - - def test_missingSSL(self): - """ - If C{getContext} is called and SSL is not available, raise - L{NotImplementedError}. - """ - self.assertRaises( - NotImplementedError, - self.webClientContextFactory().getContext, - 'example.com', 443, - ) - - - def test_returnsContext(self): - """ - If SSL is present, C{getContext} returns a L{SSL.Context}. - """ - ctx = self.webClientContextFactory().getContext('example.com', 443) - self.assertIsInstance(ctx, ssl.SSL.Context) - - - def test_setsTrustRootOnContextToDefaultTrustRoot(self): - """ - The L{CertificateOptions} has C{trustRoot} set to the default trust - roots. - """ - ctx = self.webClientContextFactory() - certificateOptions = ctx._getCertificateOptions('example.com', 443) - self.assertIsInstance( - certificateOptions.trustRoot, ssl.OpenSSLDefaultPaths) - - - if ssl is None: - test_returnsContext.skip = "SSL not present, cannot run SSL tests." - test_setsTrustRootOnContextToDefaultTrustRoot.skip = ( - "SSL not present, cannot run SSL tests.") - else: - test_missingSSL.skip = "SSL present." - - - -class HTTPConnectionPoolRetryTests(TestCase, FakeReactorAndConnectMixin): - """ - L{client.HTTPConnectionPool}, by using - L{client._RetryingHTTP11ClientProtocol}, supports retrying requests done - against previously cached connections. - """ - - def test_onlyRetryIdempotentMethods(self): - """ - Only GET, HEAD, OPTIONS, TRACE, DELETE methods cause a retry. - """ - pool = client.HTTPConnectionPool(None) - connection = client._RetryingHTTP11ClientProtocol(None, pool) - self.assertTrue(connection._shouldRetry("GET", RequestNotSent(), None)) - self.assertTrue(connection._shouldRetry("HEAD", RequestNotSent(), None)) - self.assertTrue(connection._shouldRetry( - "OPTIONS", RequestNotSent(), None)) - self.assertTrue(connection._shouldRetry( - "TRACE", RequestNotSent(), None)) - self.assertTrue(connection._shouldRetry( - "DELETE", RequestNotSent(), None)) - self.assertFalse(connection._shouldRetry( - "POST", RequestNotSent(), None)) - self.assertFalse(connection._shouldRetry( - "MYMETHOD", RequestNotSent(), None)) - # This will be covered by a different ticket, since we need support - #for resettable body producers: - # self.assertTrue(connection._doRetry("PUT", RequestNotSent(), None)) - - - def test_onlyRetryIfNoResponseReceived(self): - """ - Only L{RequestNotSent}, L{RequestTransmissionFailed} and - L{ResponseNeverReceived} exceptions cause a retry. - """ - pool = client.HTTPConnectionPool(None) - connection = client._RetryingHTTP11ClientProtocol(None, pool) - self.assertTrue(connection._shouldRetry("GET", RequestNotSent(), None)) - self.assertTrue(connection._shouldRetry( - "GET", RequestTransmissionFailed([]), None)) - self.assertTrue(connection._shouldRetry( - "GET", ResponseNeverReceived([]),None)) - self.assertFalse(connection._shouldRetry( - "GET", ResponseFailed([]), None)) - self.assertFalse(connection._shouldRetry( - "GET", ConnectionRefusedError(), None)) - - - def test_dontRetryIfFailedDueToCancel(self): - """ - If a request failed due to the operation being cancelled, - C{_shouldRetry} returns C{False} to indicate the request should not be - retried. - """ - pool = client.HTTPConnectionPool(None) - connection = client._RetryingHTTP11ClientProtocol(None, pool) - exception = ResponseNeverReceived([Failure(defer.CancelledError())]) - self.assertFalse(connection._shouldRetry( - "GET", exception, None)) - - - def test_retryIfFailedDueToNonCancelException(self): - """ - If a request failed with L{ResponseNeverReceived} due to some - arbitrary exception, C{_shouldRetry} returns C{True} to indicate the - request should be retried. - """ - pool = client.HTTPConnectionPool(None) - connection = client._RetryingHTTP11ClientProtocol(None, pool) - self.assertTrue(connection._shouldRetry( - "GET", ResponseNeverReceived([Failure(Exception())]), None)) - - - def test_wrappedOnPersistentReturned(self): - """ - If L{client.HTTPConnectionPool.getConnection} returns a previously - cached connection, it will get wrapped in a - L{client._RetryingHTTP11ClientProtocol}. - """ - pool = client.HTTPConnectionPool(Clock()) - - # Add a connection to the cache: - protocol = StubHTTPProtocol() - protocol.makeConnection(StringTransport()) - pool._putConnection(123, protocol) - - # Retrieve it, it should come back wrapped in a - # _RetryingHTTP11ClientProtocol: - d = pool.getConnection(123, DummyEndpoint()) - - def gotConnection(connection): - self.assertIsInstance(connection, - client._RetryingHTTP11ClientProtocol) - self.assertIdentical(connection._clientProtocol, protocol) - return d.addCallback(gotConnection) - - - def test_notWrappedOnNewReturned(self): - """ - If L{client.HTTPConnectionPool.getConnection} returns a new - connection, it will be returned as is. - """ - pool = client.HTTPConnectionPool(None) - d = pool.getConnection(123, DummyEndpoint()) - - def gotConnection(connection): - # Don't want to use isinstance since potentially the wrapper might - # subclass it at some point: - self.assertIdentical(connection.__class__, HTTP11ClientProtocol) - return d.addCallback(gotConnection) - - - def retryAttempt(self, willWeRetry): - """ - Fail a first request, possibly retrying depending on argument. - """ - protocols = [] - def newProtocol(): - protocol = StubHTTPProtocol() - protocols.append(protocol) - return defer.succeed(protocol) - - bodyProducer = object() - request = client.Request("FOO", "/", client.Headers(), bodyProducer, - persistent=True) - newProtocol() - protocol = protocols[0] - retrier = client._RetryingHTTP11ClientProtocol(protocol, newProtocol) - - def _shouldRetry(m, e, bp): - self.assertEqual(m, "FOO") - self.assertIdentical(bp, bodyProducer) - self.assertIsInstance(e, (RequestNotSent, ResponseNeverReceived)) - return willWeRetry - retrier._shouldRetry = _shouldRetry - - d = retrier.request(request) - - # So far, one request made: - self.assertEqual(len(protocols), 1) - self.assertEqual(len(protocols[0].requests), 1) - - # Fail the first request: - protocol.requests[0][1].errback(RequestNotSent()) - return d, protocols - - - def test_retryIfShouldRetryReturnsTrue(self): - """ - L{client._RetryingHTTP11ClientProtocol} retries when - L{client._RetryingHTTP11ClientProtocol._shouldRetry} returns C{True}. - """ - d, protocols = self.retryAttempt(True) - # We retried! - self.assertEqual(len(protocols), 2) - response = object() - protocols[1].requests[0][1].callback(response) - return d.addCallback(self.assertIdentical, response) - - - def test_dontRetryIfShouldRetryReturnsFalse(self): - """ - L{client._RetryingHTTP11ClientProtocol} does not retry when - L{client._RetryingHTTP11ClientProtocol._shouldRetry} returns C{False}. - """ - d, protocols = self.retryAttempt(False) - # We did not retry: - self.assertEqual(len(protocols), 1) - return self.assertFailure(d, RequestNotSent) - - - def test_onlyRetryWithoutBody(self): - """ - L{_RetryingHTTP11ClientProtocol} only retries queries that don't have - a body. - - This is an implementation restriction; if the restriction is fixed, - this test should be removed and PUT added to list of methods that - support retries. - """ - pool = client.HTTPConnectionPool(None) - connection = client._RetryingHTTP11ClientProtocol(None, pool) - self.assertTrue(connection._shouldRetry("GET", RequestNotSent(), None)) - self.assertFalse(connection._shouldRetry("GET", RequestNotSent(), object())) - - - def test_onlyRetryOnce(self): - """ - If a L{client._RetryingHTTP11ClientProtocol} fails more than once on - an idempotent query before a response is received, it will not retry. - """ - d, protocols = self.retryAttempt(True) - self.assertEqual(len(protocols), 2) - # Fail the second request too: - protocols[1].requests[0][1].errback(ResponseNeverReceived([])) - # We didn't retry again: - self.assertEqual(len(protocols), 2) - return self.assertFailure(d, ResponseNeverReceived) - - - def test_dontRetryIfRetryAutomaticallyFalse(self): - """ - If L{HTTPConnectionPool.retryAutomatically} is set to C{False}, don't - wrap connections with retrying logic. - """ - pool = client.HTTPConnectionPool(Clock()) - pool.retryAutomatically = False - - # Add a connection to the cache: - protocol = StubHTTPProtocol() - protocol.makeConnection(StringTransport()) - pool._putConnection(123, protocol) - - # Retrieve it, it should come back unwrapped: - d = pool.getConnection(123, DummyEndpoint()) - - def gotConnection(connection): - self.assertIdentical(connection, protocol) - return d.addCallback(gotConnection) - - - def test_retryWithNewConnection(self): - """ - L{client.HTTPConnectionPool} creates - {client._RetryingHTTP11ClientProtocol} with a new connection factory - method that creates a new connection using the same key and endpoint - as the wrapped connection. - """ - pool = client.HTTPConnectionPool(Clock()) - key = 123 - endpoint = DummyEndpoint() - newConnections = [] - - # Override the pool's _newConnection: - def newConnection(k, e): - newConnections.append((k, e)) - pool._newConnection = newConnection - - # Add a connection to the cache: - protocol = StubHTTPProtocol() - protocol.makeConnection(StringTransport()) - pool._putConnection(key, protocol) - - # Retrieve it, it should come back wrapped in a - # _RetryingHTTP11ClientProtocol: - d = pool.getConnection(key, endpoint) - - def gotConnection(connection): - self.assertIsInstance(connection, - client._RetryingHTTP11ClientProtocol) - self.assertIdentical(connection._clientProtocol, protocol) - # Verify that the _newConnection method on retrying connection - # calls _newConnection on the pool: - self.assertEqual(newConnections, []) - connection._newConnection() - self.assertEqual(len(newConnections), 1) - self.assertEqual(newConnections[0][0], key) - self.assertIdentical(newConnections[0][1], endpoint) - return d.addCallback(gotConnection) - - - -class CookieTestsMixin(object): - """ - Mixin for unit tests dealing with cookies. - """ - def addCookies(self, cookieJar, uri, cookies): - """ - Add a cookie to a cookie jar. - """ - response = client._FakeUrllib2Response( - client.Response( - ('HTTP', 1, 1), - 200, - 'OK', - client.Headers({'Set-Cookie': cookies}), - None)) - request = client._FakeUrllib2Request(uri) - cookieJar.extract_cookies(response, request) - return request, response - - - -class CookieJarTests(TestCase, CookieTestsMixin): - """ - Tests for L{twisted.web.client._FakeUrllib2Response} and - L{twisted.web.client._FakeUrllib2Request}'s interactions with - C{cookielib.CookieJar} instances. - """ - def makeCookieJar(self): - """ - @return: a C{cookielib.CookieJar} with some sample cookies - """ - cookieJar = cookielib.CookieJar() - reqres = self.addCookies( - cookieJar, - 'http://example.com:1234/foo?bar', - ['foo=1; cow=moo; Path=/foo; Comment=hello', - 'bar=2; Comment=goodbye']) - return cookieJar, reqres - - - def test_extractCookies(self): - """ - L{cookielib.CookieJar.extract_cookies} extracts cookie information from - fake urllib2 response instances. - """ - jar = self.makeCookieJar()[0] - cookies = dict([(c.name, c) for c in jar]) - - cookie = cookies['foo'] - self.assertEqual(cookie.version, 0) - self.assertEqual(cookie.name, 'foo') - self.assertEqual(cookie.value, '1') - self.assertEqual(cookie.path, '/foo') - self.assertEqual(cookie.comment, 'hello') - self.assertEqual(cookie.get_nonstandard_attr('cow'), 'moo') - - cookie = cookies['bar'] - self.assertEqual(cookie.version, 0) - self.assertEqual(cookie.name, 'bar') - self.assertEqual(cookie.value, '2') - self.assertEqual(cookie.path, '/') - self.assertEqual(cookie.comment, 'goodbye') - self.assertIdentical(cookie.get_nonstandard_attr('cow'), None) - - - def test_sendCookie(self): - """ - L{cookielib.CookieJar.add_cookie_header} adds a cookie header to a fake - urllib2 request instance. - """ - jar, (request, response) = self.makeCookieJar() - - self.assertIdentical( - request.get_header('Cookie', None), - None) - - jar.add_cookie_header(request) - self.assertEqual( - request.get_header('Cookie', None), - 'foo=1; bar=2') - - - -class CookieAgentTests(TestCase, CookieTestsMixin, FakeReactorAndConnectMixin, - AgentTestsMixin): - """ - Tests for L{twisted.web.client.CookieAgent}. - """ - def makeAgent(self): - """ - @return: a new L{twisted.web.client.CookieAgent} - """ - return client.CookieAgent( - self.buildAgentForWrapperTest(self.reactor), - cookielib.CookieJar()) - - - def setUp(self): - self.reactor = self.Reactor() - - - def test_emptyCookieJarRequest(self): - """ - L{CookieAgent.request} does not insert any C{'Cookie'} header into the - L{Request} object if there is no cookie in the cookie jar for the URI - being requested. Cookies are extracted from the response and stored in - the cookie jar. - """ - cookieJar = cookielib.CookieJar() - self.assertEqual(list(cookieJar), []) - - agent = self.buildAgentForWrapperTest(self.reactor) - cookieAgent = client.CookieAgent(agent, cookieJar) - d = cookieAgent.request( - 'GET', 'http://example.com:1234/foo?bar') - - def _checkCookie(ignored): - cookies = list(cookieJar) - self.assertEqual(len(cookies), 1) - self.assertEqual(cookies[0].name, 'foo') - self.assertEqual(cookies[0].value, '1') - - d.addCallback(_checkCookie) - - req, res = self.protocol.requests.pop() - self.assertIdentical(req.headers.getRawHeaders('cookie'), None) - - resp = client.Response( - ('HTTP', 1, 1), - 200, - 'OK', - client.Headers({'Set-Cookie': ['foo=1',]}), - None) - res.callback(resp) - - return d - - - def test_requestWithCookie(self): - """ - L{CookieAgent.request} inserts a C{'Cookie'} header into the L{Request} - object when there is a cookie matching the request URI in the cookie - jar. - """ - uri = 'http://example.com:1234/foo?bar' - cookie = 'foo=1' - - cookieJar = cookielib.CookieJar() - self.addCookies(cookieJar, uri, [cookie]) - self.assertEqual(len(list(cookieJar)), 1) - - agent = self.buildAgentForWrapperTest(self.reactor) - cookieAgent = client.CookieAgent(agent, cookieJar) - cookieAgent.request('GET', uri) - - req, res = self.protocol.requests.pop() - self.assertEqual(req.headers.getRawHeaders('cookie'), [cookie]) - - - def test_secureCookie(self): - """ - L{CookieAgent} is able to handle secure cookies, ie cookies which - should only be handled over https. - """ - uri = 'https://example.com:1234/foo?bar' - cookie = 'foo=1;secure' - - cookieJar = cookielib.CookieJar() - self.addCookies(cookieJar, uri, [cookie]) - self.assertEqual(len(list(cookieJar)), 1) - - agent = self.buildAgentForWrapperTest(self.reactor) - cookieAgent = client.CookieAgent(agent, cookieJar) - cookieAgent.request('GET', uri) - - req, res = self.protocol.requests.pop() - self.assertEqual(req.headers.getRawHeaders('cookie'), ['foo=1']) - - - def test_secureCookieOnInsecureConnection(self): - """ - If a cookie is setup as secure, it won't be sent with the request if - it's not over HTTPS. - """ - uri = 'http://example.com/foo?bar' - cookie = 'foo=1;secure' - - cookieJar = cookielib.CookieJar() - self.addCookies(cookieJar, uri, [cookie]) - self.assertEqual(len(list(cookieJar)), 1) - - agent = self.buildAgentForWrapperTest(self.reactor) - cookieAgent = client.CookieAgent(agent, cookieJar) - cookieAgent.request('GET', uri) - - req, res = self.protocol.requests.pop() - self.assertIdentical(None, req.headers.getRawHeaders('cookie')) - - - def test_portCookie(self): - """ - L{CookieAgent} supports cookies which enforces the port number they - need to be transferred upon. - """ - uri = 'https://example.com:1234/foo?bar' - cookie = 'foo=1;port=1234' - - cookieJar = cookielib.CookieJar() - self.addCookies(cookieJar, uri, [cookie]) - self.assertEqual(len(list(cookieJar)), 1) - - agent = self.buildAgentForWrapperTest(self.reactor) - cookieAgent = client.CookieAgent(agent, cookieJar) - cookieAgent.request('GET', uri) - - req, res = self.protocol.requests.pop() - self.assertEqual(req.headers.getRawHeaders('cookie'), ['foo=1']) - - - def test_portCookieOnWrongPort(self): - """ - When creating a cookie with a port directive, it won't be added to the - L{cookie.CookieJar} if the URI is on a different port. - """ - uri = 'https://example.com:4567/foo?bar' - cookie = 'foo=1;port=1234' - - cookieJar = cookielib.CookieJar() - self.addCookies(cookieJar, uri, [cookie]) - self.assertEqual(len(list(cookieJar)), 0) - - - -class Decoder1(proxyForInterface(IResponse)): - """ - A test decoder to be used by L{client.ContentDecoderAgent} tests. - """ - - - -class Decoder2(Decoder1): - """ - A test decoder to be used by L{client.ContentDecoderAgent} tests. - """ - - - -class ContentDecoderAgentTests(TestCase, FakeReactorAndConnectMixin, - AgentTestsMixin): - """ - Tests for L{client.ContentDecoderAgent}. - """ - def makeAgent(self): - """ - @return: a new L{twisted.web.client.ContentDecoderAgent} - """ - return client.ContentDecoderAgent(self.agent, []) - - - def setUp(self): - """ - Create an L{Agent} wrapped around a fake reactor. - """ - self.reactor = self.Reactor() - self.agent = self.buildAgentForWrapperTest(self.reactor) - - - def test_acceptHeaders(self): - """ - L{client.ContentDecoderAgent} sets the I{Accept-Encoding} header to the - names of the available decoder objects. - """ - agent = client.ContentDecoderAgent( - self.agent, [('decoder1', Decoder1), ('decoder2', Decoder2)]) - - agent.request('GET', 'http://example.com/foo') - - protocol = self.protocol - - self.assertEqual(len(protocol.requests), 1) - req, res = protocol.requests.pop() - self.assertEqual(req.headers.getRawHeaders('accept-encoding'), - ['decoder1,decoder2']) - - - def test_existingHeaders(self): - """ - If there are existing I{Accept-Encoding} fields, - L{client.ContentDecoderAgent} creates a new field for the decoders it - knows about. - """ - headers = http_headers.Headers({'foo': ['bar'], - 'accept-encoding': ['fizz']}) - agent = client.ContentDecoderAgent( - self.agent, [('decoder1', Decoder1), ('decoder2', Decoder2)]) - agent.request('GET', 'http://example.com/foo', headers=headers) - - protocol = self.protocol - - self.assertEqual(len(protocol.requests), 1) - req, res = protocol.requests.pop() - self.assertEqual( - list(sorted(req.headers.getAllRawHeaders())), - [('Accept-Encoding', ['fizz', 'decoder1,decoder2']), - ('Foo', ['bar']), - ('Host', ['example.com'])]) - - - def test_plainEncodingResponse(self): - """ - If the response is not encoded despited the request I{Accept-Encoding} - headers, L{client.ContentDecoderAgent} simply forwards the response. - """ - agent = client.ContentDecoderAgent( - self.agent, [('decoder1', Decoder1), ('decoder2', Decoder2)]) - deferred = agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - response = Response(('HTTP', 1, 1), 200, 'OK', http_headers.Headers(), - None) - res.callback(response) - - return deferred.addCallback(self.assertIdentical, response) - - - def test_unsupportedEncoding(self): - """ - If an encoding unknown to the L{client.ContentDecoderAgent} is found, - the response is unchanged. - """ - agent = client.ContentDecoderAgent( - self.agent, [('decoder1', Decoder1), ('decoder2', Decoder2)]) - deferred = agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers({'foo': ['bar'], - 'content-encoding': ['fizz']}) - response = Response(('HTTP', 1, 1), 200, 'OK', headers, None) - res.callback(response) - - return deferred.addCallback(self.assertIdentical, response) - - - def test_unknownEncoding(self): - """ - When L{client.ContentDecoderAgent} encounters a decoder it doesn't know - about, it stops decoding even if another encoding is known afterwards. - """ - agent = client.ContentDecoderAgent( - self.agent, [('decoder1', Decoder1), ('decoder2', Decoder2)]) - deferred = agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers({'foo': ['bar'], - 'content-encoding': - ['decoder1,fizz,decoder2']}) - response = Response(('HTTP', 1, 1), 200, 'OK', headers, None) - res.callback(response) - - def check(result): - self.assertNotIdentical(response, result) - self.assertIsInstance(result, Decoder2) - self.assertEqual(['decoder1,fizz'], - result.headers.getRawHeaders('content-encoding')) - - return deferred.addCallback(check) - - - -class SimpleAgentProtocol(Protocol): - """ - A L{Protocol} to be used with an L{client.Agent} to receive data. - - @ivar finished: L{Deferred} firing when C{connectionLost} is called. - - @ivar made: L{Deferred} firing when C{connectionMade} is called. - - @ivar received: C{list} of received data. - """ - - def __init__(self): - self.made = Deferred() - self.finished = Deferred() - self.received = [] - - - def connectionMade(self): - self.made.callback(None) - - - def connectionLost(self, reason): - self.finished.callback(None) - - - def dataReceived(self, data): - self.received.append(data) - - - -class ContentDecoderAgentWithGzipTests(TestCase, - FakeReactorAndConnectMixin): - - def setUp(self): - """ - Create an L{Agent} wrapped around a fake reactor. - """ - self.reactor = self.Reactor() - agent = self.buildAgentForWrapperTest(self.reactor) - self.agent = client.ContentDecoderAgent( - agent, [("gzip", client.GzipDecoder)]) - - - def test_gzipEncodingResponse(self): - """ - If the response has a C{gzip} I{Content-Encoding} header, - L{GzipDecoder} wraps the response to return uncompressed data to the - user. - """ - deferred = self.agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers({'foo': ['bar'], - 'content-encoding': ['gzip']}) - transport = StringTransport() - response = Response(('HTTP', 1, 1), 200, 'OK', headers, transport) - response.length = 12 - res.callback(response) - - compressor = zlib.compressobj(2, zlib.DEFLATED, 16 + zlib.MAX_WBITS) - data = (compressor.compress('x' * 6) + compressor.compress('y' * 4) + - compressor.flush()) - - def checkResponse(result): - self.assertNotIdentical(result, response) - self.assertEqual(result.version, ('HTTP', 1, 1)) - self.assertEqual(result.code, 200) - self.assertEqual(result.phrase, 'OK') - self.assertEqual(list(result.headers.getAllRawHeaders()), - [('Foo', ['bar'])]) - self.assertEqual(result.length, UNKNOWN_LENGTH) - self.assertRaises(AttributeError, getattr, result, 'unknown') - - response._bodyDataReceived(data[:5]) - response._bodyDataReceived(data[5:]) - response._bodyDataFinished() - - protocol = SimpleAgentProtocol() - result.deliverBody(protocol) - - self.assertEqual(protocol.received, ['x' * 6 + 'y' * 4]) - return defer.gatherResults([protocol.made, protocol.finished]) - - deferred.addCallback(checkResponse) - - return deferred - - - def test_brokenContent(self): - """ - If the data received by the L{GzipDecoder} isn't valid gzip-compressed - data, the call to C{deliverBody} fails with a C{zlib.error}. - """ - deferred = self.agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers({'foo': ['bar'], - 'content-encoding': ['gzip']}) - transport = StringTransport() - response = Response(('HTTP', 1, 1), 200, 'OK', headers, transport) - response.length = 12 - res.callback(response) - - data = "not gzipped content" - - def checkResponse(result): - response._bodyDataReceived(data) - - result.deliverBody(Protocol()) - - deferred.addCallback(checkResponse) - self.assertFailure(deferred, client.ResponseFailed) - - def checkFailure(error): - error.reasons[0].trap(zlib.error) - self.assertIsInstance(error.response, Response) - - return deferred.addCallback(checkFailure) - - - def test_flushData(self): - """ - When the connection with the server is lost, the gzip protocol calls - C{flush} on the zlib decompressor object to get uncompressed data which - may have been buffered. - """ - class decompressobj(object): - - def __init__(self, wbits): - pass - - def decompress(self, data): - return 'x' - - def flush(self): - return 'y' - - - oldDecompressObj = zlib.decompressobj - zlib.decompressobj = decompressobj - self.addCleanup(setattr, zlib, 'decompressobj', oldDecompressObj) - - deferred = self.agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers({'content-encoding': ['gzip']}) - transport = StringTransport() - response = Response(('HTTP', 1, 1), 200, 'OK', headers, transport) - res.callback(response) - - def checkResponse(result): - response._bodyDataReceived('data') - response._bodyDataFinished() - - protocol = SimpleAgentProtocol() - result.deliverBody(protocol) - - self.assertEqual(protocol.received, ['x', 'y']) - return defer.gatherResults([protocol.made, protocol.finished]) - - deferred.addCallback(checkResponse) - - return deferred - - - def test_flushError(self): - """ - If the C{flush} call in C{connectionLost} fails, the C{zlib.error} - exception is caught and turned into a L{ResponseFailed}. - """ - class decompressobj(object): - - def __init__(self, wbits): - pass - - def decompress(self, data): - return 'x' - - def flush(self): - raise zlib.error() - - - oldDecompressObj = zlib.decompressobj - zlib.decompressobj = decompressobj - self.addCleanup(setattr, zlib, 'decompressobj', oldDecompressObj) - - deferred = self.agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers({'content-encoding': ['gzip']}) - transport = StringTransport() - response = Response(('HTTP', 1, 1), 200, 'OK', headers, transport) - res.callback(response) - - def checkResponse(result): - response._bodyDataReceived('data') - response._bodyDataFinished() - - protocol = SimpleAgentProtocol() - result.deliverBody(protocol) - - self.assertEqual(protocol.received, ['x', 'y']) - return defer.gatherResults([protocol.made, protocol.finished]) - - deferred.addCallback(checkResponse) - - self.assertFailure(deferred, client.ResponseFailed) - - def checkFailure(error): - error.reasons[1].trap(zlib.error) - self.assertIsInstance(error.response, Response) - - return deferred.addCallback(checkFailure) - - - -class ProxyAgentTests(TestCase, FakeReactorAndConnectMixin, AgentTestsMixin): - """ - Tests for L{client.ProxyAgent}. - """ - def makeAgent(self): - """ - @return: a new L{twisted.web.client.ProxyAgent} - """ - return client.ProxyAgent( - TCP4ClientEndpoint(self.reactor, "127.0.0.1", 1234), - self.reactor) - - - def setUp(self): - self.reactor = self.Reactor() - self.agent = client.ProxyAgent( - TCP4ClientEndpoint(self.reactor, "bar", 5678), self.reactor) - oldEndpoint = self.agent._proxyEndpoint - self.agent._proxyEndpoint = self.StubEndpoint(oldEndpoint, self) - - - def test_proxyRequest(self): - """ - L{client.ProxyAgent} issues an HTTP request against the proxy, with the - full URI as path, when C{request} is called. - """ - headers = http_headers.Headers({'foo': ['bar']}) - # Just going to check the body for identity, so it doesn't need to be - # real. - body = object() - self.agent.request( - 'GET', 'http://example.com:1234/foo?bar', headers, body) - - host, port, factory = self.reactor.tcpClients.pop()[:3] - self.assertEqual(host, "bar") - self.assertEqual(port, 5678) - - self.assertIsInstance(factory._wrappedFactory, - client._HTTP11ClientFactory) - - protocol = self.protocol - - # The request should be issued. - self.assertEqual(len(protocol.requests), 1) - req, res = protocol.requests.pop() - self.assertIsInstance(req, Request) - self.assertEqual(req.method, 'GET') - self.assertEqual(req.uri, 'http://example.com:1234/foo?bar') - self.assertEqual( - req.headers, - http_headers.Headers({'foo': ['bar'], - 'host': ['example.com:1234']})) - self.assertIdentical(req.bodyProducer, body) - - - def test_nonPersistent(self): - """ - C{ProxyAgent} connections are not persistent by default. - """ - self.assertEqual(self.agent._pool.persistent, False) - - - def test_connectUsesConnectionPool(self): - """ - When a connection is made by the C{ProxyAgent}, it uses its pool's - C{getConnection} method to do so, with the endpoint it was constructed - with and a key of C{("http-proxy", endpoint)}. - """ - endpoint = DummyEndpoint() - class DummyPool(object): - connected = False - persistent = False - def getConnection(this, key, ep): - this.connected = True - self.assertIdentical(ep, endpoint) - # The key is *not* tied to the final destination, but only to - # the address of the proxy, since that's where *we* are - # connecting: - self.assertEqual(key, ("http-proxy", endpoint)) - return defer.succeed(StubHTTPProtocol()) - - pool = DummyPool() - agent = client.ProxyAgent(endpoint, self.reactor, pool=pool) - self.assertIdentical(pool, agent._pool) - - agent.request('GET', 'http://foo/') - self.assertEqual(agent._pool.connected, True) - - - -class _RedirectAgentTestsMixin(object): - """ - Test cases mixin for L{RedirectAgentTests} and - L{BrowserLikeRedirectAgentTests}. - """ - def test_noRedirect(self): - """ - L{client.RedirectAgent} behaves like L{client.Agent} if the response - doesn't contain a redirect. - """ - deferred = self.agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers() - response = Response(('HTTP', 1, 1), 200, 'OK', headers, None) - res.callback(response) - - self.assertEqual(0, len(self.protocol.requests)) - result = self.successResultOf(deferred) - self.assertIdentical(response, result) - self.assertIdentical(result.previousResponse, None) - - - def _testRedirectDefault(self, code): - """ - When getting a redirect, L{client.RedirectAgent} follows the URL - specified in the L{Location} header field and make a new request. - - @param code: HTTP status code. - """ - self.agent.request('GET', 'http://example.com/foo') - - host, port = self.reactor.tcpClients.pop()[:2] - self.assertEqual("example.com", host) - self.assertEqual(80, port) - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers( - {'location': ['https://example.com/bar']}) - response = Response(('HTTP', 1, 1), code, 'OK', headers, None) - res.callback(response) - - req2, res2 = self.protocol.requests.pop() - self.assertEqual('GET', req2.method) - self.assertEqual('/bar', req2.uri) - - host, port = self.reactor.sslClients.pop()[:2] - self.assertEqual("example.com", host) - self.assertEqual(443, port) - - - def test_redirect301(self): - """ - L{client.RedirectAgent} follows redirects on status code 301. - """ - self._testRedirectDefault(301) - - - def test_redirect302(self): - """ - L{client.RedirectAgent} follows redirects on status code 302. - """ - self._testRedirectDefault(302) - - - def test_redirect307(self): - """ - L{client.RedirectAgent} follows redirects on status code 307. - """ - self._testRedirectDefault(307) - - - def _testRedirectToGet(self, code, method): - """ - L{client.RedirectAgent} changes the method to I{GET} when getting - a redirect on a non-I{GET} request. - - @param code: HTTP status code. - - @param method: HTTP request method. - """ - self.agent.request(method, 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers( - {'location': ['http://example.com/bar']}) - response = Response(('HTTP', 1, 1), code, 'OK', headers, None) - res.callback(response) - - req2, res2 = self.protocol.requests.pop() - self.assertEqual('GET', req2.method) - self.assertEqual('/bar', req2.uri) - - - def test_redirect303(self): - """ - L{client.RedirectAgent} changes the method to I{GET} when getting a 303 - redirect on a I{POST} request. - """ - self._testRedirectToGet(303, 'POST') - - - def test_noLocationField(self): - """ - If no L{Location} header field is found when getting a redirect, - L{client.RedirectAgent} fails with a L{ResponseFailed} error wrapping a - L{error.RedirectWithNoLocation} exception. - """ - deferred = self.agent.request('GET', 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers() - response = Response(('HTTP', 1, 1), 301, 'OK', headers, None) - res.callback(response) - - fail = self.failureResultOf(deferred, client.ResponseFailed) - fail.value.reasons[0].trap(error.RedirectWithNoLocation) - self.assertEqual('http://example.com/foo', - fail.value.reasons[0].value.uri) - self.assertEqual(301, fail.value.response.code) - - - def _testPageRedirectFailure(self, code, method): - """ - When getting a redirect on an unsupported request method, - L{client.RedirectAgent} fails with a L{ResponseFailed} error wrapping - a L{error.PageRedirect} exception. - - @param code: HTTP status code. - - @param method: HTTP request method. - """ - deferred = self.agent.request(method, 'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers() - response = Response(('HTTP', 1, 1), code, 'OK', headers, None) - res.callback(response) - - fail = self.failureResultOf(deferred, client.ResponseFailed) - fail.value.reasons[0].trap(error.PageRedirect) - self.assertEqual('http://example.com/foo', - fail.value.reasons[0].value.location) - self.assertEqual(code, fail.value.response.code) - - - def test_307OnPost(self): - """ - When getting a 307 redirect on a I{POST} request, - L{client.RedirectAgent} fails with a L{ResponseFailed} error wrapping - a L{error.PageRedirect} exception. - """ - self._testPageRedirectFailure(307, 'POST') - - - def test_redirectLimit(self): - """ - If the limit of redirects specified to L{client.RedirectAgent} is - reached, the deferred fires with L{ResponseFailed} error wrapping - a L{InfiniteRedirection} exception. - """ - agent = self.buildAgentForWrapperTest(self.reactor) - redirectAgent = client.RedirectAgent(agent, 1) - - deferred = redirectAgent.request(b'GET', b'http://example.com/foo') - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers( - {b'location': [b'http://example.com/bar']}) - response = Response((b'HTTP', 1, 1), 302, b'OK', headers, None) - res.callback(response) - - req2, res2 = self.protocol.requests.pop() - - response2 = Response((b'HTTP', 1, 1), 302, b'OK', headers, None) - res2.callback(response2) - - fail = self.failureResultOf(deferred, client.ResponseFailed) - - fail.value.reasons[0].trap(error.InfiniteRedirection) - self.assertEqual('http://example.com/foo', - fail.value.reasons[0].value.location) - self.assertEqual(302, fail.value.response.code) - - - def _testRedirectURI(self, uri, location, finalURI): - """ - When L{client.RedirectAgent} encounters a relative redirect I{URI}, it - is resolved against the request I{URI} before following the redirect. - - @param uri: Request URI. - - @param location: I{Location} header redirect URI. - - @param finalURI: Expected final URI. - """ - self.agent.request('GET', uri) - - req, res = self.protocol.requests.pop() - - headers = http_headers.Headers( - {'location': [location]}) - response = Response(('HTTP', 1, 1), 302, 'OK', headers, None) - res.callback(response) - - req2, res2 = self.protocol.requests.pop() - self.assertEqual('GET', req2.method) - self.assertEqual(finalURI, req2.absoluteURI) - - - def test_relativeURI(self): - """ - L{client.RedirectAgent} resolves and follows relative I{URI}s in - redirects, preserving query strings. - """ - self._testRedirectURI( - 'http://example.com/foo/bar', 'baz', - 'http://example.com/foo/baz') - self._testRedirectURI( - 'http://example.com/foo/bar', '/baz', - 'http://example.com/baz') - self._testRedirectURI( - 'http://example.com/foo/bar', '/baz?a', - 'http://example.com/baz?a') - - - def test_relativeURIPreserveFragments(self): - """ - L{client.RedirectAgent} resolves and follows relative I{URI}s in - redirects, preserving fragments in way that complies with the HTTP 1.1 - bis draft. - - @see: U{https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-22#section-7.1.2} - """ - self._testRedirectURI( - 'http://example.com/foo/bar#frag', '/baz?a', - 'http://example.com/baz?a#frag') - self._testRedirectURI( - 'http://example.com/foo/bar', '/baz?a#frag2', - 'http://example.com/baz?a#frag2') - - - def test_relativeURISchemeRelative(self): - """ - L{client.RedirectAgent} resolves and follows scheme relative I{URI}s in - redirects, replacing the hostname and port when required. - """ - self._testRedirectURI( - 'http://example.com/foo/bar', '//foo.com/baz', - 'http://foo.com/baz') - self._testRedirectURI( - 'http://example.com/foo/bar', '//foo.com:81/baz', - 'http://foo.com:81/baz') - - - def test_responseHistory(self): - """ - L{Response.response} references the previous L{Response} from - a redirect, or C{None} if there was no previous response. - """ - agent = self.buildAgentForWrapperTest(self.reactor) - redirectAgent = client.RedirectAgent(agent) - - deferred = redirectAgent.request(b'GET', b'http://example.com/foo') - - redirectReq, redirectRes = self.protocol.requests.pop() - - headers = http_headers.Headers( - {b'location': [b'http://example.com/bar']}) - redirectResponse = Response((b'HTTP', 1, 1), 302, b'OK', headers, None) - redirectRes.callback(redirectResponse) - - req, res = self.protocol.requests.pop() - - response = Response((b'HTTP', 1, 1), 200, b'OK', headers, None) - res.callback(response) - - finalResponse = self.successResultOf(deferred) - self.assertIdentical(finalResponse.previousResponse, redirectResponse) - self.assertIdentical(redirectResponse.previousResponse, None) - - - -class RedirectAgentTests(TestCase, FakeReactorAndConnectMixin, - _RedirectAgentTestsMixin, AgentTestsMixin): - """ - Tests for L{client.RedirectAgent}. - """ - def makeAgent(self): - """ - @return: a new L{twisted.web.client.RedirectAgent} - """ - return client.RedirectAgent( - self.buildAgentForWrapperTest(self.reactor)) - - - def setUp(self): - self.reactor = self.Reactor() - self.agent = self.makeAgent() - - - def test_301OnPost(self): - """ - When getting a 301 redirect on a I{POST} request, - L{client.RedirectAgent} fails with a L{ResponseFailed} error wrapping - a L{error.PageRedirect} exception. - """ - self._testPageRedirectFailure(301, 'POST') - - - def test_302OnPost(self): - """ - When getting a 302 redirect on a I{POST} request, - L{client.RedirectAgent} fails with a L{ResponseFailed} error wrapping - a L{error.PageRedirect} exception. - """ - self._testPageRedirectFailure(302, 'POST') - - - -class BrowserLikeRedirectAgentTests(TestCase, - FakeReactorAndConnectMixin, - _RedirectAgentTestsMixin, - AgentTestsMixin): - """ - Tests for L{client.BrowserLikeRedirectAgent}. - """ - def makeAgent(self): - """ - @return: a new L{twisted.web.client.BrowserLikeRedirectAgent} - """ - return client.BrowserLikeRedirectAgent( - self.buildAgentForWrapperTest(self.reactor)) - - - def setUp(self): - self.reactor = self.Reactor() - self.agent = self.makeAgent() - - - def test_redirectToGet301(self): - """ - L{client.BrowserLikeRedirectAgent} changes the method to I{GET} when - getting a 302 redirect on a I{POST} request. - """ - self._testRedirectToGet(301, 'POST') - - - def test_redirectToGet302(self): - """ - L{client.BrowserLikeRedirectAgent} changes the method to I{GET} when - getting a 302 redirect on a I{POST} request. - """ - self._testRedirectToGet(302, 'POST') - - - -class AbortableStringTransport(StringTransport): - """ - A version of L{StringTransport} that supports C{abortConnection}. - """ - # This should be replaced by a common version in #6530. - aborting = False - - - def abortConnection(self): - """ - A testable version of the C{ITCPTransport.abortConnection} method. - - Since this is a special case of closing the connection, - C{loseConnection} is also called. - """ - self.aborting = True - self.loseConnection() - - - -class DummyResponse(object): - """ - Fake L{IResponse} for testing readBody that captures the protocol passed to - deliverBody and uses it to make a connection with a transport. - - @ivar protocol: After C{deliverBody} is called, the protocol it was called - with. - - @ivar transport: An instance created by calling C{transportFactory} which - is used by L{DummyResponse.protocol} to make a connection. - """ - - code = 200 - phrase = "OK" - - def __init__(self, headers=None, transportFactory=AbortableStringTransport): - """ - @param headers: The headers for this response. If C{None}, an empty - L{Headers} instance will be used. - @type headers: L{Headers} - - @param transportFactory: A callable used to construct the transport. - """ - if headers is None: - headers = Headers() - self.headers = headers - self.transport = transportFactory() - - - def deliverBody(self, protocol): - """ - Record the given protocol and use it to make a connection with - L{DummyResponse.transport}. - """ - self.protocol = protocol - self.protocol.makeConnection(self.transport) - - - -class AlreadyCompletedDummyResponse(DummyResponse): - """ - A dummy response that has already had its transport closed. - """ - def deliverBody(self, protocol): - """ - Make the connection, then remove the transport. - """ - self.protocol = protocol - self.protocol.makeConnection(self.transport) - self.protocol.transport = None - - - -class ReadBodyTests(TestCase): - """ - Tests for L{client.readBody} - """ - def test_success(self): - """ - L{client.readBody} returns a L{Deferred} which fires with the complete - body of the L{IResponse} provider passed to it. - """ - response = DummyResponse() - d = client.readBody(response) - response.protocol.dataReceived("first") - response.protocol.dataReceived("second") - response.protocol.connectionLost(Failure(ResponseDone())) - self.assertEqual(self.successResultOf(d), "firstsecond") - - - def test_cancel(self): - """ - When cancelling the L{Deferred} returned by L{client.readBody}, the - connection to the server will be aborted. - """ - response = DummyResponse() - deferred = client.readBody(response) - deferred.cancel() - self.failureResultOf(deferred, defer.CancelledError) - self.assertTrue(response.transport.aborting) - - - def test_withPotentialDataLoss(self): - """ - If the full body of the L{IResponse} passed to L{client.readBody} is - not definitely received, the L{Deferred} returned by L{client.readBody} - fires with a L{Failure} wrapping L{client.PartialDownloadError} with - the content that was received. - """ - response = DummyResponse() - d = client.readBody(response) - response.protocol.dataReceived("first") - response.protocol.dataReceived("second") - response.protocol.connectionLost(Failure(PotentialDataLoss())) - failure = self.failureResultOf(d) - failure.trap(client.PartialDownloadError) - self.assertEqual({ - "status": failure.value.status, - "message": failure.value.message, - "body": failure.value.response, - }, { - "status": 200, - "message": "OK", - "body": "firstsecond", - }) - - - def test_otherErrors(self): - """ - If there is an exception other than L{client.PotentialDataLoss} while - L{client.readBody} is collecting the response body, the L{Deferred} - returned by {client.readBody} fires with that exception. - """ - response = DummyResponse() - d = client.readBody(response) - response.protocol.dataReceived("first") - response.protocol.connectionLost( - Failure(ConnectionLost("mystery problem"))) - reason = self.failureResultOf(d) - reason.trap(ConnectionLost) - self.assertEqual(reason.value.args, ("mystery problem",)) - - - def test_deprecatedTransport(self): - """ - Calling L{client.readBody} with a transport that does not implement - L{twisted.internet.interfaces.ITCPTransport} produces a deprecation - warning, but no exception when cancelling. - """ - response = DummyResponse(transportFactory=StringTransport) - d = self.assertWarns( - DeprecationWarning, - 'Using readBody with a transport that does not have an ' - 'abortConnection method', - __file__, - lambda: client.readBody(response)) - d.cancel() - self.failureResultOf(d, defer.CancelledError) - - - def test_deprecatedTransportNoWarning(self): - """ - Calling L{client.readBody} with a response that has already had its - transport closed (eg. for a very small request) will not trigger a - deprecation warning. - """ - response = AlreadyCompletedDummyResponse() - client.readBody(response) - - warnings = self.flushWarnings() - self.assertEqual(len(warnings), 0) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_cgi.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_cgi.py deleted file mode 100755 index 6f803be..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_cgi.py +++ /dev/null @@ -1,364 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.twcgi}. -""" - -import sys, os - -from twisted.trial import unittest -from twisted.internet import reactor, interfaces, error -from twisted.python import util, failure, log -from twisted.web.http import NOT_FOUND, INTERNAL_SERVER_ERROR -from twisted.web import client, twcgi, server, resource -from twisted.web.test._util import _render -from twisted.web.test.test_web import DummyRequest - -DUMMY_CGI = '''\ -print "Header: OK" -print -print "cgi output" -''' - -DUAL_HEADER_CGI = '''\ -print "Header: spam" -print "Header: eggs" -print -print "cgi output" -''' - -BROKEN_HEADER_CGI = '''\ -print "XYZ" -print -print "cgi output" -''' - -SPECIAL_HEADER_CGI = '''\ -print "Server: monkeys" -print "Date: last year" -print -print "cgi output" -''' - -READINPUT_CGI = '''\ -# this is an example of a correctly-written CGI script which reads a body -# from stdin, which only reads env['CONTENT_LENGTH'] bytes. - -import os, sys - -body_length = int(os.environ.get('CONTENT_LENGTH',0)) -indata = sys.stdin.read(body_length) -print "Header: OK" -print -print "readinput ok" -''' - -READALLINPUT_CGI = '''\ -# this is an example of the typical (incorrect) CGI script which expects -# the server to close stdin when the body of the request is complete. -# A correct CGI should only read env['CONTENT_LENGTH'] bytes. - -import sys - -indata = sys.stdin.read() -print "Header: OK" -print -print "readallinput ok" -''' - -NO_DUPLICATE_CONTENT_TYPE_HEADER_CGI = '''\ -print "content-type: text/cgi-duplicate-test" -print -print "cgi output" -''' - -class PythonScript(twcgi.FilteredScript): - filter = sys.executable - -class CGITests(unittest.TestCase): - """ - Tests for L{twcgi.FilteredScript}. - """ - - if not interfaces.IReactorProcess.providedBy(reactor): - skip = "CGI tests require a functional reactor.spawnProcess()" - - def startServer(self, cgi): - root = resource.Resource() - cgipath = util.sibpath(__file__, cgi) - root.putChild("cgi", PythonScript(cgipath)) - site = server.Site(root) - self.p = reactor.listenTCP(0, site) - return self.p.getHost().port - - def tearDown(self): - if getattr(self, 'p', None): - return self.p.stopListening() - - - def writeCGI(self, source): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(source) - cgiFile.close() - return cgiFilename - - - def testCGI(self): - cgiFilename = self.writeCGI(DUMMY_CGI) - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum) - d.addCallback(self._testCGI_1) - return d - - - def _testCGI_1(self, res): - self.assertEqual(res, "cgi output" + os.linesep) - - - def test_protectedServerAndDate(self): - """ - If the CGI script emits a I{Server} or I{Date} header, these are - ignored. - """ - cgiFilename = self.writeCGI(SPECIAL_HEADER_CGI) - - portnum = self.startServer(cgiFilename) - url = "http://localhost:%d/cgi" % (portnum,) - factory = client.HTTPClientFactory(url) - reactor.connectTCP('localhost', portnum, factory) - def checkResponse(ignored): - self.assertNotIn('monkeys', factory.response_headers['server']) - self.assertNotIn('last year', factory.response_headers['date']) - factory.deferred.addCallback(checkResponse) - return factory.deferred - - - def test_noDuplicateContentTypeHeaders(self): - """ - If the CGI script emits a I{content-type} header, make sure that the - server doesn't add an additional (duplicate) one, as per ticket 4786. - """ - cgiFilename = self.writeCGI(NO_DUPLICATE_CONTENT_TYPE_HEADER_CGI) - - portnum = self.startServer(cgiFilename) - url = "http://localhost:%d/cgi" % (portnum,) - factory = client.HTTPClientFactory(url) - reactor.connectTCP('localhost', portnum, factory) - def checkResponse(ignored): - self.assertEqual( - factory.response_headers['content-type'], ['text/cgi-duplicate-test']) - factory.deferred.addCallback(checkResponse) - return factory.deferred - - - def test_duplicateHeaderCGI(self): - """ - If a CGI script emits two instances of the same header, both are sent in - the response. - """ - cgiFilename = self.writeCGI(DUAL_HEADER_CGI) - - portnum = self.startServer(cgiFilename) - url = "http://localhost:%d/cgi" % (portnum,) - factory = client.HTTPClientFactory(url) - reactor.connectTCP('localhost', portnum, factory) - def checkResponse(ignored): - self.assertEqual( - factory.response_headers['header'], ['spam', 'eggs']) - factory.deferred.addCallback(checkResponse) - return factory.deferred - - - def test_malformedHeaderCGI(self): - """ - Check for the error message in the duplicated header - """ - cgiFilename = self.writeCGI(BROKEN_HEADER_CGI) - - portnum = self.startServer(cgiFilename) - url = "http://localhost:%d/cgi" % (portnum,) - factory = client.HTTPClientFactory(url) - reactor.connectTCP('localhost', portnum, factory) - loggedMessages = [] - - def addMessage(eventDict): - loggedMessages.append(log.textFromEventDict(eventDict)) - - log.addObserver(addMessage) - self.addCleanup(log.removeObserver, addMessage) - - def checkResponse(ignored): - self.assertEqual(loggedMessages[0], - "ignoring malformed CGI header: 'XYZ'") - - factory.deferred.addCallback(checkResponse) - return factory.deferred - - - def testReadEmptyInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum) - d.addCallback(self._testReadEmptyInput_1) - return d - testReadEmptyInput.timeout = 5 - def _testReadEmptyInput_1(self, res): - self.assertEqual(res, "readinput ok%s" % os.linesep) - - def testReadInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum, - method="POST", - postdata="Here is your stdin") - d.addCallback(self._testReadInput_1) - return d - testReadInput.timeout = 5 - def _testReadInput_1(self, res): - self.assertEqual(res, "readinput ok%s" % os.linesep) - - - def testReadAllInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READALLINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum, - method="POST", - postdata="Here is your stdin") - d.addCallback(self._testReadAllInput_1) - return d - testReadAllInput.timeout = 5 - def _testReadAllInput_1(self, res): - self.assertEqual(res, "readallinput ok%s" % os.linesep) - - - def test_useReactorArgument(self): - """ - L{twcgi.FilteredScript.runProcess} uses the reactor passed as an - argument to the constructor. - """ - class FakeReactor: - """ - A fake reactor recording whether spawnProcess is called. - """ - called = False - def spawnProcess(self, *args, **kwargs): - """ - Set the C{called} flag to C{True} if C{spawnProcess} is called. - - @param args: Positional arguments. - @param kwargs: Keyword arguments. - """ - self.called = True - - fakeReactor = FakeReactor() - request = DummyRequest(['a', 'b']) - resource = twcgi.FilteredScript("dummy-file", reactor=fakeReactor) - _render(resource, request) - - self.assertTrue(fakeReactor.called) - - - -class CGIScriptTests(unittest.TestCase): - """ - Tests for L{twcgi.CGIScript}. - """ - - def test_pathInfo(self): - """ - L{twcgi.CGIScript.render} sets the process environment I{PATH_INFO} from - the request path. - """ - class FakeReactor: - """ - A fake reactor recording the environment passed to spawnProcess. - """ - def spawnProcess(self, process, filename, args, env, wdir): - """ - Store the C{env} L{dict} to an instance attribute. - - @param process: Ignored - @param filename: Ignored - @param args: Ignored - @param env: The environment L{dict} which will be stored - @param wdir: Ignored - """ - self.process_env = env - - _reactor = FakeReactor() - resource = twcgi.CGIScript(self.mktemp(), reactor=_reactor) - request = DummyRequest(['a', 'b']) - _render(resource, request) - - self.assertEqual(_reactor.process_env["PATH_INFO"], - "/a/b") - - - -class CGIDirectoryTests(unittest.TestCase): - """ - Tests for L{twcgi.CGIDirectory}. - """ - def test_render(self): - """ - L{twcgi.CGIDirectory.render} sets the HTTP response code to I{NOT - FOUND}. - """ - resource = twcgi.CGIDirectory(self.mktemp()) - request = DummyRequest(['']) - d = _render(resource, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, NOT_FOUND) - d.addCallback(cbRendered) - return d - - - def test_notFoundChild(self): - """ - L{twcgi.CGIDirectory.getChild} returns a resource which renders an - response with the HTTP I{NOT FOUND} status code if the indicated child - does not exist as an entry in the directory used to initialized the - L{twcgi.CGIDirectory}. - """ - path = self.mktemp() - os.makedirs(path) - resource = twcgi.CGIDirectory(path) - request = DummyRequest(['foo']) - child = resource.getChild("foo", request) - d = _render(child, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, NOT_FOUND) - d.addCallback(cbRendered) - return d - - - -class CGIProcessProtocolTests(unittest.TestCase): - """ - Tests for L{twcgi.CGIProcessProtocol}. - """ - def test_prematureEndOfHeaders(self): - """ - If the process communicating with L{CGIProcessProtocol} ends before - finishing writing out headers, the response has I{INTERNAL SERVER - ERROR} as its status code. - """ - request = DummyRequest(['']) - protocol = twcgi.CGIProcessProtocol(request) - protocol.processEnded(failure.Failure(error.ProcessTerminated())) - self.assertEqual(request.responseCode, INTERNAL_SERVER_ERROR) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_distrib.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_distrib.py deleted file mode 100755 index 99c36d6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_distrib.py +++ /dev/null @@ -1,434 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.distrib}. -""" - -from os.path import abspath -from xml.dom.minidom import parseString -try: - import pwd -except ImportError: - pwd = None - -from zope.interface.verify import verifyObject - -from twisted.python import filepath -from twisted.internet import reactor, defer -from twisted.trial import unittest -from twisted.spread import pb -from twisted.spread.banana import SIZE_LIMIT -from twisted.web import distrib, client, resource, static, server -from twisted.web.test.test_web import DummyRequest -from twisted.web.test._util import _render -from twisted.test import proto_helpers - - -class MySite(server.Site): - pass - - -class PBServerFactory(pb.PBServerFactory): - """ - A PB server factory which keeps track of the most recent protocol it - created. - - @ivar proto: L{None} or the L{Broker} instance most recently returned - from C{buildProtocol}. - """ - proto = None - - def buildProtocol(self, addr): - self.proto = pb.PBServerFactory.buildProtocol(self, addr) - return self.proto - - - -class DistribTests(unittest.TestCase): - port1 = None - port2 = None - sub = None - f1 = None - - def tearDown(self): - """ - Clean up all the event sources left behind by either directly by - test methods or indirectly via some distrib API. - """ - dl = [defer.Deferred(), defer.Deferred()] - if self.f1 is not None and self.f1.proto is not None: - self.f1.proto.notifyOnDisconnect(lambda: dl[0].callback(None)) - else: - dl[0].callback(None) - if self.sub is not None and self.sub.publisher is not None: - self.sub.publisher.broker.notifyOnDisconnect( - lambda: dl[1].callback(None)) - self.sub.publisher.broker.transport.loseConnection() - else: - dl[1].callback(None) - if self.port1 is not None: - dl.append(self.port1.stopListening()) - if self.port2 is not None: - dl.append(self.port2.stopListening()) - return defer.gatherResults(dl) - - - def testDistrib(self): - # site1 is the publisher - r1 = resource.Resource() - r1.putChild("there", static.Data("root", "text/plain")) - site1 = server.Site(r1) - self.f1 = PBServerFactory(distrib.ResourcePublisher(site1)) - self.port1 = reactor.listenTCP(0, self.f1) - self.sub = distrib.ResourceSubscription("127.0.0.1", - self.port1.getHost().port) - r2 = resource.Resource() - r2.putChild("here", self.sub) - f2 = MySite(r2) - self.port2 = reactor.listenTCP(0, f2) - d = client.getPage("http://127.0.0.1:%d/here/there" % \ - self.port2.getHost().port) - d.addCallback(self.assertEqual, 'root') - return d - - - def _setupDistribServer(self, child): - """ - Set up a resource on a distrib site using L{ResourcePublisher}. - - @param child: The resource to publish using distrib. - - @return: A tuple consisting of the host and port on which to contact - the created site. - """ - distribRoot = resource.Resource() - distribRoot.putChild("child", child) - distribSite = server.Site(distribRoot) - self.f1 = distribFactory = PBServerFactory( - distrib.ResourcePublisher(distribSite)) - distribPort = reactor.listenTCP( - 0, distribFactory, interface="127.0.0.1") - self.addCleanup(distribPort.stopListening) - addr = distribPort.getHost() - - self.sub = mainRoot = distrib.ResourceSubscription( - addr.host, addr.port) - mainSite = server.Site(mainRoot) - mainPort = reactor.listenTCP(0, mainSite, interface="127.0.0.1") - self.addCleanup(mainPort.stopListening) - mainAddr = mainPort.getHost() - - return mainPort, mainAddr - - - def _requestTest(self, child, **kwargs): - """ - Set up a resource on a distrib site using L{ResourcePublisher} and - then retrieve it from a L{ResourceSubscription} via an HTTP client. - - @param child: The resource to publish using distrib. - @param **kwargs: Extra keyword arguments to pass to L{getPage} when - requesting the resource. - - @return: A L{Deferred} which fires with the result of the request. - """ - mainPort, mainAddr = self._setupDistribServer(child) - return client.getPage("http://%s:%s/child" % ( - mainAddr.host, mainAddr.port), **kwargs) - - - def _requestAgentTest(self, child, **kwargs): - """ - Set up a resource on a distrib site using L{ResourcePublisher} and - then retrieve it from a L{ResourceSubscription} via an HTTP client. - - @param child: The resource to publish using distrib. - @param **kwargs: Extra keyword arguments to pass to L{Agent.request} when - requesting the resource. - - @return: A L{Deferred} which fires with a tuple consisting of a - L{twisted.test.proto_helpers.AccumulatingProtocol} containing the - body of the response and an L{IResponse} with the response itself. - """ - mainPort, mainAddr = self._setupDistribServer(child) - - d = client.Agent(reactor).request("GET", "http://%s:%s/child" % ( - mainAddr.host, mainAddr.port), **kwargs) - - def cbCollectBody(response): - protocol = proto_helpers.AccumulatingProtocol() - response.deliverBody(protocol) - d = protocol.closedDeferred = defer.Deferred() - d.addCallback(lambda _: (protocol, response)) - return d - d.addCallback(cbCollectBody) - return d - - - def test_requestHeaders(self): - """ - The request headers are available on the request object passed to a - distributed resource's C{render} method. - """ - requestHeaders = {} - - class ReportRequestHeaders(resource.Resource): - def render(self, request): - requestHeaders.update(dict( - request.requestHeaders.getAllRawHeaders())) - return "" - - request = self._requestTest( - ReportRequestHeaders(), headers={'foo': 'bar'}) - def cbRequested(result): - self.assertEqual(requestHeaders['Foo'], ['bar']) - request.addCallback(cbRequested) - return request - - - def test_requestResponseCode(self): - """ - The response code can be set by the request object passed to a - distributed resource's C{render} method. - """ - class SetResponseCode(resource.Resource): - def render(self, request): - request.setResponseCode(200) - return "" - - request = self._requestAgentTest(SetResponseCode()) - def cbRequested(result): - self.assertEqual(result[0].data, "") - self.assertEqual(result[1].code, 200) - self.assertEqual(result[1].phrase, "OK") - request.addCallback(cbRequested) - return request - - - def test_requestResponseCodeMessage(self): - """ - The response code and message can be set by the request object passed to - a distributed resource's C{render} method. - """ - class SetResponseCode(resource.Resource): - def render(self, request): - request.setResponseCode(200, "some-message") - return "" - - request = self._requestAgentTest(SetResponseCode()) - def cbRequested(result): - self.assertEqual(result[0].data, "") - self.assertEqual(result[1].code, 200) - self.assertEqual(result[1].phrase, "some-message") - request.addCallback(cbRequested) - return request - - - def test_largeWrite(self): - """ - If a string longer than the Banana size limit is passed to the - L{distrib.Request} passed to the remote resource, it is broken into - smaller strings to be transported over the PB connection. - """ - class LargeWrite(resource.Resource): - def render(self, request): - request.write('x' * SIZE_LIMIT + 'y') - request.finish() - return server.NOT_DONE_YET - - request = self._requestTest(LargeWrite()) - request.addCallback(self.assertEqual, 'x' * SIZE_LIMIT + 'y') - return request - - - def test_largeReturn(self): - """ - Like L{test_largeWrite}, but for the case where C{render} returns a - long string rather than explicitly passing it to L{Request.write}. - """ - class LargeReturn(resource.Resource): - def render(self, request): - return 'x' * SIZE_LIMIT + 'y' - - request = self._requestTest(LargeReturn()) - request.addCallback(self.assertEqual, 'x' * SIZE_LIMIT + 'y') - return request - - - def test_connectionLost(self): - """ - If there is an error issuing the request to the remote publisher, an - error response is returned. - """ - # Using pb.Root as a publisher will cause request calls to fail with an - # error every time. Just what we want to test. - self.f1 = serverFactory = PBServerFactory(pb.Root()) - self.port1 = serverPort = reactor.listenTCP(0, serverFactory) - - self.sub = subscription = distrib.ResourceSubscription( - "127.0.0.1", serverPort.getHost().port) - request = DummyRequest(['']) - d = _render(subscription, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, 500) - # This is the error we caused the request to fail with. It should - # have been logged. - self.assertEqual(len(self.flushLoggedErrors(pb.NoSuchMethod)), 1) - d.addCallback(cbRendered) - return d - - - -class _PasswordDatabase: - def __init__(self, users): - self._users = users - - - def getpwall(self): - return iter(self._users) - - - def getpwnam(self, username): - for user in self._users: - if user[0] == username: - return user - raise KeyError() - - - -class UserDirectoryTests(unittest.TestCase): - """ - Tests for L{UserDirectory}, a resource for listing all user resources - available on a system. - """ - def setUp(self): - self.alice = ('alice', 'x', 123, 456, 'Alice,,,', self.mktemp(), '/bin/sh') - self.bob = ('bob', 'x', 234, 567, 'Bob,,,', self.mktemp(), '/bin/sh') - self.database = _PasswordDatabase([self.alice, self.bob]) - self.directory = distrib.UserDirectory(self.database) - - - def test_interface(self): - """ - L{UserDirectory} instances provide L{resource.IResource}. - """ - self.assertTrue(verifyObject(resource.IResource, self.directory)) - - - def _404Test(self, name): - """ - Verify that requesting the C{name} child of C{self.directory} results - in a 404 response. - """ - request = DummyRequest([name]) - result = self.directory.getChild(name, request) - d = _render(result, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, 404) - d.addCallback(cbRendered) - return d - - - def test_getInvalidUser(self): - """ - L{UserDirectory.getChild} returns a resource which renders a 404 - response when passed a string which does not correspond to any known - user. - """ - return self._404Test('carol') - - - def test_getUserWithoutResource(self): - """ - L{UserDirectory.getChild} returns a resource which renders a 404 - response when passed a string which corresponds to a known user who has - neither a user directory nor a user distrib socket. - """ - return self._404Test('alice') - - - def test_getPublicHTMLChild(self): - """ - L{UserDirectory.getChild} returns a L{static.File} instance when passed - the name of a user with a home directory containing a I{public_html} - directory. - """ - home = filepath.FilePath(self.bob[-2]) - public_html = home.child('public_html') - public_html.makedirs() - request = DummyRequest(['bob']) - result = self.directory.getChild('bob', request) - self.assertIsInstance(result, static.File) - self.assertEqual(result.path, public_html.path) - - - def test_getDistribChild(self): - """ - L{UserDirectory.getChild} returns a L{ResourceSubscription} instance - when passed the name of a user suffixed with C{".twistd"} who has a - home directory containing a I{.twistd-web-pb} socket. - """ - home = filepath.FilePath(self.bob[-2]) - home.makedirs() - web = home.child('.twistd-web-pb') - request = DummyRequest(['bob']) - result = self.directory.getChild('bob.twistd', request) - self.assertIsInstance(result, distrib.ResourceSubscription) - self.assertEqual(result.host, 'unix') - self.assertEqual(abspath(result.port), web.path) - - - def test_invalidMethod(self): - """ - L{UserDirectory.render} raises L{UnsupportedMethod} in response to a - non-I{GET} request. - """ - request = DummyRequest(['']) - request.method = 'POST' - self.assertRaises( - server.UnsupportedMethod, self.directory.render, request) - - - def test_render(self): - """ - L{UserDirectory} renders a list of links to available user content - in response to a I{GET} request. - """ - public_html = filepath.FilePath(self.alice[-2]).child('public_html') - public_html.makedirs() - web = filepath.FilePath(self.bob[-2]) - web.makedirs() - # This really only works if it's a unix socket, but the implementation - # doesn't currently check for that. It probably should someday, and - # then skip users with non-sockets. - web.child('.twistd-web-pb').setContent("") - - request = DummyRequest(['']) - result = _render(self.directory, request) - def cbRendered(ignored): - document = parseString(''.join(request.written)) - - # Each user should have an li with a link to their page. - [alice, bob] = document.getElementsByTagName('li') - self.assertEqual(alice.firstChild.tagName, 'a') - self.assertEqual(alice.firstChild.getAttribute('href'), 'alice/') - self.assertEqual(alice.firstChild.firstChild.data, 'Alice (file)') - self.assertEqual(bob.firstChild.tagName, 'a') - self.assertEqual(bob.firstChild.getAttribute('href'), 'bob.twistd/') - self.assertEqual(bob.firstChild.firstChild.data, 'Bob (twistd)') - - result.addCallback(cbRendered) - return result - - - def test_passwordDatabase(self): - """ - If L{UserDirectory} is instantiated with no arguments, it uses the - L{pwd} module as its password database. - """ - directory = distrib.UserDirectory() - self.assertIdentical(directory._pwd, pwd) - if pwd is None: - test_passwordDatabase.skip = "pwd module required" - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_domhelpers.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_domhelpers.py deleted file mode 100644 index b008374..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_domhelpers.py +++ /dev/null @@ -1,306 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_domhelpers -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Specific tests for (some of) the methods in L{twisted.web.domhelpers}. -""" - -from xml.dom import minidom - -from twisted.trial.unittest import TestCase - -from twisted.web import microdom - -from twisted.web import domhelpers - - -class DOMHelpersTestsMixin: - """ - A mixin for L{TestCase} subclasses which defines test methods for - domhelpers functionality based on a DOM creation function provided by a - subclass. - """ - dom = None - - def test_getElementsByTagName(self): - doc1 = self.dom.parseString('<foo/>') - actual=domhelpers.getElementsByTagName(doc1, 'foo')[0].nodeName - expected='foo' - self.assertEqual(actual, expected) - el1=doc1.documentElement - actual=domhelpers.getElementsByTagName(el1, 'foo')[0].nodeName - self.assertEqual(actual, expected) - - doc2_xml='<a><foo in="a"/><b><foo in="b"/></b><c><foo in="c"/></c><foo in="d"/><foo in="ef"/><g><foo in="g"/><h><foo in="h"/></h></g></a>' - doc2 = self.dom.parseString(doc2_xml) - tag_list=domhelpers.getElementsByTagName(doc2, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - expected='abcdefgh' - self.assertEqual(actual, expected) - el2=doc2.documentElement - tag_list=domhelpers.getElementsByTagName(el2, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - self.assertEqual(actual, expected) - - doc3_xml=''' -<a><foo in="a"/> - <b><foo in="b"/> - <d><foo in="d"/> - <g><foo in="g"/></g> - <h><foo in="h"/></h> - </d> - <e><foo in="e"/> - <i><foo in="i"/></i> - </e> - </b> - <c><foo in="c"/> - <f><foo in="f"/> - <j><foo in="j"/></j> - </f> - </c> -</a>''' - doc3 = self.dom.parseString(doc3_xml) - tag_list=domhelpers.getElementsByTagName(doc3, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - expected='abdgheicfj' - self.assertEqual(actual, expected) - el3=doc3.documentElement - tag_list=domhelpers.getElementsByTagName(el3, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - self.assertEqual(actual, expected) - - doc4_xml='<foo><bar></bar><baz><foo/></baz></foo>' - doc4 = self.dom.parseString(doc4_xml) - actual=domhelpers.getElementsByTagName(doc4, 'foo') - root=doc4.documentElement - expected=[root, root.childNodes[-1].childNodes[0]] - self.assertEqual(actual, expected) - actual=domhelpers.getElementsByTagName(root, 'foo') - self.assertEqual(actual, expected) - - - def test_gatherTextNodes(self): - doc1 = self.dom.parseString('<a>foo</a>') - actual=domhelpers.gatherTextNodes(doc1) - expected='foo' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc1.documentElement) - self.assertEqual(actual, expected) - - doc2_xml='<a>a<b>b</b><c>c</c>def<g>g<h>h</h></g></a>' - doc2 = self.dom.parseString(doc2_xml) - actual=domhelpers.gatherTextNodes(doc2) - expected='abcdefgh' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc2.documentElement) - self.assertEqual(actual, expected) - - doc3_xml=('<a>a<b>b<d>d<g>g</g><h>h</h></d><e>e<i>i</i></e></b>' + - '<c>c<f>f<j>j</j></f></c></a>') - doc3 = self.dom.parseString(doc3_xml) - actual=domhelpers.gatherTextNodes(doc3) - expected='abdgheicfj' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc3.documentElement) - self.assertEqual(actual, expected) - - def test_clearNode(self): - doc1 = self.dom.parseString('<a><b><c><d/></c></b></a>') - a_node=doc1.documentElement - domhelpers.clearNode(a_node) - self.assertEqual( - a_node.toxml(), - self.dom.Element('a').toxml()) - - doc2 = self.dom.parseString('<a><b><c><d/></c></b></a>') - b_node=doc2.documentElement.childNodes[0] - domhelpers.clearNode(b_node) - actual=doc2.documentElement.toxml() - expected = self.dom.Element('a') - expected.appendChild(self.dom.Element('b')) - self.assertEqual(actual, expected.toxml()) - - - def test_get(self): - doc1 = self.dom.parseString('<a><b id="bar"/><c class="foo"/></a>') - node=domhelpers.get(doc1, "foo") - actual=node.toxml() - expected = self.dom.Element('c') - expected.setAttribute('class', 'foo') - self.assertEqual(actual, expected.toxml()) - - node=domhelpers.get(doc1, "bar") - actual=node.toxml() - expected = self.dom.Element('b') - expected.setAttribute('id', 'bar') - self.assertEqual(actual, expected.toxml()) - - self.assertRaises(domhelpers.NodeLookupError, - domhelpers.get, - doc1, - "pzork") - - def test_getIfExists(self): - doc1 = self.dom.parseString('<a><b id="bar"/><c class="foo"/></a>') - node=domhelpers.getIfExists(doc1, "foo") - actual=node.toxml() - expected = self.dom.Element('c') - expected.setAttribute('class', 'foo') - self.assertEqual(actual, expected.toxml()) - - node=domhelpers.getIfExists(doc1, "pzork") - self.assertIdentical(node, None) - - - def test_getAndClear(self): - doc1 = self.dom.parseString('<a><b id="foo"><c></c></b></a>') - node=domhelpers.getAndClear(doc1, "foo") - actual=node.toxml() - expected = self.dom.Element('b') - expected.setAttribute('id', 'foo') - self.assertEqual(actual, expected.toxml()) - - - def test_locateNodes(self): - doc1 = self.dom.parseString('<a><b foo="olive"><c foo="olive"/></b><d foo="poopy"/></a>') - node_list=domhelpers.locateNodes( - doc1.childNodes, 'foo', 'olive', noNesting=1) - actual=''.join([node.toxml() for node in node_list]) - expected = self.dom.Element('b') - expected.setAttribute('foo', 'olive') - c = self.dom.Element('c') - c.setAttribute('foo', 'olive') - expected.appendChild(c) - - self.assertEqual(actual, expected.toxml()) - - node_list=domhelpers.locateNodes( - doc1.childNodes, 'foo', 'olive', noNesting=0) - actual=''.join([node.toxml() for node in node_list]) - self.assertEqual(actual, expected.toxml() + c.toxml()) - - - def test_getParents(self): - doc1 = self.dom.parseString('<a><b><c><d/></c><e/></b><f/></a>') - node_list = domhelpers.getParents( - doc1.childNodes[0].childNodes[0].childNodes[0]) - actual = ''.join([node.tagName for node in node_list - if hasattr(node, 'tagName')]) - self.assertEqual(actual, 'cba') - - - def test_findElementsWithAttribute(self): - doc1 = self.dom.parseString('<a foo="1"><b foo="2"/><c foo="1"/><d/></a>') - node_list = domhelpers.findElementsWithAttribute(doc1, 'foo') - actual = ''.join([node.tagName for node in node_list]) - self.assertEqual(actual, 'abc') - - node_list = domhelpers.findElementsWithAttribute(doc1, 'foo', '1') - actual = ''.join([node.tagName for node in node_list]) - self.assertEqual(actual, 'ac') - - - def test_findNodesNamed(self): - doc1 = self.dom.parseString('<doc><foo/><bar/><foo>a</foo></doc>') - node_list = domhelpers.findNodesNamed(doc1, 'foo') - actual = len(node_list) - self.assertEqual(actual, 2) - - # NOT SURE WHAT THESE ARE SUPPOSED TO DO.. - # def test_RawText FIXME - # def test_superSetAttribute FIXME - # def test_superPrependAttribute FIXME - # def test_superAppendAttribute FIXME - # def test_substitute FIXME - - def test_escape(self): - j='this string " contains many & characters> xml< won\'t like' - expected='this string &quot; contains many &amp; characters&gt; xml&lt; won\'t like' - self.assertEqual(domhelpers.escape(j), expected) - - def test_unescape(self): - j='this string &quot; has &&amp; entities &gt; &lt; and some characters xml won\'t like<' - expected='this string " has && entities > < and some characters xml won\'t like<' - self.assertEqual(domhelpers.unescape(j), expected) - - - def test_getNodeText(self): - """ - L{getNodeText} returns the concatenation of all the text data at or - beneath the node passed to it. - """ - node = self.dom.parseString('<foo><bar>baz</bar><bar>quux</bar></foo>') - self.assertEqual(domhelpers.getNodeText(node), "bazquux") - - - -class MicroDOMHelpersTests(DOMHelpersTestsMixin, TestCase): - dom = microdom - - def test_gatherTextNodesDropsWhitespace(self): - """ - Microdom discards whitespace-only text nodes, so L{gatherTextNodes} - returns only the text from nodes which had non-whitespace characters. - """ - doc4_xml='''<html> - <head> - </head> - <body> - stuff - </body> -</html> -''' - doc4 = self.dom.parseString(doc4_xml) - actual = domhelpers.gatherTextNodes(doc4) - expected = '\n stuff\n ' - self.assertEqual(actual, expected) - actual = domhelpers.gatherTextNodes(doc4.documentElement) - self.assertEqual(actual, expected) - - - def test_textEntitiesNotDecoded(self): - """ - Microdom does not decode entities in text nodes. - """ - doc5_xml='<x>Souffl&amp;</x>' - doc5 = self.dom.parseString(doc5_xml) - actual=domhelpers.gatherTextNodes(doc5) - expected='Souffl&amp;' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc5.documentElement) - self.assertEqual(actual, expected) - - - -class MiniDOMHelpersTests(DOMHelpersTestsMixin, TestCase): - dom = minidom - - def test_textEntitiesDecoded(self): - """ - Minidom does decode entities in text nodes. - """ - doc5_xml='<x>Souffl&amp;</x>' - doc5 = self.dom.parseString(doc5_xml) - actual=domhelpers.gatherTextNodes(doc5) - expected='Souffl&' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc5.documentElement) - self.assertEqual(actual, expected) - - - def test_getNodeUnicodeText(self): - """ - L{domhelpers.getNodeText} returns a C{unicode} string when text - nodes are represented in the DOM with unicode, whether or not there - are non-ASCII characters present. - """ - node = self.dom.parseString("<foo>bar</foo>") - text = domhelpers.getNodeText(node) - self.assertEqual(text, u"bar") - self.assertIsInstance(text, unicode) - - node = self.dom.parseString(u"<foo>\N{SNOWMAN}</foo>".encode('utf-8')) - text = domhelpers.getNodeText(node) - self.assertEqual(text, u"\N{SNOWMAN}") - self.assertIsInstance(text, unicode) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_error.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_error.py deleted file mode 100644 index 12d625e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_error.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -HTTP errors. -""" - -from twisted.trial import unittest -from twisted.web import error - -class ErrorTests(unittest.TestCase): - """ - Tests for how L{Error} attributes are initialized. - """ - def test_noMessageValidStatus(self): - """ - If no C{message} argument is passed to the L{Error} constructor and the - C{code} argument is a valid HTTP status code, C{code} is mapped to a - descriptive string to which C{message} is assigned. - """ - e = error.Error("200") - self.assertEqual(e.message, "OK") - - - def test_noMessageInvalidStatus(self): - """ - If no C{message} argument is passed to the L{Error} constructor and - C{code} isn't a valid HTTP status code, C{message} stays C{None}. - """ - e = error.Error("InvalidCode") - self.assertEqual(e.message, None) - - - def test_messageExists(self): - """ - If a C{message} argument is passed to the L{Error} constructor, the - C{message} isn't affected by the value of C{status}. - """ - e = error.Error("200", "My own message") - self.assertEqual(e.message, "My own message") - - - -class PageRedirectTests(unittest.TestCase): - """ - Tests for how L{PageRedirect} attributes are initialized. - """ - def test_noMessageValidStatus(self): - """ - If no C{message} argument is passed to the L{PageRedirect} constructor - and the C{code} argument is a valid HTTP status code, C{code} is mapped - to a descriptive string to which C{message} is assigned. - """ - e = error.PageRedirect("200", location="/foo") - self.assertEqual(e.message, "OK to /foo") - - - def test_noMessageValidStatusNoLocation(self): - """ - If no C{message} argument is passed to the L{PageRedirect} constructor - and C{location} is also empty and the C{code} argument is a valid HTTP - status code, C{code} is mapped to a descriptive string to which - C{message} is assigned without trying to include an empty location. - """ - e = error.PageRedirect("200") - self.assertEqual(e.message, "OK") - - - def test_noMessageInvalidStatusLocationExists(self): - """ - If no C{message} argument is passed to the L{PageRedirect} constructor - and C{code} isn't a valid HTTP status code, C{message} stays C{None}. - """ - e = error.PageRedirect("InvalidCode", location="/foo") - self.assertEqual(e.message, None) - - - def test_messageExistsLocationExists(self): - """ - If a C{message} argument is passed to the L{PageRedirect} constructor, - the C{message} isn't affected by the value of C{status}. - """ - e = error.PageRedirect("200", "My own message", location="/foo") - self.assertEqual(e.message, "My own message to /foo") - - - def test_messageExistsNoLocation(self): - """ - If a C{message} argument is passed to the L{PageRedirect} constructor - and no location is provided, C{message} doesn't try to include the empty - location. - """ - e = error.PageRedirect("200", "My own message") - self.assertEqual(e.message, "My own message") - - - -class InfiniteRedirectionTests(unittest.TestCase): - """ - Tests for how L{InfiniteRedirection} attributes are initialized. - """ - def test_noMessageValidStatus(self): - """ - If no C{message} argument is passed to the L{InfiniteRedirection} - constructor and the C{code} argument is a valid HTTP status code, - C{code} is mapped to a descriptive string to which C{message} is - assigned. - """ - e = error.InfiniteRedirection("200", location="/foo") - self.assertEqual(e.message, "OK to /foo") - - - def test_noMessageValidStatusNoLocation(self): - """ - If no C{message} argument is passed to the L{InfiniteRedirection} - constructor and C{location} is also empty and the C{code} argument is a - valid HTTP status code, C{code} is mapped to a descriptive string to - which C{message} is assigned without trying to include an empty - location. - """ - e = error.InfiniteRedirection("200") - self.assertEqual(e.message, "OK") - - - def test_noMessageInvalidStatusLocationExists(self): - """ - If no C{message} argument is passed to the L{InfiniteRedirection} - constructor and C{code} isn't a valid HTTP status code, C{message} stays - C{None}. - """ - e = error.InfiniteRedirection("InvalidCode", location="/foo") - self.assertEqual(e.message, None) - - - def test_messageExistsLocationExists(self): - """ - If a C{message} argument is passed to the L{InfiniteRedirection} - constructor, the C{message} isn't affected by the value of C{status}. - """ - e = error.InfiniteRedirection("200", "My own message", location="/foo") - self.assertEqual(e.message, "My own message to /foo") - - - def test_messageExistsNoLocation(self): - """ - If a C{message} argument is passed to the L{InfiniteRedirection} - constructor and no location is provided, C{message} doesn't try to - include the empty location. - """ - e = error.InfiniteRedirection("200", "My own message") - self.assertEqual(e.message, "My own message") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_flatten.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_flatten.py deleted file mode 100644 index 7c307e0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_flatten.py +++ /dev/null @@ -1,554 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for the flattening portion of L{twisted.web.template}, implemented in -L{twisted.web._flatten}. -""" - -import sys -import traceback - -from xml.etree.cElementTree import XML - -from zope.interface import implements, implementer - -from twisted.trial.unittest import TestCase -from twisted.test.testutils import XMLAssertionMixin - -from twisted.internet.defer import passthru, succeed, gatherResults - -from twisted.web.iweb import IRenderable -from twisted.web.error import UnfilledSlot, UnsupportedType, FlattenerError - -from twisted.web.template import tags, Tag, Comment, CDATA, CharRef, slot -from twisted.web.template import Element, renderer, TagLoader, flattenString - -from twisted.web.test._util import FlattenTestCase - - - -class OrderedAttributes(object): - """ - An L{OrderedAttributes} is a stand-in for the L{Tag.attributes} dictionary - that orders things in a deterministic order. It doesn't do any sorting, so - whatever order the attributes are passed in, they will be returned. - - @ivar attributes: The result of a L{dict}C{.items} call. - @type attributes: L{list} of 2-L{tuples} - """ - - def __init__(self, attributes): - self.attributes = attributes - - - def iteritems(self): - """ - Like L{dict}C{.iteritems}. - - @return: an iterator - @rtype: list iterator - """ - return iter(self.attributes) - - - -class SerializationTests(FlattenTestCase, XMLAssertionMixin): - """ - Tests for flattening various things. - """ - def test_nestedTags(self): - """ - Test that nested tags flatten correctly. - """ - return self.assertFlattensTo( - tags.html(tags.body('42'), hi='there'), - '<html hi="there"><body>42</body></html>') - - - def test_serializeString(self): - """ - Test that strings will be flattened and escaped correctly. - """ - return gatherResults([ - self.assertFlattensTo('one', 'one'), - self.assertFlattensTo('<abc&&>123', '&lt;abc&amp;&amp;&gt;123'), - ]) - - - def test_serializeSelfClosingTags(self): - """ - The serialized form of a self-closing tag is C{'<tagName />'}. - """ - return self.assertFlattensTo(tags.img(), '<img />') - - - def test_serializeAttribute(self): - """ - The serialized form of attribute I{a} with value I{b} is C{'a="b"'}. - """ - self.assertFlattensImmediately(tags.img(src='foo'), - '<img src="foo" />') - - - def test_serializedMultipleAttributes(self): - """ - Multiple attributes are separated by a single space in their serialized - form. - """ - tag = tags.img() - tag.attributes = OrderedAttributes([("src", "foo"), ("name", "bar")]) - self.assertFlattensImmediately(tag, '<img src="foo" name="bar" />') - - - def checkAttributeSanitization(self, wrapData, wrapTag): - """ - Common implementation of L{test_serializedAttributeWithSanitization} - and L{test_serializedDeferredAttributeWithSanitization}, - L{test_serializedAttributeWithTransparentTag}. - - @param wrapData: A 1-argument callable that wraps around the - attribute's value so other tests can customize it. - @param wrapData: callable taking L{bytes} and returning something - flattenable - - @param wrapTag: A 1-argument callable that wraps around the outer tag - so other tests can customize it. - @type wrapTag: callable taking L{Tag} and returning L{Tag}. - """ - self.assertFlattensImmediately( - wrapTag(tags.img(src=wrapData("<>&\""))), - '<img src="&lt;&gt;&amp;&quot;" />') - - - def test_serializedAttributeWithSanitization(self): - """ - Attribute values containing C{"<"}, C{">"}, C{"&"}, or C{'"'} have - C{"&lt;"}, C{"&gt;"}, C{"&amp;"}, or C{"&quot;"} substituted for those - bytes in the serialized output. - """ - self.checkAttributeSanitization(passthru, passthru) - - - def test_serializedDeferredAttributeWithSanitization(self): - """ - Like L{test_serializedAttributeWithSanitization}, but when the contents - of the attribute are in a L{Deferred - <twisted.internet.defer.Deferred>}. - """ - self.checkAttributeSanitization(succeed, passthru) - - - def test_serializedAttributeWithSlotWithSanitization(self): - """ - Like L{test_serializedAttributeWithSanitization} but with a slot. - """ - toss = [] - self.checkAttributeSanitization( - lambda value: toss.append(value) or slot("stuff"), - lambda tag: tag.fillSlots(stuff=toss.pop()) - ) - - - def test_serializedAttributeWithTransparentTag(self): - """ - Attribute values which are supplied via the value of a C{t:transparent} - tag have the same substitution rules to them as values supplied - directly. - """ - self.checkAttributeSanitization(tags.transparent, passthru) - - - def test_serializedAttributeWithTransparentTagWithRenderer(self): - """ - Like L{test_serializedAttributeWithTransparentTag}, but when the - attribute is rendered by a renderer on an element. - """ - class WithRenderer(Element): - def __init__(self, value, loader): - self.value = value - super(WithRenderer, self).__init__(loader) - @renderer - def stuff(self, request, tag): - return self.value - toss = [] - self.checkAttributeSanitization( - lambda value: toss.append(value) or - tags.transparent(render="stuff"), - lambda tag: WithRenderer(toss.pop(), TagLoader(tag)) - ) - - - def test_serializedAttributeWithRenderable(self): - """ - Like L{test_serializedAttributeWithTransparentTag}, but when the - attribute is a provider of L{IRenderable} rather than a transparent - tag. - """ - @implementer(IRenderable) - class Arbitrary(object): - def __init__(self, value): - self.value = value - def render(self, request): - return self.value - self.checkAttributeSanitization(Arbitrary, passthru) - - - def checkTagAttributeSerialization(self, wrapTag): - """ - Common implementation of L{test_serializedAttributeWithTag} and - L{test_serializedAttributeWithDeferredTag}. - - @param wrapTag: A 1-argument callable that wraps around the attribute's - value so other tests can customize it. - @param wrapTag: callable taking L{Tag} and returning something - flattenable - """ - innerTag = tags.a('<>&"') - outerTag = tags.img(src=wrapTag(innerTag)) - outer = self.assertFlattensImmediately( - outerTag, - '<img src="&lt;a&gt;&amp;lt;&amp;gt;&amp;amp;&quot;&lt;/a&gt;" />') - inner = self.assertFlattensImmediately( - innerTag, '<a>&lt;&gt;&amp;"</a>') - - # Since the above quoting is somewhat tricky, validate it by making sure - # that the main use-case for tag-within-attribute is supported here: if - # we serialize a tag, it is quoted *such that it can be parsed out again - # as a tag*. - self.assertXMLEqual(XML(outer).attrib['src'], inner) - - - def test_serializedAttributeWithTag(self): - """ - L{Tag} objects which are serialized within the context of an attribute - are serialized such that the text content of the attribute may be - parsed to retrieve the tag. - """ - self.checkTagAttributeSerialization(passthru) - - - def test_serializedAttributeWithDeferredTag(self): - """ - Like L{test_serializedAttributeWithTag}, but when the L{Tag} is in a - L{Deferred <twisted.internet.defer.Deferred>}. - """ - self.checkTagAttributeSerialization(succeed) - - - def test_serializedAttributeWithTagWithAttribute(self): - """ - Similar to L{test_serializedAttributeWithTag}, but for the additional - complexity where the tag which is the attribute value itself has an - attribute value which contains bytes which require substitution. - """ - flattened = self.assertFlattensImmediately( - tags.img(src=tags.a(href='<>&"')), - '<img src="&lt;a href=' - '&quot;&amp;lt;&amp;gt;&amp;amp;&amp;quot;&quot;&gt;' - '&lt;/a&gt;" />') - - # As in checkTagAttributeSerialization, belt-and-suspenders: - self.assertXMLEqual(XML(flattened).attrib['src'], - '<a href="&lt;&gt;&amp;&quot;"></a>') - - - def test_serializeComment(self): - """ - Test that comments are correctly flattened and escaped. - """ - return self.assertFlattensTo(Comment('foo bar'), '<!--foo bar-->'), - - - def test_commentEscaping(self): - """ - The data in a L{Comment} is escaped and mangled in the flattened output - so that the result is a legal SGML and XML comment. - - SGML comment syntax is complicated and hard to use. This rule is more - restrictive, and more compatible: - - Comments start with <!-- and end with --> and never contain -- or >. - - Also by XML syntax, a comment may not end with '-'. - - @see: U{http://www.w3.org/TR/REC-xml/#sec-comments} - """ - def verifyComment(c): - self.assertTrue( - c.startswith('<!--'), - "%r does not start with the comment prefix" % (c,)) - self.assertTrue( - c.endswith('-->'), - "%r does not end with the comment suffix" % (c,)) - # If it is shorter than 7, then the prefix and suffix overlap - # illegally. - self.assertTrue( - len(c) >= 7, - "%r is too short to be a legal comment" % (c,)) - content = c[4:-3] - self.assertNotIn('--', content) - self.assertNotIn('>', content) - if content: - self.assertNotEqual(content[-1], '-') - - results = [] - for c in [ - '', - 'foo---bar', - 'foo---bar-', - 'foo>bar', - 'foo-->bar', - '----------------', - ]: - d = flattenString(None, Comment(c)) - d.addCallback(verifyComment) - results.append(d) - return gatherResults(results) - - - def test_serializeCDATA(self): - """ - Test that CDATA is correctly flattened and escaped. - """ - return gatherResults([ - self.assertFlattensTo(CDATA('foo bar'), '<![CDATA[foo bar]]>'), - self.assertFlattensTo( - CDATA('foo ]]> bar'), - '<![CDATA[foo ]]]]><![CDATA[> bar]]>'), - ]) - - - def test_serializeUnicode(self): - """ - Test that unicode is encoded correctly in the appropriate places, and - raises an error when it occurs in inappropriate place. - """ - snowman = u'\N{SNOWMAN}' - return gatherResults([ - self.assertFlattensTo(snowman, '\xe2\x98\x83'), - self.assertFlattensTo(tags.p(snowman), '<p>\xe2\x98\x83</p>'), - self.assertFlattensTo(Comment(snowman), '<!--\xe2\x98\x83-->'), - self.assertFlattensTo(CDATA(snowman), '<![CDATA[\xe2\x98\x83]]>'), - self.assertFlatteningRaises( - Tag(snowman), UnicodeEncodeError), - self.assertFlatteningRaises( - Tag('p', attributes={snowman: ''}), UnicodeEncodeError), - ]) - - - def test_serializeCharRef(self): - """ - A character reference is flattened to a string using the I{&#NNNN;} - syntax. - """ - ref = CharRef(ord(u"\N{SNOWMAN}")) - return self.assertFlattensTo(ref, "&#9731;") - - - def test_serializeDeferred(self): - """ - Test that a deferred is substituted with the current value in the - callback chain when flattened. - """ - return self.assertFlattensTo(succeed('two'), 'two') - - - def test_serializeSameDeferredTwice(self): - """ - Test that the same deferred can be flattened twice. - """ - d = succeed('three') - return gatherResults([ - self.assertFlattensTo(d, 'three'), - self.assertFlattensTo(d, 'three'), - ]) - - - def test_serializeIRenderable(self): - """ - Test that flattening respects all of the IRenderable interface. - """ - class FakeElement(object): - implements(IRenderable) - def render(ign,ored): - return tags.p( - 'hello, ', - tags.transparent(render='test'), ' - ', - tags.transparent(render='test')) - def lookupRenderMethod(ign, name): - self.assertEqual(name, 'test') - return lambda ign, node: node('world') - - return gatherResults([ - self.assertFlattensTo(FakeElement(), '<p>hello, world - world</p>'), - ]) - - - def test_serializeSlots(self): - """ - Test that flattening a slot will use the slot value from the tag. - """ - t1 = tags.p(slot('test')) - t2 = t1.clone() - t2.fillSlots(test='hello, world') - return gatherResults([ - self.assertFlatteningRaises(t1, UnfilledSlot), - self.assertFlattensTo(t2, '<p>hello, world</p>'), - ]) - - - def test_serializeDeferredSlots(self): - """ - Test that a slot with a deferred as its value will be flattened using - the value from the deferred. - """ - t = tags.p(slot('test')) - t.fillSlots(test=succeed(tags.em('four>'))) - return self.assertFlattensTo(t, '<p><em>four&gt;</em></p>') - - - def test_unknownTypeRaises(self): - """ - Test that flattening an unknown type of thing raises an exception. - """ - return self.assertFlatteningRaises(None, UnsupportedType) - - -# Use the co_filename mechanism (instead of the __file__ mechanism) because -# it is the mechanism traceback formatting uses. The two do not necessarily -# agree with each other. This requires a code object compiled in this file. -# The easiest way to get a code object is with a new function. I'll use a -# lambda to avoid adding anything else to this namespace. The result will -# be a string which agrees with the one the traceback module will put into a -# traceback for frames associated with functions defined in this file. - -HERE = (lambda: None).func_code.co_filename - - -class FlattenerErrorTests(TestCase): - """ - Tests for L{FlattenerError}. - """ - - def test_string(self): - """ - If a L{FlattenerError} is created with a string root, up to around 40 - bytes from that string are included in the string representation of the - exception. - """ - self.assertEqual( - str(FlattenerError(RuntimeError("reason"), ['abc123xyz'], [])), - "Exception while flattening:\n" - " 'abc123xyz'\n" - "RuntimeError: reason\n") - self.assertEqual( - str(FlattenerError( - RuntimeError("reason"), ['0123456789' * 10], [])), - "Exception while flattening:\n" - " '01234567890123456789<...>01234567890123456789'\n" - "RuntimeError: reason\n") - - - def test_unicode(self): - """ - If a L{FlattenerError} is created with a unicode root, up to around 40 - characters from that string are included in the string representation - of the exception. - """ - self.assertEqual( - str(FlattenerError( - RuntimeError("reason"), [u'abc\N{SNOWMAN}xyz'], [])), - "Exception while flattening:\n" - " u'abc\\u2603xyz'\n" # Codepoint for SNOWMAN - "RuntimeError: reason\n") - self.assertEqual( - str(FlattenerError( - RuntimeError("reason"), [u'01234567\N{SNOWMAN}9' * 10], - [])), - "Exception while flattening:\n" - " u'01234567\\u2603901234567\\u26039<...>01234567\\u2603901234567" - "\\u26039'\n" - "RuntimeError: reason\n") - - - def test_renderable(self): - """ - If a L{FlattenerError} is created with an L{IRenderable} provider root, - the repr of that object is included in the string representation of the - exception. - """ - class Renderable(object): - implements(IRenderable) - - def __repr__(self): - return "renderable repr" - - self.assertEqual( - str(FlattenerError( - RuntimeError("reason"), [Renderable()], [])), - "Exception while flattening:\n" - " renderable repr\n" - "RuntimeError: reason\n") - - - def test_tag(self): - """ - If a L{FlattenerError} is created with a L{Tag} instance with source - location information, the source location is included in the string - representation of the exception. - """ - tag = Tag( - 'div', filename='/foo/filename.xhtml', lineNumber=17, columnNumber=12) - - self.assertEqual( - str(FlattenerError(RuntimeError("reason"), [tag], [])), - "Exception while flattening:\n" - " File \"/foo/filename.xhtml\", line 17, column 12, in \"div\"\n" - "RuntimeError: reason\n") - - - def test_tagWithoutLocation(self): - """ - If a L{FlattenerError} is created with a L{Tag} instance without source - location information, only the tagName is included in the string - representation of the exception. - """ - self.assertEqual( - str(FlattenerError(RuntimeError("reason"), [Tag('span')], [])), - "Exception while flattening:\n" - " Tag <span>\n" - "RuntimeError: reason\n") - - - def test_traceback(self): - """ - If a L{FlattenerError} is created with traceback frames, they are - included in the string representation of the exception. - """ - # Try to be realistic in creating the data passed in for the traceback - # frames. - def f(): - g() - def g(): - raise RuntimeError("reason") - - try: - f() - except RuntimeError, exc: - # Get the traceback, minus the info for *this* frame - tbinfo = traceback.extract_tb(sys.exc_info()[2])[1:] - else: - self.fail("f() must raise RuntimeError") - - self.assertEqual( - str(FlattenerError(exc, [], tbinfo)), - "Exception while flattening:\n" - " File \"%s\", line %d, in f\n" - " g()\n" - " File \"%s\", line %d, in g\n" - " raise RuntimeError(\"reason\")\n" - "RuntimeError: reason\n" % ( - HERE, f.func_code.co_firstlineno + 1, - HERE, g.func_code.co_firstlineno + 1)) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_http.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_http.py deleted file mode 100644 index c23937e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_http.py +++ /dev/null @@ -1,2296 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test HTTP support. -""" - -import random, cgi, base64 - -try: - from urlparse import urlparse, urlunsplit, clear_cache -except ImportError: - from urllib.parse import urlparse, urlunsplit, clear_cache - -from twisted.python.compat import _PY3, iterbytes, networkString, unicode, intToBytes -from twisted.python.failure import Failure -from twisted.trial import unittest -from twisted.trial.unittest import TestCase -from twisted.web import http, http_headers -from twisted.web.http import PotentialDataLoss, _DataLoss -from twisted.web.http import _IdentityTransferDecoder -from twisted.internet.task import Clock -from twisted.internet.error import ConnectionLost -from twisted.protocols import loopback -from twisted.test.proto_helpers import StringTransport -from twisted.test.test_internet import DummyProducer -from twisted.web.test.requesthelper import DummyChannel - - - -class DateTimeTests(unittest.TestCase): - """Test date parsing functions.""" - - def testRoundtrip(self): - for i in range(10000): - time = random.randint(0, 2000000000) - timestr = http.datetimeToString(time) - time2 = http.stringToDatetime(timestr) - self.assertEqual(time, time2) - - -class DummyHTTPHandler(http.Request): - - def process(self): - self.content.seek(0, 0) - data = self.content.read() - length = self.getHeader(b'content-length') - if length is None: - length = networkString(str(length)) - request = b"'''\n" + length + b"\n" + data + b"'''\n" - self.setResponseCode(200) - self.setHeader(b"Request", self.uri) - self.setHeader(b"Command", self.method) - self.setHeader(b"Version", self.clientproto) - self.setHeader(b"Content-Length", intToBytes(len(request))) - self.write(request) - self.finish() - - -class LoopbackHTTPClient(http.HTTPClient): - - def connectionMade(self): - self.sendCommand(b"GET", b"/foo/bar") - self.sendHeader(b"Content-Length", 10) - self.endHeaders() - self.transport.write(b"0123456789") - - -class ResponseTestMixin(object): - """ - A mixin that provides a simple means of comparing an actual response string - to an expected response string by performing the minimal parsing. - """ - - def assertResponseEquals(self, responses, expected): - """ - Assert that the C{responses} matches the C{expected} responses. - - @type responses: C{bytes} - @param responses: The bytes sent in response to one or more requests. - - @type expected: C{list} of C{tuple} of C{bytes} - @param expected: The expected values for the responses. Each tuple - element of the list represents one response. Each byte string - element of the tuple is a full header line without delimiter, except - for the last element which gives the full response body. - """ - for response in expected: - expectedHeaders, expectedContent = response[:-1], response[-1] - # Intentionally avoid mutating the inputs here. - expectedStatus = expectedHeaders[0] - expectedHeaders = expectedHeaders[1:] - - headers, rest = responses.split(b'\r\n\r\n', 1) - headers = headers.splitlines() - status = headers.pop(0) - - self.assertEqual(expectedStatus, status) - self.assertEqual(set(headers), set(expectedHeaders)) - content = rest[:len(expectedContent)] - responses = rest[len(expectedContent):] - self.assertEqual(content, expectedContent) - - - -class HTTP1_0Tests(unittest.TestCase, ResponseTestMixin): - requests = ( - b"GET / HTTP/1.0\r\n" - b"\r\n" - b"GET / HTTP/1.1\r\n" - b"Accept: text/html\r\n" - b"\r\n") - - expected_response = [ - (b"HTTP/1.0 200 OK", - b"Request: /", - b"Command: GET", - b"Version: HTTP/1.0", - b"Content-Length: 13", - b"'''\nNone\n'''\n")] - - def test_buffer(self): - """ - Send requests over a channel and check responses match what is expected. - """ - b = StringTransport() - a = http.HTTPChannel() - a.requestFactory = DummyHTTPHandler - a.makeConnection(b) - # one byte at a time, to stress it. - for byte in iterbytes(self.requests): - a.dataReceived(byte) - a.connectionLost(IOError("all one")) - value = b.value() - self.assertResponseEquals(value, self.expected_response) - - - def test_requestBodyTimeout(self): - """ - L{HTTPChannel} resets its timeout whenever data from a request body is - delivered to it. - """ - clock = Clock() - transport = StringTransport() - protocol = http.HTTPChannel() - protocol.timeOut = 100 - protocol.callLater = clock.callLater - protocol.makeConnection(transport) - protocol.dataReceived(b'POST / HTTP/1.0\r\nContent-Length: 2\r\n\r\n') - clock.advance(99) - self.assertFalse(transport.disconnecting) - protocol.dataReceived(b'x') - clock.advance(99) - self.assertFalse(transport.disconnecting) - protocol.dataReceived(b'x') - self.assertEqual(len(protocol.requests), 1) - - - -class HTTP1_1Tests(HTTP1_0Tests): - - requests = ( - b"GET / HTTP/1.1\r\n" - b"Accept: text/html\r\n" - b"\r\n" - b"POST / HTTP/1.1\r\n" - b"Content-Length: 10\r\n" - b"\r\n" - b"0123456789POST / HTTP/1.1\r\n" - b"Content-Length: 10\r\n" - b"\r\n" - b"0123456789HEAD / HTTP/1.1\r\n" - b"\r\n") - - expected_response = [ - (b"HTTP/1.1 200 OK", - b"Request: /", - b"Command: GET", - b"Version: HTTP/1.1", - b"Content-Length: 13", - b"'''\nNone\n'''\n"), - (b"HTTP/1.1 200 OK", - b"Request: /", - b"Command: POST", - b"Version: HTTP/1.1", - b"Content-Length: 21", - b"'''\n10\n0123456789'''\n"), - (b"HTTP/1.1 200 OK", - b"Request: /", - b"Command: POST", - b"Version: HTTP/1.1", - b"Content-Length: 21", - b"'''\n10\n0123456789'''\n"), - (b"HTTP/1.1 200 OK", - b"Request: /", - b"Command: HEAD", - b"Version: HTTP/1.1", - b"Content-Length: 13", - b"")] - - - -class HTTP1_1_close_Tests(HTTP1_0Tests): - - requests = ( - b"GET / HTTP/1.1\r\n" - b"Accept: text/html\r\n" - b"Connection: close\r\n" - b"\r\n" - b"GET / HTTP/1.0\r\n" - b"\r\n") - - expected_response = [ - (b"HTTP/1.1 200 OK", - b"Connection: close", - b"Request: /", - b"Command: GET", - b"Version: HTTP/1.1", - b"Content-Length: 13", - b"'''\nNone\n'''\n")] - - - -class HTTP0_9Tests(HTTP1_0Tests): - - requests = ( - b"GET /\r\n") - - expected_response = b"HTTP/1.1 400 Bad Request\r\n\r\n" - - - def assertResponseEquals(self, response, expectedResponse): - self.assertEqual(response, expectedResponse) - - -class HTTPLoopbackTests(unittest.TestCase): - - expectedHeaders = {b'request': b'/foo/bar', - b'command': b'GET', - b'version': b'HTTP/1.0', - b'content-length': b'21'} - numHeaders = 0 - gotStatus = 0 - gotResponse = 0 - gotEndHeaders = 0 - - def _handleStatus(self, version, status, message): - self.gotStatus = 1 - self.assertEqual(version, b"HTTP/1.0") - self.assertEqual(status, b"200") - - def _handleResponse(self, data): - self.gotResponse = 1 - self.assertEqual(data, b"'''\n10\n0123456789'''\n") - - def _handleHeader(self, key, value): - self.numHeaders = self.numHeaders + 1 - self.assertEqual(self.expectedHeaders[key.lower()], value) - - def _handleEndHeaders(self): - self.gotEndHeaders = 1 - self.assertEqual(self.numHeaders, 4) - - def testLoopback(self): - server = http.HTTPChannel() - server.requestFactory = DummyHTTPHandler - client = LoopbackHTTPClient() - client.handleResponse = self._handleResponse - client.handleHeader = self._handleHeader - client.handleEndHeaders = self._handleEndHeaders - client.handleStatus = self._handleStatus - d = loopback.loopbackAsync(server, client) - d.addCallback(self._cbTestLoopback) - return d - - def _cbTestLoopback(self, ignored): - if not (self.gotStatus and self.gotResponse and self.gotEndHeaders): - raise RuntimeError( - "didn't got all callbacks %s" - % [self.gotStatus, self.gotResponse, self.gotEndHeaders]) - del self.gotEndHeaders - del self.gotResponse - del self.gotStatus - del self.numHeaders - - - -def _prequest(**headers): - """ - Make a request with the given request headers for the persistence tests. - """ - request = http.Request(DummyChannel(), False) - for headerName, v in headers.items(): - request.requestHeaders.setRawHeaders(networkString(headerName), v) - return request - - - -class PersistenceTests(unittest.TestCase): - """ - Tests for persistent HTTP connections. - """ - def setUp(self): - self.channel = http.HTTPChannel() - self.request = _prequest() - - - def test_http09(self): - """ - After being used for an I{HTTP/0.9} request, the L{HTTPChannel} is not - persistent. - """ - persist = self.channel.checkPersistence(self.request, b"HTTP/0.9") - self.assertFalse(persist) - self.assertEqual( - [], list(self.request.responseHeaders.getAllRawHeaders())) - - - def test_http10(self): - """ - After being used for an I{HTTP/1.0} request, the L{HTTPChannel} is not - persistent. - """ - persist = self.channel.checkPersistence(self.request, b"HTTP/1.0") - self.assertFalse(persist) - self.assertEqual( - [], list(self.request.responseHeaders.getAllRawHeaders())) - - - def test_http11(self): - """ - After being used for an I{HTTP/1.1} request, the L{HTTPChannel} is - persistent. - """ - persist = self.channel.checkPersistence(self.request, b"HTTP/1.1") - self.assertTrue(persist) - self.assertEqual( - [], list(self.request.responseHeaders.getAllRawHeaders())) - - - def test_http11Close(self): - """ - After being used for an I{HTTP/1.1} request with a I{Connection: Close} - header, the L{HTTPChannel} is not persistent. - """ - request = _prequest(connection=[b"close"]) - persist = self.channel.checkPersistence(request, b"HTTP/1.1") - self.assertFalse(persist) - self.assertEqual( - [(b"Connection", [b"close"])], - list(request.responseHeaders.getAllRawHeaders())) - - - -class IdentityTransferEncodingTests(TestCase): - """ - Tests for L{_IdentityTransferDecoder}. - """ - def setUp(self): - """ - Create an L{_IdentityTransferDecoder} with callbacks hooked up so that - calls to them can be inspected. - """ - self.data = [] - self.finish = [] - self.contentLength = 10 - self.decoder = _IdentityTransferDecoder( - self.contentLength, self.data.append, self.finish.append) - - - def test_exactAmountReceived(self): - """ - If L{_IdentityTransferDecoder.dataReceived} is called with a byte string - with length equal to the content length passed to - L{_IdentityTransferDecoder}'s initializer, the data callback is invoked - with that string and the finish callback is invoked with a zero-length - string. - """ - self.decoder.dataReceived(b'x' * self.contentLength) - self.assertEqual(self.data, [b'x' * self.contentLength]) - self.assertEqual(self.finish, [b'']) - - - def test_shortStrings(self): - """ - If L{_IdentityTransferDecoder.dataReceived} is called multiple times - with byte strings which, when concatenated, are as long as the content - length provided, the data callback is invoked with each string and the - finish callback is invoked only after the second call. - """ - self.decoder.dataReceived(b'x') - self.assertEqual(self.data, [b'x']) - self.assertEqual(self.finish, []) - self.decoder.dataReceived(b'y' * (self.contentLength - 1)) - self.assertEqual(self.data, [b'x', b'y' * (self.contentLength - 1)]) - self.assertEqual(self.finish, [b'']) - - - def test_longString(self): - """ - If L{_IdentityTransferDecoder.dataReceived} is called with a byte string - with length greater than the provided content length, only the prefix - of that string up to the content length is passed to the data callback - and the remainder is passed to the finish callback. - """ - self.decoder.dataReceived(b'x' * self.contentLength + b'y') - self.assertEqual(self.data, [b'x' * self.contentLength]) - self.assertEqual(self.finish, [b'y']) - - - def test_rejectDataAfterFinished(self): - """ - If data is passed to L{_IdentityTransferDecoder.dataReceived} after the - finish callback has been invoked, C{RuntimeError} is raised. - """ - failures = [] - def finish(bytes): - try: - decoder.dataReceived(b'foo') - except: - failures.append(Failure()) - decoder = _IdentityTransferDecoder(5, self.data.append, finish) - decoder.dataReceived(b'x' * 4) - self.assertEqual(failures, []) - decoder.dataReceived(b'y') - failures[0].trap(RuntimeError) - self.assertEqual( - str(failures[0].value), - "_IdentityTransferDecoder cannot decode data after finishing") - - - def test_unknownContentLength(self): - """ - If L{_IdentityTransferDecoder} is constructed with C{None} for the - content length, it passes all data delivered to it through to the data - callback. - """ - data = [] - finish = [] - decoder = _IdentityTransferDecoder(None, data.append, finish.append) - decoder.dataReceived(b'x') - self.assertEqual(data, [b'x']) - decoder.dataReceived(b'y') - self.assertEqual(data, [b'x', b'y']) - self.assertEqual(finish, []) - - - def _verifyCallbacksUnreferenced(self, decoder): - """ - Check the decoder's data and finish callbacks and make sure they are - None in order to help avoid references cycles. - """ - self.assertIdentical(decoder.dataCallback, None) - self.assertIdentical(decoder.finishCallback, None) - - - def test_earlyConnectionLose(self): - """ - L{_IdentityTransferDecoder.noMoreData} raises L{_DataLoss} if it is - called and the content length is known but not enough bytes have been - delivered. - """ - self.decoder.dataReceived(b'x' * (self.contentLength - 1)) - self.assertRaises(_DataLoss, self.decoder.noMoreData) - self._verifyCallbacksUnreferenced(self.decoder) - - - def test_unknownContentLengthConnectionLose(self): - """ - L{_IdentityTransferDecoder.noMoreData} calls the finish callback and - raises L{PotentialDataLoss} if it is called and the content length is - unknown. - """ - body = [] - finished = [] - decoder = _IdentityTransferDecoder(None, body.append, finished.append) - self.assertRaises(PotentialDataLoss, decoder.noMoreData) - self.assertEqual(body, []) - self.assertEqual(finished, [b'']) - self._verifyCallbacksUnreferenced(decoder) - - - def test_finishedConnectionLose(self): - """ - L{_IdentityTransferDecoder.noMoreData} does not raise any exception if - it is called when the content length is known and that many bytes have - been delivered. - """ - self.decoder.dataReceived(b'x' * self.contentLength) - self.decoder.noMoreData() - self._verifyCallbacksUnreferenced(self.decoder) - - - -class ChunkedTransferEncodingTests(unittest.TestCase): - """ - Tests for L{_ChunkedTransferDecoder}, which turns a byte stream encoded - using HTTP I{chunked} C{Transfer-Encoding} back into the original byte - stream. - """ - def test_decoding(self): - """ - L{_ChunkedTransferDecoder.dataReceived} decodes chunked-encoded data - and passes the result to the specified callback. - """ - L = [] - p = http._ChunkedTransferDecoder(L.append, None) - p.dataReceived(b'3\r\nabc\r\n5\r\n12345\r\n') - p.dataReceived(b'a\r\n0123456789\r\n') - self.assertEqual(L, [b'abc', b'12345', b'0123456789']) - - - def test_short(self): - """ - L{_ChunkedTransferDecoder.dataReceived} decodes chunks broken up and - delivered in multiple calls. - """ - L = [] - finished = [] - p = http._ChunkedTransferDecoder(L.append, finished.append) - for s in iterbytes(b'3\r\nabc\r\n5\r\n12345\r\n0\r\n\r\n'): - p.dataReceived(s) - self.assertEqual(L, [b'a', b'b', b'c', b'1', b'2', b'3', b'4', b'5']) - self.assertEqual(finished, [b'']) - - - def test_newlines(self): - """ - L{_ChunkedTransferDecoder.dataReceived} doesn't treat CR LF pairs - embedded in chunk bodies specially. - """ - L = [] - p = http._ChunkedTransferDecoder(L.append, None) - p.dataReceived(b'2\r\n\r\n\r\n') - self.assertEqual(L, [b'\r\n']) - - - def test_extensions(self): - """ - L{_ChunkedTransferDecoder.dataReceived} disregards chunk-extension - fields. - """ - L = [] - p = http._ChunkedTransferDecoder(L.append, None) - p.dataReceived(b'3; x-foo=bar\r\nabc\r\n') - self.assertEqual(L, [b'abc']) - - - def test_finish(self): - """ - L{_ChunkedTransferDecoder.dataReceived} interprets a zero-length - chunk as the end of the chunked data stream and calls the completion - callback. - """ - finished = [] - p = http._ChunkedTransferDecoder(None, finished.append) - p.dataReceived(b'0\r\n\r\n') - self.assertEqual(finished, [b'']) - - - def test_extra(self): - """ - L{_ChunkedTransferDecoder.dataReceived} passes any bytes which come - after the terminating zero-length chunk to the completion callback. - """ - finished = [] - p = http._ChunkedTransferDecoder(None, finished.append) - p.dataReceived(b'0\r\n\r\nhello') - self.assertEqual(finished, [b'hello']) - - - def test_afterFinished(self): - """ - L{_ChunkedTransferDecoder.dataReceived} raises C{RuntimeError} if it - is called after it has seen the last chunk. - """ - p = http._ChunkedTransferDecoder(None, lambda bytes: None) - p.dataReceived(b'0\r\n\r\n') - self.assertRaises(RuntimeError, p.dataReceived, b'hello') - - - def test_earlyConnectionLose(self): - """ - L{_ChunkedTransferDecoder.noMoreData} raises L{_DataLoss} if it is - called and the end of the last trailer has not yet been received. - """ - parser = http._ChunkedTransferDecoder(None, lambda bytes: None) - parser.dataReceived(b'0\r\n\r') - exc = self.assertRaises(_DataLoss, parser.noMoreData) - self.assertEqual( - str(exc), - "Chunked decoder in 'TRAILER' state, still expecting more data " - "to get to 'FINISHED' state.") - - - def test_finishedConnectionLose(self): - """ - L{_ChunkedTransferDecoder.noMoreData} does not raise any exception if - it is called after the terminal zero length chunk is received. - """ - parser = http._ChunkedTransferDecoder(None, lambda bytes: None) - parser.dataReceived(b'0\r\n\r\n') - parser.noMoreData() - - - def test_reentrantFinishedNoMoreData(self): - """ - L{_ChunkedTransferDecoder.noMoreData} can be called from the finished - callback without raising an exception. - """ - errors = [] - successes = [] - def finished(extra): - try: - parser.noMoreData() - except: - errors.append(Failure()) - else: - successes.append(True) - parser = http._ChunkedTransferDecoder(None, finished) - parser.dataReceived(b'0\r\n\r\n') - self.assertEqual(errors, []) - self.assertEqual(successes, [True]) - - - -class ChunkingTests(unittest.TestCase): - - strings = [b"abcv", b"", b"fdfsd423", b"Ffasfas\r\n", - b"523523\n\rfsdf", b"4234"] - - def testChunks(self): - for s in self.strings: - chunked = b''.join(http.toChunk(s)) - self.assertEqual((s, b''), http.fromChunk(chunked)) - self.assertRaises(ValueError, http.fromChunk, b'-5\r\nmalformed!\r\n') - - def testConcatenatedChunks(self): - chunked = b''.join([b''.join(http.toChunk(t)) for t in self.strings]) - result = [] - buffer = b"" - for c in iterbytes(chunked): - buffer = buffer + c - try: - data, buffer = http.fromChunk(buffer) - result.append(data) - except ValueError: - pass - self.assertEqual(result, self.strings) - - - -class ParsingTests(unittest.TestCase): - """ - Tests for protocol parsing in L{HTTPChannel}. - """ - def setUp(self): - self.didRequest = False - - - def runRequest(self, httpRequest, requestFactory=None, success=True, - channel=None): - """ - Execute a web request based on plain text content. - - @param httpRequest: Content for the request which is processed. - @type httpRequest: C{bytes} - - @param requestFactory: 2-argument callable returning a Request. - @type requestFactory: C{callable} - - @param success: Value to compare against I{self.didRequest}. - @type success: C{bool} - - @param channel: Channel instance over which the request is processed. - @type channel: L{HTTPChannel} - - @return: Returns the channel used for processing the request. - @rtype: L{HTTPChannel} - """ - if not channel: - channel = http.HTTPChannel() - - if requestFactory: - channel.requestFactory = requestFactory - - httpRequest = httpRequest.replace(b"\n", b"\r\n") - transport = StringTransport() - - channel.makeConnection(transport) - # one byte at a time, to stress it. - for byte in iterbytes(httpRequest): - if channel.transport.disconnecting: - break - channel.dataReceived(byte) - channel.connectionLost(IOError("all done")) - - if success: - self.assertTrue(self.didRequest) - else: - self.assertFalse(self.didRequest) - return channel - - - def test_basicAuth(self): - """ - L{HTTPChannel} provides username and password information supplied in - an I{Authorization} header to the L{Request} which makes it available - via its C{getUser} and C{getPassword} methods. - """ - requests = [] - class Request(http.Request): - def process(self): - self.credentials = (self.getUser(), self.getPassword()) - requests.append(self) - - for u, p in [(b"foo", b"bar"), (b"hello", b"there:z")]: - s = base64.encodestring(b":".join((u, p))).strip() - f = b"GET / HTTP/1.0\nAuthorization: Basic " + s + b"\n\n" - self.runRequest(f, Request, 0) - req = requests.pop() - self.assertEqual((u, p), req.credentials) - - - def test_headers(self): - """ - Headers received by L{HTTPChannel} in a request are made available to - the L{Request}. - """ - processed = [] - class MyRequest(http.Request): - def process(self): - processed.append(self) - self.finish() - - requestLines = [ - b"GET / HTTP/1.0", - b"Foo: bar", - b"baz: Quux", - b"baz: quux", - b"", - b""] - - self.runRequest(b'\n'.join(requestLines), MyRequest, 0) - [request] = processed - self.assertEqual( - request.requestHeaders.getRawHeaders(b'foo'), [b'bar']) - self.assertEqual( - request.requestHeaders.getRawHeaders(b'bAz'), [b'Quux', b'quux']) - - - def test_tooManyHeaders(self): - """ - L{HTTPChannel} enforces a limit of C{HTTPChannel.maxHeaders} on the - number of headers received per request. - """ - processed = [] - class MyRequest(http.Request): - def process(self): - processed.append(self) - - requestLines = [b"GET / HTTP/1.0"] - for i in range(http.HTTPChannel.maxHeaders + 2): - requestLines.append(networkString("%s: foo" % (i,))) - requestLines.extend([b"", b""]) - - channel = self.runRequest(b"\n".join(requestLines), MyRequest, 0) - self.assertEqual(processed, []) - self.assertEqual( - channel.transport.value(), - b"HTTP/1.1 400 Bad Request\r\n\r\n") - - - def test_invalidHeaders(self): - """ - If a Content-Length header with a non-integer value is received, a 400 - (Bad Request) response is sent to the client and the connection is - closed. - """ - requestLines = [b"GET / HTTP/1.0", b"Content-Length: x", b"", b""] - channel = self.runRequest(b"\n".join(requestLines), http.Request, 0) - self.assertEqual( - channel.transport.value(), - b"HTTP/1.1 400 Bad Request\r\n\r\n") - self.assertTrue(channel.transport.disconnecting) - - - def test_headerLimitPerRequest(self): - """ - L{HTTPChannel} enforces the limit of C{HTTPChannel.maxHeaders} per - request so that headers received in an earlier request do not count - towards the limit when processing a later request. - """ - processed = [] - class MyRequest(http.Request): - def process(self): - processed.append(self) - self.finish() - - self.patch(http.HTTPChannel, 'maxHeaders', 1) - requestLines = [ - b"GET / HTTP/1.1", - b"Foo: bar", - b"", - b"", - b"GET / HTTP/1.1", - b"Bar: baz", - b"", - b""] - - channel = self.runRequest(b"\n".join(requestLines), MyRequest, 0) - [first, second] = processed - self.assertEqual(first.getHeader(b'foo'), b'bar') - self.assertEqual(second.getHeader(b'bar'), b'baz') - self.assertEqual( - channel.transport.value(), - b'HTTP/1.1 200 OK\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'0\r\n' - b'\r\n' - b'HTTP/1.1 200 OK\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'0\r\n' - b'\r\n') - - - def test_headersTooBigInitialCommand(self): - """ - Enforces a limit of C{HTTPChannel.totalHeadersSize} - on the size of headers received per request starting from initial - command line. - """ - channel = http.HTTPChannel() - channel.totalHeadersSize = 10 - httpRequest = b'GET /path/longer/than/10 HTTP/1.1\n' - - channel = self.runRequest( - httpRequest=httpRequest, channel=channel, success=False) - - self.assertEqual( - channel.transport.value(), - b"HTTP/1.1 400 Bad Request\r\n\r\n") - - - def test_headersTooBigOtherHeaders(self): - """ - Enforces a limit of C{HTTPChannel.totalHeadersSize} - on the size of headers received per request counting first line - and total headers. - """ - channel = http.HTTPChannel() - channel.totalHeadersSize = 40 - httpRequest = ( - b'GET /less/than/40 HTTP/1.1\n' - b'Some-Header: less-than-40\n' - ) - - channel = self.runRequest( - httpRequest=httpRequest, channel=channel, success=False) - - self.assertEqual( - channel.transport.value(), - b"HTTP/1.1 400 Bad Request\r\n\r\n") - - - def test_headersTooBigPerRequest(self): - """ - Enforces total size of headers per individual request and counter - is reset at the end of each request. - """ - class SimpleRequest(http.Request): - def process(self): - self.finish() - channel = http.HTTPChannel() - channel.totalHeadersSize = 60 - channel.requestFactory = SimpleRequest - httpRequest = ( - b'GET / HTTP/1.1\n' - b'Some-Header: total-less-than-60\n' - b'\n' - b'GET / HTTP/1.1\n' - b'Some-Header: less-than-60\n' - b'\n' - ) - - channel = self.runRequest( - httpRequest=httpRequest, channel=channel, success=False) - - self.assertEqual( - channel.transport.value(), - b'HTTP/1.1 200 OK\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'0\r\n' - b'\r\n' - b'HTTP/1.1 200 OK\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'0\r\n' - b'\r\n' - ) - - - def testCookies(self): - """ - Test cookies parsing and reading. - """ - httpRequest = b'''\ -GET / HTTP/1.0 -Cookie: rabbit="eat carrot"; ninja=secret; spam="hey 1=1!" - -''' - cookies = {} - testcase = self - class MyRequest(http.Request): - def process(self): - for name in [b'rabbit', b'ninja', b'spam']: - cookies[name] = self.getCookie(name) - testcase.didRequest = True - self.finish() - - self.runRequest(httpRequest, MyRequest) - - self.assertEqual( - cookies, { - b'rabbit': b'"eat carrot"', - b'ninja': b'secret', - b'spam': b'"hey 1=1!"'}) - - - def testGET(self): - httpRequest = b'''\ -GET /?key=value&multiple=two+words&multiple=more%20words&empty= HTTP/1.0 - -''' - method = [] - args = [] - testcase = self - class MyRequest(http.Request): - def process(self): - method.append(self.method) - args.extend([ - self.args[b"key"], - self.args[b"empty"], - self.args[b"multiple"]]) - testcase.didRequest = True - self.finish() - - self.runRequest(httpRequest, MyRequest) - self.assertEqual(method, [b"GET"]) - self.assertEqual( - args, [[b"value"], [b""], [b"two words", b"more words"]]) - - - def test_extraQuestionMark(self): - """ - While only a single '?' is allowed in an URL, several other servers - allow several and pass all after the first through as part of the - query arguments. Test that we emulate this behavior. - """ - httpRequest = b'GET /foo?bar=?&baz=quux HTTP/1.0\n\n' - - method = [] - path = [] - args = [] - testcase = self - class MyRequest(http.Request): - def process(self): - method.append(self.method) - path.append(self.path) - args.extend([self.args[b'bar'], self.args[b'baz']]) - testcase.didRequest = True - self.finish() - - self.runRequest(httpRequest, MyRequest) - self.assertEqual(method, [b'GET']) - self.assertEqual(path, [b'/foo']) - self.assertEqual(args, [[b'?'], [b'quux']]) - - - def test_formPOSTRequest(self): - """ - The request body of a I{POST} request with a I{Content-Type} header - of I{application/x-www-form-urlencoded} is parsed according to that - content type and made available in the C{args} attribute of the - request object. The original bytes of the request may still be read - from the C{content} attribute. - """ - query = 'key=value&multiple=two+words&multiple=more%20words&empty=' - httpRequest = networkString('''\ -POST / HTTP/1.0 -Content-Length: %d -Content-Type: application/x-www-form-urlencoded - -%s''' % (len(query), query)) - - method = [] - args = [] - content = [] - testcase = self - class MyRequest(http.Request): - def process(self): - method.append(self.method) - args.extend([ - self.args[b'key'], self.args[b'empty'], - self.args[b'multiple']]) - content.append(self.content.read()) - testcase.didRequest = True - self.finish() - - self.runRequest(httpRequest, MyRequest) - self.assertEqual(method, [b"POST"]) - self.assertEqual( - args, [[b"value"], [b""], [b"two words", b"more words"]]) - # Reading from the content file-like must produce the entire request - # body. - self.assertEqual(content, [networkString(query)]) - - - def testMissingContentDisposition(self): - req = b'''\ -POST / HTTP/1.0 -Content-Type: multipart/form-data; boundary=AaB03x -Content-Length: 103 - ---AaB03x -Content-Type: text/plain -Content-Transfer-Encoding: quoted-printable - -abasdfg ---AaB03x-- -''' - self.runRequest(req, http.Request, success=False) - if _PY3: - testMissingContentDisposition.skip = ( - "Cannot parse multipart/form-data on Python 3. " - "See http://bugs.python.org/issue12411 and #5511.") - - - def test_chunkedEncoding(self): - """ - If a request uses the I{chunked} transfer encoding, the request body is - decoded accordingly before it is made available on the request. - """ - httpRequest = b'''\ -GET / HTTP/1.0 -Content-Type: text/plain -Transfer-Encoding: chunked - -6 -Hello, -14 - spam,eggs spam spam -0 - -''' - path = [] - method = [] - content = [] - decoder = [] - testcase = self - class MyRequest(http.Request): - def process(self): - content.append(self.content.fileno()) - content.append(self.content.read()) - method.append(self.method) - path.append(self.path) - decoder.append(self.channel._transferDecoder) - testcase.didRequest = True - self.finish() - - self.runRequest(httpRequest, MyRequest) - # The tempfile API used to create content returns an - # instance of a different type depending on what platform - # we're running on. The point here is to verify that the - # request body is in a file that's on the filesystem. - # Having a fileno method that returns an int is a somewhat - # close approximation of this. -exarkun - self.assertIsInstance(content[0], int) - self.assertEqual(content[1], b'Hello, spam,eggs spam spam') - self.assertEqual(method, [b'GET']) - self.assertEqual(path, [b'/']) - self.assertEqual(decoder, [None]) - - - def test_malformedChunkedEncoding(self): - """ - If a request uses the I{chunked} transfer encoding, but provides an - invalid chunk length value, the request fails with a 400 error. - """ - # See test_chunkedEncoding for the correct form of this request. - httpRequest = b'''\ -GET / HTTP/1.1 -Content-Type: text/plain -Transfer-Encoding: chunked - -MALFORMED_LINE_THIS_SHOULD_BE_'6' -Hello, -14 - spam,eggs spam spam -0 - -''' - didRequest = [] - - class MyRequest(http.Request): - - def process(self): - # This request should fail, so this should never be called. - didRequest.append(True) - - channel = self.runRequest(httpRequest, MyRequest, success=False) - self.assertFalse(didRequest, "Request.process called") - self.assertEqual( - channel.transport.value(), - b"HTTP/1.1 400 Bad Request\r\n\r\n") - self.assertTrue(channel.transport.disconnecting) - - - -class QueryArgumentsTests(unittest.TestCase): - def testParseqs(self): - self.assertEqual( - cgi.parse_qs(b"a=b&d=c;+=f"), - http.parse_qs(b"a=b&d=c;+=f")) - self.assertRaises( - ValueError, http.parse_qs, b"blah", strict_parsing=True) - self.assertEqual( - cgi.parse_qs(b"a=&b=c", keep_blank_values=1), - http.parse_qs(b"a=&b=c", keep_blank_values=1)) - self.assertEqual( - cgi.parse_qs(b"a=&b=c"), - http.parse_qs(b"a=&b=c")) - - - def test_urlparse(self): - """ - For a given URL, L{http.urlparse} should behave the same as L{urlparse}, - except it should always return C{bytes}, never text. - """ - def urls(): - for scheme in (b'http', b'https'): - for host in (b'example.com',): - for port in (None, 100): - for path in (b'', b'path'): - if port is not None: - host = host + b':' + networkString(str(port)) - yield urlunsplit((scheme, host, path, b'', b'')) - - - def assertSameParsing(url, decode): - """ - Verify that C{url} is parsed into the same objects by both - L{http.urlparse} and L{urlparse}. - """ - urlToStandardImplementation = url - if decode: - urlToStandardImplementation = url.decode('ascii') - - # stdlib urlparse will give back whatever type we give it. To be - # able to compare the values meaningfully, if it gives back unicode, - # convert all the values to bytes. - standardResult = urlparse(urlToStandardImplementation) - if isinstance(standardResult.scheme, unicode): - # The choice of encoding is basically irrelevant. The values - # are all in ASCII. UTF-8 is, of course, the correct choice. - expected = (standardResult.scheme.encode('utf-8'), - standardResult.netloc.encode('utf-8'), - standardResult.path.encode('utf-8'), - standardResult.params.encode('utf-8'), - standardResult.query.encode('utf-8'), - standardResult.fragment.encode('utf-8')) - else: - expected = (standardResult.scheme, - standardResult.netloc, - standardResult.path, - standardResult.params, - standardResult.query, - standardResult.fragment) - - scheme, netloc, path, params, query, fragment = http.urlparse(url) - self.assertEqual( - (scheme, netloc, path, params, query, fragment), expected) - self.assertIsInstance(scheme, bytes) - self.assertIsInstance(netloc, bytes) - self.assertIsInstance(path, bytes) - self.assertIsInstance(params, bytes) - self.assertIsInstance(query, bytes) - self.assertIsInstance(fragment, bytes) - - # With caching, unicode then str - clear_cache() - for url in urls(): - assertSameParsing(url, True) - assertSameParsing(url, False) - - # With caching, str then unicode - clear_cache() - for url in urls(): - assertSameParsing(url, False) - assertSameParsing(url, True) - - # Without caching - for url in urls(): - clear_cache() - assertSameParsing(url, True) - clear_cache() - assertSameParsing(url, False) - - - def test_urlparseRejectsUnicode(self): - """ - L{http.urlparse} should reject unicode input early. - """ - self.assertRaises(TypeError, http.urlparse, u'http://example.org/path') - - - -class ClientDriver(http.HTTPClient): - def handleStatus(self, version, status, message): - self.version = version - self.status = status - self.message = message - -class ClientStatusParsingTests(unittest.TestCase): - def testBaseline(self): - c = ClientDriver() - c.lineReceived(b'HTTP/1.0 201 foo') - self.assertEqual(c.version, b'HTTP/1.0') - self.assertEqual(c.status, b'201') - self.assertEqual(c.message, b'foo') - - def testNoMessage(self): - c = ClientDriver() - c.lineReceived(b'HTTP/1.0 201') - self.assertEqual(c.version, b'HTTP/1.0') - self.assertEqual(c.status, b'201') - self.assertEqual(c.message, b'') - - def testNoMessage_trailingSpace(self): - c = ClientDriver() - c.lineReceived(b'HTTP/1.0 201 ') - self.assertEqual(c.version, b'HTTP/1.0') - self.assertEqual(c.status, b'201') - self.assertEqual(c.message, b'') - - - -class RequestTests(unittest.TestCase, ResponseTestMixin): - """ - Tests for L{http.Request} - """ - def _compatHeadersTest(self, oldName, newName): - """ - Verify that each of two different attributes which are associated with - the same state properly reflect changes made through the other. - - This is used to test that the C{headers}/C{responseHeaders} and - C{received_headers}/C{requestHeaders} pairs interact properly. - """ - req = http.Request(DummyChannel(), False) - getattr(req, newName).setRawHeaders(b"test", [b"lemur"]) - self.assertEqual(getattr(req, oldName)[b"test"], b"lemur") - setattr(req, oldName, {b"foo": b"bar"}) - self.assertEqual( - list(getattr(req, newName).getAllRawHeaders()), - [(b"Foo", [b"bar"])]) - setattr(req, newName, http_headers.Headers()) - self.assertEqual(getattr(req, oldName), {}) - - - def test_received_headers(self): - """ - L{Request.received_headers} is a backwards compatible API which - accesses and allows mutation of the state at L{Request.requestHeaders}. - """ - self._compatHeadersTest('received_headers', 'requestHeaders') - - - def test_headers(self): - """ - L{Request.headers} is a backwards compatible API which accesses and - allows mutation of the state at L{Request.responseHeaders}. - """ - self._compatHeadersTest('headers', 'responseHeaders') - - - def test_getHeader(self): - """ - L{http.Request.getHeader} returns the value of the named request - header. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders(b"test", [b"lemur"]) - self.assertEqual(req.getHeader(b"test"), b"lemur") - - - def test_getHeaderReceivedMultiples(self): - """ - When there are multiple values for a single request header, - L{http.Request.getHeader} returns the last value. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders(b"test", [b"lemur", b"panda"]) - self.assertEqual(req.getHeader(b"test"), b"panda") - - - def test_getHeaderNotFound(self): - """ - L{http.Request.getHeader} returns C{None} when asked for the value of a - request header which is not present. - """ - req = http.Request(DummyChannel(), False) - self.assertEqual(req.getHeader(b"test"), None) - - - def test_getAllHeaders(self): - """ - L{http.Request.getAllheaders} returns a C{dict} mapping all request - header names to their corresponding values. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders(b"test", [b"lemur"]) - self.assertEqual(req.getAllHeaders(), {b"test": b"lemur"}) - - - def test_getAllHeadersNoHeaders(self): - """ - L{http.Request.getAllHeaders} returns an empty C{dict} if there are no - request headers. - """ - req = http.Request(DummyChannel(), False) - self.assertEqual(req.getAllHeaders(), {}) - - - def test_getAllHeadersMultipleHeaders(self): - """ - When there are multiple values for a single request header, - L{http.Request.getAllHeaders} returns only the last value. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders(b"test", [b"lemur", b"panda"]) - self.assertEqual(req.getAllHeaders(), {b"test": b"panda"}) - - - def test_setResponseCode(self): - """ - L{http.Request.setResponseCode} takes a status code and causes it to be - used as the response status. - """ - channel = DummyChannel() - req = http.Request(channel, False) - req.setResponseCode(201) - req.write(b'') - self.assertEqual( - channel.transport.written.getvalue().splitlines()[0], - b"(no clientproto yet) 201 Created") - - - def test_setResponseCodeAndMessage(self): - """ - L{http.Request.setResponseCode} takes a status code and a message and - causes them to be used as the response status. - """ - channel = DummyChannel() - req = http.Request(channel, False) - req.setResponseCode(202, "happily accepted") - req.write(b'') - self.assertEqual( - channel.transport.written.getvalue().splitlines()[0], - b'(no clientproto yet) 202 happily accepted') - - - def test_setResponseCodeAcceptsIntegers(self): - """ - L{http.Request.setResponseCode} accepts C{int} for the code parameter - and raises L{TypeError} if passed anything else. - """ - req = http.Request(DummyChannel(), False) - req.setResponseCode(1) - self.assertRaises(TypeError, req.setResponseCode, "1") - - - def test_setResponseCodeAcceptsLongIntegers(self): - """ - L{http.Request.setResponseCode} accepts C{long} for the code - parameter. - """ - req = http.Request(DummyChannel(), False) - req.setResponseCode(long(1)) - if _PY3: - test_setResponseCodeAcceptsLongIntegers.skip = ( - "Python 3 has no separate long integer type.") - - - def test_setHost(self): - """ - L{http.Request.setHost} sets the value of the host request header. - The port should not be added because it is the default. - """ - req = http.Request(DummyChannel(), False) - req.setHost(b"example.com", 80) - self.assertEqual( - req.requestHeaders.getRawHeaders(b"host"), [b"example.com"]) - - - def test_setHostSSL(self): - """ - L{http.Request.setHost} sets the value of the host request header. - The port should not be added because it is the default. - """ - d = DummyChannel() - d.transport = DummyChannel.SSL() - req = http.Request(d, False) - req.setHost(b"example.com", 443) - self.assertEqual( - req.requestHeaders.getRawHeaders(b"host"), [b"example.com"]) - - - def test_setHostNonDefaultPort(self): - """ - L{http.Request.setHost} sets the value of the host request header. - The port should be added because it is not the default. - """ - req = http.Request(DummyChannel(), False) - req.setHost(b"example.com", 81) - self.assertEqual( - req.requestHeaders.getRawHeaders(b"host"), [b"example.com:81"]) - - - def test_setHostSSLNonDefaultPort(self): - """ - L{http.Request.setHost} sets the value of the host request header. - The port should be added because it is not the default. - """ - d = DummyChannel() - d.transport = DummyChannel.SSL() - req = http.Request(d, False) - req.setHost(b"example.com", 81) - self.assertEqual( - req.requestHeaders.getRawHeaders(b"host"), [b"example.com:81"]) - - - def test_setHeader(self): - """ - L{http.Request.setHeader} sets the value of the given response header. - """ - req = http.Request(DummyChannel(), False) - req.setHeader(b"test", b"lemur") - self.assertEqual(req.responseHeaders.getRawHeaders(b"test"), [b"lemur"]) - - - def test_firstWrite(self): - """ - For an HTTP 1.0 request, L{http.Request.write} sends an HTTP 1.0 - Response-Line and whatever response headers are set. - """ - req = http.Request(DummyChannel(), False) - trans = StringTransport() - - req.transport = trans - - req.setResponseCode(200) - req.clientproto = b"HTTP/1.0" - req.responseHeaders.setRawHeaders(b"test", [b"lemur"]) - req.write(b'Hello') - - self.assertResponseEquals( - trans.value(), - [(b"HTTP/1.0 200 OK", - b"Test: lemur", - b"Hello")]) - - - def test_nonByteHeaderValue(self): - """ - L{http.Request.write} casts non-bytes header value to bytes - transparently. - """ - req = http.Request(DummyChannel(), False) - trans = StringTransport() - - req.transport = trans - - req.setResponseCode(200) - req.clientproto = b"HTTP/1.0" - req.responseHeaders.setRawHeaders(b"test", [10]) - req.write(b'Hello') - - self.assertResponseEquals( - trans.value(), - [(b"HTTP/1.0 200 OK", - b"Test: 10", - b"Hello")]) - - warnings = self.flushWarnings( - offendingFunctions=[self.test_nonByteHeaderValue]) - self.assertEqual(1, len(warnings)) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "Passing non-bytes header values is deprecated since " - "Twisted 12.3. Pass only bytes instead.") - - - def test_firstWriteHTTP11Chunked(self): - """ - For an HTTP 1.1 request, L{http.Request.write} sends an HTTP 1.1 - Response-Line, whatever response headers are set, and uses chunked - encoding for the response body. - """ - req = http.Request(DummyChannel(), False) - trans = StringTransport() - - req.transport = trans - - req.setResponseCode(200) - req.clientproto = b"HTTP/1.1" - req.responseHeaders.setRawHeaders(b"test", [b"lemur"]) - req.write(b'Hello') - req.write(b'World!') - - self.assertResponseEquals( - trans.value(), - [(b"HTTP/1.1 200 OK", - b"Test: lemur", - b"Transfer-Encoding: chunked", - b"5\r\nHello\r\n6\r\nWorld!\r\n")]) - - - def test_firstWriteLastModified(self): - """ - For an HTTP 1.0 request for a resource with a known last modified time, - L{http.Request.write} sends an HTTP Response-Line, whatever response - headers are set, and a last-modified header with that time. - """ - req = http.Request(DummyChannel(), False) - trans = StringTransport() - - req.transport = trans - - req.setResponseCode(200) - req.clientproto = b"HTTP/1.0" - req.lastModified = 0 - req.responseHeaders.setRawHeaders(b"test", [b"lemur"]) - req.write(b'Hello') - - self.assertResponseEquals( - trans.value(), - [(b"HTTP/1.0 200 OK", - b"Test: lemur", - b"Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT", - b"Hello")]) - - - def test_receivedCookiesDefault(self): - """ - L{http.Request.received_cookies} defaults to an empty L{dict}. - """ - req = http.Request(DummyChannel(), False) - self.assertEqual(req.received_cookies, {}) - - - def test_parseCookies(self): - """ - L{http.Request.parseCookies} extracts cookies from C{requestHeaders} - and adds them to C{received_cookies}. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", [b'test="lemur"; test2="panda"']) - req.parseCookies() - self.assertEqual( - req.received_cookies, {b"test": b'"lemur"', b"test2": b'"panda"'}) - - - def test_parseCookiesMultipleHeaders(self): - """ - L{http.Request.parseCookies} can extract cookies from multiple Cookie - headers. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", [b'test="lemur"', b'test2="panda"']) - req.parseCookies() - self.assertEqual( - req.received_cookies, {b"test": b'"lemur"', b"test2": b'"panda"'}) - - - def test_parseCookiesNoCookie(self): - """ - L{http.Request.parseCookies} can be called on a request without a - cookie header. - """ - req = http.Request(DummyChannel(), False) - req.parseCookies() - self.assertEqual(req.received_cookies, {}) - - - def test_parseCookiesEmptyCookie(self): - """ - L{http.Request.parseCookies} can be called on a request with an - empty cookie header. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", []) - req.parseCookies() - self.assertEqual(req.received_cookies, {}) - - - def test_parseCookiesIgnoreValueless(self): - """ - L{http.Request.parseCookies} ignores cookies which don't have a - value. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", [b'foo; bar; baz;']) - req.parseCookies() - self.assertEqual( - req.received_cookies, {}) - - - def test_parseCookiesEmptyValue(self): - """ - L{http.Request.parseCookies} parses cookies with an empty value. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", [b'foo=']) - req.parseCookies() - self.assertEqual( - req.received_cookies, {b'foo': b''}) - - - def test_parseCookiesRetainRightSpace(self): - """ - L{http.Request.parseCookies} leaves trailing whitespace in the - cookie value. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", [b'foo=bar ']) - req.parseCookies() - self.assertEqual( - req.received_cookies, {b'foo': b'bar '}) - - - def test_parseCookiesStripLeftSpace(self): - """ - L{http.Request.parseCookies} strips leading whitespace in the - cookie key. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", [b' foo=bar']) - req.parseCookies() - self.assertEqual( - req.received_cookies, {b'foo': b'bar'}) - - - def test_parseCookiesContinueAfterMalformedCookie(self): - """ - L{http.Request.parseCookies} parses valid cookies set before or - after malformed cookies. - """ - req = http.Request(DummyChannel(), False) - req.requestHeaders.setRawHeaders( - b"cookie", [b'12345; test="lemur"; 12345; test2="panda"; 12345']) - req.parseCookies() - self.assertEqual( - req.received_cookies, {b"test": b'"lemur"', b"test2": b'"panda"'}) - - - def test_connectionLost(self): - """ - L{http.Request.connectionLost} closes L{Request.content} and drops the - reference to the L{HTTPChannel} to assist with garbage collection. - """ - req = http.Request(DummyChannel(), False) - - # Cause Request.content to be created at all. - req.gotLength(10) - - # Grab a reference to content in case the Request drops it later on. - content = req.content - - # Put some bytes into it - req.handleContentChunk(b"hello") - - # Then something goes wrong and content should get closed. - req.connectionLost(Failure(ConnectionLost("Finished"))) - self.assertTrue(content.closed) - self.assertIdentical(req.channel, None) - - - def test_registerProducerTwiceFails(self): - """ - Calling L{Request.registerProducer} when a producer is already - registered raises ValueError. - """ - req = http.Request(DummyChannel(), False) - req.registerProducer(DummyProducer(), True) - self.assertRaises( - ValueError, req.registerProducer, DummyProducer(), True) - - - def test_registerProducerWhenQueuedPausesPushProducer(self): - """ - Calling L{Request.registerProducer} with an IPushProducer when the - request is queued pauses the producer. - """ - req = http.Request(DummyChannel(), True) - producer = DummyProducer() - req.registerProducer(producer, True) - self.assertEqual(['pause'], producer.events) - - - def test_registerProducerWhenQueuedDoesntPausePullProducer(self): - """ - Calling L{Request.registerProducer} with an IPullProducer when the - request is queued does not pause the producer, because it doesn't make - sense to pause a pull producer. - """ - req = http.Request(DummyChannel(), True) - producer = DummyProducer() - req.registerProducer(producer, False) - self.assertEqual([], producer.events) - - - def test_registerProducerWhenQueuedDoesntRegisterPushProducer(self): - """ - Calling L{Request.registerProducer} with an IPushProducer when the - request is queued does not register the producer on the request's - transport. - """ - self.assertIdentical( - None, getattr(http.StringTransport, 'registerProducer', None), - "StringTransport cannot implement registerProducer for this test " - "to be valid.") - req = http.Request(DummyChannel(), True) - producer = DummyProducer() - req.registerProducer(producer, True) - # This is a roundabout assertion: http.StringTransport doesn't - # implement registerProducer, so Request.registerProducer can't have - # tried to call registerProducer on the transport. - self.assertIsInstance(req.transport, http.StringTransport) - - - def test_registerProducerWhenQueuedDoesntRegisterPullProducer(self): - """ - Calling L{Request.registerProducer} with an IPullProducer when the - request is queued does not register the producer on the request's - transport. - """ - self.assertIdentical( - None, getattr(http.StringTransport, 'registerProducer', None), - "StringTransport cannot implement registerProducer for this test " - "to be valid.") - req = http.Request(DummyChannel(), True) - producer = DummyProducer() - req.registerProducer(producer, False) - # This is a roundabout assertion: http.StringTransport doesn't - # implement registerProducer, so Request.registerProducer can't have - # tried to call registerProducer on the transport. - self.assertIsInstance(req.transport, http.StringTransport) - - - def test_registerProducerWhenNotQueuedRegistersPushProducer(self): - """ - Calling L{Request.registerProducer} with an IPushProducer when the - request is not queued registers the producer as a push producer on the - request's transport. - """ - req = http.Request(DummyChannel(), False) - producer = DummyProducer() - req.registerProducer(producer, True) - self.assertEqual([(producer, True)], req.transport.producers) - - - def test_registerProducerWhenNotQueuedRegistersPullProducer(self): - """ - Calling L{Request.registerProducer} with an IPullProducer when the - request is not queued registers the producer as a pull producer on the - request's transport. - """ - req = http.Request(DummyChannel(), False) - producer = DummyProducer() - req.registerProducer(producer, False) - self.assertEqual([(producer, False)], req.transport.producers) - - - def test_connectionLostNotification(self): - """ - L{Request.connectionLost} triggers all finish notification Deferreds - and cleans up per-request state. - """ - d = DummyChannel() - request = http.Request(d, True) - finished = request.notifyFinish() - request.connectionLost(Failure(ConnectionLost("Connection done"))) - self.assertIdentical(request.channel, None) - return self.assertFailure(finished, ConnectionLost) - - - def test_finishNotification(self): - """ - L{Request.finish} triggers all finish notification Deferreds. - """ - request = http.Request(DummyChannel(), False) - finished = request.notifyFinish() - # Force the request to have a non-None content attribute. This is - # probably a bug in Request. - request.gotLength(1) - request.finish() - return finished - - - def test_writeAfterFinish(self): - """ - Calling L{Request.write} after L{Request.finish} has been called results - in a L{RuntimeError} being raised. - """ - request = http.Request(DummyChannel(), False) - finished = request.notifyFinish() - # Force the request to have a non-None content attribute. This is - # probably a bug in Request. - request.gotLength(1) - request.write(b'foobar') - request.finish() - self.assertRaises(RuntimeError, request.write, b'foobar') - return finished - - - def test_finishAfterConnectionLost(self): - """ - Calling L{Request.finish} after L{Request.connectionLost} has been - called results in a L{RuntimeError} being raised. - """ - channel = DummyChannel() - req = http.Request(channel, False) - req.connectionLost(Failure(ConnectionLost("The end."))) - self.assertRaises(RuntimeError, req.finish) - - - def test_reprUninitialized(self): - """ - L{Request.__repr__} returns the class name, object address, and - dummy-place holder values when used on a L{Request} which has not yet - been initialized. - """ - request = http.Request(DummyChannel(), False) - self.assertEqual( - repr(request), - '<Request at 0x%x method=(no method yet) uri=(no uri yet) ' - 'clientproto=(no clientproto yet)>' % (id(request),)) - - - def test_reprInitialized(self): - """ - L{Request.__repr__} returns, as a L{str}, the class name, object - address, and the method, uri, and client protocol of the HTTP request - it represents. The string is in the form:: - - <Request at ADDRESS method=METHOD uri=URI clientproto=PROTOCOL> - """ - request = http.Request(DummyChannel(), False) - request.clientproto = b'HTTP/1.0' - request.method = b'GET' - request.uri = b'/foo/bar' - self.assertEqual( - repr(request), - '<Request at 0x%x method=GET uri=/foo/bar ' - 'clientproto=HTTP/1.0>' % (id(request),)) - - - def test_reprSubclass(self): - """ - Subclasses of L{Request} inherit a C{__repr__} implementation which - includes the subclass's name in place of the string C{"Request"}. - """ - class Otherwise(http.Request): - pass - - request = Otherwise(DummyChannel(), False) - self.assertEqual( - repr(request), - '<Otherwise at 0x%x method=(no method yet) uri=(no uri yet) ' - 'clientproto=(no clientproto yet)>' % (id(request),)) - - - def test_unregisterNonQueuedNonStreamingProducer(self): - """ - L{Request.unregisterProducer} unregisters a non-queued non-streaming - producer from the request and the request's transport. - """ - req = http.Request(DummyChannel(), False) - req.transport = StringTransport() - req.registerProducer(DummyProducer(), False) - req.unregisterProducer() - self.assertEqual((None, None), (req.producer, req.transport.producer)) - - - def test_unregisterNonQueuedStreamingProducer(self): - """ - L{Request.unregisterProducer} unregisters a non-queued streaming - producer from the request and the request's transport. - """ - req = http.Request(DummyChannel(), False) - req.transport = StringTransport() - req.registerProducer(DummyProducer(), True) - req.unregisterProducer() - self.assertEqual((None, None), (req.producer, req.transport.producer)) - - - def test_unregisterQueuedNonStreamingProducer(self): - """ - L{Request.unregisterProducer} unregisters a queued non-streaming - producer from the request but not from the transport. - """ - existing = DummyProducer() - channel = DummyChannel() - transport = StringTransport() - channel.transport = transport - transport.registerProducer(existing, True) - req = http.Request(channel, True) - req.registerProducer(DummyProducer(), False) - req.unregisterProducer() - self.assertEqual((None, existing), (req.producer, transport.producer)) - - - def test_unregisterQueuedStreamingProducer(self): - """ - L{Request.unregisterProducer} unregisters a queued streaming producer - from the request but not from the transport. - """ - existing = DummyProducer() - channel = DummyChannel() - transport = StringTransport() - channel.transport = transport - transport.registerProducer(existing, True) - req = http.Request(channel, True) - req.registerProducer(DummyProducer(), True) - req.unregisterProducer() - self.assertEqual((None, existing), (req.producer, transport.producer)) - - - -class MultilineHeadersTests(unittest.TestCase): - """ - Tests to exercise handling of multiline headers by L{HTTPClient}. RFCs 1945 - (HTTP 1.0) and 2616 (HTTP 1.1) state that HTTP message header fields can - span multiple lines if each extra line is preceded by at least one space or - horizontal tab. - """ - def setUp(self): - """ - Initialize variables used to verify that the header-processing functions - are getting called. - """ - self.handleHeaderCalled = False - self.handleEndHeadersCalled = False - - # Dictionary of sample complete HTTP header key/value pairs, including - # multiline headers. - expectedHeaders = {b'Content-Length': b'10', - b'X-Multiline' : b'line-0\tline-1', - b'X-Multiline2' : b'line-2 line-3'} - - def ourHandleHeader(self, key, val): - """ - Dummy implementation of L{HTTPClient.handleHeader}. - """ - self.handleHeaderCalled = True - self.assertEqual(val, self.expectedHeaders[key]) - - - def ourHandleEndHeaders(self): - """ - Dummy implementation of L{HTTPClient.handleEndHeaders}. - """ - self.handleEndHeadersCalled = True - - - def test_extractHeader(self): - """ - A header isn't processed by L{HTTPClient.extractHeader} until it is - confirmed in L{HTTPClient.lineReceived} that the header has been - received completely. - """ - c = ClientDriver() - c.handleHeader = self.ourHandleHeader - c.handleEndHeaders = self.ourHandleEndHeaders - - c.lineReceived(b'HTTP/1.0 201') - c.lineReceived(b'Content-Length: 10') - self.assertIdentical(c.length, None) - self.assertFalse(self.handleHeaderCalled) - self.assertFalse(self.handleEndHeadersCalled) - - # Signal end of headers. - c.lineReceived(b'') - self.assertTrue(self.handleHeaderCalled) - self.assertTrue(self.handleEndHeadersCalled) - - self.assertEqual(c.length, 10) - - - def test_noHeaders(self): - """ - An HTTP request with no headers will not cause any calls to - L{handleHeader} but will cause L{handleEndHeaders} to be called on - L{HTTPClient} subclasses. - """ - c = ClientDriver() - c.handleHeader = self.ourHandleHeader - c.handleEndHeaders = self.ourHandleEndHeaders - c.lineReceived(b'HTTP/1.0 201') - - # Signal end of headers. - c.lineReceived(b'') - self.assertFalse(self.handleHeaderCalled) - self.assertTrue(self.handleEndHeadersCalled) - - self.assertEqual(c.version, b'HTTP/1.0') - self.assertEqual(c.status, b'201') - - - def test_multilineHeaders(self): - """ - L{HTTPClient} parses multiline headers by buffering header lines until - an empty line or a line that does not start with whitespace hits - lineReceived, confirming that the header has been received completely. - """ - c = ClientDriver() - c.handleHeader = self.ourHandleHeader - c.handleEndHeaders = self.ourHandleEndHeaders - - c.lineReceived(b'HTTP/1.0 201') - c.lineReceived(b'X-Multiline: line-0') - self.assertFalse(self.handleHeaderCalled) - # Start continuing line with a tab. - c.lineReceived(b'\tline-1') - c.lineReceived(b'X-Multiline2: line-2') - # The previous header must be complete, so now it can be processed. - self.assertTrue(self.handleHeaderCalled) - # Start continuing line with a space. - c.lineReceived(b' line-3') - c.lineReceived(b'Content-Length: 10') - - # Signal end of headers. - c.lineReceived(b'') - self.assertTrue(self.handleEndHeadersCalled) - - self.assertEqual(c.version, b'HTTP/1.0') - self.assertEqual(c.status, b'201') - self.assertEqual(c.length, 10) - - - -class Expect100ContinueServerTests(unittest.TestCase, ResponseTestMixin): - """ - Test that the HTTP server handles 'Expect: 100-continue' header correctly. - - The tests in this class all assume a simplistic behavior where user code - cannot choose to deny a request. Once ticket #288 is implemented and user - code can run before the body of a POST is processed this should be - extended to support overriding this behavior. - """ - - def test_HTTP10(self): - """ - HTTP/1.0 requests do not get 100-continue returned, even if 'Expect: - 100-continue' is included (RFC 2616 10.1.1). - """ - transport = StringTransport() - channel = http.HTTPChannel() - channel.requestFactory = DummyHTTPHandler - channel.makeConnection(transport) - channel.dataReceived(b"GET / HTTP/1.0\r\n") - channel.dataReceived(b"Host: www.example.com\r\n") - channel.dataReceived(b"Content-Length: 3\r\n") - channel.dataReceived(b"Expect: 100-continue\r\n") - channel.dataReceived(b"\r\n") - self.assertEqual(transport.value(), b"") - channel.dataReceived(b"abc") - self.assertResponseEquals( - transport.value(), - [(b"HTTP/1.0 200 OK", - b"Command: GET", - b"Content-Length: 13", - b"Version: HTTP/1.0", - b"Request: /", - b"'''\n3\nabc'''\n")]) - - - def test_expect100ContinueHeader(self): - """ - If a HTTP/1.1 client sends a 'Expect: 100-continue' header, the server - responds with a 100 response code before handling the request body, if - any. The normal resource rendering code will then be called, which - will send an additional response code. - """ - transport = StringTransport() - channel = http.HTTPChannel() - channel.requestFactory = DummyHTTPHandler - channel.makeConnection(transport) - channel.dataReceived(b"GET / HTTP/1.1\r\n") - channel.dataReceived(b"Host: www.example.com\r\n") - channel.dataReceived(b"Expect: 100-continue\r\n") - channel.dataReceived(b"Content-Length: 3\r\n") - # The 100 continue response is not sent until all headers are - # received: - self.assertEqual(transport.value(), b"") - channel.dataReceived(b"\r\n") - # The 100 continue response is sent *before* the body is even - # received: - self.assertEqual(transport.value(), b"HTTP/1.1 100 Continue\r\n\r\n") - channel.dataReceived(b"abc") - response = transport.value() - self.assertTrue( - response.startswith(b"HTTP/1.1 100 Continue\r\n\r\n")) - response = response[len(b"HTTP/1.1 100 Continue\r\n\r\n"):] - self.assertResponseEquals( - response, - [(b"HTTP/1.1 200 OK", - b"Command: GET", - b"Content-Length: 13", - b"Version: HTTP/1.1", - b"Request: /", - b"'''\n3\nabc'''\n")]) - - - def test_expect100ContinueWithPipelining(self): - """ - If a HTTP/1.1 client sends a 'Expect: 100-continue' header, followed - by another pipelined request, the 100 response does not interfere with - the response to the second request. - """ - transport = StringTransport() - channel = http.HTTPChannel() - channel.requestFactory = DummyHTTPHandler - channel.makeConnection(transport) - channel.dataReceived( - b"GET / HTTP/1.1\r\n" - b"Host: www.example.com\r\n" - b"Expect: 100-continue\r\n" - b"Content-Length: 3\r\n" - b"\r\nabc" - b"POST /foo HTTP/1.1\r\n" - b"Host: www.example.com\r\n" - b"Content-Length: 4\r\n" - b"\r\ndefg") - response = transport.value() - self.assertTrue( - response.startswith(b"HTTP/1.1 100 Continue\r\n\r\n")) - response = response[len(b"HTTP/1.1 100 Continue\r\n\r\n"):] - self.assertResponseEquals( - response, - [(b"HTTP/1.1 200 OK", - b"Command: GET", - b"Content-Length: 13", - b"Version: HTTP/1.1", - b"Request: /", - b"'''\n3\nabc'''\n"), - (b"HTTP/1.1 200 OK", - b"Command: POST", - b"Content-Length: 14", - b"Version: HTTP/1.1", - b"Request: /foo", - b"'''\n4\ndefg'''\n")]) - - - -def sub(keys, d): - """ - Create a new dict containing only a subset of the items of an existing - dict. - - @param keys: An iterable of the keys which will be added (with values from - C{d}) to the result. - - @param d: The existing L{dict} from which to copy items. - - @return: The new L{dict} with keys given by C{keys} and values given by the - corresponding values in C{d}. - @rtype: L{dict} - """ - return dict([(k, d[k]) for k in keys]) - - - -class DeprecatedRequestAttributesTests(unittest.TestCase): - """ - Tests for deprecated attributes of L{twisted.web.http.Request}. - """ - def test_readHeaders(self): - """ - Reading from the C{headers} attribute is deprecated in favor of use of - the C{responseHeaders} attribute. - """ - request = http.Request(DummyChannel(), True) - request.headers - warnings = self.flushWarnings( - offendingFunctions=[self.test_readHeaders]) - - self.assertEqual({ - "category": DeprecationWarning, - "message": ( - "twisted.web.http.Request.headers was deprecated in " - "Twisted 13.2.0: Please use twisted.web.http.Request." - "responseHeaders instead.")}, - sub(["category", "message"], warnings[0])) - - - def test_writeHeaders(self): - """ - Writing to the C{headers} attribute is deprecated in favor of use of - the C{responseHeaders} attribute. - """ - request = http.Request(DummyChannel(), True) - request.headers = {b"foo": b"bar"} - warnings = self.flushWarnings( - offendingFunctions=[self.test_writeHeaders]) - - self.assertEqual({ - "category": DeprecationWarning, - "message": ( - "twisted.web.http.Request.headers was deprecated in " - "Twisted 13.2.0: Please use twisted.web.http.Request." - "responseHeaders instead.")}, - sub(["category", "message"], warnings[0])) - - - def test_readReceivedHeaders(self): - """ - Reading from the C{received_headers} attribute is deprecated in favor - of use of the C{requestHeaders} attribute. - """ - request = http.Request(DummyChannel(), True) - request.received_headers - warnings = self.flushWarnings( - offendingFunctions=[self.test_readReceivedHeaders]) - - self.assertEqual({ - "category": DeprecationWarning, - "message": ( - "twisted.web.http.Request.received_headers was deprecated " - "in Twisted 13.2.0: Please use twisted.web.http.Request." - "requestHeaders instead.")}, - sub(["category", "message"], warnings[0])) - - - def test_writeReceivedHeaders(self): - """ - Writing to the C{received_headers} attribute is deprecated in favor of use of - the C{requestHeaders} attribute. - """ - request = http.Request(DummyChannel(), True) - request.received_headers = {b"foo": b"bar"} - warnings = self.flushWarnings( - offendingFunctions=[self.test_writeReceivedHeaders]) - - self.assertEqual({ - "category": DeprecationWarning, - "message": ( - "twisted.web.http.Request.received_headers was deprecated " - "in Twisted 13.2.0: Please use twisted.web.http.Request." - "requestHeaders instead.")}, - sub(["category", "message"], warnings[0])) - - - def test_getClient(self): - """ - L{Request.getClient} is deprecated in favor of resolving the hostname - in application code. - """ - channel = DummyChannel() - request = http.Request(channel, True) - request.gotLength(123) - request.requestReceived(b"GET", b"/", b"HTTP/1.1") - expected = channel.transport.getPeer().host - self.assertEqual(expected, request.getClient()) - warnings = self.flushWarnings( - offendingFunctions=[self.test_getClient]) - - self.assertEqual({ - "category": DeprecationWarning, - "message": ( - "twisted.web.http.Request.getClient was deprecated " - "in Twisted 15.0.0; please use Twisted Names to " - "resolve hostnames instead")}, - sub(["category", "message"], warnings[0])) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_http_headers.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_http_headers.py deleted file mode 100644 index 7a12a06..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_http_headers.py +++ /dev/null @@ -1,629 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.http_headers}. -""" - -from __future__ import division, absolute_import - -from twisted.python.compat import _PY3 -from twisted.trial.unittest import TestCase -from twisted.web.http_headers import _DictHeaders, Headers - -class HeadersTests(TestCase): - """ - Tests for L{Headers}. - """ - def test_initializer(self): - """ - The header values passed to L{Headers.__init__} can be retrieved via - L{Headers.getRawHeaders}. - """ - h = Headers({b'Foo': [b'bar']}) - self.assertEqual(h.getRawHeaders(b'foo'), [b'bar']) - - - def test_setRawHeaders(self): - """ - L{Headers.setRawHeaders} sets the header values for the given - header name to the sequence of byte string values. - """ - rawValue = [b"value1", b"value2"] - h = Headers() - h.setRawHeaders(b"test", rawValue) - self.assertTrue(h.hasHeader(b"test")) - self.assertTrue(h.hasHeader(b"Test")) - self.assertEqual(h.getRawHeaders(b"test"), rawValue) - - - def test_rawHeadersTypeChecking(self): - """ - L{Headers.setRawHeaders} requires values to be of type list. - """ - h = Headers() - self.assertRaises(TypeError, h.setRawHeaders, {b'Foo': b'bar'}) - - - def test_addRawHeader(self): - """ - L{Headers.addRawHeader} adds a new value for a given header. - """ - h = Headers() - h.addRawHeader(b"test", b"lemur") - self.assertEqual(h.getRawHeaders(b"test"), [b"lemur"]) - h.addRawHeader(b"test", b"panda") - self.assertEqual(h.getRawHeaders(b"test"), [b"lemur", b"panda"]) - - - def test_getRawHeadersNoDefault(self): - """ - L{Headers.getRawHeaders} returns C{None} if the header is not found and - no default is specified. - """ - self.assertIdentical(Headers().getRawHeaders(b"test"), None) - - - def test_getRawHeadersDefaultValue(self): - """ - L{Headers.getRawHeaders} returns the specified default value when no - header is found. - """ - h = Headers() - default = object() - self.assertIdentical(h.getRawHeaders(b"test", default), default) - - - def test_getRawHeaders(self): - """ - L{Headers.getRawHeaders} returns the values which have been set for a - given header. - """ - h = Headers() - h.setRawHeaders(b"test", [b"lemur"]) - self.assertEqual(h.getRawHeaders(b"test"), [b"lemur"]) - self.assertEqual(h.getRawHeaders(b"Test"), [b"lemur"]) - - - def test_hasHeaderTrue(self): - """ - Check that L{Headers.hasHeader} returns C{True} when the given header - is found. - """ - h = Headers() - h.setRawHeaders(b"test", [b"lemur"]) - self.assertTrue(h.hasHeader(b"test")) - self.assertTrue(h.hasHeader(b"Test")) - - - def test_hasHeaderFalse(self): - """ - L{Headers.hasHeader} returns C{False} when the given header is not - found. - """ - self.assertFalse(Headers().hasHeader(b"test")) - - - def test_removeHeader(self): - """ - Check that L{Headers.removeHeader} removes the given header. - """ - h = Headers() - - h.setRawHeaders(b"foo", [b"lemur"]) - self.assertTrue(h.hasHeader(b"foo")) - h.removeHeader(b"foo") - self.assertFalse(h.hasHeader(b"foo")) - - h.setRawHeaders(b"bar", [b"panda"]) - self.assertTrue(h.hasHeader(b"bar")) - h.removeHeader(b"Bar") - self.assertFalse(h.hasHeader(b"bar")) - - - def test_removeHeaderDoesntExist(self): - """ - L{Headers.removeHeader} is a no-operation when the specified header is - not found. - """ - h = Headers() - h.removeHeader(b"test") - self.assertEqual(list(h.getAllRawHeaders()), []) - - - def test_canonicalNameCaps(self): - """ - L{Headers._canonicalNameCaps} returns the canonical capitalization for - the given header. - """ - h = Headers() - self.assertEqual(h._canonicalNameCaps(b"test"), b"Test") - self.assertEqual(h._canonicalNameCaps(b"test-stuff"), b"Test-Stuff") - self.assertEqual(h._canonicalNameCaps(b"content-md5"), b"Content-MD5") - self.assertEqual(h._canonicalNameCaps(b"dnt"), b"DNT") - self.assertEqual(h._canonicalNameCaps(b"etag"), b"ETag") - self.assertEqual(h._canonicalNameCaps(b"p3p"), b"P3P") - self.assertEqual(h._canonicalNameCaps(b"te"), b"TE") - self.assertEqual(h._canonicalNameCaps(b"www-authenticate"), - b"WWW-Authenticate") - self.assertEqual(h._canonicalNameCaps(b"x-xss-protection"), - b"X-XSS-Protection") - - - def test_getAllRawHeaders(self): - """ - L{Headers.getAllRawHeaders} returns an iterable of (k, v) pairs, where - C{k} is the canonicalized representation of the header name, and C{v} - is a sequence of values. - """ - h = Headers() - h.setRawHeaders(b"test", [b"lemurs"]) - h.setRawHeaders(b"www-authenticate", [b"basic aksljdlk="]) - - allHeaders = set([(k, tuple(v)) for k, v in h.getAllRawHeaders()]) - - self.assertEqual(allHeaders, - set([(b"WWW-Authenticate", (b"basic aksljdlk=",)), - (b"Test", (b"lemurs",))])) - - - def test_headersComparison(self): - """ - A L{Headers} instance compares equal to itself and to another - L{Headers} instance with the same values. - """ - first = Headers() - first.setRawHeaders(b"foo", [b"panda"]) - second = Headers() - second.setRawHeaders(b"foo", [b"panda"]) - third = Headers() - third.setRawHeaders(b"foo", [b"lemur", b"panda"]) - self.assertEqual(first, first) - self.assertEqual(first, second) - self.assertNotEqual(first, third) - - - def test_otherComparison(self): - """ - An instance of L{Headers} does not compare equal to other unrelated - objects. - """ - h = Headers() - self.assertNotEqual(h, ()) - self.assertNotEqual(h, object()) - self.assertNotEqual(h, b"foo") - - - def test_repr(self): - """ - The L{repr} of a L{Headers} instance shows the names and values of all - the headers it contains. - """ - foo = b"foo" - bar = b"bar" - baz = b"baz" - self.assertEqual( - repr(Headers({foo: [bar, baz]})), - "Headers({%r: [%r, %r]})" % (foo, bar, baz)) - - - def test_subclassRepr(self): - """ - The L{repr} of an instance of a subclass of L{Headers} uses the name - of the subclass instead of the string C{"Headers"}. - """ - foo = b"foo" - bar = b"bar" - baz = b"baz" - class FunnyHeaders(Headers): - pass - self.assertEqual( - repr(FunnyHeaders({foo: [bar, baz]})), - "FunnyHeaders({%r: [%r, %r]})" % (foo, bar, baz)) - - - def test_copy(self): - """ - L{Headers.copy} creates a new independant copy of an existing - L{Headers} instance, allowing future modifications without impacts - between the copies. - """ - h = Headers() - h.setRawHeaders(b'test', [b'foo']) - i = h.copy() - self.assertEqual(i.getRawHeaders(b'test'), [b'foo']) - h.addRawHeader(b'test', b'bar') - self.assertEqual(i.getRawHeaders(b'test'), [b'foo']) - i.addRawHeader(b'test', b'baz') - self.assertEqual(h.getRawHeaders(b'test'), [b'foo', b'bar']) - - - -class HeaderDictTests(TestCase): - """ - Tests for the backwards compatible C{dict} interface for L{Headers} - provided by L{_DictHeaders}. - """ - def headers(self, **kw): - """ - Create a L{Headers} instance populated with the header name/values - specified by C{kw} and a L{_DictHeaders} wrapped around it and return - them both. - """ - h = Headers() - for k, v in kw.items(): - h.setRawHeaders(k.encode('ascii'), v) - return h, _DictHeaders(h) - - - def test_getItem(self): - """ - L{_DictHeaders.__getitem__} returns a single header for the given name. - """ - headers, wrapper = self.headers(test=[b"lemur"]) - self.assertEqual(wrapper[b"test"], b"lemur") - - - def test_getItemMultiple(self): - """ - L{_DictHeaders.__getitem__} returns only the last header value for a - given name. - """ - headers, wrapper = self.headers(test=[b"lemur", b"panda"]) - self.assertEqual(wrapper[b"test"], b"panda") - - - def test_getItemMissing(self): - """ - L{_DictHeaders.__getitem__} raises L{KeyError} if called with a header - which is not present. - """ - headers, wrapper = self.headers() - exc = self.assertRaises(KeyError, wrapper.__getitem__, b"test") - self.assertEqual(exc.args, (b"test",)) - - - def test_iteration(self): - """ - L{_DictHeaders.__iter__} returns an iterator the elements of which - are the lowercase name of each header present. - """ - headers, wrapper = self.headers(foo=[b"lemur", b"panda"], bar=[b"baz"]) - self.assertEqual(set(list(wrapper)), set([b"foo", b"bar"])) - - - def test_length(self): - """ - L{_DictHeaders.__len__} returns the number of headers present. - """ - headers, wrapper = self.headers() - self.assertEqual(len(wrapper), 0) - headers.setRawHeaders(b"foo", [b"bar"]) - self.assertEqual(len(wrapper), 1) - headers.setRawHeaders(b"test", [b"lemur", b"panda"]) - self.assertEqual(len(wrapper), 2) - - - def test_setItem(self): - """ - L{_DictHeaders.__setitem__} sets a single header value for the given - name. - """ - headers, wrapper = self.headers() - wrapper[b"test"] = b"lemur" - self.assertEqual(headers.getRawHeaders(b"test"), [b"lemur"]) - - - def test_setItemOverwrites(self): - """ - L{_DictHeaders.__setitem__} will replace any previous header values for - the given name. - """ - headers, wrapper = self.headers(test=[b"lemur", b"panda"]) - wrapper[b"test"] = b"lemur" - self.assertEqual(headers.getRawHeaders(b"test"), [b"lemur"]) - - - def test_delItem(self): - """ - L{_DictHeaders.__delitem__} will remove the header values for the given - name. - """ - headers, wrapper = self.headers(test=[b"lemur"]) - del wrapper[b"test"] - self.assertFalse(headers.hasHeader(b"test")) - - - def test_delItemMissing(self): - """ - L{_DictHeaders.__delitem__} will raise L{KeyError} if the given name is - not present. - """ - headers, wrapper = self.headers() - exc = self.assertRaises(KeyError, wrapper.__delitem__, b"test") - self.assertEqual(exc.args, (b"test",)) - - - def test_keys(self, _method='keys', _requireList=not _PY3): - """ - L{_DictHeaders.keys} will return a list of all present header names. - """ - headers, wrapper = self.headers(test=[b"lemur"], foo=[b"bar"]) - keys = getattr(wrapper, _method)() - if _requireList: - self.assertIsInstance(keys, list) - self.assertEqual(set(keys), set([b"foo", b"test"])) - - - def test_iterkeys(self): - """ - L{_DictHeaders.iterkeys} will return all present header names. - """ - self.test_keys('iterkeys', False) - - - def test_values(self, _method='values', _requireList=not _PY3): - """ - L{_DictHeaders.values} will return a list of all present header values, - returning only the last value for headers with more than one. - """ - headers, wrapper = self.headers( - foo=[b"lemur"], bar=[b"marmot", b"panda"]) - values = getattr(wrapper, _method)() - if _requireList: - self.assertIsInstance(values, list) - self.assertEqual(set(values), set([b"lemur", b"panda"])) - - - def test_itervalues(self): - """ - L{_DictHeaders.itervalues} will return all present header values, - returning only the last value for headers with more than one. - """ - self.test_values('itervalues', False) - - - def test_items(self, _method='items', _requireList=not _PY3): - """ - L{_DictHeaders.items} will return a list of all present header names - and values as tuples, returning only the last value for headers with - more than one. - """ - headers, wrapper = self.headers( - foo=[b"lemur"], bar=[b"marmot", b"panda"]) - items = getattr(wrapper, _method)() - if _requireList: - self.assertIsInstance(items, list) - self.assertEqual( - set(items), set([(b"foo", b"lemur"), (b"bar", b"panda")])) - - - def test_iteritems(self): - """ - L{_DictHeaders.iteritems} will return all present header names and - values as tuples, returning only the last value for headers with more - than one. - """ - self.test_items('iteritems', False) - - - def test_clear(self): - """ - L{_DictHeaders.clear} will remove all headers. - """ - headers, wrapper = self.headers(foo=[b"lemur"], bar=[b"panda"]) - wrapper.clear() - self.assertEqual(list(headers.getAllRawHeaders()), []) - - - def test_copy(self): - """ - L{_DictHeaders.copy} will return a C{dict} with all the same headers - and the last value for each. - """ - headers, wrapper = self.headers( - foo=[b"lemur", b"panda"], bar=[b"marmot"]) - duplicate = wrapper.copy() - self.assertEqual(duplicate, {b"foo": b"panda", b"bar": b"marmot"}) - - - def test_get(self): - """ - L{_DictHeaders.get} returns the last value for the given header name. - """ - headers, wrapper = self.headers(foo=[b"lemur", b"panda"]) - self.assertEqual(wrapper.get(b"foo"), b"panda") - - - def test_getMissing(self): - """ - L{_DictHeaders.get} returns C{None} for a header which is not present. - """ - headers, wrapper = self.headers() - self.assertIdentical(wrapper.get(b"foo"), None) - - - def test_getDefault(self): - """ - L{_DictHeaders.get} returns the last value for the given header name - even when it is invoked with a default value. - """ - headers, wrapper = self.headers(foo=[b"lemur"]) - self.assertEqual(wrapper.get(b"foo", b"bar"), b"lemur") - - - def test_getDefaultMissing(self): - """ - L{_DictHeaders.get} returns the default value specified if asked for a - header which is not present. - """ - headers, wrapper = self.headers() - self.assertEqual(wrapper.get(b"foo", b"bar"), b"bar") - - - def test_has_key(self): - """ - L{_DictHeaders.has_key} returns C{True} if the given header is present, - C{False} otherwise. - """ - headers, wrapper = self.headers(foo=[b"lemur"]) - self.assertTrue(wrapper.has_key(b"foo")) - self.assertFalse(wrapper.has_key(b"bar")) - - - def test_contains(self): - """ - L{_DictHeaders.__contains__} returns C{True} if the given header is - present, C{False} otherwise. - """ - headers, wrapper = self.headers(foo=[b"lemur"]) - self.assertIn(b"foo", wrapper) - self.assertNotIn(b"bar", wrapper) - - - def test_pop(self): - """ - L{_DictHeaders.pop} returns the last header value associated with the - given header name and removes the header. - """ - headers, wrapper = self.headers(foo=[b"lemur", b"panda"]) - self.assertEqual(wrapper.pop(b"foo"), b"panda") - self.assertIdentical(headers.getRawHeaders(b"foo"), None) - - - def test_popMissing(self): - """ - L{_DictHeaders.pop} raises L{KeyError} if passed a header name which is - not present. - """ - headers, wrapper = self.headers() - self.assertRaises(KeyError, wrapper.pop, b"foo") - - - def test_popDefault(self): - """ - L{_DictHeaders.pop} returns the last header value associated with the - given header name and removes the header, even if it is supplied with a - default value. - """ - headers, wrapper = self.headers(foo=[b"lemur"]) - self.assertEqual(wrapper.pop(b"foo", b"bar"), b"lemur") - self.assertIdentical(headers.getRawHeaders(b"foo"), None) - - - def test_popDefaultMissing(self): - """ - L{_DictHeaders.pop} returns the default value is asked for a header - name which is not present. - """ - headers, wrapper = self.headers(foo=[b"lemur"]) - self.assertEqual(wrapper.pop(b"bar", b"baz"), b"baz") - self.assertEqual(headers.getRawHeaders(b"foo"), [b"lemur"]) - - - def test_popitem(self): - """ - L{_DictHeaders.popitem} returns some header name/value pair. - """ - headers, wrapper = self.headers(foo=[b"lemur", b"panda"]) - self.assertEqual(wrapper.popitem(), (b"foo", b"panda")) - self.assertIdentical(headers.getRawHeaders(b"foo"), None) - - - def test_popitemEmpty(self): - """ - L{_DictHeaders.popitem} raises L{KeyError} if there are no headers - present. - """ - headers, wrapper = self.headers() - self.assertRaises(KeyError, wrapper.popitem) - - - def test_update(self): - """ - L{_DictHeaders.update} adds the header/value pairs in the C{dict} it is - passed, overriding any existing values for those headers. - """ - headers, wrapper = self.headers(foo=[b"lemur"]) - wrapper.update({b"foo": b"panda", b"bar": b"marmot"}) - self.assertEqual(headers.getRawHeaders(b"foo"), [b"panda"]) - self.assertEqual(headers.getRawHeaders(b"bar"), [b"marmot"]) - - - def test_updateWithKeywords(self): - """ - L{_DictHeaders.update} adds header names given as keyword arguments - with the keyword values as the header value. - """ - headers, wrapper = self.headers(foo=[b"lemur"]) - wrapper.update(foo=b"panda", bar=b"marmot") - self.assertEqual(headers.getRawHeaders(b"foo"), [b"panda"]) - self.assertEqual(headers.getRawHeaders(b"bar"), [b"marmot"]) - - if _PY3: - test_updateWithKeywords.skip = "Not yet supported on Python 3; see #6082." - - - def test_setdefaultMissing(self): - """ - If passed the name of a header which is not present, - L{_DictHeaders.setdefault} sets the value of the given header to the - specified default value and returns it. - """ - headers, wrapper = self.headers(foo=[b"bar"]) - self.assertEqual(wrapper.setdefault(b"baz", b"quux"), b"quux") - self.assertEqual(headers.getRawHeaders(b"foo"), [b"bar"]) - self.assertEqual(headers.getRawHeaders(b"baz"), [b"quux"]) - - - def test_setdefaultPresent(self): - """ - If passed the name of a header which is present, - L{_DictHeaders.setdefault} makes no changes to the headers and - returns the last value already associated with that header. - """ - headers, wrapper = self.headers(foo=[b"bar", b"baz"]) - self.assertEqual(wrapper.setdefault(b"foo", b"quux"), b"baz") - self.assertEqual(headers.getRawHeaders(b"foo"), [b"bar", b"baz"]) - - - def test_setdefaultDefault(self): - """ - If a value is not passed to L{_DictHeaders.setdefault}, C{None} is - used. - """ - # This results in an invalid state for the headers, but maybe some - # application is doing this an intermediate step towards some other - # state. Anyway, it was broken with the old implementation so it's - # broken with the new implementation. Compatibility, for the win. - # -exarkun - headers, wrapper = self.headers() - self.assertIdentical(wrapper.setdefault(b"foo"), None) - self.assertEqual(headers.getRawHeaders(b"foo"), [None]) - - - def test_dictComparison(self): - """ - An instance of L{_DictHeaders} compares equal to a C{dict} which - contains the same header/value pairs. For header names with multiple - values, the last value only is considered. - """ - headers, wrapper = self.headers(foo=[b"lemur"], bar=[b"panda", b"marmot"]) - self.assertNotEqual(wrapper, {b"foo": b"lemur", b"bar": b"panda"}) - self.assertEqual(wrapper, {b"foo": b"lemur", b"bar": b"marmot"}) - - - def test_otherComparison(self): - """ - An instance of L{_DictHeaders} does not compare equal to other - unrelated objects. - """ - headers, wrapper = self.headers() - self.assertNotEqual(wrapper, ()) - self.assertNotEqual(wrapper, object()) - self.assertNotEqual(wrapper, b"foo") - - if _PY3: - # Python 3 lacks these APIs - del test_iterkeys, test_itervalues, test_iteritems, test_has_key - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_httpauth.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_httpauth.py deleted file mode 100644 index ee7f443..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_httpauth.py +++ /dev/null @@ -1,634 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web._auth}. -""" - - -from zope.interface import implements -from zope.interface.verify import verifyObject - -from twisted.trial import unittest - -from twisted.python.failure import Failure -from twisted.internet.error import ConnectionDone -from twisted.internet.address import IPv4Address - -from twisted.cred import error, portal -from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse -from twisted.cred.checkers import ANONYMOUS, AllowAnonymousAccess -from twisted.cred.credentials import IUsernamePassword - -from twisted.web.iweb import ICredentialFactory -from twisted.web.resource import IResource, Resource, getChildForRequest -from twisted.web._auth import basic, digest -from twisted.web._auth.wrapper import HTTPAuthSessionWrapper, UnauthorizedResource -from twisted.web._auth.basic import BasicCredentialFactory - -from twisted.web.server import NOT_DONE_YET -from twisted.web.static import Data - -from twisted.web.test.test_web import DummyRequest - - -def b64encode(s): - return s.encode('base64').strip() - - -class BasicAuthTestsMixin: - """ - L{TestCase} mixin class which defines a number of tests for - L{basic.BasicCredentialFactory}. Because this mixin defines C{setUp}, it - must be inherited before L{TestCase}. - """ - def setUp(self): - self.request = self.makeRequest() - self.realm = 'foo' - self.username = 'dreid' - self.password = 'S3CuR1Ty' - self.credentialFactory = basic.BasicCredentialFactory(self.realm) - - - def makeRequest(self, method='GET', clientAddress=None): - """ - Create a request object to be passed to - L{basic.BasicCredentialFactory.decode} along with a response value. - Override this in a subclass. - """ - raise NotImplementedError("%r did not implement makeRequest" % ( - self.__class__,)) - - - def test_interface(self): - """ - L{BasicCredentialFactory} implements L{ICredentialFactory}. - """ - self.assertTrue( - verifyObject(ICredentialFactory, self.credentialFactory)) - - - def test_usernamePassword(self): - """ - L{basic.BasicCredentialFactory.decode} turns a base64-encoded response - into a L{UsernamePassword} object with a password which reflects the - one which was encoded in the response. - """ - response = b64encode('%s:%s' % (self.username, self.password)) - - creds = self.credentialFactory.decode(response, self.request) - self.assertTrue(IUsernamePassword.providedBy(creds)) - self.assertTrue(creds.checkPassword(self.password)) - self.assertFalse(creds.checkPassword(self.password + 'wrong')) - - - def test_incorrectPadding(self): - """ - L{basic.BasicCredentialFactory.decode} decodes a base64-encoded - response with incorrect padding. - """ - response = b64encode('%s:%s' % (self.username, self.password)) - response = response.strip('=') - - creds = self.credentialFactory.decode(response, self.request) - self.assertTrue(verifyObject(IUsernamePassword, creds)) - self.assertTrue(creds.checkPassword(self.password)) - - - def test_invalidEncoding(self): - """ - L{basic.BasicCredentialFactory.decode} raises L{LoginFailed} if passed - a response which is not base64-encoded. - """ - response = 'x' # one byte cannot be valid base64 text - self.assertRaises( - error.LoginFailed, - self.credentialFactory.decode, response, self.makeRequest()) - - - def test_invalidCredentials(self): - """ - L{basic.BasicCredentialFactory.decode} raises L{LoginFailed} when - passed a response which is not valid base64-encoded text. - """ - response = b64encode('123abc+/') - self.assertRaises( - error.LoginFailed, - self.credentialFactory.decode, - response, self.makeRequest()) - - -class RequestMixin: - def makeRequest(self, method='GET', clientAddress=None): - """ - Create a L{DummyRequest} (change me to create a - L{twisted.web.http.Request} instead). - """ - request = DummyRequest('/') - request.method = method - request.client = clientAddress - return request - - - -class BasicAuthTests(RequestMixin, BasicAuthTestsMixin, unittest.TestCase): - """ - Basic authentication tests which use L{twisted.web.http.Request}. - """ - - - -class DigestAuthTests(RequestMixin, unittest.TestCase): - """ - Digest authentication tests which use L{twisted.web.http.Request}. - """ - - def setUp(self): - """ - Create a DigestCredentialFactory for testing - """ - self.realm = "test realm" - self.algorithm = "md5" - self.credentialFactory = digest.DigestCredentialFactory( - self.algorithm, self.realm) - self.request = self.makeRequest() - - - def test_decode(self): - """ - L{digest.DigestCredentialFactory.decode} calls the C{decode} method on - L{twisted.cred.digest.DigestCredentialFactory} with the HTTP method and - host of the request. - """ - host = '169.254.0.1' - method = 'GET' - done = [False] - response = object() - def check(_response, _method, _host): - self.assertEqual(response, _response) - self.assertEqual(method, _method) - self.assertEqual(host, _host) - done[0] = True - - self.patch(self.credentialFactory.digest, 'decode', check) - req = self.makeRequest(method, IPv4Address('TCP', host, 81)) - self.credentialFactory.decode(response, req) - self.assertTrue(done[0]) - - - def test_interface(self): - """ - L{DigestCredentialFactory} implements L{ICredentialFactory}. - """ - self.assertTrue( - verifyObject(ICredentialFactory, self.credentialFactory)) - - - def test_getChallenge(self): - """ - The challenge issued by L{DigestCredentialFactory.getChallenge} must - include C{'qop'}, C{'realm'}, C{'algorithm'}, C{'nonce'}, and - C{'opaque'} keys. The values for the C{'realm'} and C{'algorithm'} - keys must match the values supplied to the factory's initializer. - None of the values may have newlines in them. - """ - challenge = self.credentialFactory.getChallenge(self.request) - self.assertEqual(challenge['qop'], 'auth') - self.assertEqual(challenge['realm'], 'test realm') - self.assertEqual(challenge['algorithm'], 'md5') - self.assertIn('nonce', challenge) - self.assertIn('opaque', challenge) - for v in challenge.values(): - self.assertNotIn('\n', v) - - - def test_getChallengeWithoutClientIP(self): - """ - L{DigestCredentialFactory.getChallenge} can issue a challenge even if - the L{Request} it is passed returns C{None} from C{getClientIP}. - """ - request = self.makeRequest('GET', None) - challenge = self.credentialFactory.getChallenge(request) - self.assertEqual(challenge['qop'], 'auth') - self.assertEqual(challenge['realm'], 'test realm') - self.assertEqual(challenge['algorithm'], 'md5') - self.assertIn('nonce', challenge) - self.assertIn('opaque', challenge) - - - -class UnauthorizedResourceTests(unittest.TestCase): - """ - Tests for L{UnauthorizedResource}. - """ - def test_getChildWithDefault(self): - """ - An L{UnauthorizedResource} is every child of itself. - """ - resource = UnauthorizedResource([]) - self.assertIdentical( - resource.getChildWithDefault("foo", None), resource) - self.assertIdentical( - resource.getChildWithDefault("bar", None), resource) - - - def _unauthorizedRenderTest(self, request): - """ - Render L{UnauthorizedResource} for the given request object and verify - that the response code is I{Unauthorized} and that a I{WWW-Authenticate} - header is set in the response containing a challenge. - """ - resource = UnauthorizedResource([ - BasicCredentialFactory('example.com')]) - request.render(resource) - self.assertEqual(request.responseCode, 401) - self.assertEqual( - request.responseHeaders.getRawHeaders('www-authenticate'), - ['basic realm="example.com"']) - - - def test_render(self): - """ - L{UnauthorizedResource} renders with a 401 response code and a - I{WWW-Authenticate} header and puts a simple unauthorized message - into the response body. - """ - request = DummyRequest(['']) - self._unauthorizedRenderTest(request) - self.assertEqual('Unauthorized', ''.join(request.written)) - - - def test_renderHEAD(self): - """ - The rendering behavior of L{UnauthorizedResource} for a I{HEAD} request - is like its handling of a I{GET} request, but no response body is - written. - """ - request = DummyRequest(['']) - request.method = 'HEAD' - self._unauthorizedRenderTest(request) - self.assertEqual('', ''.join(request.written)) - - - def test_renderQuotesRealm(self): - """ - The realm value included in the I{WWW-Authenticate} header set in - the response when L{UnauthorizedResounrce} is rendered has quotes - and backslashes escaped. - """ - resource = UnauthorizedResource([ - BasicCredentialFactory('example\\"foo')]) - request = DummyRequest(['']) - request.render(resource) - self.assertEqual( - request.responseHeaders.getRawHeaders('www-authenticate'), - ['basic realm="example\\\\\\"foo"']) - - - -class Realm(object): - """ - A simple L{IRealm} implementation which gives out L{WebAvatar} for any - avatarId. - - @type loggedIn: C{int} - @ivar loggedIn: The number of times C{requestAvatar} has been invoked for - L{IResource}. - - @type loggedOut: C{int} - @ivar loggedOut: The number of times the logout callback has been invoked. - """ - implements(portal.IRealm) - - def __init__(self, avatarFactory): - self.loggedOut = 0 - self.loggedIn = 0 - self.avatarFactory = avatarFactory - - - def requestAvatar(self, avatarId, mind, *interfaces): - if IResource in interfaces: - self.loggedIn += 1 - return IResource, self.avatarFactory(avatarId), self.logout - raise NotImplementedError() - - - def logout(self): - self.loggedOut += 1 - - - -class HTTPAuthHeaderTests(unittest.TestCase): - """ - Tests for L{HTTPAuthSessionWrapper}. - """ - makeRequest = DummyRequest - - def setUp(self): - """ - Create a realm, portal, and L{HTTPAuthSessionWrapper} to use in the tests. - """ - self.username = 'foo bar' - self.password = 'bar baz' - self.avatarContent = "contents of the avatar resource itself" - self.childName = "foo-child" - self.childContent = "contents of the foo child of the avatar" - self.checker = InMemoryUsernamePasswordDatabaseDontUse() - self.checker.addUser(self.username, self.password) - self.avatar = Data(self.avatarContent, 'text/plain') - self.avatar.putChild( - self.childName, Data(self.childContent, 'text/plain')) - self.avatars = {self.username: self.avatar} - self.realm = Realm(self.avatars.get) - self.portal = portal.Portal(self.realm, [self.checker]) - self.credentialFactories = [] - self.wrapper = HTTPAuthSessionWrapper( - self.portal, self.credentialFactories) - - - def _authorizedBasicLogin(self, request): - """ - Add an I{basic authorization} header to the given request and then - dispatch it, starting from C{self.wrapper} and returning the resulting - L{IResource}. - """ - authorization = b64encode(self.username + ':' + self.password) - request.headers['authorization'] = 'Basic ' + authorization - return getChildForRequest(self.wrapper, request) - - - def test_getChildWithDefault(self): - """ - Resource traversal which encounters an L{HTTPAuthSessionWrapper} - results in an L{UnauthorizedResource} instance when the request does - not have the required I{Authorization} headers. - """ - request = self.makeRequest([self.childName]) - child = getChildForRequest(self.wrapper, request) - d = request.notifyFinish() - def cbFinished(result): - self.assertEqual(request.responseCode, 401) - d.addCallback(cbFinished) - request.render(child) - return d - - - def _invalidAuthorizationTest(self, response): - """ - Create a request with the given value as the value of an - I{Authorization} header and perform resource traversal with it, - starting at C{self.wrapper}. Assert that the result is a 401 response - code. Return a L{Deferred} which fires when this is all done. - """ - self.credentialFactories.append(BasicCredentialFactory('example.com')) - request = self.makeRequest([self.childName]) - request.headers['authorization'] = response - child = getChildForRequest(self.wrapper, request) - d = request.notifyFinish() - def cbFinished(result): - self.assertEqual(request.responseCode, 401) - d.addCallback(cbFinished) - request.render(child) - return d - - - def test_getChildWithDefaultUnauthorizedUser(self): - """ - Resource traversal which enouncters an L{HTTPAuthSessionWrapper} - results in an L{UnauthorizedResource} when the request has an - I{Authorization} header with a user which does not exist. - """ - return self._invalidAuthorizationTest('Basic ' + b64encode('foo:bar')) - - - def test_getChildWithDefaultUnauthorizedPassword(self): - """ - Resource traversal which enouncters an L{HTTPAuthSessionWrapper} - results in an L{UnauthorizedResource} when the request has an - I{Authorization} header with a user which exists and the wrong - password. - """ - return self._invalidAuthorizationTest( - 'Basic ' + b64encode(self.username + ':bar')) - - - def test_getChildWithDefaultUnrecognizedScheme(self): - """ - Resource traversal which enouncters an L{HTTPAuthSessionWrapper} - results in an L{UnauthorizedResource} when the request has an - I{Authorization} header with an unrecognized scheme. - """ - return self._invalidAuthorizationTest('Quux foo bar baz') - - - def test_getChildWithDefaultAuthorized(self): - """ - Resource traversal which encounters an L{HTTPAuthSessionWrapper} - results in an L{IResource} which renders the L{IResource} avatar - retrieved from the portal when the request has a valid I{Authorization} - header. - """ - self.credentialFactories.append(BasicCredentialFactory('example.com')) - request = self.makeRequest([self.childName]) - child = self._authorizedBasicLogin(request) - d = request.notifyFinish() - def cbFinished(ignored): - self.assertEqual(request.written, [self.childContent]) - d.addCallback(cbFinished) - request.render(child) - return d - - - def test_renderAuthorized(self): - """ - Resource traversal which terminates at an L{HTTPAuthSessionWrapper} - and includes correct authentication headers results in the - L{IResource} avatar (not one of its children) retrieved from the - portal being rendered. - """ - self.credentialFactories.append(BasicCredentialFactory('example.com')) - # Request it exactly, not any of its children. - request = self.makeRequest([]) - child = self._authorizedBasicLogin(request) - d = request.notifyFinish() - def cbFinished(ignored): - self.assertEqual(request.written, [self.avatarContent]) - d.addCallback(cbFinished) - request.render(child) - return d - - - def test_getChallengeCalledWithRequest(self): - """ - When L{HTTPAuthSessionWrapper} finds an L{ICredentialFactory} to issue - a challenge, it calls the C{getChallenge} method with the request as an - argument. - """ - class DumbCredentialFactory(object): - implements(ICredentialFactory) - scheme = 'dumb' - - def __init__(self): - self.requests = [] - - def getChallenge(self, request): - self.requests.append(request) - return {} - - factory = DumbCredentialFactory() - self.credentialFactories.append(factory) - request = self.makeRequest([self.childName]) - child = getChildForRequest(self.wrapper, request) - d = request.notifyFinish() - def cbFinished(ignored): - self.assertEqual(factory.requests, [request]) - d.addCallback(cbFinished) - request.render(child) - return d - - - def _logoutTest(self): - """ - Issue a request for an authentication-protected resource using valid - credentials and then return the C{DummyRequest} instance which was - used. - - This is a helper for tests about the behavior of the logout - callback. - """ - self.credentialFactories.append(BasicCredentialFactory('example.com')) - - class SlowerResource(Resource): - def render(self, request): - return NOT_DONE_YET - - self.avatar.putChild(self.childName, SlowerResource()) - request = self.makeRequest([self.childName]) - child = self._authorizedBasicLogin(request) - request.render(child) - self.assertEqual(self.realm.loggedOut, 0) - return request - - - def test_logout(self): - """ - The realm's logout callback is invoked after the resource is rendered. - """ - request = self._logoutTest() - request.finish() - self.assertEqual(self.realm.loggedOut, 1) - - - def test_logoutOnError(self): - """ - The realm's logout callback is also invoked if there is an error - generating the response (for example, if the client disconnects - early). - """ - request = self._logoutTest() - request.processingFailed( - Failure(ConnectionDone("Simulated disconnect"))) - self.assertEqual(self.realm.loggedOut, 1) - - - def test_decodeRaises(self): - """ - Resource traversal which enouncters an L{HTTPAuthSessionWrapper} - results in an L{UnauthorizedResource} when the request has a I{Basic - Authorization} header which cannot be decoded using base64. - """ - self.credentialFactories.append(BasicCredentialFactory('example.com')) - request = self.makeRequest([self.childName]) - request.headers['authorization'] = 'Basic decode should fail' - child = getChildForRequest(self.wrapper, request) - self.assertIsInstance(child, UnauthorizedResource) - - - def test_selectParseResponse(self): - """ - L{HTTPAuthSessionWrapper._selectParseHeader} returns a two-tuple giving - the L{ICredentialFactory} to use to parse the header and a string - containing the portion of the header which remains to be parsed. - """ - basicAuthorization = 'Basic abcdef123456' - self.assertEqual( - self.wrapper._selectParseHeader(basicAuthorization), - (None, None)) - factory = BasicCredentialFactory('example.com') - self.credentialFactories.append(factory) - self.assertEqual( - self.wrapper._selectParseHeader(basicAuthorization), - (factory, 'abcdef123456')) - - - def test_unexpectedDecodeError(self): - """ - Any unexpected exception raised by the credential factory's C{decode} - method results in a 500 response code and causes the exception to be - logged. - """ - class UnexpectedException(Exception): - pass - - class BadFactory(object): - scheme = 'bad' - - def getChallenge(self, client): - return {} - - def decode(self, response, request): - raise UnexpectedException() - - self.credentialFactories.append(BadFactory()) - request = self.makeRequest([self.childName]) - request.headers['authorization'] = 'Bad abc' - child = getChildForRequest(self.wrapper, request) - request.render(child) - self.assertEqual(request.responseCode, 500) - self.assertEqual(len(self.flushLoggedErrors(UnexpectedException)), 1) - - - def test_unexpectedLoginError(self): - """ - Any unexpected failure from L{Portal.login} results in a 500 response - code and causes the failure to be logged. - """ - class UnexpectedException(Exception): - pass - - class BrokenChecker(object): - credentialInterfaces = (IUsernamePassword,) - - def requestAvatarId(self, credentials): - raise UnexpectedException() - - self.portal.registerChecker(BrokenChecker()) - self.credentialFactories.append(BasicCredentialFactory('example.com')) - request = self.makeRequest([self.childName]) - child = self._authorizedBasicLogin(request) - request.render(child) - self.assertEqual(request.responseCode, 500) - self.assertEqual(len(self.flushLoggedErrors(UnexpectedException)), 1) - - - def test_anonymousAccess(self): - """ - Anonymous requests are allowed if a L{Portal} has an anonymous checker - registered. - """ - unprotectedContents = "contents of the unprotected child resource" - - self.avatars[ANONYMOUS] = Resource() - self.avatars[ANONYMOUS].putChild( - self.childName, Data(unprotectedContents, 'text/plain')) - self.portal.registerChecker(AllowAnonymousAccess()) - - self.credentialFactories.append(BasicCredentialFactory('example.com')) - request = self.makeRequest([self.childName]) - child = getChildForRequest(self.wrapper, request) - d = request.notifyFinish() - def cbFinished(ignored): - self.assertEqual(request.written, [unprotectedContents]) - d.addCallback(cbFinished) - request.render(child) - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_newclient.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_newclient.py deleted file mode 100644 index 9fbf797..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_newclient.py +++ /dev/null @@ -1,2686 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web._newclient}. -""" - -from __future__ import division, absolute_import -__metaclass__ = type - -from zope.interface import implementer -from zope.interface.verify import verifyObject - -from twisted.python import log -from twisted.python.failure import Failure -from twisted.internet.interfaces import IConsumer, IPushProducer -from twisted.internet.error import ConnectionDone, ConnectionLost -from twisted.internet.defer import Deferred, succeed, fail, CancelledError -from twisted.internet.protocol import Protocol -from twisted.trial.unittest import TestCase -from twisted.test.proto_helpers import StringTransport, AccumulatingProtocol -from twisted.web._newclient import UNKNOWN_LENGTH, STATUS, HEADER, BODY, DONE -from twisted.web._newclient import Request, Response, HTTPParser, HTTPClientParser -from twisted.web._newclient import BadResponseVersion, ParseError, HTTP11ClientProtocol -from twisted.web._newclient import ChunkedEncoder, RequestGenerationFailed -from twisted.web._newclient import RequestTransmissionFailed, ResponseFailed -from twisted.web._newclient import WrongBodyLength, RequestNotSent -from twisted.web._newclient import ConnectionAborted, ResponseNeverReceived -from twisted.web._newclient import BadHeaders, ResponseDone, PotentialDataLoss, ExcessWrite -from twisted.web._newclient import TransportProxyProducer, LengthEnforcingConsumer, makeStatefulDispatcher -from twisted.web.http_headers import Headers -from twisted.web.http import _DataLoss -from twisted.web.iweb import IBodyProducer, IResponse - - - -class StringTransport(StringTransport): - """ - A version of C{StringTransport} that supports C{abortConnection}. - """ - aborting = False - - - def abortConnection(self): - """ - A testable version of the C{ITCPTransport.abortConnection} method. - - Since this is a special case of closing the connection, - C{loseConnection} is also called. - """ - self.aborting = True - self.loseConnection() - - - -class ArbitraryException(Exception): - """ - A unique, arbitrary exception type which L{twisted.web._newclient} knows - nothing about. - """ - - -class AnotherArbitraryException(Exception): - """ - Similar to L{ArbitraryException} but with a different identity. - """ - - -# A re-usable Headers instance for tests which don't really care what headers -# they're sending. -_boringHeaders = Headers({b'host': [b'example.com']}) - - -def assertWrapperExceptionTypes(self, deferred, mainType, reasonTypes): - """ - Assert that the given L{Deferred} fails with the exception given by - C{mainType} and that the exceptions wrapped by the instance of C{mainType} - it fails with match the list of exception types given by C{reasonTypes}. - - This is a helper for testing failures of exceptions which subclass - L{_newclient._WrapperException}. - - @param self: A L{TestCase} instance which will be used to make the - assertions. - - @param deferred: The L{Deferred} which is expected to fail with - C{mainType}. - - @param mainType: A L{_newclient._WrapperException} subclass which will be - trapped on C{deferred}. - - @param reasonTypes: A sequence of exception types which will be trapped on - the resulting C{mainType} exception instance's C{reasons} sequence. - - @return: A L{Deferred} which fires with the C{mainType} instance - C{deferred} fails with, or which fails somehow. - """ - def cbFailed(err): - for reason, type in zip(err.reasons, reasonTypes): - reason.trap(type) - self.assertEqual(len(err.reasons), len(reasonTypes), - "len(%s) != len(%s)" % (err.reasons, reasonTypes)) - return err - d = self.assertFailure(deferred, mainType) - d.addCallback(cbFailed) - return d - - - -def assertResponseFailed(self, deferred, reasonTypes): - """ - A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType} - of L{ResponseFailed}. - """ - return assertWrapperExceptionTypes(self, deferred, ResponseFailed, reasonTypes) - - - -def assertRequestGenerationFailed(self, deferred, reasonTypes): - """ - A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType} - of L{RequestGenerationFailed}. - """ - return assertWrapperExceptionTypes(self, deferred, RequestGenerationFailed, reasonTypes) - - - -def assertRequestTransmissionFailed(self, deferred, reasonTypes): - """ - A simple helper to invoke L{assertWrapperExceptionTypes} with a C{mainType} - of L{RequestTransmissionFailed}. - """ - return assertWrapperExceptionTypes(self, deferred, RequestTransmissionFailed, reasonTypes) - - - -def justTransportResponse(transport): - """ - Helper function for creating a Response which uses the given transport. - All of the other parameters to L{Response.__init__} are filled with - arbitrary values. Only use this method if you don't care about any of - them. - """ - return Response((b'HTTP', 1, 1), 200, b'OK', _boringHeaders, transport) - - - -class MakeStatefulDispatcherTests(TestCase): - """ - Tests for L{makeStatefulDispatcher}. - """ - def test_functionCalledByState(self): - """ - A method defined with L{makeStatefulDispatcher} invokes a second - method based on the current state of the object. - """ - class Foo: - _state = 'A' - - def bar(self): - pass - bar = makeStatefulDispatcher('quux', bar) - - def _quux_A(self): - return 'a' - - def _quux_B(self): - return 'b' - - stateful = Foo() - self.assertEqual(stateful.bar(), 'a') - stateful._state = 'B' - self.assertEqual(stateful.bar(), 'b') - stateful._state = 'C' - self.assertRaises(RuntimeError, stateful.bar) - - - -class _HTTPParserTests(object): - """ - Base test class for L{HTTPParser} which is responsible for the bulk of - the task of parsing HTTP bytes. - """ - sep = None - - def test_statusCallback(self): - """ - L{HTTPParser} calls its C{statusReceived} method when it receives a - status line. - """ - status = [] - protocol = HTTPParser() - protocol.statusReceived = status.append - protocol.makeConnection(StringTransport()) - self.assertEqual(protocol.state, STATUS) - protocol.dataReceived(b'HTTP/1.1 200 OK' + self.sep) - self.assertEqual(status, [b'HTTP/1.1 200 OK']) - self.assertEqual(protocol.state, HEADER) - - - def _headerTestSetup(self): - header = {} - protocol = HTTPParser() - protocol.headerReceived = header.__setitem__ - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK' + self.sep) - return header, protocol - - - def test_headerCallback(self): - """ - L{HTTPParser} calls its C{headerReceived} method when it receives a - header. - """ - header, protocol = self._headerTestSetup() - protocol.dataReceived(b'X-Foo:bar' + self.sep) - # Cannot tell it's not a continue header until the next line arrives - # and is not a continuation - protocol.dataReceived(self.sep) - self.assertEqual(header, {b'X-Foo': b'bar'}) - self.assertEqual(protocol.state, BODY) - - - def test_continuedHeaderCallback(self): - """ - If a header is split over multiple lines, L{HTTPParser} calls - C{headerReceived} with the entire value once it is received. - """ - header, protocol = self._headerTestSetup() - protocol.dataReceived(b'X-Foo: bar' + self.sep) - protocol.dataReceived(b' baz' + self.sep) - protocol.dataReceived(b'\tquux' + self.sep) - protocol.dataReceived(self.sep) - self.assertEqual(header, {b'X-Foo': b'bar baz\tquux'}) - self.assertEqual(protocol.state, BODY) - - - def test_fieldContentWhitespace(self): - """ - Leading and trailing linear whitespace is stripped from the header - value passed to the C{headerReceived} callback. - """ - header, protocol = self._headerTestSetup() - value = self.sep.join([b' \t ', b' bar \t', b' \t', b'']) - protocol.dataReceived(b'X-Bar:' + value) - protocol.dataReceived(b'X-Foo:' + value) - protocol.dataReceived(self.sep) - self.assertEqual(header, {b'X-Foo': b'bar', - b'X-Bar': b'bar'}) - - - def test_allHeadersCallback(self): - """ - After the last header is received, L{HTTPParser} calls - C{allHeadersReceived}. - """ - called = [] - header, protocol = self._headerTestSetup() - def allHeadersReceived(): - called.append(protocol.state) - protocol.state = STATUS - protocol.allHeadersReceived = allHeadersReceived - protocol.dataReceived(self.sep) - self.assertEqual(called, [HEADER]) - self.assertEqual(protocol.state, STATUS) - - - def test_noHeaderCallback(self): - """ - If there are no headers in the message, L{HTTPParser} does not call - C{headerReceived}. - """ - header, protocol = self._headerTestSetup() - protocol.dataReceived(self.sep) - self.assertEqual(header, {}) - self.assertEqual(protocol.state, BODY) - - - def test_headersSavedOnResponse(self): - """ - All headers received by L{HTTPParser} are added to - L{HTTPParser.headers}. - """ - protocol = HTTPParser() - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK' + self.sep) - protocol.dataReceived(b'X-Foo: bar' + self.sep) - protocol.dataReceived(b'X-Foo: baz' + self.sep) - protocol.dataReceived(self.sep) - expected = [(b'X-Foo', [b'bar', b'baz'])] - self.assertEqual(expected, list(protocol.headers.getAllRawHeaders())) - - - def test_connectionControlHeaders(self): - """ - L{HTTPParser.isConnectionControlHeader} returns C{True} for headers - which are always connection control headers (similar to "hop-by-hop" - headers from RFC 2616 section 13.5.1) and C{False} for other headers. - """ - protocol = HTTPParser() - connHeaderNames = [ - b'content-length', b'connection', b'keep-alive', b'te', b'trailers', - b'transfer-encoding', b'upgrade', b'proxy-connection'] - - for header in connHeaderNames: - self.assertTrue( - protocol.isConnectionControlHeader(header), - "Expecting %r to be a connection control header, but " - "wasn't" % (header,)) - self.assertFalse( - protocol.isConnectionControlHeader(b"date"), - "Expecting the arbitrarily selected 'date' header to not be " - "a connection control header, but was.") - - - def test_switchToBodyMode(self): - """ - L{HTTPParser.switchToBodyMode} raises L{RuntimeError} if called more - than once. - """ - protocol = HTTPParser() - protocol.makeConnection(StringTransport()) - protocol.switchToBodyMode(object()) - self.assertRaises(RuntimeError, protocol.switchToBodyMode, object()) - - - -class HTTPParserRFCComplaintDelimeterTests(_HTTPParserTests, TestCase): - """ - L{_HTTPParserTests} using standard CR LF newlines. - """ - sep = b'\r\n' - - - -class HTTPParserNonRFCComplaintDelimeterTests(_HTTPParserTests, TestCase): - """ - L{_HTTPParserTests} using bare LF newlines. - """ - sep = b'\n' - - - -class HTTPClientParserTests(TestCase): - """ - Tests for L{HTTPClientParser} which is responsible for parsing HTTP - response messages. - """ - def test_parseVersion(self): - """ - L{HTTPClientParser.parseVersion} parses a status line into its three - components. - """ - protocol = HTTPClientParser(None, None) - self.assertEqual( - protocol.parseVersion(b'CANDY/7.2'), - (b'CANDY', 7, 2)) - - - def test_parseBadVersion(self): - """ - L{HTTPClientParser.parseVersion} raises L{ValueError} when passed an - unparsable version. - """ - protocol = HTTPClientParser(None, None) - e = BadResponseVersion - f = protocol.parseVersion - - def checkParsing(s): - exc = self.assertRaises(e, f, s) - self.assertEqual(exc.data, s) - - checkParsing(b'foo') - checkParsing(b'foo/bar/baz') - - checkParsing(b'foo/') - checkParsing(b'foo/..') - - checkParsing(b'foo/a.b') - checkParsing(b'foo/-1.-1') - - - def test_responseStatusParsing(self): - """ - L{HTTPClientParser.statusReceived} parses the version, code, and phrase - from the status line and stores them on the response object. - """ - request = Request(b'GET', b'/', _boringHeaders, None) - protocol = HTTPClientParser(request, None) - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - self.assertEqual(protocol.response.version, (b'HTTP', 1, 1)) - self.assertEqual(protocol.response.code, 200) - self.assertEqual(protocol.response.phrase, b'OK') - - - def test_badResponseStatus(self): - """ - L{HTTPClientParser.statusReceived} raises L{ParseError} if it is called - with a status line which cannot be parsed. - """ - protocol = HTTPClientParser(None, None) - - def checkParsing(s): - exc = self.assertRaises(ParseError, protocol.statusReceived, s) - self.assertEqual(exc.data, s) - - # If there are fewer than three whitespace-delimited parts to the - # status line, it is not valid and cannot be parsed. - checkParsing(b'foo') - checkParsing(b'HTTP/1.1 200') - - # If the response code is not an integer, the status line is not valid - # and cannot be parsed. - checkParsing(b'HTTP/1.1 bar OK') - - - def _noBodyTest(self, request, status, response): - """ - Assert that L{HTTPClientParser} parses the given C{response} to - C{request}, resulting in a response with no body and no extra bytes and - leaving the transport in the producing state. - - @param request: A L{Request} instance which might have caused a server - to return the given response. - @param status: A string giving the status line of the response to be - parsed. - @param response: A string giving the response to be parsed. - - @return: A C{dict} of headers from the response. - """ - header = {} - finished = [] - body = [] - bodyDataFinished = [] - protocol = HTTPClientParser(request, finished.append) - protocol.headerReceived = header.__setitem__ - transport = StringTransport() - protocol.makeConnection(transport) - # Deliver just the status to initialize the response object so we can - # monkey-patch it to observe progress of the response parser. - protocol.dataReceived(status) - protocol.response._bodyDataReceived = body.append - protocol.response._bodyDataFinished = ( - lambda: bodyDataFinished.append(True)) - protocol.dataReceived(response) - self.assertEqual(transport.producerState, u'producing') - self.assertEqual(protocol.state, DONE) - self.assertEqual(body, []) - self.assertEqual(finished, [b'']) - self.assertEqual(bodyDataFinished, [True]) - self.assertEqual(protocol.response.length, 0) - return header - - - def test_headResponse(self): - """ - If the response is to a HEAD request, no body is expected, the body - callback is not invoked, and the I{Content-Length} header is passed to - the header callback. - """ - request = Request(b'HEAD', b'/', _boringHeaders, None) - status = b'HTTP/1.1 200 OK\r\n' - response = ( - b'Content-Length: 10\r\n' - b'\r\n') - header = self._noBodyTest(request, status, response) - self.assertEqual(header, {b'Content-Length': b'10'}) - - - def test_noContentResponse(self): - """ - If the response code is I{NO CONTENT} (204), no body is expected and - the body callback is not invoked. - """ - request = Request(b'GET', b'/', _boringHeaders, None) - status = b'HTTP/1.1 204 NO CONTENT\r\n' - response = b'\r\n' - self._noBodyTest(request, status, response) - - - def test_notModifiedResponse(self): - """ - If the response code is I{NOT MODIFIED} (304), no body is expected and - the body callback is not invoked. - """ - request = Request(b'GET', b'/', _boringHeaders, None) - status = b'HTTP/1.1 304 NOT MODIFIED\r\n' - response = b'\r\n' - self._noBodyTest(request, status, response) - - - def test_responseHeaders(self): - """ - The response headers are added to the response object's C{headers} - L{Headers} instance. - """ - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), - lambda rest: None) - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - protocol.dataReceived(b'X-Foo: bar\r\n') - protocol.dataReceived(b'\r\n') - self.assertEqual( - protocol.connHeaders, - Headers({})) - self.assertEqual( - protocol.response.headers, - Headers({b'x-foo': [b'bar']})) - self.assertIdentical(protocol.response.length, UNKNOWN_LENGTH) - - - def test_connectionHeaders(self): - """ - The connection control headers are added to the parser's C{connHeaders} - L{Headers} instance. - """ - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), - lambda rest: None) - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - protocol.dataReceived(b'Content-Length: 123\r\n') - protocol.dataReceived(b'Connection: close\r\n') - protocol.dataReceived(b'\r\n') - self.assertEqual( - protocol.response.headers, - Headers({})) - self.assertEqual( - protocol.connHeaders, - Headers({b'content-length': [b'123'], - b'connection': [b'close']})) - self.assertEqual(protocol.response.length, 123) - - - def test_headResponseContentLengthEntityHeader(self): - """ - If a HEAD request is made, the I{Content-Length} header in the response - is added to the response headers, not the connection control headers. - """ - protocol = HTTPClientParser( - Request(b'HEAD', b'/', _boringHeaders, None), - lambda rest: None) - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - protocol.dataReceived(b'Content-Length: 123\r\n') - protocol.dataReceived(b'\r\n') - self.assertEqual( - protocol.response.headers, - Headers({b'content-length': [b'123']})) - self.assertEqual( - protocol.connHeaders, - Headers({})) - self.assertEqual(protocol.response.length, 0) - - - def test_contentLength(self): - """ - If a response includes a body with a length given by the - I{Content-Length} header, the bytes which make up the body are passed - to the C{_bodyDataReceived} callback on the L{HTTPParser}. - """ - finished = [] - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), - finished.append) - transport = StringTransport() - protocol.makeConnection(transport) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - body = [] - protocol.response._bodyDataReceived = body.append - protocol.dataReceived(b'Content-Length: 10\r\n') - protocol.dataReceived(b'\r\n') - - # Incidentally, the transport should be paused now. It is the response - # object's responsibility to resume this when it is ready for bytes. - self.assertEqual(transport.producerState, u'paused') - - self.assertEqual(protocol.state, BODY) - protocol.dataReceived(b'x' * 6) - self.assertEqual(body, [b'x' * 6]) - self.assertEqual(protocol.state, BODY) - protocol.dataReceived(b'y' * 4) - self.assertEqual(body, [b'x' * 6, b'y' * 4]) - self.assertEqual(protocol.state, DONE) - self.assertEqual(finished, [b'']) - - - def test_zeroContentLength(self): - """ - If a response includes a I{Content-Length} header indicating zero bytes - in the response, L{Response.length} is set accordingly and no data is - delivered to L{Response._bodyDataReceived}. - """ - finished = [] - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), - finished.append) - - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - - body = [] - protocol.response._bodyDataReceived = body.append - - protocol.dataReceived(b'Content-Length: 0\r\n') - protocol.dataReceived(b'\r\n') - - self.assertEqual(protocol.state, DONE) - self.assertEqual(body, []) - self.assertEqual(finished, [b'']) - self.assertEqual(protocol.response.length, 0) - - - def test_multipleContentLengthHeaders(self): - """ - If a response includes multiple I{Content-Length} headers, - L{HTTPClientParser.dataReceived} raises L{ValueError} to indicate that - the response is invalid and the transport is now unusable. - """ - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), - None) - - protocol.makeConnection(StringTransport()) - self.assertRaises( - ValueError, - protocol.dataReceived, - b'HTTP/1.1 200 OK\r\n' - b'Content-Length: 1\r\n' - b'Content-Length: 2\r\n' - b'\r\n') - - - def test_extraBytesPassedBack(self): - """ - If extra bytes are received past the end of a response, they are passed - to the finish callback. - """ - finished = [] - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), - finished.append) - - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - protocol.dataReceived(b'Content-Length: 0\r\n') - protocol.dataReceived(b'\r\nHere is another thing!') - self.assertEqual(protocol.state, DONE) - self.assertEqual(finished, [b'Here is another thing!']) - - - def test_extraBytesPassedBackHEAD(self): - """ - If extra bytes are received past the end of the headers of a response - to a HEAD request, they are passed to the finish callback. - """ - finished = [] - protocol = HTTPClientParser( - Request(b'HEAD', b'/', _boringHeaders, None), - finished.append) - - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - protocol.dataReceived(b'Content-Length: 12\r\n') - protocol.dataReceived(b'\r\nHere is another thing!') - self.assertEqual(protocol.state, DONE) - self.assertEqual(finished, [b'Here is another thing!']) - - - def test_chunkedResponseBody(self): - """ - If the response headers indicate the response body is encoded with the - I{chunked} transfer encoding, the body is decoded according to that - transfer encoding before being passed to L{Response._bodyDataReceived}. - """ - finished = [] - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), - finished.append) - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - - body = [] - protocol.response._bodyDataReceived = body.append - - protocol.dataReceived(b'Transfer-Encoding: chunked\r\n') - protocol.dataReceived(b'\r\n') - - # No data delivered yet - self.assertEqual(body, []) - - # Cannot predict the length of a chunked encoded response body. - self.assertIdentical(protocol.response.length, UNKNOWN_LENGTH) - - # Deliver some chunks and make sure the data arrives - protocol.dataReceived(b'3\r\na') - self.assertEqual(body, [b'a']) - protocol.dataReceived(b'bc\r\n') - self.assertEqual(body, [b'a', b'bc']) - - # The response's _bodyDataFinished method should be called when the last - # chunk is received. Extra data should be passed to the finished - # callback. - protocol.dataReceived(b'0\r\n\r\nextra') - self.assertEqual(finished, [b'extra']) - - - def test_unknownContentLength(self): - """ - If a response does not include a I{Transfer-Encoding} or a - I{Content-Length}, the end of response body is indicated by the - connection being closed. - """ - finished = [] - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), finished.append) - transport = StringTransport() - protocol.makeConnection(transport) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - - body = [] - protocol.response._bodyDataReceived = body.append - - protocol.dataReceived(b'\r\n') - protocol.dataReceived(b'foo') - protocol.dataReceived(b'bar') - self.assertEqual(body, [b'foo', b'bar']) - protocol.connectionLost(ConnectionDone(u"simulated end of connection")) - self.assertEqual(finished, [b'']) - - - def test_contentLengthAndTransferEncoding(self): - """ - According to RFC 2616, section 4.4, point 3, if I{Content-Length} and - I{Transfer-Encoding: chunked} are present, I{Content-Length} MUST be - ignored - """ - finished = [] - protocol = HTTPClientParser( - Request(b'GET', b'/', _boringHeaders, None), finished.append) - transport = StringTransport() - protocol.makeConnection(transport) - protocol.dataReceived(b'HTTP/1.1 200 OK\r\n') - - body = [] - protocol.response._bodyDataReceived = body.append - - protocol.dataReceived( - b'Content-Length: 102\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'3\r\n' - b'abc\r\n' - b'0\r\n' - b'\r\n') - - self.assertEqual(body, [b'abc']) - self.assertEqual(finished, [b'']) - - - def test_connectionLostBeforeBody(self): - """ - If L{HTTPClientParser.connectionLost} is called before the headers are - finished, the C{_responseDeferred} is fired with the L{Failure} passed - to C{connectionLost}. - """ - transport = StringTransport() - protocol = HTTPClientParser(Request(b'GET', b'/', _boringHeaders, - None), None) - protocol.makeConnection(transport) - # Grab this here because connectionLost gets rid of the attribute - responseDeferred = protocol._responseDeferred - protocol.connectionLost(Failure(ArbitraryException())) - - return assertResponseFailed( - self, responseDeferred, [ArbitraryException]) - - - def test_connectionLostWithError(self): - """ - If one of the L{Response} methods called by - L{HTTPClientParser.connectionLost} raises an exception, the exception - is logged and not re-raised. - """ - transport = StringTransport() - protocol = HTTPClientParser(Request(b'GET', b'/', _boringHeaders, None), - None) - protocol.makeConnection(transport) - - response = [] - protocol._responseDeferred.addCallback(response.append) - protocol.dataReceived( - b'HTTP/1.1 200 OK\r\n' - b'Content-Length: 1\r\n' - b'\r\n') - response = response[0] - - # Arrange for an exception - def fakeBodyDataFinished(err=None): - raise ArbitraryException() - response._bodyDataFinished = fakeBodyDataFinished - - protocol.connectionLost(None) - - self.assertEqual(len(self.flushLoggedErrors(ArbitraryException)), 1) - - - def test_noResponseAtAll(self): - """ - If no response at all was received and the connection is lost, the - resulting error is L{ResponseNeverReceived}. - """ - protocol = HTTPClientParser( - Request(b'HEAD', b'/', _boringHeaders, None), - lambda ign: None) - d = protocol._responseDeferred - - protocol.makeConnection(StringTransport()) - protocol.connectionLost(ConnectionLost()) - return self.assertFailure(d, ResponseNeverReceived) - - - def test_someResponseButNotAll(self): - """ - If a partial response was received and the connection is lost, the - resulting error is L{ResponseFailed}, but not - L{ResponseNeverReceived}. - """ - protocol = HTTPClientParser( - Request(b'HEAD', b'/', _boringHeaders, None), - lambda ign: None) - d = protocol._responseDeferred - - protocol.makeConnection(StringTransport()) - protocol.dataReceived(b'2') - protocol.connectionLost(ConnectionLost()) - return self.assertFailure(d, ResponseFailed).addCallback( - self.assertIsInstance, ResponseFailed) - - - -class SlowRequest: - """ - L{SlowRequest} is a fake implementation of L{Request} which is easily - controlled externally (for example, by code in a test method). - - @ivar stopped: A flag indicating whether C{stopWriting} has been called. - - @ivar finished: After C{writeTo} is called, a L{Deferred} which was - returned by that method. L{SlowRequest} will never fire this - L{Deferred}. - """ - method = b'GET' - stopped = False - persistent = False - - def writeTo(self, transport): - self.finished = Deferred() - return self.finished - - - def stopWriting(self): - self.stopped = True - - - -class SimpleRequest: - """ - L{SimpleRequest} is a fake implementation of L{Request} which writes a - short, fixed string to the transport passed to its C{writeTo} method and - returns a succeeded L{Deferred}. This vaguely emulates the behavior of a - L{Request} with no body producer. - """ - persistent = False - - def writeTo(self, transport): - transport.write(b'SOME BYTES') - return succeed(None) - - - -class HTTP11ClientProtocolTests(TestCase): - """ - Tests for the HTTP 1.1 client protocol implementation, - L{HTTP11ClientProtocol}. - """ - def setUp(self): - """ - Create an L{HTTP11ClientProtocol} connected to a fake transport. - """ - self.transport = StringTransport() - self.protocol = HTTP11ClientProtocol() - self.protocol.makeConnection(self.transport) - - - def test_request(self): - """ - L{HTTP11ClientProtocol.request} accepts a L{Request} and calls its - C{writeTo} method with its own transport. - """ - self.protocol.request(SimpleRequest()) - self.assertEqual(self.transport.value(), b'SOME BYTES') - - - def test_secondRequest(self): - """ - The second time L{HTTP11ClientProtocol.request} is called, it returns a - L{Deferred} which immediately fires with a L{Failure} wrapping a - L{RequestNotSent} exception. - """ - self.protocol.request(SlowRequest()) - def cbNotSent(ignored): - self.assertEqual(self.transport.value(), b'') - d = self.assertFailure( - self.protocol.request(SimpleRequest()), RequestNotSent) - d.addCallback(cbNotSent) - return d - - - def test_requestAfterConnectionLost(self): - """ - L{HTTP11ClientProtocol.request} returns a L{Deferred} which immediately - fires with a L{Failure} wrapping a L{RequestNotSent} if called after - the protocol has been disconnected. - """ - self.protocol.connectionLost( - Failure(ConnectionDone(u"sad transport"))) - def cbNotSent(ignored): - self.assertEqual(self.transport.value(), b'') - d = self.assertFailure( - self.protocol.request(SimpleRequest()), RequestNotSent) - d.addCallback(cbNotSent) - return d - - - def test_failedWriteTo(self): - """ - If the L{Deferred} returned by L{Request.writeTo} fires with a - L{Failure}, L{HTTP11ClientProtocol.request} disconnects its transport - and returns a L{Deferred} which fires with a L{Failure} of - L{RequestGenerationFailed} wrapping the underlying failure. - """ - class BrokenRequest: - persistent = False - def writeTo(self, transport): - return fail(ArbitraryException()) - - d = self.protocol.request(BrokenRequest()) - def cbFailed(ignored): - self.assertTrue(self.transport.disconnecting) - # Simulate what would happen if the protocol had a real transport - # and make sure no exception is raised. - self.protocol.connectionLost( - Failure(ConnectionDone(u"you asked for it"))) - d = assertRequestGenerationFailed(self, d, [ArbitraryException]) - d.addCallback(cbFailed) - return d - - - def test_synchronousWriteToError(self): - """ - If L{Request.writeTo} raises an exception, - L{HTTP11ClientProtocol.request} returns a L{Deferred} which fires with - a L{Failure} of L{RequestGenerationFailed} wrapping that exception. - """ - class BrokenRequest: - persistent = False - def writeTo(self, transport): - raise ArbitraryException() - - d = self.protocol.request(BrokenRequest()) - return assertRequestGenerationFailed(self, d, [ArbitraryException]) - - - def test_connectionLostDuringRequestGeneration(self, mode=None): - """ - If L{HTTP11ClientProtocol}'s transport is disconnected before the - L{Deferred} returned by L{Request.writeTo} fires, the L{Deferred} - returned by L{HTTP11ClientProtocol.request} fires with a L{Failure} of - L{RequestTransmissionFailed} wrapping the underlying failure. - """ - request = SlowRequest() - d = self.protocol.request(request) - d = assertRequestTransmissionFailed(self, d, [ArbitraryException]) - - # The connection hasn't been lost yet. The request should still be - # allowed to do its thing. - self.assertFalse(request.stopped) - - self.protocol.connectionLost(Failure(ArbitraryException())) - - # Now the connection has been lost. The request should have been told - # to stop writing itself. - self.assertTrue(request.stopped) - - if mode == 'callback': - request.finished.callback(None) - elif mode == 'errback': - request.finished.errback(Failure(AnotherArbitraryException())) - errors = self.flushLoggedErrors(AnotherArbitraryException) - self.assertEqual(len(errors), 1) - else: - # Don't fire the writeTo Deferred at all. - pass - return d - - - def test_connectionLostBeforeGenerationFinished(self): - """ - If the request passed to L{HTTP11ClientProtocol} finishes generation - successfully after the L{HTTP11ClientProtocol}'s connection has been - lost, nothing happens. - """ - return self.test_connectionLostDuringRequestGeneration('callback') - - - def test_connectionLostBeforeGenerationFailed(self): - """ - If the request passed to L{HTTP11ClientProtocol} finished generation - with an error after the L{HTTP11ClientProtocol}'s connection has been - lost, nothing happens. - """ - return self.test_connectionLostDuringRequestGeneration('errback') - - - def test_errorMessageOnConnectionLostBeforeGenerationFailedDoesNotConfuse(self): - """ - If the request passed to L{HTTP11ClientProtocol} finished generation - with an error after the L{HTTP11ClientProtocol}'s connection has been - lost, an error is logged that gives a non-confusing hint to user on what - went wrong. - """ - errors = [] - log.addObserver(errors.append) - self.addCleanup(log.removeObserver, errors.append) - - def check(ignore): - error = errors[0] - self.assertEqual(error[u'why'], - u'Error writing request, but not in valid state ' - u'to finalize request: CONNECTION_LOST') - - return self.test_connectionLostDuringRequestGeneration( - 'errback').addCallback(check) - - - def test_receiveSimplestResponse(self): - """ - When a response is delivered to L{HTTP11ClientProtocol}, the - L{Deferred} previously returned by the C{request} method is called back - with a L{Response} instance and the connection is closed. - """ - d = self.protocol.request(Request(b'GET', b'/', _boringHeaders, None)) - def cbRequest(response): - self.assertEqual(response.code, 200) - self.assertEqual(response.headers, Headers()) - self.assertTrue(self.transport.disconnecting) - self.assertEqual(self.protocol.state, u'QUIESCENT') - d.addCallback(cbRequest) - self.protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-Length: 0\r\n" - b"Connection: close\r\n" - b"\r\n") - return d - - - def test_receiveResponseHeaders(self): - """ - The headers included in a response delivered to L{HTTP11ClientProtocol} - are included on the L{Response} instance passed to the callback - returned by the C{request} method. - """ - d = self.protocol.request(Request(b'GET', b'/', _boringHeaders, None)) - def cbRequest(response): - expected = Headers({b'x-foo': [b'bar', b'baz']}) - self.assertEqual(response.headers, expected) - d.addCallback(cbRequest) - self.protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"X-Foo: bar\r\n" - b"X-Foo: baz\r\n" - b"\r\n") - return d - - - def test_receiveResponseBeforeRequestGenerationDone(self): - """ - If response bytes are delivered to L{HTTP11ClientProtocol} before the - L{Deferred} returned by L{Request.writeTo} fires, those response bytes - are parsed as part of the response. - - The connection is also closed, because we're in a confusing state, and - therefore the C{quiescentCallback} isn't called. - """ - quiescentResult = [] - transport = StringTransport() - protocol = HTTP11ClientProtocol(quiescentResult.append) - protocol.makeConnection(transport) - - request = SlowRequest() - d = protocol.request(request) - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"X-Foo: bar\r\n" - b"Content-Length: 6\r\n" - b"\r\n" - b"foobar") - def cbResponse(response): - p = AccumulatingProtocol() - whenFinished = p.closedDeferred = Deferred() - response.deliverBody(p) - self.assertEqual( - protocol.state, u'TRANSMITTING_AFTER_RECEIVING_RESPONSE') - self.assertTrue(transport.disconnecting) - self.assertEqual(quiescentResult, []) - return whenFinished.addCallback( - lambda ign: (response, p.data)) - d.addCallback(cbResponse) - def cbAllResponse(result): - response, body = result - self.assertEqual(response.version, (b'HTTP', 1, 1)) - self.assertEqual(response.code, 200) - self.assertEqual(response.phrase, b'OK') - self.assertEqual(response.headers, Headers({b'x-foo': [b'bar']})) - self.assertEqual(body, b"foobar") - - # Also nothing bad should happen if the request does finally - # finish, even though it is completely irrelevant. - request.finished.callback(None) - - d.addCallback(cbAllResponse) - return d - - - def test_connectionLostAfterReceivingResponseBeforeRequestGenerationDone(self): - """ - If response bytes are delivered to L{HTTP11ClientProtocol} before the - request completes, calling C{connectionLost} on the protocol will - result in protocol being moved to C{'CONNECTION_LOST'} state. - """ - request = SlowRequest() - d = self.protocol.request(request) - self.protocol.dataReceived( - b"HTTP/1.1 400 BAD REQUEST\r\n" - b"Content-Length: 9\r\n" - b"\r\n" - b"tisk tisk") - def cbResponse(response): - p = AccumulatingProtocol() - whenFinished = p.closedDeferred = Deferred() - response.deliverBody(p) - return whenFinished.addCallback( - lambda ign: (response, p.data)) - d.addCallback(cbResponse) - def cbAllResponse(ignore): - request.finished.callback(None) - # Nothing dire will happen when the connection is lost - self.protocol.connectionLost(Failure(ArbitraryException())) - self.assertEqual(self.protocol._state, u'CONNECTION_LOST') - d.addCallback(cbAllResponse) - return d - - - def test_receiveResponseBody(self): - """ - The C{deliverBody} method of the response object with which the - L{Deferred} returned by L{HTTP11ClientProtocol.request} fires can be - used to get the body of the response. - """ - protocol = AccumulatingProtocol() - whenFinished = protocol.closedDeferred = Deferred() - requestDeferred = self.protocol.request(Request(b'GET', b'/', _boringHeaders, None)) - - self.protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-Length: 6\r\n" - b"\r") - - # Here's what's going on: all the response headers have been delivered - # by this point, so the request Deferred can fire with a Response - # object. The body is yet to come, but that's okay, because the - # Response object is how you *get* the body. - result = [] - requestDeferred.addCallback(result.append) - - self.assertEqual(result, []) - # Deliver the very last byte of the response. It is exactly at this - # point which the Deferred returned by request should fire. - self.protocol.dataReceived(b"\n") - response = result[0] - - response.deliverBody(protocol) - - self.protocol.dataReceived(b"foo") - self.protocol.dataReceived(b"bar") - - def cbAllResponse(ignored): - self.assertEqual(protocol.data, b"foobar") - protocol.closedReason.trap(ResponseDone) - whenFinished.addCallback(cbAllResponse) - return whenFinished - - - def test_responseBodyFinishedWhenConnectionLostWhenContentLengthIsUnknown( - self): - """ - If the length of the response body is unknown, the protocol passed to - the response's C{deliverBody} method has its C{connectionLost} - method called with a L{Failure} wrapping a L{PotentialDataLoss} - exception. - """ - requestDeferred = self.protocol.request(Request(b'GET', b'/', - _boringHeaders, None)) - self.protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"\r\n") - - result = [] - requestDeferred.addCallback(result.append) - response = result[0] - - protocol = AccumulatingProtocol() - response.deliverBody(protocol) - - self.protocol.dataReceived(b"foo") - self.protocol.dataReceived(b"bar") - - self.assertEqual(protocol.data, b"foobar") - self.protocol.connectionLost( - Failure(ConnectionDone(u"low-level transport disconnected"))) - - protocol.closedReason.trap(PotentialDataLoss) - - - def test_chunkedResponseBodyUnfinishedWhenConnectionLost(self): - """ - If the final chunk has not been received when the connection is lost - (for any reason), the protocol passed to C{deliverBody} has its - C{connectionLost} method called with a L{Failure} wrapping the - exception for that reason. - """ - requestDeferred = self.protocol.request(Request(b'GET', b'/', - _boringHeaders, None)) - self.protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Transfer-Encoding: chunked\r\n" - b"\r\n") - - result = [] - requestDeferred.addCallback(result.append) - response = result[0] - - protocol = AccumulatingProtocol() - response.deliverBody(protocol) - - self.protocol.dataReceived(b"3\r\nfoo\r\n") - self.protocol.dataReceived(b"3\r\nbar\r\n") - - self.assertEqual(protocol.data, b"foobar") - - self.protocol.connectionLost(Failure(ArbitraryException())) - - return assertResponseFailed( - self, fail(protocol.closedReason), [ArbitraryException, _DataLoss]) - - - def test_parserDataReceivedException(self): - """ - If the parser L{HTTP11ClientProtocol} delivers bytes to in - C{dataReceived} raises an exception, the exception is wrapped in a - L{Failure} and passed to the parser's C{connectionLost} and then the - L{HTTP11ClientProtocol}'s transport is disconnected. - """ - requestDeferred = self.protocol.request(Request(b'GET', b'/', - _boringHeaders, None)) - self.protocol.dataReceived(b'unparseable garbage goes here\r\n') - d = assertResponseFailed(self, requestDeferred, [ParseError]) - def cbFailed(exc): - self.assertTrue(self.transport.disconnecting) - self.assertEqual( - exc.reasons[0].value.data, b'unparseable garbage goes here') - - # Now do what StringTransport doesn't do but a real transport would - # have, call connectionLost on the HTTP11ClientProtocol. Nothing - # is asserted about this, but it's important for it to not raise an - # exception. - self.protocol.connectionLost(Failure(ConnectionDone(u"it is done"))) - - d.addCallback(cbFailed) - return d - - - def test_proxyStopped(self): - """ - When the HTTP response parser is disconnected, the - L{TransportProxyProducer} which was connected to it as a transport is - stopped. - """ - requestDeferred = self.protocol.request(Request(b'GET', b'/', - _boringHeaders, None)) - transport = self.protocol._parser.transport - self.assertIdentical(transport._producer, self.transport) - self.protocol._disconnectParser( - Failure(ConnectionDone(u"connection done"))) - self.assertIdentical(transport._producer, None) - return assertResponseFailed(self, requestDeferred, [ConnectionDone]) - - - def test_abortClosesConnection(self): - """ - L{HTTP11ClientProtocol.abort} will tell the transport to close its - connection when it is invoked, and returns a C{Deferred} that fires - when the connection is lost. - """ - transport = StringTransport() - protocol = HTTP11ClientProtocol() - protocol.makeConnection(transport) - r1 = [] - r2 = [] - protocol.abort().addCallback(r1.append) - protocol.abort().addCallback(r2.append) - self.assertEqual((r1, r2), ([], [])) - self.assertTrue(transport.disconnecting) - - # Disconnect protocol, the Deferreds will fire: - protocol.connectionLost(Failure(ConnectionDone())) - self.assertEqual(r1, [None]) - self.assertEqual(r2, [None]) - - - def test_abortAfterConnectionLost(self): - """ - L{HTTP11ClientProtocol.abort} called after the connection is lost - returns a C{Deferred} that fires immediately. - """ - transport = StringTransport() - protocol = HTTP11ClientProtocol() - protocol.makeConnection(transport) - protocol.connectionLost(Failure(ConnectionDone())) - - result = [] - protocol.abort().addCallback(result.append) - self.assertEqual(result, [None]) - self.assertEqual(protocol._state, u"CONNECTION_LOST") - - - def test_abortBeforeResponseBody(self): - """ - The Deferred returned by L{HTTP11ClientProtocol.request} will fire - with a L{ResponseFailed} failure containing a L{ConnectionAborted} - exception, if the connection was aborted before all response headers - have been received. - """ - transport = StringTransport() - protocol = HTTP11ClientProtocol() - protocol.makeConnection(transport) - result = protocol.request(Request(b'GET', b'/', _boringHeaders, None)) - protocol.abort() - self.assertTrue(transport.disconnecting) - protocol.connectionLost(Failure(ConnectionDone())) - return assertResponseFailed(self, result, [ConnectionAborted]) - - - def test_abortAfterResponseHeaders(self): - """ - When the connection is aborted after the response headers have - been received and the L{Response} has been made available to - application code, the response body protocol's C{connectionLost} - method will be invoked with a L{ResponseFailed} failure containing a - L{ConnectionAborted} exception. - """ - transport = StringTransport() - protocol = HTTP11ClientProtocol() - protocol.makeConnection(transport) - result = protocol.request(Request(b'GET', b'/', _boringHeaders, None)) - - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-Length: 1\r\n" - b"\r\n" - ) - - testResult = Deferred() - - class BodyDestination(Protocol): - """ - A body response protocol which immediately aborts the HTTP - connection. - """ - def connectionMade(self): - """ - Abort the HTTP connection. - """ - protocol.abort() - - def connectionLost(self, reason): - """ - Make the reason for the losing of the connection available to - the unit test via C{testResult}. - """ - testResult.errback(reason) - - - def deliverBody(response): - """ - Connect the L{BodyDestination} response body protocol to the - response, and then simulate connection loss after ensuring that - the HTTP connection has been aborted. - """ - response.deliverBody(BodyDestination()) - self.assertTrue(transport.disconnecting) - protocol.connectionLost(Failure(ConnectionDone())) - - - def checkError(error): - self.assertIsInstance(error.response, Response) - - - result.addCallback(deliverBody) - deferred = assertResponseFailed(self, testResult, - [ConnectionAborted, _DataLoss]) - return deferred.addCallback(checkError) - - - def test_quiescentCallbackCalled(self): - """ - If after a response is done the {HTTP11ClientProtocol} stays open and - returns to QUIESCENT state, all per-request state is reset and the - C{quiescentCallback} is called with the protocol instance. - - This is useful for implementing a persistent connection pool. - - The C{quiescentCallback} is called *before* the response-receiving - protocol's C{connectionLost}, so that new requests triggered by end of - first request can re-use a persistent connection. - """ - quiescentResult = [] - def callback(p): - self.assertEqual(p, protocol) - self.assertEqual(p.state, u"QUIESCENT") - quiescentResult.append(p) - - transport = StringTransport() - protocol = HTTP11ClientProtocol(callback) - protocol.makeConnection(transport) - - requestDeferred = protocol.request( - Request(b'GET', b'/', _boringHeaders, None, persistent=True)) - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-length: 3\r\n" - b"\r\n") - - # Headers done, but still no quiescent callback: - self.assertEqual(quiescentResult, []) - - result = [] - requestDeferred.addCallback(result.append) - response = result[0] - - # When response body is done (i.e. connectionLost is called), note the - # fact in quiescentResult: - bodyProtocol = AccumulatingProtocol() - bodyProtocol.closedDeferred = Deferred() - bodyProtocol.closedDeferred.addCallback( - lambda ign: quiescentResult.append(u"response done")) - - response.deliverBody(bodyProtocol) - protocol.dataReceived(b"abc") - bodyProtocol.closedReason.trap(ResponseDone) - # Quiescent callback called *before* protocol handling the response - # body gets its connectionLost called: - self.assertEqual(quiescentResult, [protocol, u"response done"]) - - # Make sure everything was cleaned up: - self.assertEqual(protocol._parser, None) - self.assertEqual(protocol._finishedRequest, None) - self.assertEqual(protocol._currentRequest, None) - self.assertEqual(protocol._transportProxy, None) - self.assertEqual(protocol._responseDeferred, None) - - - def test_transportProducingWhenQuiescentAfterFullBody(self): - """ - The C{quiescentCallback} passed to L{HTTP11ClientProtocol} will only be - invoked once that protocol is in a state similar to its initial state. - One of the aspects of this initial state is the producer-state of its - transport; an L{HTTP11ClientProtocol} begins with a transport that is - producing, i.e. not C{pauseProducing}'d. - - Therefore, when C{quiescentCallback} is invoked the protocol will still - be producing. - """ - quiescentResult = [] - def callback(p): - self.assertEqual(p, protocol) - self.assertEqual(p.state, u"QUIESCENT") - quiescentResult.append(p) - - transport = StringTransport() - protocol = HTTP11ClientProtocol(callback) - protocol.makeConnection(transport) - requestDeferred = protocol.request( - Request(b'GET', b'/', _boringHeaders, None, persistent=True)) - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-length: 3\r\n" - b"\r\n" - b"BBB" # _full_ content of the response. - ) - - response = self.successResultOf(requestDeferred) - # Sanity check: response should have full response body, just waiting - # for deliverBody - self.assertEqual(response._state, u'DEFERRED_CLOSE') - - # The transport is quiescent, because the response has been received. - # If we were connection pooling here, it would have been returned to - # the pool. - self.assertEqual(len(quiescentResult), 1) - - # And that transport is totally still reading, right? Because it would - # leak forever if it were sitting there disconnected from the - # reactor... - self.assertEqual(transport.producerState, u'producing') - - - def test_quiescentCallbackCalledEmptyResponse(self): - """ - The quiescentCallback is called before the request C{Deferred} fires, - in cases where the response has no body. - """ - quiescentResult = [] - def callback(p): - self.assertEqual(p, protocol) - self.assertEqual(p.state, u"QUIESCENT") - quiescentResult.append(p) - - transport = StringTransport() - protocol = HTTP11ClientProtocol(callback) - protocol.makeConnection(transport) - - requestDeferred = protocol.request( - Request(b'GET', b'/', _boringHeaders, None, persistent=True)) - requestDeferred.addCallback(quiescentResult.append) - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-length: 0\r\n" - b"\r\n") - - self.assertEqual(len(quiescentResult), 2) - self.assertIdentical(quiescentResult[0], protocol) - self.assertIsInstance(quiescentResult[1], Response) - - - def test_quiescentCallbackNotCalled(self): - """ - If after a response is done the {HTTP11ClientProtocol} returns a - C{Connection: close} header in the response, the C{quiescentCallback} - is not called and the connection is lost. - """ - quiescentResult = [] - transport = StringTransport() - protocol = HTTP11ClientProtocol(quiescentResult.append) - protocol.makeConnection(transport) - - requestDeferred = protocol.request( - Request(b'GET', b'/', _boringHeaders, None, persistent=True)) - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-length: 0\r\n" - b"Connection: close\r\n" - b"\r\n") - - result = [] - requestDeferred.addCallback(result.append) - response = result[0] - - bodyProtocol = AccumulatingProtocol() - response.deliverBody(bodyProtocol) - bodyProtocol.closedReason.trap(ResponseDone) - self.assertEqual(quiescentResult, []) - self.assertTrue(transport.disconnecting) - - - def test_quiescentCallbackNotCalledNonPersistentQuery(self): - """ - If the request was non-persistent (i.e. sent C{Connection: close}), - the C{quiescentCallback} is not called and the connection is lost. - """ - quiescentResult = [] - transport = StringTransport() - protocol = HTTP11ClientProtocol(quiescentResult.append) - protocol.makeConnection(transport) - - requestDeferred = protocol.request( - Request(b'GET', b'/', _boringHeaders, None, persistent=False)) - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-length: 0\r\n" - b"\r\n") - - result = [] - requestDeferred.addCallback(result.append) - response = result[0] - - bodyProtocol = AccumulatingProtocol() - response.deliverBody(bodyProtocol) - bodyProtocol.closedReason.trap(ResponseDone) - self.assertEqual(quiescentResult, []) - self.assertTrue(transport.disconnecting) - - - def test_quiescentCallbackThrows(self): - """ - If C{quiescentCallback} throws an exception, the error is logged and - protocol is disconnected. - """ - def callback(p): - raise ZeroDivisionError() - - transport = StringTransport() - protocol = HTTP11ClientProtocol(callback) - protocol.makeConnection(transport) - - requestDeferred = protocol.request( - Request(b'GET', b'/', _boringHeaders, None, persistent=True)) - protocol.dataReceived( - b"HTTP/1.1 200 OK\r\n" - b"Content-length: 0\r\n" - b"\r\n") - - result = [] - requestDeferred.addCallback(result.append) - response = result[0] - bodyProtocol = AccumulatingProtocol() - response.deliverBody(bodyProtocol) - bodyProtocol.closedReason.trap(ResponseDone) - - errors = self.flushLoggedErrors(ZeroDivisionError) - self.assertEqual(len(errors), 1) - self.assertTrue(transport.disconnecting) - - - def test_cancelBeforeResponse(self): - """ - The L{Deferred} returned by L{HTTP11ClientProtocol.request} will fire - with a L{ResponseNeverReceived} failure containing a L{CancelledError} - exception if the request was cancelled before any response headers were - received. - """ - transport = StringTransport() - protocol = HTTP11ClientProtocol() - protocol.makeConnection(transport) - result = protocol.request(Request(b'GET', b'/', _boringHeaders, None)) - result.cancel() - self.assertTrue(transport.aborting) - return assertWrapperExceptionTypes( - self, result, ResponseNeverReceived, [CancelledError]) - - - def test_cancelDuringResponse(self): - """ - The L{Deferred} returned by L{HTTP11ClientProtocol.request} will fire - with a L{ResponseFailed} failure containing a L{CancelledError} - exception if the request was cancelled before all response headers were - received. - """ - transport = StringTransport() - protocol = HTTP11ClientProtocol() - protocol.makeConnection(transport) - result = protocol.request(Request(b'GET', b'/', _boringHeaders, None)) - protocol.dataReceived(b"HTTP/1.1 200 OK\r\n") - result.cancel() - self.assertTrue(transport.aborting) - return assertResponseFailed(self, result, [CancelledError]) - - - def assertCancelDuringBodyProduction(self, producerLength): - """ - The L{Deferred} returned by L{HTTP11ClientProtocol.request} will fire - with a L{RequestGenerationFailed} failure containing a - L{CancelledError} exception if the request was cancelled before a - C{bodyProducer} has finished producing. - """ - transport = StringTransport() - protocol = HTTP11ClientProtocol() - protocol.makeConnection(transport) - producer = StringProducer(producerLength) - - nonLocal = {'cancelled': False} - def cancel(ign): - nonLocal['cancelled'] = True - def startProducing(consumer): - producer.consumer = consumer - producer.finished = Deferred(cancel) - return producer.finished - producer.startProducing = startProducing - - result = protocol.request(Request(b'POST', b'/bar', _boringHeaders, - producer)) - producer.consumer.write(b'x' * 5) - result.cancel() - self.assertTrue(transport.aborting) - self.assertTrue(nonLocal['cancelled']) - return assertRequestGenerationFailed(self, result, [CancelledError]) - - - def test_cancelDuringBodyProduction(self): - """ - The L{Deferred} returned by L{HTTP11ClientProtocol.request} will fire - with a L{RequestGenerationFailed} failure containing a - L{CancelledError} exception if the request was cancelled before a - C{bodyProducer} with an explicit length has finished producing. - """ - return self.assertCancelDuringBodyProduction(10) - - - def test_cancelDuringChunkedBodyProduction(self): - """ - The L{Deferred} returned by L{HTTP11ClientProtocol.request} will fire - with a L{RequestGenerationFailed} failure containing a - L{CancelledError} exception if the request was cancelled before a - C{bodyProducer} with C{UNKNOWN_LENGTH} has finished producing. - """ - return self.assertCancelDuringBodyProduction(UNKNOWN_LENGTH) - - - -@implementer(IBodyProducer) -class StringProducer: - """ - L{StringProducer} is a dummy body producer. - - @ivar stopped: A flag which indicates whether or not C{stopProducing} has - been called. - @ivar consumer: After C{startProducing} is called, the value of the - C{consumer} argument to that method. - @ivar finished: After C{startProducing} is called, a L{Deferred} which was - returned by that method. L{StringProducer} will never fire this - L{Deferred}. - """ - - stopped = False - - def __init__(self, length): - self.length = length - - - def startProducing(self, consumer): - self.consumer = consumer - self.finished = Deferred() - return self.finished - - - def stopProducing(self): - self.stopped = True - - - -class RequestTests(TestCase): - """ - Tests for L{Request}. - """ - def setUp(self): - self.transport = StringTransport() - - - def test_sendSimplestRequest(self): - """ - L{Request.writeTo} formats the request data and writes it to the given - transport. - """ - Request(b'GET', b'/', _boringHeaders, None).writeTo(self.transport) - self.assertEqual( - self.transport.value(), - b"GET / HTTP/1.1\r\n" - b"Connection: close\r\n" - b"Host: example.com\r\n" - b"\r\n") - - - def test_sendSimplestPersistentRequest(self): - """ - A pesistent request does not send 'Connection: close' header. - """ - req = Request(b'GET', b'/', _boringHeaders, None, persistent=True) - req.writeTo(self.transport) - self.assertEqual( - self.transport.value(), - b"GET / HTTP/1.1\r\n" - b"Host: example.com\r\n" - b"\r\n") - - - def test_sendRequestHeaders(self): - """ - L{Request.writeTo} formats header data and writes it to the given - transport. - """ - headers = Headers({b'x-foo': [b'bar', b'baz'], - b'host': [b'example.com']}) - Request(b'GET', b'/foo', headers, None).writeTo(self.transport) - lines = self.transport.value().split(b'\r\n') - self.assertEqual(lines[0], b"GET /foo HTTP/1.1") - self.assertEqual(lines[-2:], [b"", b""]) - del lines[0], lines[-2:] - lines.sort() - self.assertEqual( - lines, - [b"Connection: close", - b"Host: example.com", - b"X-Foo: bar", - b"X-Foo: baz"]) - - - def test_sendChunkedRequestBody(self): - """ - L{Request.writeTo} uses chunked encoding to write data from the request - body producer to the given transport. It registers the request body - producer with the transport. - """ - producer = StringProducer(UNKNOWN_LENGTH) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - request.writeTo(self.transport) - - self.assertNotIdentical(producer.consumer, None) - self.assertIdentical(self.transport.producer, producer) - self.assertTrue(self.transport.streaming) - - self.assertEqual( - self.transport.value(), - b"POST /bar HTTP/1.1\r\n" - b"Connection: close\r\n" - b"Transfer-Encoding: chunked\r\n" - b"Host: example.com\r\n" - b"\r\n") - self.transport.clear() - - producer.consumer.write(b'x' * 3) - producer.consumer.write(b'y' * 15) - producer.finished.callback(None) - self.assertIdentical(self.transport.producer, None) - self.assertEqual( - self.transport.value(), - b"3\r\n" - b"xxx\r\n" - b"f\r\n" - b"yyyyyyyyyyyyyyy\r\n" - b"0\r\n" - b"\r\n") - - - def test_sendChunkedRequestBodyWithError(self): - """ - If L{Request} is created with a C{bodyProducer} without a known length - and the L{Deferred} returned from its C{startProducing} method fires - with a L{Failure}, the L{Deferred} returned by L{Request.writeTo} fires - with that L{Failure} and the body producer is unregistered from the - transport. The final zero-length chunk is not written to the - transport. - """ - producer = StringProducer(UNKNOWN_LENGTH) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - writeDeferred = request.writeTo(self.transport) - self.transport.clear() - producer.finished.errback(ArbitraryException()) - def cbFailed(ignored): - self.assertEqual(self.transport.value(), b"") - self.assertIdentical(self.transport.producer, None) - d = self.assertFailure(writeDeferred, ArbitraryException) - d.addCallback(cbFailed) - return d - - - def test_sendRequestBodyWithLength(self): - """ - If L{Request} is created with a C{bodyProducer} with a known length, - that length is sent as the value for the I{Content-Length} header and - chunked encoding is not used. - """ - producer = StringProducer(3) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - request.writeTo(self.transport) - - self.assertNotIdentical(producer.consumer, None) - self.assertIdentical(self.transport.producer, producer) - self.assertTrue(self.transport.streaming) - - self.assertEqual( - self.transport.value(), - b"POST /bar HTTP/1.1\r\n" - b"Connection: close\r\n" - b"Content-Length: 3\r\n" - b"Host: example.com\r\n" - b"\r\n") - self.transport.clear() - - producer.consumer.write(b'abc') - producer.finished.callback(None) - self.assertIdentical(self.transport.producer, None) - self.assertEqual(self.transport.value(), b"abc") - - - def test_sendRequestBodyWithTooFewBytes(self): - """ - If L{Request} is created with a C{bodyProducer} with a known length and - the producer does not produce that many bytes, the L{Deferred} returned - by L{Request.writeTo} fires with a L{Failure} wrapping a - L{WrongBodyLength} exception. - """ - producer = StringProducer(3) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - writeDeferred = request.writeTo(self.transport) - producer.consumer.write(b'ab') - producer.finished.callback(None) - self.assertIdentical(self.transport.producer, None) - return self.assertFailure(writeDeferred, WrongBodyLength) - - - def _sendRequestBodyWithTooManyBytesTest(self, finisher): - """ - Verify that when too many bytes have been written by a body producer - and then the body producer's C{startProducing} L{Deferred} fires that - the producer is unregistered from the transport and that the - L{Deferred} returned from L{Request.writeTo} is fired with a L{Failure} - wrapping a L{WrongBodyLength}. - - @param finisher: A callable which will be invoked with the body - producer after too many bytes have been written to the transport. - It should fire the startProducing Deferred somehow. - """ - producer = StringProducer(3) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - writeDeferred = request.writeTo(self.transport) - - producer.consumer.write(b'ab') - - # The producer hasn't misbehaved yet, so it shouldn't have been - # stopped. - self.assertFalse(producer.stopped) - - producer.consumer.write(b'cd') - - # Now the producer *has* misbehaved, so we should have tried to - # make it stop. - self.assertTrue(producer.stopped) - - # The transport should have had the producer unregistered from it as - # well. - self.assertIdentical(self.transport.producer, None) - - def cbFailed(exc): - # The "cd" should not have been written to the transport because - # the request can now locally be recognized to be invalid. If we - # had written the extra bytes, the server could have decided to - # start processing the request, which would be bad since we're - # going to indicate failure locally. - self.assertEqual( - self.transport.value(), - b"POST /bar HTTP/1.1\r\n" - b"Connection: close\r\n" - b"Content-Length: 3\r\n" - b"Host: example.com\r\n" - b"\r\n" - b"ab") - self.transport.clear() - - # Subsequent writes should be ignored, as should firing the - # Deferred returned from startProducing. - self.assertRaises(ExcessWrite, producer.consumer.write, b'ef') - - # Likewise, if the Deferred returned from startProducing fires, - # this should more or less be ignored (aside from possibly logging - # an error). - finisher(producer) - - # There should have been nothing further written to the transport. - self.assertEqual(self.transport.value(), b"") - - d = self.assertFailure(writeDeferred, WrongBodyLength) - d.addCallback(cbFailed) - return d - - - def test_sendRequestBodyWithTooManyBytes(self): - """ - If L{Request} is created with a C{bodyProducer} with a known length and - the producer tries to produce more than than many bytes, the - L{Deferred} returned by L{Request.writeTo} fires with a L{Failure} - wrapping a L{WrongBodyLength} exception. - """ - def finisher(producer): - producer.finished.callback(None) - return self._sendRequestBodyWithTooManyBytesTest(finisher) - - - def test_sendRequestBodyErrorWithTooManyBytes(self): - """ - If L{Request} is created with a C{bodyProducer} with a known length and - the producer tries to produce more than than many bytes, the - L{Deferred} returned by L{Request.writeTo} fires with a L{Failure} - wrapping a L{WrongBodyLength} exception. - """ - def finisher(producer): - producer.finished.errback(ArbitraryException()) - errors = self.flushLoggedErrors(ArbitraryException) - self.assertEqual(len(errors), 1) - return self._sendRequestBodyWithTooManyBytesTest(finisher) - - - def test_sendRequestBodyErrorWithConsumerError(self): - """ - Though there should be no way for the internal C{finishedConsuming} - L{Deferred} in L{Request._writeToContentLength} to fire a L{Failure} - after the C{finishedProducing} L{Deferred} has fired, in case this does - happen, the error should be logged with a message about how there's - probably a bug in L{Request}. - - This is a whitebox test. - """ - producer = StringProducer(3) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - request.writeTo(self.transport) - - finishedConsuming = producer.consumer._finished - - producer.consumer.write(b'abc') - producer.finished.callback(None) - - finishedConsuming.errback(ArbitraryException()) - self.assertEqual(len(self.flushLoggedErrors(ArbitraryException)), 1) - - - def _sendRequestBodyFinishedEarlyThenTooManyBytes(self, finisher): - """ - Verify that if the body producer fires its Deferred and then keeps - writing to the consumer that the extra writes are ignored and the - L{Deferred} returned by L{Request.writeTo} fires with a L{Failure} - wrapping the most appropriate exception type. - """ - producer = StringProducer(3) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - writeDeferred = request.writeTo(self.transport) - - producer.consumer.write(b'ab') - finisher(producer) - self.assertIdentical(self.transport.producer, None) - self.transport.clear() - self.assertRaises(ExcessWrite, producer.consumer.write, b'cd') - self.assertEqual(self.transport.value(), b"") - return writeDeferred - - - def test_sendRequestBodyFinishedEarlyThenTooManyBytes(self): - """ - If the request body producer indicates it is done by firing the - L{Deferred} returned from its C{startProducing} method but then goes on - to write too many bytes, the L{Deferred} returned by {Request.writeTo} - fires with a L{Failure} wrapping L{WrongBodyLength}. - """ - def finisher(producer): - producer.finished.callback(None) - return self.assertFailure( - self._sendRequestBodyFinishedEarlyThenTooManyBytes(finisher), - WrongBodyLength) - - - def test_sendRequestBodyErroredEarlyThenTooManyBytes(self): - """ - If the request body producer indicates an error by firing the - L{Deferred} returned from its C{startProducing} method but then goes on - to write too many bytes, the L{Deferred} returned by {Request.writeTo} - fires with that L{Failure} and L{WrongBodyLength} is logged. - """ - def finisher(producer): - producer.finished.errback(ArbitraryException()) - return self.assertFailure( - self._sendRequestBodyFinishedEarlyThenTooManyBytes(finisher), - ArbitraryException) - - - def test_sendChunkedRequestBodyFinishedThenWriteMore(self, _with=None): - """ - If the request body producer with an unknown length tries to write - after firing the L{Deferred} returned by its C{startProducing} method, - the C{write} call raises an exception and does not write anything to - the underlying transport. - """ - producer = StringProducer(UNKNOWN_LENGTH) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - writeDeferred = request.writeTo(self.transport) - producer.finished.callback(_with) - self.transport.clear() - - self.assertRaises(ExcessWrite, producer.consumer.write, b'foo') - self.assertEqual(self.transport.value(), b"") - return writeDeferred - - - def test_sendChunkedRequestBodyFinishedWithErrorThenWriteMore(self): - """ - If the request body producer with an unknown length tries to write - after firing the L{Deferred} returned by its C{startProducing} method - with a L{Failure}, the C{write} call raises an exception and does not - write anything to the underlying transport. - """ - d = self.test_sendChunkedRequestBodyFinishedThenWriteMore( - Failure(ArbitraryException())) - return self.assertFailure(d, ArbitraryException) - - - def test_sendRequestBodyWithError(self): - """ - If the L{Deferred} returned from the C{startProducing} method of the - L{IBodyProducer} passed to L{Request} fires with a L{Failure}, the - L{Deferred} returned from L{Request.writeTo} fails with that - L{Failure}. - """ - producer = StringProducer(5) - request = Request(b'POST', b'/bar', _boringHeaders, producer) - writeDeferred = request.writeTo(self.transport) - - # Sanity check - the producer should be registered with the underlying - # transport. - self.assertIdentical(self.transport.producer, producer) - self.assertTrue(self.transport.streaming) - - producer.consumer.write(b'ab') - self.assertEqual( - self.transport.value(), - b"POST /bar HTTP/1.1\r\n" - b"Connection: close\r\n" - b"Content-Length: 5\r\n" - b"Host: example.com\r\n" - b"\r\n" - b"ab") - - self.assertFalse(self.transport.disconnecting) - producer.finished.errback(Failure(ArbitraryException())) - - # Disconnection is handled by a higher level. Request should leave the - # transport alone in this case. - self.assertFalse(self.transport.disconnecting) - - # Oh. Except it should unregister the producer that it registered. - self.assertIdentical(self.transport.producer, None) - - return self.assertFailure(writeDeferred, ArbitraryException) - - - def test_hostHeaderRequired(self): - """ - L{Request.writeTo} raises L{BadHeaders} if there is not exactly one - I{Host} header and writes nothing to the given transport. - """ - request = Request(b'GET', b'/', Headers({}), None) - self.assertRaises(BadHeaders, request.writeTo, self.transport) - self.assertEqual(self.transport.value(), b'') - - request = Request(b'GET', b'/', - Headers({b'Host': [b'example.com', b'example.org']}), None) - self.assertRaises(BadHeaders, request.writeTo, self.transport) - self.assertEqual(self.transport.value(), b'') - - - def test_stopWriting(self): - """ - L{Request.stopWriting} calls its body producer's C{stopProducing} - method. - """ - producer = StringProducer(3) - request = Request(b'GET', b'/', _boringHeaders, producer) - request.writeTo(self.transport) - self.assertFalse(producer.stopped) - request.stopWriting() - self.assertTrue(producer.stopped) - - - def test_brokenStopProducing(self): - """ - If the body producer's C{stopProducing} method raises an exception, - L{Request.stopWriting} logs it and does not re-raise it. - """ - producer = StringProducer(3) - def brokenStopProducing(): - raise ArbitraryException(u"stopProducing is busted") - producer.stopProducing = brokenStopProducing - - request = Request(b'GET', b'/', _boringHeaders, producer) - request.writeTo(self.transport) - request.stopWriting() - self.assertEqual( - len(self.flushLoggedErrors(ArbitraryException)), 1) - - - -class LengthEnforcingConsumerTests(TestCase): - """ - Tests for L{LengthEnforcingConsumer}. - """ - def setUp(self): - self.result = Deferred() - self.producer = StringProducer(10) - self.transport = StringTransport() - self.enforcer = LengthEnforcingConsumer( - self.producer, self.transport, self.result) - - - def test_write(self): - """ - L{LengthEnforcingConsumer.write} calls the wrapped consumer's C{write} - method with the bytes it is passed as long as there are fewer of them - than the C{length} attribute indicates remain to be received. - """ - self.enforcer.write(b'abc') - self.assertEqual(self.transport.value(), b'abc') - self.transport.clear() - self.enforcer.write(b'def') - self.assertEqual(self.transport.value(), b'def') - - - def test_finishedEarly(self): - """ - L{LengthEnforcingConsumer._noMoreWritesExpected} raises - L{WrongBodyLength} if it is called before the indicated number of bytes - have been written. - """ - self.enforcer.write(b'x' * 9) - self.assertRaises(WrongBodyLength, self.enforcer._noMoreWritesExpected) - - - def test_writeTooMany(self, _unregisterAfter=False): - """ - If it is called with a total number of bytes exceeding the indicated - limit passed to L{LengthEnforcingConsumer.__init__}, - L{LengthEnforcingConsumer.write} fires the L{Deferred} with a - L{Failure} wrapping a L{WrongBodyLength} and also calls the - C{stopProducing} method of the producer. - """ - self.enforcer.write(b'x' * 10) - self.assertFalse(self.producer.stopped) - self.enforcer.write(b'x') - self.assertTrue(self.producer.stopped) - if _unregisterAfter: - self.enforcer._noMoreWritesExpected() - return self.assertFailure(self.result, WrongBodyLength) - - - def test_writeAfterNoMoreExpected(self): - """ - If L{LengthEnforcingConsumer.write} is called after - L{LengthEnforcingConsumer._noMoreWritesExpected}, it calls the - producer's C{stopProducing} method and raises L{ExcessWrite}. - """ - self.enforcer.write(b'x' * 10) - self.enforcer._noMoreWritesExpected() - self.assertFalse(self.producer.stopped) - self.assertRaises(ExcessWrite, self.enforcer.write, b'x') - self.assertTrue(self.producer.stopped) - - - def test_finishedLate(self): - """ - L{LengthEnforcingConsumer._noMoreWritesExpected} does nothing (in - particular, it does not raise any exception) if called after too many - bytes have been passed to C{write}. - """ - return self.test_writeTooMany(True) - - - def test_finished(self): - """ - If L{LengthEnforcingConsumer._noMoreWritesExpected} is called after - the correct number of bytes have been written it returns C{None}. - """ - self.enforcer.write(b'x' * 10) - self.assertIdentical(self.enforcer._noMoreWritesExpected(), None) - - - def test_stopProducingRaises(self): - """ - If L{LengthEnforcingConsumer.write} calls the producer's - C{stopProducing} because too many bytes were written and the - C{stopProducing} method raises an exception, the exception is logged - and the L{LengthEnforcingConsumer} still errbacks the finished - L{Deferred}. - """ - def brokenStopProducing(): - StringProducer.stopProducing(self.producer) - raise ArbitraryException(u"stopProducing is busted") - self.producer.stopProducing = brokenStopProducing - - def cbFinished(ignored): - self.assertEqual( - len(self.flushLoggedErrors(ArbitraryException)), 1) - d = self.test_writeTooMany() - d.addCallback(cbFinished) - return d - - - -class RequestBodyConsumerTests(TestCase): - """ - Tests for L{ChunkedEncoder} which sits between an L{ITransport} and a - request/response body producer and chunked encodes everything written to - it. - """ - def test_interface(self): - """ - L{ChunkedEncoder} instances provide L{IConsumer}. - """ - self.assertTrue( - verifyObject(IConsumer, ChunkedEncoder(StringTransport()))) - - - def test_write(self): - """ - L{ChunkedEncoder.write} writes to the transport the chunked encoded - form of the bytes passed to it. - """ - transport = StringTransport() - encoder = ChunkedEncoder(transport) - encoder.write(b'foo') - self.assertEqual(transport.value(), b'3\r\nfoo\r\n') - transport.clear() - encoder.write(b'x' * 16) - self.assertEqual(transport.value(), b'10\r\n' + b'x' * 16 + b'\r\n') - - - def test_producerRegistration(self): - """ - L{ChunkedEncoder.registerProducer} registers the given streaming - producer with its transport and L{ChunkedEncoder.unregisterProducer} - writes a zero-length chunk to its transport and unregisters the - transport's producer. - """ - transport = StringTransport() - producer = object() - encoder = ChunkedEncoder(transport) - encoder.registerProducer(producer, True) - self.assertIdentical(transport.producer, producer) - self.assertTrue(transport.streaming) - encoder.unregisterProducer() - self.assertIdentical(transport.producer, None) - self.assertEqual(transport.value(), b'0\r\n\r\n') - - - -class TransportProxyProducerTests(TestCase): - """ - Tests for L{TransportProxyProducer} which proxies the L{IPushProducer} - interface of a transport. - """ - def test_interface(self): - """ - L{TransportProxyProducer} instances provide L{IPushProducer}. - """ - self.assertTrue( - verifyObject(IPushProducer, TransportProxyProducer(None))) - - - def test_stopProxyingUnreferencesProducer(self): - """ - L{TransportProxyProducer._stopProxying} drops the reference to the - wrapped L{IPushProducer} provider. - """ - transport = StringTransport() - proxy = TransportProxyProducer(transport) - self.assertIdentical(proxy._producer, transport) - proxy._stopProxying() - self.assertIdentical(proxy._producer, None) - - - def test_resumeProducing(self): - """ - L{TransportProxyProducer.resumeProducing} calls the wrapped - transport's C{resumeProducing} method unless told to stop proxying. - """ - transport = StringTransport() - transport.pauseProducing() - - proxy = TransportProxyProducer(transport) - # The transport should still be paused. - self.assertEqual(transport.producerState, u'paused') - proxy.resumeProducing() - # The transport should now be resumed. - self.assertEqual(transport.producerState, u'producing') - - transport.pauseProducing() - proxy._stopProxying() - - # The proxy should no longer do anything to the transport. - proxy.resumeProducing() - self.assertEqual(transport.producerState, u'paused') - - - def test_pauseProducing(self): - """ - L{TransportProxyProducer.pauseProducing} calls the wrapped transport's - C{pauseProducing} method unless told to stop proxying. - """ - transport = StringTransport() - - proxy = TransportProxyProducer(transport) - # The transport should still be producing. - self.assertEqual(transport.producerState, u'producing') - proxy.pauseProducing() - # The transport should now be paused. - self.assertEqual(transport.producerState, u'paused') - - transport.resumeProducing() - proxy._stopProxying() - - # The proxy should no longer do anything to the transport. - proxy.pauseProducing() - self.assertEqual(transport.producerState, u'producing') - - - def test_stopProducing(self): - """ - L{TransportProxyProducer.stopProducing} calls the wrapped transport's - C{stopProducing} method unless told to stop proxying. - """ - transport = StringTransport() - proxy = TransportProxyProducer(transport) - # The transport should still be producing. - self.assertEqual(transport.producerState, u'producing') - proxy.stopProducing() - # The transport should now be stopped. - self.assertEqual(transport.producerState, u'stopped') - - transport = StringTransport() - proxy = TransportProxyProducer(transport) - proxy._stopProxying() - proxy.stopProducing() - # The transport should not have been stopped. - self.assertEqual(transport.producerState, u'producing') - - - -class ResponseTests(TestCase): - """ - Tests for L{Response}. - """ - - def test_verifyInterface(self): - """ - L{Response} instances provide L{IResponse}. - """ - response = justTransportResponse(StringTransport()) - self.assertTrue(verifyObject(IResponse, response)) - - - def test_makeConnection(self): - """ - The L{IProtocol} provider passed to L{Response.deliverBody} has its - C{makeConnection} method called with an L{IPushProducer} provider - hooked up to the response as an argument. - """ - producers = [] - transport = StringTransport() - class SomeProtocol(Protocol): - def makeConnection(self, producer): - producers.append(producer) - - consumer = SomeProtocol() - response = justTransportResponse(transport) - response.deliverBody(consumer) - [theProducer] = producers - theProducer.pauseProducing() - self.assertEqual(transport.producerState, u'paused') - theProducer.resumeProducing() - self.assertEqual(transport.producerState, u'producing') - - - def test_dataReceived(self): - """ - The L{IProtocol} provider passed to L{Response.deliverBody} has its - C{dataReceived} method called with bytes received as part of the - response body. - """ - bytes = [] - class ListConsumer(Protocol): - def dataReceived(self, data): - bytes.append(data) - - - consumer = ListConsumer() - response = justTransportResponse(StringTransport()) - response.deliverBody(consumer) - - response._bodyDataReceived(b'foo') - self.assertEqual(bytes, [b'foo']) - - - def test_connectionLost(self): - """ - The L{IProtocol} provider passed to L{Response.deliverBody} has its - C{connectionLost} method called with a L{Failure} wrapping - L{ResponseDone} when the response's C{_bodyDataFinished} method is - called. - """ - lost = [] - class ListConsumer(Protocol): - def connectionLost(self, reason): - lost.append(reason) - - consumer = ListConsumer() - response = justTransportResponse(StringTransport()) - response.deliverBody(consumer) - - response._bodyDataFinished() - lost[0].trap(ResponseDone) - self.assertEqual(len(lost), 1) - - # The protocol reference should be dropped, too, to facilitate GC or - # whatever. - self.assertIdentical(response._bodyProtocol, None) - - - def test_bufferEarlyData(self): - """ - If data is delivered to the L{Response} before a protocol is registered - with C{deliverBody}, that data is buffered until the protocol is - registered and then is delivered. - """ - bytes = [] - class ListConsumer(Protocol): - def dataReceived(self, data): - bytes.append(data) - - protocol = ListConsumer() - response = justTransportResponse(StringTransport()) - response._bodyDataReceived(b'foo') - response._bodyDataReceived(b'bar') - response.deliverBody(protocol) - response._bodyDataReceived(b'baz') - self.assertEqual(bytes, [b'foo', b'bar', b'baz']) - # Make sure the implementation-detail-byte-buffer is cleared because - # not clearing it wastes memory. - self.assertIdentical(response._bodyBuffer, None) - - - def test_multipleStartProducingFails(self): - """ - L{Response.deliverBody} raises L{RuntimeError} if called more than - once. - """ - response = justTransportResponse(StringTransport()) - response.deliverBody(Protocol()) - self.assertRaises(RuntimeError, response.deliverBody, Protocol()) - - - def test_startProducingAfterFinishedFails(self): - """ - L{Response.deliverBody} raises L{RuntimeError} if called after - L{Response._bodyDataFinished}. - """ - response = justTransportResponse(StringTransport()) - response.deliverBody(Protocol()) - response._bodyDataFinished() - self.assertRaises(RuntimeError, response.deliverBody, Protocol()) - - - def test_bodyDataReceivedAfterFinishedFails(self): - """ - L{Response._bodyDataReceived} raises L{RuntimeError} if called after - L{Response._bodyDataFinished} but before L{Response.deliverBody}. - """ - response = justTransportResponse(StringTransport()) - response._bodyDataFinished() - self.assertRaises(RuntimeError, response._bodyDataReceived, b'foo') - - - def test_bodyDataReceivedAfterDeliveryFails(self): - """ - L{Response._bodyDataReceived} raises L{RuntimeError} if called after - L{Response._bodyDataFinished} and after L{Response.deliverBody}. - """ - response = justTransportResponse(StringTransport()) - response._bodyDataFinished() - response.deliverBody(Protocol()) - self.assertRaises(RuntimeError, response._bodyDataReceived, b'foo') - - - def test_bodyDataFinishedAfterFinishedFails(self): - """ - L{Response._bodyDataFinished} raises L{RuntimeError} if called more - than once. - """ - response = justTransportResponse(StringTransport()) - response._bodyDataFinished() - self.assertRaises(RuntimeError, response._bodyDataFinished) - - - def test_bodyDataFinishedAfterDeliveryFails(self): - """ - L{Response._bodyDataFinished} raises L{RuntimeError} if called after - the body has been delivered. - """ - response = justTransportResponse(StringTransport()) - response._bodyDataFinished() - response.deliverBody(Protocol()) - self.assertRaises(RuntimeError, response._bodyDataFinished) - - - def test_transportResumed(self): - """ - L{Response.deliverBody} resumes the HTTP connection's transport - before passing it to the consumer's C{makeConnection} method. - """ - transportState = [] - class ListConsumer(Protocol): - def makeConnection(self, transport): - transportState.append(transport.producerState) - - transport = StringTransport() - transport.pauseProducing() - protocol = ListConsumer() - response = justTransportResponse(transport) - self.assertEqual(transport.producerState, u'paused') - response.deliverBody(protocol) - self.assertEqual(transportState, [u'producing']) - - - def test_bodyDataFinishedBeforeStartProducing(self): - """ - If the entire body is delivered to the L{Response} before the - response's C{deliverBody} method is called, the protocol passed to - C{deliverBody} is immediately given the body data and then - disconnected. - """ - transport = StringTransport() - response = justTransportResponse(transport) - response._bodyDataReceived(b'foo') - response._bodyDataReceived(b'bar') - response._bodyDataFinished() - - protocol = AccumulatingProtocol() - response.deliverBody(protocol) - self.assertEqual(protocol.data, b'foobar') - protocol.closedReason.trap(ResponseDone) - - - def test_finishedWithErrorWhenConnected(self): - """ - The L{Failure} passed to L{Response._bodyDataFinished} when the response - is in the I{connected} state is passed to the C{connectionLost} method - of the L{IProtocol} provider passed to the L{Response}'s - C{deliverBody} method. - """ - transport = StringTransport() - response = justTransportResponse(transport) - - protocol = AccumulatingProtocol() - response.deliverBody(protocol) - - # Sanity check - this test is for the connected state - self.assertEqual(response._state, u'CONNECTED') - response._bodyDataFinished(Failure(ArbitraryException())) - - protocol.closedReason.trap(ArbitraryException) - - - def test_finishedWithErrorWhenInitial(self): - """ - The L{Failure} passed to L{Response._bodyDataFinished} when the response - is in the I{initial} state is passed to the C{connectionLost} method of - the L{IProtocol} provider passed to the L{Response}'s C{deliverBody} - method. - """ - transport = StringTransport() - response = justTransportResponse(transport) - - # Sanity check - this test is for the initial state - self.assertEqual(response._state, u'INITIAL') - response._bodyDataFinished(Failure(ArbitraryException())) - - protocol = AccumulatingProtocol() - response.deliverBody(protocol) - - protocol.closedReason.trap(ArbitraryException) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_proxy.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_proxy.py deleted file mode 100644 index 3ed1893..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_proxy.py +++ /dev/null @@ -1,544 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test for L{twisted.web.proxy}. -""" - -from twisted.trial.unittest import TestCase -from twisted.test.proto_helpers import StringTransportWithDisconnection -from twisted.test.proto_helpers import MemoryReactor - -from twisted.web.resource import Resource -from twisted.web.server import Site -from twisted.web.proxy import ReverseProxyResource, ProxyClientFactory -from twisted.web.proxy import ProxyClient, ProxyRequest, ReverseProxyRequest -from twisted.web.test.test_web import DummyRequest - - -class ReverseProxyResourceTests(TestCase): - """ - Tests for L{ReverseProxyResource}. - """ - - def _testRender(self, uri, expectedURI): - """ - Check that a request pointing at C{uri} produce a new proxy connection, - with the path of this request pointing at C{expectedURI}. - """ - root = Resource() - reactor = MemoryReactor() - resource = ReverseProxyResource("127.0.0.1", 1234, "/path", reactor) - root.putChild('index', resource) - site = Site(root) - - transport = StringTransportWithDisconnection() - channel = site.buildProtocol(None) - channel.makeConnection(transport) - # Clear the timeout if the tests failed - self.addCleanup(channel.connectionLost, None) - - channel.dataReceived("GET %s HTTP/1.1\r\nAccept: text/html\r\n\r\n" % - (uri,)) - - # Check that one connection has been created, to the good host/port - self.assertEqual(len(reactor.tcpClients), 1) - self.assertEqual(reactor.tcpClients[0][0], "127.0.0.1") - self.assertEqual(reactor.tcpClients[0][1], 1234) - - # Check the factory passed to the connect, and its given path - factory = reactor.tcpClients[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEqual(factory.rest, expectedURI) - self.assertEqual(factory.headers["host"], "127.0.0.1:1234") - - - def test_render(self): - """ - Test that L{ReverseProxyResource.render} initiates a connection to the - given server with a L{ProxyClientFactory} as parameter. - """ - return self._testRender("/index", "/path") - - - def test_renderWithQuery(self): - """ - Test that L{ReverseProxyResource.render} passes query parameters to the - created factory. - """ - return self._testRender("/index?foo=bar", "/path?foo=bar") - - - def test_getChild(self): - """ - The L{ReverseProxyResource.getChild} method should return a resource - instance with the same class as the originating resource, forward - port, host, and reactor values, and update the path value with the - value passed. - """ - reactor = MemoryReactor() - resource = ReverseProxyResource("127.0.0.1", 1234, "/path", reactor) - child = resource.getChild('foo', None) - # The child should keep the same class - self.assertIsInstance(child, ReverseProxyResource) - self.assertEqual(child.path, "/path/foo") - self.assertEqual(child.port, 1234) - self.assertEqual(child.host, "127.0.0.1") - self.assertIdentical(child.reactor, resource.reactor) - - - def test_getChildWithSpecial(self): - """ - The L{ReverseProxyResource} return by C{getChild} has a path which has - already been quoted. - """ - resource = ReverseProxyResource("127.0.0.1", 1234, "/path") - child = resource.getChild(' /%', None) - self.assertEqual(child.path, "/path/%20%2F%25") - - - -class DummyChannel(object): - """ - A dummy HTTP channel, that does nothing but holds a transport and saves - connection lost. - - @ivar transport: the transport used by the client. - @ivar lostReason: the reason saved at connection lost. - """ - - def __init__(self, transport): - """ - Hold a reference to the transport. - """ - self.transport = transport - self.lostReason = None - - - def connectionLost(self, reason): - """ - Keep track of the connection lost reason. - """ - self.lostReason = reason - - - -class ProxyClientTests(TestCase): - """ - Tests for L{ProxyClient}. - """ - - def _parseOutHeaders(self, content): - """ - Parse the headers out of some web content. - - @param content: Bytes received from a web server. - @return: A tuple of (requestLine, headers, body). C{headers} is a dict - of headers, C{requestLine} is the first line (e.g. "POST /foo ...") - and C{body} is whatever is left. - """ - headers, body = content.split('\r\n\r\n') - headers = headers.split('\r\n') - requestLine = headers.pop(0) - return ( - requestLine, dict(header.split(': ') for header in headers), body) - - - def makeRequest(self, path): - """ - Make a dummy request object for the URL path. - - @param path: A URL path, beginning with a slash. - @return: A L{DummyRequest}. - """ - return DummyRequest(path) - - - def makeProxyClient(self, request, method="GET", headers=None, - requestBody=""): - """ - Make a L{ProxyClient} object used for testing. - - @param request: The request to use. - @param method: The HTTP method to use, GET by default. - @param headers: The HTTP headers to use expressed as a dict. If not - provided, defaults to {'accept': 'text/html'}. - @param requestBody: The body of the request. Defaults to the empty - string. - @return: A L{ProxyClient} - """ - if headers is None: - headers = {"accept": "text/html"} - path = '/' + request.postpath - return ProxyClient( - method, path, 'HTTP/1.0', headers, requestBody, request) - - - def connectProxy(self, proxyClient): - """ - Connect a proxy client to a L{StringTransportWithDisconnection}. - - @param proxyClient: A L{ProxyClient}. - @return: The L{StringTransportWithDisconnection}. - """ - clientTransport = StringTransportWithDisconnection() - clientTransport.protocol = proxyClient - proxyClient.makeConnection(clientTransport) - return clientTransport - - - def assertForwardsHeaders(self, proxyClient, requestLine, headers): - """ - Assert that C{proxyClient} sends C{headers} when it connects. - - @param proxyClient: A L{ProxyClient}. - @param requestLine: The request line we expect to be sent. - @param headers: A dict of headers we expect to be sent. - @return: If the assertion is successful, return the request body as - bytes. - """ - self.connectProxy(proxyClient) - requestContent = proxyClient.transport.value() - receivedLine, receivedHeaders, body = self._parseOutHeaders( - requestContent) - self.assertEqual(receivedLine, requestLine) - self.assertEqual(receivedHeaders, headers) - return body - - - def makeResponseBytes(self, code, message, headers, body): - lines = ["HTTP/1.0 %d %s" % (code, message)] - for header, values in headers: - for value in values: - lines.append("%s: %s" % (header, value)) - lines.extend(['', body]) - return '\r\n'.join(lines) - - - def assertForwardsResponse(self, request, code, message, headers, body): - """ - Assert that C{request} has forwarded a response from the server. - - @param request: A L{DummyRequest}. - @param code: The expected HTTP response code. - @param message: The expected HTTP message. - @param headers: The expected HTTP headers. - @param body: The expected response body. - """ - self.assertEqual(request.responseCode, code) - self.assertEqual(request.responseMessage, message) - receivedHeaders = list(request.responseHeaders.getAllRawHeaders()) - receivedHeaders.sort() - expectedHeaders = headers[:] - expectedHeaders.sort() - self.assertEqual(receivedHeaders, expectedHeaders) - self.assertEqual(''.join(request.written), body) - - - def _testDataForward(self, code, message, headers, body, method="GET", - requestBody="", loseConnection=True): - """ - Build a fake proxy connection, and send C{data} over it, checking that - it's forwarded to the originating request. - """ - request = self.makeRequest('foo') - client = self.makeProxyClient( - request, method, {'accept': 'text/html'}, requestBody) - - receivedBody = self.assertForwardsHeaders( - client, '%s /foo HTTP/1.0' % (method,), - {'connection': 'close', 'accept': 'text/html'}) - - self.assertEqual(receivedBody, requestBody) - - # Fake an answer - client.dataReceived( - self.makeResponseBytes(code, message, headers, body)) - - # Check that the response data has been forwarded back to the original - # requester. - self.assertForwardsResponse(request, code, message, headers, body) - - # Check that when the response is done, the request is finished. - if loseConnection: - client.transport.loseConnection() - - # Even if we didn't call loseConnection, the transport should be - # disconnected. This lets us not rely on the server to close our - # sockets for us. - self.assertFalse(client.transport.connected) - self.assertEqual(request.finished, 1) - - - def test_forward(self): - """ - When connected to the server, L{ProxyClient} should send the saved - request, with modifications of the headers, and then forward the result - to the parent request. - """ - return self._testDataForward( - 200, "OK", [("Foo", ["bar", "baz"])], "Some data\r\n") - - - def test_postData(self): - """ - Try to post content in the request, and check that the proxy client - forward the body of the request. - """ - return self._testDataForward( - 200, "OK", [("Foo", ["bar"])], "Some data\r\n", "POST", "Some content") - - - def test_statusWithMessage(self): - """ - If the response contains a status with a message, it should be - forwarded to the parent request with all the information. - """ - return self._testDataForward( - 404, "Not Found", [], "") - - - def test_contentLength(self): - """ - If the response contains a I{Content-Length} header, the inbound - request object should still only have C{finish} called on it once. - """ - data = "foo bar baz" - return self._testDataForward( - 200, "OK", [("Content-Length", [str(len(data))])], data) - - - def test_losesConnection(self): - """ - If the response contains a I{Content-Length} header, the outgoing - connection is closed when all response body data has been received. - """ - data = "foo bar baz" - return self._testDataForward( - 200, "OK", [("Content-Length", [str(len(data))])], data, - loseConnection=False) - - - def test_headersCleanups(self): - """ - The headers given at initialization should be modified: - B{proxy-connection} should be removed if present, and B{connection} - should be added. - """ - client = ProxyClient('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html", "proxy-connection": "foo"}, '', None) - self.assertEqual(client.headers, - {"accept": "text/html", "connection": "close"}) - - - def test_keepaliveNotForwarded(self): - """ - The proxy doesn't really know what to do with keepalive things from - the remote server, so we stomp over any keepalive header we get from - the client. - """ - headers = { - "accept": "text/html", - 'keep-alive': '300', - 'connection': 'keep-alive', - } - expectedHeaders = headers.copy() - expectedHeaders['connection'] = 'close' - del expectedHeaders['keep-alive'] - client = ProxyClient('GET', '/foo', 'HTTP/1.0', headers, '', None) - self.assertForwardsHeaders( - client, 'GET /foo HTTP/1.0', expectedHeaders) - - - def test_defaultHeadersOverridden(self): - """ - L{server.Request} within the proxy sets certain response headers by - default. When we get these headers back from the remote server, the - defaults are overridden rather than simply appended. - """ - request = self.makeRequest('foo') - request.responseHeaders.setRawHeaders('server', ['old-bar']) - request.responseHeaders.setRawHeaders('date', ['old-baz']) - request.responseHeaders.setRawHeaders('content-type', ["old/qux"]) - client = self.makeProxyClient(request, headers={'accept': 'text/html'}) - self.connectProxy(client) - headers = { - 'Server': ['bar'], - 'Date': ['2010-01-01'], - 'Content-Type': ['application/x-baz'], - } - client.dataReceived( - self.makeResponseBytes(200, "OK", headers.items(), '')) - self.assertForwardsResponse( - request, 200, 'OK', headers.items(), '') - - - -class ProxyClientFactoryTests(TestCase): - """ - Tests for L{ProxyClientFactory}. - """ - - def test_connectionFailed(self): - """ - Check that L{ProxyClientFactory.clientConnectionFailed} produces - a B{501} response to the parent request. - """ - request = DummyRequest(['foo']) - factory = ProxyClientFactory('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html"}, '', request) - - factory.clientConnectionFailed(None, None) - self.assertEqual(request.responseCode, 501) - self.assertEqual(request.responseMessage, "Gateway error") - self.assertEqual( - list(request.responseHeaders.getAllRawHeaders()), - [("Content-Type", ["text/html"])]) - self.assertEqual( - ''.join(request.written), - "<H1>Could not connect</H1>") - self.assertEqual(request.finished, 1) - - - def test_buildProtocol(self): - """ - L{ProxyClientFactory.buildProtocol} should produce a L{ProxyClient} - with the same values of attributes (with updates on the headers). - """ - factory = ProxyClientFactory('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html"}, 'Some data', - None) - proto = factory.buildProtocol(None) - self.assertIsInstance(proto, ProxyClient) - self.assertEqual(proto.command, 'GET') - self.assertEqual(proto.rest, '/foo') - self.assertEqual(proto.data, 'Some data') - self.assertEqual(proto.headers, - {"accept": "text/html", "connection": "close"}) - - - -class ProxyRequestTests(TestCase): - """ - Tests for L{ProxyRequest}. - """ - - def _testProcess(self, uri, expectedURI, method="GET", data=""): - """ - Build a request pointing at C{uri}, and check that a proxied request - is created, pointing a C{expectedURI}. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = MemoryReactor() - request = ProxyRequest(channel, False, reactor) - request.gotLength(len(data)) - request.handleContentChunk(data) - request.requestReceived(method, 'http://example.com%s' % (uri,), - 'HTTP/1.0') - - self.assertEqual(len(reactor.tcpClients), 1) - self.assertEqual(reactor.tcpClients[0][0], "example.com") - self.assertEqual(reactor.tcpClients[0][1], 80) - - factory = reactor.tcpClients[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEqual(factory.command, method) - self.assertEqual(factory.version, 'HTTP/1.0') - self.assertEqual(factory.headers, {'host': 'example.com'}) - self.assertEqual(factory.data, data) - self.assertEqual(factory.rest, expectedURI) - self.assertEqual(factory.father, request) - - - def test_process(self): - """ - L{ProxyRequest.process} should create a connection to the given server, - with a L{ProxyClientFactory} as connection factory, with the correct - parameters: - - forward comment, version and data values - - update headers with the B{host} value - - remove the host from the URL - - pass the request as parent request - """ - return self._testProcess("/foo/bar", "/foo/bar") - - - def test_processWithoutTrailingSlash(self): - """ - If the incoming request doesn't contain a slash, - L{ProxyRequest.process} should add one when instantiating - L{ProxyClientFactory}. - """ - return self._testProcess("", "/") - - - def test_processWithData(self): - """ - L{ProxyRequest.process} should be able to retrieve request body and - to forward it. - """ - return self._testProcess( - "/foo/bar", "/foo/bar", "POST", "Some content") - - - def test_processWithPort(self): - """ - Check that L{ProxyRequest.process} correctly parse port in the incoming - URL, and create a outgoing connection with this port. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = MemoryReactor() - request = ProxyRequest(channel, False, reactor) - request.gotLength(0) - request.requestReceived('GET', 'http://example.com:1234/foo/bar', - 'HTTP/1.0') - - # That should create one connection, with the port parsed from the URL - self.assertEqual(len(reactor.tcpClients), 1) - self.assertEqual(reactor.tcpClients[0][0], "example.com") - self.assertEqual(reactor.tcpClients[0][1], 1234) - - - -class DummyFactory(object): - """ - A simple holder for C{host} and C{port} information. - """ - - def __init__(self, host, port): - self.host = host - self.port = port - - - -class ReverseProxyRequestTests(TestCase): - """ - Tests for L{ReverseProxyRequest}. - """ - - def test_process(self): - """ - L{ReverseProxyRequest.process} should create a connection to its - factory host/port, using a L{ProxyClientFactory} instantiated with the - correct parameters, and particularly set the B{host} header to the - factory host. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = MemoryReactor() - request = ReverseProxyRequest(channel, False, reactor) - request.factory = DummyFactory("example.com", 1234) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - - # Check that one connection has been created, to the good host/port - self.assertEqual(len(reactor.tcpClients), 1) - self.assertEqual(reactor.tcpClients[0][0], "example.com") - self.assertEqual(reactor.tcpClients[0][1], 1234) - - # Check the factory passed to the connect, and its headers - factory = reactor.tcpClients[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEqual(factory.headers, {'host': 'example.com'}) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_resource.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_resource.py deleted file mode 100644 index 38cbe59..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_resource.py +++ /dev/null @@ -1,261 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.resource}. -""" - -from twisted.trial.unittest import TestCase - -from twisted.web.error import UnsupportedMethod -from twisted.web.resource import ( - NOT_FOUND, FORBIDDEN, Resource, ErrorPage, NoResource, ForbiddenResource, - getChildForRequest) -from twisted.web.test.requesthelper import DummyRequest - - -class ErrorPageTests(TestCase): - """ - Tests for L{ErrorPage}, L{NoResource}, and L{ForbiddenResource}. - """ - - errorPage = ErrorPage - noResource = NoResource - forbiddenResource = ForbiddenResource - - def test_getChild(self): - """ - The C{getChild} method of L{ErrorPage} returns the L{ErrorPage} it is - called on. - """ - page = self.errorPage(321, "foo", "bar") - self.assertIdentical(page.getChild(b"name", object()), page) - - - def _pageRenderingTest(self, page, code, brief, detail): - request = DummyRequest([b'']) - template = ( - u"\n" - u"<html>\n" - u" <head><title>%s - %s</title></head>\n" - u" <body>\n" - u" <h1>%s</h1>\n" - u" <p>%s</p>\n" - u" </body>\n" - u"</html>\n") - expected = template % (code, brief, brief, detail) - self.assertEqual( - page.render(request), expected.encode('utf-8')) - self.assertEqual(request.responseCode, code) - self.assertEqual( - request.outgoingHeaders, - {b'content-type': b'text/html; charset=utf-8'}) - - - def test_errorPageRendering(self): - """ - L{ErrorPage.render} returns a C{bytes} describing the error defined by - the response code and message passed to L{ErrorPage.__init__}. It also - uses that response code to set the response code on the L{Request} - passed in. - """ - code = 321 - brief = "brief description text" - detail = "much longer text might go here" - page = self.errorPage(code, brief, detail) - self._pageRenderingTest(page, code, brief, detail) - - - def test_noResourceRendering(self): - """ - L{NoResource} sets the HTTP I{NOT FOUND} code. - """ - detail = "long message" - page = self.noResource(detail) - self._pageRenderingTest(page, NOT_FOUND, "No Such Resource", detail) - - - def test_forbiddenResourceRendering(self): - """ - L{ForbiddenResource} sets the HTTP I{FORBIDDEN} code. - """ - detail = "longer message" - page = self.forbiddenResource(detail) - self._pageRenderingTest(page, FORBIDDEN, "Forbidden Resource", detail) - - - -class DynamicChild(Resource): - """ - A L{Resource} to be created on the fly by L{DynamicChildren}. - """ - def __init__(self, path, request): - Resource.__init__(self) - self.path = path - self.request = request - - - -class DynamicChildren(Resource): - """ - A L{Resource} with dynamic children. - """ - def getChild(self, path, request): - return DynamicChild(path, request) - - - -class BytesReturnedRenderable(Resource): - """ - A L{Resource} with minimal capabilities to render a response. - """ - def __init__(self, response): - """ - @param response: A C{bytes} object giving the value to return from - C{render_GET}. - """ - Resource.__init__(self) - self._response = response - - - def render_GET(self, request): - """ - Render a response to a I{GET} request by returning a short byte string - to be written by the server. - """ - return self._response - - - -class ImplicitAllowedMethods(Resource): - """ - A L{Resource} which implicitly defines its allowed methods by defining - renderers to handle them. - """ - def render_GET(self, request): - pass - - - def render_PUT(self, request): - pass - - - -class ResourceTests(TestCase): - """ - Tests for L{Resource}. - """ - def test_staticChildren(self): - """ - L{Resource.putChild} adds a I{static} child to the resource. That child - is returned from any call to L{Resource.getChildWithDefault} for the - child's path. - """ - resource = Resource() - child = Resource() - sibling = Resource() - resource.putChild(b"foo", child) - resource.putChild(b"bar", sibling) - self.assertIdentical( - child, resource.getChildWithDefault(b"foo", DummyRequest([]))) - - - def test_dynamicChildren(self): - """ - L{Resource.getChildWithDefault} delegates to L{Resource.getChild} when - the requested path is not associated with any static child. - """ - path = b"foo" - request = DummyRequest([]) - resource = DynamicChildren() - child = resource.getChildWithDefault(path, request) - self.assertIsInstance(child, DynamicChild) - self.assertEqual(child.path, path) - self.assertIdentical(child.request, request) - - - def test_defaultHEAD(self): - """ - When not otherwise overridden, L{Resource.render} treats a I{HEAD} - request as if it were a I{GET} request. - """ - expected = b"insert response here" - request = DummyRequest([]) - request.method = b'HEAD' - resource = BytesReturnedRenderable(expected) - self.assertEqual(expected, resource.render(request)) - - - def test_explicitAllowedMethods(self): - """ - The L{UnsupportedMethod} raised by L{Resource.render} for an unsupported - request method has a C{allowedMethods} attribute set to the value of the - C{allowedMethods} attribute of the L{Resource}, if it has one. - """ - expected = [b'GET', b'HEAD', b'PUT'] - resource = Resource() - resource.allowedMethods = expected - request = DummyRequest([]) - request.method = b'FICTIONAL' - exc = self.assertRaises(UnsupportedMethod, resource.render, request) - self.assertEqual(set(expected), set(exc.allowedMethods)) - - - def test_implicitAllowedMethods(self): - """ - The L{UnsupportedMethod} raised by L{Resource.render} for an unsupported - request method has a C{allowedMethods} attribute set to a list of the - methods supported by the L{Resource}, as determined by the - I{render_}-prefixed methods which it defines, if C{allowedMethods} is - not explicitly defined by the L{Resource}. - """ - expected = set([b'GET', b'HEAD', b'PUT']) - resource = ImplicitAllowedMethods() - request = DummyRequest([]) - request.method = b'FICTIONAL' - exc = self.assertRaises(UnsupportedMethod, resource.render, request) - self.assertEqual(expected, set(exc.allowedMethods)) - - - - -class GetChildForRequestTests(TestCase): - """ - Tests for L{getChildForRequest}. - """ - def test_exhaustedPostPath(self): - """ - L{getChildForRequest} returns whatever resource has been reached by the - time the request's C{postpath} is empty. - """ - request = DummyRequest([]) - resource = Resource() - result = getChildForRequest(resource, request) - self.assertIdentical(resource, result) - - - def test_leafResource(self): - """ - L{getChildForRequest} returns the first resource it encounters with a - C{isLeaf} attribute set to C{True}. - """ - request = DummyRequest([b"foo", b"bar"]) - resource = Resource() - resource.isLeaf = True - result = getChildForRequest(resource, request) - self.assertIdentical(resource, result) - - - def test_postPathToPrePath(self): - """ - As path segments from the request are traversed, they are taken from - C{postpath} and put into C{prepath}. - """ - request = DummyRequest([b"foo", b"bar"]) - root = Resource() - child = Resource() - child.isLeaf = True - root.putChild(b"foo", child) - self.assertIdentical(child, getChildForRequest(root, request)) - self.assertEqual(request.prepath, [b"foo"]) - self.assertEqual(request.postpath, [b"bar"]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_script.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_script.py deleted file mode 100644 index 3459fff..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_script.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.script}. -""" - -import os - -from twisted.trial.unittest import TestCase -from twisted.python.filepath import FilePath -from twisted.web.http import NOT_FOUND -from twisted.web.script import ResourceScriptDirectory, PythonScript -from twisted.web.test._util import _render -from twisted.web.test.requesthelper import DummyRequest - - -class ResourceScriptDirectoryTests(TestCase): - """ - Tests for L{ResourceScriptDirectory}. - """ - def test_renderNotFound(self): - """ - L{ResourceScriptDirectory.render} sets the HTTP response code to I{NOT - FOUND}. - """ - resource = ResourceScriptDirectory(self.mktemp()) - request = DummyRequest([b'']) - d = _render(resource, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, NOT_FOUND) - d.addCallback(cbRendered) - return d - - - def test_notFoundChild(self): - """ - L{ResourceScriptDirectory.getChild} returns a resource which renders an - response with the HTTP I{NOT FOUND} status code if the indicated child - does not exist as an entry in the directory used to initialized the - L{ResourceScriptDirectory}. - """ - path = self.mktemp() - os.makedirs(path) - resource = ResourceScriptDirectory(path) - request = DummyRequest([b'foo']) - child = resource.getChild("foo", request) - d = _render(child, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, NOT_FOUND) - d.addCallback(cbRendered) - return d - - - def test_render(self): - """ - L{ResourceScriptDirectory.getChild} returns a resource which renders a - response with the HTTP 200 status code and the content of the rpy's - C{request} global. - """ - tmp = FilePath(self.mktemp()) - tmp.makedirs() - tmp.child("test.rpy").setContent(b""" -from twisted.web.resource import Resource -class TestResource(Resource): - isLeaf = True - def render_GET(self, request): - return b'ok' -resource = TestResource()""") - resource = ResourceScriptDirectory(tmp._asBytesPath()) - request = DummyRequest([b'']) - child = resource.getChild(b"test.rpy", request) - d = _render(child, request) - def cbRendered(ignored): - self.assertEqual(b"".join(request.written), b"ok") - d.addCallback(cbRendered) - return d - - - -class PythonScriptTests(TestCase): - """ - Tests for L{PythonScript}. - """ - def test_notFoundRender(self): - """ - If the source file a L{PythonScript} is initialized with doesn't exist, - L{PythonScript.render} sets the HTTP response code to I{NOT FOUND}. - """ - resource = PythonScript(self.mktemp(), None) - request = DummyRequest([b'']) - d = _render(resource, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, NOT_FOUND) - d.addCallback(cbRendered) - return d - - - def test_renderException(self): - """ - L{ResourceScriptDirectory.getChild} returns a resource which renders a - response with the HTTP 200 status code and the content of the rpy's - C{request} global. - """ - tmp = FilePath(self.mktemp()) - tmp.makedirs() - child = tmp.child("test.epy") - child.setContent(b'raise Exception("nooo")') - resource = PythonScript(child._asBytesPath(), None) - request = DummyRequest([b'']) - d = _render(resource, request) - def cbRendered(ignored): - self.assertIn(b"nooo", b"".join(request.written)) - d.addCallback(cbRendered) - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_soap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_soap.py deleted file mode 100644 index d58710c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_soap.py +++ /dev/null @@ -1,114 +0,0 @@ -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -# - -"""Test SOAP support.""" - -try: - import SOAPpy -except ImportError: - SOAPpy = None - class SOAPPublisher: pass -else: - from twisted.web import soap - SOAPPublisher = soap.SOAPPublisher - -from twisted.trial import unittest -from twisted.web import server, error -from twisted.internet import reactor, defer - - -class Test(SOAPPublisher): - - def soap_add(self, a, b): - return a + b - - def soap_kwargs(self, a=1, b=2): - return a + b - soap_kwargs.useKeywords=True - - def soap_triple(self, string, num): - return [string, num, None] - - def soap_struct(self): - return SOAPpy.structType({"a": "c"}) - - def soap_defer(self, x): - return defer.succeed(x) - - def soap_deferFail(self): - return defer.fail(ValueError()) - - def soap_fail(self): - raise RuntimeError - - def soap_deferFault(self): - return defer.fail(ValueError()) - - def soap_complex(self): - return {"a": ["b", "c", 12, []], "D": "foo"} - - def soap_dict(self, map, key): - return map[key] - - -class SOAPTests(unittest.TestCase): - - def setUp(self): - self.publisher = Test() - self.p = reactor.listenTCP(0, server.Site(self.publisher), - interface="127.0.0.1") - self.port = self.p.getHost().port - - def tearDown(self): - return self.p.stopListening() - - def proxy(self): - return soap.Proxy("http://127.0.0.1:%d/" % self.port) - - def testResults(self): - inputOutput = [ - ("add", (2, 3), 5), - ("defer", ("a",), "a"), - ("dict", ({"a": 1}, "a"), 1), - ("triple", ("a", 1), ["a", 1, None])] - - dl = [] - for meth, args, outp in inputOutput: - d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEqual, outp) - dl.append(d) - - # SOAPpy kinda blows. - d = self.proxy().callRemote('complex') - d.addCallback(lambda result: result._asdict()) - d.addCallback(self.assertEqual, {"a": ["b", "c", 12, []], "D": "foo"}) - dl.append(d) - - # We now return to our regularly scheduled program, already in progress. - return defer.DeferredList(dl, fireOnOneErrback=True) - - def testMethodNotFound(self): - """ - Check that a non existing method return error 500. - """ - d = self.proxy().callRemote('doesntexist') - self.assertFailure(d, error.Error) - def cb(err): - self.assertEqual(int(err.status), 500) - d.addCallback(cb) - return d - - def testLookupFunction(self): - """ - Test lookupFunction method on publisher, to see available remote - methods. - """ - self.assertTrue(self.publisher.lookupFunction("add")) - self.assertTrue(self.publisher.lookupFunction("fail")) - self.assertFalse(self.publisher.lookupFunction("foobar")) - -if not SOAPpy: - SOAPTests.skip = "SOAPpy not installed" - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_stan.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_stan.py deleted file mode 100644 index 8014501..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_stan.py +++ /dev/null @@ -1,139 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web._stan} portion of the L{twisted.web.template} -implementation. -""" - -from twisted.web.template import Comment, CDATA, CharRef, Tag -from twisted.trial.unittest import TestCase - -def proto(*a, **kw): - """ - Produce a new tag for testing. - """ - return Tag('hello')(*a, **kw) - - -class TagTests(TestCase): - """ - Tests for L{Tag}. - """ - def test_fillSlots(self): - """ - L{Tag.fillSlots} returns self. - """ - tag = proto() - self.assertIdentical(tag, tag.fillSlots(test='test')) - - - def test_cloneShallow(self): - """ - L{Tag.clone} copies all attributes and children of a tag, including its - render attribute. If the shallow flag is C{False}, that's where it - stops. - """ - innerList = ["inner list"] - tag = proto("How are you", innerList, - hello="world", render="aSampleMethod") - tag.fillSlots(foo='bar') - tag.filename = "foo/bar" - tag.lineNumber = 6 - tag.columnNumber = 12 - clone = tag.clone(deep=False) - self.assertEqual(clone.attributes['hello'], 'world') - self.assertNotIdentical(clone.attributes, tag.attributes) - self.assertEqual(clone.children, ["How are you", innerList]) - self.assertNotIdentical(clone.children, tag.children) - self.assertIdentical(clone.children[1], innerList) - self.assertEqual(tag.slotData, clone.slotData) - self.assertNotIdentical(tag.slotData, clone.slotData) - self.assertEqual(clone.filename, "foo/bar") - self.assertEqual(clone.lineNumber, 6) - self.assertEqual(clone.columnNumber, 12) - self.assertEqual(clone.render, "aSampleMethod") - - - def test_cloneDeep(self): - """ - L{Tag.clone} copies all attributes and children of a tag, including its - render attribute. In its normal operating mode (where the deep flag is - C{True}, as is the default), it will clone all sub-lists and sub-tags. - """ - innerTag = proto("inner") - innerList = ["inner list"] - tag = proto("How are you", innerTag, innerList, - hello="world", render="aSampleMethod") - tag.fillSlots(foo='bar') - tag.filename = "foo/bar" - tag.lineNumber = 6 - tag.columnNumber = 12 - clone = tag.clone() - self.assertEqual(clone.attributes['hello'], 'world') - self.assertNotIdentical(clone.attributes, tag.attributes) - self.assertNotIdentical(clone.children, tag.children) - # sanity check - self.assertIdentical(tag.children[1], innerTag) - # clone should have sub-clone - self.assertNotIdentical(clone.children[1], innerTag) - # sanity check - self.assertIdentical(tag.children[2], innerList) - # clone should have sub-clone - self.assertNotIdentical(clone.children[2], innerList) - self.assertEqual(tag.slotData, clone.slotData) - self.assertNotIdentical(tag.slotData, clone.slotData) - self.assertEqual(clone.filename, "foo/bar") - self.assertEqual(clone.lineNumber, 6) - self.assertEqual(clone.columnNumber, 12) - self.assertEqual(clone.render, "aSampleMethod") - - - def test_clear(self): - """ - L{Tag.clear} removes all children from a tag, but leaves its attributes - in place. - """ - tag = proto("these are", "children", "cool", andSoIs='this-attribute') - tag.clear() - self.assertEqual(tag.children, []) - self.assertEqual(tag.attributes, {'andSoIs': 'this-attribute'}) - - - def test_suffix(self): - """ - L{Tag.__call__} accepts Python keywords with a suffixed underscore as - the DOM attribute of that literal suffix. - """ - proto = Tag('div') - tag = proto() - tag(class_='a') - self.assertEqual(tag.attributes, {'class': 'a'}) - - - def test_commentRepr(self): - """ - L{Comment.__repr__} returns a value which makes it easy to see what's in - the comment. - """ - self.assertEqual(repr(Comment(u"hello there")), - "Comment(u'hello there')") - - - def test_cdataRepr(self): - """ - L{CDATA.__repr__} returns a value which makes it easy to see what's in - the comment. - """ - self.assertEqual(repr(CDATA(u"test data")), - "CDATA(u'test data')") - - - def test_charrefRepr(self): - """ - L{CharRef.__repr__} returns a value which makes it easy to see what - character is referred to. - """ - snowman = ord(u"\N{SNOWMAN}") - self.assertEqual(repr(CharRef(snowman)), "CharRef(9731)") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_static.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_static.py deleted file mode 100644 index 30917e7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_static.py +++ /dev/null @@ -1,1668 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.static}. -""" -import errno -import inspect -import mimetypes -import os -import re - - -from io import BytesIO as StringIO - -from zope.interface.verify import verifyObject - -from twisted.internet import abstract, interfaces -from twisted.python.runtime import platform -from twisted.python.filepath import FilePath -from twisted.python import log -from twisted.python.compat import iteritems, intToBytes, networkString -from twisted.trial.unittest import TestCase -from twisted.web import static, http, script, resource -from twisted.web.server import UnsupportedMethod -from twisted.web.test.requesthelper import DummyRequest -from twisted.web.test._util import _render - - -class StaticDataTests(TestCase): - """ - Tests for L{Data}. - """ - def test_headRequest(self): - """ - L{Data.render} returns an empty response body for a I{HEAD} request. - """ - data = static.Data(b"foo", "bar") - request = DummyRequest(['']) - request.method = b'HEAD' - d = _render(data, request) - def cbRendered(ignored): - self.assertEqual(b''.join(request.written), b"") - d.addCallback(cbRendered) - return d - - - def test_invalidMethod(self): - """ - L{Data.render} raises L{UnsupportedMethod} in response to a non-I{GET}, - non-I{HEAD} request. - """ - data = static.Data(b"foo", b"bar") - request = DummyRequest([b'']) - request.method = b'POST' - self.assertRaises(UnsupportedMethod, data.render, request) - - - -class StaticFileTests(TestCase): - """ - Tests for the basic behavior of L{File}. - """ - def _render(self, resource, request): - return _render(resource, request) - - - def test_invalidMethod(self): - """ - L{File.render} raises L{UnsupportedMethod} in response to a non-I{GET}, - non-I{HEAD} request. - """ - request = DummyRequest([b'']) - request.method = b'POST' - path = FilePath(self.mktemp()) - path.setContent(b"foo") - file = static.File(path.path) - self.assertRaises(UnsupportedMethod, file.render, request) - - - def test_notFound(self): - """ - If a request is made which encounters a L{File} before a final segment - which does not correspond to any file in the path the L{File} was - created with, a not found response is sent. - """ - base = FilePath(self.mktemp()) - base.makedirs() - file = static.File(base.path) - - request = DummyRequest([b'foobar']) - child = resource.getChildForRequest(file, request) - - d = self._render(child, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, 404) - d.addCallback(cbRendered) - return d - - - def test_emptyChild(self): - """ - The C{''} child of a L{File} which corresponds to a directory in the - filesystem is a L{DirectoryLister}. - """ - base = FilePath(self.mktemp()) - base.makedirs() - file = static.File(base.path) - - request = DummyRequest([b'']) - child = resource.getChildForRequest(file, request) - self.assertIsInstance(child, static.DirectoryLister) - self.assertEqual(child.path, base.path) - - - def test_securityViolationNotFound(self): - """ - If a request is made which encounters a L{File} before a final segment - which cannot be looked up in the filesystem due to security - considerations, a not found response is sent. - """ - base = FilePath(self.mktemp()) - base.makedirs() - file = static.File(base.path) - - request = DummyRequest([b'..']) - child = resource.getChildForRequest(file, request) - - d = self._render(child, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, 404) - d.addCallback(cbRendered) - return d - - - def test_forbiddenResource(self): - """ - If the file in the filesystem which would satisfy a request cannot be - read, L{File.render} sets the HTTP response code to I{FORBIDDEN}. - """ - base = FilePath(self.mktemp()) - base.setContent(b'') - # Make sure we can delete the file later. - self.addCleanup(base.chmod, 0o700) - - # Get rid of our own read permission. - base.chmod(0) - - file = static.File(base.path) - request = DummyRequest([b'']) - d = self._render(file, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, 403) - d.addCallback(cbRendered) - return d - if platform.isWindows(): - test_forbiddenResource.skip = "Cannot remove read permission on Windows" - - - def test_forbiddenResource_default(self): - """ - L{File.forbidden} defaults to L{resource.ForbiddenResource}. - """ - self.assertIsInstance( - static.File(b'.').forbidden, resource.ForbiddenResource) - - - def test_forbiddenResource_customize(self): - """ - The resource rendered for forbidden requests is stored as a class - member so that users can customize it. - """ - base = FilePath(self.mktemp()) - base.setContent(b'') - markerResponse = b'custom-forbidden-response' - - def failingOpenForReading(): - raise IOError(errno.EACCES, "") - - class CustomForbiddenResource(resource.Resource): - def render(self, request): - return markerResponse - - class CustomStaticFile(static.File): - forbidden = CustomForbiddenResource() - - fileResource = CustomStaticFile(base.path) - fileResource.openForReading = failingOpenForReading - request = DummyRequest([b'']) - - result = fileResource.render(request) - - self.assertEqual(markerResponse, result) - - - def test_indexNames(self): - """ - If a request is made which encounters a L{File} before a final empty - segment, a file in the L{File} instance's C{indexNames} list which - exists in the path the L{File} was created with is served as the - response to the request. - """ - base = FilePath(self.mktemp()) - base.makedirs() - base.child("foo.bar").setContent(b"baz") - file = static.File(base.path) - file.indexNames = [b'foo.bar'] - - request = DummyRequest([b'']) - child = resource.getChildForRequest(file, request) - - d = self._render(child, request) - def cbRendered(ignored): - self.assertEqual(b''.join(request.written), b'baz') - self.assertEqual(request.outgoingHeaders[b'content-length'], b'3') - d.addCallback(cbRendered) - return d - - - def test_staticFile(self): - """ - If a request is made which encounters a L{File} before a final segment - which names a file in the path the L{File} was created with, that file - is served as the response to the request. - """ - base = FilePath(self.mktemp()) - base.makedirs() - base.child("foo.bar").setContent(b"baz") - file = static.File(base.path) - - request = DummyRequest([b'foo.bar']) - child = resource.getChildForRequest(file, request) - - d = self._render(child, request) - def cbRendered(ignored): - self.assertEqual(b''.join(request.written), b'baz') - self.assertEqual(request.outgoingHeaders[b'content-length'], b'3') - d.addCallback(cbRendered) - return d - - - def test_staticFileDeletedGetChild(self): - """ - A L{static.File} created for a directory which does not exist should - return childNotFound from L{static.File.getChild}. - """ - staticFile = static.File(self.mktemp()) - request = DummyRequest([b'foo.bar']) - child = staticFile.getChild("foo.bar", request) - self.assertEqual(child, staticFile.childNotFound) - - - def test_staticFileDeletedRender(self): - """ - A L{static.File} created for a file which does not exist should render - its C{childNotFound} page. - """ - staticFile = static.File(self.mktemp()) - request = DummyRequest([b'foo.bar']) - request2 = DummyRequest([b'foo.bar']) - d = self._render(staticFile, request) - d2 = self._render(staticFile.childNotFound, request2) - def cbRendered2(ignored): - def cbRendered(ignored): - self.assertEqual(b''.join(request.written), - b''.join(request2.written)) - d.addCallback(cbRendered) - return d - d2.addCallback(cbRendered2) - return d2 - - - def test_getChildChildNotFound_customize(self): - """ - The resource rendered for child not found requests can be customize - using a class member. - """ - base = FilePath(self.mktemp()) - base.setContent(b'') - markerResponse = b'custom-child-not-found-response' - - class CustomChildNotFoundResource(resource.Resource): - def render(self, request): - return markerResponse - - class CustomStaticFile(static.File): - childNotFound = CustomChildNotFoundResource() - - fileResource = CustomStaticFile(base.path) - request = DummyRequest([b'no-child.txt']) - - child = fileResource.getChild(b'no-child.txt', request) - result = child.render(request) - - self.assertEqual(markerResponse, result) - - - def test_headRequest(self): - """ - L{static.File.render} returns an empty response body for I{HEAD} - requests. - """ - path = FilePath(self.mktemp()) - path.setContent(b"foo") - file = static.File(path.path) - request = DummyRequest([b'']) - request.method = b'HEAD' - d = _render(file, request) - def cbRendered(ignored): - self.assertEqual(b"".join(request.written), b"") - d.addCallback(cbRendered) - return d - - - def test_processors(self): - """ - If a request is made which encounters a L{File} before a final segment - which names a file with an extension which is in the L{File}'s - C{processors} mapping, the processor associated with that extension is - used to serve the response to the request. - """ - base = FilePath(self.mktemp()) - base.makedirs() - base.child("foo.bar").setContent( - b"from twisted.web.static import Data\n" - b"resource = Data(b'dynamic world', 'text/plain')\n") - - file = static.File(base.path) - file.processors = {b'.bar': script.ResourceScript} - request = DummyRequest([b"foo.bar"]) - child = resource.getChildForRequest(file, request) - - d = self._render(child, request) - def cbRendered(ignored): - self.assertEqual(b''.join(request.written), b'dynamic world') - self.assertEqual(request.outgoingHeaders[b'content-length'], b'13') - d.addCallback(cbRendered) - return d - - - def test_ignoreExt(self): - """ - The list of ignored extensions can be set by passing a value to - L{File.__init__} or by calling L{File.ignoreExt} later. - """ - file = static.File(b".") - self.assertEqual(file.ignoredExts, []) - file.ignoreExt(b".foo") - file.ignoreExt(b".bar") - self.assertEqual(file.ignoredExts, [b".foo", b".bar"]) - - file = static.File(b".", ignoredExts=(b".bar", b".baz")) - self.assertEqual(file.ignoredExts, [b".bar", b".baz"]) - - - def test_ignoredExtensionsIgnored(self): - """ - A request for the I{base} child of a L{File} succeeds with a resource - for the I{base<extension>} file in the path the L{File} was created - with if such a file exists and the L{File} has been configured to - ignore the I{<extension>} extension. - """ - base = FilePath(self.mktemp()) - base.makedirs() - base.child('foo.bar').setContent(b'baz') - base.child('foo.quux').setContent(b'foobar') - file = static.File(base.path, ignoredExts=(b".bar",)) - - request = DummyRequest([b"foo"]) - child = resource.getChildForRequest(file, request) - - d = self._render(child, request) - def cbRendered(ignored): - self.assertEqual(b''.join(request.written), b'baz') - d.addCallback(cbRendered) - return d - - - def _makeFilePathWithStringIO(self): - """ - Create a L{File} that when opened for reading, returns a L{StringIO}. - - @return: 2-tuple of the opened "file" and the L{File}. - @rtype: L{tuple} - """ - fakeFile = StringIO() - path = FilePath(self.mktemp()) - path.touch() - file = static.File(path.path) - # Open our file instead of a real one - file.open = lambda: fakeFile - return fakeFile, file - - - def test_HEADClosesFile(self): - """ - A HEAD request opens the file, gets the size, and then closes it after - the request. - """ - fakeFile, file = self._makeFilePathWithStringIO() - request = DummyRequest(['']) - request.method = b'HEAD' - self.successResultOf(_render(file, request)) - self.assertEqual(b''.join(request.written), b'') - self.assertTrue(fakeFile.closed) - - - def test_cachedRequestClosesFile(self): - """ - A GET request that is cached closes the file after the request. - """ - fakeFile, file = self._makeFilePathWithStringIO() - request = DummyRequest(['']) - request.method = b'GET' - # This request will always return saying that it is cached - request.setLastModified = lambda _: http.CACHED - self.successResultOf(_render(file, request)) - self.assertEqual(b''.join(request.written), b'') - self.assertTrue(fakeFile.closed) - - - -class StaticMakeProducerTests(TestCase): - """ - Tests for L{File.makeProducer}. - """ - - - def makeResourceWithContent(self, content, type=None, encoding=None): - """ - Make a L{static.File} resource that has C{content} for its content. - - @param content: The L{bytes} to use as the contents of the resource. - @param type: Optional value for the content type of the resource. - """ - fileName = FilePath(self.mktemp()) - fileName.setContent(content) - resource = static.File(fileName._asBytesPath()) - resource.encoding = encoding - resource.type = type - return resource - - - def contentHeaders(self, request): - """ - Extract the content-* headers from the L{DummyRequest} C{request}. - - This returns the subset of C{request.outgoingHeaders} of headers that - start with 'content-'. - """ - contentHeaders = {} - for k, v in iteritems(request.outgoingHeaders): - if k.startswith(b'content-'): - contentHeaders[k] = v - return contentHeaders - - - def test_noRangeHeaderGivesNoRangeStaticProducer(self): - """ - makeProducer when no Range header is set returns an instance of - NoRangeStaticProducer. - """ - resource = self.makeResourceWithContent(b'') - request = DummyRequest([]) - with resource.openForReading() as file: - producer = resource.makeProducer(request, file) - self.assertIsInstance(producer, static.NoRangeStaticProducer) - - - def test_noRangeHeaderSets200OK(self): - """ - makeProducer when no Range header is set sets the responseCode on the - request to 'OK'. - """ - resource = self.makeResourceWithContent(b'') - request = DummyRequest([]) - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual(http.OK, request.responseCode) - - - def test_noRangeHeaderSetsContentHeaders(self): - """ - makeProducer when no Range header is set sets the Content-* headers - for the response. - """ - length = 123 - contentType = "text/plain" - contentEncoding = 'gzip' - resource = self.makeResourceWithContent( - b'a'*length, type=contentType, encoding=contentEncoding) - request = DummyRequest([]) - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - {b'content-type': networkString(contentType), b'content-length': intToBytes(length), - b'content-encoding': networkString(contentEncoding)}, - self.contentHeaders(request)) - - - def test_singleRangeGivesSingleRangeStaticProducer(self): - """ - makeProducer when the Range header requests a single byte range - returns an instance of SingleRangeStaticProducer. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=1-3' - resource = self.makeResourceWithContent(b'abcdef') - with resource.openForReading() as file: - producer = resource.makeProducer(request, file) - self.assertIsInstance(producer, static.SingleRangeStaticProducer) - - - def test_singleRangeSets206PartialContent(self): - """ - makeProducer when the Range header requests a single, satisfiable byte - range sets the response code on the request to 'Partial Content'. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=1-3' - resource = self.makeResourceWithContent(b'abcdef') - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - http.PARTIAL_CONTENT, request.responseCode) - - - def test_singleRangeSetsContentHeaders(self): - """ - makeProducer when the Range header requests a single, satisfiable byte - range sets the Content-* headers appropriately. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=1-3' - contentType = "text/plain" - contentEncoding = 'gzip' - resource = self.makeResourceWithContent(b'abcdef', type=contentType, encoding=contentEncoding) - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - {b'content-type': networkString(contentType), - b'content-encoding': networkString(contentEncoding), - b'content-range': b'bytes 1-3/6', b'content-length': b'3'}, - self.contentHeaders(request)) - - - def test_singleUnsatisfiableRangeReturnsSingleRangeStaticProducer(self): - """ - makeProducer still returns an instance of L{SingleRangeStaticProducer} - when the Range header requests a single unsatisfiable byte range. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=4-10' - resource = self.makeResourceWithContent(b'abc') - with resource.openForReading() as file: - producer = resource.makeProducer(request, file) - self.assertIsInstance(producer, static.SingleRangeStaticProducer) - - - def test_singleUnsatisfiableRangeSets416ReqestedRangeNotSatisfiable(self): - """ - makeProducer sets the response code of the request to of 'Requested - Range Not Satisfiable' when the Range header requests a single - unsatisfiable byte range. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=4-10' - resource = self.makeResourceWithContent(b'abc') - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - http.REQUESTED_RANGE_NOT_SATISFIABLE, request.responseCode) - - - def test_singleUnsatisfiableRangeSetsContentHeaders(self): - """ - makeProducer when the Range header requests a single, unsatisfiable - byte range sets the Content-* headers appropriately. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=4-10' - contentType = "text/plain" - resource = self.makeResourceWithContent(b'abc', type=contentType) - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - {b'content-type': b'text/plain', b'content-length': b'0', - b'content-range': b'bytes */3'}, - self.contentHeaders(request)) - - - def test_singlePartiallyOverlappingRangeSetsContentHeaders(self): - """ - makeProducer when the Range header requests a single byte range that - partly overlaps the resource sets the Content-* headers appropriately. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=2-10' - contentType = "text/plain" - resource = self.makeResourceWithContent(b'abc', type=contentType) - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - {b'content-type': b'text/plain', b'content-length': b'1', - b'content-range': b'bytes 2-2/3'}, - self.contentHeaders(request)) - - - def test_multipleRangeGivesMultipleRangeStaticProducer(self): - """ - makeProducer when the Range header requests a single byte range - returns an instance of MultipleRangeStaticProducer. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=1-3,5-6' - resource = self.makeResourceWithContent(b'abcdef') - with resource.openForReading() as file: - producer = resource.makeProducer(request, file) - self.assertIsInstance(producer, static.MultipleRangeStaticProducer) - - - def test_multipleRangeSets206PartialContent(self): - """ - makeProducer when the Range header requests a multiple satisfiable - byte ranges sets the response code on the request to 'Partial - Content'. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=1-3,5-6' - resource = self.makeResourceWithContent(b'abcdef') - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - http.PARTIAL_CONTENT, request.responseCode) - - - - def test_mutipleRangeSetsContentHeaders(self): - """ - makeProducer when the Range header requests a single, satisfiable byte - range sets the Content-* headers appropriately. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=1-3,5-6' - resource = self.makeResourceWithContent( - b'abcdefghijkl', encoding='gzip') - with resource.openForReading() as file: - producer = resource.makeProducer(request, file) - contentHeaders = self.contentHeaders(request) - # The only content-* headers set are content-type and content-length. - self.assertEqual( - set([b'content-length', b'content-type']), - set(contentHeaders.keys())) - # The content-length depends on the boundary used in the response. - expectedLength = 5 - for boundary, offset, size in producer.rangeInfo: - expectedLength += len(boundary) - self.assertEqual(intToBytes(expectedLength), contentHeaders[b'content-length']) - # Content-type should be set to a value indicating a multipart - # response and the boundary used to separate the parts. - self.assertIn(b'content-type', contentHeaders) - contentType = contentHeaders[b'content-type'] - self.assertNotIdentical( - None, re.match( - b'multipart/byteranges; boundary="[^"]*"\Z', contentType)) - # Content-encoding is not set in the response to a multiple range - # response, which is a bit wussy but works well enough with the way - # static.File does content-encodings... - self.assertNotIn(b'content-encoding', contentHeaders) - - - def test_multipleUnsatisfiableRangesReturnsMultipleRangeStaticProducer(self): - """ - makeProducer still returns an instance of L{SingleRangeStaticProducer} - when the Range header requests multiple ranges, none of which are - satisfiable. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=10-12,15-20' - resource = self.makeResourceWithContent(b'abc') - with resource.openForReading() as file: - producer = resource.makeProducer(request, file) - self.assertIsInstance(producer, static.MultipleRangeStaticProducer) - - - def test_multipleUnsatisfiableRangesSets416ReqestedRangeNotSatisfiable(self): - """ - makeProducer sets the response code of the request to of 'Requested - Range Not Satisfiable' when the Range header requests multiple ranges, - none of which are satisfiable. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=10-12,15-20' - resource = self.makeResourceWithContent(b'abc') - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - http.REQUESTED_RANGE_NOT_SATISFIABLE, request.responseCode) - - - def test_multipleUnsatisfiableRangeSetsContentHeaders(self): - """ - makeProducer when the Range header requests multiple ranges, none of - which are satisfiable, sets the Content-* headers appropriately. - """ - request = DummyRequest([]) - request.headers['range'] = b'bytes=4-10' - contentType = "text/plain" - request.headers[b'range'] = b'bytes=10-12,15-20' - resource = self.makeResourceWithContent(b'abc', type=contentType) - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - {b'content-length': b'0', b'content-range': b'bytes */3'}, - self.contentHeaders(request)) - - - def test_oneSatisfiableRangeIsEnough(self): - """ - makeProducer when the Range header requests multiple ranges, at least - one of which matches, sets the response code to 'Partial Content'. - """ - request = DummyRequest([]) - request.headers[b'range'] = b'bytes=1-3,100-200' - resource = self.makeResourceWithContent(b'abcdef') - with resource.openForReading() as file: - resource.makeProducer(request, file) - self.assertEqual( - http.PARTIAL_CONTENT, request.responseCode) - - - - -class StaticProducerTests(TestCase): - """ - Tests for the abstract L{StaticProducer}. - """ - - def test_stopProducingClosesFile(self): - """ - L{StaticProducer.stopProducing} closes the file object the producer is - producing data from. - """ - fileObject = StringIO() - producer = static.StaticProducer(None, fileObject) - producer.stopProducing() - self.assertTrue(fileObject.closed) - - - def test_stopProducingSetsRequestToNone(self): - """ - L{StaticProducer.stopProducing} sets the request instance variable to - None, which indicates to subclasses' resumeProducing methods that no - more data should be produced. - """ - fileObject = StringIO() - producer = static.StaticProducer(DummyRequest([]), fileObject) - producer.stopProducing() - self.assertIdentical(None, producer.request) - - - -class NoRangeStaticProducerTests(TestCase): - """ - Tests for L{NoRangeStaticProducer}. - """ - - def test_implementsIPullProducer(self): - """ - L{NoRangeStaticProducer} implements L{IPullProducer}. - """ - verifyObject( - interfaces.IPullProducer, - static.NoRangeStaticProducer(None, None)) - - - def test_resumeProducingProducesContent(self): - """ - L{NoRangeStaticProducer.resumeProducing} writes content from the - resource to the request. - """ - request = DummyRequest([]) - content = b'abcdef' - producer = static.NoRangeStaticProducer( - request, StringIO(content)) - # start calls registerProducer on the DummyRequest, which pulls all - # output from the producer and so we just need this one call. - producer.start() - self.assertEqual(content, b''.join(request.written)) - - - def test_resumeProducingBuffersOutput(self): - """ - L{NoRangeStaticProducer.start} writes at most - C{abstract.FileDescriptor.bufferSize} bytes of content from the - resource to the request at once. - """ - request = DummyRequest([]) - bufferSize = abstract.FileDescriptor.bufferSize - content = b'a' * (2*bufferSize + 1) - producer = static.NoRangeStaticProducer( - request, StringIO(content)) - # start calls registerProducer on the DummyRequest, which pulls all - # output from the producer and so we just need this one call. - producer.start() - expected = [ - content[0:bufferSize], - content[bufferSize:2*bufferSize], - content[2*bufferSize:] - ] - self.assertEqual(expected, request.written) - - - def test_finishCalledWhenDone(self): - """ - L{NoRangeStaticProducer.resumeProducing} calls finish() on the request - after it is done producing content. - """ - request = DummyRequest([]) - finishDeferred = request.notifyFinish() - callbackList = [] - finishDeferred.addCallback(callbackList.append) - producer = static.NoRangeStaticProducer( - request, StringIO(b'abcdef')) - # start calls registerProducer on the DummyRequest, which pulls all - # output from the producer and so we just need this one call. - producer.start() - self.assertEqual([None], callbackList) - - - -class SingleRangeStaticProducerTests(TestCase): - """ - Tests for L{SingleRangeStaticProducer}. - """ - - def test_implementsIPullProducer(self): - """ - L{SingleRangeStaticProducer} implements L{IPullProducer}. - """ - verifyObject( - interfaces.IPullProducer, - static.SingleRangeStaticProducer(None, None, None, None)) - - - def test_resumeProducingProducesContent(self): - """ - L{SingleRangeStaticProducer.resumeProducing} writes the given amount - of content, starting at the given offset, from the resource to the - request. - """ - request = DummyRequest([]) - content = b'abcdef' - producer = static.SingleRangeStaticProducer( - request, StringIO(content), 1, 3) - # DummyRequest.registerProducer pulls all output from the producer, so - # we just need to call start. - producer.start() - self.assertEqual(content[1:4], b''.join(request.written)) - - - def test_resumeProducingBuffersOutput(self): - """ - L{SingleRangeStaticProducer.start} writes at most - C{abstract.FileDescriptor.bufferSize} bytes of content from the - resource to the request at once. - """ - request = DummyRequest([]) - bufferSize = abstract.FileDescriptor.bufferSize - content = b'abc' * bufferSize - producer = static.SingleRangeStaticProducer( - request, StringIO(content), 1, bufferSize+10) - # DummyRequest.registerProducer pulls all output from the producer, so - # we just need to call start. - producer.start() - expected = [ - content[1:bufferSize+1], - content[bufferSize+1:bufferSize+11], - ] - self.assertEqual(expected, request.written) - - - def test_finishCalledWhenDone(self): - """ - L{SingleRangeStaticProducer.resumeProducing} calls finish() on the - request after it is done producing content. - """ - request = DummyRequest([]) - finishDeferred = request.notifyFinish() - callbackList = [] - finishDeferred.addCallback(callbackList.append) - producer = static.SingleRangeStaticProducer( - request, StringIO(b'abcdef'), 1, 1) - # start calls registerProducer on the DummyRequest, which pulls all - # output from the producer and so we just need this one call. - producer.start() - self.assertEqual([None], callbackList) - - - -class MultipleRangeStaticProducerTests(TestCase): - """ - Tests for L{MultipleRangeStaticProducer}. - """ - - def test_implementsIPullProducer(self): - """ - L{MultipleRangeStaticProducer} implements L{IPullProducer}. - """ - verifyObject( - interfaces.IPullProducer, - static.MultipleRangeStaticProducer(None, None, None)) - - - def test_resumeProducingProducesContent(self): - """ - L{MultipleRangeStaticProducer.resumeProducing} writes the requested - chunks of content from the resource to the request, with the supplied - boundaries in between each chunk. - """ - request = DummyRequest([]) - content = b'abcdef' - producer = static.MultipleRangeStaticProducer( - request, StringIO(content), [(b'1', 1, 3), (b'2', 5, 1)]) - # DummyRequest.registerProducer pulls all output from the producer, so - # we just need to call start. - producer.start() - self.assertEqual(b'1bcd2f', b''.join(request.written)) - - - def test_resumeProducingBuffersOutput(self): - """ - L{MultipleRangeStaticProducer.start} writes about - C{abstract.FileDescriptor.bufferSize} bytes of content from the - resource to the request at once. - - To be specific about the 'about' above: it can write slightly more, - for example in the case where the first boundary plus the first chunk - is less than C{bufferSize} but first boundary plus the first chunk - plus the second boundary is more, but this is unimportant as in - practice the boundaries are fairly small. On the other side, it is - important for performance to bundle up several small chunks into one - call to request.write. - """ - request = DummyRequest([]) - content = b'0123456789' * 2 - producer = static.MultipleRangeStaticProducer( - request, StringIO(content), - [(b'a', 0, 2), (b'b', 5, 10), (b'c', 0, 0)]) - producer.bufferSize = 10 - # DummyRequest.registerProducer pulls all output from the producer, so - # we just need to call start. - producer.start() - expected = [ - b'a' + content[0:2] + b'b' + content[5:11], - content[11:15] + b'c', - ] - self.assertEqual(expected, request.written) - - - def test_finishCalledWhenDone(self): - """ - L{MultipleRangeStaticProducer.resumeProducing} calls finish() on the - request after it is done producing content. - """ - request = DummyRequest([]) - finishDeferred = request.notifyFinish() - callbackList = [] - finishDeferred.addCallback(callbackList.append) - producer = static.MultipleRangeStaticProducer( - request, StringIO(b'abcdef'), [(b'', 1, 2)]) - # start calls registerProducer on the DummyRequest, which pulls all - # output from the producer and so we just need this one call. - producer.start() - self.assertEqual([None], callbackList) - - - -class RangeTests(TestCase): - """ - Tests for I{Range-Header} support in L{twisted.web.static.File}. - - @type file: L{file} - @ivar file: Temporary (binary) file containing the content to be served. - - @type resource: L{static.File} - @ivar resource: A leaf web resource using C{file} as content. - - @type request: L{DummyRequest} - @ivar request: A fake request, requesting C{resource}. - - @type catcher: L{list} - @ivar catcher: List which gathers all log information. - """ - def setUp(self): - """ - Create a temporary file with a fixed payload of 64 bytes. Create a - resource for that file and create a request which will be for that - resource. Each test can set a different range header to test different - aspects of the implementation. - """ - path = FilePath(self.mktemp()) - # This is just a jumble of random stuff. It's supposed to be a good - # set of data for this test, particularly in order to avoid - # accidentally seeing the right result by having a byte sequence - # repeated at different locations or by having byte values which are - # somehow correlated with their position in the string. - self.payload = (b'\xf8u\xf3E\x8c7\xce\x00\x9e\xb6a0y0S\xf0\xef\xac\xb7' - b'\xbe\xb5\x17M\x1e\x136k{\x1e\xbe\x0c\x07\x07\t\xd0' - b'\xbckY\xf5I\x0b\xb8\x88oZ\x1d\x85b\x1a\xcdk\xf2\x1d' - b'&\xfd%\xdd\x82q/A\x10Y\x8b') - path.setContent(self.payload) - self.file = path.open() - self.resource = static.File(self.file.name) - self.resource.isLeaf = 1 - self.request = DummyRequest([b'']) - self.request.uri = self.file.name - self.catcher = [] - log.addObserver(self.catcher.append) - - - def tearDown(self): - """ - Clean up the resource file and the log observer. - """ - self.file.close() - log.removeObserver(self.catcher.append) - - - def _assertLogged(self, expected): - """ - Asserts that a given log message occurred with an expected message. - """ - logItem = self.catcher.pop() - self.assertEqual(logItem["message"][0], expected) - self.assertEqual( - self.catcher, [], "An additional log occured: %r" % (logItem,)) - - - def test_invalidRanges(self): - """ - L{File._parseRangeHeader} raises L{ValueError} when passed - syntactically invalid byte ranges. - """ - f = self.resource._parseRangeHeader - - # there's no = - self.assertRaises(ValueError, f, b'bytes') - - # unknown isn't a valid Bytes-Unit - self.assertRaises(ValueError, f, b'unknown=1-2') - - # there's no - in =stuff - self.assertRaises(ValueError, f, b'bytes=3') - - # both start and end are empty - self.assertRaises(ValueError, f, b'bytes=-') - - # start isn't an integer - self.assertRaises(ValueError, f, b'bytes=foo-') - - # end isn't an integer - self.assertRaises(ValueError, f, b'bytes=-foo') - - # end isn't equal to or greater than start - self.assertRaises(ValueError, f, b'bytes=5-4') - - - def test_rangeMissingStop(self): - """ - A single bytes range without an explicit stop position is parsed into a - two-tuple giving the start position and C{None}. - """ - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=0-'), [(0, None)]) - - - def test_rangeMissingStart(self): - """ - A single bytes range without an explicit start position is parsed into - a two-tuple of C{None} and the end position. - """ - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=-3'), [(None, 3)]) - - - def test_range(self): - """ - A single bytes range with explicit start and stop positions is parsed - into a two-tuple of those positions. - """ - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=2-5'), [(2, 5)]) - - - def test_rangeWithSpace(self): - """ - A single bytes range with whitespace in allowed places is parsed in - the same way as it would be without the whitespace. - """ - self.assertEqual( - self.resource._parseRangeHeader(b' bytes=1-2 '), [(1, 2)]) - self.assertEqual( - self.resource._parseRangeHeader(b'bytes =1-2 '), [(1, 2)]) - self.assertEqual( - self.resource._parseRangeHeader(b'bytes= 1-2'), [(1, 2)]) - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=1 -2'), [(1, 2)]) - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=1- 2'), [(1, 2)]) - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=1-2 '), [(1, 2)]) - - - def test_nullRangeElements(self): - """ - If there are multiple byte ranges but only one is non-null, the - non-null range is parsed and its start and stop returned. - """ - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=1-2,\r\n, ,\t'), [(1, 2)]) - - - def test_multipleRanges(self): - """ - If multiple byte ranges are specified their starts and stops are - returned. - """ - self.assertEqual( - self.resource._parseRangeHeader(b'bytes=1-2,3-4'), - [(1, 2), (3, 4)]) - - - def test_bodyLength(self): - """ - A correct response to a range request is as long as the length of the - requested range. - """ - self.request.headers[b'range'] = b'bytes=0-43' - self.resource.render(self.request) - self.assertEqual(len(b''.join(self.request.written)), 44) - - - def test_invalidRangeRequest(self): - """ - An incorrect range request (RFC 2616 defines a correct range request as - a Bytes-Unit followed by a '=' character followed by a specific range. - Only 'bytes' is defined) results in the range header value being logged - and a normal 200 response being sent. - """ - self.request.headers[b'range'] = range = b'foobar=0-43' - self.resource.render(self.request) - expected = "Ignoring malformed Range header %r" % (range.decode(),) - self._assertLogged(expected) - self.assertEqual(b''.join(self.request.written), self.payload) - self.assertEqual(self.request.responseCode, http.OK) - self.assertEqual( - self.request.outgoingHeaders[b'content-length'], - intToBytes(len(self.payload))) - - - def parseMultipartBody(self, body, boundary): - """ - Parse C{body} as a multipart MIME response separated by C{boundary}. - - Note that this with fail the calling test on certain syntactic - problems. - """ - sep = b"\r\n--" + boundary - parts = body.split(sep) - self.assertEqual(b'', parts[0]) - self.assertEqual(b'--\r\n', parts[-1]) - parsed_parts = [] - for part in parts[1:-1]: - before, header1, header2, blank, partBody = part.split(b'\r\n', 4) - headers = header1 + b'\n' + header2 - self.assertEqual(b'', before) - self.assertEqual(b'', blank) - partContentTypeValue = re.search( - b'^content-type: (.*)$', headers, re.I|re.M).group(1) - start, end, size = re.search( - b'^content-range: bytes ([0-9]+)-([0-9]+)/([0-9]+)$', - headers, re.I|re.M).groups() - parsed_parts.append( - {b'contentType': partContentTypeValue, - b'contentRange': (start, end, size), - b'body': partBody}) - return parsed_parts - - - def test_multipleRangeRequest(self): - """ - The response to a request for multipe bytes ranges is a MIME-ish - multipart response. - """ - startEnds = [(0, 2), (20, 30), (40, 50)] - rangeHeaderValue = b','.join([networkString("%s-%s" % (s,e)) for (s, e) in startEnds]) - self.request.headers[b'range'] = b'bytes=' + rangeHeaderValue - self.resource.render(self.request) - self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) - boundary = re.match( - b'^multipart/byteranges; boundary="(.*)"$', - self.request.outgoingHeaders[b'content-type']).group(1) - parts = self.parseMultipartBody(b''.join(self.request.written), boundary) - self.assertEqual(len(startEnds), len(parts)) - for part, (s, e) in zip(parts, startEnds): - self.assertEqual(networkString(self.resource.type), - part[b'contentType']) - start, end, size = part[b'contentRange'] - self.assertEqual(int(start), s) - self.assertEqual(int(end), e) - self.assertEqual(int(size), self.resource.getFileSize()) - self.assertEqual(self.payload[s:e+1], part[b'body']) - - - def test_multipleRangeRequestWithRangeOverlappingEnd(self): - """ - The response to a request for multipe bytes ranges is a MIME-ish - multipart response, even when one of the ranged falls off the end of - the resource. - """ - startEnds = [(0, 2), (40, len(self.payload) + 10)] - rangeHeaderValue = b','.join([networkString("%s-%s" % (s,e)) for (s, e) in startEnds]) - self.request.headers[b'range'] = b'bytes=' + rangeHeaderValue - self.resource.render(self.request) - self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) - boundary = re.match( - b'^multipart/byteranges; boundary="(.*)"$', - self.request.outgoingHeaders[b'content-type']).group(1) - parts = self.parseMultipartBody(b''.join(self.request.written), boundary) - self.assertEqual(len(startEnds), len(parts)) - for part, (s, e) in zip(parts, startEnds): - self.assertEqual(networkString(self.resource.type), - part[b'contentType']) - start, end, size = part[b'contentRange'] - self.assertEqual(int(start), s) - self.assertEqual(int(end), min(e, self.resource.getFileSize()-1)) - self.assertEqual(int(size), self.resource.getFileSize()) - self.assertEqual(self.payload[s:e+1], part[b'body']) - - - def test_implicitEnd(self): - """ - If the end byte position is omitted, then it is treated as if the - length of the resource was specified by the end byte position. - """ - self.request.headers[b'range'] = b'bytes=23-' - self.resource.render(self.request) - self.assertEqual(b''.join(self.request.written), self.payload[23:]) - self.assertEqual(len(b''.join(self.request.written)), 41) - self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEqual( - self.request.outgoingHeaders[b'content-range'], b'bytes 23-63/64') - self.assertEqual(self.request.outgoingHeaders[b'content-length'], b'41') - - - def test_implicitStart(self): - """ - If the start byte position is omitted but the end byte position is - supplied, then the range is treated as requesting the last -N bytes of - the resource, where N is the end byte position. - """ - self.request.headers[b'range'] = b'bytes=-17' - self.resource.render(self.request) - self.assertEqual(b''.join(self.request.written), self.payload[-17:]) - self.assertEqual(len(b''.join(self.request.written)), 17) - self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEqual( - self.request.outgoingHeaders[b'content-range'], b'bytes 47-63/64') - self.assertEqual(self.request.outgoingHeaders[b'content-length'], b'17') - - - def test_explicitRange(self): - """ - A correct response to a bytes range header request from A to B starts - with the A'th byte and ends with (including) the B'th byte. The first - byte of a page is numbered with 0. - """ - self.request.headers[b'range'] = b'bytes=3-43' - self.resource.render(self.request) - written = b''.join(self.request.written) - self.assertEqual(written, self.payload[3:44]) - self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEqual( - self.request.outgoingHeaders[b'content-range'], b'bytes 3-43/64') - self.assertEqual( - intToBytes(len(written)), self.request.outgoingHeaders[b'content-length']) - - - def test_explicitRangeOverlappingEnd(self): - """ - A correct response to a bytes range header request from A to B when B - is past the end of the resource starts with the A'th byte and ends - with the last byte of the resource. The first byte of a page is - numbered with 0. - """ - self.request.headers[b'range'] = b'bytes=40-100' - self.resource.render(self.request) - written = b''.join(self.request.written) - self.assertEqual(written, self.payload[40:]) - self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEqual( - self.request.outgoingHeaders[b'content-range'], b'bytes 40-63/64') - self.assertEqual( - intToBytes(len(written)), self.request.outgoingHeaders[b'content-length']) - - - def test_statusCodeRequestedRangeNotSatisfiable(self): - """ - If a range is syntactically invalid due to the start being greater than - the end, the range header is ignored (the request is responded to as if - it were not present). - """ - self.request.headers[b'range'] = b'bytes=20-13' - self.resource.render(self.request) - self.assertEqual(self.request.responseCode, http.OK) - self.assertEqual(b''.join(self.request.written), self.payload) - self.assertEqual( - self.request.outgoingHeaders[b'content-length'], - intToBytes(len(self.payload))) - - - def test_invalidStartBytePos(self): - """ - If a range is unsatisfiable due to the start not being less than the - length of the resource, the response is 416 (Requested range not - satisfiable) and no data is written to the response body (RFC 2616, - section 14.35.1). - """ - self.request.headers[b'range'] = b'bytes=67-108' - self.resource.render(self.request) - self.assertEqual( - self.request.responseCode, http.REQUESTED_RANGE_NOT_SATISFIABLE) - self.assertEqual(b''.join(self.request.written), b'') - self.assertEqual(self.request.outgoingHeaders[b'content-length'], b'0') - # Sections 10.4.17 and 14.16 - self.assertEqual( - self.request.outgoingHeaders[b'content-range'], - networkString('bytes */%d' % (len(self.payload),))) - - - -class DirectoryListerTests(TestCase): - """ - Tests for L{static.DirectoryLister}. - """ - def _request(self, uri): - request = DummyRequest([b'']) - request.uri = uri - return request - - - def test_renderHeader(self): - """ - L{static.DirectoryLister} prints the request uri as header of the - rendered content. - """ - path = FilePath(self.mktemp()) - path.makedirs() - - lister = static.DirectoryLister(path.path) - data = lister.render(self._request(b'foo')) - self.assertIn(b"<h1>Directory listing for foo</h1>", data) - self.assertIn(b"<title>Directory listing for foo</title>", data) - - - def test_renderUnquoteHeader(self): - """ - L{static.DirectoryLister} unquote the request uri before printing it. - """ - path = FilePath(self.mktemp()) - path.makedirs() - - lister = static.DirectoryLister(path.path) - data = lister.render(self._request(b'foo%20bar')) - self.assertIn(b"<h1>Directory listing for foo bar</h1>", data) - self.assertIn(b"<title>Directory listing for foo bar</title>", data) - - - def test_escapeHeader(self): - """ - L{static.DirectoryLister} escape "&", "<" and ">" after unquoting the - request uri. - """ - path = FilePath(self.mktemp()) - path.makedirs() - - lister = static.DirectoryLister(path.path) - data = lister.render(self._request(b'foo%26bar')) - self.assertIn(b"<h1>Directory listing for foo&amp;bar</h1>", data) - self.assertIn(b"<title>Directory listing for foo&amp;bar</title>", data) - - - def test_renderFiles(self): - """ - L{static.DirectoryLister} is able to list all the files inside a - directory. - """ - path = FilePath(self.mktemp()) - path.makedirs() - path.child('file1').setContent(b"content1") - path.child('file2').setContent(b"content2" * 1000) - - lister = static.DirectoryLister(path.path) - data = lister.render(self._request(b'foo')) - body = b"""<tr class="odd"> - <td><a href="file1">file1</a></td> - <td>8B</td> - <td>[text/html]</td> - <td></td> -</tr> -<tr class="even"> - <td><a href="file2">file2</a></td> - <td>7K</td> - <td>[text/html]</td> - <td></td> -</tr>""" - self.assertIn(body, data) - - - def test_renderDirectories(self): - """ - L{static.DirectoryLister} is able to list all the directories inside - a directory. - """ - path = FilePath(self.mktemp()) - path.makedirs() - path.child('dir1').makedirs() - path.child('dir2 & 3').makedirs() - - lister = static.DirectoryLister(path.path) - data = lister.render(self._request(b'foo')) - body = b"""<tr class="odd"> - <td><a href="dir1/">dir1/</a></td> - <td></td> - <td>[Directory]</td> - <td></td> -</tr> -<tr class="even"> - <td><a href="dir2%20%26%203/">dir2 &amp; 3/</a></td> - <td></td> - <td>[Directory]</td> - <td></td> -</tr>""" - self.assertIn(body, data) - - - def test_renderFiltered(self): - """ - L{static.DirectoryLister} takes a optional C{dirs} argument that - filter out the list of directories and files printed. - """ - path = FilePath(self.mktemp()) - path.makedirs() - path.child('dir1').makedirs() - path.child('dir2').makedirs() - path.child('dir3').makedirs() - lister = static.DirectoryLister(path.path, dirs=["dir1", "dir3"]) - data = lister.render(self._request(b'foo')) - body = b"""<tr class="odd"> - <td><a href="dir1/">dir1/</a></td> - <td></td> - <td>[Directory]</td> - <td></td> -</tr> -<tr class="even"> - <td><a href="dir3/">dir3/</a></td> - <td></td> - <td>[Directory]</td> - <td></td> -</tr>""" - self.assertIn(body, data) - - - def test_oddAndEven(self): - """ - L{static.DirectoryLister} gives an alternate class for each odd and - even rows in the table. - """ - lister = static.DirectoryLister(None) - elements = [{"href": "", "text": "", "size": "", "type": "", - "encoding": ""} for i in range(5)] - content = lister._buildTableContent(elements) - - self.assertEqual(len(content), 5) - self.assertTrue(content[0].startswith('<tr class="odd">')) - self.assertTrue(content[1].startswith('<tr class="even">')) - self.assertTrue(content[2].startswith('<tr class="odd">')) - self.assertTrue(content[3].startswith('<tr class="even">')) - self.assertTrue(content[4].startswith('<tr class="odd">')) - - - def test_contentType(self): - """ - L{static.DirectoryLister} produces a MIME-type that indicates that it is - HTML, and includes its charset (UTF-8). - """ - path = FilePath(self.mktemp()) - path.makedirs() - lister = static.DirectoryLister(path.path) - req = self._request(b'') - lister.render(req) - self.assertEqual(req.outgoingHeaders[b'content-type'], - b"text/html; charset=utf-8") - - - def test_mimeTypeAndEncodings(self): - """ - L{static.DirectoryLister} is able to detect mimetype and encoding of - listed files. - """ - path = FilePath(self.mktemp()) - path.makedirs() - path.child('file1.txt').setContent(b"file1") - path.child('file2.py').setContent(b"python") - path.child('file3.conf.gz').setContent(b"conf compressed") - path.child('file4.diff.bz2').setContent(b"diff compressed") - directory = os.listdir(path.path) - directory.sort() - - contentTypes = { - ".txt": "text/plain", - ".py": "text/python", - ".conf": "text/configuration", - ".diff": "text/diff" - } - - lister = static.DirectoryLister(path.path, contentTypes=contentTypes) - dirs, files = lister._getFilesAndDirectories(directory) - self.assertEqual(dirs, []) - self.assertEqual(files, [ - {'encoding': '', - 'href': 'file1.txt', - 'size': '5B', - 'text': 'file1.txt', - 'type': '[text/plain]'}, - {'encoding': '', - 'href': 'file2.py', - 'size': '6B', - 'text': 'file2.py', - 'type': '[text/python]'}, - {'encoding': '[gzip]', - 'href': 'file3.conf.gz', - 'size': '15B', - 'text': 'file3.conf.gz', - 'type': '[text/configuration]'}, - {'encoding': '[bzip2]', - 'href': 'file4.diff.bz2', - 'size': '15B', - 'text': 'file4.diff.bz2', - 'type': '[text/diff]'}]) - - - def test_brokenSymlink(self): - """ - If on the file in the listing points to a broken symlink, it should not - be returned by L{static.DirectoryLister._getFilesAndDirectories}. - """ - path = FilePath(self.mktemp()) - path.makedirs() - file1 = path.child('file1') - file1.setContent(b"file1") - file1.linkTo(path.child("file2")) - file1.remove() - - lister = static.DirectoryLister(path.path) - directory = os.listdir(path.path) - directory.sort() - dirs, files = lister._getFilesAndDirectories(directory) - self.assertEqual(dirs, []) - self.assertEqual(files, []) - - if getattr(os, "symlink", None) is None: - test_brokenSymlink.skip = "No symlink support" - - - def test_childrenNotFound(self): - """ - Any child resource of L{static.DirectoryLister} renders an HTTP - I{NOT FOUND} response code. - """ - path = FilePath(self.mktemp()) - path.makedirs() - lister = static.DirectoryLister(path.path) - request = self._request(b'') - child = resource.getChildForRequest(lister, request) - result = _render(child, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, http.NOT_FOUND) - result.addCallback(cbRendered) - return result - - - def test_repr(self): - """ - L{static.DirectoryLister.__repr__} gives the path of the lister. - """ - path = FilePath(self.mktemp()) - lister = static.DirectoryLister(path.path) - self.assertEqual(repr(lister), - "<DirectoryLister of %r>" % (path.path,)) - self.assertEqual(str(lister), - "<DirectoryLister of %r>" % (path.path,)) - - def test_formatFileSize(self): - """ - L{static.formatFileSize} format an amount of bytes into a more readable - format. - """ - self.assertEqual(static.formatFileSize(0), "0B") - self.assertEqual(static.formatFileSize(123), "123B") - self.assertEqual(static.formatFileSize(4567), "4K") - self.assertEqual(static.formatFileSize(8900000), "8M") - self.assertEqual(static.formatFileSize(1234000000), "1G") - self.assertEqual(static.formatFileSize(1234567890000), "1149G") - - - -class LoadMimeTypesTests(TestCase): - """ - Tests for the MIME type loading routine. - - @cvar UNSET: A sentinel to signify that C{self.paths} has not been set by - the mock init. - """ - UNSET = object() - - def setUp(self): - self.paths = self.UNSET - - - def _fakeInit(self, paths): - """ - A mock L{mimetypes.init} that records the value of the passed C{paths} - argument. - - @param paths: The paths that will be recorded. - """ - self.paths = paths - - - def test_defaultArgumentIsNone(self): - """ - By default, C{None} is passed to C{mimetypes.init}. - """ - static.loadMimeTypes(init=self._fakeInit) - self.assertIdentical(self.paths, None) - - - def test_extraLocationsWork(self): - """ - Passed MIME type files are passed to C{mimetypes.init}. - """ - paths = ["x", "y", "z"] - static.loadMimeTypes(paths, init=self._fakeInit) - self.assertIdentical(self.paths, paths) - - - def test_usesGlobalInitFunction(self): - """ - By default, C{mimetypes.init} is called. - """ - # Checking mimetypes.inited doesn't always work, because - # something, somewhere, calls mimetypes.init. Yay global - # mutable state :) - args, _, _, defaults = inspect.getargspec(static.loadMimeTypes) - defaultInit = defaults[args.index("init")] - self.assertIdentical(defaultInit, mimetypes.init) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_tap.py deleted file mode 100644 index 5ce997e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_tap.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.tap}. -""" - -import os, stat - -from twisted.python.reflect import requireModule -from twisted.python.usage import UsageError -from twisted.python.filepath import FilePath -from twisted.internet.interfaces import IReactorUNIX -from twisted.internet import reactor -from twisted.python.threadpool import ThreadPool -from twisted.trial.unittest import TestCase -from twisted.application import strports - -from twisted.web.server import Site -from twisted.web.static import Data, File -from twisted.web.distrib import ResourcePublisher, UserDirectory -from twisted.web.wsgi import WSGIResource -from twisted.web.tap import Options, makePersonalServerFactory, makeService -from twisted.web.twcgi import CGIScript -from twisted.web.script import PythonScript - - -from twisted.spread.pb import PBServerFactory - -application = object() - -class ServiceTests(TestCase): - """ - Tests for the service creation APIs in L{twisted.web.tap}. - """ - def _pathOption(self): - """ - Helper for the I{--path} tests which creates a directory and creates - an L{Options} object which uses that directory as its static - filesystem root. - - @return: A two-tuple of a L{FilePath} referring to the directory and - the value associated with the C{'root'} key in the L{Options} - instance after parsing a I{--path} option. - """ - path = FilePath(self.mktemp()) - path.makedirs() - options = Options() - options.parseOptions(['--path', path.path]) - root = options['root'] - return path, root - - - def test_path(self): - """ - The I{--path} option causes L{Options} to create a root resource - which serves responses from the specified path. - """ - path, root = self._pathOption() - self.assertIsInstance(root, File) - self.assertEqual(root.path, path.path) - - - def test_cgiProcessor(self): - """ - The I{--path} option creates a root resource which serves a - L{CGIScript} instance for any child with the C{".cgi"} extension. - """ - path, root = self._pathOption() - path.child("foo.cgi").setContent("") - self.assertIsInstance(root.getChild("foo.cgi", None), CGIScript) - - - def test_epyProcessor(self): - """ - The I{--path} option creates a root resource which serves a - L{PythonScript} instance for any child with the C{".epy"} extension. - """ - path, root = self._pathOption() - path.child("foo.epy").setContent("") - self.assertIsInstance(root.getChild("foo.epy", None), PythonScript) - - - def test_rpyProcessor(self): - """ - The I{--path} option creates a root resource which serves the - C{resource} global defined by the Python source in any child with - the C{".rpy"} extension. - """ - path, root = self._pathOption() - path.child("foo.rpy").setContent( - "from twisted.web.static import Data\n" - "resource = Data('content', 'major/minor')\n") - child = root.getChild("foo.rpy", None) - self.assertIsInstance(child, Data) - self.assertEqual(child.data, 'content') - self.assertEqual(child.type, 'major/minor') - - - def test_makePersonalServerFactory(self): - """ - L{makePersonalServerFactory} returns a PB server factory which has - as its root object a L{ResourcePublisher}. - """ - # The fact that this pile of objects can actually be used somehow is - # verified by twisted.web.test.test_distrib. - site = Site(Data("foo bar", "text/plain")) - serverFactory = makePersonalServerFactory(site) - self.assertIsInstance(serverFactory, PBServerFactory) - self.assertIsInstance(serverFactory.root, ResourcePublisher) - self.assertIdentical(serverFactory.root.site, site) - - - def test_personalServer(self): - """ - The I{--personal} option to L{makeService} causes it to return a - service which will listen on the server address given by the I{--port} - option. - """ - port = self.mktemp() - options = Options() - options.parseOptions(['--port', 'unix:' + port, '--personal']) - service = makeService(options) - service.startService() - self.addCleanup(service.stopService) - self.assertTrue(os.path.exists(port)) - self.assertTrue(stat.S_ISSOCK(os.stat(port).st_mode)) - - if not IReactorUNIX.providedBy(reactor): - test_personalServer.skip = ( - "The reactor does not support UNIX domain sockets") - - - def test_defaultPersonalPath(self): - """ - If the I{--port} option not specified but the I{--personal} option is, - L{Options} defaults the port to C{UserDirectory.userSocketName} in the - user's home directory. - """ - options = Options() - options.parseOptions(['--personal']) - path = os.path.expanduser( - os.path.join('~', UserDirectory.userSocketName)) - self.assertEqual( - strports.parse(options['port'], None)[:2], - ('UNIX', (path, None))) - - if not IReactorUNIX.providedBy(reactor): - test_defaultPersonalPath.skip = ( - "The reactor does not support UNIX domain sockets") - - - def test_defaultPort(self): - """ - If the I{--port} option is not specified, L{Options} defaults the port - to C{8080}. - """ - options = Options() - options.parseOptions([]) - self.assertEqual( - strports.parse(options['port'], None)[:2], - ('TCP', (8080, None))) - - - def test_wsgi(self): - """ - The I{--wsgi} option takes the fully-qualifed Python name of a WSGI - application object and creates a L{WSGIResource} at the root which - serves that application. - """ - options = Options() - options.parseOptions(['--wsgi', __name__ + '.application']) - root = options['root'] - self.assertTrue(root, WSGIResource) - self.assertIdentical(root._reactor, reactor) - self.assertTrue(isinstance(root._threadpool, ThreadPool)) - self.assertIdentical(root._application, application) - - # The threadpool should start and stop with the reactor. - self.assertFalse(root._threadpool.started) - reactor.fireSystemEvent('startup') - self.assertTrue(root._threadpool.started) - self.assertFalse(root._threadpool.joined) - reactor.fireSystemEvent('shutdown') - self.assertTrue(root._threadpool.joined) - - - def test_invalidApplication(self): - """ - If I{--wsgi} is given an invalid name, L{Options.parseOptions} - raises L{UsageError}. - """ - options = Options() - for name in [__name__ + '.nosuchthing', 'foo.']: - exc = self.assertRaises( - UsageError, options.parseOptions, ['--wsgi', name]) - self.assertEqual(str(exc), "No such WSGI application: %r" % (name,)) - - - def test_HTTPSFailureOnMissingSSL(self): - """ - An L{UsageError} is raised when C{https} is requested but there is no - support for SSL. - """ - options = Options() - - exception = self.assertRaises( - UsageError, options.parseOptions, ['--https=443']) - - self.assertEqual('SSL support not installed', exception.message) - - if requireModule('OpenSSL.SSL') is not None: - test_HTTPSFailureOnMissingSSL.skip = 'SSL module is available.' - - - def test_HTTPSAcceptedOnAvailableSSL(self): - """ - When SSL support is present, it accepts the --https option. - """ - options = Options() - - options.parseOptions(['--https=443']) - - self.assertEqual('443', options['https']) - - if requireModule('OpenSSL.SSL') is None: - test_HTTPSAcceptedOnAvailableSSL.skip = 'SSL module is not available.' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_template.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_template.py deleted file mode 100644 index 6ef73be..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_template.py +++ /dev/null @@ -1,820 +0,0 @@ - -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Tests for L{twisted.web.template} -""" - -from cStringIO import StringIO - -from zope.interface.verify import verifyObject - -from twisted.internet.defer import succeed, gatherResults -from twisted.python.filepath import FilePath -from twisted.trial.unittest import TestCase -from twisted.trial.util import suppress as SUPPRESS -from twisted.web.template import ( - Element, TagLoader, renderer, tags, XMLFile, XMLString) -from twisted.web.iweb import ITemplateLoader - -from twisted.web.error import (FlattenerError, MissingTemplateLoader, - MissingRenderMethod) - -from twisted.web.template import renderElement -from twisted.web._element import UnexposedMethodError -from twisted.web.test._util import FlattenTestCase -from twisted.web.test.test_web import DummyRequest -from twisted.web.server import NOT_DONE_YET - - -_xmlFileSuppress = SUPPRESS(category=DeprecationWarning, - message="Passing filenames or file objects to XMLFile is " - "deprecated since Twisted 12.1. Pass a FilePath instead.") - - -class TagFactoryTests(TestCase): - """ - Tests for L{_TagFactory} through the publicly-exposed L{tags} object. - """ - def test_lookupTag(self): - """ - HTML tags can be retrieved through C{tags}. - """ - tag = tags.a - self.assertEqual(tag.tagName, "a") - - - def test_lookupHTML5Tag(self): - """ - Twisted supports the latest and greatest HTML tags from the HTML5 - specification. - """ - tag = tags.video - self.assertEqual(tag.tagName, "video") - - - def test_lookupTransparentTag(self): - """ - To support transparent inclusion in templates, there is a special tag, - the transparent tag, which has no name of its own but is accessed - through the "transparent" attribute. - """ - tag = tags.transparent - self.assertEqual(tag.tagName, "") - - - def test_lookupInvalidTag(self): - """ - Invalid tags which are not part of HTML cause AttributeErrors when - accessed through C{tags}. - """ - self.assertRaises(AttributeError, getattr, tags, "invalid") - - - def test_lookupXMP(self): - """ - As a special case, the <xmp> tag is simply not available through - C{tags} or any other part of the templating machinery. - """ - self.assertRaises(AttributeError, getattr, tags, "xmp") - - - -class ElementTests(TestCase): - """ - Tests for the awesome new L{Element} class. - """ - def test_missingTemplateLoader(self): - """ - L{Element.render} raises L{MissingTemplateLoader} if the C{loader} - attribute is C{None}. - """ - element = Element() - err = self.assertRaises(MissingTemplateLoader, element.render, None) - self.assertIdentical(err.element, element) - - - def test_missingTemplateLoaderRepr(self): - """ - A L{MissingTemplateLoader} instance can be repr()'d without error. - """ - class PrettyReprElement(Element): - def __repr__(self): - return 'Pretty Repr Element' - self.assertIn('Pretty Repr Element', - repr(MissingTemplateLoader(PrettyReprElement()))) - - - def test_missingRendererMethod(self): - """ - When called with the name which is not associated with a render method, - L{Element.lookupRenderMethod} raises L{MissingRenderMethod}. - """ - element = Element() - err = self.assertRaises( - MissingRenderMethod, element.lookupRenderMethod, "foo") - self.assertIdentical(err.element, element) - self.assertEqual(err.renderName, "foo") - - - def test_missingRenderMethodRepr(self): - """ - A L{MissingRenderMethod} instance can be repr()'d without error. - """ - class PrettyReprElement(Element): - def __repr__(self): - return 'Pretty Repr Element' - s = repr(MissingRenderMethod(PrettyReprElement(), - 'expectedMethod')) - self.assertIn('Pretty Repr Element', s) - self.assertIn('expectedMethod', s) - - - def test_definedRenderer(self): - """ - When called with the name of a defined render method, - L{Element.lookupRenderMethod} returns that render method. - """ - class ElementWithRenderMethod(Element): - @renderer - def foo(self, request, tag): - return "bar" - foo = ElementWithRenderMethod().lookupRenderMethod("foo") - self.assertEqual(foo(None, None), "bar") - - - def test_render(self): - """ - L{Element.render} loads a document from the C{loader} attribute and - returns it. - """ - class TemplateLoader(object): - def load(self): - return "result" - - class StubElement(Element): - loader = TemplateLoader() - - element = StubElement() - self.assertEqual(element.render(None), "result") - - - def test_misuseRenderer(self): - """ - If the L{renderer} decorator is called without any arguments, it will - raise a comprehensible exception. - """ - te = self.assertRaises(TypeError, renderer) - self.assertEqual(str(te), - "expose() takes at least 1 argument (0 given)") - - - def test_renderGetDirectlyError(self): - """ - Called directly, without a default, L{renderer.get} raises - L{UnexposedMethodError} when it cannot find a renderer. - """ - self.assertRaises(UnexposedMethodError, renderer.get, None, - "notARenderer") - - - -class XMLFileReprTests(TestCase): - """ - Tests for L{twisted.web.template.XMLFile}'s C{__repr__}. - """ - def test_filePath(self): - """ - An L{XMLFile} with a L{FilePath} returns a useful repr(). - """ - path = FilePath("/tmp/fake.xml") - self.assertEqual('<XMLFile of %r>' % (path,), repr(XMLFile(path))) - - - def test_filename(self): - """ - An L{XMLFile} with a filename returns a useful repr(). - """ - fname = "/tmp/fake.xml" - self.assertEqual('<XMLFile of %r>' % (fname,), repr(XMLFile(fname))) - test_filename.suppress = [_xmlFileSuppress] - - - def test_file(self): - """ - An L{XMLFile} with a file object returns a useful repr(). - """ - fobj = StringIO("not xml") - self.assertEqual('<XMLFile of %r>' % (fobj,), repr(XMLFile(fobj))) - test_file.suppress = [_xmlFileSuppress] - - - -class XMLLoaderTestsMixin(object): - """ - @ivar templateString: Simple template to use to exercise the loaders. - - @ivar deprecatedUse: C{True} if this use of L{XMLFile} is deprecated and - should emit a C{DeprecationWarning}. - """ - - loaderFactory = None - templateString = '<p>Hello, world.</p>' - def test_load(self): - """ - Verify that the loader returns a tag with the correct children. - """ - loader = self.loaderFactory() - tag, = loader.load() - - warnings = self.flushWarnings(offendingFunctions=[self.loaderFactory]) - if self.deprecatedUse: - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "Passing filenames or file objects to XMLFile is " - "deprecated since Twisted 12.1. Pass a FilePath instead.") - else: - self.assertEqual(len(warnings), 0) - - self.assertEqual(tag.tagName, 'p') - self.assertEqual(tag.children, [u'Hello, world.']) - - - def test_loadTwice(self): - """ - If {load()} can be called on a loader twice the result should be the - same. - """ - loader = self.loaderFactory() - tags1 = loader.load() - tags2 = loader.load() - self.assertEqual(tags1, tags2) - test_loadTwice.suppress = [_xmlFileSuppress] - - - -class XMLStringLoaderTests(TestCase, XMLLoaderTestsMixin): - """ - Tests for L{twisted.web.template.XMLString} - """ - deprecatedUse = False - def loaderFactory(self): - """ - @return: an L{XMLString} constructed with C{self.templateString}. - """ - return XMLString(self.templateString) - - - -class XMLFileWithFilePathTests(TestCase, XMLLoaderTestsMixin): - """ - Tests for L{twisted.web.template.XMLFile}'s L{FilePath} support. - """ - deprecatedUse = False - def loaderFactory(self): - """ - @return: an L{XMLString} constructed with a L{FilePath} pointing to a - file that contains C{self.templateString}. - """ - fp = FilePath(self.mktemp()) - fp.setContent(self.templateString) - return XMLFile(fp) - - - -class XMLFileWithFileTests(TestCase, XMLLoaderTestsMixin): - """ - Tests for L{twisted.web.template.XMLFile}'s deprecated file object support. - """ - deprecatedUse = True - def loaderFactory(self): - """ - @return: an L{XMLString} constructed with a file object that contains - C{self.templateString}. - """ - return XMLFile(StringIO(self.templateString)) - - - -class XMLFileWithFilenameTests(TestCase, XMLLoaderTestsMixin): - """ - Tests for L{twisted.web.template.XMLFile}'s deprecated filename support. - """ - deprecatedUse = True - def loaderFactory(self): - """ - @return: an L{XMLString} constructed with a filename that points to a - file containing C{self.templateString}. - """ - fp = FilePath(self.mktemp()) - fp.setContent(self.templateString) - return XMLFile(fp.path) - - - -class FlattenIntegrationTests(FlattenTestCase): - """ - Tests for integration between L{Element} and - L{twisted.web._flatten.flatten}. - """ - - def test_roundTrip(self): - """ - Given a series of parsable XML strings, verify that - L{twisted.web._flatten.flatten} will flatten the L{Element} back to the - input when sent on a round trip. - """ - fragments = [ - "<p>Hello, world.</p>", - "<p><!-- hello, world --></p>", - "<p><![CDATA[Hello, world.]]></p>", - '<test1 xmlns:test2="urn:test2">' - '<test2:test3></test2:test3></test1>', - '<test1 xmlns="urn:test2"><test3></test3></test1>', - '<p>\xe2\x98\x83</p>', - ] - deferreds = [ - self.assertFlattensTo(Element(loader=XMLString(xml)), xml) - for xml in fragments] - return gatherResults(deferreds) - - - def test_entityConversion(self): - """ - When flattening an HTML entity, it should flatten out to the utf-8 - representation if possible. - """ - element = Element(loader=XMLString('<p>&#9731;</p>')) - return self.assertFlattensTo(element, '<p>\xe2\x98\x83</p>') - - - def test_missingTemplateLoader(self): - """ - Rendering a Element without a loader attribute raises the appropriate - exception. - """ - return self.assertFlatteningRaises(Element(), MissingTemplateLoader) - - - def test_missingRenderMethod(self): - """ - Flattening an L{Element} with a C{loader} which has a tag with a render - directive fails with L{FlattenerError} if there is no available render - method to satisfy that directive. - """ - element = Element(loader=XMLString(""" - <p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1" - t:render="unknownMethod" /> - """)) - return self.assertFlatteningRaises(element, MissingRenderMethod) - - - def test_transparentRendering(self): - """ - A C{transparent} element should be eliminated from the DOM and rendered as - only its children. - """ - element = Element(loader=XMLString( - '<t:transparent ' - 'xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">' - 'Hello, world.' - '</t:transparent>' - )) - return self.assertFlattensTo(element, "Hello, world.") - - - def test_attrRendering(self): - """ - An Element with an attr tag renders the vaule of its attr tag as an - attribute of its containing tag. - """ - element = Element(loader=XMLString( - '<a xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">' - '<t:attr name="href">http://example.com</t:attr>' - 'Hello, world.' - '</a>' - )) - return self.assertFlattensTo(element, - '<a href="http://example.com">Hello, world.</a>') - - - def test_errorToplevelAttr(self): - """ - A template with a toplevel C{attr} tag will not load; it will raise - L{AssertionError} if you try. - """ - self.assertRaises( - AssertionError, - XMLString, - """<t:attr - xmlns:t='http://twistedmatrix.com/ns/twisted.web.template/0.1' - name='something' - >hello</t:attr> - """) - - - def test_errorUnnamedAttr(self): - """ - A template with an C{attr} tag with no C{name} attribute will not load; - it will raise L{AssertionError} if you try. - """ - self.assertRaises( - AssertionError, - XMLString, - """<html><t:attr - xmlns:t='http://twistedmatrix.com/ns/twisted.web.template/0.1' - >hello</t:attr></html>""") - - - def test_lenientPrefixBehavior(self): - """ - If the parser sees a prefix it doesn't recognize on an attribute, it - will pass it on through to serialization. - """ - theInput = ( - '<hello:world hello:sample="testing" ' - 'xmlns:hello="http://made-up.example.com/ns/not-real">' - 'This is a made-up tag.</hello:world>') - element = Element(loader=XMLString(theInput)) - self.assertFlattensTo(element, theInput) - - - def test_deferredRendering(self): - """ - An Element with a render method which returns a Deferred will render - correctly. - """ - class RenderfulElement(Element): - @renderer - def renderMethod(self, request, tag): - return succeed("Hello, world.") - element = RenderfulElement(loader=XMLString(""" - <p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1" - t:render="renderMethod"> - Goodbye, world. - </p> - """)) - return self.assertFlattensTo(element, "Hello, world.") - - - def test_loaderClassAttribute(self): - """ - If there is a non-None loader attribute on the class of an Element - instance but none on the instance itself, the class attribute is used. - """ - class SubElement(Element): - loader = XMLString("<p>Hello, world.</p>") - return self.assertFlattensTo(SubElement(), "<p>Hello, world.</p>") - - - def test_directiveRendering(self): - """ - An Element with a valid render directive has that directive invoked and - the result added to the output. - """ - renders = [] - class RenderfulElement(Element): - @renderer - def renderMethod(self, request, tag): - renders.append((self, request)) - return tag("Hello, world.") - element = RenderfulElement(loader=XMLString(""" - <p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1" - t:render="renderMethod" /> - """)) - return self.assertFlattensTo(element, "<p>Hello, world.</p>") - - - def test_directiveRenderingOmittingTag(self): - """ - An Element with a render method which omits the containing tag - successfully removes that tag from the output. - """ - class RenderfulElement(Element): - @renderer - def renderMethod(self, request, tag): - return "Hello, world." - element = RenderfulElement(loader=XMLString(""" - <p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1" - t:render="renderMethod"> - Goodbye, world. - </p> - """)) - return self.assertFlattensTo(element, "Hello, world.") - - - def test_elementContainingStaticElement(self): - """ - An Element which is returned by the render method of another Element is - rendered properly. - """ - class RenderfulElement(Element): - @renderer - def renderMethod(self, request, tag): - return tag(Element( - loader=XMLString("<em>Hello, world.</em>"))) - element = RenderfulElement(loader=XMLString(""" - <p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1" - t:render="renderMethod" /> - """)) - return self.assertFlattensTo(element, "<p><em>Hello, world.</em></p>") - - - def test_elementUsingSlots(self): - """ - An Element which is returned by the render method of another Element is - rendered properly. - """ - class RenderfulElement(Element): - @renderer - def renderMethod(self, request, tag): - return tag.fillSlots(test2='world.') - element = RenderfulElement(loader=XMLString( - '<p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1"' - ' t:render="renderMethod">' - '<t:slot name="test1" default="Hello, " />' - '<t:slot name="test2" />' - '</p>' - )) - return self.assertFlattensTo(element, "<p>Hello, world.</p>") - - - def test_elementContainingDynamicElement(self): - """ - Directives in the document factory of a Element returned from a render - method of another Element are satisfied from the correct object: the - "inner" Element. - """ - class OuterElement(Element): - @renderer - def outerMethod(self, request, tag): - return tag(InnerElement(loader=XMLString(""" - <t:ignored - xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1" - t:render="innerMethod" /> - """))) - class InnerElement(Element): - @renderer - def innerMethod(self, request, tag): - return "Hello, world." - element = OuterElement(loader=XMLString(""" - <p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1" - t:render="outerMethod" /> - """)) - return self.assertFlattensTo(element, "<p>Hello, world.</p>") - - - def test_sameLoaderTwice(self): - """ - Rendering the output of a loader, or even the same element, should - return different output each time. - """ - sharedLoader = XMLString( - '<p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">' - '<t:transparent t:render="classCounter" /> ' - '<t:transparent t:render="instanceCounter" />' - '</p>') - - class DestructiveElement(Element): - count = 0 - instanceCount = 0 - loader = sharedLoader - - @renderer - def classCounter(self, request, tag): - DestructiveElement.count += 1 - return tag(str(DestructiveElement.count)) - @renderer - def instanceCounter(self, request, tag): - self.instanceCount += 1 - return tag(str(self.instanceCount)) - - e1 = DestructiveElement() - e2 = DestructiveElement() - self.assertFlattensImmediately(e1, "<p>1 1</p>") - self.assertFlattensImmediately(e1, "<p>2 2</p>") - self.assertFlattensImmediately(e2, "<p>3 1</p>") - - - -class TagLoaderTests(FlattenTestCase): - """ - Tests for L{TagLoader}. - """ - def setUp(self): - self.loader = TagLoader(tags.i('test')) - - - def test_interface(self): - """ - An instance of L{TagLoader} provides L{ITemplateLoader}. - """ - self.assertTrue(verifyObject(ITemplateLoader, self.loader)) - - - def test_loadsList(self): - """ - L{TagLoader.load} returns a list, per L{ITemplateLoader}. - """ - self.assertIsInstance(self.loader.load(), list) - - - def test_flatten(self): - """ - L{TagLoader} can be used in an L{Element}, and flattens as the tag used - to construct the L{TagLoader} would flatten. - """ - e = Element(self.loader) - self.assertFlattensImmediately(e, '<i>test</i>') - - - -class TestElement(Element): - """ - An L{Element} that can be rendered successfully. - """ - loader = XMLString( - '<p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">' - 'Hello, world.' - '</p>') - - - -class TestFailureElement(Element): - """ - An L{Element} that can be used in place of L{FailureElement} to verify - that L{renderElement} can render failures properly. - """ - loader = XMLString( - '<p xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">' - 'I failed.' - '</p>') - - def __init__(self, failure, loader=None): - self.failure = failure - - - -class FailingElement(Element): - """ - An element that raises an exception when rendered. - """ - def render(self, request): - a = 42 - b = 0 - return a // b - - - -class FakeSite(object): - """ - A minimal L{Site} object that we can use to test displayTracebacks - """ - displayTracebacks = False - - - -class RenderElementTests(TestCase): - """ - Test L{renderElement} - """ - - def setUp(self): - """ - Set up a common L{DummyRequest} and L{FakeSite}. - """ - self.request = DummyRequest([""]) - self.request.site = FakeSite() - - - def test_simpleRender(self): - """ - L{renderElement} returns NOT_DONE_YET and eventually - writes the rendered L{Element} to the request before finishing the - request. - """ - element = TestElement() - - d = self.request.notifyFinish() - - def check(_): - self.assertEqual( - "".join(self.request.written), - "<!DOCTYPE html>\n" - "<p>Hello, world.</p>") - self.assertTrue(self.request.finished) - - d.addCallback(check) - - self.assertIdentical(NOT_DONE_YET, renderElement(self.request, element)) - - return d - - - def test_simpleFailure(self): - """ - L{renderElement} handles failures by writing a minimal - error message to the request and finishing it. - """ - element = FailingElement() - - d = self.request.notifyFinish() - - def check(_): - flushed = self.flushLoggedErrors(FlattenerError) - self.assertEqual(len(flushed), 1) - self.assertEqual( - "".join(self.request.written), - ('<!DOCTYPE html>\n' - '<div style="font-size:800%;' - 'background-color:#FFF;' - 'color:#F00' - '">An error occurred while rendering the response.</div>')) - self.assertTrue(self.request.finished) - - d.addCallback(check) - - self.assertIdentical(NOT_DONE_YET, renderElement(self.request, element)) - - return d - - - def test_simpleFailureWithTraceback(self): - """ - L{renderElement} will render a traceback when rendering of - the element fails and our site is configured to display tracebacks. - """ - self.request.site.displayTracebacks = True - - element = FailingElement() - - d = self.request.notifyFinish() - - def check(_): - flushed = self.flushLoggedErrors(FlattenerError) - self.assertEqual(len(flushed), 1) - self.assertEqual( - "".join(self.request.written), - "<!DOCTYPE html>\n<p>I failed.</p>") - self.assertTrue(self.request.finished) - - d.addCallback(check) - - renderElement(self.request, element, _failElement=TestFailureElement) - - return d - - - def test_nonDefaultDoctype(self): - """ - L{renderElement} will write the doctype string specified by the - doctype keyword argument. - """ - - element = TestElement() - - d = self.request.notifyFinish() - - def check(_): - self.assertEqual( - "".join(self.request.written), - ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' - ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' - '<p>Hello, world.</p>')) - - d.addCallback(check) - - renderElement( - self.request, - element, - doctype=( - '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' - ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">')) - - return d - - - def test_noneDoctype(self): - """ - L{renderElement} will not write out a doctype if the doctype keyword - argument is C{None}. - """ - - element = TestElement() - - d = self.request.notifyFinish() - - def check(_): - self.assertEqual( - "".join(self.request.written), - '<p>Hello, world.</p>') - - d.addCallback(check) - - renderElement(self.request, element, doctype=None) - - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_util.py deleted file mode 100644 index 00e0443..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_util.py +++ /dev/null @@ -1,326 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.util}. -""" - -from twisted.python.failure import Failure -from twisted.trial.unittest import TestCase -from twisted.internet import defer -from twisted.web import util -from twisted.web.error import FlattenerError -from twisted.web.util import ( - redirectTo, _SourceLineElement, - _SourceFragmentElement, _FrameElement, _StackElement, - FailureElement, formatFailure, DeferredResource) - -from twisted.web.http import FOUND -from twisted.web.server import Request -from twisted.web.template import TagLoader, flattenString, tags -from twisted.web import resource -from twisted.web.test.requesthelper import DummyChannel, DummyRequest - - -class RedirectToTests(TestCase): - """ - Tests for L{redirectTo}. - """ - - def test_headersAndCode(self): - """ - L{redirectTo} will set the C{Location} and C{Content-Type} headers on - its request, and set the response code to C{FOUND}, so the browser will - be redirected. - """ - request = Request(DummyChannel(), True) - request.method = 'GET' - targetURL = "http://target.example.com/4321" - redirectTo(targetURL, request) - self.assertEqual(request.code, FOUND) - self.assertEqual( - request.responseHeaders.getRawHeaders('location'), [targetURL]) - self.assertEqual( - request.responseHeaders.getRawHeaders('content-type'), - ['text/html; charset=utf-8']) - - - def test_redirectToUnicodeURL(self) : - """ - L{redirectTo} will raise TypeError if unicode object is passed in URL - """ - request = Request(DummyChannel(), True) - request.method = 'GET' - targetURL = u'http://target.example.com/4321' - self.assertRaises(TypeError, redirectTo, targetURL, request) - - - -class FailureElementTests(TestCase): - """ - Tests for L{FailureElement} and related helpers which can render a - L{Failure} as an HTML string. - """ - def setUp(self): - """ - Create a L{Failure} which can be used by the rendering tests. - """ - def lineNumberProbeAlsoBroken(): - message = "This is a problem" - raise Exception(message) - # Figure out the line number from which the exception will be raised. - self.base = lineNumberProbeAlsoBroken.func_code.co_firstlineno + 1 - - try: - lineNumberProbeAlsoBroken() - except: - self.failure = Failure(captureVars=True) - self.frame = self.failure.frames[-1] - - - def test_sourceLineElement(self): - """ - L{_SourceLineElement} renders a source line and line number. - """ - element = _SourceLineElement( - TagLoader(tags.div( - tags.span(render="lineNumber"), - tags.span(render="sourceLine"))), - 50, " print 'hello'") - d = flattenString(None, element) - expected = ( - u"<div><span>50</span><span>" - u" \N{NO-BREAK SPACE} \N{NO-BREAK SPACE}print 'hello'</span></div>") - d.addCallback( - self.assertEqual, expected.encode('utf-8')) - return d - - - def test_sourceFragmentElement(self): - """ - L{_SourceFragmentElement} renders source lines at and around the line - number indicated by a frame object. - """ - element = _SourceFragmentElement( - TagLoader(tags.div( - tags.span(render="lineNumber"), - tags.span(render="sourceLine"), - render="sourceLines")), - self.frame) - - source = [ - u' \N{NO-BREAK SPACE} \N{NO-BREAK SPACE}message = ' - u'"This is a problem"', - - u' \N{NO-BREAK SPACE} \N{NO-BREAK SPACE}raise Exception(message)', - u'# Figure out the line number from which the exception will be ' - u'raised.', - ] - d = flattenString(None, element) - d.addCallback( - self.assertEqual, - ''.join([ - '<div class="snippet%sLine"><span>%d</span><span>%s</span>' - '</div>' % ( - ["", "Highlight"][lineNumber == 1], - self.base + lineNumber, - (u" \N{NO-BREAK SPACE}" * 4 + sourceLine).encode( - 'utf-8')) - for (lineNumber, sourceLine) - in enumerate(source)])) - return d - - - def test_frameElementFilename(self): - """ - The I{filename} renderer of L{_FrameElement} renders the filename - associated with the frame object used to initialize the - L{_FrameElement}. - """ - element = _FrameElement( - TagLoader(tags.span(render="filename")), - self.frame) - d = flattenString(None, element) - d.addCallback( - # __file__ differs depending on whether an up-to-date .pyc file - # already existed. - self.assertEqual, "<span>" + __file__.rstrip('c') + "</span>") - return d - - - def test_frameElementLineNumber(self): - """ - The I{lineNumber} renderer of L{_FrameElement} renders the line number - associated with the frame object used to initialize the - L{_FrameElement}. - """ - element = _FrameElement( - TagLoader(tags.span(render="lineNumber")), - self.frame) - d = flattenString(None, element) - d.addCallback( - self.assertEqual, "<span>" + str(self.base + 1) + "</span>") - return d - - - def test_frameElementFunction(self): - """ - The I{function} renderer of L{_FrameElement} renders the line number - associated with the frame object used to initialize the - L{_FrameElement}. - """ - element = _FrameElement( - TagLoader(tags.span(render="function")), - self.frame) - d = flattenString(None, element) - d.addCallback( - self.assertEqual, "<span>lineNumberProbeAlsoBroken</span>") - return d - - - def test_frameElementSource(self): - """ - The I{source} renderer of L{_FrameElement} renders the source code near - the source filename/line number associated with the frame object used to - initialize the L{_FrameElement}. - """ - element = _FrameElement(None, self.frame) - renderer = element.lookupRenderMethod("source") - tag = tags.div() - result = renderer(None, tag) - self.assertIsInstance(result, _SourceFragmentElement) - self.assertIdentical(result.frame, self.frame) - self.assertEqual([tag], result.loader.load()) - - - def test_stackElement(self): - """ - The I{frames} renderer of L{_StackElement} renders each stack frame in - the list of frames used to initialize the L{_StackElement}. - """ - element = _StackElement(None, self.failure.frames[:2]) - renderer = element.lookupRenderMethod("frames") - tag = tags.div() - result = renderer(None, tag) - self.assertIsInstance(result, list) - self.assertIsInstance(result[0], _FrameElement) - self.assertIdentical(result[0].frame, self.failure.frames[0]) - self.assertIsInstance(result[1], _FrameElement) - self.assertIdentical(result[1].frame, self.failure.frames[1]) - # They must not share the same tag object. - self.assertNotEqual(result[0].loader.load(), result[1].loader.load()) - self.assertEqual(2, len(result)) - - - def test_failureElementTraceback(self): - """ - The I{traceback} renderer of L{FailureElement} renders the failure's - stack frames using L{_StackElement}. - """ - element = FailureElement(self.failure) - renderer = element.lookupRenderMethod("traceback") - tag = tags.div() - result = renderer(None, tag) - self.assertIsInstance(result, _StackElement) - self.assertIdentical(result.stackFrames, self.failure.frames) - self.assertEqual([tag], result.loader.load()) - - - def test_failureElementType(self): - """ - The I{type} renderer of L{FailureElement} renders the failure's - exception type. - """ - element = FailureElement( - self.failure, TagLoader(tags.span(render="type"))) - d = flattenString(None, element) - d.addCallback( - self.assertEqual, "<span>exceptions.Exception</span>") - return d - - - def test_failureElementValue(self): - """ - The I{value} renderer of L{FailureElement} renders the value's exception - value. - """ - element = FailureElement( - self.failure, TagLoader(tags.span(render="value"))) - d = flattenString(None, element) - d.addCallback( - self.assertEqual, '<span>This is a problem</span>') - return d - - - -class FormatFailureTests(TestCase): - """ - Tests for L{twisted.web.util.formatFailure} which returns an HTML string - representing the L{Failure} instance passed to it. - """ - def test_flattenerError(self): - """ - If there is an error flattening the L{Failure} instance, - L{formatFailure} raises L{FlattenerError}. - """ - self.assertRaises(FlattenerError, formatFailure, object()) - - - def test_returnsBytes(self): - """ - The return value of L{formatFailure} is a C{str} instance (not a - C{unicode} instance) with numeric character references for any non-ASCII - characters meant to appear in the output. - """ - try: - raise Exception("Fake bug") - except: - result = formatFailure(Failure()) - - self.assertIsInstance(result, str) - self.assertTrue(all(ord(ch) < 128 for ch in result)) - # Indentation happens to rely on NO-BREAK SPACE - self.assertIn("&#160;", result) - - - -class SDResource(resource.Resource): - def __init__(self,default): - self.default = default - - - def getChildWithDefault(self, name, request): - d = defer.succeed(self.default) - resource = util.DeferredResource(d) - return resource.getChildWithDefault(name, request) - - - -class DeferredResourceTests(TestCase): - """ - Tests for L{DeferredResource}. - """ - - def testDeferredResource(self): - r = resource.Resource() - r.isLeaf = 1 - s = SDResource(r) - d = DummyRequest(['foo', 'bar', 'baz']) - resource.getChildForRequest(s, d) - self.assertEqual(d.postpath, ['bar', 'baz']) - - - def test_render(self): - """ - L{DeferredResource} uses the request object's C{render} method to - render the resource which is the result of the L{Deferred} being - handled. - """ - rendered = [] - request = DummyRequest([]) - request.render = rendered.append - - result = resource.Resource() - deferredResource = DeferredResource(defer.succeed(result)) - deferredResource.render(request) - self.assertEqual(rendered, [result]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_vhost.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_vhost.py deleted file mode 100644 index 13e6357..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_vhost.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.vhost}. -""" - -from twisted.internet.defer import gatherResults -from twisted.trial.unittest import TestCase -from twisted.web.http import NOT_FOUND -from twisted.web.static import Data -from twisted.web.vhost import NameVirtualHost -from twisted.web.test.test_web import DummyRequest -from twisted.web.test._util import _render - -class NameVirtualHostTests(TestCase): - """ - Tests for L{NameVirtualHost}. - """ - def test_renderWithoutHost(self): - """ - L{NameVirtualHost.render} returns the result of rendering the - instance's C{default} if it is not C{None} and there is no I{Host} - header in the request. - """ - virtualHostResource = NameVirtualHost() - virtualHostResource.default = Data("correct result", "") - request = DummyRequest(['']) - self.assertEqual( - virtualHostResource.render(request), "correct result") - - - def test_renderWithoutHostNoDefault(self): - """ - L{NameVirtualHost.render} returns a response with a status of I{NOT - FOUND} if the instance's C{default} is C{None} and there is no I{Host} - header in the request. - """ - virtualHostResource = NameVirtualHost() - request = DummyRequest(['']) - d = _render(virtualHostResource, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, NOT_FOUND) - d.addCallback(cbRendered) - return d - - - def test_renderWithHost(self): - """ - L{NameVirtualHost.render} returns the result of rendering the resource - which is the value in the instance's C{host} dictionary corresponding - to the key indicated by the value of the I{Host} header in the request. - """ - virtualHostResource = NameVirtualHost() - virtualHostResource.addHost('example.org', Data("winner", "")) - - request = DummyRequest(['']) - request.headers['host'] = 'example.org' - d = _render(virtualHostResource, request) - def cbRendered(ignored, request): - self.assertEqual(''.join(request.written), "winner") - d.addCallback(cbRendered, request) - - # The port portion of the Host header should not be considered. - requestWithPort = DummyRequest(['']) - requestWithPort.headers['host'] = 'example.org:8000' - dWithPort = _render(virtualHostResource, requestWithPort) - def cbRendered(ignored, requestWithPort): - self.assertEqual(''.join(requestWithPort.written), "winner") - dWithPort.addCallback(cbRendered, requestWithPort) - - return gatherResults([d, dWithPort]) - - - def test_renderWithUnknownHost(self): - """ - L{NameVirtualHost.render} returns the result of rendering the - instance's C{default} if it is not C{None} and there is no host - matching the value of the I{Host} header in the request. - """ - virtualHostResource = NameVirtualHost() - virtualHostResource.default = Data("correct data", "") - request = DummyRequest(['']) - request.headers['host'] = 'example.com' - d = _render(virtualHostResource, request) - def cbRendered(ignored): - self.assertEqual(''.join(request.written), "correct data") - d.addCallback(cbRendered) - return d - - - def test_renderWithUnknownHostNoDefault(self): - """ - L{NameVirtualHost.render} returns a response with a status of I{NOT - FOUND} if the instance's C{default} is C{None} and there is no host - matching the value of the I{Host} header in the request. - """ - virtualHostResource = NameVirtualHost() - request = DummyRequest(['']) - request.headers['host'] = 'example.com' - d = _render(virtualHostResource, request) - def cbRendered(ignored): - self.assertEqual(request.responseCode, NOT_FOUND) - d.addCallback(cbRendered) - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_web.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_web.py deleted file mode 100644 index 3b82230..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_web.py +++ /dev/null @@ -1,1198 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for various parts of L{twisted.web}. -""" - -import os -import zlib - -from zope.interface import implementer -from zope.interface.verify import verifyObject - -from twisted.python.compat import _PY3 -from twisted.python.filepath import FilePath -from twisted.trial import unittest -from twisted.internet import reactor -from twisted.internet.address import IPv4Address -from twisted.internet.task import Clock -from twisted.web import server, resource -from twisted.web import iweb, http, error - -from twisted.web.test.requesthelper import DummyChannel, DummyRequest -from twisted.web.static import Data - - -class ResourceTests(unittest.TestCase): - def testListEntities(self): - r = resource.Resource() - self.assertEqual([], r.listEntities()) - - -class SimpleResource(resource.Resource): - """ - @ivar _contentType: C{None} or a C{str} giving the value of the - I{Content-Type} header in the response this resource will render. If it - is C{None}, no I{Content-Type} header will be set in the response. - """ - def __init__(self, contentType=None): - resource.Resource.__init__(self) - self._contentType = contentType - - - def render(self, request): - if self._contentType is not None: - request.responseHeaders.setRawHeaders( - b"content-type", [self._contentType]) - - if http.CACHED in (request.setLastModified(10), - request.setETag(b'MatchingTag')): - return b'' - else: - return b"correct" - - - -class SiteTest(unittest.TestCase): - """ - Unit tests for L{server.Site}. - """ - - def test_simplestSite(self): - """ - L{Site.getResourceFor} returns the C{b""} child of the root resource it - is constructed with when processing a request for I{/}. - """ - sres1 = SimpleResource() - sres2 = SimpleResource() - sres1.putChild(b"",sres2) - site = server.Site(sres1) - self.assertIdentical( - site.getResourceFor(DummyRequest([b''])), - sres2, "Got the wrong resource.") - - - def test_defaultRequestFactory(self): - """ - L{server.Request} is the default request factory. - """ - site = server.Site(resource=SimpleResource()) - - self.assertIs(server.Request, site.requestFactory) - - - def test_constructorRequestFactory(self): - """ - Can be initialized with a custom requestFactory. - """ - customFactory = object() - - site = server.Site( - resource=SimpleResource(), requestFactory=customFactory) - - self.assertIs(customFactory, site.requestFactory) - - - def test_buildProtocol(self): - """ - Returns a C{Channel} whose C{site} and C{requestFactory} attributes are - assigned from the C{site} instance. - """ - site = server.Site(SimpleResource()) - - channel = site.buildProtocol(None) - - self.assertIs(site, channel.site) - self.assertIs(site.requestFactory, channel.requestFactory) - - - -class SessionTests(unittest.TestCase): - """ - Tests for L{server.Session}. - """ - def setUp(self): - """ - Create a site with one active session using a deterministic, easily - controlled clock. - """ - self.clock = Clock() - self.uid = b'unique' - self.site = server.Site(resource.Resource()) - self.session = server.Session(self.site, self.uid, self.clock) - self.site.sessions[self.uid] = self.session - - - def test_defaultReactor(self): - """ - If not value is passed to L{server.Session.__init__}, the global - reactor is used. - """ - session = server.Session(server.Site(resource.Resource()), b'123') - self.assertIdentical(session._reactor, reactor) - - - def test_startCheckingExpiration(self): - """ - L{server.Session.startCheckingExpiration} causes the session to expire - after L{server.Session.sessionTimeout} seconds without activity. - """ - self.session.startCheckingExpiration() - - # Advance to almost the timeout - nothing should happen. - self.clock.advance(self.session.sessionTimeout - 1) - self.assertIn(self.uid, self.site.sessions) - - # Advance to the timeout, the session should expire. - self.clock.advance(1) - self.assertNotIn(self.uid, self.site.sessions) - - # There should be no calls left over, either. - self.assertFalse(self.clock.calls) - - - def test_expire(self): - """ - L{server.Session.expire} expires the session. - """ - self.session.expire() - # It should be gone from the session dictionary. - self.assertNotIn(self.uid, self.site.sessions) - # And there should be no pending delayed calls. - self.assertFalse(self.clock.calls) - - - def test_expireWhileChecking(self): - """ - L{server.Session.expire} expires the session even if the timeout call - isn't due yet. - """ - self.session.startCheckingExpiration() - self.test_expire() - - - def test_notifyOnExpire(self): - """ - A function registered with L{server.Session.notifyOnExpire} is called - when the session expires. - """ - callbackRan = [False] - def expired(): - callbackRan[0] = True - self.session.notifyOnExpire(expired) - self.session.expire() - self.assertTrue(callbackRan[0]) - - - def test_touch(self): - """ - L{server.Session.touch} updates L{server.Session.lastModified} and - delays session timeout. - """ - # Make sure it works before startCheckingExpiration - self.clock.advance(3) - self.session.touch() - self.assertEqual(self.session.lastModified, 3) - - # And after startCheckingExpiration - self.session.startCheckingExpiration() - self.clock.advance(self.session.sessionTimeout - 1) - self.session.touch() - self.clock.advance(self.session.sessionTimeout - 1) - self.assertIn(self.uid, self.site.sessions) - - # It should have advanced it by just sessionTimeout, no more. - self.clock.advance(1) - self.assertNotIn(self.uid, self.site.sessions) - - - -# Conditional requests: -# If-None-Match, If-Modified-Since - -# make conditional request: -# normal response if condition succeeds -# if condition fails: -# response code -# no body - -def httpBody(whole): - return whole.split(b'\r\n\r\n', 1)[1] - -def httpHeader(whole, key): - key = key.lower() - headers = whole.split(b'\r\n\r\n', 1)[0] - for header in headers.split(b'\r\n'): - if header.lower().startswith(key): - return header.split(b':', 1)[1].strip() - return None - -def httpCode(whole): - l1 = whole.split(b'\r\n', 1)[0] - return int(l1.split()[1]) - -class ConditionalTests(unittest.TestCase): - """ - web.server's handling of conditional requests for cache validation. - """ - def setUp(self): - self.resrc = SimpleResource() - self.resrc.putChild(b'', self.resrc) - self.resrc.putChild(b'with-content-type', SimpleResource(b'image/jpeg')) - self.site = server.Site(self.resrc) - self.site.startFactory() - self.addCleanup(self.site.stopFactory) - - # HELLLLLLLLLLP! This harness is Very Ugly. - self.channel = self.site.buildProtocol(None) - self.transport = http.StringTransport() - self.transport.close = lambda *a, **kw: None - self.transport.disconnecting = lambda *a, **kw: 0 - self.transport.getPeer = lambda *a, **kw: "peer" - self.transport.getHost = lambda *a, **kw: "host" - self.channel.makeConnection(self.transport) - - - def tearDown(self): - self.channel.connectionLost(None) - - - def _modifiedTest(self, modifiedSince=None, etag=None): - """ - Given the value C{modifiedSince} for the I{If-Modified-Since} header or - the value C{etag} for the I{If-Not-Match} header, verify that a response - with a 200 code, a default Content-Type, and the resource as the body is - returned. - """ - if modifiedSince is not None: - validator = b"If-Modified-Since: " + modifiedSince - else: - validator = b"If-Not-Match: " + etag - for line in [b"GET / HTTP/1.1", validator, b""]: - self.channel.lineReceived(line) - result = self.transport.getvalue() - self.assertEqual(httpCode(result), http.OK) - self.assertEqual(httpBody(result), b"correct") - self.assertEqual(httpHeader(result, b"Content-Type"), b"text/html") - - - def test_modified(self): - """ - If a request is made with an I{If-Modified-Since} header value with - a timestamp indicating a time before the last modification of the - requested resource, a 200 response is returned along with a response - body containing the resource. - """ - self._modifiedTest(modifiedSince=http.datetimeToString(1)) - - - def test_unmodified(self): - """ - If a request is made with an I{If-Modified-Since} header value with a - timestamp indicating a time after the last modification of the request - resource, a 304 response is returned along with an empty response body - and no Content-Type header if the application does not set one. - """ - for line in [b"GET / HTTP/1.1", - b"If-Modified-Since: " + http.datetimeToString(100), b""]: - self.channel.lineReceived(line) - result = self.transport.getvalue() - self.assertEqual(httpCode(result), http.NOT_MODIFIED) - self.assertEqual(httpBody(result), b"") - # Since there SHOULD NOT (RFC 2616, section 10.3.5) be any - # entity-headers, the Content-Type is not set if the application does - # not explicitly set it. - self.assertEqual(httpHeader(result, b"Content-Type"), None) - - - def test_invalidTimestamp(self): - """ - If a request is made with an I{If-Modified-Since} header value which - cannot be parsed, the header is treated as not having been present - and a normal 200 response is returned with a response body - containing the resource. - """ - self._modifiedTest(modifiedSince=b"like, maybe a week ago, I guess?") - - - def test_invalidTimestampYear(self): - """ - If a request is made with an I{If-Modified-Since} header value which - contains a string in the year position which is not an integer, the - header is treated as not having been present and a normal 200 - response is returned with a response body containing the resource. - """ - self._modifiedTest(modifiedSince=b"Thu, 01 Jan blah 00:00:10 GMT") - - - def test_invalidTimestampTooLongAgo(self): - """ - If a request is made with an I{If-Modified-Since} header value which - contains a year before the epoch, the header is treated as not - having been present and a normal 200 response is returned with a - response body containing the resource. - """ - self._modifiedTest(modifiedSince=b"Thu, 01 Jan 1899 00:00:10 GMT") - - - def test_invalidTimestampMonth(self): - """ - If a request is made with an I{If-Modified-Since} header value which - contains a string in the month position which is not a recognized - month abbreviation, the header is treated as not having been present - and a normal 200 response is returned with a response body - containing the resource. - """ - self._modifiedTest(modifiedSince=b"Thu, 01 Blah 1970 00:00:10 GMT") - - - def test_etagMatchedNot(self): - """ - If a request is made with an I{If-None-Match} ETag which does not match - the current ETag of the requested resource, the header is treated as not - having been present and a normal 200 response is returned with a - response body containing the resource. - """ - self._modifiedTest(etag=b"unmatchedTag") - - - def test_etagMatched(self): - """ - If a request is made with an I{If-None-Match} ETag which does match the - current ETag of the requested resource, a 304 response is returned along - with an empty response body. - """ - for line in [b"GET / HTTP/1.1", b"If-None-Match: MatchingTag", b""]: - self.channel.lineReceived(line) - result = self.transport.getvalue() - self.assertEqual(httpHeader(result, b"ETag"), b"MatchingTag") - self.assertEqual(httpCode(result), http.NOT_MODIFIED) - self.assertEqual(httpBody(result), b"") - - - def test_unmodifiedWithContentType(self): - """ - Similar to L{test_etagMatched}, but the response should include a - I{Content-Type} header if the application explicitly sets one. - - This I{Content-Type} header SHOULD NOT be present according to RFC 2616, - section 10.3.5. It will only be present if the application explicitly - sets it. - """ - for line in [b"GET /with-content-type HTTP/1.1", - b"If-None-Match: MatchingTag", b""]: - self.channel.lineReceived(line) - result = self.transport.getvalue() - self.assertEqual(httpCode(result), http.NOT_MODIFIED) - self.assertEqual(httpBody(result), b"") - self.assertEqual(httpHeader(result, b"Content-Type"), b"image/jpeg") - - - -class RequestTests(unittest.TestCase): - """ - Tests for the HTTP request class, L{server.Request}. - """ - - def test_interface(self): - """ - L{server.Request} instances provide L{iweb.IRequest}. - """ - self.assertTrue( - verifyObject(iweb.IRequest, server.Request(DummyChannel(), True))) - - - def testChildLink(self): - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - self.assertEqual(request.childLink(b'baz'), b'bar/baz') - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar/', b'HTTP/1.0') - self.assertEqual(request.childLink(b'baz'), b'baz') - - def testPrePathURLSimple(self): - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - request.setHost(b'example.com', 80) - self.assertEqual(request.prePathURL(), b'http://example.com/foo/bar') - - def testPrePathURLNonDefault(self): - d = DummyChannel() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost(b'example.com', 81) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - self.assertEqual(request.prePathURL(), b'http://example.com:81/foo/bar') - - def testPrePathURLSSLPort(self): - d = DummyChannel() - d.transport.port = 443 - request = server.Request(d, 1) - request.setHost(b'example.com', 443) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - self.assertEqual(request.prePathURL(), b'http://example.com:443/foo/bar') - - def testPrePathURLSSLPortAndSSL(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 443 - request = server.Request(d, 1) - request.setHost(b'example.com', 443) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - self.assertEqual(request.prePathURL(), b'https://example.com/foo/bar') - - def testPrePathURLHTTPPortAndSSL(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 80 - request = server.Request(d, 1) - request.setHost(b'example.com', 80) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - self.assertEqual(request.prePathURL(), b'https://example.com:80/foo/bar') - - def testPrePathURLSSLNonDefault(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost(b'example.com', 81) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - self.assertEqual(request.prePathURL(), b'https://example.com:81/foo/bar') - - def testPrePathURLSetSSLHost(self): - d = DummyChannel() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost(b'foo.com', 81, 1) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo/bar', b'HTTP/1.0') - self.assertEqual(request.prePathURL(), b'https://foo.com:81/foo/bar') - - - def test_prePathURLQuoting(self): - """ - L{Request.prePathURL} quotes special characters in the URL segments to - preserve the original meaning. - """ - d = DummyChannel() - request = server.Request(d, 1) - request.setHost(b'example.com', 80) - request.gotLength(0) - request.requestReceived(b'GET', b'/foo%2Fbar', b'HTTP/1.0') - self.assertEqual(request.prePathURL(), b'http://example.com/foo%2Fbar') - - - -class GzipEncoderTests(unittest.TestCase): - - if _PY3: - skip = "GzipEncoder not ported to Python 3 yet." - - def setUp(self): - self.channel = DummyChannel() - staticResource = Data(b"Some data", "text/plain") - wrapped = resource.EncodingResourceWrapper( - staticResource, [server.GzipEncoderFactory()]) - self.channel.site.resource.putChild(b"foo", wrapped) - - - def test_interfaces(self): - """ - L{server.GzipEncoderFactory} implements the - L{iweb._IRequestEncoderFactory} and its C{encoderForRequest} returns an - instance of L{server._GzipEncoder} which implements - L{iweb._IRequestEncoder}. - """ - request = server.Request(self.channel, False) - request.gotLength(0) - request.requestHeaders.setRawHeaders(b"Accept-Encoding", - [b"gzip,deflate"]) - factory = server.GzipEncoderFactory() - self.assertTrue(verifyObject(iweb._IRequestEncoderFactory, factory)) - - encoder = factory.encoderForRequest(request) - self.assertTrue(verifyObject(iweb._IRequestEncoder, encoder)) - - - def test_encoding(self): - """ - If the client request passes a I{Accept-Encoding} header which mentions - gzip, L{server._GzipEncoder} automatically compresses the data. - """ - request = server.Request(self.channel, False) - request.gotLength(0) - request.requestHeaders.setRawHeaders(b"Accept-Encoding", - [b"gzip,deflate"]) - request.requestReceived(b'GET', b'/foo', b'HTTP/1.0') - data = self.channel.transport.written.getvalue() - self.assertNotIn(b"Content-Length", data) - self.assertIn(b"Content-Encoding: gzip\r\n", data) - body = data[data.find(b"\r\n\r\n") + 4:] - self.assertEqual(b"Some data", - zlib.decompress(body, 16 + zlib.MAX_WBITS)) - - - def test_nonEncoding(self): - """ - L{server.GzipEncoderFactory} doesn't return a L{server._GzipEncoder} if - the I{Accept-Encoding} header doesn't mention gzip support. - """ - request = server.Request(self.channel, False) - request.gotLength(0) - request.requestHeaders.setRawHeaders(b"Accept-Encoding", - [b"foo,bar"]) - request.requestReceived(b'GET', b'/foo', b'HTTP/1.0') - data = self.channel.transport.written.getvalue() - self.assertIn(b"Content-Length", data) - self.assertNotIn(b"Content-Encoding: gzip\r\n", data) - body = data[data.find(b"\r\n\r\n") + 4:] - self.assertEqual(b"Some data", body) - - - def test_multipleAccept(self): - """ - If there are multiple I{Accept-Encoding} header, - L{server.GzipEncoderFactory} reads them properly to detect if gzip is - supported. - """ - request = server.Request(self.channel, False) - request.gotLength(0) - request.requestHeaders.setRawHeaders(b"Accept-Encoding", - [b"deflate", b"gzip"]) - request.requestReceived(b'GET', b'/foo', b'HTTP/1.0') - data = self.channel.transport.written.getvalue() - self.assertNotIn(b"Content-Length", data) - self.assertIn(b"Content-Encoding: gzip\r\n", data) - body = data[data.find(b"\r\n\r\n") + 4:] - self.assertEqual(b"Some data", - zlib.decompress(body, 16 + zlib.MAX_WBITS)) - - - def test_alreadyEncoded(self): - """ - If the content is already encoded and the I{Content-Encoding} header is - set, L{server.GzipEncoderFactory} properly appends gzip to it. - """ - request = server.Request(self.channel, False) - request.gotLength(0) - request.requestHeaders.setRawHeaders(b"Accept-Encoding", - [b"deflate", b"gzip"]) - request.responseHeaders.setRawHeaders(b"Content-Encoding", - [b"deflate"]) - request.requestReceived(b'GET', b'/foo', b'HTTP/1.0') - data = self.channel.transport.written.getvalue() - self.assertNotIn(b"Content-Length", data) - self.assertIn(b"Content-Encoding: deflate,gzip\r\n", data) - body = data[data.find(b"\r\n\r\n") + 4:] - self.assertEqual(b"Some data", - zlib.decompress(body, 16 + zlib.MAX_WBITS)) - - - def test_multipleEncodingLines(self): - """ - If there are several I{Content-Encoding} headers, - L{server.GzipEncoderFactory} normalizes it and appends gzip to the - field value. - """ - request = server.Request(self.channel, False) - request.gotLength(0) - request.requestHeaders.setRawHeaders(b"Accept-Encoding", - [b"deflate", b"gzip"]) - request.responseHeaders.setRawHeaders(b"Content-Encoding", - [b"foo", b"bar"]) - request.requestReceived(b'GET', b'/foo', b'HTTP/1.0') - data = self.channel.transport.written.getvalue() - self.assertNotIn(b"Content-Length", data) - self.assertIn(b"Content-Encoding: foo,bar,gzip\r\n", data) - body = data[data.find(b"\r\n\r\n") + 4:] - self.assertEqual(b"Some data", - zlib.decompress(body, 16 + zlib.MAX_WBITS)) - - - -class RootResource(resource.Resource): - isLeaf=0 - def getChildWithDefault(self, name, request): - request.rememberRootURL() - return resource.Resource.getChildWithDefault(self, name, request) - def render(self, request): - return '' - -class RememberURLTests(unittest.TestCase): - def createServer(self, r): - chan = DummyChannel() - chan.site = server.Site(r) - return chan - - def testSimple(self): - r = resource.Resource() - r.isLeaf=0 - rr = RootResource() - r.putChild(b'foo', rr) - rr.putChild(b'', rr) - rr.putChild(b'bar', resource.Resource()) - chan = self.createServer(r) - for url in [b'/foo/', b'/foo/bar', b'/foo/bar/baz', b'/foo/bar/']: - request = server.Request(chan, 1) - request.setHost(b'example.com', 81) - request.gotLength(0) - request.requestReceived(b'GET', url, b'HTTP/1.0') - self.assertEqual(request.getRootURL(), b"http://example.com/foo") - - def testRoot(self): - rr = RootResource() - rr.putChild(b'', rr) - rr.putChild(b'bar', resource.Resource()) - chan = self.createServer(rr) - for url in [b'/', b'/bar', b'/bar/baz', b'/bar/']: - request = server.Request(chan, 1) - request.setHost(b'example.com', 81) - request.gotLength(0) - request.requestReceived(b'GET', url, b'HTTP/1.0') - self.assertEqual(request.getRootURL(), b"http://example.com/") - - -class NewRenderResource(resource.Resource): - def render_GET(self, request): - return b"hi hi" - - def render_HEH(self, request): - return b"ho ho" - - - -@implementer(resource.IResource) -class HeadlessResource(object): - """ - A resource that implements GET but not HEAD. - """ - - allowedMethods = [b"GET"] - - def render(self, request): - """ - Leave the request open for future writes. - """ - self.request = request - if request.method not in self.allowedMethods: - raise error.UnsupportedMethod(self.allowedMethods) - self.request.write(b"some data") - return server.NOT_DONE_YET - - - -class NewRenderTests(unittest.TestCase): - """ - Tests for L{server.Request.render}. - """ - def _getReq(self, resource=None): - """ - Create a request object with a stub channel and install the - passed resource at /newrender. If no resource is passed, - create one. - """ - d = DummyChannel() - if resource is None: - resource = NewRenderResource() - d.site.resource.putChild(b'newrender', resource) - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost(b'example.com', 81) - request.gotLength(0) - return request - - def testGoodMethods(self): - req = self._getReq() - req.requestReceived(b'GET', b'/newrender', b'HTTP/1.0') - self.assertEqual(req.transport.getvalue().splitlines()[-1], b'hi hi') - - req = self._getReq() - req.requestReceived(b'HEH', b'/newrender', b'HTTP/1.0') - self.assertEqual(req.transport.getvalue().splitlines()[-1], b'ho ho') - - def testBadMethods(self): - req = self._getReq() - req.requestReceived(b'CONNECT', b'/newrender', b'HTTP/1.0') - self.assertEqual(req.code, 501) - - req = self._getReq() - req.requestReceived(b'hlalauguG', b'/newrender', b'HTTP/1.0') - self.assertEqual(req.code, 501) - - def testImplicitHead(self): - req = self._getReq() - req.requestReceived(b'HEAD', b'/newrender', b'HTTP/1.0') - self.assertEqual(req.code, 200) - self.assertEqual(-1, req.transport.getvalue().find(b'hi hi')) - - - def test_unsupportedHead(self): - """ - HEAD requests against resource that only claim support for GET - should not include a body in the response. - """ - resource = HeadlessResource() - req = self._getReq(resource) - req.requestReceived(b"HEAD", b"/newrender", b"HTTP/1.0") - headers, body = req.transport.getvalue().split(b'\r\n\r\n') - self.assertEqual(req.code, 200) - self.assertEqual(body, b'') - - - -class GettableResource(resource.Resource): - """ - Used by AllowedMethodsTests to simulate an allowed method. - """ - def render_GET(self): - pass - - def render_fred_render_ethel(self): - """ - The unusual method name is designed to test the culling method - in C{twisted.web.resource._computeAllowedMethods}. - """ - pass - - - -class AllowedMethodsTests(unittest.TestCase): - """ - 'C{twisted.web.resource._computeAllowedMethods} is provided by a - default should the subclass not provide the method. - """ - - if _PY3: - skip = "Allowed methods functionality not ported to Python 3." - - def _getReq(self): - """ - Generate a dummy request for use by C{_computeAllowedMethod} tests. - """ - d = DummyChannel() - d.site.resource.putChild(b'gettableresource', GettableResource()) - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost(b'example.com', 81) - request.gotLength(0) - return request - - - def test_computeAllowedMethods(self): - """ - C{_computeAllowedMethods} will search through the - 'gettableresource' for all attributes/methods of the form - 'render_{method}' ('render_GET', for example) and return a list of - the methods. 'HEAD' will always be included from the - resource.Resource superclass. - """ - res = GettableResource() - allowedMethods = resource._computeAllowedMethods(res) - self.assertEqual(set(allowedMethods), - set([b'GET', b'HEAD', b'fred_render_ethel'])) - - - def test_notAllowed(self): - """ - When an unsupported method is requested, the default - L{_computeAllowedMethods} method will be called to determine the - allowed methods, and the HTTP 405 'Method Not Allowed' status will - be returned with the allowed methods will be returned in the - 'Allow' header. - """ - req = self._getReq() - req.requestReceived(b'POST', b'/gettableresource', b'HTTP/1.0') - self.assertEqual(req.code, 405) - self.assertEqual( - set(req.responseHeaders.getRawHeaders(b'allow')[0].split(b", ")), - set([b'GET', b'HEAD', b'fred_render_ethel']) - ) - - - def test_notAllowedQuoting(self): - """ - When an unsupported method response is generated, an HTML message will - be displayed. That message should include a quoted form of the URI and, - since that value come from a browser and shouldn't necessarily be - trusted. - """ - req = self._getReq() - req.requestReceived(b'POST', b'/gettableresource?' - b'value=<script>bad', b'HTTP/1.0') - self.assertEqual(req.code, 405) - renderedPage = req.transport.getvalue() - self.assertNotIn(b"<script>bad", renderedPage) - self.assertIn(b'&lt;script&gt;bad', renderedPage) - - - def test_notImplementedQuoting(self): - """ - When an not-implemented method response is generated, an HTML message - will be displayed. That message should include a quoted form of the - requested method, since that value come from a browser and shouldn't - necessarily be trusted. - """ - req = self._getReq() - req.requestReceived(b'<style>bad', b'/gettableresource', b'HTTP/1.0') - self.assertEqual(req.code, 501) - renderedPage = req.transport.getvalue() - self.assertNotIn(b"<style>bad", renderedPage) - self.assertIn(b'&lt;style&gt;bad', renderedPage) - - - -class DummyRequestForLogTest(DummyRequest): - uri = b'/dummy' # parent class uri has "http://", which doesn't really happen - code = 123 - - clientproto = b'HTTP/1.0' - sentLength = None - client = IPv4Address('TCP', '1.2.3.4', 12345) - - - -class AccessLogTestsMixin(object): - """ - A mixin for L{TestCase} subclasses defining tests that apply to - L{HTTPFactory} and its subclasses. - """ - def factory(self, *args, **kwargs): - """ - Get the factory class to apply logging tests to. - - Subclasses must override this method. - """ - raise NotImplementedError("Subclass failed to override factory") - - - def test_combinedLogFormat(self): - """ - The factory's C{log} method writes a I{combined log format} line to the - factory's log file. - """ - reactor = Clock() - # Set the clock to an arbitrary point in time. It doesn't matter when - # as long as it corresponds to the timestamp in the string literal in - # the assertion below. - reactor.advance(1234567890) - - logPath = self.mktemp() - factory = self.factory(logPath=logPath) - factory._reactor = reactor - factory.startFactory() - - try: - factory.log(DummyRequestForLogTest(factory)) - finally: - factory.stopFactory() - - self.assertEqual( - # Client IP - b'"1.2.3.4" ' - # Some blanks we never fill in - b'- - ' - # The current time (circa 1234567890) - b'[13/Feb/2009:23:31:30 +0000] ' - # Method, URI, version - b'"GET /dummy HTTP/1.0" ' - # Response code - b'123 ' - # Response length - b'- ' - # Value of the "Referer" header. Probably incorrectly quoted. - b'"-" ' - # Value pf the "User-Agent" header. Probably incorrectly quoted. - b'"-"' + self.linesep, - FilePath(logPath).getContent()) - - - def test_logFormatOverride(self): - """ - If the factory is initialized with a custom log formatter then that - formatter is used to generate lines for the log file. - """ - def notVeryGoodFormatter(timestamp, request): - return u"this is a bad log format" - - reactor = Clock() - reactor.advance(1234567890) - - logPath = self.mktemp() - factory = self.factory( - logPath=logPath, logFormatter=notVeryGoodFormatter) - factory._reactor = reactor - factory.startFactory() - try: - factory.log(DummyRequestForLogTest(factory)) - finally: - factory.stopFactory() - - self.assertEqual( - # self.linesep is a sad thing. - # https://twistedmatrix.com/trac/ticket/6938 - b"this is a bad log format" + self.linesep, - FilePath(logPath).getContent()) - - - -class HTTPFactoryAccessLogTests(AccessLogTestsMixin, unittest.TestCase): - """ - Tests for L{http.HTTPFactory.log}. - """ - factory = http.HTTPFactory - linesep = b"\n" - - - -class SiteAccessLogTests(AccessLogTestsMixin, unittest.TestCase): - """ - Tests for L{server.Site.log}. - """ - if _PY3: - skip = "Site not ported to Python 3 yet." - - linesep = os.linesep - - def factory(self, *args, **kwargs): - return server.Site(resource.Resource(), *args, **kwargs) - - - -class CombinedLogFormatterTests(unittest.TestCase): - """ - Tests for L{twisted.web.http.combinedLogFormatter}. - """ - def test_interface(self): - """ - L{combinedLogFormatter} provides L{IAccessLogFormatter}. - """ - self.assertTrue(verifyObject( - iweb.IAccessLogFormatter, http.combinedLogFormatter)) - - - def test_nonASCII(self): - """ - Bytes in fields of the request which are not part of ASCII are escaped - in the result. - """ - reactor = Clock() - reactor.advance(1234567890) - - timestamp = http.datetimeToLogString(reactor.seconds()) - request = DummyRequestForLogTest(http.HTTPFactory()) - request.client = IPv4Address("TCP", b"evil x-forwarded-for \x80", 12345) - request.method = b"POS\x81" - request.protocol = b"HTTP/1.\x82" - request.headers[b"referer"] = b"evil \x83" - request.headers[b"user-agent"] = b"evil \x84" - - line = http.combinedLogFormatter(timestamp, request) - self.assertEqual( - u'"evil x-forwarded-for \\x80" - - [13/Feb/2009:23:31:30 +0000] ' - u'"POS\\x81 /dummy HTTP/1.0" 123 - "evil \\x83" "evil \\x84"', - line) - - - -class ProxiedLogFormatterTests(unittest.TestCase): - """ - Tests for L{twisted.web.http.proxiedLogFormatter}. - """ - def test_interface(self): - """ - L{proxiedLogFormatter} provides L{IAccessLogFormatter}. - """ - self.assertTrue(verifyObject( - iweb.IAccessLogFormatter, http.proxiedLogFormatter)) - - - def _xforwardedforTest(self, header): - """ - Assert that a request with the given value in its I{X-Forwarded-For} - header is logged by L{proxiedLogFormatter} the same way it would have - been logged by L{combinedLogFormatter} but with 172.16.1.2 as the - client address instead of the normal value. - - @param header: An I{X-Forwarded-For} header with left-most address of - 172.16.1.2. - """ - reactor = Clock() - reactor.advance(1234567890) - - timestamp = http.datetimeToLogString(reactor.seconds()) - request = DummyRequestForLogTest(http.HTTPFactory()) - expected = http.combinedLogFormatter(timestamp, request).replace( - u"1.2.3.4", u"172.16.1.2") - request.requestHeaders.setRawHeaders(b"x-forwarded-for", [header]) - line = http.proxiedLogFormatter(timestamp, request) - - self.assertEqual(expected, line) - - - def test_xforwardedfor(self): - """ - L{proxiedLogFormatter} logs the value of the I{X-Forwarded-For} header - in place of the client address field. - """ - self._xforwardedforTest(b"172.16.1.2, 10.0.0.3, 192.168.1.4") - - - def test_extraForwardedSpaces(self): - """ - Any extra spaces around the address in the I{X-Forwarded-For} header - are stripped and not included in the log string. - """ - self._xforwardedforTest(b" 172.16.1.2 , 10.0.0.3, 192.168.1.4") - - - -class LogEscapingTests(unittest.TestCase): - def setUp(self): - self.logPath = self.mktemp() - self.site = http.HTTPFactory(self.logPath) - self.site.startFactory() - self.request = DummyRequestForLogTest(self.site, False) - - - def assertLogs(self, line): - """ - Assert that if C{self.request} is logged using C{self.site} then - C{line} is written to the site's access log file. - - @param line: The expected line. - @type line: L{bytes} - - @raise self.failureException: If the log file contains something other - than the expected line. - """ - try: - self.site.log(self.request) - finally: - self.site.stopFactory() - logged = FilePath(self.logPath).getContent() - self.assertEqual(line, logged) - - - def test_simple(self): - """ - A I{GET} request is logged with no extra escapes. - """ - self.site._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.assertLogs( - b'"1.2.3.4" - - [25/Oct/2004:12:31:59 +0000] ' - b'"GET /dummy HTTP/1.0" 123 - "-" "-"\n') - - - def test_methodQuote(self): - """ - If the HTTP request method includes a quote, the quote is escaped. - """ - self.site._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.method = b'G"T' - self.assertLogs( - b'"1.2.3.4" - - [25/Oct/2004:12:31:59 +0000] ' - b'"G\\"T /dummy HTTP/1.0" 123 - "-" "-"\n') - - - def test_requestQuote(self): - """ - If the HTTP request path includes a quote, the quote is escaped. - """ - self.site._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.uri = b'/dummy"withquote' - self.assertLogs( - b'"1.2.3.4" - - [25/Oct/2004:12:31:59 +0000] ' - b'"GET /dummy\\"withquote HTTP/1.0" 123 - "-" "-"\n') - - - def test_protoQuote(self): - """ - If the HTTP request version includes a quote, the quote is escaped. - """ - self.site._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.clientproto = b'HT"P/1.0' - self.assertLogs( - b'"1.2.3.4" - - [25/Oct/2004:12:31:59 +0000] ' - b'"GET /dummy HT\\"P/1.0" 123 - "-" "-"\n') - - - def test_refererQuote(self): - """ - If the value of the I{Referer} header contains a quote, the quote is - escaped. - """ - self.site._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.headers[b'referer'] = ( - b'http://malicious" ".website.invalid') - self.assertLogs( - b'"1.2.3.4" - - [25/Oct/2004:12:31:59 +0000] ' - b'"GET /dummy HTTP/1.0" 123 - ' - b'"http://malicious\\" \\".website.invalid" "-"\n') - - - def test_userAgentQuote(self): - """ - If the value of the I{User-Agent} header contains a quote, the quote is - escaped. - """ - self.site._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.headers[b'user-agent'] = b'Malicious Web" Evil' - self.assertLogs( - b'"1.2.3.4" - - [25/Oct/2004:12:31:59 +0000] ' - b'"GET /dummy HTTP/1.0" 123 - "-" "Malicious Web\\" Evil"\n') - - - -class ServerAttributesTests(unittest.TestCase): - """ - Tests that deprecated twisted.web.server attributes raise the appropriate - deprecation warnings when used. - """ - - def test_deprecatedAttributeDateTimeString(self): - """ - twisted.web.server.date_time_string should not be used; instead use - twisted.web.http.datetimeToString directly - """ - server.date_time_string - warnings = self.flushWarnings( - offendingFunctions=[self.test_deprecatedAttributeDateTimeString]) - - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - ("twisted.web.server.date_time_string was deprecated in Twisted " - "12.1.0: Please use twisted.web.http.datetimeToString instead")) - - - def test_deprecatedAttributeStringDateTime(self): - """ - twisted.web.server.string_date_time should not be used; instead use - twisted.web.http.stringToDatetime directly - """ - server.string_date_time - warnings = self.flushWarnings( - offendingFunctions=[self.test_deprecatedAttributeStringDateTime]) - - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - ("twisted.web.server.string_date_time was deprecated in Twisted " - "12.1.0: Please use twisted.web.http.stringToDatetime instead")) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_webclient.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_webclient.py deleted file mode 100644 index 1627f94..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_webclient.py +++ /dev/null @@ -1,1313 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for the old L{twisted.web.client} APIs, C{getPage} and friends. -""" - -from __future__ import division, absolute_import - -import os -from errno import ENOSPC - -try: - from urlparse import urlparse, urljoin -except ImportError: - from urllib.parse import urlparse, urljoin - -from twisted.python.compat import _PY3, networkString, nativeString, intToBytes -from twisted.trial import unittest -from twisted.web import server, client, error, resource -from twisted.web.static import Data -from twisted.web.util import Redirect -from twisted.internet import reactor, defer, interfaces -from twisted.python.filepath import FilePath -from twisted.python.log import msg -from twisted.protocols.policies import WrappingFactory -from twisted.test.proto_helpers import StringTransport - -try: - from twisted.internet import ssl -except: - ssl = None - -from twisted import test -serverPEM = FilePath(test.__file__.encode("utf-8")).sibling(b'server.pem') -serverPEMPath = nativeString(serverPEM.path) - - -_PY3DownloadSkip = "downloadPage will be ported to Python 3 in ticket #6197." - - -class ExtendedRedirect(resource.Resource): - """ - Redirection resource. - - The HTTP status code is set according to the C{code} query parameter. - - @type lastMethod: C{str} - @ivar lastMethod: Last handled HTTP request method - """ - isLeaf = True - lastMethod = None - - - def __init__(self, url): - resource.Resource.__init__(self) - self.url = url - - - def render(self, request): - if self.lastMethod: - self.lastMethod = request.method - return b"OK Thnx!" - else: - self.lastMethod = request.method - code = int(request.args[b'code'][0]) - return self.redirectTo(self.url, request, code) - - - def getChild(self, name, request): - return self - - - def redirectTo(self, url, request, code): - request.setResponseCode(code) - request.setHeader(b"location", url) - return b"OK Bye!" - - - -class ForeverTakingResource(resource.Resource): - """ - L{ForeverTakingResource} is a resource which never finishes responding - to requests. - """ - def __init__(self, write=False): - resource.Resource.__init__(self) - self._write = write - - def render(self, request): - if self._write: - request.write(b'some bytes') - return server.NOT_DONE_YET - - -class CookieMirrorResource(resource.Resource): - def render(self, request): - l = [] - for k,v in sorted(list(request.received_cookies.items())): - l.append((nativeString(k), nativeString(v))) - l.sort() - return networkString(repr(l)) - -class RawCookieMirrorResource(resource.Resource): - def render(self, request): - header = request.getHeader(b'cookie') - if header is None: - return b'None' - return networkString(repr(nativeString(header))) - -class ErrorResource(resource.Resource): - - def render(self, request): - request.setResponseCode(401) - if request.args.get(b"showlength"): - request.setHeader(b"content-length", b"0") - return b"" - -class NoLengthResource(resource.Resource): - - def render(self, request): - return b"nolength" - - - -class HostHeaderResource(resource.Resource): - """ - A testing resource which renders itself as the value of the host header - from the request. - """ - def render(self, request): - return request.requestHeaders.getRawHeaders(b"host")[0] - - - -class PayloadResource(resource.Resource): - """ - A testing resource which renders itself as the contents of the request body - as long as the request body is 100 bytes long, otherwise which renders - itself as C{"ERROR"}. - """ - def render(self, request): - data = request.content.read() - contentLength = request.requestHeaders.getRawHeaders(b"content-length")[0] - if len(data) != 100 or int(contentLength) != 100: - return b"ERROR" - return data - - -class DelayResource(resource.Resource): - - def __init__(self, seconds): - self.seconds = seconds - - def render(self, request): - def response(): - request.write(b'some bytes') - request.finish() - reactor.callLater(self.seconds, response) - return server.NOT_DONE_YET - - -class BrokenDownloadResource(resource.Resource): - - def render(self, request): - # only sends 3 bytes even though it claims to send 5 - request.setHeader(b"content-length", b"5") - request.write(b'abc') - return b'' - -class CountingRedirect(Redirect): - """ - A L{Redirect} resource that keeps track of the number of times the - resource has been accessed. - """ - def __init__(self, *a, **kw): - Redirect.__init__(self, *a, **kw) - self.count = 0 - - def render(self, request): - self.count += 1 - return Redirect.render(self, request) - - -class CountingResource(resource.Resource): - """ - A resource that keeps track of the number of times it has been accessed. - """ - def __init__(self): - resource.Resource.__init__(self) - self.count = 0 - - def render(self, request): - self.count += 1 - return b"Success" - - - -class URLJoinTests(unittest.TestCase): - """ - Tests for L{client._urljoin}. - """ - def test_noFragments(self): - """ - L{client._urljoin} does not include a fragment identifier in the - resulting URL if neither the base nor the new path include a fragment - identifier. - """ - self.assertEqual( - client._urljoin(b'http://foo.com/bar', b'/quux'), - b'http://foo.com/quux') - self.assertEqual( - client._urljoin(b'http://foo.com/bar#', b'/quux'), - b'http://foo.com/quux') - self.assertEqual( - client._urljoin(b'http://foo.com/bar', b'/quux#'), - b'http://foo.com/quux') - - - def test_preserveFragments(self): - """ - L{client._urljoin} preserves the fragment identifier from either the - new path or the base URL respectively, as specified in the HTTP 1.1 bis - draft. - - @see: U{https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-22#section-7.1.2} - """ - self.assertEqual( - client._urljoin(b'http://foo.com/bar#frag', b'/quux'), - b'http://foo.com/quux#frag') - self.assertEqual( - client._urljoin(b'http://foo.com/bar', b'/quux#frag2'), - b'http://foo.com/quux#frag2') - self.assertEqual( - client._urljoin(b'http://foo.com/bar#frag', b'/quux#frag2'), - b'http://foo.com/quux#frag2') - - - -class HTTPPageGetterTests(unittest.TestCase): - """ - Tests for L{HTTPPagerGetter}, the HTTP client protocol implementation - used to implement L{getPage}. - """ - def test_earlyHeaders(self): - """ - When a connection is made, L{HTTPPagerGetter} sends the headers from - its factory's C{headers} dict. If I{Host} or I{Content-Length} is - present in this dict, the values are not sent, since they are sent with - special values before the C{headers} dict is processed. If - I{User-Agent} is present in the dict, it overrides the value of the - C{agent} attribute of the factory. If I{Cookie} is present in the - dict, its value is added to the values from the factory's C{cookies} - attribute. - """ - factory = client.HTTPClientFactory( - b'http://foo/bar', - agent=b"foobar", - cookies={b'baz': b'quux'}, - postdata=b"some data", - headers={ - b'Host': b'example.net', - b'User-Agent': b'fooble', - b'Cookie': b'blah blah', - b'Content-Length': b'12981', - b'Useful': b'value'}) - transport = StringTransport() - protocol = client.HTTPPageGetter() - protocol.factory = factory - protocol.makeConnection(transport) - result = transport.value() - for expectedHeader in [ - b"Host: example.net\r\n", - b"User-Agent: foobar\r\n", - b"Content-Length: 9\r\n", - b"Useful: value\r\n", - b"connection: close\r\n", - b"Cookie: blah blah; baz=quux\r\n"]: - self.assertIn(expectedHeader, result) - - - -class WebClientTests(unittest.TestCase): - def _listen(self, site): - return reactor.listenTCP(0, site, interface="127.0.0.1") - - def setUp(self): - self.agent = None # for twisted.web.client.Agent test - self.cleanupServerConnections = 0 - r = resource.Resource() - r.putChild(b"file", Data(b"0123456789", "text/html")) - r.putChild(b"redirect", Redirect(b"/file")) - self.infiniteRedirectResource = CountingRedirect(b"/infiniteRedirect") - r.putChild(b"infiniteRedirect", self.infiniteRedirectResource) - r.putChild(b"wait", ForeverTakingResource()) - r.putChild(b"write-then-wait", ForeverTakingResource(write=True)) - r.putChild(b"error", ErrorResource()) - r.putChild(b"nolength", NoLengthResource()) - r.putChild(b"host", HostHeaderResource()) - r.putChild(b"payload", PayloadResource()) - r.putChild(b"broken", BrokenDownloadResource()) - r.putChild(b"cookiemirror", CookieMirrorResource()) - r.putChild(b'delay1', DelayResource(1)) - r.putChild(b'delay2', DelayResource(2)) - - self.afterFoundGetCounter = CountingResource() - r.putChild(b"afterFoundGetCounter", self.afterFoundGetCounter) - r.putChild(b"afterFoundGetRedirect", Redirect(b"/afterFoundGetCounter")) - - miscasedHead = Data(b"miscased-head GET response content", "major/minor") - miscasedHead.render_Head = lambda request: b"miscased-head content" - r.putChild(b"miscased-head", miscasedHead) - - self.extendedRedirect = ExtendedRedirect(b'/extendedRedirect') - r.putChild(b"extendedRedirect", self.extendedRedirect) - self.site = server.Site(r, timeout=None) - self.wrapper = WrappingFactory(self.site) - self.port = self._listen(self.wrapper) - self.portno = self.port.getHost().port - - def tearDown(self): - if self.agent: - # clean up connections for twisted.web.client.Agent test. - self.agent.closeCachedConnections() - self.agent = None - - # If the test indicated it might leave some server-side connections - # around, clean them up. - connections = list(self.wrapper.protocols.keys()) - # If there are fewer server-side connections than requested, - # that's okay. Some might have noticed that the client closed - # the connection and cleaned up after themselves. - for n in range(min(len(connections), self.cleanupServerConnections)): - proto = connections.pop() - msg("Closing %r" % (proto,)) - proto.transport.loseConnection() - if connections: - msg("Some left-over connections; this test is probably buggy.") - return self.port.stopListening() - - def getURL(self, path): - host = "http://127.0.0.1:%d/" % self.portno - return networkString(urljoin(host, nativeString(path))) - - def testPayload(self): - s = b"0123456789" * 10 - return client.getPage(self.getURL("payload"), postdata=s - ).addCallback(self.assertEqual, s - ) - - - def test_getPageBrokenDownload(self): - """ - If the connection is closed before the number of bytes indicated by - I{Content-Length} have been received, the L{Deferred} returned by - L{getPage} fails with L{PartialDownloadError}. - """ - d = client.getPage(self.getURL("broken")) - d = self.assertFailure(d, client.PartialDownloadError) - d.addCallback(lambda exc: self.assertEqual(exc.response, b"abc")) - return d - - - def test_downloadPageBrokenDownload(self): - """ - If the connection is closed before the number of bytes indicated by - I{Content-Length} have been received, the L{Deferred} returned by - L{downloadPage} fails with L{PartialDownloadError}. - """ - # test what happens when download gets disconnected in the middle - path = FilePath(self.mktemp()) - d = client.downloadPage(self.getURL("broken"), path.path) - d = self.assertFailure(d, client.PartialDownloadError) - - def checkResponse(response): - """ - The HTTP status code from the server is propagated through the - C{PartialDownloadError}. - """ - self.assertEqual(response.status, b"200") - self.assertEqual(response.message, b"OK") - return response - d.addCallback(checkResponse) - - def cbFailed(ignored): - self.assertEqual(path.getContent(), b"abc") - d.addCallback(cbFailed) - return d - - def test_downloadPageLogsFileCloseError(self): - """ - If there is an exception closing the file being written to after the - connection is prematurely closed, that exception is logged. - """ - class BrokenFile: - def write(self, bytes): - pass - - def close(self): - raise IOError(ENOSPC, "No file left on device") - - d = client.downloadPage(self.getURL("broken"), BrokenFile()) - d = self.assertFailure(d, client.PartialDownloadError) - def cbFailed(ignored): - self.assertEqual(len(self.flushLoggedErrors(IOError)), 1) - d.addCallback(cbFailed) - return d - - - def testHostHeader(self): - # if we pass Host header explicitly, it should be used, otherwise - # it should extract from url - return defer.gatherResults([ - client.getPage(self.getURL("host")).addCallback( - self.assertEqual, b"127.0.0.1:" + intToBytes(self.portno)), - client.getPage(self.getURL("host"), - headers={b"Host": b"www.example.com"}).addCallback( - self.assertEqual, b"www.example.com")]) - - - def test_getPage(self): - """ - L{client.getPage} returns a L{Deferred} which is called back with - the body of the response if the default method B{GET} is used. - """ - d = client.getPage(self.getURL("file")) - d.addCallback(self.assertEqual, b"0123456789") - return d - - - def test_getPageHEAD(self): - """ - L{client.getPage} returns a L{Deferred} which is called back with - the empty string if the method is I{HEAD} and there is a successful - response code. - """ - d = client.getPage(self.getURL("file"), method=b"HEAD") - d.addCallback(self.assertEqual, b"") - return d - - - def test_getPageNotQuiteHEAD(self): - """ - If the request method is a different casing of I{HEAD} (ie, not all - capitalized) then it is not a I{HEAD} request and the response body - is returned. - """ - d = client.getPage(self.getURL("miscased-head"), method=b'Head') - d.addCallback(self.assertEqual, b"miscased-head content") - return d - - - def test_timeoutNotTriggering(self): - """ - When a non-zero timeout is passed to L{getPage} and the page is - retrieved before the timeout period elapses, the L{Deferred} is - called back with the contents of the page. - """ - d = client.getPage(self.getURL("host"), timeout=100) - d.addCallback(self.assertEqual, - networkString("127.0.0.1:%s" % (self.portno,))) - return d - - - def test_timeoutTriggering(self): - """ - When a non-zero timeout is passed to L{getPage} and that many - seconds elapse before the server responds to the request. the - L{Deferred} is errbacked with a L{error.TimeoutError}. - """ - # This will probably leave some connections around. - self.cleanupServerConnections = 1 - return self.assertFailure( - client.getPage(self.getURL("wait"), timeout=0.000001), - defer.TimeoutError) - - - def testDownloadPage(self): - downloads = [] - downloadData = [(b"file", self.mktemp(), b"0123456789"), - (b"nolength", self.mktemp(), b"nolength")] - - for (url, name, data) in downloadData: - d = client.downloadPage(self.getURL(url), name) - d.addCallback(self._cbDownloadPageTest, data, name) - downloads.append(d) - return defer.gatherResults(downloads) - - def _cbDownloadPageTest(self, ignored, data, name): - bytes = file(name, "rb").read() - self.assertEqual(bytes, data) - - def testDownloadPageError1(self): - class errorfile: - def write(self, data): - raise IOError("badness happened during write") - def close(self): - pass - ef = errorfile() - return self.assertFailure( - client.downloadPage(self.getURL("file"), ef), - IOError) - - def testDownloadPageError2(self): - class errorfile: - def write(self, data): - pass - def close(self): - raise IOError("badness happened during close") - ef = errorfile() - return self.assertFailure( - client.downloadPage(self.getURL("file"), ef), - IOError) - - def testDownloadPageError3(self): - # make sure failures in open() are caught too. This is tricky. - # Might only work on posix. - tmpfile = open("unwritable", "wb") - tmpfile.close() - os.chmod("unwritable", 0) # make it unwritable (to us) - d = self.assertFailure( - client.downloadPage(self.getURL("file"), "unwritable"), - IOError) - d.addBoth(self._cleanupDownloadPageError3) - return d - - def _cleanupDownloadPageError3(self, ignored): - os.chmod("unwritable", 0o700) - os.unlink("unwritable") - return ignored - - def _downloadTest(self, method): - dl = [] - for (url, code) in [("nosuchfile", b"404"), ("error", b"401"), - ("error?showlength=1", b"401")]: - d = method(url) - d = self.assertFailure(d, error.Error) - d.addCallback(lambda exc, code=code: self.assertEqual(exc.args[0], code)) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def testServerError(self): - return self._downloadTest(lambda url: client.getPage(self.getURL(url))) - - def testDownloadServerError(self): - return self._downloadTest(lambda url: client.downloadPage(self.getURL(url), url.split('?')[0])) - - def testFactoryInfo(self): - url = self.getURL('file') - uri = client.URI.fromBytes(url) - factory = client.HTTPClientFactory(url) - reactor.connectTCP(nativeString(uri.host), uri.port, factory) - return factory.deferred.addCallback(self._cbFactoryInfo, factory) - - def _cbFactoryInfo(self, ignoredResult, factory): - self.assertEqual(factory.status, b'200') - self.assert_(factory.version.startswith(b'HTTP/')) - self.assertEqual(factory.message, b'OK') - self.assertEqual(factory.response_headers[b'content-length'][0], b'10') - - - def test_followRedirect(self): - """ - By default, L{client.getPage} follows redirects and returns the content - of the target resource. - """ - d = client.getPage(self.getURL("redirect")) - d.addCallback(self.assertEqual, b"0123456789") - return d - - - def test_noFollowRedirect(self): - """ - If C{followRedirect} is passed a false value, L{client.getPage} does not - follow redirects and returns a L{Deferred} which fails with - L{error.PageRedirect} when it encounters one. - """ - d = self.assertFailure( - client.getPage(self.getURL("redirect"), followRedirect=False), - error.PageRedirect) - d.addCallback(self._cbCheckLocation) - return d - - - def _cbCheckLocation(self, exc): - self.assertEqual(exc.location, b"/file") - - - def test_infiniteRedirection(self): - """ - When more than C{redirectLimit} HTTP redirects are encountered, the - page request fails with L{InfiniteRedirection}. - """ - def checkRedirectCount(*a): - self.assertEqual(f._redirectCount, 13) - self.assertEqual(self.infiniteRedirectResource.count, 13) - - f = client._makeGetterFactory( - self.getURL('infiniteRedirect'), - client.HTTPClientFactory, - redirectLimit=13) - d = self.assertFailure(f.deferred, error.InfiniteRedirection) - d.addCallback(checkRedirectCount) - return d - - - def test_isolatedFollowRedirect(self): - """ - C{client.HTTPPagerGetter} instances each obey the C{followRedirect} - value passed to the L{client.getPage} call which created them. - """ - d1 = client.getPage(self.getURL('redirect'), followRedirect=True) - d2 = client.getPage(self.getURL('redirect'), followRedirect=False) - - d = self.assertFailure(d2, error.PageRedirect - ).addCallback(lambda dummy: d1) - return d - - - def test_afterFoundGet(self): - """ - Enabling unsafe redirection behaviour overwrites the method of - redirected C{POST} requests with C{GET}. - """ - url = self.getURL('extendedRedirect?code=302') - f = client.HTTPClientFactory(url, followRedirect=True, method=b"POST") - self.assertFalse( - f.afterFoundGet, - "By default, afterFoundGet must be disabled") - - def gotPage(page): - self.assertEqual( - self.extendedRedirect.lastMethod, - b"GET", - "With afterFoundGet, the HTTP method must change to GET") - - d = client.getPage( - url, followRedirect=True, afterFoundGet=True, method=b"POST") - d.addCallback(gotPage) - return d - - - def test_downloadAfterFoundGet(self): - """ - Passing C{True} for C{afterFoundGet} to L{client.downloadPage} invokes - the same kind of redirect handling as passing that argument to - L{client.getPage} invokes. - """ - url = self.getURL('extendedRedirect?code=302') - - def gotPage(page): - self.assertEqual( - self.extendedRedirect.lastMethod, - b"GET", - "With afterFoundGet, the HTTP method must change to GET") - - d = client.downloadPage(url, "downloadTemp", - followRedirect=True, afterFoundGet=True, method="POST") - d.addCallback(gotPage) - return d - - - def test_afterFoundGetMakesOneRequest(self): - """ - When C{afterFoundGet} is C{True}, L{client.getPage} only issues one - request to the server when following the redirect. This is a regression - test, see #4760. - """ - def checkRedirectCount(*a): - self.assertEqual(self.afterFoundGetCounter.count, 1) - - url = self.getURL('afterFoundGetRedirect') - d = client.getPage( - url, followRedirect=True, afterFoundGet=True, method=b"POST") - d.addCallback(checkRedirectCount) - return d - - - def testPartial(self): - name = self.mktemp() - f = open(name, "wb") - f.write(b"abcd") - f.close() - - partialDownload = [(True, b"abcd456789"), - (True, b"abcd456789"), - (False, b"0123456789")] - - d = defer.succeed(None) - for (partial, expectedData) in partialDownload: - d.addCallback(self._cbRunPartial, name, partial) - d.addCallback(self._cbPartialTest, expectedData, name) - - return d - - testPartial.skip = "Cannot test until webserver can serve partial data properly" - - def _cbRunPartial(self, ignored, name, partial): - return client.downloadPage(self.getURL("file"), name, supportPartial=partial) - - def _cbPartialTest(self, ignored, expectedData, filename): - bytes = file(filename, "rb").read() - self.assertEqual(bytes, expectedData) - - - def test_downloadTimeout(self): - """ - If the timeout indicated by the C{timeout} parameter to - L{client.HTTPDownloader.__init__} elapses without the complete response - being received, the L{defer.Deferred} returned by - L{client.downloadPage} fires with a L{Failure} wrapping a - L{defer.TimeoutError}. - """ - self.cleanupServerConnections = 2 - # Verify the behavior if no bytes are ever written. - first = client.downloadPage( - self.getURL("wait"), - self.mktemp(), timeout=0.01) - - # Verify the behavior if some bytes are written but then the request - # never completes. - second = client.downloadPage( - self.getURL("write-then-wait"), - self.mktemp(), timeout=0.01) - - return defer.gatherResults([ - self.assertFailure(first, defer.TimeoutError), - self.assertFailure(second, defer.TimeoutError)]) - - - def test_downloadHeaders(self): - """ - After L{client.HTTPDownloader.deferred} fires, the - L{client.HTTPDownloader} instance's C{status} and C{response_headers} - attributes are populated with the values from the response. - """ - def checkHeaders(factory): - self.assertEqual(factory.status, b'200') - self.assertEqual(factory.response_headers[b'content-type'][0], b'text/html') - self.assertEqual(factory.response_headers[b'content-length'][0], b'10') - os.unlink(factory.fileName) - factory = client._makeGetterFactory( - self.getURL('file'), - client.HTTPDownloader, - fileOrName=self.mktemp()) - return factory.deferred.addCallback(lambda _: checkHeaders(factory)) - - - def test_downloadCookies(self): - """ - The C{cookies} dict passed to the L{client.HTTPDownloader} - initializer is used to populate the I{Cookie} header included in the - request sent to the server. - """ - output = self.mktemp() - factory = client._makeGetterFactory( - self.getURL('cookiemirror'), - client.HTTPDownloader, - fileOrName=output, - cookies={b'foo': b'bar'}) - def cbFinished(ignored): - self.assertEqual( - FilePath(output).getContent(), - "[('foo', 'bar')]") - factory.deferred.addCallback(cbFinished) - return factory.deferred - - - def test_downloadRedirectLimit(self): - """ - When more than C{redirectLimit} HTTP redirects are encountered, the - page request fails with L{InfiniteRedirection}. - """ - def checkRedirectCount(*a): - self.assertEqual(f._redirectCount, 7) - self.assertEqual(self.infiniteRedirectResource.count, 7) - - f = client._makeGetterFactory( - self.getURL('infiniteRedirect'), - client.HTTPDownloader, - fileOrName=self.mktemp(), - redirectLimit=7) - d = self.assertFailure(f.deferred, error.InfiniteRedirection) - d.addCallback(checkRedirectCount) - return d - - if _PY3: - for method in ( - test_downloadPageBrokenDownload, - test_downloadPageLogsFileCloseError, - testDownloadPage, - testDownloadPageError1, - testDownloadPageError2, - testDownloadPageError3, - testDownloadServerError, - test_downloadAfterFoundGet, - testPartial, - test_downloadTimeout, - test_downloadHeaders, - test_downloadCookies, - test_downloadRedirectLimit): - method.skip = _PY3DownloadSkip - del method - - - def test_setURL(self): - """ - L{client.HTTPClientFactory.setURL} alters the scheme, host, port and - path for absolute URLs. - """ - url = b'http://example.com' - f = client.HTTPClientFactory(url) - self.assertEqual( - (url, b'http', b'example.com', 80, b'/'), - (f.url, f.scheme, f.host, f.port, f.path)) - - - def test_setURLRemovesFragment(self): - """ - L{client.HTTPClientFactory.setURL} removes the fragment identifier from - the path component. - """ - f = client.HTTPClientFactory(b'http://example.com') - url = b'https://foo.com:8443/bar;123?a#frag' - f.setURL(url) - self.assertEqual( - (url, b'https', b'foo.com', 8443, b'/bar;123?a'), - (f.url, f.scheme, f.host, f.port, f.path)) - - - def test_setURLRelativePath(self): - """ - L{client.HTTPClientFactory.setURL} alters the path in a relative URL. - """ - f = client.HTTPClientFactory(b'http://example.com') - url = b'/hello' - f.setURL(url) - self.assertEqual( - (url, b'http', b'example.com', 80, b'/hello'), - (f.url, f.scheme, f.host, f.port, f.path)) - - - -class WebClientSSLTests(WebClientTests): - def _listen(self, site): - return reactor.listenSSL( - 0, site, - contextFactory=ssl.DefaultOpenSSLContextFactory( - serverPEMPath, serverPEMPath), - interface="127.0.0.1") - - def getURL(self, path): - return networkString("https://127.0.0.1:%d/%s" % (self.portno, path)) - - def testFactoryInfo(self): - url = self.getURL('file') - uri = client.URI.fromBytes(url) - factory = client.HTTPClientFactory(url) - reactor.connectSSL(nativeString(uri.host), uri.port, factory, - ssl.ClientContextFactory()) - # The base class defines _cbFactoryInfo correctly for this - return factory.deferred.addCallback(self._cbFactoryInfo, factory) - - - -class WebClientRedirectBetweenSSLandPlainTextTests(unittest.TestCase): - def getHTTPS(self, path): - return networkString("https://127.0.0.1:%d/%s" % (self.tlsPortno, path)) - - def getHTTP(self, path): - return networkString("http://127.0.0.1:%d/%s" % (self.plainPortno, path)) - - def setUp(self): - plainRoot = Data(b'not me', 'text/plain') - tlsRoot = Data(b'me neither', 'text/plain') - - plainSite = server.Site(plainRoot, timeout=None) - tlsSite = server.Site(tlsRoot, timeout=None) - - self.tlsPort = reactor.listenSSL( - 0, tlsSite, - contextFactory=ssl.DefaultOpenSSLContextFactory( - serverPEMPath, serverPEMPath), - interface="127.0.0.1") - self.plainPort = reactor.listenTCP(0, plainSite, interface="127.0.0.1") - - self.plainPortno = self.plainPort.getHost().port - self.tlsPortno = self.tlsPort.getHost().port - - plainRoot.putChild(b'one', Redirect(self.getHTTPS('two'))) - tlsRoot.putChild(b'two', Redirect(self.getHTTP('three'))) - plainRoot.putChild(b'three', Redirect(self.getHTTPS('four'))) - tlsRoot.putChild(b'four', Data(b'FOUND IT!', 'text/plain')) - - def tearDown(self): - ds = list( - map(defer.maybeDeferred, - [self.plainPort.stopListening, self.tlsPort.stopListening])) - return defer.gatherResults(ds) - - def testHoppingAround(self): - return client.getPage(self.getHTTP("one") - ).addCallback(self.assertEqual, b"FOUND IT!" - ) - - -class CookieTests(unittest.TestCase): - def _listen(self, site): - return reactor.listenTCP(0, site, interface="127.0.0.1") - - def setUp(self): - root = Data(b'El toro!', 'text/plain') - root.putChild(b"cookiemirror", CookieMirrorResource()) - root.putChild(b"rawcookiemirror", RawCookieMirrorResource()) - site = server.Site(root, timeout=None) - self.port = self._listen(site) - self.portno = self.port.getHost().port - - def tearDown(self): - return self.port.stopListening() - - def getHTTP(self, path): - return networkString("http://127.0.0.1:%d/%s" % (self.portno, path)) - - def testNoCookies(self): - return client.getPage(self.getHTTP("cookiemirror") - ).addCallback(self.assertEqual, b"[]" - ) - - def testSomeCookies(self): - cookies = {b'foo': b'bar', b'baz': b'quux'} - return client.getPage(self.getHTTP("cookiemirror"), cookies=cookies - ).addCallback(self.assertEqual, b"[('baz', 'quux'), ('foo', 'bar')]" - ) - - def testRawNoCookies(self): - return client.getPage(self.getHTTP("rawcookiemirror") - ).addCallback(self.assertEqual, b"None" - ) - - def testRawSomeCookies(self): - cookies = {b'foo': b'bar', b'baz': b'quux'} - return client.getPage(self.getHTTP("rawcookiemirror"), cookies=cookies - ).addCallback(self.assertIn, - (b"'foo=bar; baz=quux'", b"'baz=quux; foo=bar'") - ) - - def testCookieHeaderParsing(self): - factory = client.HTTPClientFactory(b'http://foo.example.com/') - proto = factory.buildProtocol('127.42.42.42') - transport = StringTransport() - proto.makeConnection(transport) - for line in [ - b'200 Ok', - b'Squash: yes', - b'Hands: stolen', - b'Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT', - b'Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/', - b'Set-Cookie: SHIPPING=FEDEX; path=/foo', - b'', - b'body', - b'more body', - ]: - proto.dataReceived(line + b'\r\n') - self.assertEqual(transport.value(), - b'GET / HTTP/1.0\r\n' - b'Host: foo.example.com\r\n' - b'User-Agent: Twisted PageGetter\r\n' - b'\r\n') - self.assertEqual(factory.cookies, - { - b'CUSTOMER': b'WILE_E_COYOTE', - b'PART_NUMBER': b'ROCKET_LAUNCHER_0001', - b'SHIPPING': b'FEDEX', - }) - - - -class HostHeaderTests(unittest.TestCase): - """ - Test that L{HTTPClientFactory} includes the port in the host header - if needed. - """ - - def _getHost(self, bytes): - """ - Retrieve the value of the I{Host} header from the serialized - request given by C{bytes}. - """ - for line in bytes.split(b'\r\n'): - try: - name, value = line.split(b':', 1) - if name.strip().lower() == b'host': - return value.strip() - except ValueError: - pass - - - def test_HTTPDefaultPort(self): - """ - No port should be included in the host header when connecting to the - default HTTP port. - """ - factory = client.HTTPClientFactory(b'http://foo.example.com/') - proto = factory.buildProtocol(b'127.42.42.42') - proto.makeConnection(StringTransport()) - self.assertEqual(self._getHost(proto.transport.value()), - b'foo.example.com') - - - def test_HTTPPort80(self): - """ - No port should be included in the host header when connecting to the - default HTTP port even if it is in the URL. - """ - factory = client.HTTPClientFactory(b'http://foo.example.com:80/') - proto = factory.buildProtocol('127.42.42.42') - proto.makeConnection(StringTransport()) - self.assertEqual(self._getHost(proto.transport.value()), - b'foo.example.com') - - - def test_HTTPNotPort80(self): - """ - The port should be included in the host header when connecting to the - a non default HTTP port. - """ - factory = client.HTTPClientFactory(b'http://foo.example.com:8080/') - proto = factory.buildProtocol('127.42.42.42') - proto.makeConnection(StringTransport()) - self.assertEqual(self._getHost(proto.transport.value()), - b'foo.example.com:8080') - - - def test_HTTPSDefaultPort(self): - """ - No port should be included in the host header when connecting to the - default HTTPS port. - """ - factory = client.HTTPClientFactory(b'https://foo.example.com/') - proto = factory.buildProtocol('127.42.42.42') - proto.makeConnection(StringTransport()) - self.assertEqual(self._getHost(proto.transport.value()), - b'foo.example.com') - - - def test_HTTPSPort443(self): - """ - No port should be included in the host header when connecting to the - default HTTPS port even if it is in the URL. - """ - factory = client.HTTPClientFactory(b'https://foo.example.com:443/') - proto = factory.buildProtocol('127.42.42.42') - proto.makeConnection(StringTransport()) - self.assertEqual(self._getHost(proto.transport.value()), - b'foo.example.com') - - - def test_HTTPSNotPort443(self): - """ - The port should be included in the host header when connecting to the - a non default HTTPS port. - """ - factory = client.HTTPClientFactory(b'http://foo.example.com:8080/') - proto = factory.buildProtocol('127.42.42.42') - proto.makeConnection(StringTransport()) - self.assertEqual(self._getHost(proto.transport.value()), - b'foo.example.com:8080') - - -if ssl is None or not hasattr(ssl, 'DefaultOpenSSLContextFactory'): - for case in [WebClientSSLTests, WebClientRedirectBetweenSSLandPlainTextTests]: - case.skip = "OpenSSL not present" - -if not interfaces.IReactorSSL(reactor, None): - for case in [WebClientSSLTests, WebClientRedirectBetweenSSLandPlainTextTests]: - case.skip = "Reactor doesn't support SSL" - - - -class URITests(unittest.TestCase): - """ - Tests for L{twisted.web.client.URI}. - """ - def assertURIEquals(self, uri, scheme, netloc, host, port, path, - params=b'', query=b'', fragment=b''): - """ - Assert that all of a L{client.URI}'s components match the expected - values. - - @param uri: U{client.URI} instance whose attributes will be checked - for equality. - - @type scheme: L{bytes} - @param scheme: URI scheme specifier. - - @type netloc: L{bytes} - @param netloc: Network location component. - - @type host: L{bytes} - @param host: Host name. - - @type port: L{int} - @param port: Port number. - - @type path: L{bytes} - @param path: Hierarchical path. - - @type params: L{bytes} - @param params: Parameters for last path segment, defaults to C{b''}. - - @type query: L{bytes} - @param query: Query string, defaults to C{b''}. - - @type fragment: L{bytes} - @param fragment: Fragment identifier, defaults to C{b''}. - """ - self.assertEqual( - (scheme, netloc, host, port, path, params, query, fragment), - (uri.scheme, uri.netloc, uri.host, uri.port, uri.path, uri.params, - uri.query, uri.fragment)) - - - def test_parseDefaultPort(self): - """ - L{client.URI.fromBytes} by default assumes port 80 for the I{http} - scheme and 443 for the I{https} scheme. - """ - uri = client.URI.fromBytes(b'http://example.com') - self.assertEqual(80, uri.port) - # Weird (but commonly accepted) structure uses default port. - uri = client.URI.fromBytes(b'http://example.com:') - self.assertEqual(80, uri.port) - uri = client.URI.fromBytes(b'https://example.com') - self.assertEqual(443, uri.port) - - - def test_parseCustomDefaultPort(self): - """ - L{client.URI.fromBytes} accepts a C{defaultPort} parameter that - overrides the normal default port logic. - """ - uri = client.URI.fromBytes(b'http://example.com', defaultPort=5144) - self.assertEqual(5144, uri.port) - uri = client.URI.fromBytes(b'https://example.com', defaultPort=5144) - self.assertEqual(5144, uri.port) - - - def test_netlocHostPort(self): - """ - Parsing a I{URI} splits the network location component into I{host} and - I{port}. - """ - uri = client.URI.fromBytes(b'http://example.com:5144') - self.assertEqual(5144, uri.port) - self.assertEqual(b'example.com', uri.host) - self.assertEqual(b'example.com:5144', uri.netloc) - - # Spaces in the hostname are trimmed, the default path is /. - uri = client.URI.fromBytes(b'http://example.com ') - self.assertEqual(b'example.com', uri.netloc) - - - def test_path(self): - """ - Parse the path from a I{URI}. - """ - uri = b'http://example.com/foo/bar' - parsed = client.URI.fromBytes(uri) - self.assertURIEquals( - parsed, - scheme=b'http', - netloc=b'example.com', - host=b'example.com', - port=80, - path=b'/foo/bar') - self.assertEqual(uri, parsed.toBytes()) - - - def test_noPath(self): - """ - The path of a I{URI} that has no path is the empty string. - """ - uri = b'http://example.com' - parsed = client.URI.fromBytes(uri) - self.assertURIEquals( - parsed, - scheme=b'http', - netloc=b'example.com', - host=b'example.com', - port=80, - path=b'') - self.assertEqual(uri, parsed.toBytes()) - - - def test_emptyPath(self): - """ - The path of a I{URI} with an empty path is C{b'/'}. - """ - uri = b'http://example.com/' - self.assertURIEquals( - client.URI.fromBytes(uri), - scheme=b'http', - netloc=b'example.com', - host=b'example.com', - port=80, - path=b'/') - - - def test_param(self): - """ - Parse I{URI} parameters from a I{URI}. - """ - uri = b'http://example.com/foo/bar;param' - parsed = client.URI.fromBytes(uri) - self.assertURIEquals( - parsed, - scheme=b'http', - netloc=b'example.com', - host=b'example.com', - port=80, - path=b'/foo/bar', - params=b'param') - self.assertEqual(uri, parsed.toBytes()) - - - def test_query(self): - """ - Parse the query string from a I{URI}. - """ - uri = b'http://example.com/foo/bar;param?a=1&b=2' - parsed = client.URI.fromBytes(uri) - self.assertURIEquals( - parsed, - scheme=b'http', - netloc=b'example.com', - host=b'example.com', - port=80, - path=b'/foo/bar', - params=b'param', - query=b'a=1&b=2') - self.assertEqual(uri, parsed.toBytes()) - - - def test_fragment(self): - """ - Parse the fragment identifier from a I{URI}. - """ - uri = b'http://example.com/foo/bar;param?a=1&b=2#frag' - parsed = client.URI.fromBytes(uri) - self.assertURIEquals( - parsed, - scheme=b'http', - netloc=b'example.com', - host=b'example.com', - port=80, - path=b'/foo/bar', - params=b'param', - query=b'a=1&b=2', - fragment=b'frag') - self.assertEqual(uri, parsed.toBytes()) - - - def test_originForm(self): - """ - L{client.URI.originForm} produces an absolute I{URI} path including - the I{URI} path. - """ - uri = client.URI.fromBytes(b'http://example.com/foo') - self.assertEqual(b'/foo', uri.originForm) - - - def test_originFormComplex(self): - """ - L{client.URI.originForm} produces an absolute I{URI} path including - the I{URI} path, parameters and query string but excludes the fragment - identifier. - """ - uri = client.URI.fromBytes(b'http://example.com/foo;param?a=1#frag') - self.assertEqual(b'/foo;param?a=1', uri.originForm) - - - def test_originFormNoPath(self): - """ - L{client.URI.originForm} produces a path of C{b'/'} when the I{URI} - specifies no path. - """ - uri = client.URI.fromBytes(b'http://example.com') - self.assertEqual(b'/', uri.originForm) - - - def test_originFormEmptyPath(self): - """ - L{client.URI.originForm} produces a path of C{b'/'} when the I{URI} - specifies an empty path. - """ - uri = client.URI.fromBytes(b'http://example.com/') - self.assertEqual(b'/', uri.originForm) - - - def test_externalUnicodeInterference(self): - """ - L{client.URI.fromBytes} parses the scheme, host, and path elements - into L{bytes}, even when passed an URL which has previously been passed - to L{urlparse} as a L{unicode} string. - """ - goodInput = b'http://example.com/path' - badInput = goodInput.decode('ascii') - urlparse(badInput) - uri = client.URI.fromBytes(goodInput) - self.assertIsInstance(uri.scheme, bytes) - self.assertIsInstance(uri.host, bytes) - self.assertIsInstance(uri.path, bytes) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_wsgi.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_wsgi.py deleted file mode 100644 index 4e902e5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_wsgi.py +++ /dev/null @@ -1,1571 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.wsgi}. -""" - -__metaclass__ = type - -from sys import exc_info -from urllib import quote -from thread import get_ident -import StringIO, cStringIO, tempfile - -from zope.interface.verify import verifyObject - -from twisted.python.log import addObserver, removeObserver, err -from twisted.python.failure import Failure -from twisted.python.threadpool import ThreadPool -from twisted.internet.defer import Deferred, gatherResults -from twisted.internet import reactor -from twisted.internet.error import ConnectionLost -from twisted.trial.unittest import TestCase -from twisted.web import http -from twisted.web.resource import IResource, Resource -from twisted.web.server import Request, Site, version -from twisted.web.wsgi import WSGIResource -from twisted.web.test.test_web import DummyChannel - - -class SynchronousThreadPool: - """ - A single-threaded implementation of part of the L{ThreadPool} interface. - This implementation calls functions synchronously rather than running - them in a thread pool. It is used to make the tests which are not - directly for thread-related behavior deterministic. - """ - def callInThread(self, f, *a, **kw): - """ - Call C{f(*a, **kw)} in this thread rather than scheduling it to be - called in a thread. - """ - try: - f(*a, **kw) - except: - # callInThread doesn't let exceptions propagate to the caller. - # None is always returned and any exception raised gets logged - # later on. - err(None, "Callable passed to SynchronousThreadPool.callInThread failed") - - - -class SynchronousReactorThreads: - """ - A single-threaded implementation of part of the L{IReactorThreads} - interface. This implementation assumes that it will only be invoked - from the reactor thread, so it calls functions synchronously rather than - trying to schedule them to run in the reactor thread. It is used in - conjunction with L{SynchronousThreadPool} to make the tests which are - not directly for thread-related behavior deterministic. - """ - def callFromThread(self, f, *a, **kw): - """ - Call C{f(*a, **kw)} in this thread which should also be the reactor - thread. - """ - f(*a, **kw) - - - -class WSGIResourceTests(TestCase): - def setUp(self): - """ - Create a L{WSGIResource} with synchronous threading objects and a no-op - application object. This is useful for testing certain things about - the resource implementation which are unrelated to WSGI. - """ - self.resource = WSGIResource( - SynchronousReactorThreads(), SynchronousThreadPool(), - lambda environ, startResponse: None) - - - def test_interfaces(self): - """ - L{WSGIResource} implements L{IResource} and stops resource traversal. - """ - verifyObject(IResource, self.resource) - self.assertTrue(self.resource.isLeaf) - - - def test_unsupported(self): - """ - A L{WSGIResource} cannot have L{IResource} children. Its - C{getChildWithDefault} and C{putChild} methods raise L{RuntimeError}. - """ - self.assertRaises( - RuntimeError, - self.resource.getChildWithDefault, - "foo", Request(DummyChannel(), False)) - self.assertRaises( - RuntimeError, - self.resource.putChild, - "foo", Resource()) - - -class WSGITestsMixin: - """ - @ivar channelFactory: A no-argument callable which will be invoked to - create a new HTTP channel to associate with request objects. - """ - channelFactory = DummyChannel - - def setUp(self): - self.threadpool = SynchronousThreadPool() - self.reactor = SynchronousReactorThreads() - - - def lowLevelRender( - self, requestFactory, applicationFactory, channelFactory, method, - version, resourceSegments, requestSegments, query=None, headers=[], - body=None, safe=''): - """ - @param method: A C{str} giving the request method to use. - - @param version: A C{str} like C{'1.1'} giving the request version. - - @param resourceSegments: A C{list} of unencoded path segments which - specifies the location in the resource hierarchy at which the - L{WSGIResource} will be placed, eg C{['']} for I{/}, C{['foo', - 'bar', '']} for I{/foo/bar/}, etc. - - @param requestSegments: A C{list} of unencoded path segments giving the - request URI. - - @param query: A C{list} of two-tuples of C{str} giving unencoded query - argument keys and values. - - @param headers: A C{list} of two-tuples of C{str} giving request header - names and corresponding values. - - @param safe: A C{str} giving the bytes which are to be considered - I{safe} for inclusion in the request URI and not quoted. - - @return: A L{Deferred} which will be called back with a two-tuple of - the arguments passed which would be passed to the WSGI application - object for this configuration and request (ie, the environment and - start_response callable). - """ - root = WSGIResource( - self.reactor, self.threadpool, applicationFactory()) - resourceSegments.reverse() - for seg in resourceSegments: - tmp = Resource() - tmp.putChild(seg, root) - root = tmp - - channel = channelFactory() - channel.site = Site(root) - request = requestFactory(channel, False) - for k, v in headers: - request.requestHeaders.addRawHeader(k, v) - request.gotLength(0) - if body: - request.content.write(body) - request.content.seek(0) - uri = '/' + '/'.join([quote(seg, safe) for seg in requestSegments]) - if query is not None: - uri += '?' + '&'.join(['='.join([quote(k, safe), quote(v, safe)]) - for (k, v) in query]) - request.requestReceived(method, uri, 'HTTP/' + version) - return request - - - def render(self, *a, **kw): - result = Deferred() - def applicationFactory(): - def application(*args): - environ, startResponse = args - result.callback(args) - startResponse('200 OK', []) - return iter(()) - return application - self.lowLevelRender( - Request, applicationFactory, self.channelFactory, *a, **kw) - return result - - - def requestFactoryFactory(self, requestClass=Request): - d = Deferred() - def requestFactory(*a, **kw): - request = requestClass(*a, **kw) - # If notifyFinish is called after lowLevelRender returns, it won't - # do the right thing, because the request will have already - # finished. One might argue that this is a bug in - # Request.notifyFinish. - request.notifyFinish().chainDeferred(d) - return request - return d, requestFactory - - - def getContentFromResponse(self, response): - return response.split('\r\n\r\n', 1)[1] - - - -class EnvironTests(WSGITestsMixin, TestCase): - """ - Tests for the values in the C{environ} C{dict} passed to the application - object by L{twisted.web.wsgi.WSGIResource}. - """ - def environKeyEqual(self, key, value): - def assertEnvironKeyEqual((environ, startResponse)): - self.assertEqual(environ[key], value) - return assertEnvironKeyEqual - - - def test_environIsDict(self): - """ - L{WSGIResource} calls the application object with an C{environ} - parameter which is exactly of type C{dict}. - """ - d = self.render('GET', '1.1', [], ['']) - def cbRendered((environ, startResponse)): - self.assertIdentical(type(environ), dict) - d.addCallback(cbRendered) - return d - - - def test_requestMethod(self): - """ - The C{'REQUEST_METHOD'} key of the C{environ} C{dict} passed to the - application contains the HTTP method in the request (RFC 3875, section - 4.1.12). - """ - get = self.render('GET', '1.1', [], ['']) - get.addCallback(self.environKeyEqual('REQUEST_METHOD', 'GET')) - - # Also make sure a different request method shows up as a different - # value in the environ dict. - post = self.render('POST', '1.1', [], ['']) - post.addCallback(self.environKeyEqual('REQUEST_METHOD', 'POST')) - - return gatherResults([get, post]) - - - def test_scriptName(self): - """ - The C{'SCRIPT_NAME'} key of the C{environ} C{dict} passed to the - application contains the I{abs_path} (RFC 2396, section 3) to this - resource (RFC 3875, section 4.1.13). - """ - root = self.render('GET', '1.1', [], ['']) - root.addCallback(self.environKeyEqual('SCRIPT_NAME', '')) - - emptyChild = self.render('GET', '1.1', [''], ['']) - emptyChild.addCallback(self.environKeyEqual('SCRIPT_NAME', '/')) - - leaf = self.render('GET', '1.1', ['foo'], ['foo']) - leaf.addCallback(self.environKeyEqual('SCRIPT_NAME', '/foo')) - - container = self.render('GET', '1.1', ['foo', ''], ['foo', '']) - container.addCallback(self.environKeyEqual('SCRIPT_NAME', '/foo/')) - - internal = self.render('GET', '1.1', ['foo'], ['foo', 'bar']) - internal.addCallback(self.environKeyEqual('SCRIPT_NAME', '/foo')) - - unencoded = self.render( - 'GET', '1.1', ['foo', '/', 'bar\xff'], ['foo', '/', 'bar\xff']) - # The RFC says "(not URL-encoded)", even though that makes - # interpretation of SCRIPT_NAME ambiguous. - unencoded.addCallback( - self.environKeyEqual('SCRIPT_NAME', '/foo///bar\xff')) - - return gatherResults([ - root, emptyChild, leaf, container, internal, unencoded]) - - - def test_pathInfo(self): - """ - The C{'PATH_INFO'} key of the C{environ} C{dict} passed to the - application contains the suffix of the request URI path which is not - included in the value for the C{'SCRIPT_NAME'} key (RFC 3875, section - 4.1.5). - """ - assertKeyEmpty = self.environKeyEqual('PATH_INFO', '') - - root = self.render('GET', '1.1', [], ['']) - root.addCallback(self.environKeyEqual('PATH_INFO', '/')) - - emptyChild = self.render('GET', '1.1', [''], ['']) - emptyChild.addCallback(assertKeyEmpty) - - leaf = self.render('GET', '1.1', ['foo'], ['foo']) - leaf.addCallback(assertKeyEmpty) - - container = self.render('GET', '1.1', ['foo', ''], ['foo', '']) - container.addCallback(assertKeyEmpty) - - internalLeaf = self.render('GET', '1.1', ['foo'], ['foo', 'bar']) - internalLeaf.addCallback(self.environKeyEqual('PATH_INFO', '/bar')) - - internalContainer = self.render('GET', '1.1', ['foo'], ['foo', '']) - internalContainer.addCallback(self.environKeyEqual('PATH_INFO', '/')) - - unencoded = self.render('GET', '1.1', [], ['foo', '/', 'bar\xff']) - unencoded.addCallback( - self.environKeyEqual('PATH_INFO', '/foo///bar\xff')) - - return gatherResults([ - root, leaf, container, internalLeaf, - internalContainer, unencoded]) - - - def test_queryString(self): - """ - The C{'QUERY_STRING'} key of the C{environ} C{dict} passed to the - application contains the portion of the request URI after the first - I{?} (RFC 3875, section 4.1.7). - """ - missing = self.render('GET', '1.1', [], [''], None) - missing.addCallback(self.environKeyEqual('QUERY_STRING', '')) - - empty = self.render('GET', '1.1', [], [''], []) - empty.addCallback(self.environKeyEqual('QUERY_STRING', '')) - - present = self.render('GET', '1.1', [], [''], [('foo', 'bar')]) - present.addCallback(self.environKeyEqual('QUERY_STRING', 'foo=bar')) - - unencoded = self.render('GET', '1.1', [], [''], [('/', '/')]) - unencoded.addCallback(self.environKeyEqual('QUERY_STRING', '%2F=%2F')) - - # "?" is reserved in the <searchpart> portion of a URL. However, it - # seems to be a common mistake of clients to forget to quote it. So, - # make sure we handle that invalid case. - doubleQuestion = self.render( - 'GET', '1.1', [], [''], [('foo', '?bar')], safe='?') - doubleQuestion.addCallback( - self.environKeyEqual('QUERY_STRING', 'foo=?bar')) - - return gatherResults([ - missing, empty, present, unencoded, doubleQuestion]) - - - def test_contentType(self): - """ - The C{'CONTENT_TYPE'} key of the C{environ} C{dict} passed to the - application contains the value of the I{Content-Type} request header - (RFC 3875, section 4.1.3). - """ - missing = self.render('GET', '1.1', [], ['']) - missing.addCallback(self.environKeyEqual('CONTENT_TYPE', '')) - - present = self.render( - 'GET', '1.1', [], [''], None, [('content-type', 'x-foo/bar')]) - present.addCallback(self.environKeyEqual('CONTENT_TYPE', 'x-foo/bar')) - - return gatherResults([missing, present]) - - - def test_contentLength(self): - """ - The C{'CONTENT_LENGTH'} key of the C{environ} C{dict} passed to the - application contains the value of the I{Content-Length} request header - (RFC 3875, section 4.1.2). - """ - missing = self.render('GET', '1.1', [], ['']) - missing.addCallback(self.environKeyEqual('CONTENT_LENGTH', '')) - - present = self.render( - 'GET', '1.1', [], [''], None, [('content-length', '1234')]) - present.addCallback(self.environKeyEqual('CONTENT_LENGTH', '1234')) - - return gatherResults([missing, present]) - - - def test_serverName(self): - """ - The C{'SERVER_NAME'} key of the C{environ} C{dict} passed to the - application contains the best determination of the server hostname - possible, using either the value of the I{Host} header in the request - or the address the server is listening on if that header is not - present (RFC 3875, section 4.1.14). - """ - missing = self.render('GET', '1.1', [], ['']) - # 10.0.0.1 value comes from a bit far away - - # twisted.test.test_web.DummyChannel.transport.getHost().host - missing.addCallback(self.environKeyEqual('SERVER_NAME', '10.0.0.1')) - - present = self.render( - 'GET', '1.1', [], [''], None, [('host', 'example.org')]) - present.addCallback(self.environKeyEqual('SERVER_NAME', 'example.org')) - - return gatherResults([missing, present]) - - - def test_serverPort(self): - """ - The C{'SERVER_PORT'} key of the C{environ} C{dict} passed to the - application contains the port number of the server which received the - request (RFC 3875, section 4.1.15). - """ - portNumber = 12354 - def makeChannel(): - channel = DummyChannel() - channel.transport = DummyChannel.TCP() - channel.transport.port = portNumber - return channel - self.channelFactory = makeChannel - - d = self.render('GET', '1.1', [], ['']) - d.addCallback(self.environKeyEqual('SERVER_PORT', str(portNumber))) - return d - - - def test_serverProtocol(self): - """ - The C{'SERVER_PROTOCOL'} key of the C{environ} C{dict} passed to the - application contains the HTTP version number received in the request - (RFC 3875, section 4.1.16). - """ - old = self.render('GET', '1.0', [], ['']) - old.addCallback(self.environKeyEqual('SERVER_PROTOCOL', 'HTTP/1.0')) - - new = self.render('GET', '1.1', [], ['']) - new.addCallback(self.environKeyEqual('SERVER_PROTOCOL', 'HTTP/1.1')) - - return gatherResults([old, new]) - - - def test_remoteAddr(self): - """ - The C{'REMOTE_ADDR'} key of the C{environ} C{dict} passed to the - application contains the address of the client making the request. - """ - d = self.render('GET', '1.1', [], ['']) - d.addCallback(self.environKeyEqual('REMOTE_ADDR', '192.168.1.1')) - - return d - - def test_headers(self): - """ - HTTP request headers are copied into the C{environ} C{dict} passed to - the application with a C{HTTP_} prefix added to their names. - """ - singleValue = self.render( - 'GET', '1.1', [], [''], None, [('foo', 'bar'), ('baz', 'quux')]) - def cbRendered((environ, startResponse)): - self.assertEqual(environ['HTTP_FOO'], 'bar') - self.assertEqual(environ['HTTP_BAZ'], 'quux') - singleValue.addCallback(cbRendered) - - multiValue = self.render( - 'GET', '1.1', [], [''], None, [('foo', 'bar'), ('foo', 'baz')]) - multiValue.addCallback(self.environKeyEqual('HTTP_FOO', 'bar,baz')) - - withHyphen = self.render( - 'GET', '1.1', [], [''], None, [('foo-bar', 'baz')]) - withHyphen.addCallback(self.environKeyEqual('HTTP_FOO_BAR', 'baz')) - - multiLine = self.render( - 'GET', '1.1', [], [''], None, [('foo', 'bar\n\tbaz')]) - multiLine.addCallback(self.environKeyEqual('HTTP_FOO', 'bar \tbaz')) - - return gatherResults([singleValue, multiValue, withHyphen, multiLine]) - - - def test_wsgiVersion(self): - """ - The C{'wsgi.version'} key of the C{environ} C{dict} passed to the - application has the value C{(1, 0)} indicating that this is a WSGI 1.0 - container. - """ - versionDeferred = self.render('GET', '1.1', [], ['']) - versionDeferred.addCallback(self.environKeyEqual('wsgi.version', (1, 0))) - return versionDeferred - - - def test_wsgiRunOnce(self): - """ - The C{'wsgi.run_once'} key of the C{environ} C{dict} passed to the - application is set to C{False}. - """ - once = self.render('GET', '1.1', [], ['']) - once.addCallback(self.environKeyEqual('wsgi.run_once', False)) - return once - - - def test_wsgiMultithread(self): - """ - The C{'wsgi.multithread'} key of the C{environ} C{dict} passed to the - application is set to C{True}. - """ - thread = self.render('GET', '1.1', [], ['']) - thread.addCallback(self.environKeyEqual('wsgi.multithread', True)) - return thread - - - def test_wsgiMultiprocess(self): - """ - The C{'wsgi.multiprocess'} key of the C{environ} C{dict} passed to the - application is set to C{False}. - """ - process = self.render('GET', '1.1', [], ['']) - process.addCallback(self.environKeyEqual('wsgi.multiprocess', False)) - return process - - - def test_wsgiURLScheme(self): - """ - The C{'wsgi.url_scheme'} key of the C{environ} C{dict} passed to the - application has the request URL scheme. - """ - # XXX Does this need to be different if the request is for an absolute - # URL? - def channelFactory(): - channel = DummyChannel() - channel.transport = DummyChannel.SSL() - return channel - - self.channelFactory = DummyChannel - httpDeferred = self.render('GET', '1.1', [], ['']) - httpDeferred.addCallback(self.environKeyEqual('wsgi.url_scheme', 'http')) - - self.channelFactory = channelFactory - httpsDeferred = self.render('GET', '1.1', [], ['']) - httpsDeferred.addCallback(self.environKeyEqual('wsgi.url_scheme', 'https')) - - return gatherResults([httpDeferred, httpsDeferred]) - - - def test_wsgiErrors(self): - """ - The C{'wsgi.errors'} key of the C{environ} C{dict} passed to the - application is a file-like object (as defined in the U{Input and Errors - Streams<http://www.python.org/dev/peps/pep-0333/#input-and-error-streams>} - section of PEP 333) which converts bytes written to it into events for - the logging system. - """ - events = [] - addObserver(events.append) - self.addCleanup(removeObserver, events.append) - - errors = self.render('GET', '1.1', [], ['']) - def cbErrors((environ, startApplication)): - errors = environ['wsgi.errors'] - errors.write('some message\n') - errors.writelines(['another\nmessage\n']) - errors.flush() - self.assertEqual(events[0]['message'], ('some message\n',)) - self.assertEqual(events[0]['system'], 'wsgi') - self.assertTrue(events[0]['isError']) - self.assertEqual(events[1]['message'], ('another\nmessage\n',)) - self.assertEqual(events[1]['system'], 'wsgi') - self.assertTrue(events[1]['isError']) - self.assertEqual(len(events), 2) - errors.addCallback(cbErrors) - return errors - - -class InputStreamTestMixin(WSGITestsMixin): - """ - A mixin for L{TestCase} subclasses which defines a number of tests against - L{_InputStream}. The subclass is expected to create a file-like object to - be wrapped by an L{_InputStream} under test. - """ - def getFileType(self): - raise NotImplementedError( - "%s.getFile must be implemented" % (self.__class__.__name__,)) - - - def _renderAndReturnReaderResult(self, reader, content): - contentType = self.getFileType() - class CustomizedRequest(Request): - def gotLength(self, length): - # Always allocate a file of the specified type, instead of - # using the base behavior of selecting one depending on the - # length. - self.content = contentType() - - def appFactoryFactory(reader): - result = Deferred() - def applicationFactory(): - def application(*args): - environ, startResponse = args - result.callback(reader(environ['wsgi.input'])) - startResponse('200 OK', []) - return iter(()) - return application - return result, applicationFactory - d, appFactory = appFactoryFactory(reader) - self.lowLevelRender( - CustomizedRequest, appFactory, DummyChannel, - 'PUT', '1.1', [], [''], None, [], - content) - return d - - - def test_readAll(self): - """ - Calling L{_InputStream.read} with no arguments returns the entire input - stream. - """ - bytes = "some bytes are here" - d = self._renderAndReturnReaderResult(lambda input: input.read(), bytes) - d.addCallback(self.assertEqual, bytes) - return d - - - def test_readSome(self): - """ - Calling L{_InputStream.read} with an integer returns that many bytes - from the input stream, as long as it is less than or equal to the total - number of bytes available. - """ - bytes = "hello, world." - d = self._renderAndReturnReaderResult(lambda input: input.read(3), bytes) - d.addCallback(self.assertEqual, "hel") - return d - - - def test_readMoreThan(self): - """ - Calling L{_InputStream.read} with an integer that is greater than the - total number of bytes in the input stream returns all bytes in the - input stream. - """ - bytes = "some bytes are here" - d = self._renderAndReturnReaderResult( - lambda input: input.read(len(bytes) + 3), bytes) - d.addCallback(self.assertEqual, bytes) - return d - - - def test_readTwice(self): - """ - Calling L{_InputStream.read} a second time returns bytes starting from - the position after the last byte returned by the previous read. - """ - bytes = "some bytes, hello" - def read(input): - input.read(3) - return input.read() - d = self._renderAndReturnReaderResult(read, bytes) - d.addCallback(self.assertEqual, bytes[3:]) - return d - - - def test_readNone(self): - """ - Calling L{_InputStream.read} with C{None} as an argument returns all - bytes in the input stream. - """ - bytes = "the entire stream" - d = self._renderAndReturnReaderResult( - lambda input: input.read(None), bytes) - d.addCallback(self.assertEqual, bytes) - return d - - - def test_readNegative(self): - """ - Calling L{_InputStream.read} with a negative integer as an argument - returns all bytes in the input stream. - """ - bytes = "all of the input" - d = self._renderAndReturnReaderResult( - lambda input: input.read(-1), bytes) - d.addCallback(self.assertEqual, bytes) - return d - - - def test_readline(self): - """ - Calling L{_InputStream.readline} with no argument returns one line from - the input stream. - """ - bytes = "hello\nworld" - d = self._renderAndReturnReaderResult( - lambda input: input.readline(), bytes) - d.addCallback(self.assertEqual, "hello\n") - return d - - - def test_readlineSome(self): - """ - Calling L{_InputStream.readline} with an integer returns at most that - many bytes, even if it is not enough to make up a complete line. - - COMPATIBILITY NOTE: the size argument is excluded from the WSGI - specification, but is provided here anyhow, because useful libraries - such as python stdlib's cgi.py assume their input file-like-object - supports readline with a size argument. If you use it, be aware your - application may not be portable to other conformant WSGI servers. - """ - bytes = "goodbye\nworld" - d = self._renderAndReturnReaderResult( - lambda input: input.readline(3), bytes) - d.addCallback(self.assertEqual, "goo") - return d - - - def test_readlineMoreThan(self): - """ - Calling L{_InputStream.readline} with an integer which is greater than - the number of bytes in the next line returns only the next line. - """ - bytes = "some lines\nof text" - d = self._renderAndReturnReaderResult( - lambda input: input.readline(20), bytes) - d.addCallback(self.assertEqual, "some lines\n") - return d - - - def test_readlineTwice(self): - """ - Calling L{_InputStream.readline} a second time returns the line - following the line returned by the first call. - """ - bytes = "first line\nsecond line\nlast line" - def readline(input): - input.readline() - return input.readline() - d = self._renderAndReturnReaderResult(readline, bytes) - d.addCallback(self.assertEqual, "second line\n") - return d - - - def test_readlineNone(self): - """ - Calling L{_InputStream.readline} with C{None} as an argument returns - one line from the input stream. - """ - bytes = "this is one line\nthis is another line" - d = self._renderAndReturnReaderResult( - lambda input: input.readline(None), bytes) - d.addCallback(self.assertEqual, "this is one line\n") - return d - - - def test_readlineNegative(self): - """ - Calling L{_InputStream.readline} with a negative integer as an argument - returns one line from the input stream. - """ - bytes = "input stream line one\nline two" - d = self._renderAndReturnReaderResult( - lambda input: input.readline(-1), bytes) - d.addCallback(self.assertEqual, "input stream line one\n") - return d - - - def test_readlines(self): - """ - Calling L{_InputStream.readlines} with no arguments returns a list of - all lines from the input stream. - """ - bytes = "alice\nbob\ncarol" - d = self._renderAndReturnReaderResult( - lambda input: input.readlines(), bytes) - d.addCallback(self.assertEqual, ["alice\n", "bob\n", "carol"]) - return d - - - def test_readlinesSome(self): - """ - Calling L{_InputStream.readlines} with an integer as an argument - returns a list of lines from the input stream with the argument serving - as an approximate bound on the total number of bytes to read. - """ - bytes = "123\n456\n789\n0" - d = self._renderAndReturnReaderResult( - lambda input: input.readlines(5), bytes) - def cbLines(lines): - # Make sure we got enough lines to make 5 bytes. Anything beyond - # that is fine too. - self.assertEqual(lines[:2], ["123\n", "456\n"]) - d.addCallback(cbLines) - return d - - - def test_readlinesMoreThan(self): - """ - Calling L{_InputStream.readlines} with an integer which is greater than - the total number of bytes in the input stream returns a list of all - lines from the input. - """ - bytes = "one potato\ntwo potato\nthree potato" - d = self._renderAndReturnReaderResult( - lambda input: input.readlines(100), bytes) - d.addCallback( - self.assertEqual, - ["one potato\n", "two potato\n", "three potato"]) - return d - - - def test_readlinesAfterRead(self): - """ - Calling L{_InputStream.readlines} after a call to L{_InputStream.read} - returns lines starting at the byte after the last byte returned by the - C{read} call. - """ - bytes = "hello\nworld\nfoo" - def readlines(input): - input.read(7) - return input.readlines() - d = self._renderAndReturnReaderResult(readlines, bytes) - d.addCallback(self.assertEqual, ["orld\n", "foo"]) - return d - - - def test_readlinesNone(self): - """ - Calling L{_InputStream.readlines} with C{None} as an argument returns - all lines from the input. - """ - bytes = "one fish\ntwo fish\n" - d = self._renderAndReturnReaderResult( - lambda input: input.readlines(None), bytes) - d.addCallback(self.assertEqual, ["one fish\n", "two fish\n"]) - return d - - - def test_readlinesNegative(self): - """ - Calling L{_InputStream.readlines} with a negative integer as an - argument returns a list of all lines from the input. - """ - bytes = "red fish\nblue fish\n" - d = self._renderAndReturnReaderResult( - lambda input: input.readlines(-1), bytes) - d.addCallback(self.assertEqual, ["red fish\n", "blue fish\n"]) - return d - - - def test_iterable(self): - """ - Iterating over L{_InputStream} produces lines from the input stream. - """ - bytes = "green eggs\nand ham\n" - d = self._renderAndReturnReaderResult(lambda input: list(input), bytes) - d.addCallback(self.assertEqual, ["green eggs\n", "and ham\n"]) - return d - - - def test_iterableAfterRead(self): - """ - Iterating over L{_InputStream} after calling L{_InputStream.read} - produces lines from the input stream starting from the first byte after - the last byte returned by the C{read} call. - """ - bytes = "green eggs\nand ham\n" - def iterate(input): - input.read(3) - return list(input) - d = self._renderAndReturnReaderResult(iterate, bytes) - d.addCallback(self.assertEqual, ["en eggs\n", "and ham\n"]) - return d - - - -class InputStreamStringIOTests(InputStreamTestMixin, TestCase): - """ - Tests for L{_InputStream} when it is wrapped around a L{StringIO.StringIO}. - """ - def getFileType(self): - return StringIO.StringIO - - - -class InputStreamCStringIOTests(InputStreamTestMixin, TestCase): - """ - Tests for L{_InputStream} when it is wrapped around a - L{cStringIO.StringIO}. - """ - def getFileType(self): - return cStringIO.StringIO - - - -class InputStreamTemporaryFileTests(InputStreamTestMixin, TestCase): - """ - Tests for L{_InputStream} when it is wrapped around a L{tempfile.TemporaryFile}. - """ - def getFileType(self): - return tempfile.TemporaryFile - - - -class StartResponseTests(WSGITestsMixin, TestCase): - """ - Tests for the I{start_response} parameter passed to the application object - by L{WSGIResource}. - """ - def test_status(self): - """ - The response status passed to the I{start_response} callable is written - as the status of the response to the request. - """ - channel = DummyChannel() - - def applicationFactory(): - def application(environ, startResponse): - startResponse('107 Strange message', []) - return iter(()) - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertTrue( - channel.transport.written.getvalue().startswith( - 'HTTP/1.1 107 Strange message')) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def _headersTest(self, appHeaders, expectedHeaders): - """ - Verify that if the response headers given by C{appHeaders} are passed - to the I{start_response} callable, then the response header lines given - by C{expectedHeaders} plus I{Server} and I{Date} header lines are - included in the response. - """ - # Make the Date header value deterministic - self.patch(http, 'datetimeToString', lambda: 'Tuesday') - - channel = DummyChannel() - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', appHeaders) - return iter(()) - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - response = channel.transport.written.getvalue() - headers, rest = response.split('\r\n\r\n', 1) - headerLines = headers.split('\r\n')[1:] - headerLines.sort() - allExpectedHeaders = expectedHeaders + [ - 'Date: Tuesday', - 'Server: ' + version, - 'Transfer-Encoding: chunked'] - allExpectedHeaders.sort() - self.assertEqual(headerLines, allExpectedHeaders) - - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - return d - - - def test_headers(self): - """ - The headers passed to the I{start_response} callable are included in - the response as are the required I{Date} and I{Server} headers and the - necessary connection (hop to hop) header I{Transfer-Encoding}. - """ - return self._headersTest( - [('foo', 'bar'), ('baz', 'quux')], - ['Baz: quux', 'Foo: bar']) - - - def test_applicationProvidedContentType(self): - """ - If I{Content-Type} is included in the headers passed to the - I{start_response} callable, one I{Content-Type} header is included in - the response. - """ - return self._headersTest( - [('content-type', 'monkeys are great')], - ['Content-Type: monkeys are great']) - - - def test_applicationProvidedServerAndDate(self): - """ - If either I{Server} or I{Date} is included in the headers passed to the - I{start_response} callable, they are disregarded. - """ - return self._headersTest( - [('server', 'foo'), ('Server', 'foo'), - ('date', 'bar'), ('dATE', 'bar')], - []) - - - def test_delayedUntilReturn(self): - """ - Nothing is written in response to a request when the I{start_response} - callable is invoked. If the iterator returned by the application - object produces only empty strings, the response is written after the - last element is produced. - """ - channel = DummyChannel() - - intermediateValues = [] - def record(): - intermediateValues.append(channel.transport.written.getvalue()) - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', [('foo', 'bar'), ('baz', 'quux')]) - yield '' - record() - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertEqual(intermediateValues, ['']) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def test_delayedUntilContent(self): - """ - Nothing is written in response to a request when the I{start_response} - callable is invoked. Once a non-empty string has been produced by the - iterator returned by the application object, the response status and - headers are written. - """ - channel = DummyChannel() - - intermediateValues = [] - def record(): - intermediateValues.append(channel.transport.written.getvalue()) - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', [('foo', 'bar')]) - yield '' - record() - yield 'foo' - record() - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertFalse(intermediateValues[0]) - self.assertTrue(intermediateValues[1]) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def test_content(self): - """ - Content produced by the iterator returned by the application object is - written to the request as it is produced. - """ - channel = DummyChannel() - - intermediateValues = [] - def record(): - intermediateValues.append(channel.transport.written.getvalue()) - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', [('content-length', '6')]) - yield 'foo' - record() - yield 'bar' - record() - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertEqual( - self.getContentFromResponse(intermediateValues[0]), - 'foo') - self.assertEqual( - self.getContentFromResponse(intermediateValues[1]), - 'foobar') - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def test_multipleStartResponse(self): - """ - If the I{start_response} callable is invoked multiple times before a - data for the response body is produced, the values from the last call - are used. - """ - channel = DummyChannel() - - def applicationFactory(): - def application(environ, startResponse): - startResponse('100 Foo', []) - startResponse('200 Bar', []) - return iter(()) - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertTrue( - channel.transport.written.getvalue().startswith( - 'HTTP/1.1 200 Bar\r\n')) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def test_startResponseWithException(self): - """ - If the I{start_response} callable is invoked with a third positional - argument before the status and headers have been written to the - response, the status and headers become the newly supplied values. - """ - channel = DummyChannel() - - def applicationFactory(): - def application(environ, startResponse): - startResponse('100 Foo', [], (Exception, Exception("foo"), None)) - return iter(()) - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertTrue( - channel.transport.written.getvalue().startswith( - 'HTTP/1.1 100 Foo\r\n')) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def test_startResponseWithExceptionTooLate(self): - """ - If the I{start_response} callable is invoked with a third positional - argument after the status and headers have been written to the - response, the supplied I{exc_info} values are re-raised to the - application. - """ - channel = DummyChannel() - - class SomeException(Exception): - pass - - try: - raise SomeException() - except: - excInfo = exc_info() - - reraised = [] - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', []) - yield 'foo' - try: - startResponse('500 ERR', [], excInfo) - except: - reraised.append(exc_info()) - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertTrue( - channel.transport.written.getvalue().startswith( - 'HTTP/1.1 200 OK\r\n')) - self.assertEqual(reraised[0][0], excInfo[0]) - self.assertEqual(reraised[0][1], excInfo[1]) - self.assertEqual(reraised[0][2].tb_next, excInfo[2]) - - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def test_write(self): - """ - I{start_response} returns the I{write} callable which can be used to - write bytes to the response body without buffering. - """ - channel = DummyChannel() - - intermediateValues = [] - def record(): - intermediateValues.append(channel.transport.written.getvalue()) - - def applicationFactory(): - def application(environ, startResponse): - write = startResponse('100 Foo', [('content-length', '6')]) - write('foo') - record() - write('bar') - record() - return iter(()) - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertEqual( - self.getContentFromResponse(intermediateValues[0]), - 'foo') - self.assertEqual( - self.getContentFromResponse(intermediateValues[1]), - 'foobar') - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - -class ApplicationTests(WSGITestsMixin, TestCase): - """ - Tests for things which are done to the application object and the iterator - it returns. - """ - def enableThreads(self): - self.reactor = reactor - self.threadpool = ThreadPool() - self.threadpool.start() - self.addCleanup(self.threadpool.stop) - - - def test_close(self): - """ - If the application object returns an iterator which also has a I{close} - method, that method is called after iteration is complete. - """ - channel = DummyChannel() - - class Result: - def __init__(self): - self.open = True - - def __iter__(self): - for i in range(3): - if self.open: - yield str(i) - - def close(self): - self.open = False - - result = Result() - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', [('content-length', '3')]) - return result - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertEqual( - self.getContentFromResponse( - channel.transport.written.getvalue()), - '012') - self.assertFalse(result.open) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], ['']) - - return d - - - def test_applicationCalledInThread(self): - """ - The application object is invoked and iterated in a thread which is not - the reactor thread. - """ - self.enableThreads() - invoked = [] - - def applicationFactory(): - def application(environ, startResponse): - def result(): - for i in range(3): - invoked.append(get_ident()) - yield str(i) - invoked.append(get_ident()) - startResponse('200 OK', [('content-length', '3')]) - return result() - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - self.assertNotIn(get_ident(), invoked) - self.assertEqual(len(set(invoked)), 1) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - DummyChannel, 'GET', '1.1', [], ['']) - - return d - - - def test_writeCalledFromThread(self): - """ - The I{write} callable returned by I{start_response} calls the request's - C{write} method in the reactor thread. - """ - self.enableThreads() - invoked = [] - - class ThreadVerifier(Request): - def write(self, bytes): - invoked.append(get_ident()) - return Request.write(self, bytes) - - def applicationFactory(): - def application(environ, startResponse): - write = startResponse('200 OK', []) - write('foo') - return iter(()) - return application - - d, requestFactory = self.requestFactoryFactory(ThreadVerifier) - def cbRendered(ignored): - self.assertEqual(set(invoked), set([get_ident()])) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, DummyChannel, - 'GET', '1.1', [], ['']) - - return d - - - def test_iteratedValuesWrittenFromThread(self): - """ - Strings produced by the iterator returned by the application object are - written to the request in the reactor thread. - """ - self.enableThreads() - invoked = [] - - class ThreadVerifier(Request): - def write(self, bytes): - invoked.append(get_ident()) - return Request.write(self, bytes) - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', []) - yield 'foo' - return application - - d, requestFactory = self.requestFactoryFactory(ThreadVerifier) - def cbRendered(ignored): - self.assertEqual(set(invoked), set([get_ident()])) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, DummyChannel, - 'GET', '1.1', [], ['']) - - return d - - - def test_statusWrittenFromThread(self): - """ - The response status is set on the request object in the reactor thread. - """ - self.enableThreads() - invoked = [] - - class ThreadVerifier(Request): - def setResponseCode(self, code, message): - invoked.append(get_ident()) - return Request.setResponseCode(self, code, message) - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', []) - return iter(()) - return application - - d, requestFactory = self.requestFactoryFactory(ThreadVerifier) - def cbRendered(ignored): - self.assertEqual(set(invoked), set([get_ident()])) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, DummyChannel, - 'GET', '1.1', [], ['']) - - return d - - - def test_connectionClosedDuringIteration(self): - """ - If the request connection is lost while the application object is being - iterated, iteration is stopped. - """ - class UnreliableConnection(Request): - """ - This is a request which pretends its connection is lost immediately - after the first write is done to it. - """ - def write(self, bytes): - self.connectionLost(Failure(ConnectionLost("No more connection"))) - - self.badIter = False - def appIter(): - yield "foo" - self.badIter = True - raise Exception("Should not have gotten here") - - def applicationFactory(): - def application(environ, startResponse): - startResponse('200 OK', []) - return appIter() - return application - - d, requestFactory = self.requestFactoryFactory(UnreliableConnection) - def cbRendered(ignored): - self.assertFalse(self.badIter, "Should not have resumed iteration") - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, DummyChannel, - 'GET', '1.1', [], ['']) - - return self.assertFailure(d, ConnectionLost) - - - def _internalServerErrorTest(self, application): - channel = DummyChannel() - - def applicationFactory(): - return application - - d, requestFactory = self.requestFactoryFactory() - def cbRendered(ignored): - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - - self.assertTrue( - channel.transport.written.getvalue().startswith( - 'HTTP/1.1 500 Internal Server Error')) - d.addCallback(cbRendered) - - self.lowLevelRender( - requestFactory, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - return d - - - def test_applicationExceptionBeforeStartResponse(self): - """ - If the application raises an exception before calling I{start_response} - then the response status is I{500} and the exception is logged. - """ - def application(environ, startResponse): - raise RuntimeError("This application had some error.") - return self._internalServerErrorTest(application) - - - def test_applicationExceptionAfterStartResponse(self): - """ - If the application calls I{start_response} but then raises an exception - before any data is written to the response then the response status is - I{500} and the exception is logged. - """ - def application(environ, startResponse): - startResponse('200 OK', []) - raise RuntimeError("This application had some error.") - return self._internalServerErrorTest(application) - - - def _connectionClosedTest(self, application, responseContent): - channel = DummyChannel() - - def applicationFactory(): - return application - - d, requestFactory = self.requestFactoryFactory() - - # Capture the request so we can disconnect it later on. - requests = [] - def requestFactoryWrapper(*a, **kw): - requests.append(requestFactory(*a, **kw)) - return requests[-1] - - def ebRendered(ignored): - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - - response = channel.transport.written.getvalue() - self.assertTrue(response.startswith('HTTP/1.1 200 OK')) - # Chunked transfer-encoding makes this a little messy. - self.assertIn(responseContent, response) - d.addErrback(ebRendered) - - self.lowLevelRender( - requestFactoryWrapper, applicationFactory, - lambda: channel, 'GET', '1.1', [], [''], None, []) - - # By now the connection should be closed. - self.assertTrue(channel.transport.disconnected) - # Give it a little push to go the rest of the way. - requests[0].connectionLost(Failure(ConnectionLost("All gone"))) - - return d - - - def test_applicationExceptionAfterWrite(self): - """ - If the application raises an exception after the response status has - already been sent then the connection is closed and the exception is - logged. - """ - responseContent = ( - 'Some bytes, triggering the server to start sending the response') - - def application(environ, startResponse): - startResponse('200 OK', []) - yield responseContent - raise RuntimeError("This application had some error.") - return self._connectionClosedTest(application, responseContent) - - - def test_applicationCloseException(self): - """ - If the application returns a closeable iterator and the C{close} method - raises an exception when called then the connection is still closed and - the exception is logged. - """ - responseContent = 'foo' - - class Application(object): - def __init__(self, environ, startResponse): - startResponse('200 OK', []) - - def __iter__(self): - yield responseContent - - def close(self): - raise RuntimeError("This application had some error.") - - return self._connectionClosedTest(Application, responseContent) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_xml.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_xml.py deleted file mode 100644 index fea47be..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_xml.py +++ /dev/null @@ -1,1081 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xml -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Some fairly inadequate testcases for Twisted XML support. -""" - -from twisted.trial.unittest import TestCase -from twisted.web import sux -from twisted.web import microdom -from twisted.web import domhelpers - - -class Sux0r(sux.XMLParser): - def __init__(self): - self.tokens = [] - - def getTagStarts(self): - return [token for token in self.tokens if token[0] == 'start'] - - def gotTagStart(self, name, attrs): - self.tokens.append(("start", name, attrs)) - - def gotText(self, text): - self.tokens.append(("text", text)) - -class SUXTests(TestCase): - - def testBork(self): - s = "<bork><bork><bork>" - ms = Sux0r() - ms.connectionMade() - ms.dataReceived(s) - self.assertEqual(len(ms.getTagStarts()),3) - - -class MicroDOMTests(TestCase): - - def test_leadingTextDropping(self): - """ - Make sure that if there's no top-level node lenient-mode won't - drop leading text that's outside of any elements. - """ - s = "Hi orders! <br>Well. <br>" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEqual(d.firstChild().toxml(), - '<html>Hi orders! <br />Well. <br /></html>') - - def test_trailingTextDropping(self): - """ - Ensure that no *trailing* text in a mal-formed - no-top-level-element document(s) will not be dropped. - """ - s = "<br>Hi orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEqual(d.firstChild().toxml(), - '<html><br />Hi orders!</html>') - - - def test_noTags(self): - """ - A string with nothing that looks like a tag at all should just - be parsed as body text. - """ - s = "Hi orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEqual(d.firstChild().toxml(), - "<html>Hi orders!</html>") - - - def test_surroundingCrap(self): - """ - If a document is surrounded by non-xml text, the text should - be remain in the XML. - """ - s = "Hi<br> orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEqual(d.firstChild().toxml(), - "<html>Hi<br /> orders!</html>") - - - def testCaseSensitiveSoonCloser(self): - s = """ - <HTML><BODY> - <P ALIGN="CENTER"> - <A HREF="http://www.apache.org/"><IMG SRC="/icons/apache_pb.gif"></A> - </P> - - <P> - This is an insane set of text nodes that should NOT be gathered under - the A tag above. - </P> - </BODY></HTML> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - l = domhelpers.findNodesNamed(d.documentElement, 'a') - n = domhelpers.gatherTextNodes(l[0],1).replace('&nbsp;',' ') - self.assertEqual(n.find('insane'), -1) - - - def test_lenientParenting(self): - """ - Test that C{parentNode} attributes are set to meaningful values when - we are parsing HTML that lacks a root node. - """ - # Spare the rod, ruin the child. - s = "<br/><br/>" - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertIdentical(d.documentElement, - d.documentElement.firstChild().parentNode) - - - def test_lenientParentSingle(self): - """ - Test that the C{parentNode} attribute is set to a meaningful value - when we parse an HTML document that has a non-Element root node. - """ - s = "Hello" - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertIdentical(d.documentElement, - d.documentElement.firstChild().parentNode) - - - def testUnEntities(self): - s = """ - <HTML> - This HTML goes between Stupid <=CrAzY!=> Dumb. - </HTML> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - n = domhelpers.gatherTextNodes(d) - self.assertNotEquals(n.find('>'), -1) - - def testEmptyError(self): - self.assertRaises(sux.ParseError, microdom.parseString, "") - - def testTameDocument(self): - s = """ - <test> - <it> - <is> - <a> - test - </a> - </is> - </it> - </test> - """ - d = microdom.parseString(s) - self.assertEqual( - domhelpers.gatherTextNodes(d.documentElement).strip() ,'test') - - def testAwfulTagSoup(self): - s = """ - <html> - <head><title> I send you this message to have your advice!!!!</titl e - </headd> - - <body bgcolor alink hlink vlink> - - <h1><BLINK>SALE</blINK> TWENTY MILLION EMAILS & FUR COAT NOW - FREE WITH `ENLARGER'</h1> - - YES THIS WONDERFUL AWFER IS NOW HERER!!! - - <script LANGUAGE="javascript"> -function give_answers() { -if (score < 70) { -alert("I hate you"); -}} - </script><a href=/foo.com/lalal name=foo>lalal</a> - </body> - </HTML> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - l = domhelpers.findNodesNamed(d.documentElement, 'blink') - self.assertEqual(len(l), 1) - - def testScriptLeniency(self): - s = """ - <script>(foo < bar) and (bar > foo)</script> - <script language="javascript">foo </scrip bar </script> - <script src="foo"> - <script src="foo">baz</script> - <script /><script></script> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertEqual(d.firstChild().firstChild().firstChild().data, - "(foo < bar) and (bar > foo)") - self.assertEqual( - d.firstChild().getElementsByTagName("script")[1].firstChild().data, - "foo </scrip bar ") - - def testScriptLeniencyIntelligence(self): - # if there is comment or CDATA in script, the autoquoting in bEL mode - # should not happen - s = """<script><!-- lalal --></script>""" - self.assertEqual( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - s = """<script><![CDATA[lalal]]></script>""" - self.assertEqual( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - s = """<script> // <![CDATA[ - lalal - //]]></script>""" - self.assertEqual( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - - def testPreserveCase(self): - s = '<eNcApSuLaTe><sUxor></sUxor><bOrk><w00T>TeXt</W00t></BoRk></EnCaPsUlAtE>' - s2 = s.lower().replace('text', 'TeXt') - # these are the only two option permutations that *can* parse the above - d = microdom.parseString(s, caseInsensitive=1, preserveCase=1) - d2 = microdom.parseString(s, caseInsensitive=1, preserveCase=0) - # caseInsensitive=0 preserveCase=0 is not valid, it's converted to - # caseInsensitive=0 preserveCase=1 - d3 = microdom.parseString(s2, caseInsensitive=0, preserveCase=1) - d4 = microdom.parseString(s2, caseInsensitive=1, preserveCase=0) - d5 = microdom.parseString(s2, caseInsensitive=1, preserveCase=1) - # this is slightly contrived, toxml() doesn't need to be identical - # for the documents to be equivalent (i.e. <b></b> to <b/>), - # however this assertion tests preserving case for start and - # end tags while still matching stuff like <bOrk></BoRk> - self.assertEqual(d.documentElement.toxml(), s) - self.assert_(d.isEqualToDocument(d2), "%r != %r" % (d.toxml(), d2.toxml())) - self.assert_(d2.isEqualToDocument(d3), "%r != %r" % (d2.toxml(), d3.toxml())) - # caseInsensitive=0 on the left, NOT perserveCase=1 on the right - ## XXX THIS TEST IS TURNED OFF UNTIL SOMEONE WHO CARES ABOUT FIXING IT DOES - #self.failIf(d3.isEqualToDocument(d2), "%r == %r" % (d3.toxml(), d2.toxml())) - self.assert_(d3.isEqualToDocument(d4), "%r != %r" % (d3.toxml(), d4.toxml())) - self.assert_(d4.isEqualToDocument(d5), "%r != %r" % (d4.toxml(), d5.toxml())) - - def testDifferentQuotes(self): - s = '<test a="a" b=\'b\' />' - d = microdom.parseString(s) - e = d.documentElement - self.assertEqual(e.getAttribute('a'), 'a') - self.assertEqual(e.getAttribute('b'), 'b') - - def testLinebreaks(self): - s = '<test \na="a"\n\tb="#b" />' - d = microdom.parseString(s) - e = d.documentElement - self.assertEqual(e.getAttribute('a'), 'a') - self.assertEqual(e.getAttribute('b'), '#b') - - def testMismatchedTags(self): - for s in '<test>', '<test> </tset>', '</test>': - self.assertRaises(microdom.MismatchedTags, microdom.parseString, s) - - def testComment(self): - s = "<bar><!--<foo />--></bar>" - d = microdom.parseString(s) - e = d.documentElement - self.assertEqual(e.nodeName, "bar") - c = e.childNodes[0] - self.assert_(isinstance(c, microdom.Comment)) - self.assertEqual(c.value, "<foo />") - c2 = c.cloneNode() - self.assert_(c is not c2) - self.assertEqual(c2.toxml(), "<!--<foo />-->") - - def testText(self): - d = microdom.parseString("<bar>xxxx</bar>").documentElement - text = d.childNodes[0] - self.assert_(isinstance(text, microdom.Text)) - self.assertEqual(text.value, "xxxx") - clone = text.cloneNode() - self.assert_(clone is not text) - self.assertEqual(clone.toxml(), "xxxx") - - def testEntities(self): - nodes = microdom.parseString("<b>&amp;&#12AB;</b>").documentElement.childNodes - self.assertEqual(len(nodes), 2) - self.assertEqual(nodes[0].data, "&amp;") - self.assertEqual(nodes[1].data, "&#12AB;") - self.assertEqual(nodes[0].cloneNode().toxml(), "&amp;") - for n in nodes: - self.assert_(isinstance(n, microdom.EntityReference)) - - def testCData(self): - s = '<x><![CDATA[</x>\r\n & foo]]></x>' - cdata = microdom.parseString(s).documentElement.childNodes[0] - self.assert_(isinstance(cdata, microdom.CDATASection)) - self.assertEqual(cdata.data, "</x>\r\n & foo") - self.assertEqual(cdata.cloneNode().toxml(), "<![CDATA[</x>\r\n & foo]]>") - - def testSingletons(self): - s = "<foo><b/><b /><b\n/></foo>" - s2 = "<foo><b/><b/><b/></foo>" - nodes = microdom.parseString(s).documentElement.childNodes - nodes2 = microdom.parseString(s2).documentElement.childNodes - self.assertEqual(len(nodes), 3) - for (n, n2) in zip(nodes, nodes2): - self.assert_(isinstance(n, microdom.Element)) - self.assertEqual(n.nodeName, "b") - self.assert_(n.isEqualToNode(n2)) - - def testAttributes(self): - s = '<foo a="b" />' - node = microdom.parseString(s).documentElement - - self.assertEqual(node.getAttribute("a"), "b") - self.assertEqual(node.getAttribute("c"), None) - self.assert_(node.hasAttribute("a")) - self.assert_(not node.hasAttribute("c")) - a = node.getAttributeNode("a") - self.assertEqual(a.value, "b") - - node.setAttribute("foo", "bar") - self.assertEqual(node.getAttribute("foo"), "bar") - - def testChildren(self): - s = "<foo><bar /><baz /><bax>foo</bax></foo>" - d = microdom.parseString(s).documentElement - self.assertEqual([n.nodeName for n in d.childNodes], ["bar", "baz", "bax"]) - self.assertEqual(d.lastChild().nodeName, "bax") - self.assertEqual(d.firstChild().nodeName, "bar") - self.assert_(d.hasChildNodes()) - self.assert_(not d.firstChild().hasChildNodes()) - - def testMutate(self): - s = "<foo />" - s1 = '<foo a="b"><bar/><foo/></foo>' - s2 = '<foo a="b">foo</foo>' - d = microdom.parseString(s).documentElement - d1 = microdom.parseString(s1).documentElement - d2 = microdom.parseString(s2).documentElement - - d.appendChild(d.cloneNode()) - d.setAttribute("a", "b") - child = d.childNodes[0] - self.assertEqual(child.getAttribute("a"), None) - self.assertEqual(child.nodeName, "foo") - - d.insertBefore(microdom.Element("bar"), child) - self.assertEqual(d.childNodes[0].nodeName, "bar") - self.assertEqual(d.childNodes[1], child) - for n in d.childNodes: - self.assertEqual(n.parentNode, d) - self.assert_(d.isEqualToNode(d1)) - - d.removeChild(child) - self.assertEqual(len(d.childNodes), 1) - self.assertEqual(d.childNodes[0].nodeName, "bar") - - t = microdom.Text("foo") - d.replaceChild(t, d.firstChild()) - self.assertEqual(d.firstChild(), t) - self.assert_(d.isEqualToNode(d2)) - - - def test_replaceNonChild(self): - """ - L{Node.replaceChild} raises L{ValueError} if the node given to be - replaced is not a child of the node C{replaceChild} is called on. - """ - parent = microdom.parseString('<foo />') - orphan = microdom.parseString('<bar />') - replacement = microdom.parseString('<baz />') - - self.assertRaises( - ValueError, parent.replaceChild, replacement, orphan) - - - def testSearch(self): - s = "<foo><bar id='me' /><baz><foo /></baz></foo>" - s2 = "<fOo><bAr id='me' /><bAz><fOO /></bAz></fOo>" - d = microdom.parseString(s) - d2 = microdom.parseString(s2, caseInsensitive=0, preserveCase=1) - d3 = microdom.parseString(s2, caseInsensitive=1, preserveCase=1) - - root = d.documentElement - self.assertEqual(root.firstChild(), d.getElementById('me')) - self.assertEqual(d.getElementsByTagName("foo"), - [root, root.lastChild().firstChild()]) - - root = d2.documentElement - self.assertEqual(root.firstChild(), d2.getElementById('me')) - self.assertEqual(d2.getElementsByTagName('fOo'), [root]) - self.assertEqual(d2.getElementsByTagName('fOO'), - [root.lastChild().firstChild()]) - self.assertEqual(d2.getElementsByTagName('foo'), []) - - root = d3.documentElement - self.assertEqual(root.firstChild(), d3.getElementById('me')) - self.assertEqual(d3.getElementsByTagName('FOO'), - [root, root.lastChild().firstChild()]) - self.assertEqual(d3.getElementsByTagName('fOo'), - [root, root.lastChild().firstChild()]) - - def testDoctype(self): - s = ('<?xml version="1.0"?>' - '<!DOCTYPE foo PUBLIC "baz" "http://www.example.com/example.dtd">' - '<foo></foo>') - s2 = '<foo/>' - d = microdom.parseString(s) - d2 = microdom.parseString(s2) - self.assertEqual(d.doctype, - 'foo PUBLIC "baz" "http://www.example.com/example.dtd"') - self.assertEqual(d.toxml(), s) - self.failIf(d.isEqualToDocument(d2)) - self.failUnless(d.documentElement.isEqualToNode(d2.documentElement)) - - samples = [("<img/>", "<img />"), - ("<foo A='b'>x</foo>", '<foo A="b">x</foo>'), - ("<foo><BAR /></foo>", "<foo><BAR></BAR></foo>"), - ("<foo>hello there &amp; yoyoy</foo>", - "<foo>hello there &amp; yoyoy</foo>"), - ] - - def testOutput(self): - for s, out in self.samples: - d = microdom.parseString(s, caseInsensitive=0) - d2 = microdom.parseString(out, caseInsensitive=0) - testOut = d.documentElement.toxml() - self.assertEqual(out, testOut) - self.assert_(d.isEqualToDocument(d2)) - - def testErrors(self): - for s in ["<foo>&am</foo>", "<foo", "<f>&</f>", "<() />"]: - self.assertRaises(Exception, microdom.parseString, s) - - def testCaseInsensitive(self): - s = "<foo a='b'><BAx>x</bax></FOO>" - s2 = '<foo a="b"><bax>x</bax></foo>' - s3 = "<FOO a='b'><BAx>x</BAx></FOO>" - s4 = "<foo A='b'>x</foo>" - d = microdom.parseString(s) - d2 = microdom.parseString(s2) - d3 = microdom.parseString(s3, caseInsensitive=1) - d4 = microdom.parseString(s4, caseInsensitive=1, preserveCase=1) - d5 = microdom.parseString(s4, caseInsensitive=1, preserveCase=0) - d6 = microdom.parseString(s4, caseInsensitive=0, preserveCase=0) - out = microdom.parseString(s).documentElement.toxml() - self.assertRaises(microdom.MismatchedTags, microdom.parseString, - s, caseInsensitive=0) - self.assertEqual(out, s2) - self.failUnless(d.isEqualToDocument(d2)) - self.failUnless(d.isEqualToDocument(d3)) - self.failUnless(d4.documentElement.hasAttribute('a')) - self.failIf(d6.documentElement.hasAttribute('a')) - self.assertEqual(d4.documentElement.toxml(), '<foo A="b">x</foo>') - self.assertEqual(d5.documentElement.toxml(), '<foo a="b">x</foo>') - def testEatingWhitespace(self): - s = """<hello> - </hello>""" - d = microdom.parseString(s) - self.failUnless(not d.documentElement.hasChildNodes(), - d.documentElement.childNodes) - self.failUnless(d.isEqualToDocument(microdom.parseString('<hello></hello>'))) - - def testLenientAmpersand(self): - prefix = "<?xml version='1.0'?>" - # we use <pre> so space will be preserved - for i, o in [("&", "&amp;"), - ("& ", "&amp; "), - ("&amp;", "&amp;"), - ("&hello monkey", "&amp;hello monkey")]: - d = microdom.parseString("%s<pre>%s</pre>" - % (prefix, i), beExtremelyLenient=1) - self.assertEqual(d.documentElement.toxml(), "<pre>%s</pre>" % o) - # non-space preserving - d = microdom.parseString("<t>hello & there</t>", beExtremelyLenient=1) - self.assertEqual(d.documentElement.toxml(), "<t>hello &amp; there</t>") - - def testInsensitiveLenient(self): - # testing issue #537 - d = microdom.parseString( - "<?xml version='1.0'?><bar><xA><y>c</Xa> <foo></bar>", - beExtremelyLenient=1) - self.assertEqual(d.documentElement.firstChild().toxml(), "<xa><y>c</y></xa>") - - def testLaterCloserSimple(self): - s = "<ul><li>foo<li>bar<li>baz</ul>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<ul><li>foo</li><li>bar</li><li>baz</li></ul>" - actual = d.documentElement.toxml() - self.assertEqual(expected, actual) - - def testLaterCloserCaseInsensitive(self): - s = "<DL><p><DT>foo<DD>bar</DL>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<dl><p></p><dt>foo</dt><dd>bar</dd></dl>" - actual = d.documentElement.toxml() - self.assertEqual(expected, actual) - - - def testLaterCloserDL(self): - s = ("<dl>" - "<dt>word<dd>definition" - "<dt>word<dt>word<dd>definition<dd>definition" - "</dl>") - expected = ("<dl>" - "<dt>word</dt><dd>definition</dd>" - "<dt>word</dt><dt>word</dt><dd>definition</dd><dd>definition</dd>" - "</dl>") - d = microdom.parseString(s, beExtremelyLenient=1) - actual = d.documentElement.toxml() - self.assertEqual(expected, actual) - - - def testUnicodeTolerance(self): - import struct - s = '<foo><bar><baz /></bar></foo>' - j =(u'<?xml version="1.0" encoding="UCS-2" ?>\r\n<JAPANESE>\r\n' - u'<TITLE>\u5c02\u9580\u5bb6\u30ea\u30b9\u30c8 </TITLE></JAPANESE>') - j2=('\xff\xfe<\x00?\x00x\x00m\x00l\x00 \x00v\x00e\x00r\x00s\x00i\x00o' - '\x00n\x00=\x00"\x001\x00.\x000\x00"\x00 \x00e\x00n\x00c\x00o\x00d' - '\x00i\x00n\x00g\x00=\x00"\x00U\x00C\x00S\x00-\x002\x00"\x00 \x00?' - '\x00>\x00\r\x00\n\x00<\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E' - '\x00>\x00\r\x00\n\x00<\x00T\x00I\x00T\x00L\x00E\x00>\x00\x02\\' - '\x80\x95\xb6[\xea0\xb90\xc80 \x00<\x00/\x00T\x00I\x00T\x00L\x00E' - '\x00>\x00<\x00/\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E\x00>\x00') - def reverseBytes(s): - fmt = str(len(s) // 2) + 'H' - return struct.pack('<' + fmt, *struct.unpack('>' + fmt, s)) - urd = microdom.parseString(reverseBytes(s.encode('UTF-16'))) - ud = microdom.parseString(s.encode('UTF-16')) - sd = microdom.parseString(s) - self.assert_(ud.isEqualToDocument(sd)) - self.assert_(ud.isEqualToDocument(urd)) - ud = microdom.parseString(j) - urd = microdom.parseString(reverseBytes(j2)) - sd = microdom.parseString(j2) - self.assert_(ud.isEqualToDocument(sd)) - self.assert_(ud.isEqualToDocument(urd)) - - # test that raw text still gets encoded - # test that comments get encoded - j3=microdom.parseString(u'<foo/>') - hdr='<?xml version="1.0"?>' - div=microdom.lmx().text(u'\u221a', raw=1).node - de=j3.documentElement - de.appendChild(div) - de.appendChild(j3.createComment(u'\u221a')) - self.assertEqual(j3.toxml(), hdr+ - u'<foo><div>\u221a</div><!--\u221a--></foo>'.encode('utf8')) - - def testNamedChildren(self): - tests = {"<foo><bar /><bar unf='1' /><bar>asdfadsf</bar>" - "<bam/></foo>" : 3, - '<foo>asdf</foo>' : 0, - '<foo><bar><bar></bar></bar></foo>' : 1, - } - for t in tests.keys(): - node = microdom.parseString(t).documentElement - result = domhelpers.namedChildren(node, 'bar') - self.assertEqual(len(result), tests[t]) - if result: - self.assert_(hasattr(result[0], 'tagName')) - - def testCloneNode(self): - s = '<foo a="b"><bax>x</bax></foo>' - node = microdom.parseString(s).documentElement - clone = node.cloneNode(deep=1) - self.failIfEquals(node, clone) - self.assertEqual(len(node.childNodes), len(clone.childNodes)) - c1, c2 = node.firstChild(), clone.firstChild() - self.failIfEquals(c1, c2) - self.assertEqual(len(c1.childNodes), len(c2.childNodes)) - self.failIfEquals(c1.firstChild(), c2.firstChild()) - self.assertEqual(s, clone.toxml()) - self.assertEqual(node.namespace, clone.namespace) - - def testCloneDocument(self): - s = ('<?xml version="1.0"?>' - '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' - '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><foo></foo>') - - node = microdom.parseString(s) - clone = node.cloneNode(deep=1) - self.failIfEquals(node, clone) - self.assertEqual(len(node.childNodes), len(clone.childNodes)) - self.assertEqual(s, clone.toxml()) - - self.failUnless(clone.isEqualToDocument(node)) - self.failUnless(node.isEqualToDocument(clone)) - - - def testLMX(self): - n = microdom.Element("p") - lmx = microdom.lmx(n) - lmx.text("foo") - b = lmx.b(a="c") - b.foo()["z"] = "foo" - b.foo() - b.add("bar", c="y") - - s = '<p>foo<b a="c"><foo z="foo"></foo><foo></foo><bar c="y"></bar></b></p>' - self.assertEqual(s, n.toxml()) - - - def testDict(self): - """ - Returns a dictionary which is hashable. - """ - n = microdom.Element("p") - hash(n) - - - def testEscaping(self): - # issue 590 - raw = "&'some \"stuff\"', <what up?>" - cooked = "&amp;'some &quot;stuff&quot;', &lt;what up?&gt;" - esc1 = microdom.escape(raw) - self.assertEqual(esc1, cooked) - self.assertEqual(microdom.unescape(esc1), raw) - - def testNamespaces(self): - s = ''' - <x xmlns="base"> - <y /> - <y q="1" x:q="2" y:q="3" /> - <y:y xml:space="1">here is some space </y:y> - <y:y /> - <x:y /> - </x> - ''' - d = microdom.parseString(s) - # at least make sure it doesn't traceback - s2 = d.toprettyxml() - self.assertEqual(d.documentElement.namespace, - "base") - self.assertEqual(d.documentElement.getElementsByTagName("y")[0].namespace, - "base") - self.assertEqual( - d.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), - '1') - - d2 = microdom.parseString(s2) - self.assertEqual(d2.documentElement.namespace, - "base") - self.assertEqual(d2.documentElement.getElementsByTagName("y")[0].namespace, - "base") - self.assertEqual( - d2.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), - '1') - - def testNamespaceDelete(self): - """ - Test that C{toxml} can support xml structures that remove namespaces. - """ - s1 = ('<?xml version="1.0"?><html xmlns="http://www.w3.org/TR/REC-html40">' - '<body xmlns=""></body></html>') - s2 = microdom.parseString(s1).toxml() - self.assertEqual(s1, s2) - - def testNamespaceInheritance(self): - """ - Check that unspecified namespace is a thing separate from undefined - namespace. This test added after discovering some weirdness in Lore. - """ - # will only work if childNodes is mutated. not sure why. - child = microdom.Element('ol') - parent = microdom.Element('div', namespace='http://www.w3.org/1999/xhtml') - parent.childNodes = [child] - self.assertEqual(parent.toxml(), - '<div xmlns="http://www.w3.org/1999/xhtml"><ol></ol></div>') - - def test_prefixedTags(self): - """ - XML elements with a prefixed name as per upper level tag definition - have a start-tag of C{"<prefix:tag>"} and an end-tag of - C{"</prefix:tag>"}. - - Refer to U{http://www.w3.org/TR/xml-names/#ns-using} for details. - """ - outerNamespace = "http://example.com/outer" - innerNamespace = "http://example.com/inner" - - document = microdom.Document() - # Create the root in one namespace. Microdom will probably make this - # the default namespace. - root = document.createElement("root", namespace=outerNamespace) - - # Give the root some prefixes to use. - root.addPrefixes({innerNamespace: "inner"}) - - # Append a child to the root from the namespace that prefix is bound - # to. - tag = document.createElement("tag", namespace=innerNamespace) - - # Give that tag a child too. This way we test rendering of tags with - # children and without children. - child = document.createElement("child", namespace=innerNamespace) - - tag.appendChild(child) - root.appendChild(tag) - document.appendChild(root) - - # ok, the xml should appear like this - xmlOk = ( - '<?xml version="1.0"?>' - '<root xmlns="http://example.com/outer" ' - 'xmlns:inner="http://example.com/inner">' - '<inner:tag><inner:child></inner:child></inner:tag>' - '</root>') - - xmlOut = document.toxml() - self.assertEqual(xmlOut, xmlOk) - - - def test_prefixPropagation(self): - """ - Children of prefixed tags respect the default namespace at the point - where they are rendered. Specifically, they are not influenced by the - prefix of their parent as that prefix has no bearing on them. - - See U{http://www.w3.org/TR/xml-names/#scoping} for details. - - To further clarify the matter, the following:: - - <root xmlns="http://example.com/ns/test"> - <mytag xmlns="http://example.com/ns/mytags"> - <mysubtag xmlns="http://example.com/ns/mytags"> - <element xmlns="http://example.com/ns/test"></element> - </mysubtag> - </mytag> - </root> - - Should become this after all the namespace declarations have been - I{moved up}:: - - <root xmlns="http://example.com/ns/test" - xmlns:mytags="http://example.com/ns/mytags"> - <mytags:mytag> - <mytags:mysubtag> - <element></element> - </mytags:mysubtag> - </mytags:mytag> - </root> - """ - outerNamespace = "http://example.com/outer" - innerNamespace = "http://example.com/inner" - - document = microdom.Document() - # creates a root element - root = document.createElement("root", namespace=outerNamespace) - document.appendChild(root) - - # Create a child with a specific namespace with a prefix bound to it. - root.addPrefixes({innerNamespace: "inner"}) - mytag = document.createElement("mytag",namespace=innerNamespace) - root.appendChild(mytag) - - # Create a child of that which has the outer namespace. - mysubtag = document.createElement("mysubtag", namespace=outerNamespace) - mytag.appendChild(mysubtag) - - xmlOk = ( - '<?xml version="1.0"?>' - '<root xmlns="http://example.com/outer" ' - 'xmlns:inner="http://example.com/inner">' - '<inner:mytag>' - '<mysubtag></mysubtag>' - '</inner:mytag>' - '</root>' - ) - xmlOut = document.toxml() - self.assertEqual(xmlOut, xmlOk) - - - -class BrokenHTMLTests(TestCase): - """ - Tests for when microdom encounters very bad HTML and C{beExtremelyLenient} - is enabled. These tests are inspired by some HTML generated in by a mailer, - which breaks up very long lines by splitting them with '!\n '. The expected - behaviour is loosely modelled on the way Firefox treats very bad HTML. - """ - - def checkParsed(self, input, expected, beExtremelyLenient=1): - """ - Check that C{input}, when parsed, produces a DOM where the XML - of the document element is equal to C{expected}. - """ - output = microdom.parseString(input, - beExtremelyLenient=beExtremelyLenient) - self.assertEqual(output.documentElement.toxml(), expected) - - - def test_brokenAttributeName(self): - """ - Check that microdom does its best to handle broken attribute names. - The important thing is that it doesn't raise an exception. - """ - input = '<body><h1><div al!\n ign="center">Foo</div></h1></body>' - expected = ('<body><h1><div ign="center" al="True">' - 'Foo</div></h1></body>') - self.checkParsed(input, expected) - - - def test_brokenAttributeValue(self): - """ - Check that microdom encompasses broken attribute values. - """ - input = '<body><h1><div align="cen!\n ter">Foo</div></h1></body>' - expected = '<body><h1><div align="cen!\n ter">Foo</div></h1></body>' - self.checkParsed(input, expected) - - - def test_brokenOpeningTag(self): - """ - Check that microdom does its best to handle broken opening tags. - The important thing is that it doesn't raise an exception. - """ - input = '<body><h1><sp!\n an>Hello World!</span></h1></body>' - expected = '<body><h1><sp an="True">Hello World!</sp></h1></body>' - self.checkParsed(input, expected) - - - def test_brokenSelfClosingTag(self): - """ - Check that microdom does its best to handle broken self-closing tags - The important thing is that it doesn't raise an exception. - """ - self.checkParsed('<body><span /!\n></body>', - '<body><span></span></body>') - self.checkParsed('<span!\n />', '<span></span>') - - - def test_brokenClosingTag(self): - """ - Check that microdom does its best to handle broken closing tags. - The important thing is that it doesn't raise an exception. - """ - input = '<body><h1><span>Hello World!</sp!\nan></h1></body>' - expected = '<body><h1><span>Hello World!</span></h1></body>' - self.checkParsed(input, expected) - input = '<body><h1><span>Hello World!</!\nspan></h1></body>' - self.checkParsed(input, expected) - input = '<body><h1><span>Hello World!</span!\n></h1></body>' - self.checkParsed(input, expected) - input = '<body><h1><span>Hello World!<!\n/span></h1></body>' - expected = '<body><h1><span>Hello World!<!></!></span></h1></body>' - self.checkParsed(input, expected) - - - - -class NodeTests(TestCase): - """ - Tests for L{Node}. - """ - def test_isNodeEqualTo(self): - """ - L{Node.isEqualToNode} returns C{True} if and only if passed a L{Node} - with the same children. - """ - # A node is equal to itself - node = microdom.Node(object()) - self.assertTrue(node.isEqualToNode(node)) - another = microdom.Node(object()) - # Two nodes with no children are equal - self.assertTrue(node.isEqualToNode(another)) - node.appendChild(microdom.Node(object())) - # A node with no children is not equal to a node with a child - self.assertFalse(node.isEqualToNode(another)) - another.appendChild(microdom.Node(object())) - # A node with a child and no grandchildren is equal to another node - # with a child and no grandchildren. - self.assertTrue(node.isEqualToNode(another)) - # A node with a child and a grandchild is not equal to another node - # with a child and no grandchildren. - node.firstChild().appendChild(microdom.Node(object())) - self.assertFalse(node.isEqualToNode(another)) - # A node with a child and a grandchild is equal to another node with a - # child and a grandchild. - another.firstChild().appendChild(microdom.Node(object())) - self.assertTrue(node.isEqualToNode(another)) - - def test_validChildInstance(self): - """ - Children of L{Node} instances must also be L{Node} instances. - """ - node = microdom.Node() - child = microdom.Node() - # Node.appendChild() only accepts Node instances. - node.appendChild(child) - self.assertRaises(TypeError, node.appendChild, None) - # Node.insertBefore() only accepts Node instances. - self.assertRaises(TypeError, node.insertBefore, child, None) - self.assertRaises(TypeError, node.insertBefore, None, child) - self.assertRaises(TypeError, node.insertBefore, None, None) - # Node.removeChild() only accepts Node instances. - node.removeChild(child) - self.assertRaises(TypeError, node.removeChild, None) - # Node.replaceChild() only accepts Node instances. - self.assertRaises(TypeError, node.replaceChild, child, None) - self.assertRaises(TypeError, node.replaceChild, None, child) - self.assertRaises(TypeError, node.replaceChild, None, None) - - -class DocumentTests(TestCase): - """ - Tests for L{Document}. - """ - doctype = 'foo PUBLIC "baz" "http://www.example.com/example.dtd"' - - def test_isEqualToNode(self): - """ - L{Document.isEqualToNode} returns C{True} if and only if passed a - L{Document} with the same C{doctype} and C{documentElement}. - """ - # A document is equal to itself - document = microdom.Document() - self.assertTrue(document.isEqualToNode(document)) - # A document without a doctype or documentElement is equal to another - # document without a doctype or documentElement. - another = microdom.Document() - self.assertTrue(document.isEqualToNode(another)) - # A document with a doctype is not equal to a document without a - # doctype. - document.doctype = self.doctype - self.assertFalse(document.isEqualToNode(another)) - # Two documents with the same doctype are equal - another.doctype = self.doctype - self.assertTrue(document.isEqualToNode(another)) - # A document with a documentElement is not equal to a document without - # a documentElement - document.appendChild(microdom.Node(object())) - self.assertFalse(document.isEqualToNode(another)) - # Two documents with equal documentElements are equal. - another.appendChild(microdom.Node(object())) - self.assertTrue(document.isEqualToNode(another)) - # Two documents with documentElements which are not equal are not - # equal. - document.documentElement.appendChild(microdom.Node(object())) - self.assertFalse(document.isEqualToNode(another)) - - - def test_childRestriction(self): - """ - L{Document.appendChild} raises L{ValueError} if the document already - has a child. - """ - document = microdom.Document() - child = microdom.Node() - another = microdom.Node() - document.appendChild(child) - self.assertRaises(ValueError, document.appendChild, another) - - - -class EntityReferenceTests(TestCase): - """ - Tests for L{EntityReference}. - """ - def test_isEqualToNode(self): - """ - L{EntityReference.isEqualToNode} returns C{True} if and only if passed - a L{EntityReference} with the same C{eref}. - """ - self.assertTrue( - microdom.EntityReference('quot').isEqualToNode( - microdom.EntityReference('quot'))) - self.assertFalse( - microdom.EntityReference('quot').isEqualToNode( - microdom.EntityReference('apos'))) - - - -class CharacterDataTests(TestCase): - """ - Tests for L{CharacterData}. - """ - def test_isEqualToNode(self): - """ - L{CharacterData.isEqualToNode} returns C{True} if and only if passed a - L{CharacterData} with the same value. - """ - self.assertTrue( - microdom.CharacterData('foo').isEqualToNode( - microdom.CharacterData('foo'))) - self.assertFalse( - microdom.CharacterData('foo').isEqualToNode( - microdom.CharacterData('bar'))) - - - -class CommentTests(TestCase): - """ - Tests for L{Comment}. - """ - def test_isEqualToNode(self): - """ - L{Comment.isEqualToNode} returns C{True} if and only if passed a - L{Comment} with the same value. - """ - self.assertTrue( - microdom.Comment('foo').isEqualToNode( - microdom.Comment('foo'))) - self.assertFalse( - microdom.Comment('foo').isEqualToNode( - microdom.Comment('bar'))) - - - -class TextTests(TestCase): - """ - Tests for L{Text}. - """ - def test_isEqualToNode(self): - """ - L{Text.isEqualToNode} returns C{True} if and only if passed a L{Text} - which represents the same data. - """ - self.assertTrue( - microdom.Text('foo', raw=True).isEqualToNode( - microdom.Text('foo', raw=True))) - self.assertFalse( - microdom.Text('foo', raw=True).isEqualToNode( - microdom.Text('foo', raw=False))) - self.assertFalse( - microdom.Text('foo', raw=True).isEqualToNode( - microdom.Text('bar', raw=True))) - - - -class CDATASectionTests(TestCase): - """ - Tests for L{CDATASection}. - """ - def test_isEqualToNode(self): - """ - L{CDATASection.isEqualToNode} returns C{True} if and only if passed a - L{CDATASection} which represents the same data. - """ - self.assertTrue( - microdom.CDATASection('foo').isEqualToNode( - microdom.CDATASection('foo'))) - self.assertFalse( - microdom.CDATASection('foo').isEqualToNode( - microdom.CDATASection('bar'))) - - - -class ElementTests(TestCase): - """ - Tests for L{Element}. - """ - def test_isEqualToNode(self): - """ - L{Element.isEqualToNode} returns C{True} if and only if passed a - L{Element} with the same C{nodeName}, C{namespace}, C{childNodes}, and - C{attributes}. - """ - self.assertTrue( - microdom.Element( - 'foo', {'a': 'b'}, object(), namespace='bar').isEqualToNode( - microdom.Element( - 'foo', {'a': 'b'}, object(), namespace='bar'))) - - # Elements with different nodeName values do not compare equal. - self.assertFalse( - microdom.Element( - 'foo', {'a': 'b'}, object(), namespace='bar').isEqualToNode( - microdom.Element( - 'bar', {'a': 'b'}, object(), namespace='bar'))) - - # Elements with different namespaces do not compare equal. - self.assertFalse( - microdom.Element( - 'foo', {'a': 'b'}, object(), namespace='bar').isEqualToNode( - microdom.Element( - 'foo', {'a': 'b'}, object(), namespace='baz'))) - - # Elements with different childNodes do not compare equal. - one = microdom.Element('foo', {'a': 'b'}, object(), namespace='bar') - two = microdom.Element('foo', {'a': 'b'}, object(), namespace='bar') - two.appendChild(microdom.Node(object())) - self.assertFalse(one.isEqualToNode(two)) - - # Elements with different attributes do not compare equal. - self.assertFalse( - microdom.Element( - 'foo', {'a': 'b'}, object(), namespace='bar').isEqualToNode( - microdom.Element( - 'foo', {'a': 'c'}, object(), namespace='bar'))) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_xmlrpc.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_xmlrpc.py deleted file mode 100644 index 8bb110b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/test/test_xmlrpc.py +++ /dev/null @@ -1,819 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xmlrpc -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for XML-RPC support in L{twisted.web.xmlrpc}. -""" - -import datetime -import xmlrpclib -from StringIO import StringIO - -from twisted.trial import unittest -from twisted.web import xmlrpc -from twisted.web.xmlrpc import ( - XMLRPC, payloadTemplate, addIntrospection, _QueryFactory, withRequest) -from twisted.web import server, static, client, error, http -from twisted.internet import reactor, defer -from twisted.internet.error import ConnectionDone -from twisted.python import failure -from twisted.python.reflect import namedModule -from twisted.test.proto_helpers import MemoryReactor -from twisted.web.test.test_web import DummyRequest -try: - namedModule('twisted.internet.ssl') -except ImportError: - sslSkip = "OpenSSL not present" -else: - sslSkip = None - - -class AsyncXMLRPCTests(unittest.TestCase): - """ - Tests for L{XMLRPC}'s support of Deferreds. - """ - def setUp(self): - self.request = DummyRequest(['']) - self.request.method = 'POST' - self.request.content = StringIO( - payloadTemplate % ('async', xmlrpclib.dumps(()))) - - result = self.result = defer.Deferred() - class AsyncResource(XMLRPC): - def xmlrpc_async(self): - return result - - self.resource = AsyncResource() - - - def test_deferredResponse(self): - """ - If an L{XMLRPC} C{xmlrpc_*} method returns a L{defer.Deferred}, the - response to the request is the result of that L{defer.Deferred}. - """ - self.resource.render(self.request) - self.assertEqual(self.request.written, []) - - self.result.callback("result") - - resp = xmlrpclib.loads("".join(self.request.written)) - self.assertEqual(resp, (('result',), None)) - self.assertEqual(self.request.finished, 1) - - - def test_interruptedDeferredResponse(self): - """ - While waiting for the L{Deferred} returned by an L{XMLRPC} C{xmlrpc_*} - method to fire, the connection the request was issued over may close. - If this happens, neither C{write} nor C{finish} is called on the - request. - """ - self.resource.render(self.request) - self.request.processingFailed( - failure.Failure(ConnectionDone("Simulated"))) - self.result.callback("result") - self.assertEqual(self.request.written, []) - self.assertEqual(self.request.finished, 0) - - - -class TestRuntimeError(RuntimeError): - pass - - - -class TestValueError(ValueError): - pass - - - -class Test(XMLRPC): - - # If you add xmlrpc_ methods to this class, go change test_listMethods - # below. - - FAILURE = 666 - NOT_FOUND = 23 - SESSION_EXPIRED = 42 - - def xmlrpc_echo(self, arg): - return arg - - # the doc string is part of the test - def xmlrpc_add(self, a, b): - """ - This function add two numbers. - """ - return a + b - - xmlrpc_add.signature = [['int', 'int', 'int'], - ['double', 'double', 'double']] - - # the doc string is part of the test - def xmlrpc_pair(self, string, num): - """ - This function puts the two arguments in an array. - """ - return [string, num] - - xmlrpc_pair.signature = [['array', 'string', 'int']] - - # the doc string is part of the test - def xmlrpc_defer(self, x): - """Help for defer.""" - return defer.succeed(x) - - def xmlrpc_deferFail(self): - return defer.fail(TestValueError()) - - # don't add a doc string, it's part of the test - def xmlrpc_fail(self): - raise TestRuntimeError - - def xmlrpc_fault(self): - return xmlrpc.Fault(12, "hello") - - def xmlrpc_deferFault(self): - return defer.fail(xmlrpc.Fault(17, "hi")) - - def xmlrpc_complex(self): - return {"a": ["b", "c", 12, []], "D": "foo"} - - def xmlrpc_dict(self, map, key): - return map[key] - xmlrpc_dict.help = 'Help for dict.' - - @withRequest - def xmlrpc_withRequest(self, request, other): - """ - A method decorated with L{withRequest} which can be called by - a test to verify that the request object really is passed as - an argument. - """ - return ( - # as a proof that request is a request - request.method + - # plus proof other arguments are still passed along - ' ' + other) - - - def lookupProcedure(self, procedurePath): - try: - return XMLRPC.lookupProcedure(self, procedurePath) - except xmlrpc.NoSuchFunction: - if procedurePath.startswith("SESSION"): - raise xmlrpc.Fault(self.SESSION_EXPIRED, - "Session non-existant/expired.") - else: - raise - - - -class TestLookupProcedure(XMLRPC): - """ - This is a resource which customizes procedure lookup to be used by the tests - of support for this customization. - """ - def echo(self, x): - return x - - - def lookupProcedure(self, procedureName): - """ - Lookup a procedure from a fixed set of choices, either I{echo} or - I{system.listeMethods}. - """ - if procedureName == 'echo': - return self.echo - raise xmlrpc.NoSuchFunction( - self.NOT_FOUND, 'procedure %s not found' % (procedureName,)) - - - -class TestListProcedures(XMLRPC): - """ - This is a resource which customizes procedure enumeration to be used by the - tests of support for this customization. - """ - def listProcedures(self): - """ - Return a list of a single method this resource will claim to support. - """ - return ['foo'] - - - -class TestAuthHeader(Test): - """ - This is used to get the header info so that we can test - authentication. - """ - def __init__(self): - Test.__init__(self) - self.request = None - - def render(self, request): - self.request = request - return Test.render(self, request) - - def xmlrpc_authinfo(self): - return self.request.getUser(), self.request.getPassword() - - -class TestQueryProtocol(xmlrpc.QueryProtocol): - """ - QueryProtocol for tests that saves headers received inside the factory. - """ - - def connectionMade(self): - self.factory.transport = self.transport - xmlrpc.QueryProtocol.connectionMade(self) - - def handleHeader(self, key, val): - self.factory.headers[key.lower()] = val - - -class TestQueryFactory(xmlrpc._QueryFactory): - """ - QueryFactory using L{TestQueryProtocol} for saving headers. - """ - protocol = TestQueryProtocol - - def __init__(self, *args, **kwargs): - self.headers = {} - xmlrpc._QueryFactory.__init__(self, *args, **kwargs) - - -class TestQueryFactoryCancel(xmlrpc._QueryFactory): - """ - QueryFactory that saves a reference to the - L{twisted.internet.interfaces.IConnector} to test connection lost. - """ - - def startedConnecting(self, connector): - self.connector = connector - - -class XMLRPCTests(unittest.TestCase): - - def setUp(self): - self.p = reactor.listenTCP(0, server.Site(Test()), - interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - def tearDown(self): - self.factories = [] - return self.p.stopListening() - - def queryFactory(self, *args, **kwargs): - """ - Specific queryFactory for proxy that uses our custom - L{TestQueryFactory}, and save factories. - """ - factory = TestQueryFactory(*args, **kwargs) - self.factories.append(factory) - return factory - - def proxy(self, factory=None): - """ - Return a new xmlrpc.Proxy for the test site created in - setUp(), using the given factory as the queryFactory, or - self.queryFactory if no factory is provided. - """ - p = xmlrpc.Proxy("http://127.0.0.1:%d/" % self.port) - if factory is None: - p.queryFactory = self.queryFactory - else: - p.queryFactory = factory - return p - - def test_results(self): - inputOutput = [ - ("add", (2, 3), 5), - ("defer", ("a",), "a"), - ("dict", ({"a": 1}, "a"), 1), - ("pair", ("a", 1), ["a", 1]), - ("complex", (), {"a": ["b", "c", 12, []], "D": "foo"})] - - dl = [] - for meth, args, outp in inputOutput: - d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEqual, outp) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def test_errors(self): - """ - Verify that for each way a method exposed via XML-RPC can fail, the - correct 'Content-type' header is set in the response and that the - client-side Deferred is errbacked with an appropriate C{Fault} - instance. - """ - dl = [] - for code, methodName in [(666, "fail"), (666, "deferFail"), - (12, "fault"), (23, "noSuchMethod"), - (17, "deferFault"), (42, "SESSION_TEST")]: - d = self.proxy().callRemote(methodName) - d = self.assertFailure(d, xmlrpc.Fault) - d.addCallback(lambda exc, code=code: - self.assertEqual(exc.faultCode, code)) - dl.append(d) - d = defer.DeferredList(dl, fireOnOneErrback=True) - def cb(ign): - for factory in self.factories: - self.assertEqual(factory.headers['content-type'], - 'text/xml') - self.flushLoggedErrors(TestRuntimeError, TestValueError) - d.addCallback(cb) - return d - - - def test_cancel(self): - """ - A deferred from the Proxy can be cancelled, disconnecting - the L{twisted.internet.interfaces.IConnector}. - """ - def factory(*args, **kw): - factory.f = TestQueryFactoryCancel(*args, **kw) - return factory.f - d = self.proxy(factory).callRemote('add', 2, 3) - self.assertNotEquals(factory.f.connector.state, "disconnected") - d.cancel() - self.assertEqual(factory.f.connector.state, "disconnected") - d = self.assertFailure(d, defer.CancelledError) - return d - - - def test_errorGet(self): - """ - A classic GET on the xml server should return a NOT_ALLOWED. - """ - d = client.getPage("http://127.0.0.1:%d/" % (self.port,)) - d = self.assertFailure(d, error.Error) - d.addCallback( - lambda exc: self.assertEqual(int(exc.args[0]), http.NOT_ALLOWED)) - return d - - def test_errorXMLContent(self): - """ - Test that an invalid XML input returns an L{xmlrpc.Fault}. - """ - d = client.getPage("http://127.0.0.1:%d/" % (self.port,), - method="POST", postdata="foo") - def cb(result): - self.assertRaises(xmlrpc.Fault, xmlrpclib.loads, result) - d.addCallback(cb) - return d - - - def test_datetimeRoundtrip(self): - """ - If an L{xmlrpclib.DateTime} is passed as an argument to an XML-RPC - call and then returned by the server unmodified, the result should - be equal to the original object. - """ - when = xmlrpclib.DateTime() - d = self.proxy().callRemote("echo", when) - d.addCallback(self.assertEqual, when) - return d - - - def test_doubleEncodingError(self): - """ - If it is not possible to encode a response to the request (for example, - because L{xmlrpclib.dumps} raises an exception when encoding a - L{Fault}) the exception which prevents the response from being - generated is logged and the request object is finished anyway. - """ - d = self.proxy().callRemote("echo", "") - - # *Now* break xmlrpclib.dumps. Hopefully the client already used it. - def fakeDumps(*args, **kwargs): - raise RuntimeError("Cannot encode anything at all!") - self.patch(xmlrpclib, 'dumps', fakeDumps) - - # It doesn't matter how it fails, so long as it does. Also, it happens - # to fail with an implementation detail exception right now, not - # something suitable as part of a public interface. - d = self.assertFailure(d, Exception) - - def cbFailed(ignored): - # The fakeDumps exception should have been logged. - self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1) - d.addCallback(cbFailed) - return d - - - def test_closeConnectionAfterRequest(self): - """ - The connection to the web server is closed when the request is done. - """ - d = self.proxy().callRemote('echo', '') - def responseDone(ignored): - [factory] = self.factories - self.assertFalse(factory.transport.connected) - self.assertTrue(factory.transport.disconnected) - return d.addCallback(responseDone) - - - def test_tcpTimeout(self): - """ - For I{HTTP} URIs, L{xmlrpc.Proxy.callRemote} passes the value it - received for the C{connectTimeout} parameter as the C{timeout} argument - to the underlying connectTCP call. - """ - reactor = MemoryReactor() - proxy = xmlrpc.Proxy("http://127.0.0.1:69", connectTimeout=2.0, - reactor=reactor) - proxy.callRemote("someMethod") - self.assertEqual(reactor.tcpClients[0][3], 2.0) - - - def test_sslTimeout(self): - """ - For I{HTTPS} URIs, L{xmlrpc.Proxy.callRemote} passes the value it - received for the C{connectTimeout} parameter as the C{timeout} argument - to the underlying connectSSL call. - """ - reactor = MemoryReactor() - proxy = xmlrpc.Proxy("https://127.0.0.1:69", connectTimeout=3.0, - reactor=reactor) - proxy.callRemote("someMethod") - self.assertEqual(reactor.sslClients[0][4], 3.0) - test_sslTimeout.skip = sslSkip - - - -class XMLRPCProxyWithoutSlashTests(XMLRPCTests): - """ - Test with proxy that doesn't add a slash. - """ - - def proxy(self, factory=None): - p = xmlrpc.Proxy("http://127.0.0.1:%d" % self.port) - if factory is None: - p.queryFactory = self.queryFactory - else: - p.queryFactory = factory - return p - - - -class XMLRPCPublicLookupProcedureTests(unittest.TestCase): - """ - Tests for L{XMLRPC}'s support of subclasses which override - C{lookupProcedure} and C{listProcedures}. - """ - - def createServer(self, resource): - self.p = reactor.listenTCP( - 0, server.Site(resource), interface="127.0.0.1") - self.addCleanup(self.p.stopListening) - self.port = self.p.getHost().port - self.proxy = xmlrpc.Proxy('http://127.0.0.1:%d' % self.port) - - - def test_lookupProcedure(self): - """ - A subclass of L{XMLRPC} can override C{lookupProcedure} to find - procedures that are not defined using a C{xmlrpc_}-prefixed method name. - """ - self.createServer(TestLookupProcedure()) - what = "hello" - d = self.proxy.callRemote("echo", what) - d.addCallback(self.assertEqual, what) - return d - - - def test_errors(self): - """ - A subclass of L{XMLRPC} can override C{lookupProcedure} to raise - L{NoSuchFunction} to indicate that a requested method is not available - to be called, signalling a fault to the XML-RPC client. - """ - self.createServer(TestLookupProcedure()) - d = self.proxy.callRemote("xxxx", "hello") - d = self.assertFailure(d, xmlrpc.Fault) - return d - - - def test_listMethods(self): - """ - A subclass of L{XMLRPC} can override C{listProcedures} to define - Overriding listProcedures should prevent introspection from being - broken. - """ - resource = TestListProcedures() - addIntrospection(resource) - self.createServer(resource) - d = self.proxy.callRemote("system.listMethods") - def listed(procedures): - # The list will also include other introspection procedures added by - # addIntrospection. We just want to see "foo" from our customized - # listProcedures. - self.assertIn('foo', procedures) - d.addCallback(listed) - return d - - - -class SerializationConfigMixin: - """ - Mixin which defines a couple tests which should pass when a particular flag - is passed to L{XMLRPC}. - - These are not meant to be exhaustive serialization tests, since L{xmlrpclib} - does all of the actual serialization work. They are just meant to exercise - a few codepaths to make sure we are calling into xmlrpclib correctly. - - @ivar flagName: A C{str} giving the name of the flag which must be passed to - L{XMLRPC} to allow the tests to pass. Subclasses should set this. - - @ivar value: A value which the specified flag will allow the serialization - of. Subclasses should set this. - """ - def setUp(self): - """ - Create a new XML-RPC server with C{allowNone} set to C{True}. - """ - kwargs = {self.flagName: True} - self.p = reactor.listenTCP( - 0, server.Site(Test(**kwargs)), interface="127.0.0.1") - self.addCleanup(self.p.stopListening) - self.port = self.p.getHost().port - self.proxy = xmlrpc.Proxy( - "http://127.0.0.1:%d/" % (self.port,), **kwargs) - - - def test_roundtripValue(self): - """ - C{self.value} can be round-tripped over an XMLRPC method call/response. - """ - d = self.proxy.callRemote('defer', self.value) - d.addCallback(self.assertEqual, self.value) - return d - - - def test_roundtripNestedValue(self): - """ - A C{dict} which contains C{self.value} can be round-tripped over an - XMLRPC method call/response. - """ - d = self.proxy.callRemote('defer', {'a': self.value}) - d.addCallback(self.assertEqual, {'a': self.value}) - return d - - - -class XMLRPCAllowNoneTests(SerializationConfigMixin, unittest.TestCase): - """ - Tests for passing C{None} when the C{allowNone} flag is set. - """ - flagName = "allowNone" - value = None - - -class XMLRPCUseDateTimeTests(SerializationConfigMixin, unittest.TestCase): - """ - Tests for passing a C{datetime.datetime} instance when the C{useDateTime} - flag is set. - """ - flagName = "useDateTime" - value = datetime.datetime(2000, 12, 28, 3, 45, 59) - - -class XMLRPCAuthenticatedTests(XMLRPCTests): - """ - Test with authenticated proxy. We run this with the same inout/ouput as - above. - """ - user = "username" - password = "asecret" - - def setUp(self): - self.p = reactor.listenTCP(0, server.Site(TestAuthHeader()), - interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - - def test_authInfoInURL(self): - p = xmlrpc.Proxy("http://%s:%s@127.0.0.1:%d/" % ( - self.user, self.password, self.port)) - d = p.callRemote("authinfo") - d.addCallback(self.assertEqual, [self.user, self.password]) - return d - - - def test_explicitAuthInfo(self): - p = xmlrpc.Proxy("http://127.0.0.1:%d/" % ( - self.port,), self.user, self.password) - d = p.callRemote("authinfo") - d.addCallback(self.assertEqual, [self.user, self.password]) - return d - - - def test_longPassword(self): - """ - C{QueryProtocol} uses the C{base64.b64encode} function to encode user - name and password in the I{Authorization} header, so that it doesn't - embed new lines when using long inputs. - """ - longPassword = self.password * 40 - p = xmlrpc.Proxy("http://127.0.0.1:%d/" % ( - self.port,), self.user, longPassword) - d = p.callRemote("authinfo") - d.addCallback(self.assertEqual, [self.user, longPassword]) - return d - - - def test_explicitAuthInfoOverride(self): - p = xmlrpc.Proxy("http://wrong:info@127.0.0.1:%d/" % ( - self.port,), self.user, self.password) - d = p.callRemote("authinfo") - d.addCallback(self.assertEqual, [self.user, self.password]) - return d - - -class XMLRPCIntrospectionTests(XMLRPCTests): - - def setUp(self): - xmlrpc = Test() - addIntrospection(xmlrpc) - self.p = reactor.listenTCP(0, server.Site(xmlrpc),interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - def test_listMethods(self): - - def cbMethods(meths): - meths.sort() - self.assertEqual( - meths, - ['add', 'complex', 'defer', 'deferFail', - 'deferFault', 'dict', 'echo', 'fail', 'fault', - 'pair', 'system.listMethods', - 'system.methodHelp', - 'system.methodSignature', 'withRequest']) - - d = self.proxy().callRemote("system.listMethods") - d.addCallback(cbMethods) - return d - - def test_methodHelp(self): - inputOutputs = [ - ("defer", "Help for defer."), - ("fail", ""), - ("dict", "Help for dict.")] - - dl = [] - for meth, expected in inputOutputs: - d = self.proxy().callRemote("system.methodHelp", meth) - d.addCallback(self.assertEqual, expected) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def test_methodSignature(self): - inputOutputs = [ - ("defer", ""), - ("add", [['int', 'int', 'int'], - ['double', 'double', 'double']]), - ("pair", [['array', 'string', 'int']])] - - dl = [] - for meth, expected in inputOutputs: - d = self.proxy().callRemote("system.methodSignature", meth) - d.addCallback(self.assertEqual, expected) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - -class XMLRPCClientErrorHandlingTests(unittest.TestCase): - """ - Test error handling on the xmlrpc client. - """ - def setUp(self): - self.resource = static.Data( - "This text is not a valid XML-RPC response.", - "text/plain") - self.resource.isLeaf = True - self.port = reactor.listenTCP(0, server.Site(self.resource), - interface='127.0.0.1') - - def tearDown(self): - return self.port.stopListening() - - def test_erroneousResponse(self): - """ - Test that calling the xmlrpc client on a static http server raises - an exception. - """ - proxy = xmlrpc.Proxy("http://127.0.0.1:%d/" % - (self.port.getHost().port,)) - return self.assertFailure(proxy.callRemote("someMethod"), Exception) - - - -class QueryFactoryParseResponseTests(unittest.TestCase): - """ - Test the behaviour of L{_QueryFactory.parseResponse}. - """ - - def setUp(self): - # The _QueryFactory that we are testing. We don't care about any - # of the constructor parameters. - self.queryFactory = _QueryFactory( - path=None, host=None, method='POST', user=None, password=None, - allowNone=False, args=()) - # An XML-RPC response that will parse without raising an error. - self.goodContents = xmlrpclib.dumps(('',)) - # An 'XML-RPC response' that will raise a parsing error. - self.badContents = 'invalid xml' - # A dummy 'reason' to pass to clientConnectionLost. We don't care - # what it is. - self.reason = failure.Failure(ConnectionDone()) - - - def test_parseResponseCallbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as a callback - of L{_QueryFactory.parseResponse}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addCallback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.parseResponse(self.goodContents) - return d - - - def test_parseResponseErrbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as an errback - of L{_QueryFactory.parseResponse}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addErrback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.parseResponse(self.badContents) - return d - - - def test_badStatusErrbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as an errback - of L{_QueryFactory.badStatus}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addErrback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.badStatus('status', 'message') - return d - - def test_parseResponseWithoutData(self): - """ - Some server can send a response without any data: - L{_QueryFactory.parseResponse} should catch the error and call the - result errback. - """ - content = """ -<methodResponse> - <params> - <param> - </param> - </params> -</methodResponse>""" - d = self.queryFactory.deferred - self.queryFactory.parseResponse(content) - return self.assertFailure(d, IndexError) - - - -class XMLRPCWithRequestTests(unittest.TestCase): - - def setUp(self): - self.resource = Test() - - - def test_withRequest(self): - """ - When an XML-RPC method is called and the implementation is - decorated with L{withRequest}, the request object is passed as - the first argument. - """ - request = DummyRequest('/RPC2') - request.method = "POST" - request.content = StringIO(xmlrpclib.dumps(("foo",), 'withRequest')) - def valid(n, request): - data = xmlrpclib.loads(request.written[0]) - self.assertEqual(data, (('POST foo',), None)) - d = request.notifyFinish().addCallback(valid, request) - self.resource.render_POST(request) - return d diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/NEWS deleted file mode 100644 index c577978..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/NEWS +++ /dev/null @@ -1,782 +0,0 @@ -Ticket numbers in this file can be looked up by visiting -http://twistedmatrix.com/trac/ticket/<number> - -Twisted Web 15.2.1 (2015-05-23) -=============================== - -No significant changes have been made for this release. - - -Twisted Web 15.2.0 (2015-05-18) -=============================== - -Features --------- - - twisted.web.static is now ported to Python 3. (#6177) - - twisted.web.server.Site accepts requestFactory as constructor - argument. (#7016) - -Deprecations and Removals -------------------------- - - twisted.web.util had some HTML generation functions deprecated - since 12.1 that have now been removed. (#7828) - -Other ------ - - #6927, #7797, #7802, #7846 - - -Twisted Web 15.1.0 (2015-04-02) -=============================== - -Features --------- - - twisted.web.static.File allows defining a custom resource for - rendering forbidden pages. (#6951) - -Other ------ - - #7000, #7485, #7750, #7762 - - -Twisted Web 15.0.0 (2015-01-24) -=============================== - -Features --------- - - twisted.web.client.Agent.usingEndpointFactory allows creating an - Agent that connects in non-standard ways, e.g. via a proxy or a - UNIX socket. (#6634) - - The Deferred returned by twisted.web.client.readBody can now be - cancelled. (#6686) - -Deprecations and Removals -------------------------- - - twisted.web.iweb.IRequest.getClient is now deprecated. Its - implementation in Twisted, twisted.web.http.Request.getClient, is - also deprecated and will no longer attempt to resolve the client IP - address to a hostname. (#2252) - -Other ------ - - #7247, #7302, #7680, #7689 - - -Twisted Web 14.0.2 (2014-09-18) -=============================== - -No significant changes have been made for this release. - - -Twisted Web 14.0.1 (2014-09-17) -=============================== - -Bugfixes --------- - - BrowserLikePolicyForHTTPS would always ignore the specified - trustRoot and use the system trust root instead, which has been - rectified. (#7647) - - -Twisted Web 14.0.0 (2014-05-08) -=============================== - -Features --------- - - twisted.web.http.proxiedLogFormatter can now be used with - twisted.web.http.HTTPFactory (and subclasses) to record X - -Forwarded-For values to the access log when the HTTP server is - deployed behind a reverse proxy. (#1468) - - twisted.web.client.Agent now uses - twisted.internet.ssl.CertificateOptions for SSL/TLS and benefits - from its continuous improvements. (#6893) - -Bugfixes --------- - - twisted.web.client.Agent now correctly manage flow-control on - pooled connections, and therefore requests will no longer hang - sometimes when deliverBody is not called synchronously within the - callback on Request. (#6751) - - twisted.web.client.Agent now verifies that the provided server - certificate in a TLS connection is trusted by the platform. (#7042) - - When requesting an HTTPS URL with twisted.web.client.Agent, the - hostname of the presented certificate will be checked against the - requested hostname; mismatches will now result in an error rather - than a man-in-the-middle opportunity for attackers. This may break - existing code that incorrectly depended on insecure behavior, but - such code was erroneous and should be updated. (#4888) - -Other ------ - - #5004, #6881, #6956 - - -Twisted Web 13.2.0 (2013-10-29) -=============================== - -Features --------- - - IAgent has been added to twisted.web.iweb to explicitly define the - interface implemented by the various "Agent" classes in - twisted.web.client. (#6702) - -Bugfixes --------- - - twisted.web.client.Response.deliverBody now calls connectionLost on - the body protocol for responses with no body (such as 204, 304, and - HEAD requests). (#5476) - - twisted.web.static.loadMimeTypes now uses all available system MIME - types. (#5717) - -Deprecations and Removals -------------------------- - - Two attributes of twisted.web.iweb.IRequest, headers and - received_headers, are now deprecated. (#6704) - -Other ------ - - #5387, #6119, #6121, #6695, #6701, #6734 - - -Twisted Web 13.1.0 (2013-06-23) -=============================== - -Features --------- - - The deferred returned by twisted.web.client.Agent.request can now - be cancelled. (#4330) - - twisted.web.client.BrowserLikeRedirectAgent, a new redirect agent, - treats HTTP 301 and 302 like HTTP 303 on non-HEAD/GET requests, - changing the method to GET before proceeding. (#5434) - - The new attribute twisted.web.iweb.IResponse.request is a reference - to a provider of the new twisted.web.iweb.IClientRequest interface - which, among other things, provides a way to access the request's - absolute URI. It is now also possible to inspect redirect history - with twisted.web.iweb.IResponse.previousResponse. (#5435) - - twisted.web.client.RedirectAgent now supports relative URI - references in the Location HTTP header. (#5462) - - twisted.web.client now provides readBody to collect the body of a - response from Agent into a string. (#6251) - -Bugfixes --------- - - twisted.web.xmlrpc.QueryProtocol now generates valid Authorization - headers for long user names and passwords. (#2980) - -Other ------ - - #6122, #6153, #6342, #6381, #6391, #6503 - - -Twisted Web 13.0.0 (2013-03-19) -=============================== - -Bugfixes --------- - - twisted.web.template now properly quotes attribute values, - including Tag instances serialized within attribute values. (#6275) - -Other ------ - - #6167, #6297, #6326 - - -Twisted Web 12.3.0 (2012-12-20) -=============================== - -Features --------- - - twisted.web.server.Site now supports an encoders argument to encode - request content, twisted.web.server.GzipEncoderFactory being the - first one provided. (#104) - -Bugfixes --------- - - twisted.web.http.HTTPChannel.headerReceived now catches the error - if the Content-Length header is not an integer and return a 400 Bad - Request response. (#6029) - - twisted.web.http.HTTPChannel now drops the connection and issues a - 400 error upon receipt of a chunk-encoding encoded request with a - bad chunk-length field. (#6030) - -Improved Documentation ----------------------- - - twisted.web.iweb.IRequest now documents its `content` attribute and - a new "web in 60 seconds" howto demonstrates its use. (#6181) - -Other ------ - - #5882, #5883, #5887, #5920, #6031, #6077, #6078, #6079, #6080, - #6110, #6113, #6196, #6205 - - -Twisted Web 12.2.0 (2012-08-26) -=============================== - -Deprecations and Removals -------------------------- - - twisted.web.static.FileTransfer, deprecated since 9.0, is removed - now. Use a subclass of StaticProducer instead. (#5651) - - ErrorPage, NoResource and ForbiddenResource in twisted.web.error - were deprecated since 9.0 and are removed now. (#5659) - - twisted.web.google, deprecated since Twisted 11.1, is removed now. - (#5768) - -Other ------ - - #5665 - - -Twisted Web 12.1.0 (2012-06-02) -=============================== - -Features --------- - - twisted.web.client.Agent and ProxyAgent now support persistent - connections. (#3420) - - Added twisted.web.template.renderElement, a function which renders - an Element to a response. (#5395) - - twisted.web.client.HTTPConnectionPool now ensures that failed - queries on persistent connections are retried, when possible. - (#5479) - - twisted.web.template.XMLFile now supports FilePath objects. (#5509) - - twisted.web.template.renderElement takes a doctype keyword - argument, which will be written as the first line of the response, - defaulting to the HTML5 doctype. (#5560) - -Bugfixes --------- - - twisted.web.util.formatFailure now quotes all data in its output to - avoid it being mistakenly interpreted as markup. (#4896) - - twisted.web.distrib now lets distributed servers set the response - message. (#5525) - -Deprecations and Removals -------------------------- - - PHP3Script and PHPScript were removed from twisted.web.twcgi, - deprecated since 10.1. Use twcgi.FilteredScript instead. (#5456) - - twisted.web.template.XMLFile's support for file objects and - filenames is now deprecated. Use the new support for FilePath - objects. (#5509) - - twisted.web.server.date_time_string and - twisted.web.server.string_date_time are now deprecated in favor of - twisted.web.http.datetimeToString and twisted.web. - http.stringToDatetime (#5535) - -Other ------ - - #4966, #5460, #5490, #5591, #5602, #5609, #5612 - - -Twisted Web 12.0.0 (2012-02-10) -=============================== - -Features --------- - - twisted.web.util.redirectTo now raises TypeError if the URL passed - to it is a unicode string instead of a byte string. (#5236) - - The new class twisted.web.template.CharRef provides support for - inserting numeric character references in output generated by - twisted.web.template. (#5408) - -Improved Documentation ----------------------- - - The Twisted Web howto now has a section on proxies and reverse - proxies. (#399) - - The web client howto now covers ContentDecoderAgent and links to an - example of its use. (#5415) - -Other ------ - - #5404, #5438 - - -Twisted Web 11.1.0 (2011-11-15) -=============================== - -Features --------- - - twisted.web.client.ProxyAgent is a new HTTP/1.1 web client which - adds proxy support. (#1774) - - twisted.web.client.Agent now takes optional connectTimeout and - bindAddress arguments which are forwarded to the subsequent - connectTCP/connectSSL call. (#3450) - - The new class twisted.web.client.FileBodyProducer makes it easy to - upload data in HTTP requests made using the Agent client APIs. - (#4017) - - twisted.web.xmlrpc.XMLRPC now allows its lookupProcedure method to - be overridden to change how XML-RPC procedures are dispatched. - (#4836) - - A new HTTP cookie-aware Twisted Web Agent wrapper is included in - twisted.web.client.CookieAgent (#4922) - - New class twisted.web.template.TagLoader provides an - ITemplateLoader implementation which loads already-created - twisted.web.iweb.IRenderable providers. (#5040) - - The new class twisted.web.client.RedirectAgent adds redirect - support to the HTTP 1.1 client stack. (#5157) - - twisted.web.template now supports HTML tags from the HTML5 - standard, including <canvas> and <video>. (#5306) - -Bugfixes --------- - - twisted.web.client.getPage and .downloadPage now only fire their - result Deferred after the underlying connection they use has been - closed. (#3796) - - twisted.web.server now omits the default Content-Type header from - NOT MODIFIED responses. (#4156) - - twisted.web.server now responds correctly to 'Expect: 100-continue' - headers, although this is not yet usefully exposed to user code. - (#4673) - - twisted.web.client.Agent no longer raises an exception if a server - responds and closes the connection before the request has been - fully transmitted. (#5013) - - twisted.web.http_headers.Headers now correctly capitalizes the - header names Content-MD5, DNT, ETag, P3P, TE, and X-XSS-Protection. - (#5054) - - twisted.web.template now escapes more inputs to comments which - require escaping in the output. (#5275) - -Improved Documentation ----------------------- - - The twisted.web.template howto now documents the common idiom of - yielding tag clones from a renderer. (#5286) - - CookieAgent is now documented in the twisted.web.client how-to. - (#5110) - -Deprecations and Removals -------------------------- - - twisted.web.google is now deprecated. (#5209) - -Other ------ - - #4951, #5057, #5175, #5288, #5316 - - -Twisted Web 11.0.0 (2011-04-01) -=============================== - -Features --------- - - twisted.web._newclient.HTTPParser (and therefore Agent) now handles - HTTP headers delimited by bare LF newlines. (#3833) - - twisted.web.client.downloadPage now accepts the `afterFoundGet` - parameter, with the same meaning as the `getPage` parameter of the - same name. (#4364) - - twisted.web.xmlrpc.Proxy constructor now takes additional 'timeout' - and 'reactor' arguments. The 'timeout' argument defaults to 30 - seconds. (#4741) - - Twisted Web now has a templating system, twisted.web.template, - which is a direct, simplified derivative of Divmod Nevow. (#4939) - -Bugfixes --------- - - HTTPPageGetter now adds the port to the host header if it is not - the default for that scheme. (#3857) - - twisted.web.http.Request.write now raises an exception if it is - called after response generation has already finished. (#4317) - - twisted.web.client.HTTPPageGetter and twisted.web.client.getPage - now no longer make two requests when using afterFoundGet. (#4760) - - twisted.web.twcgi no longer adds an extra "content-type" header to - CGI responses. (#4786) - - twisted.web will now properly specify an encoding (UTF-8) on error, - redirect, and directory listing pages, so that IE7 and previous - will not improperly guess the 'utf7' encoding in these cases. - Please note that Twisted still sets a *default* content-type of - 'text/html', and you shouldn't rely on that: you should set the - encoding appropriately in your application. (#4900) - - twisted.web.http.Request.setHost now sets the port in the host - header if it is not the default. (#4918) - - default NOT_IMPLEMENTED and NOT_ALLOWED pages now quote the request - method and URI respectively, to protect against browsers which - don't quote those values for us. (#4978) - -Improved Documentation ----------------------- - - The XML-RPC howto now includes an example demonstrating how to - access the HTTP request object in a server-side XML-RPC method. - (#4732) - - The Twisted Web client howto now uses the correct, public name for - twisted.web.client.Response. (#4769) - - Some broken links were fixed, descriptions were updated, and new - API links were added in the Resource Templating documentation - (resource-templates.xhtml) (#4968) - -Other ------ - - #2271, #2386, #4162, #4733, #4855, #4911, #4973 - - -Twisted Web 10.2.0 (2010-11-29) -=============================== - -Features --------- - - twisted.web.xmlrpc.XMLRPC.xmlrpc_* methods can now be decorated - using withRequest to cause them to be passed the HTTP request - object. (#3073) - -Bugfixes --------- - - twisted.web.xmlrpc.QueryProtocol.handleResponse now disconnects - from the server, meaning that Twisted XML-RPC clients disconnect - from the server as soon as they receive a response, rather than - relying on the server to disconnect. (#2518) - - twisted.web.twcgi now generates responses containing all - occurrences of duplicate headers produced by CGI scripts, not just - the last value. (#4742) - -Deprecations and Removals -------------------------- - - twisted.web.trp, which has been deprecated since Twisted 9.0, was - removed. (#4299) - -Other ------ - - #4576, #4577, #4709, #4723 - - -Twisted Web 10.1.0 (2010-06-27) -=============================== - -Features --------- - - twisted.web.xmlrpc.XMLRPC and twisted.web.xmlrpc.Proxy now expose - xmlrpclib's support of datetime.datetime objects if useDateTime is - set to True. (#3219) - - HTTP11ClientProtocol now has an abort() method for cancelling an - outstanding request by closing the connection before receiving the - entire response. (#3811) - - twisted.web.http_headers.Headers initializer now rejects - incorrectly structured dictionaries. (#4022) - - twisted.web.client.Agent now supports HTTPS URLs. (#4023) - - twisted.web.xmlrpc.Proxy.callRemote now returns a Deferred which - can be cancelled to abort the attempted XML-RPC call. (#4377) - -Bugfixes --------- - - twisted.web.guard now logs out avatars even if a request completes - with an error. (#4411) - - twisted.web.xmlrpc.XMLRPC will now no longer trigger a RuntimeError - by trying to write responses to closed connections. (#4423) - -Improved Documentation ----------------------- - - Fix broken links to deliverBody and iweb.UNKNOWN_LENGTH in - doc/web/howto/client.xhtml. (#4507) - -Deprecations and Removals -------------------------- - - twisted.web.twcgi.PHP3Script and twisted.web.twcgi.PHPScript are - now deprecated. (#516) - -Other ------ - - #4403, #4452 - - -Twisted Web 10.0.0 (2010-03-01) -=============================== - -Features --------- - - Twisted Web in 60 Seconds, a series of short tutorials with self- - contained examples on a range of common web topics, is now a part - of the Twisted Web howto documentation. (#4192) - -Bugfixes --------- - - Data and File from twisted.web.static and - twisted.web.distrib.UserDirectory will now only generate a 200 - response for GET or HEAD requests. - twisted.web.client.HTTPPageGetter will no longer ignore the case of - a request method when considering whether to apply special HEAD - processing to a response. (#446) - - - twisted.web.http.HTTPClient now supports multi-line headers. - (#2062) - - - Resources served via twisted.web.distrib will no longer encounter a - Banana error when writing more than 640kB at once to the request - object. (#3212) - - - The Error, PageRedirect, and InfiniteRedirection exception in - twisted.web now initialize an empty message parameter by mapping - the HTTP status code parameter to a descriptive string. Previously - the lookup would always fail, leaving message empty. (#3806) - - - The 'wsgi.input' WSGI environment object now supports -1 and None - as arguments to the read and readlines methods. (#4114) - - - twisted.web.wsgi doesn't unquote QUERY_STRING anymore, thus - complying with the WSGI reference implementation. (#4143) - - - The HTTP proxy will no longer pass on keep-alive request headers - from the client, preventing pages from loading then "hanging" - (leaving the connection open with no hope of termination). (#4179) - -Deprecations and Removals -------------------------- - - Remove '--static' option from twistd web, that served as an alias - for the '--path' option. (#3907) - -Other ------ - - #3784, #4216, #4242 - - -Twisted Web 9.0.0 (2009-11-24) -============================== - -Features --------- - - There is now an iweb.IRequest interface which specifies the interface that - request objects provide (#3416) - - downloadPage now supports the same cookie, redirect, and timeout features - that getPage supports (#2971) - - A chapter about WSGI has been added to the twisted.web documentation (#3510) - - The HTTP auth support in the web server now allows anonymous sessions by - logging in with ANONYMOUS credentials when no Authorization header is - provided in a request (#3924, #3936) - - HTTPClientFactory now accepts a parameter to enable a common deviation from - the HTTP 1.1 standard by responding to redirects in a POSTed request with a - GET instead of another POST (#3624) - - A new basic HTTP/1.1 client API is included in twisted.web.client.Agent - (#886, #3987) - -Fixes ------ - - Requests for "insecure" children of a static.File (such as paths containing - encoded directory separators) will now result in a 404 instead of a 500 - (#3549, #3469) - - When specifying a followRedirect argument to the getPage function, the state - of redirect-following for other getPage calls should now be unaffected. It - was previously overwriting a class attribute which would affect outstanding - getPage calls (#3192) - - Downloading an URL of the form "http://example.com:/" will now work, - ignoring the extraneous colon (#2402) - - microdom's appendChild method will no longer issue a spurious warning, and - microdom's methods in general should now issue more meaningful exceptions - when invalid parameters are passed (#3421) - - WSGI applications will no longer have spurious Content-Type headers added to - their responses by the twisted.web server. In addition, WSGI applications - will no longer be able to specify the server-restricted headers Server and - Date (#3569) - - http_headers.Headers now normalizes the case of raw headers passed directly - to it in the same way that it normalizes the headers passed to setRawHeaders - (#3557) - - The distrib module no longer relies on the deprecated woven package (#3559) - - twisted.web.domhelpers now works with both microdom and minidom (#3600) - - twisted.web servers will now ignore invalid If-Modified-Since headers instead - of returning a 500 error (#3601) - - Certain request-bound memory and file resources are cleaned up slightly - sooner by the request when the connection is lost (#1621, #3176) - - xmlrpclib.DateTime objects should now correctly round-trip over twisted.web's - XMLRPC support in all supported versions of Python, and errors during error - serialization will no longer hang a twisted.web XMLRPC response (#2446) - - request.content should now always be seeked to the beginning when - request.process is called, so application code should never need to seek - back manually (#3585) - - Fetching a child of static.File with a double-slash in the URL (such as - "example//foo.html") should now return a 404 instead of a traceback and - 500 error (#3631) - - downloadPage will now fire a Failure on its returned Deferred instead of - indicating success when the connection is prematurely lost (#3645) - - static.File will now provide a 404 instead of a 500 error when it was - constructed with a non-existent file (#3634) - - microdom should now serialize namespaces correctly (#3672) - - The HTTP Auth support resource wrapper should no longer corrupt requests and - cause them to skip a segment in the request path (#3679) - - The twisted.web WSGI support should now include leading slashes in PATH_INFO, - and SCRIPT_NAME will be empty if the application is at the root of the - resource tree. This means that WSGI applications should no longer generate - URLs with double-slashes in them even if they naively concatenate the values - (#3721) - - WSGI applications should now receive the requesting client's IP in the - REMOTE_ADDR environment variable (#3730) - - The distrib module should work again. It was unfortunately broken with the - refactoring of twisted.web's header support (#3697) - - static.File now supports multiple ranges specified in the Range header - (#3574) - - static.File should now generate a correct Content-Length value when the - requested Range value doesn't fit entirely within the file's contents (#3814) - - Attempting to call request.finish() after the connection has been lost will - now immediately raise a RuntimeError (#4013) - - An HTTP-auth resource should now be able to directly render the wrapped - avatar, whereas before it would only allow retrieval of child resources - (#4014) - - twisted.web's wsgi support should no longer attempt to call request.finish - twice, which would cause errors in certain cases (#4025) - - WSGI applications should now be able to handle requests with large bodies - (#4029) - - Exceptions raised from WSGI applications should now more reliably be turned - into 500 errors on the HTTP level (#4019) - - DeferredResource now correctly passes through exceptions raised from the - wrapped resource, instead of turning them all into 500 errors (#3932) - - Agent.request now generates a Host header when no headers are passed at - (#4131) - -Deprecations and Removals -------------------------- - - The unmaintained and untested twisted.web.monitor module was removed (#2763) - - The twisted.web.woven package has been removed (#1522) - - All of the error resources in twisted.web.error are now in - twisted.web.resource, and accessing them through twisted.web.error is now - deprecated (#3035) - - To facilitate a simplification of the timeout logic in server.Session, - various things have been deprecated (#3457) - - the loopFactory attribute is now ignored - - the checkExpired method now does nothing - - the lifetime parameter to startCheckingExpiration is now ignored - - The twisted.web.trp module is now deprecated (#2030) - -Other ------ - - #2763, #3540, #3575, #3610, #3605, #1176, #3539, #3750, #3761, #3779, #2677, - #3782, #3904, #3919, #3418, #3990, #1404, #4050 - - -Web 8.2.0 (2008-12-16) -====================== - -Features --------- - - The web server can now deal with multi-value headers in the new attributes of - Request, requestHeaders and responseHeaders (#165) - - There is now a resource-wrapper which implements HTTP Basic and Digest auth - in terms of twisted.cred (#696) - - It's now possible to limit the number of redirects that client.getPage will - follow (#2412) - - The directory-listing code no longer uses Woven (#3257) - - static.File now supports Range headers with a single range (#1493) - - twisted.web now has a rudimentary WSGI container (#2753) - - The web server now supports chunked encoding in requests (#3385) - -Fixes ------ - - The xmlrpc client now raises an error when the server sends an empty - response (#3399) - - HTTPPageGetter no longer duplicates default headers when they're explicitly - overridden in the headers parameter (#1382) - - The server will no longer timeout clients which are still sending request - data (#1903) - - microdom's isEqualToNode now returns False when the nodes aren't equal - (#2542) - -Deprecations and Removals -------------------------- - - - Request.headers and Request.received_headers are not quite deprecated, but - they are discouraged in favor of requestHeaders and responseHeaders (#165) - -Other ------ - - #909, #687, #2938, #1152, #2930, #2025, #2683, #3471 - - -8.1.0 (2008-05-18) -================== - -Fixes ------ - - - Fixed an XMLRPC bug whereby sometimes a callRemote Deferred would - accidentally be fired twice when a connection was lost during the handling of - a response (#3152) - - Fixed a bug in the "Using Twisted Web" document which prevented an example - resource from being renderable (#3147) - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Add support to twisted.web.client.getPage for the HTTP HEAD method. (#2750) - -Fixes ------ - - Set content-type in xmlrpc responses to "text/xml" (#2430) - - Add more error checking in the xmlrpc.XMLRPC render method, and enforce - POST requests. (#2505) - - Reject unicode input to twisted.web.client._parse to reject invalid - unicode URLs early. (#2628) - - Correctly re-quote URL path segments when generating an URL string to - return from Request.prePathURL. (#2934) - - Make twisted.web.proxy.ProxyClientFactory close the connection when - reporting a 501 error. (#1089) - - Fix twisted.web.proxy.ReverseProxyResource to specify the port in the - host header if different from 80. (#1117) - - Change twisted.web.proxy.ReverseProxyResource so that it correctly encodes - the request URI it sends on to the server for which it is a proxy. (#3013) - - Make "twistd web --personal" use PBServerFactory (#2681) - -Misc ----- - - #1996, #2382, #2211, #2633, #2634, #2640, #2752, #238, #2905 - - -0.7.0 (2007-01-02) -================== - -Features --------- - - Python 2.5 is now supported (#1867) - - twisted.web.xmlrpc now supports the <nil/> xml-rpc extension type - in both the server and the client (#469) - -Fixes ------ - - Microdom and SUX now manages certain malformed XML more resiliently - (#1984, #2225, #2298) - - twisted.web.client.getPage can now deal with an URL of the form - "http://example.com" (no trailing slash) (#1080) - - The HTTP server now allows (invalid) URLs with multiple question - marks (#1550) - - '=' can now be in the value of a cookie (#1051) - - Microdom now correctly handles xmlns="" (#2184) - -Deprecations and Removals -------------------------- - - websetroot was removed, because it wasn't working anyway (#945) - - woven.guard no longer supports the old twisted.cred API (#1440) - -Other ------ -The following changes are minor or closely related to other changes. - - - #1636, #1637, #1638, #1936, #1883, #447 - - -0.6.0 (2006-05-21) -================== - -Features --------- - - Basic auth support for the XMLRPC client (#1474). - -Fixes ------ - - More correct datetime parsing. - - Efficiency improvements (#974) - - Handle popular non-RFC compliant formats for If-Modified-Since - headers (#976). - - Improve support for certain buggy CGI scripts. - - CONTENT_LENGTH is now available to CGI scripts. - - Support for even worse HTML in microdom (#1358). - - Trying to view a user's home page when the user doesn't have a - ~/public_html no longer displays a traceback (#551). - - Misc: #543, #1011, #1005, #1287, #1337, #1383, #1079, #1492, #1189, - #737, #872. - - -0.5.0 -===== - - Client properly reports timeouts as error - - "Socially deprecate" woven - - Fix memory leak in _c_urlarg library - - Stop using _c_urlarg library - - Fix 'gzip' and 'bzip2' content-encodings - - Escape log entries so remote user cannot corrupt the log - - Commented out range support because it's broken - - Fix HEAD responses without content-length diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/README deleted file mode 100644 index fd09eb3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/README +++ /dev/null @@ -1,6 +0,0 @@ -Twisted Web 15.2.1 - -Twisted Web depends on Twisted Core. pyOpenSSL -(<https://github.com/pyca/pyopenssl>) is also required for HTTPS. SOAPpy -(<http://pywebsvcs.sourceforge.net/>) is required for SOAP support. For Quixote -resource templates, Quixote (<http://www.quixote.ca/>) is required. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/setup.py deleted file mode 100644 index dd23923..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/topfiles/setup.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="web", - scripts=dist.getScripts("web"), - # metadata - name="Twisted Web", - description="Twisted web server, programmable in Python.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="James Knight", - url="http://twistedmatrix.com/trac/wiki/TwistedWeb", - license="MIT", - long_description="""\ -Twisted Web is a complete web server, aimed at hosting web -applications using Twisted and Python, but fully able to serve static -pages, also. -""", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Internet :: WWW/HTTP :: HTTP Servers", - "Topic :: Internet :: WWW/HTTP :: WSGI", - "Topic :: Software Development :: Libraries :: Python Modules", - ], - ) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/twcgi.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/twcgi.py deleted file mode 100644 index 88cdfc0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/twcgi.py +++ /dev/null @@ -1,304 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_cgi -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I hold resource classes and helper classes that deal with CGI scripts. -""" - -# System Imports -import os -import urllib - -# Twisted Imports -from twisted.web import http -from twisted.internet import protocol -from twisted.spread import pb -from twisted.python import log, filepath -from twisted.web import resource, server, static - - -class CGIDirectory(resource.Resource, filepath.FilePath): - def __init__(self, pathname): - resource.Resource.__init__(self) - filepath.FilePath.__init__(self, pathname) - - def getChild(self, path, request): - fnp = self.child(path) - if not fnp.exists(): - return static.File.childNotFound - elif fnp.isdir(): - return CGIDirectory(fnp.path) - else: - return CGIScript(fnp.path) - return resource.NoResource() - - def render(self, request): - notFound = resource.NoResource( - "CGI directories do not support directory listing.") - return notFound.render(request) - - - -class CGIScript(resource.Resource): - """ - L{CGIScript} is a resource which runs child processes according to the CGI - specification. - - The implementation is complex due to the fact that it requires asynchronous - IPC with an external process with an unpleasant protocol. - """ - isLeaf = 1 - def __init__(self, filename, registry=None, reactor=None): - """ - Initialize, with the name of a CGI script file. - """ - self.filename = filename - if reactor is None: - # This installs a default reactor, if None was installed before. - # We do a late import here, so that importing the current module - # won't directly trigger installing a default reactor. - from twisted.internet import reactor - self._reactor = reactor - - - def render(self, request): - """ - Do various things to conform to the CGI specification. - - I will set up the usual slew of environment variables, then spin off a - process. - - @type request: L{twisted.web.http.Request} - @param request: An HTTP request. - """ - script_name = "/" + "/".join(request.prepath) - serverName = request.getRequestHostname().split(':')[0] - env = {"SERVER_SOFTWARE": server.version, - "SERVER_NAME": serverName, - "GATEWAY_INTERFACE": "CGI/1.1", - "SERVER_PROTOCOL": request.clientproto, - "SERVER_PORT": str(request.getHost().port), - "REQUEST_METHOD": request.method, - "SCRIPT_NAME": script_name, # XXX - "SCRIPT_FILENAME": self.filename, - "REQUEST_URI": request.uri, - } - - ip = request.getClientIP() - if ip is not None: - env['REMOTE_ADDR'] = ip - pp = request.postpath - if pp: - env["PATH_INFO"] = "/" + "/".join(pp) - - if hasattr(request, "content"): - # request.content is either a StringIO or a TemporaryFile, and - # the file pointer is sitting at the beginning (seek(0,0)) - request.content.seek(0,2) - length = request.content.tell() - request.content.seek(0,0) - env['CONTENT_LENGTH'] = str(length) - - try: - qindex = request.uri.index('?') - except ValueError: - env['QUERY_STRING'] = '' - qargs = [] - else: - qs = env['QUERY_STRING'] = request.uri[qindex+1:] - if '=' in qs: - qargs = [] - else: - qargs = [urllib.unquote(x) for x in qs.split('+')] - - # Propagate HTTP headers - for title, header in request.getAllHeaders().items(): - envname = title.replace('-', '_').upper() - if title not in ('content-type', 'content-length'): - envname = "HTTP_" + envname - env[envname] = header - # Propagate our environment - for key, value in os.environ.items(): - if key not in env: - env[key] = value - # And they're off! - self.runProcess(env, request, qargs) - return server.NOT_DONE_YET - - - def runProcess(self, env, request, qargs=[]): - """ - Run the cgi script. - - @type env: A C{dict} of C{str}, or C{None} - @param env: The environment variables to pass to the processs that will - get spawned. See - L{twisted.internet.interfaces.IReactorProcess.spawnProcess} for more - information about environments and process creation. - - @type request: L{twisted.web.http.Request} - @param request: An HTTP request. - - @type qargs: A C{list} of C{str} - @param qargs: The command line arguments to pass to the process that - will get spawned. - """ - p = CGIProcessProtocol(request) - self._reactor.spawnProcess(p, self.filename, [self.filename] + qargs, - env, os.path.dirname(self.filename)) - - - -class FilteredScript(CGIScript): - """ - I am a special version of a CGI script, that uses a specific executable. - - This is useful for interfacing with other scripting languages that adhere to - the CGI standard. My C{filter} attribute specifies what executable to run, - and my C{filename} init parameter describes which script to pass to the - first argument of that script. - - To customize me for a particular location of a CGI interpreter, override - C{filter}. - - @type filter: C{str} - @ivar filter: The absolute path to the executable. - """ - - filter = '/usr/bin/cat' - - - def runProcess(self, env, request, qargs=[]): - """ - Run a script through the C{filter} executable. - - @type env: A C{dict} of C{str}, or C{None} - @param env: The environment variables to pass to the processs that will - get spawned. See - L{twisted.internet.interfaces.IReactorProcess.spawnProcess} for more - information about environments and process creation. - - @type request: L{twisted.web.http.Request} - @param request: An HTTP request. - - @type qargs: A C{list} of C{str} - @param qargs: The command line arguments to pass to the process that - will get spawned. - """ - p = CGIProcessProtocol(request) - self._reactor.spawnProcess(p, self.filter, - [self.filter, self.filename] + qargs, env, - os.path.dirname(self.filename)) - - - -class CGIProcessProtocol(protocol.ProcessProtocol, pb.Viewable): - handling_headers = 1 - headers_written = 0 - headertext = '' - errortext = '' - - # Remotely relay producer interface. - - def view_resumeProducing(self, issuer): - self.resumeProducing() - - def view_pauseProducing(self, issuer): - self.pauseProducing() - - def view_stopProducing(self, issuer): - self.stopProducing() - - def resumeProducing(self): - self.transport.resumeProducing() - - def pauseProducing(self): - self.transport.pauseProducing() - - def stopProducing(self): - self.transport.loseConnection() - - def __init__(self, request): - self.request = request - - def connectionMade(self): - self.request.registerProducer(self, 1) - self.request.content.seek(0, 0) - content = self.request.content.read() - if content: - self.transport.write(content) - self.transport.closeStdin() - - def errReceived(self, error): - self.errortext = self.errortext + error - - def outReceived(self, output): - """ - Handle a chunk of input - """ - # First, make sure that the headers from the script are sorted - # out (we'll want to do some parsing on these later.) - if self.handling_headers: - text = self.headertext + output - headerEnds = [] - for delimiter in '\n\n','\r\n\r\n','\r\r', '\n\r\n': - headerend = text.find(delimiter) - if headerend != -1: - headerEnds.append((headerend, delimiter)) - if headerEnds: - # The script is entirely in control of response headers; disable the - # default Content-Type value normally provided by - # twisted.web.server.Request. - self.request.defaultContentType = None - - headerEnds.sort() - headerend, delimiter = headerEnds[0] - self.headertext = text[:headerend] - # This is a final version of the header text. - linebreak = delimiter[:len(delimiter)//2] - headers = self.headertext.split(linebreak) - for header in headers: - br = header.find(': ') - if br == -1: - log.msg( - format='ignoring malformed CGI header: %(header)r', - header=header) - else: - headerName = header[:br].lower() - headerText = header[br+2:] - if headerName == 'location': - self.request.setResponseCode(http.FOUND) - if headerName == 'status': - try: - statusNum = int(headerText[:3]) #"XXX <description>" sometimes happens. - except: - log.msg( "malformed status header" ) - else: - self.request.setResponseCode(statusNum) - else: - # Don't allow the application to control these required headers. - if headerName.lower() not in ('server', 'date'): - self.request.responseHeaders.addRawHeader(headerName, headerText) - output = text[headerend+len(delimiter):] - self.handling_headers = 0 - if self.handling_headers: - self.headertext = text - if not self.handling_headers: - self.request.write(output) - - def processEnded(self, reason): - if reason.value.exitCode != 0: - log.msg("CGI %s exited with exit code %s" % - (self.request.uri, reason.value.exitCode)) - if self.errortext: - log.msg("Errors from CGI %s: %s" % (self.request.uri, self.errortext)) - if self.handling_headers: - log.msg("Premature end of headers in %s: %s" % (self.request.uri, self.headertext)) - self.request.write( - resource.ErrorPage(http.INTERNAL_SERVER_ERROR, - "CGI Script Error", - "Premature end of script headers.").render(self.request)) - self.request.unregisterProducer() - self.request.finish() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/util.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/util.py deleted file mode 100644 index 3aa7cfc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/util.py +++ /dev/null @@ -1,371 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_util -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An assortment of web server-related utilities. -""" - -from __future__ import division, absolute_import - -import linecache - -from twisted.python.compat import _PY3, unicode, nativeString -from twisted.python.reflect import fullyQualifiedName -from twisted.python.modules import getModule - -from twisted.web import resource - -if not _PY3: - # TODO: Remove when twisted.web.template and _flatten is ported - # https://tm.tl/#7811 - from twisted.web.template import ( - TagLoader, XMLFile, Element, renderer, flattenString) - # TODO: Remove when twisted.python.urlpath is ported - # https://tm.tl/#7831 - from twisted.python import urlpath -else: - Element = object - renderer = XMLFile = lambda a: a - - -def redirectTo(URL, request): - """ - Generate a redirect to the given location. - - @param URL: A L{bytes} giving the location to which to redirect. - @type URL: L{bytes} - - @param request: The request object to use to generate the redirect. - @type request: L{IRequest<twisted.web.iweb.IRequest>} provider - - @raise TypeError: If the type of C{URL} a L{unicode} instead of L{bytes}. - - @return: A C{bytes} containing HTML which tries to convince the client agent - to visit the new location even if it doesn't respect the I{FOUND} - response code. This is intended to be returned from a render method, - eg:: - - def render_GET(self, request): - return redirectTo(b"http://example.com/", request) - """ - if isinstance(URL, unicode) : - raise TypeError("Unicode object not allowed as URL") - request.setHeader(b"Content-Type", b"text/html; charset=utf-8") - request.redirect(URL) - content = """ -<html> - <head> - <meta http-equiv=\"refresh\" content=\"0;URL=%(url)s\"> - </head> - <body bgcolor=\"#FFFFFF\" text=\"#000000\"> - <a href=\"%(url)s\">click here</a> - </body> -</html> -""" % {'url': nativeString(URL)} - if _PY3: - content = content.encode("utf8") - return content - - -class Redirect(resource.Resource): - isLeaf = True - - def __init__(self, url): - resource.Resource.__init__(self) - self.url = url - - def render(self, request): - return redirectTo(self.url, request) - - def getChild(self, name, request): - return self - - -class ChildRedirector(Redirect): - isLeaf = 0 - def __init__(self, url): - # XXX is this enough? - if ((url.find('://') == -1) - and (not url.startswith('..')) - and (not url.startswith('/'))): - raise ValueError("It seems you've given me a redirect (%s) that is a child of myself! That's not good, it'll cause an infinite redirect." % url) - Redirect.__init__(self, url) - - def getChild(self, name, request): - newUrl = self.url - if not newUrl.endswith('/'): - newUrl += '/' - newUrl += name - return ChildRedirector(newUrl) - - -class ParentRedirect(resource.Resource): - """ - I redirect to URLPath.here(). - """ - isLeaf = 1 - def render(self, request): - return redirectTo(urlpath.URLPath.fromRequest(request).here(), request) - - def getChild(self, request): - return self - - -class DeferredResource(resource.Resource): - """ - I wrap up a Deferred that will eventually result in a Resource - object. - """ - isLeaf = 1 - - def __init__(self, d): - resource.Resource.__init__(self) - self.d = d - - def getChild(self, name, request): - return self - - def render(self, request): - self.d.addCallback(self._cbChild, request).addErrback( - self._ebChild,request) - from twisted.web.server import NOT_DONE_YET - return NOT_DONE_YET - - def _cbChild(self, child, request): - request.render(resource.getChildForRequest(child, request)) - - def _ebChild(self, reason, request): - request.processingFailed(reason) - return reason - - - -class _SourceLineElement(Element): - """ - L{_SourceLineElement} is an L{IRenderable} which can render a single line of - source code. - - @ivar number: A C{int} giving the line number of the source code to be - rendered. - @ivar source: A C{str} giving the source code to be rendered. - """ - def __init__(self, loader, number, source): - Element.__init__(self, loader) - self.number = number - self.source = source - - - @renderer - def sourceLine(self, request, tag): - """ - Render the line of source as a child of C{tag}. - """ - return tag(self.source.replace(' ', u' \N{NO-BREAK SPACE}')) - - - @renderer - def lineNumber(self, request, tag): - """ - Render the line number as a child of C{tag}. - """ - return tag(str(self.number)) - - - -class _SourceFragmentElement(Element): - """ - L{_SourceFragmentElement} is an L{IRenderable} which can render several lines - of source code near the line number of a particular frame object. - - @ivar frame: A L{Failure<twisted.python.failure.Failure>}-style frame object - for which to load a source line to render. This is really a tuple - holding some information from a frame object. See - L{Failure.frames<twisted.python.failure.Failure>} for specifics. - """ - def __init__(self, loader, frame): - Element.__init__(self, loader) - self.frame = frame - - - def _getSourceLines(self): - """ - Find the source line references by C{self.frame} and yield, in source - line order, it and the previous and following lines. - - @return: A generator which yields two-tuples. Each tuple gives a source - line number and the contents of that source line. - """ - filename = self.frame[1] - lineNumber = self.frame[2] - for snipLineNumber in range(lineNumber - 1, lineNumber + 2): - yield (snipLineNumber, - linecache.getline(filename, snipLineNumber).rstrip()) - - - @renderer - def sourceLines(self, request, tag): - """ - Render the source line indicated by C{self.frame} and several - surrounding lines. The active line will be given a I{class} of - C{"snippetHighlightLine"}. Other lines will be given a I{class} of - C{"snippetLine"}. - """ - for (lineNumber, sourceLine) in self._getSourceLines(): - newTag = tag.clone() - if lineNumber == self.frame[2]: - cssClass = "snippetHighlightLine" - else: - cssClass = "snippetLine" - loader = TagLoader(newTag(**{"class": cssClass})) - yield _SourceLineElement(loader, lineNumber, sourceLine) - - - -class _FrameElement(Element): - """ - L{_FrameElement} is an L{IRenderable} which can render details about one - frame from a L{Failure<twisted.python.failure.Failure>}. - - @ivar frame: A L{Failure<twisted.python.failure.Failure>}-style frame object - for which to load a source line to render. This is really a tuple - holding some information from a frame object. See - L{Failure.frames<twisted.python.failure.Failure>} for specifics. - """ - def __init__(self, loader, frame): - Element.__init__(self, loader) - self.frame = frame - - - @renderer - def filename(self, request, tag): - """ - Render the name of the file this frame references as a child of C{tag}. - """ - return tag(self.frame[1]) - - - @renderer - def lineNumber(self, request, tag): - """ - Render the source line number this frame references as a child of - C{tag}. - """ - return tag(str(self.frame[2])) - - - @renderer - def function(self, request, tag): - """ - Render the function name this frame references as a child of C{tag}. - """ - return tag(self.frame[0]) - - - @renderer - def source(self, request, tag): - """ - Render the source code surrounding the line this frame references, - replacing C{tag}. - """ - return _SourceFragmentElement(TagLoader(tag), self.frame) - - - -class _StackElement(Element): - """ - L{_StackElement} renders an L{IRenderable} which can render a list of frames. - """ - def __init__(self, loader, stackFrames): - Element.__init__(self, loader) - self.stackFrames = stackFrames - - - @renderer - def frames(self, request, tag): - """ - Render the list of frames in this L{_StackElement}, replacing C{tag}. - """ - return [ - _FrameElement(TagLoader(tag.clone()), frame) - for frame - in self.stackFrames] - - - -class FailureElement(Element): - """ - L{FailureElement} is an L{IRenderable} which can render detailed information - about a L{Failure<twisted.python.failure.Failure>}. - - @ivar failure: The L{Failure<twisted.python.failure.Failure>} instance which - will be rendered. - - @since: 12.1 - """ - loader = XMLFile(getModule(__name__).filePath.sibling("failure.xhtml")) - - def __init__(self, failure, loader=None): - Element.__init__(self, loader) - self.failure = failure - - - @renderer - def type(self, request, tag): - """ - Render the exception type as a child of C{tag}. - """ - return tag(fullyQualifiedName(self.failure.type)) - - - @renderer - def value(self, request, tag): - """ - Render the exception value as a child of C{tag}. - """ - return tag(str(self.failure.value)) - - - @renderer - def traceback(self, request, tag): - """ - Render all the frames in the wrapped - L{Failure<twisted.python.failure.Failure>}'s traceback stack, replacing - C{tag}. - """ - return _StackElement(TagLoader(tag), self.failure.frames) - - - -def formatFailure(myFailure): - """ - Construct an HTML representation of the given failure. - - Consider using L{FailureElement} instead. - - @type myFailure: L{Failure<twisted.python.failure.Failure>} - - @rtype: C{str} - @return: A string containing the HTML representation of the given failure. - """ - result = [] - flattenString(None, FailureElement(myFailure)).addBoth(result.append) - if isinstance(result[0], str): - # Ensure the result string is all ASCII, for compatibility with the - # default encoding expected by browsers. - return result[0].decode('utf-8').encode('ascii', 'xmlcharrefreplace') - result[0].raiseException() - - - -__all__ = [ - "redirectTo", "Redirect", "ChildRedirector", "ParentRedirect", - "DeferredResource", "FailureElement", "formatFailure"] - -if _PY3: - __all3__ = ["redirectTo", "Redirect"] - for name in __all__[:]: - if name not in __all3__: - __all__.remove(name) - del globals()[name] - del name, __all3__ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/vhost.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/vhost.py deleted file mode 100644 index 1acee21..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/vhost.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- test-case-name: twisted.web. -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -I am a virtual hosts implementation. -""" - -# Twisted Imports -from twisted.python import roots -from twisted.web import resource - - -class VirtualHostCollection(roots.Homogenous): - """Wrapper for virtual hosts collection. - - This exists for configuration purposes. - """ - entityType = resource.Resource - - def __init__(self, nvh): - self.nvh = nvh - - def listStaticEntities(self): - return self.nvh.hosts.items() - - def getStaticEntity(self, name): - return self.nvh.hosts.get(self) - - def reallyPutEntity(self, name, entity): - self.nvh.addHost(name, entity) - - def delEntity(self, name): - self.nvh.removeHost(name) - - -class NameVirtualHost(resource.Resource): - """I am a resource which represents named virtual hosts. - """ - - default = None - - def __init__(self): - """Initialize. - """ - resource.Resource.__init__(self) - self.hosts = {} - - def listStaticEntities(self): - return resource.Resource.listStaticEntities(self) + [("Virtual Hosts", VirtualHostCollection(self))] - - def getStaticEntity(self, name): - if name == "Virtual Hosts": - return VirtualHostCollection(self) - else: - return resource.Resource.getStaticEntity(self, name) - - def addHost(self, name, resrc): - """Add a host to this virtual host. - - This will take a host named `name', and map it to a resource - `resrc'. For example, a setup for our virtual hosts would be:: - - nvh.addHost('divunal.com', divunalDirectory) - nvh.addHost('www.divunal.com', divunalDirectory) - nvh.addHost('twistedmatrix.com', twistedMatrixDirectory) - nvh.addHost('www.twistedmatrix.com', twistedMatrixDirectory) - """ - self.hosts[name] = resrc - - def removeHost(self, name): - """Remove a host.""" - del self.hosts[name] - - def _getResourceForRequest(self, request): - """(Internal) Get the appropriate resource for the given host. - """ - hostHeader = request.getHeader('host') - if hostHeader == None: - return self.default or resource.NoResource() - else: - host = hostHeader.lower().split(':', 1)[0] - return (self.hosts.get(host, self.default) - or resource.NoResource("host %s not in vhost map" % repr(host))) - - def render(self, request): - """Implementation of resource.Resource's render method. - """ - resrc = self._getResourceForRequest(request) - return resrc.render(request) - - def getChild(self, path, request): - """Implementation of resource.Resource's getChild method. - """ - resrc = self._getResourceForRequest(request) - if resrc.isLeaf: - request.postpath.insert(0,request.prepath.pop(-1)) - return resrc - else: - return resrc.getChildWithDefault(path, request) - -class _HostResource(resource.Resource): - - def getChild(self, path, request): - if ':' in path: - host, port = path.split(':', 1) - port = int(port) - else: - host, port = path, 80 - request.setHost(host, port) - prefixLen = 3+request.isSecure()+4+len(path)+len(request.prepath[-3]) - request.path = '/'+'/'.join(request.postpath) - request.uri = request.uri[prefixLen:] - del request.prepath[:3] - return request.site.getResourceFor(request) - - -class VHostMonsterResource(resource.Resource): - - """ - Use this to be able to record the hostname and method (http vs. https) - in the URL without disturbing your web site. If you put this resource - in a URL http://foo.com/bar then requests to - http://foo.com/bar/http/baz.com/something will be equivalent to - http://foo.com/something, except that the hostname the request will - appear to be accessing will be "baz.com". So if "baz.com" is redirecting - all requests for to foo.com, while foo.com is inaccessible from the outside, - then redirect and url generation will work correctly - """ - def getChild(self, path, request): - if path == 'http': - request.isSecure = lambda: 0 - elif path == 'https': - request.isSecure = lambda: 1 - return _HostResource() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/wsgi.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/wsgi.py deleted file mode 100644 index 0918c4d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/wsgi.py +++ /dev/null @@ -1,403 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An implementation of -U{Web Resource Gateway Interface<http://www.python.org/dev/peps/pep-0333/>}. -""" - -__metaclass__ = type - -from sys import exc_info - -from zope.interface import implements - -from twisted.python.log import msg, err -from twisted.python.failure import Failure -from twisted.web.resource import IResource -from twisted.web.server import NOT_DONE_YET -from twisted.web.http import INTERNAL_SERVER_ERROR - - -class _ErrorStream: - """ - File-like object instances of which are used as the value for the - C{'wsgi.errors'} key in the C{environ} dictionary passed to the application - object. - - This simply passes writes on to L{logging<twisted.python.log>} system as - error events from the C{'wsgi'} system. In the future, it may be desirable - to expose more information in the events it logs, such as the application - object which generated the message. - """ - def write(self, bytes): - """ - Generate an event for the logging system with the given bytes as the - message. - - This is called in a WSGI application thread, not the I/O thread. - """ - msg(bytes, system='wsgi', isError=True) - - - def writelines(self, iovec): - """ - Join the given lines and pass them to C{write} to be handled in the - usual way. - - This is called in a WSGI application thread, not the I/O thread. - - @param iovec: A C{list} of C{'\\n'}-terminated C{str} which will be - logged. - """ - self.write(''.join(iovec)) - - - def flush(self): - """ - Nothing is buffered, so flushing does nothing. This method is required - to exist by PEP 333, though. - - This is called in a WSGI application thread, not the I/O thread. - """ - - - -class _InputStream: - """ - File-like object instances of which are used as the value for the - C{'wsgi.input'} key in the C{environ} dictionary passed to the application - object. - - This only exists to make the handling of C{readline(-1)} consistent across - different possible underlying file-like object implementations. The other - supported methods pass through directly to the wrapped object. - """ - def __init__(self, input): - """ - Initialize the instance. - - This is called in the I/O thread, not a WSGI application thread. - """ - self._wrapped = input - - - def read(self, size=None): - """ - Pass through to the underlying C{read}. - - This is called in a WSGI application thread, not the I/O thread. - """ - # Avoid passing None because cStringIO and file don't like it. - if size is None: - return self._wrapped.read() - return self._wrapped.read(size) - - - def readline(self, size=None): - """ - Pass through to the underlying C{readline}, with a size of C{-1} replaced - with a size of C{None}. - - This is called in a WSGI application thread, not the I/O thread. - """ - # Check for -1 because StringIO doesn't handle it correctly. Check for - # None because files and tempfiles don't accept that. - if size == -1 or size is None: - return self._wrapped.readline() - return self._wrapped.readline(size) - - - def readlines(self, size=None): - """ - Pass through to the underlying C{readlines}. - - This is called in a WSGI application thread, not the I/O thread. - """ - # Avoid passing None because cStringIO and file don't like it. - if size is None: - return self._wrapped.readlines() - return self._wrapped.readlines(size) - - - def __iter__(self): - """ - Pass through to the underlying C{__iter__}. - - This is called in a WSGI application thread, not the I/O thread. - """ - return iter(self._wrapped) - - - -class _WSGIResponse: - """ - Helper for L{WSGIResource} which drives the WSGI application using a - threadpool and hooks it up to the L{Request}. - - @ivar started: A C{bool} indicating whether or not the response status and - headers have been written to the request yet. This may only be read or - written in the WSGI application thread. - - @ivar reactor: An L{IReactorThreads} provider which is used to call methods - on the request in the I/O thread. - - @ivar threadpool: A L{ThreadPool} which is used to call the WSGI - application object in a non-I/O thread. - - @ivar application: The WSGI application object. - - @ivar request: The L{Request} upon which the WSGI environment is based and - to which the application's output will be sent. - - @ivar environ: The WSGI environment C{dict}. - - @ivar status: The HTTP response status C{str} supplied to the WSGI - I{start_response} callable by the application. - - @ivar headers: A list of HTTP response headers supplied to the WSGI - I{start_response} callable by the application. - - @ivar _requestFinished: A flag which indicates whether it is possible to - generate more response data or not. This is C{False} until - L{Request.notifyFinish} tells us the request is done, then C{True}. - """ - - _requestFinished = False - - def __init__(self, reactor, threadpool, application, request): - self.started = False - self.reactor = reactor - self.threadpool = threadpool - self.application = application - self.request = request - self.request.notifyFinish().addBoth(self._finished) - - if request.prepath: - scriptName = '/' + '/'.join(request.prepath) - else: - scriptName = '' - - if request.postpath: - pathInfo = '/' + '/'.join(request.postpath) - else: - pathInfo = '' - - parts = request.uri.split('?', 1) - if len(parts) == 1: - queryString = '' - else: - queryString = parts[1] - - self.environ = { - 'REQUEST_METHOD': request.method, - 'REMOTE_ADDR': request.getClientIP(), - 'SCRIPT_NAME': scriptName, - 'PATH_INFO': pathInfo, - 'QUERY_STRING': queryString, - 'CONTENT_TYPE': request.getHeader('content-type') or '', - 'CONTENT_LENGTH': request.getHeader('content-length') or '', - 'SERVER_NAME': request.getRequestHostname(), - 'SERVER_PORT': str(request.getHost().port), - 'SERVER_PROTOCOL': request.clientproto} - - - # The application object is entirely in control of response headers; - # disable the default Content-Type value normally provided by - # twisted.web.server.Request. - self.request.defaultContentType = None - - for name, values in request.requestHeaders.getAllRawHeaders(): - name = 'HTTP_' + name.upper().replace('-', '_') - # It might be preferable for http.HTTPChannel to clear out - # newlines. - self.environ[name] = ','.join([ - v.replace('\n', ' ') for v in values]) - - self.environ.update({ - 'wsgi.version': (1, 0), - 'wsgi.url_scheme': request.isSecure() and 'https' or 'http', - 'wsgi.run_once': False, - 'wsgi.multithread': True, - 'wsgi.multiprocess': False, - 'wsgi.errors': _ErrorStream(), - # Attend: request.content was owned by the I/O thread up until - # this point. By wrapping it and putting the result into the - # environment dictionary, it is effectively being given to - # another thread. This means that whatever it is, it has to be - # safe to access it from two different threads. The access - # *should* all be serialized (first the I/O thread writes to - # it, then the WSGI thread reads from it, then the I/O thread - # closes it). However, since the request is made available to - # arbitrary application code during resource traversal, it's - # possible that some other code might decide to use it in the - # I/O thread concurrently with its use in the WSGI thread. - # More likely than not, this will break. This seems like an - # unlikely possibility to me, but if it is to be allowed, - # something here needs to change. -exarkun - 'wsgi.input': _InputStream(request.content)}) - - - def _finished(self, ignored): - """ - Record the end of the response generation for the request being - serviced. - """ - self._requestFinished = True - - - def startResponse(self, status, headers, excInfo=None): - """ - The WSGI I{start_response} callable. The given values are saved until - they are needed to generate the response. - - This will be called in a non-I/O thread. - """ - if self.started and excInfo is not None: - raise excInfo[0], excInfo[1], excInfo[2] - self.status = status - self.headers = headers - return self.write - - - def write(self, bytes): - """ - The WSGI I{write} callable returned by the I{start_response} callable. - The given bytes will be written to the response body, possibly flushing - the status and headers first. - - This will be called in a non-I/O thread. - """ - def wsgiWrite(started): - if not started: - self._sendResponseHeaders() - self.request.write(bytes) - self.reactor.callFromThread(wsgiWrite, self.started) - self.started = True - - - def _sendResponseHeaders(self): - """ - Set the response code and response headers on the request object, but - do not flush them. The caller is responsible for doing a write in - order for anything to actually be written out in response to the - request. - - This must be called in the I/O thread. - """ - code, message = self.status.split(None, 1) - code = int(code) - self.request.setResponseCode(code, message) - - for name, value in self.headers: - # Don't allow the application to control these required headers. - if name.lower() not in ('server', 'date'): - self.request.responseHeaders.addRawHeader(name, value) - - - def start(self): - """ - Start the WSGI application in the threadpool. - - This must be called in the I/O thread. - """ - self.threadpool.callInThread(self.run) - - - def run(self): - """ - Call the WSGI application object, iterate it, and handle its output. - - This must be called in a non-I/O thread (ie, a WSGI application - thread). - """ - try: - appIterator = self.application(self.environ, self.startResponse) - for elem in appIterator: - if elem: - self.write(elem) - if self._requestFinished: - break - close = getattr(appIterator, 'close', None) - if close is not None: - close() - except: - def wsgiError(started, type, value, traceback): - err(Failure(value, type, traceback), "WSGI application error") - if started: - self.request.transport.loseConnection() - else: - self.request.setResponseCode(INTERNAL_SERVER_ERROR) - self.request.finish() - self.reactor.callFromThread(wsgiError, self.started, *exc_info()) - else: - def wsgiFinish(started): - if not self._requestFinished: - if not started: - self._sendResponseHeaders() - self.request.finish() - self.reactor.callFromThread(wsgiFinish, self.started) - self.started = True - - - -class WSGIResource: - """ - An L{IResource} implementation which delegates responsibility for all - resources hierarchically inferior to it to a WSGI application. - - @ivar _reactor: An L{IReactorThreads} provider which will be passed on to - L{_WSGIResponse} to schedule calls in the I/O thread. - - @ivar _threadpool: A L{ThreadPool} which will be passed on to - L{_WSGIResponse} to run the WSGI application object. - - @ivar _application: The WSGI application object. - """ - implements(IResource) - - # Further resource segments are left up to the WSGI application object to - # handle. - isLeaf = True - - def __init__(self, reactor, threadpool, application): - self._reactor = reactor - self._threadpool = threadpool - self._application = application - - - def render(self, request): - """ - Turn the request into the appropriate C{environ} C{dict} suitable to be - passed to the WSGI application object and then pass it on. - - The WSGI application object is given almost complete control of the - rendering process. C{NOT_DONE_YET} will always be returned in order - and response completion will be dictated by the application object, as - will the status, headers, and the response body. - """ - response = _WSGIResponse( - self._reactor, self._threadpool, self._application, request) - response.start() - return NOT_DONE_YET - - - def getChildWithDefault(self, name, request): - """ - Reject attempts to retrieve a child resource. All path segments beyond - the one which refers to this resource are handled by the WSGI - application object. - """ - raise RuntimeError("Cannot get IResource children from WSGIResource") - - - def putChild(self, path, child): - """ - Reject attempts to add a child resource to this resource. The WSGI - application object handles all path segments beneath this resource, so - L{IResource} children can never be found. - """ - raise RuntimeError("Cannot put IResource children under WSGIResource") - - -__all__ = ['WSGIResource'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/xmlrpc.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/xmlrpc.py deleted file mode 100644 index 0536857..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/web/xmlrpc.py +++ /dev/null @@ -1,572 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xmlrpc -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A generic resource for publishing objects via XML-RPC. - -Maintainer: Itamar Shtull-Trauring -""" - -# System Imports -import base64 -import xmlrpclib -import urlparse - -# Sibling Imports -from twisted.web import resource, server, http -from twisted.internet import defer, protocol, reactor -from twisted.python import log, reflect, failure - -# These are deprecated, use the class level definitions -NOT_FOUND = 8001 -FAILURE = 8002 - - -# Useful so people don't need to import xmlrpclib directly -Fault = xmlrpclib.Fault -Binary = xmlrpclib.Binary -Boolean = xmlrpclib.Boolean -DateTime = xmlrpclib.DateTime - - -def withRequest(f): - """ - Decorator to cause the request to be passed as the first argument - to the method. - - If an I{xmlrpc_} method is wrapped with C{withRequest}, the - request object is passed as the first argument to that method. - For example:: - - @withRequest - def xmlrpc_echo(self, request, s): - return s - - @since: 10.2 - """ - f.withRequest = True - return f - - - -class NoSuchFunction(Fault): - """ - There is no function by the given name. - """ - - -class Handler: - """ - Handle a XML-RPC request and store the state for a request in progress. - - Override the run() method and return result using self.result, - a Deferred. - - We require this class since we're not using threads, so we can't - encapsulate state in a running function if we're going to have - to wait for results. - - For example, lets say we want to authenticate against twisted.cred, - run a LDAP query and then pass its result to a database query, all - as a result of a single XML-RPC command. We'd use a Handler instance - to store the state of the running command. - """ - - def __init__(self, resource, *args): - self.resource = resource # the XML-RPC resource we are connected to - self.result = defer.Deferred() - self.run(*args) - - def run(self, *args): - # event driven equivalent of 'raise UnimplementedError' - self.result.errback( - NotImplementedError("Implement run() in subclasses")) - - -class XMLRPC(resource.Resource): - """ - A resource that implements XML-RPC. - - You probably want to connect this to '/RPC2'. - - Methods published can return XML-RPC serializable results, Faults, - Binary, Boolean, DateTime, Deferreds, or Handler instances. - - By default methods beginning with 'xmlrpc_' are published. - - Sub-handlers for prefixed methods (e.g., system.listMethods) - can be added with putSubHandler. By default, prefixes are - separated with a '.'. Override self.separator to change this. - - @ivar allowNone: Permit XML translating of Python constant None. - @type allowNone: C{bool} - - @ivar useDateTime: Present C{datetime} values as C{datetime.datetime} - objects? - @type useDateTime: C{bool} - """ - - # Error codes for Twisted, if they conflict with yours then - # modify them at runtime. - NOT_FOUND = 8001 - FAILURE = 8002 - - isLeaf = 1 - separator = '.' - allowedMethods = ('POST',) - - def __init__(self, allowNone=False, useDateTime=False): - resource.Resource.__init__(self) - self.subHandlers = {} - self.allowNone = allowNone - self.useDateTime = useDateTime - - - def __setattr__(self, name, value): - self.__dict__[name] = value - - - def putSubHandler(self, prefix, handler): - self.subHandlers[prefix] = handler - - def getSubHandler(self, prefix): - return self.subHandlers.get(prefix, None) - - def getSubHandlerPrefixes(self): - return self.subHandlers.keys() - - def render_POST(self, request): - request.content.seek(0, 0) - request.setHeader("content-type", "text/xml") - try: - args, functionPath = xmlrpclib.loads(request.content.read(), - use_datetime=self.useDateTime) - except Exception, e: - f = Fault(self.FAILURE, "Can't deserialize input: %s" % (e,)) - self._cbRender(f, request) - else: - try: - function = self.lookupProcedure(functionPath) - except Fault, f: - self._cbRender(f, request) - else: - # Use this list to track whether the response has failed or not. - # This will be used later on to decide if the result of the - # Deferred should be written out and Request.finish called. - responseFailed = [] - request.notifyFinish().addErrback(responseFailed.append) - if getattr(function, 'withRequest', False): - d = defer.maybeDeferred(function, request, *args) - else: - d = defer.maybeDeferred(function, *args) - d.addErrback(self._ebRender) - d.addCallback(self._cbRender, request, responseFailed) - return server.NOT_DONE_YET - - - def _cbRender(self, result, request, responseFailed=None): - if responseFailed: - return - - if isinstance(result, Handler): - result = result.result - if not isinstance(result, Fault): - result = (result,) - try: - try: - content = xmlrpclib.dumps( - result, methodresponse=True, - allow_none=self.allowNone) - except Exception, e: - f = Fault(self.FAILURE, "Can't serialize output: %s" % (e,)) - content = xmlrpclib.dumps(f, methodresponse=True, - allow_none=self.allowNone) - - request.setHeader("content-length", str(len(content))) - request.write(content) - except: - log.err() - request.finish() - - - def _ebRender(self, failure): - if isinstance(failure.value, Fault): - return failure.value - log.err(failure) - return Fault(self.FAILURE, "error") - - - def lookupProcedure(self, procedurePath): - """ - Given a string naming a procedure, return a callable object for that - procedure or raise NoSuchFunction. - - The returned object will be called, and should return the result of the - procedure, a Deferred, or a Fault instance. - - Override in subclasses if you want your own policy. The base - implementation that given C{'foo'}, C{self.xmlrpc_foo} will be returned. - If C{procedurePath} contains C{self.separator}, the sub-handler for the - initial prefix is used to search for the remaining path. - - If you override C{lookupProcedure}, you may also want to override - C{listProcedures} to accurately report the procedures supported by your - resource, so that clients using the I{system.listMethods} procedure - receive accurate results. - - @since: 11.1 - """ - if procedurePath.find(self.separator) != -1: - prefix, procedurePath = procedurePath.split(self.separator, 1) - handler = self.getSubHandler(prefix) - if handler is None: - raise NoSuchFunction(self.NOT_FOUND, - "no such subHandler %s" % prefix) - return handler.lookupProcedure(procedurePath) - - f = getattr(self, "xmlrpc_%s" % procedurePath, None) - if not f: - raise NoSuchFunction(self.NOT_FOUND, - "procedure %s not found" % procedurePath) - elif not callable(f): - raise NoSuchFunction(self.NOT_FOUND, - "procedure %s not callable" % procedurePath) - else: - return f - - def listProcedures(self): - """ - Return a list of the names of all xmlrpc procedures. - - @since: 11.1 - """ - return reflect.prefixedMethodNames(self.__class__, 'xmlrpc_') - - -class XMLRPCIntrospection(XMLRPC): - """ - Implement the XML-RPC Introspection API. - - By default, the methodHelp method returns the 'help' method attribute, - if it exists, otherwise the __doc__ method attribute, if it exists, - otherwise the empty string. - - To enable the methodSignature method, add a 'signature' method attribute - containing a list of lists. See methodSignature's documentation for the - format. Note the type strings should be XML-RPC types, not Python types. - """ - - def __init__(self, parent): - """ - Implement Introspection support for an XMLRPC server. - - @param parent: the XMLRPC server to add Introspection support to. - @type parent: L{XMLRPC} - """ - XMLRPC.__init__(self) - self._xmlrpc_parent = parent - - def xmlrpc_listMethods(self): - """ - Return a list of the method names implemented by this server. - """ - functions = [] - todo = [(self._xmlrpc_parent, '')] - while todo: - obj, prefix = todo.pop(0) - functions.extend([prefix + name for name in obj.listProcedures()]) - todo.extend([ (obj.getSubHandler(name), - prefix + name + obj.separator) - for name in obj.getSubHandlerPrefixes() ]) - return functions - - xmlrpc_listMethods.signature = [['array']] - - def xmlrpc_methodHelp(self, method): - """ - Return a documentation string describing the use of the given method. - """ - method = self._xmlrpc_parent.lookupProcedure(method) - return (getattr(method, 'help', None) - or getattr(method, '__doc__', None) or '') - - xmlrpc_methodHelp.signature = [['string', 'string']] - - def xmlrpc_methodSignature(self, method): - """ - Return a list of type signatures. - - Each type signature is a list of the form [rtype, type1, type2, ...] - where rtype is the return type and typeN is the type of the Nth - argument. If no signature information is available, the empty - string is returned. - """ - method = self._xmlrpc_parent.lookupProcedure(method) - return getattr(method, 'signature', None) or '' - - xmlrpc_methodSignature.signature = [['array', 'string'], - ['string', 'string']] - - -def addIntrospection(xmlrpc): - """ - Add Introspection support to an XMLRPC server. - - @param parent: the XMLRPC server to add Introspection support to. - @type parent: L{XMLRPC} - """ - xmlrpc.putSubHandler('system', XMLRPCIntrospection(xmlrpc)) - - -class QueryProtocol(http.HTTPClient): - - def connectionMade(self): - self._response = None - self.sendCommand('POST', self.factory.path) - self.sendHeader('User-Agent', 'Twisted/XMLRPClib') - self.sendHeader('Host', self.factory.host) - self.sendHeader('Content-type', 'text/xml') - self.sendHeader('Content-length', str(len(self.factory.payload))) - if self.factory.user: - auth = '%s:%s' % (self.factory.user, self.factory.password) - auth = base64.b64encode(auth) - self.sendHeader('Authorization', 'Basic %s' % (auth,)) - self.endHeaders() - self.transport.write(self.factory.payload) - - def handleStatus(self, version, status, message): - if status != '200': - self.factory.badStatus(status, message) - - def handleResponse(self, contents): - """ - Handle the XML-RPC response received from the server. - - Specifically, disconnect from the server and store the XML-RPC - response so that it can be properly handled when the disconnect is - finished. - """ - self.transport.loseConnection() - self._response = contents - - def connectionLost(self, reason): - """ - The connection to the server has been lost. - - If we have a full response from the server, then parse it and fired a - Deferred with the return value or C{Fault} that the server gave us. - """ - http.HTTPClient.connectionLost(self, reason) - if self._response is not None: - response, self._response = self._response, None - self.factory.parseResponse(response) - - -payloadTemplate = """<?xml version="1.0"?> -<methodCall> -<methodName>%s</methodName> -%s -</methodCall> -""" - - -class _QueryFactory(protocol.ClientFactory): - """ - XML-RPC Client Factory - - @ivar path: The path portion of the URL to which to post method calls. - @type path: C{str} - - @ivar host: The value to use for the Host HTTP header. - @type host: C{str} - - @ivar user: The username with which to authenticate with the server - when making calls. - @type user: C{str} or C{NoneType} - - @ivar password: The password with which to authenticate with the server - when making calls. - @type password: C{str} or C{NoneType} - - @ivar useDateTime: Accept datetime values as datetime.datetime objects. - also passed to the underlying xmlrpclib implementation. Defaults to - C{False}. - @type useDateTime: C{bool} - """ - - deferred = None - protocol = QueryProtocol - - def __init__(self, path, host, method, user=None, password=None, - allowNone=False, args=(), canceller=None, useDateTime=False): - """ - @param method: The name of the method to call. - @type method: C{str} - - @param allowNone: allow the use of None values in parameters. It's - passed to the underlying xmlrpclib implementation. Defaults to - C{False}. - @type allowNone: C{bool} or C{NoneType} - - @param args: the arguments to pass to the method. - @type args: C{tuple} - - @param canceller: A 1-argument callable passed to the deferred as the - canceller callback. - @type canceller: callable or C{NoneType} - """ - self.path, self.host = path, host - self.user, self.password = user, password - self.payload = payloadTemplate % (method, - xmlrpclib.dumps(args, allow_none=allowNone)) - self.deferred = defer.Deferred(canceller) - self.useDateTime = useDateTime - - def parseResponse(self, contents): - if not self.deferred: - return - try: - response = xmlrpclib.loads(contents, - use_datetime=self.useDateTime)[0][0] - except: - deferred, self.deferred = self.deferred, None - deferred.errback(failure.Failure()) - else: - deferred, self.deferred = self.deferred, None - deferred.callback(response) - - def clientConnectionLost(self, _, reason): - if self.deferred is not None: - deferred, self.deferred = self.deferred, None - deferred.errback(reason) - - clientConnectionFailed = clientConnectionLost - - def badStatus(self, status, message): - deferred, self.deferred = self.deferred, None - deferred.errback(ValueError(status, message)) - - - -class Proxy: - """ - A Proxy for making remote XML-RPC calls. - - Pass the URL of the remote XML-RPC server to the constructor. - - Use C{proxy.callRemote('foobar', *args)} to call remote method - 'foobar' with *args. - - @ivar user: The username with which to authenticate with the server - when making calls. If specified, overrides any username information - embedded in C{url}. If not specified, a value may be taken from - C{url} if present. - @type user: C{str} or C{NoneType} - - @ivar password: The password with which to authenticate with the server - when making calls. If specified, overrides any password information - embedded in C{url}. If not specified, a value may be taken from - C{url} if present. - @type password: C{str} or C{NoneType} - - @ivar allowNone: allow the use of None values in parameters. It's - passed to the underlying L{xmlrpclib} implementation. Defaults to - C{False}. - @type allowNone: C{bool} or C{NoneType} - - @ivar useDateTime: Accept datetime values as datetime.datetime objects. - also passed to the underlying L{xmlrpclib} implementation. Defaults to - C{False}. - @type useDateTime: C{bool} - - @ivar connectTimeout: Number of seconds to wait before assuming the - connection has failed. - @type connectTimeout: C{float} - - @ivar _reactor: The reactor used to create connections. - @type _reactor: Object providing L{twisted.internet.interfaces.IReactorTCP} - - @ivar queryFactory: Object returning a factory for XML-RPC protocol. Mainly - useful for tests. - """ - queryFactory = _QueryFactory - - def __init__(self, url, user=None, password=None, allowNone=False, - useDateTime=False, connectTimeout=30.0, reactor=reactor): - """ - @param url: The URL to which to post method calls. Calls will be made - over SSL if the scheme is HTTPS. If netloc contains username or - password information, these will be used to authenticate, as long as - the C{user} and C{password} arguments are not specified. - @type url: C{str} - - """ - scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) - netlocParts = netloc.split('@') - if len(netlocParts) == 2: - userpass = netlocParts.pop(0).split(':') - self.user = userpass.pop(0) - try: - self.password = userpass.pop(0) - except: - self.password = None - else: - self.user = self.password = None - hostport = netlocParts[0].split(':') - self.host = hostport.pop(0) - try: - self.port = int(hostport.pop(0)) - except: - self.port = None - self.path = path - if self.path in ['', None]: - self.path = '/' - self.secure = (scheme == 'https') - if user is not None: - self.user = user - if password is not None: - self.password = password - self.allowNone = allowNone - self.useDateTime = useDateTime - self.connectTimeout = connectTimeout - self._reactor = reactor - - - def callRemote(self, method, *args): - """ - Call remote XML-RPC C{method} with given arguments. - - @return: a L{defer.Deferred} that will fire with the method response, - or a failure if the method failed. Generally, the failure type will - be L{Fault}, but you can also have an C{IndexError} on some buggy - servers giving empty responses. - - If the deferred is cancelled before the request completes, the - connection is closed and the deferred will fire with a - L{defer.CancelledError}. - """ - def cancel(d): - factory.deferred = None - connector.disconnect() - factory = self.queryFactory( - self.path, self.host, method, self.user, - self.password, self.allowNone, args, cancel, self.useDateTime) - - if self.secure: - from twisted.internet import ssl - connector = self._reactor.connectSSL( - self.host, self.port or 443, - factory, ssl.ClientContextFactory(), - timeout=self.connectTimeout) - else: - connector = self._reactor.connectTCP( - self.host, self.port or 80, factory, - timeout=self.connectTimeout) - return factory.deferred - - -__all__ = [ - "XMLRPC", "Handler", "NoSuchFunction", "Proxy", - - "Fault", "Binary", "Boolean", "DateTime"] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/__init__.py deleted file mode 100644 index c550e5e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted Words: Client and server implementations for IRC, XMPP, and other chat -services. -""" - -from twisted.words._version import version -__version__ = version.short() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/_version.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/_version.py deleted file mode 100644 index e84a209..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/_version.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# This is an auto-generated file. Do not edit it. - -""" -Provides Twisted version information. -""" - -from twisted.python import versions -version = versions.Version('twisted.words', 15, 2, 1) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/ewords.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/ewords.py deleted file mode 100644 index 7621a71..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/ewords.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Exception definitions for Words -""" - -class WordsError(Exception): - def __str__(self): - return self.__class__.__name__ + ': ' + Exception.__str__(self) - -class NoSuchUser(WordsError): - pass - - -class DuplicateUser(WordsError): - pass - - -class NoSuchGroup(WordsError): - pass - - -class DuplicateGroup(WordsError): - pass - - -class AlreadyLoggedIn(WordsError): - pass - -__all__ = [ - 'WordsError', 'NoSuchUser', 'DuplicateUser', - 'NoSuchGroup', 'DuplicateGroup', 'AlreadyLoggedIn', - ] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/__init__.py deleted file mode 100644 index f2ef3b8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Instance Messenger, Pan-protocol chat client. -""" - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/baseaccount.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/baseaccount.py deleted file mode 100644 index 0261dbf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/baseaccount.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- Python -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -class AccountManager: - """I am responsible for managing a user's accounts. - - That is, remembering what accounts are available, their settings, - adding and removal of accounts, etc. - - @ivar accounts: A collection of available accounts. - @type accounts: mapping of strings to L{Account<interfaces.IAccount>}s. - """ - def __init__(self): - self.accounts = {} - - def getSnapShot(self): - """A snapshot of all the accounts and their status. - - @returns: A list of tuples, each of the form - (string:accountName, boolean:isOnline, - boolean:autoLogin, string:gatewayType) - """ - data = [] - for account in self.accounts.values(): - data.append((account.accountName, account.isOnline(), - account.autoLogin, account.gatewayType)) - return data - - def isEmpty(self): - return len(self.accounts) == 0 - - def getConnectionInfo(self): - connectioninfo = [] - for account in self.accounts.values(): - connectioninfo.append(account.isOnline()) - return connectioninfo - - def addAccount(self, account): - self.accounts[account.accountName] = account - - def delAccount(self, accountName): - del self.accounts[accountName] - - def connect(self, accountName, chatui): - """ - @returntype: Deferred L{interfaces.IClient} - """ - return self.accounts[accountName].logOn(chatui) - - def disconnect(self, accountName): - pass - #self.accounts[accountName].logOff() - not yet implemented - - def quit(self): - pass - #for account in self.accounts.values(): - # account.logOff() - not yet implemented diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/basechat.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/basechat.py deleted file mode 100644 index 076275f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/basechat.py +++ /dev/null @@ -1,512 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_basechat -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Base classes for Instance Messenger clients. -""" - -from twisted.words.im.locals import OFFLINE, ONLINE, AWAY - - -class ContactsList: - """ - A GUI object that displays a contacts list. - - @ivar chatui: The GUI chat client associated with this contacts list. - @type chatui: L{ChatUI} - - @ivar contacts: The contacts. - @type contacts: C{dict} mapping C{str} to a L{IPerson<interfaces.IPerson>} - provider - - @ivar onlineContacts: The contacts who are currently online (have a status - that is not C{OFFLINE}). - @type onlineContacts: C{dict} mapping C{str} to a - L{IPerson<interfaces.IPerson>} provider - - @ivar clients: The signed-on clients. - @type clients: C{list} of L{IClient<interfaces.IClient>} providers - """ - def __init__(self, chatui): - """ - @param chatui: The GUI chat client associated with this contacts list. - @type chatui: L{ChatUI} - """ - self.chatui = chatui - self.contacts = {} - self.onlineContacts = {} - self.clients = [] - - - def setContactStatus(self, person): - """ - Inform the user that a person's status has changed. - - @param person: The person whose status has changed. - @type person: L{IPerson<interfaces.IPerson>} provider - """ - if not self.contacts.has_key(person.name): - self.contacts[person.name] = person - if not self.onlineContacts.has_key(person.name) and \ - (person.status == ONLINE or person.status == AWAY): - self.onlineContacts[person.name] = person - if self.onlineContacts.has_key(person.name) and \ - person.status == OFFLINE: - del self.onlineContacts[person.name] - - - def registerAccountClient(self, client): - """ - Notify the user that an account client has been signed on to. - - @param client: The client being added to your list of account clients. - @type client: L{IClient<interfaces.IClient>} provider - """ - if not client in self.clients: - self.clients.append(client) - - - def unregisterAccountClient(self, client): - """ - Notify the user that an account client has been signed off or - disconnected from. - - @param client: The client being removed from the list of account - clients. - @type client: L{IClient<interfaces.IClient>} provider - """ - if client in self.clients: - self.clients.remove(client) - - - def contactChangedNick(self, person, newnick): - """ - Update your contact information to reflect a change to a contact's - nickname. - - @param person: The person in your contacts list whose nickname is - changing. - @type person: L{IPerson<interfaces.IPerson>} provider - - @param newnick: The new nickname for this person. - @type newnick: C{str} - """ - oldname = person.name - if oldname in self.contacts: - del self.contacts[oldname] - person.name = newnick - self.contacts[newnick] = person - if self.onlineContacts.has_key(oldname): - del self.onlineContacts[oldname] - self.onlineContacts[newnick] = person - - - -class Conversation: - """ - A GUI window of a conversation with a specific person. - - @ivar person: The person who you're having this conversation with. - @type person: L{IPerson<interfaces.IPerson>} provider - - @ivar chatui: The GUI chat client associated with this conversation. - @type chatui: L{ChatUI} - """ - def __init__(self, person, chatui): - """ - @param person: The person who you're having this conversation with. - @type person: L{IPerson<interfaces.IPerson>} provider - - @param chatui: The GUI chat client associated with this conversation. - @type chatui: L{ChatUI} - """ - self.chatui = chatui - self.person = person - - - def show(self): - """ - Display the ConversationWindow. - """ - raise NotImplementedError("Subclasses must implement this method") - - - def hide(self): - """ - Hide the ConversationWindow. - """ - raise NotImplementedError("Subclasses must implement this method") - - - def sendText(self, text): - """ - Send text to the person with whom the user is conversing. - - @param text: The text to be sent. - @type text: C{str} - """ - self.person.sendMessage(text, None) - - - def showMessage(self, text, metadata=None): - """ - Display a message sent from the person with whom the user is conversing. - - @param text: The sent message. - @type text: C{str} - - @param metadata: Metadata associated with this message. - @type metadata: C{dict} - """ - raise NotImplementedError("Subclasses must implement this method") - - - def contactChangedNick(self, person, newnick): - """ - Change a person's name. - - @param person: The person whose nickname is changing. - @type person: L{IPerson<interfaces.IPerson>} provider - - @param newnick: The new nickname for this person. - @type newnick: C{str} - """ - self.person.name = newnick - - - -class GroupConversation: - """ - A GUI window of a conversation with a group of people. - - @ivar chatui: The GUI chat client associated with this conversation. - @type chatui: L{ChatUI} - - @ivar group: The group of people that are having this conversation. - @type group: L{IGroup<interfaces.IGroup>} provider - - @ivar members: The names of the people in this conversation. - @type members: C{list} of C{str} - """ - def __init__(self, group, chatui): - """ - @param chatui: The GUI chat client associated with this conversation. - @type chatui: L{ChatUI} - - @param group: The group of people that are having this conversation. - @type group: L{IGroup<interfaces.IGroup>} provider - """ - self.chatui = chatui - self.group = group - self.members = [] - - - def show(self): - """ - Display the GroupConversationWindow. - """ - raise NotImplementedError("Subclasses must implement this method") - - - def hide(self): - """ - Hide the GroupConversationWindow. - """ - raise NotImplementedError("Subclasses must implement this method") - - - def sendText(self, text): - """ - Send text to the group. - - @param: The text to be sent. - @type text: C{str} - """ - self.group.sendGroupMessage(text, None) - - - def showGroupMessage(self, sender, text, metadata=None): - """ - Display to the user a message sent to this group from the given sender. - - @param sender: The person sending the message. - @type sender: C{str} - - @param text: The sent message. - @type text: C{str} - - @param metadata: Metadata associated with this message. - @type metadata: C{dict} - """ - raise NotImplementedError("Subclasses must implement this method") - - - def setGroupMembers(self, members): - """ - Set the list of members in the group. - - @param members: The names of the people that will be in this group. - @type members: C{list} of C{str} - """ - self.members = members - - - def setTopic(self, topic, author): - """ - Change the topic for the group conversation window and display this - change to the user. - - @param topic: This group's topic. - @type topic: C{str} - - @param author: The person changing the topic. - @type author: C{str} - """ - raise NotImplementedError("Subclasses must implement this method") - - - def memberJoined(self, member): - """ - Add the given member to the list of members in the group conversation - and displays this to the user. - - @param member: The person joining the group conversation. - @type member: C{str} - """ - if not member in self.members: - self.members.append(member) - - - def memberChangedNick(self, oldnick, newnick): - """ - Change the nickname for a member of the group conversation and displays - this change to the user. - - @param oldnick: The old nickname. - @type oldnick: C{str} - - @param newnick: The new nickname. - @type newnick: C{str} - """ - if oldnick in self.members: - self.members.remove(oldnick) - self.members.append(newnick) - - - def memberLeft(self, member): - """ - Delete the given member from the list of members in the group - conversation and displays the change to the user. - - @param member: The person leaving the group conversation. - @type member: C{str} - """ - if member in self.members: - self.members.remove(member) - - - -class ChatUI: - """ - A GUI chat client. - - @type conversations: C{dict} of L{Conversation} - @ivar conversations: A cache of all the direct windows. - - @type groupConversations: C{dict} of L{GroupConversation} - @ivar groupConversations: A cache of all the group windows. - - @type persons: C{dict} with keys that are a C{tuple} of (C{str}, - L{IAccount<interfaces.IAccount>} provider) and values that are - L{IPerson<interfaces.IPerson>} provider - @ivar persons: A cache of all the users associated with this client. - - @type groups: C{dict} with keys that are a C{tuple} of (C{str}, - L{IAccount<interfaces.IAccount>} provider) and values that are - L{IGroup<interfaces.IGroup>} provider - @ivar groups: A cache of all the groups associated with this client. - - @type onlineClients: C{list} of L{IClient<interfaces.IClient>} providers - @ivar onlineClients: A list of message sources currently online. - - @type contactsList: L{ContactsList} - @ivar contactsList: A contacts list. - """ - def __init__(self): - self.conversations = {} - self.groupConversations = {} - self.persons = {} - self.groups = {} - self.onlineClients = [] - self.contactsList = ContactsList(self) - - - def registerAccountClient(self, client): - """ - Notify the user that an account has been signed on to. - - @type client: L{IClient<interfaces.IClient>} provider - @param client: The client account for the person who has just signed on. - - @rtype client: L{IClient<interfaces.IClient>} provider - @return: The client, so that it may be used in a callback chain. - """ - self.onlineClients.append(client) - self.contactsList.registerAccountClient(client) - return client - - - def unregisterAccountClient(self, client): - """ - Notify the user that an account has been signed off or disconnected. - - @type client: L{IClient<interfaces.IClient>} provider - @param client: The client account for the person who has just signed - off. - """ - self.onlineClients.remove(client) - self.contactsList.unregisterAccountClient(client) - - - def getContactsList(self): - """ - Get the contacts list associated with this chat window. - - @rtype: L{ContactsList} - @return: The contacts list associated with this chat window. - """ - return self.contactsList - - - def getConversation(self, person, Class=Conversation, stayHidden=False): - """ - For the given person object, return the conversation window or create - and return a new conversation window if one does not exist. - - @type person: L{IPerson<interfaces.IPerson>} provider - @param person: The person whose conversation window we want to get. - - @type Class: L{IConversation<interfaces.IConversation>} implementor - @param: The kind of conversation window we want. If the conversation - window for this person didn't already exist, create one of this type. - - @type stayHidden: C{bool} - @param stayHidden: Whether or not the conversation window should stay - hidden. - - @rtype: L{IConversation<interfaces.IConversation>} provider - @return: The conversation window. - """ - conv = self.conversations.get(person) - if not conv: - conv = Class(person, self) - self.conversations[person] = conv - if stayHidden: - conv.hide() - else: - conv.show() - return conv - - - def getGroupConversation(self, group, Class=GroupConversation, - stayHidden=False): - """ - For the given group object, return the group conversation window or - create and return a new group conversation window if it doesn't exist. - - @type group: L{IGroup<interfaces.IGroup>} provider - @param group: The group whose conversation window we want to get. - - @type Class: L{IConversation<interfaces.IConversation>} implementor - @param: The kind of conversation window we want. If the conversation - window for this person didn't already exist, create one of this type. - - @type stayHidden: C{bool} - @param stayHidden: Whether or not the conversation window should stay - hidden. - - @rtype: L{IGroupConversation<interfaces.IGroupConversation>} provider - @return: The group conversation window. - """ - conv = self.groupConversations.get(group) - if not conv: - conv = Class(group, self) - self.groupConversations[group] = conv - if stayHidden: - conv.hide() - else: - conv.show() - return conv - - - def getPerson(self, name, client): - """ - For the given name and account client, return an instance of a - L{IGroup<interfaces.IPerson>} provider or create and return a new - instance of a L{IGroup<interfaces.IPerson>} provider. - - @type name: C{str} - @param name: The name of the person of interest. - - @type client: L{IClient<interfaces.IClient>} provider - @param client: The client account of interest. - - @rtype: L{IPerson<interfaces.IPerson>} provider - @return: The person with that C{name}. - """ - account = client.account - p = self.persons.get((name, account)) - if not p: - p = account.getPerson(name) - self.persons[name, account] = p - return p - - - def getGroup(self, name, client): - """ - For the given name and account client, return an instance of a - L{IGroup<interfaces.IGroup>} provider or create and return a new instance - of a L{IGroup<interfaces.IGroup>} provider. - - @type name: C{str} - @param name: The name of the group of interest. - - @type client: L{IClient<interfaces.IClient>} provider - @param client: The client account of interest. - - @rtype: L{IGroup<interfaces.IGroup>} provider - @return: The group with that C{name}. - """ - # I accept 'client' instead of 'account' in my signature for - # backwards compatibility. (Groups changed to be Account-oriented - # in CVS revision 1.8.) - account = client.account - g = self.groups.get((name, account)) - if not g: - g = account.getGroup(name) - self.groups[name, account] = g - return g - - - def contactChangedNick(self, person, newnick): - """ - For the given C{person}, change the C{person}'s C{name} to C{newnick} - and tell the contact list and any conversation windows with that - C{person} to change as well. - - @type person: L{IPerson<interfaces.IPerson>} provider - @param person: The person whose nickname will get changed. - - @type newnick: C{str} - @param newnick: The new C{name} C{person} will take. - """ - oldnick = person.name - if (oldnick, person.account) in self.persons: - conv = self.conversations.get(person) - if conv: - conv.contactChangedNick(person, newnick) - self.contactsList.contactChangedNick(person, newnick) - del self.persons[oldnick, person.account] - person.name = newnick - self.persons[person.name, person.account] = person diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/basesupport.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/basesupport.py deleted file mode 100644 index 43b4c1a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/basesupport.py +++ /dev/null @@ -1,269 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Instance Messenger base classes for protocol support. - -You will find these useful if you're adding a new protocol to IM. -""" - -# Abstract representation of chat "model" classes - -from twisted.words.im.locals import OFFLINE, OfflineError - -from twisted.internet.protocol import Protocol - -from twisted.python.reflect import prefixedMethods -from twisted.persisted import styles - -from twisted.internet import error - -class AbstractGroup: - def __init__(self, name, account): - self.name = name - self.account = account - - def getGroupCommands(self): - """finds group commands - - these commands are methods on me that start with imgroup_; they are - called with no arguments - """ - return prefixedMethods(self, "imgroup_") - - def getTargetCommands(self, target): - """finds group commands - - these commands are methods on me that start with imgroup_; they are - called with a user present within this room as an argument - - you may want to override this in your group in order to filter for - appropriate commands on the given user - """ - return prefixedMethods(self, "imtarget_") - - def join(self): - if not self.account.client: - raise OfflineError - self.account.client.joinGroup(self.name) - - def leave(self): - if not self.account.client: - raise OfflineError - self.account.client.leaveGroup(self.name) - - def __repr__(self): - return '<%s %r>' % (self.__class__, self.name) - - def __str__(self): - return '%s@%s' % (self.name, self.account.accountName) - -class AbstractPerson: - def __init__(self, name, baseAccount): - self.name = name - self.account = baseAccount - self.status = OFFLINE - - def getPersonCommands(self): - """finds person commands - - these commands are methods on me that start with imperson_; they are - called with no arguments - """ - return prefixedMethods(self, "imperson_") - - def getIdleTime(self): - """ - Returns a string. - """ - return '--' - - def __repr__(self): - return '<%s %r/%s>' % (self.__class__, self.name, self.status) - - def __str__(self): - return '%s@%s' % (self.name, self.account.accountName) - -class AbstractClientMixin: - """Designed to be mixed in to a Protocol implementing class. - - Inherit from me first. - - @ivar _logonDeferred: Fired when I am done logging in. - """ - def __init__(self, account, chatui, logonDeferred): - for base in self.__class__.__bases__: - if issubclass(base, Protocol): - self.__class__._protoBase = base - break - else: - pass - self.account = account - self.chat = chatui - self._logonDeferred = logonDeferred - - def connectionMade(self): - self._protoBase.connectionMade(self) - - def connectionLost(self, reason): - self.account._clientLost(self, reason) - self.unregisterAsAccountClient() - return self._protoBase.connectionLost(self, reason) - - def unregisterAsAccountClient(self): - """Tell the chat UI that I have `signed off'. - """ - self.chat.unregisterAccountClient(self) - - -class AbstractAccount(styles.Versioned): - """Base class for Accounts. - - I am the start of an implementation of L{IAccount<interfaces.IAccount>}, I - implement L{isOnline} and most of L{logOn}, though you'll need to implement - L{_startLogOn} in a subclass. - - @cvar _groupFactory: A Callable that will return a L{IGroup} appropriate - for this account type. - @cvar _personFactory: A Callable that will return a L{IPerson} appropriate - for this account type. - - @type _isConnecting: boolean - @ivar _isConnecting: Whether I am in the process of establishing a - connection to the server. - @type _isOnline: boolean - @ivar _isOnline: Whether I am currently on-line with the server. - - @ivar accountName: - @ivar autoLogin: - @ivar username: - @ivar password: - @ivar host: - @ivar port: - """ - - _isOnline = 0 - _isConnecting = 0 - client = None - - _groupFactory = AbstractGroup - _personFactory = AbstractPerson - - persistanceVersion = 2 - - def __init__(self, accountName, autoLogin, username, password, host, port): - self.accountName = accountName - self.autoLogin = autoLogin - self.username = username - self.password = password - self.host = host - self.port = port - - self._groups = {} - self._persons = {} - - def upgrateToVersion2(self): - # Added in CVS revision 1.16. - for k in ('_groups', '_persons'): - if not hasattr(self, k): - setattr(self, k, {}) - - def __getstate__(self): - state = styles.Versioned.__getstate__(self) - for k in ('client', '_isOnline', '_isConnecting'): - try: - del state[k] - except KeyError: - pass - return state - - def isOnline(self): - return self._isOnline - - def logOn(self, chatui): - """Log on to this account. - - Takes care to not start a connection if a connection is - already in progress. You will need to implement - L{_startLogOn} for this to work, and it would be a good idea - to override L{_loginFailed} too. - - @returntype: Deferred L{interfaces.IClient} - """ - if (not self._isConnecting) and (not self._isOnline): - self._isConnecting = 1 - d = self._startLogOn(chatui) - d.addCallback(self._cb_logOn) - # if chatui is not None: - # (I don't particularly like having to pass chatUI to this function, - # but we haven't factored it out yet.) - d.addCallback(chatui.registerAccountClient) - d.addErrback(self._loginFailed) - return d - else: - raise error.ConnectError("Connection in progress") - - def getGroup(self, name): - """Group factory. - - @param name: Name of the group on this account. - @type name: string - """ - group = self._groups.get(name) - if group is None: - group = self._groupFactory(name, self) - self._groups[name] = group - return group - - def getPerson(self, name): - """Person factory. - - @param name: Name of the person on this account. - @type name: string - """ - person = self._persons.get(name) - if person is None: - person = self._personFactory(name, self) - self._persons[name] = person - return person - - def _startLogOn(self, chatui): - """Start the sign on process. - - Factored out of L{logOn}. - - @returntype: Deferred L{interfaces.IClient} - """ - raise NotImplementedError() - - def _cb_logOn(self, client): - self._isConnecting = 0 - self._isOnline = 1 - self.client = client - return client - - def _loginFailed(self, reason): - """Errorback for L{logOn}. - - @type reason: Failure - - @returns: I{reason}, for further processing in the callback chain. - @returntype: Failure - """ - self._isConnecting = 0 - self._isOnline = 0 # just in case - return reason - - def _clientLost(self, client, reason): - self.client = None - self._isConnecting = 0 - self._isOnline = 0 - return reason - - def __repr__(self): - return "<%s: %s (%s@%s:%s)>" % (self.__class__, - self.accountName, - self.username, - self.host, - self.port) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/instancemessenger.glade b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/instancemessenger.glade deleted file mode 100644 index 33ffaa2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/instancemessenger.glade +++ /dev/null @@ -1,3165 +0,0 @@ -<?xml version="1.0"?> -<GTK-Interface> - -<project> - <name>InstanceMessenger</name> - <program_name>instancemessenger</program_name> - <directory></directory> - <source_directory>src</source_directory> - <pixmaps_directory>pixmaps</pixmaps_directory> - <language>C</language> - <gnome_support>True</gnome_support> - <gettext_support>True</gettext_support> - <use_widget_names>True</use_widget_names> -</project> - -<widget> - <class>GtkWindow</class> - <name>UnseenConversationWindow</name> - <visible>False</visible> - <title>Unseen Conversation Window</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkVBox</class> - <name>ConversationWidget</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkVPaned</class> - <name>vpaned1</name> - <handle_size>10</handle_size> - <gutter_size>6</gutter_size> - <position>0</position> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow10</name> - <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <shrink>False</shrink> - <resize>True</resize> - </child> - - <widget> - <class>GtkText</class> - <name>ConversationOutput</name> - <editable>False</editable> - <text></text> - </widget> - </widget> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow11</name> - <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <shrink>True</shrink> - <resize>False</resize> - </child> - - <widget> - <class>GtkText</class> - <name>ConversationMessageEntry</name> - <can_focus>True</can_focus> - <has_focus>True</has_focus> - <signal> - <name>key_press_event</name> - <handler>handle_key_press_event</handler> - <last_modification_time>Tue, 29 Jan 2002 12:42:58 GMT</last_modification_time> - </signal> - <editable>True</editable> - <text></text> - </widget> - </widget> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox9</name> - <homogeneous>True</homogeneous> - <spacing>0</spacing> - <child> - <padding>3</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>button42</name> - <can_focus>True</can_focus> - <label> Send Message </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>3</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>AddRemoveContact</name> - <can_focus>True</can_focus> - <label> Add Contact </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>3</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>CloseContact</name> - <can_focus>True</can_focus> - <label> Close </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>3</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>MainIMWindow</name> - <signal> - <name>destroy</name> - <handler>on_MainIMWindow_destroy</handler> - <last_modification_time>Sun, 21 Jul 2002 08:16:08 GMT</last_modification_time> - </signal> - <title>Instance Messenger</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>True</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkNotebook</class> - <name>ContactsNotebook</name> - <can_focus>True</can_focus> - <signal> - <name>key_press_event</name> - <handler>on_ContactsWidget_key_press_event</handler> - <last_modification_time>Tue, 07 May 2002 03:02:33 GMT</last_modification_time> - </signal> - <show_tabs>True</show_tabs> - <show_border>True</show_border> - <tab_pos>GTK_POS_TOP</tab_pos> - <scrollable>False</scrollable> - <tab_hborder>2</tab_hborder> - <tab_vborder>2</tab_vborder> - <popup_enable>False</popup_enable> - - <widget> - <class>GtkVBox</class> - <name>vbox11</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkLabel</class> - <name>OnlineCount</name> - <label>Online: %d</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow14</name> - <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCTree</class> - <name>OnlineContactsTree</name> - <can_focus>True</can_focus> - <signal> - <name>tree_select_row</name> - <handler>on_OnlineContactsTree_tree_select_row</handler> - <last_modification_time>Tue, 07 May 2002 03:06:32 GMT</last_modification_time> - </signal> - <signal> - <name>select_row</name> - <handler>on_OnlineContactsTree_select_row</handler> - <last_modification_time>Tue, 07 May 2002 04:36:10 GMT</last_modification_time> - </signal> - <columns>4</columns> - <column_widths>109,35,23,80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>True</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CTree:title</child_name> - <name>label77</name> - <label>Alias</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CTree:title</child_name> - <name>label78</name> - <label>Status</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CTree:title</child_name> - <name>label79</name> - <label>Idle</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CTree:title</child_name> - <name>label80</name> - <label>Account</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - - <widget> - <class>GtkVBox</class> - <name>vbox30</name> - <homogeneous>False</homogeneous> - <spacing>2</spacing> - <child> - <padding>1</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkEntry</class> - <name>ContactNameEntry</name> - <can_focus>True</can_focus> - <signal> - <name>activate</name> - <handler>on_ContactNameEntry_activate</handler> - <last_modification_time>Tue, 07 May 2002 04:07:25 GMT</last_modification_time> - </signal> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkOptionMenu</class> - <name>AccountsListPopup</name> - <can_focus>True</can_focus> - <items>Nothing -To -Speak -Of -</items> - <initial_choice>1</initial_choice> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox7</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>PlainSendIM</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_PlainSendIM_clicked</handler> - <last_modification_time>Tue, 29 Jan 2002 03:17:35 GMT</last_modification_time> - </signal> - <label> Send IM </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>PlainGetInfo</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_PlainGetInfo_clicked</handler> - <last_modification_time>Tue, 07 May 2002 04:06:59 GMT</last_modification_time> - </signal> - <label> Get Info </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>PlainJoinChat</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_PlainJoinChat_clicked</handler> - <last_modification_time>Tue, 29 Jan 2002 13:04:49 GMT</last_modification_time> - </signal> - <label> Join Group </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>PlainGoAway</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_PlainGoAway_clicked</handler> - <last_modification_time>Tue, 07 May 2002 04:06:53 GMT</last_modification_time> - </signal> - <label> Go Away </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox8</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>AddContactButton</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_AddContactButton_clicked</handler> - <last_modification_time>Tue, 07 May 2002 04:06:33 GMT</last_modification_time> - </signal> - <label> Add Contact </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>RemoveContactButton</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_RemoveContactButton_clicked</handler> - <last_modification_time>Tue, 07 May 2002 04:06:28 GMT</last_modification_time> - </signal> - <label> Remove Contact </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - </widget> - </widget> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label35</name> - <label> Online Contacts </label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkVBox</class> - <name>vbox14</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkScrolledWindow</class> - <name>OfflineContactsScroll</name> - <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCList</class> - <name>OfflineContactsList</name> - <can_focus>True</can_focus> - <signal> - <name>select_row</name> - <handler>on_OfflineContactsList_select_row</handler> - <last_modification_time>Tue, 07 May 2002 03:00:07 GMT</last_modification_time> - </signal> - <columns>4</columns> - <column_widths>66,80,80,80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>True</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label41</name> - <label>Contact</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label42</name> - <label>Account</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label43</name> - <label>Alias</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label44</name> - <label>Group</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label36</name> - <label> All Contacts </label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkVBox</class> - <name>AccountManWidget</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow12</name> - <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCList</class> - <name>accountsList</name> - <can_focus>True</can_focus> - <columns>4</columns> - <column_widths>80,36,34,80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>True</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label45</name> - <label>Service Name</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label46</name> - <label>Online</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label47</name> - <label>Auto</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label48</name> - <label>Gateway</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - - <widget> - <class>GtkTable</class> - <name>table5</name> - <rows>2</rows> - <columns>3</columns> - <homogeneous>False</homogeneous> - <row_spacing>0</row_spacing> - <column_spacing>0</column_spacing> - <child> - <padding>3</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>NewAccountButton</name> - <can_default>True</can_default> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_NewAccountButton_clicked</handler> - <last_modification_time>Sun, 27 Jan 2002 10:32:20 GMT</last_modification_time> - </signal> - <label>New Account</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button46</name> - <sensitive>False</sensitive> - <can_default>True</can_default> - <label>Modify Account</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>LogOnButton</name> - <can_default>True</can_default> - <has_default>True</has_default> - <can_focus>True</can_focus> - <has_focus>True</has_focus> - <signal> - <name>clicked</name> - <handler>on_LogOnButton_clicked</handler> - <last_modification_time>Mon, 28 Jan 2002 04:06:23 GMT</last_modification_time> - </signal> - <label>Logon</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <left_attach>2</left_attach> - <right_attach>3</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>DeleteAccountButton</name> - <can_default>True</can_default> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_DeleteAccountButton_clicked</handler> - <last_modification_time>Mon, 28 Jan 2002 00:18:22 GMT</last_modification_time> - </signal> - <label>Delete Account</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <left_attach>2</left_attach> - <right_attach>3</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>ConsoleButton</name> - <can_default>True</can_default> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_ConsoleButton_clicked</handler> - <last_modification_time>Mon, 29 Apr 2002 09:13:32 GMT</last_modification_time> - </signal> - <label>Console</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button75</name> - <can_default>True</can_default> - <can_focus>True</can_focus> - <label>Quit</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>True</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>True</yfill> - </child> - </widget> - </widget> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label107</name> - <label>Accounts</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>UnseenGroupWindow</name> - <visible>False</visible> - <title>Unseen Group Window</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkVBox</class> - <name>GroupChatBox</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkHBox</class> - <name>hbox5</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkEntry</class> - <name>TopicEntry</name> - <can_focus>True</can_focus> - <signal> - <name>activate</name> - <handler>on_TopicEntry_activate</handler> - <last_modification_time>Sat, 23 Feb 2002 02:57:41 GMT</last_modification_time> - </signal> - <signal> - <name>focus_out_event</name> - <handler>on_TopicEntry_focus_out_event</handler> - <last_modification_time>Sun, 21 Jul 2002 09:36:54 GMT</last_modification_time> - </signal> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text>&lt;TOPIC NOT RECEIVED&gt;</text> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>AuthorLabel</name> - <label>&lt;nobody&gt;</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>HideButton</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_HideButton_clicked</handler> - <last_modification_time>Tue, 29 Jan 2002 14:10:00 GMT</last_modification_time> - </signal> - <label>&lt;</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - </widget> - - <widget> - <class>GtkVPaned</class> - <name>vpaned2</name> - <handle_size>10</handle_size> - <gutter_size>6</gutter_size> - <position>0</position> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkHPaned</class> - <name>GroupHPaned</name> - <handle_size>6</handle_size> - <gutter_size>6</gutter_size> - <child> - <shrink>False</shrink> - <resize>True</resize> - </child> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow4</name> - <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <shrink>False</shrink> - <resize>True</resize> - </child> - - <widget> - <class>GtkText</class> - <name>GroupOutput</name> - <can_focus>True</can_focus> - <editable>False</editable> - <text></text> - </widget> - </widget> - - <widget> - <class>GtkVBox</class> - <name>actionvbox</name> - <width>110</width> - <homogeneous>False</homogeneous> - <spacing>1</spacing> - <child> - <shrink>True</shrink> - <resize>False</resize> - </child> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow5</name> - <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCList</class> - <name>ParticipantList</name> - <can_focus>True</can_focus> - <signal> - <name>select_row</name> - <handler>on_ParticipantList_select_row</handler> - <last_modification_time>Sat, 13 Jul 2002 08:11:12 GMT</last_modification_time> - </signal> - <signal> - <name>unselect_row</name> - <handler>on_ParticipantList_unselect_row</handler> - <last_modification_time>Sat, 13 Jul 2002 08:23:25 GMT</last_modification_time> - </signal> - <columns>1</columns> - <column_widths>80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>False</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label18</name> - <label>Users</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>frame10</name> - <label>Group</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - - <widget> - <class>GtkVBox</class> - <name>GroupActionsBox</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>Placeholder</class> - </widget> - - <widget> - <class>Placeholder</class> - </widget> - - <widget> - <class>Placeholder</class> - </widget> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>PersonFrame</name> - <label>Person</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - - <widget> - <class>GtkVBox</class> - <name>PersonActionsBox</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>Placeholder</class> - </widget> - - <widget> - <class>Placeholder</class> - </widget> - - <widget> - <class>Placeholder</class> - </widget> - </widget> - </widget> - </widget> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox6</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <shrink>True</shrink> - <resize>False</resize> - </child> - - <widget> - <class>GtkLabel</class> - <name>NickLabel</name> - <label>&lt;no nick&gt;</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <padding>4</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow9</name> - <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkText</class> - <name>GroupInput</name> - <can_focus>True</can_focus> - <has_focus>True</has_focus> - <signal> - <name>key_press_event</name> - <handler>handle_key_press_event</handler> - <last_modification_time>Tue, 29 Jan 2002 12:41:03 GMT</last_modification_time> - </signal> - <editable>True</editable> - <text></text> - </widget> - </widget> - </widget> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>NewAccountWindow</name> - <border_width>3</border_width> - <visible>False</visible> - <signal> - <name>destroy</name> - <handler>on_NewAccountWindow_destroy</handler> - <last_modification_time>Sun, 27 Jan 2002 10:35:19 GMT</last_modification_time> - </signal> - <title>New Account</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>True</auto_shrink> - - <widget> - <class>GtkVBox</class> - <name>vbox17</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkHBox</class> - <name>hbox11</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <padding>3</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkLabel</class> - <name>label49</name> - <label>Gateway:</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkOptionMenu</class> - <name>GatewayOptionMenu</name> - <can_focus>True</can_focus> - <items>Twisted (Perspective Broker) -Internet Relay Chat -AIM (TOC) -AIM (OSCAR) -</items> - <initial_choice>0</initial_choice> - <child> - <padding>4</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>GatewayFrame</name> - <border_width>3</border_width> - <label>Gateway Options</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>Placeholder</class> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>frame2</name> - <border_width>3</border_width> - <label>Standard Options</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkTable</class> - <name>table1</name> - <border_width>3</border_width> - <rows>2</rows> - <columns>2</columns> - <homogeneous>False</homogeneous> - <row_spacing>0</row_spacing> - <column_spacing>0</column_spacing> - - <widget> - <class>GtkCheckButton</class> - <name>AutoLogin</name> - <can_focus>True</can_focus> - <label>Automatically Log In</label> - <active>False</active> - <draw_indicator>True</draw_indicator> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>True</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>accountName</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>True</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label50</name> - <label> Auto-Login: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>True</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>True</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label51</name> - <label>Account Name: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>True</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>True</yfill> - </child> - </widget> - </widget> - </widget> - - <widget> - <class>GtkHButtonBox</class> - <name>hbuttonbox2</name> - <layout_style>GTK_BUTTONBOX_SPREAD</layout_style> - <spacing>30</spacing> - <child_min_width>85</child_min_width> - <child_min_height>27</child_min_height> - <child_ipad_x>7</child_ipad_x> - <child_ipad_y>0</child_ipad_y> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>button50</name> - <can_default>True</can_default> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>createAccount</handler> - <last_modification_time>Sun, 27 Jan 2002 11:25:05 GMT</last_modification_time> - </signal> - <label>OK</label> - <relief>GTK_RELIEF_NORMAL</relief> - </widget> - - <widget> - <class>GtkButton</class> - <name>button51</name> - <can_default>True</can_default> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>destroyMe</handler> - <last_modification_time>Sun, 27 Jan 2002 11:27:12 GMT</last_modification_time> - </signal> - <label>Cancel</label> - <relief>GTK_RELIEF_NORMAL</relief> - </widget> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>PBAccountWindow</name> - <visible>False</visible> - <title>PB Account Window</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkVBox</class> - <name>PBAccountWidget</name> - <border_width>4</border_width> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkTable</class> - <name>table3</name> - <rows>4</rows> - <columns>2</columns> - <homogeneous>False</homogeneous> - <row_spacing>0</row_spacing> - <column_spacing>0</column_spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkEntry</class> - <name>hostname</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text>twistedmatrix.com</text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>identity</name> - <can_focus>True</can_focus> - <has_focus>True</has_focus> - <signal> - <name>changed</name> - <handler>on_identity_changed</handler> - <last_modification_time>Sun, 27 Jan 2002 11:52:17 GMT</last_modification_time> - </signal> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label52</name> - <label> Hostname: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label54</name> - <label>Identity Name: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>password</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>False</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>portno</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text>8787</text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>3</top_attach> - <bottom_attach>4</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label55</name> - <label> Password: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label53</name> - <label> Port Number: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>3</top_attach> - <bottom_attach>4</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>frame3</name> - <label>Perspectives</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkVBox</class> - <name>vbox19</name> - <border_width>3</border_width> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow13</name> - <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCList</class> - <name>serviceList</name> - <can_focus>True</can_focus> - <signal> - <name>select_row</name> - <handler>on_serviceList_select_row</handler> - <last_modification_time>Sun, 27 Jan 2002 12:04:38 GMT</last_modification_time> - </signal> - <columns>3</columns> - <column_widths>80,80,80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>True</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label60</name> - <label>Service Type</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label61</name> - <label>Service Name</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label62</name> - <label>Perspective Name</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - - <widget> - <class>GtkTable</class> - <name>table4</name> - <rows>3</rows> - <columns>2</columns> - <homogeneous>False</homogeneous> - <row_spacing>0</row_spacing> - <column_spacing>0</column_spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkLabel</class> - <name>label63</name> - <label>Perspective Name: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label59</name> - <label> Service Type: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkCombo</class> - <name>serviceCombo</name> - <value_in_list>False</value_in_list> - <ok_if_empty>True</ok_if_empty> - <case_sensitive>False</case_sensitive> - <use_arrows>True</use_arrows> - <use_arrows_always>False</use_arrows_always> - <items>twisted.words -twisted.reality -twisted.manhole -</items> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - - <widget> - <class>GtkEntry</class> - <child_name>GtkCombo:entry</child_name> - <name>serviceType</name> - <can_focus>True</can_focus> - <signal> - <name>changed</name> - <handler>on_serviceType_changed</handler> - <last_modification_time>Sun, 27 Jan 2002 11:49:07 GMT</last_modification_time> - </signal> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text>twisted.words</text> - </widget> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label64</name> - <label> Service Name: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>serviceName</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>perspectiveName</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox13</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>button53</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>addPerspective</handler> - <last_modification_time>Mon, 28 Jan 2002 01:07:15 GMT</last_modification_time> - </signal> - <label> Add Perspective </label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button54</name> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>removePerspective</handler> - <last_modification_time>Sun, 27 Jan 2002 11:34:36 GMT</last_modification_time> - </signal> - <label>Remove Perspective</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>False</fill> - </child> - </widget> - </widget> - </widget> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>IRCAccountWindow</name> - <title>IRC Account Window</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkTable</class> - <name>IRCAccountWidget</name> - <rows>5</rows> - <columns>2</columns> - <homogeneous>False</homogeneous> - <row_spacing>0</row_spacing> - <column_spacing>0</column_spacing> - - <widget> - <class>GtkLabel</class> - <name>label65</name> - <label> Nickname: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label66</name> - <label> Server: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label67</name> - <label> Port: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label68</name> - <label> Channels: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>3</top_attach> - <bottom_attach>4</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label69</name> - <label> Password: </label> - <justify>GTK_JUSTIFY_RIGHT</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>4</top_attach> - <bottom_attach>5</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>ircNick</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>ircServer</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>ircPort</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text>6667</text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>ircChannels</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>3</top_attach> - <bottom_attach>4</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>ircPassword</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>4</top_attach> - <bottom_attach>5</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>TOCAccountWindow</name> - <title>TOC Account Window</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkTable</class> - <name>TOCAccountWidget</name> - <rows>4</rows> - <columns>2</columns> - <homogeneous>False</homogeneous> - <row_spacing>0</row_spacing> - <column_spacing>0</column_spacing> - - <widget> - <class>GtkLabel</class> - <name>label70</name> - <label> Screen Name: </label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label71</name> - <label> Password: </label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label72</name> - <label> Host: </label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label73</name> - <label> Port: </label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>3</top_attach> - <bottom_attach>4</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>TOCName</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>TOCPass</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>False</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>TOCHost</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text>toc.oscar.aol.com</text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>2</top_attach> - <bottom_attach>3</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>TOCPort</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text>9898</text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>3</top_attach> - <bottom_attach>4</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>JoinGroupWindow</name> - <border_width>5</border_width> - <visible>False</visible> - <title>Group to Join</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkVBox</class> - <name>vbox20</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkOptionMenu</class> - <name>AccountSelector</name> - <can_focus>True</can_focus> - <items>None -In -Particular -</items> - <initial_choice>0</initial_choice> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox15</name> - <homogeneous>False</homogeneous> - <spacing>5</spacing> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkEntry</class> - <name>GroupNameEntry</name> - <can_focus>True</can_focus> - <has_focus>True</has_focus> - <signal> - <name>activate</name> - <handler>on_GroupJoinButton_clicked</handler> - <last_modification_time>Tue, 29 Jan 2002 13:27:18 GMT</last_modification_time> - </signal> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>GroupJoinButton</name> - <can_default>True</can_default> - <has_default>True</has_default> - <can_focus>True</can_focus> - <signal> - <name>clicked</name> - <handler>on_GroupJoinButton_clicked</handler> - <last_modification_time>Tue, 29 Jan 2002 13:16:50 GMT</last_modification_time> - </signal> - <label>Join</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - </widget> - </widget> -</widget> - -<widget> - <class>GtkWindow</class> - <name>UnifiedWindow</name> - <title>Twisted Instance Messenger</title> - <type>GTK_WINDOW_TOPLEVEL</type> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>True</allow_grow> - <auto_shrink>False</auto_shrink> - - <widget> - <class>GtkVBox</class> - <name>vbox25</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkHBox</class> - <name>hbox28</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>button74</name> - <can_focus>True</can_focus> - <label>&gt;</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>entry3</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkOptionMenu</class> - <name>optionmenu3</name> - <items>List -Of -Online -Accounts -</items> - <initial_choice>0</initial_choice> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkOptionMenu</class> - <name>optionmenu4</name> - <can_focus>True</can_focus> - <items>Contact -Person -Group -Account -</items> - <initial_choice>0</initial_choice> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - </widget> - - <widget> - <class>GtkHPaned</class> - <name>hpaned1</name> - <handle_size>10</handle_size> - <gutter_size>6</gutter_size> - <position>0</position> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkVBox</class> - <name>vbox26</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - <child> - <shrink>True</shrink> - <resize>False</resize> - </child> - - <widget> - <class>GtkFrame</class> - <name>frame7</name> - <border_width>2</border_width> - <label>Accounts</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkVBox</class> - <name>vbox27</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow18</name> - <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCList</class> - <name>clist4</name> - <columns>4</columns> - <column_widths>18,25,25,80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>False</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label95</name> - <label>label87</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label96</name> - <label>label88</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label97</name> - <label>label89</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label98</name> - <label>label90</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox23</name> - <homogeneous>True</homogeneous> - <spacing>2</spacing> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>button65</name> - <label>New</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button66</name> - <label>Delete</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button67</name> - <label>Connect</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - </widget> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>frame8</name> - <border_width>2</border_width> - <label>Contacts</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkVBox</class> - <name>vbox28</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow19</name> - <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCList</class> - <name>clist5</name> - <columns>3</columns> - <column_widths>18,17,80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>False</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label99</name> - <label>label84</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label100</name> - <label>label85</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label101</name> - <label>label86</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox24</name> - <homogeneous>True</homogeneous> - <spacing>2</spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>button68</name> - <can_focus>True</can_focus> - <label>Talk</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button69</name> - <can_focus>True</can_focus> - <label>Info</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button70</name> - <can_focus>True</can_focus> - <label>Add</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button71</name> - <can_focus>True</can_focus> - <label>Remove</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - </widget> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>frame9</name> - <border_width>2</border_width> - <label>Groups</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkVBox</class> - <name>vbox29</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow20</name> - <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkCList</class> - <name>clist6</name> - <columns>3</columns> - <column_widths>21,75,80</column_widths> - <selection_mode>GTK_SELECTION_SINGLE</selection_mode> - <show_titles>False</show_titles> - <shadow_type>GTK_SHADOW_IN</shadow_type> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label102</name> - <label>label91</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label103</name> - <label>label92</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>CList:title</child_name> - <name>label104</name> - <label>label93</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - </widget> - </widget> - </widget> - - <widget> - <class>GtkHBox</class> - <name>hbox27</name> - <homogeneous>True</homogeneous> - <spacing>2</spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>button72</name> - <label>Join</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkButton</class> - <name>button73</name> - <label>Leave</label> - <relief>GTK_RELIEF_NORMAL</relief> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - </widget> - </widget> - </widget> - - <widget> - <class>GtkHSeparator</class> - <name>hseparator2</name> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label105</name> - <label>Twisted IM V. %s</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>3</ypad> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label106</name> - <label>This -Space -Left -Intentionally -Blank -(Here is where the UI for the currently -selected element -for interaction -will go.)</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <shrink>True</shrink> - <resize>True</resize> - </child> - </widget> - </widget> - </widget> -</widget> - -</GTK-Interface> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/interfaces.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/interfaces.py deleted file mode 100644 index b1d48cd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/interfaces.py +++ /dev/null @@ -1,362 +0,0 @@ -# -*- Python -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Pan-protocol chat client. -""" - -from zope.interface import Interface, Attribute - -# (Random musings, may not reflect on current state of code:) -# -# Accounts have Protocol components (clients) -# Persons have Conversation components -# Groups have GroupConversation components -# Persons and Groups are associated with specific Accounts -# At run-time, Clients/Accounts are slaved to a User Interface -# (Note: User may be a bot, so don't assume all UIs are built on gui toolkits) - - -class IAccount(Interface): - """ - I represent a user's account with a chat service. - """ - - client = Attribute('The L{IClient} currently connecting to this account, if any.') - gatewayType = Attribute('A C{str} that identifies the protocol used by this account.') - - def __init__(accountName, autoLogin, username, password, host, port): - """ - @type accountName: string - @param accountName: A name to refer to the account by locally. - @type autoLogin: boolean - @type username: string - @type password: string - @type host: string - @type port: integer - """ - - def isOnline(): - """ - Am I online? - - @rtype: boolean - """ - - def logOn(chatui): - """ - Go on-line. - - @type chatui: Implementor of C{IChatUI} - - @rtype: L{Deferred} L{Client} - """ - - def logOff(): - """ - Sign off. - """ - - def getGroup(groupName): - """ - @rtype: L{Group<IGroup>} - """ - - def getPerson(personName): - """ - @rtype: L{Person<IPerson>} - """ - -class IClient(Interface): - - account = Attribute('The L{IAccount} I am a Client for') - - def __init__(account, chatui, logonDeferred): - """ - @type account: L{IAccount} - @type chatui: L{IChatUI} - @param logonDeferred: Will be called back once I am logged on. - @type logonDeferred: L{Deferred<twisted.internet.defer.Deferred>} - """ - - def joinGroup(groupName): - """ - @param groupName: The name of the group to join. - @type groupName: string - """ - - def leaveGroup(groupName): - """ - @param groupName: The name of the group to leave. - @type groupName: string - """ - - def getGroupConversation(name, hide=0): - pass - - def getPerson(name): - pass - - -class IPerson(Interface): - - def __init__(name, account): - """ - Initialize me. - - @param name: My name, as the server knows me. - @type name: string - @param account: The account I am accessed through. - @type account: I{Account} - """ - - def isOnline(): - """ - Am I online right now? - - @rtype: boolean - """ - - def getStatus(): - """ - What is my on-line status? - - @return: L{locals.StatusEnum} - """ - - def getIdleTime(): - """ - @rtype: string (XXX: How about a scalar?) - """ - - def sendMessage(text, metadata=None): - """ - Send a message to this person. - - @type text: string - @type metadata: dict - """ - - -class IGroup(Interface): - """ - A group which you may have a conversation with. - - Groups generally have a loosely-defined set of members, who may - leave and join at any time. - """ - - name = Attribute('My C{str} name, as the server knows me.') - account = Attribute('The L{Account<IAccount>} I am accessed through.') - - def __init__(name, account): - """ - Initialize me. - - @param name: My name, as the server knows me. - @type name: str - @param account: The account I am accessed through. - @type account: L{Account<IAccount>} - """ - - def setTopic(text): - """ - Set this Groups topic on the server. - - @type text: string - """ - - def sendGroupMessage(text, metadata=None): - """ - Send a message to this group. - - @type text: str - - @type metadata: dict - @param metadata: Valid keys for this dictionary include: - - - C{'style'}: associated with one of: - - C{'emote'}: indicates this is an action - """ - - def join(): - """ - Join this group. - """ - - def leave(): - """ - Depart this group. - """ - - -class IConversation(Interface): - """ - A conversation with a specific person. - """ - - def __init__(person, chatui): - """ - @type person: L{IPerson} - """ - - def show(): - """ - doesn't seem like it belongs in this interface. - """ - - def hide(): - """ - nor this neither. - """ - - def sendText(text, metadata): - pass - - def showMessage(text, metadata): - pass - - def changedNick(person, newnick): - """ - @param person: XXX Shouldn't this always be Conversation.person? - """ - -class IGroupConversation(Interface): - - def show(): - """ - doesn't seem like it belongs in this interface. - """ - - def hide(): - """ - nor this neither. - """ - - def sendText(text, metadata): - pass - - def showGroupMessage(sender, text, metadata): - pass - - def setGroupMembers(members): - """ - Sets the list of members in the group and displays it to the user. - """ - - def setTopic(topic, author): - """ - Displays the topic (from the server) for the group conversation window. - - @type topic: string - @type author: string (XXX: Not Person?) - """ - - def memberJoined(member): - """ - Adds the given member to the list of members in the group conversation - and displays this to the user, - - @type member: string (XXX: Not Person?) - """ - - def memberChangedNick(oldnick, newnick): - """ - Changes the oldnick in the list of members to C{newnick} and displays this - change to the user, - - @type oldnick: string (XXX: Not Person?) - @type newnick: string - """ - - def memberLeft(member): - """ - Deletes the given member from the list of members in the group - conversation and displays the change to the user. - - @type member: string (XXX: Not Person?) - """ - - -class IChatUI(Interface): - - def registerAccountClient(client): - """ - Notifies user that an account has been signed on to. - - @type client: L{Client<IClient>} - """ - - def unregisterAccountClient(client): - """ - Notifies user that an account has been signed off or disconnected. - - @type client: L{Client<IClient>} - """ - - def getContactsList(): - """ - @rtype: L{ContactsList} - """ - - # WARNING: You'll want to be polymorphed into something with - # intrinsic stoning resistance before continuing. - - def getConversation(person, Class, stayHidden=0): - """ - For the given person object, returns the conversation window - or creates and returns a new conversation window if one does not exist. - - @type person: L{Person<IPerson>} - @type Class: L{Conversation<IConversation>} class - @type stayHidden: boolean - - @rtype: L{Conversation<IConversation>} - """ - - def getGroupConversation(group, Class, stayHidden=0): - """ - For the given group object, returns the group conversation window or - creates and returns a new group conversation window if it doesn't exist. - - @type group: L{Group<interfaces.IGroup>} - @type Class: L{Conversation<interfaces.IConversation>} class - @type stayHidden: boolean - - @rtype: L{GroupConversation<interfaces.IGroupConversation>} - """ - - def getPerson(name, client): - """ - Get a Person for a client. - - Duplicates L{IAccount.getPerson}. - - @type name: string - @type client: L{Client<IClient>} - - @rtype: L{Person<IPerson>} - """ - - def getGroup(name, client): - """ - Get a Group for a client. - - Duplicates L{IAccount.getGroup}. - - @type name: string - @type client: L{Client<IClient>} - - @rtype: L{Group<IGroup>} - """ - - def contactChangedNick(oldnick, newnick): - """ - For the given person, changes the person's name to newnick, and - tells the contact list and any conversation windows with that person - to change as well. - - @type oldnick: string - @type newnick: string - """ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/ircsupport.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/ircsupport.py deleted file mode 100644 index e05c0e7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/ircsupport.py +++ /dev/null @@ -1,265 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -IRC support for Instance Messenger. -""" - -import string - -from twisted.words.protocols import irc -from twisted.words.im.locals import ONLINE -from twisted.internet import defer, reactor, protocol -from twisted.internet.defer import succeed -from twisted.words.im import basesupport, interfaces, locals -from zope.interface import implements - - -class IRCPerson(basesupport.AbstractPerson): - - def imperson_whois(self): - if self.account.client is None: - raise locals.OfflineError - self.account.client.sendLine("WHOIS %s" % self.name) - - ### interface impl - - def isOnline(self): - return ONLINE - - def getStatus(self): - return ONLINE - - def setStatus(self,status): - self.status=status - self.chat.getContactsList().setContactStatus(self) - - def sendMessage(self, text, meta=None): - if self.account.client is None: - raise locals.OfflineError - for line in string.split(text, '\n'): - if meta and meta.get("style", None) == "emote": - self.account.client.ctcpMakeQuery(self.name,[('ACTION', line)]) - else: - self.account.client.msg(self.name, line) - return succeed(text) - -class IRCGroup(basesupport.AbstractGroup): - - implements(interfaces.IGroup) - - def imgroup_testAction(self): - pass - - def imtarget_kick(self, target): - if self.account.client is None: - raise locals.OfflineError - reason = "for great justice!" - self.account.client.sendLine("KICK #%s %s :%s" % ( - self.name, target.name, reason)) - - ### Interface Implementation - - def setTopic(self, topic): - if self.account.client is None: - raise locals.OfflineError - self.account.client.topic(self.name, topic) - - def sendGroupMessage(self, text, meta={}): - if self.account.client is None: - raise locals.OfflineError - if meta and meta.get("style", None) == "emote": - self.account.client.me(self.name,text) - return succeed(text) - #standard shmandard, clients don't support plain escaped newlines! - for line in string.split(text, '\n'): - self.account.client.say(self.name, line) - return succeed(text) - - def leave(self): - if self.account.client is None: - raise locals.OfflineError - self.account.client.leave(self.name) - self.account.client.getGroupConversation(self.name,1) - - -class IRCProto(basesupport.AbstractClientMixin, irc.IRCClient): - def __init__(self, account, chatui, logonDeferred=None): - basesupport.AbstractClientMixin.__init__(self, account, chatui, - logonDeferred) - self._namreplies={} - self._ingroups={} - self._groups={} - self._topics={} - - def getGroupConversation(self, name, hide=0): - name=string.lower(name) - return self.chat.getGroupConversation(self.chat.getGroup(name, self), - stayHidden=hide) - - def getPerson(self,name): - return self.chat.getPerson(name, self) - - def connectionMade(self): - # XXX: Why do I duplicate code in IRCClient.register? - try: - self.performLogin = True - self.nickname = self.account.username - self.password = self.account.password - self.realname = "Twisted-IM user" - - irc.IRCClient.connectionMade(self) - - for channel in self.account.channels: - self.joinGroup(channel) - self.account._isOnline=1 - if self._logonDeferred is not None: - self._logonDeferred.callback(self) - self.chat.getContactsList() - except: - import traceback - traceback.print_exc() - - def setNick(self,nick): - self.name=nick - self.accountName="%s (IRC)"%nick - irc.IRCClient.setNick(self,nick) - - def kickedFrom(self, channel, kicker, message): - """ - Called when I am kicked from a channel. - """ - return self.chat.getGroupConversation( - self.chat.getGroup(channel[1:], self), 1) - - def userKicked(self, kickee, channel, kicker, message): - pass - - def noticed(self, username, channel, message): - self.privmsg(username, channel, message, {"dontAutoRespond": 1}) - - def privmsg(self, username, channel, message, metadata=None): - if metadata is None: - metadata = {} - username=string.split(username,'!',1)[0] - if username==self.name: return - if channel[0]=='#': - group=channel[1:] - self.getGroupConversation(group).showGroupMessage(username, message, metadata) - return - self.chat.getConversation(self.getPerson(username)).showMessage(message, metadata) - - def action(self,username,channel,emote): - username=string.split(username,'!',1)[0] - if username==self.name: return - meta={'style':'emote'} - if channel[0]=='#': - group=channel[1:] - self.getGroupConversation(group).showGroupMessage(username, emote, meta) - return - self.chat.getConversation(self.getPerson(username)).showMessage(emote,meta) - - def irc_RPL_NAMREPLY(self,prefix,params): - """ - RPL_NAMREPLY - >> NAMES #bnl - << :Arlington.VA.US.Undernet.Org 353 z3p = #bnl :pSwede Dan-- SkOyg AG - """ - group=string.lower(params[2][1:]) - users=string.split(params[3]) - for ui in range(len(users)): - while users[ui][0] in ["@","+"]: # channel modes - users[ui]=users[ui][1:] - if not self._namreplies.has_key(group): - self._namreplies[group]=[] - self._namreplies[group].extend(users) - for nickname in users: - try: - self._ingroups[nickname].append(group) - except: - self._ingroups[nickname]=[group] - - def irc_RPL_ENDOFNAMES(self,prefix,params): - group=params[1][1:] - self.getGroupConversation(group).setGroupMembers(self._namreplies[string.lower(group)]) - del self._namreplies[string.lower(group)] - - def irc_RPL_TOPIC(self,prefix,params): - self._topics[params[1][1:]]=params[2] - - def irc_333(self,prefix,params): - group=params[1][1:] - self.getGroupConversation(group).setTopic(self._topics[group],params[2]) - del self._topics[group] - - def irc_TOPIC(self,prefix,params): - nickname = string.split(prefix,"!")[0] - group = params[0][1:] - topic = params[1] - self.getGroupConversation(group).setTopic(topic,nickname) - - def irc_JOIN(self,prefix,params): - nickname=string.split(prefix,"!")[0] - group=string.lower(params[0][1:]) - if nickname!=self.nickname: - try: - self._ingroups[nickname].append(group) - except: - self._ingroups[nickname]=[group] - self.getGroupConversation(group).memberJoined(nickname) - - def irc_PART(self,prefix,params): - nickname=string.split(prefix,"!")[0] - group=string.lower(params[0][1:]) - if nickname!=self.nickname: - if group in self._ingroups[nickname]: - self._ingroups[nickname].remove(group) - self.getGroupConversation(group).memberLeft(nickname) - - def irc_QUIT(self,prefix,params): - nickname=string.split(prefix,"!")[0] - if self._ingroups.has_key(nickname): - for group in self._ingroups[nickname]: - self.getGroupConversation(group).memberLeft(nickname) - self._ingroups[nickname]=[] - - def irc_NICK(self, prefix, params): - fromNick = string.split(prefix, "!")[0] - toNick = params[0] - if not self._ingroups.has_key(fromNick): - return - for group in self._ingroups[fromNick]: - self.getGroupConversation(group).memberChangedNick(fromNick, toNick) - self._ingroups[toNick] = self._ingroups[fromNick] - del self._ingroups[fromNick] - - def irc_unknown(self, prefix, command, params): - pass - - # GTKIM calls - def joinGroup(self,name): - self.join(name) - self.getGroupConversation(name) - -class IRCAccount(basesupport.AbstractAccount): - implements(interfaces.IAccount) - gatewayType = "IRC" - - _groupFactory = IRCGroup - _personFactory = IRCPerson - - def __init__(self, accountName, autoLogin, username, password, host, port, - channels=''): - basesupport.AbstractAccount.__init__(self, accountName, autoLogin, - username, password, host, port) - self.channels = map(string.strip,string.split(channels,',')) - if self.channels == ['']: - self.channels = [] - - def _startLogOn(self, chatui): - logonDeferred = defer.Deferred() - cc = protocol.ClientCreator(reactor, IRCProto, self, chatui, - logonDeferred) - d = cc.connectTCP(self.host, self.port) - d.addErrback(logonDeferred.errback) - return logonDeferred diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/locals.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/locals.py deleted file mode 100644 index a63547a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/locals.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -class Enum: - group = None - - def __init__(self, label): - self.label = label - - def __repr__(self): - return '<%s: %s>' % (self.group, self.label) - - def __str__(self): - return self.label - - -class StatusEnum(Enum): - group = 'Status' - -OFFLINE = Enum('Offline') -ONLINE = Enum('Online') -AWAY = Enum('Away') - -class OfflineError(Exception): - """The requested action can't happen while offline.""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/pbsupport.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/pbsupport.py deleted file mode 100644 index 04d14e9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/im/pbsupport.py +++ /dev/null @@ -1,260 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -L{twisted.words} support for Instance Messenger. -""" - -from twisted.internet import defer -from twisted.internet import error -from twisted.python import log -from twisted.python.failure import Failure -from twisted.spread import pb - -from twisted.words.im.locals import ONLINE, OFFLINE, AWAY - -from twisted.words.im import basesupport, interfaces -from zope.interface import implements - - -class TwistedWordsPerson(basesupport.AbstractPerson): - """I a facade for a person you can talk to through a twisted.words service. - """ - def __init__(self, name, wordsAccount): - basesupport.AbstractPerson.__init__(self, name, wordsAccount) - self.status = OFFLINE - - def isOnline(self): - return ((self.status == ONLINE) or - (self.status == AWAY)) - - def getStatus(self): - return self.status - - def sendMessage(self, text, metadata): - """Return a deferred... - """ - if metadata: - d=self.account.client.perspective.directMessage(self.name, - text, metadata) - d.addErrback(self.metadataFailed, "* "+text) - return d - else: - return self.account.client.perspective.callRemote('directMessage',self.name, text) - - def metadataFailed(self, result, text): - print "result:",result,"text:",text - return self.account.client.perspective.directMessage(self.name, text) - - def setStatus(self, status): - self.status = status - self.chat.getContactsList().setContactStatus(self) - -class TwistedWordsGroup(basesupport.AbstractGroup): - implements(interfaces.IGroup) - def __init__(self, name, wordsClient): - basesupport.AbstractGroup.__init__(self, name, wordsClient) - self.joined = 0 - - def sendGroupMessage(self, text, metadata=None): - """Return a deferred. - """ - #for backwards compatibility with older twisted.words servers. - if metadata: - d=self.account.client.perspective.callRemote( - 'groupMessage', self.name, text, metadata) - d.addErrback(self.metadataFailed, "* "+text) - return d - else: - return self.account.client.perspective.callRemote('groupMessage', - self.name, text) - - def setTopic(self, text): - self.account.client.perspective.callRemote( - 'setGroupMetadata', - {'topic': text, 'topic_author': self.client.name}, - self.name) - - def metadataFailed(self, result, text): - print "result:",result,"text:",text - return self.account.client.perspective.callRemote('groupMessage', - self.name, text) - - def joining(self): - self.joined = 1 - - def leaving(self): - self.joined = 0 - - def leave(self): - return self.account.client.perspective.callRemote('leaveGroup', - self.name) - - - -class TwistedWordsClient(pb.Referenceable, basesupport.AbstractClientMixin): - """In some cases, this acts as an Account, since it a source of text - messages (multiple Words instances may be on a single PB connection) - """ - def __init__(self, acct, serviceName, perspectiveName, chatui, - _logonDeferred=None): - self.accountName = "%s (%s:%s)" % (acct.accountName, serviceName, perspectiveName) - self.name = perspectiveName - print "HELLO I AM A PB SERVICE", serviceName, perspectiveName - self.chat = chatui - self.account = acct - self._logonDeferred = _logonDeferred - - def getPerson(self, name): - return self.chat.getPerson(name, self) - - def getGroup(self, name): - return self.chat.getGroup(name, self) - - def getGroupConversation(self, name): - return self.chat.getGroupConversation(self.getGroup(name)) - - def addContact(self, name): - self.perspective.callRemote('addContact', name) - - def remote_receiveGroupMembers(self, names, group): - print 'received group members:', names, group - self.getGroupConversation(group).setGroupMembers(names) - - def remote_receiveGroupMessage(self, sender, group, message, metadata=None): - print 'received a group message', sender, group, message, metadata - self.getGroupConversation(group).showGroupMessage(sender, message, metadata) - - def remote_memberJoined(self, member, group): - print 'member joined', member, group - self.getGroupConversation(group).memberJoined(member) - - def remote_memberLeft(self, member, group): - print 'member left' - self.getGroupConversation(group).memberLeft(member) - - def remote_notifyStatusChanged(self, name, status): - self.chat.getPerson(name, self).setStatus(status) - - def remote_receiveDirectMessage(self, name, message, metadata=None): - self.chat.getConversation(self.chat.getPerson(name, self)).showMessage(message, metadata) - - def remote_receiveContactList(self, clist): - for name, status in clist: - self.chat.getPerson(name, self).setStatus(status) - - def remote_setGroupMetadata(self, dict_, groupName): - if dict_.has_key("topic"): - self.getGroupConversation(groupName).setTopic(dict_["topic"], dict_.get("topic_author", None)) - - def joinGroup(self, name): - self.getGroup(name).joining() - return self.perspective.callRemote('joinGroup', name).addCallback(self._cbGroupJoined, name) - - def leaveGroup(self, name): - self.getGroup(name).leaving() - return self.perspective.callRemote('leaveGroup', name).addCallback(self._cbGroupLeft, name) - - def _cbGroupJoined(self, result, name): - groupConv = self.chat.getGroupConversation(self.getGroup(name)) - groupConv.showGroupMessage("sys", "you joined") - self.perspective.callRemote('getGroupMembers', name) - - def _cbGroupLeft(self, result, name): - print 'left',name - groupConv = self.chat.getGroupConversation(self.getGroup(name), 1) - groupConv.showGroupMessage("sys", "you left") - - def connected(self, perspective): - print 'Connected Words Client!', perspective - if self._logonDeferred is not None: - self._logonDeferred.callback(self) - self.perspective = perspective - self.chat.getContactsList() - - -pbFrontEnds = { - "twisted.words": TwistedWordsClient, - "twisted.reality": None - } - - -class PBAccount(basesupport.AbstractAccount): - implements(interfaces.IAccount) - gatewayType = "PB" - _groupFactory = TwistedWordsGroup - _personFactory = TwistedWordsPerson - - def __init__(self, accountName, autoLogin, username, password, host, port, - services=None): - """ - @param username: The name of your PB Identity. - @type username: string - """ - basesupport.AbstractAccount.__init__(self, accountName, autoLogin, - username, password, host, port) - self.services = [] - if not services: - services = [('twisted.words', 'twisted.words', username)] - for serviceType, serviceName, perspectiveName in services: - self.services.append([pbFrontEnds[serviceType], serviceName, - perspectiveName]) - - def logOn(self, chatui): - """ - @returns: this breaks with L{interfaces.IAccount} - @returntype: DeferredList of L{interfaces.IClient}s - """ - # Overriding basesupport's implementation on account of the - # fact that _startLogOn tends to return a deferredList rather - # than a simple Deferred, and we need to do registerAccountClient. - if (not self._isConnecting) and (not self._isOnline): - self._isConnecting = 1 - d = self._startLogOn(chatui) - d.addErrback(self._loginFailed) - def registerMany(results): - for success, result in results: - if success: - chatui.registerAccountClient(result) - self._cb_logOn(result) - else: - log.err(result) - d.addCallback(registerMany) - return d - else: - raise error.ConnectionError("Connection in progress") - - - def _startLogOn(self, chatui): - print 'Connecting...', - d = pb.getObjectAt(self.host, self.port) - d.addCallbacks(self._cbConnected, self._ebConnected, - callbackArgs=(chatui,)) - return d - - def _cbConnected(self, root, chatui): - print 'Connected!' - print 'Identifying...', - d = pb.authIdentity(root, self.username, self.password) - d.addCallbacks(self._cbIdent, self._ebConnected, - callbackArgs=(chatui,)) - return d - - def _cbIdent(self, ident, chatui): - if not ident: - print 'falsely identified.' - return self._ebConnected(Failure(Exception("username or password incorrect"))) - print 'Identified!' - dl = [] - for handlerClass, sname, pname in self.services: - d = defer.Deferred() - dl.append(d) - handler = handlerClass(self, sname, pname, chatui, d) - ident.callRemote('attach', sname, pname, handler).addCallback(handler.connected) - return defer.DeferredList(dl) - - def _ebConnected(self, error): - print 'Not connected.' - return error - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/iwords.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/iwords.py deleted file mode 100644 index e34e62c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/iwords.py +++ /dev/null @@ -1,267 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from zope.interface import Interface, Attribute - - -class IProtocolPlugin(Interface): - """Interface for plugins providing an interface to a Words service - """ - - name = Attribute("A single word describing what kind of interface this is (eg, irc or web)") - - def getFactory(realm, portal): - """Retrieve a C{twisted.internet.interfaces.IServerFactory} provider - - @param realm: An object providing C{twisted.cred.portal.IRealm} and - C{IChatService}, with which service information should be looked up. - - @param portal: An object providing C{twisted.cred.portal.IPortal}, - through which logins should be performed. - """ - - -class IGroup(Interface): - name = Attribute("A short string, unique among groups.") - - def add(user): - """Include the given user in this group. - - @type user: L{IUser} - """ - - def remove(user, reason=None): - """Remove the given user from this group. - - @type user: L{IUser} - @type reason: C{unicode} - """ - - def size(): - """Return the number of participants in this group. - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with an C{int} representing the - number of participants in this group. - """ - - def receive(sender, recipient, message): - """ - Broadcast the given message from the given sender to other - users in group. - - The message is not re-transmitted to the sender. - - @param sender: L{IUser} - - @type recipient: L{IGroup} - @param recipient: This is probably a wart. Maybe it will be removed - in the future. For now, it should be the group object the message - is being delivered to. - - @param message: C{dict} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with None when delivery has been - attempted for all users. - """ - - def setMetadata(meta): - """Change the metadata associated with this group. - - @type meta: C{dict} - """ - - def iterusers(): - """Return an iterator of all users in this group. - """ - - -class IChatClient(Interface): - """Interface through which IChatService interacts with clients. - """ - - name = Attribute("A short string, unique among users. This will be set by the L{IChatService} at login time.") - - def receive(sender, recipient, message): - """ - Callback notifying this user of the given message sent by the - given user. - - This will be invoked whenever another user sends a message to a - group this user is participating in, or whenever another user sends - a message directly to this user. In the former case, C{recipient} - will be the group to which the message was sent; in the latter, it - will be the same object as the user who is receiving the message. - - @type sender: L{IUser} - @type recipient: L{IUser} or L{IGroup} - @type message: C{dict} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires when the message has been delivered, - or which fails in some way. If the Deferred fails and the message - was directed at a group, this user will be removed from that group. - """ - - def groupMetaUpdate(group, meta): - """ - Callback notifying this user that the metadata for the given - group has changed. - - @type group: L{IGroup} - @type meta: C{dict} - - @rtype: L{twisted.internet.defer.Deferred} - """ - - def userJoined(group, user): - """ - Callback notifying this user that the given user has joined - the given group. - - @type group: L{IGroup} - @type user: L{IUser} - - @rtype: L{twisted.internet.defer.Deferred} - """ - - def userLeft(group, user, reason=None): - """ - Callback notifying this user that the given user has left the - given group for the given reason. - - @type group: L{IGroup} - @type user: L{IUser} - @type reason: C{unicode} - - @rtype: L{twisted.internet.defer.Deferred} - """ - - -class IUser(Interface): - """Interface through which clients interact with IChatService. - """ - - realm = Attribute("A reference to the Realm to which this user belongs. Set if and only if the user is logged in.") - mind = Attribute("A reference to the mind which logged in to this user. Set if and only if the user is logged in.") - name = Attribute("A short string, unique among users.") - - lastMessage = Attribute("A POSIX timestamp indicating the time of the last message received from this user.") - signOn = Attribute("A POSIX timestamp indicating this user's most recent sign on time.") - - def loggedIn(realm, mind): - """Invoked by the associated L{IChatService} when login occurs. - - @param realm: The L{IChatService} through which login is occurring. - @param mind: The mind object used for cred login. - """ - - def send(recipient, message): - """Send the given message to the given user or group. - - @type recipient: Either L{IUser} or L{IGroup} - @type message: C{dict} - """ - - def join(group): - """Attempt to join the given group. - - @type group: L{IGroup} - @rtype: L{twisted.internet.defer.Deferred} - """ - - def leave(group): - """Discontinue participation in the given group. - - @type group: L{IGroup} - @rtype: L{twisted.internet.defer.Deferred} - """ - - def itergroups(): - """ - Return an iterator of all groups of which this user is a - member. - """ - - -class IChatService(Interface): - name = Attribute("A short string identifying this chat service (eg, a hostname)") - - createGroupOnRequest = Attribute( - "A boolean indicating whether L{getGroup} should implicitly " - "create groups which are requested but which do not yet exist.") - - createUserOnRequest = Attribute( - "A boolean indicating whether L{getUser} should implicitly " - "create users which are requested but which do not yet exist.") - - def itergroups(): - """Return all groups available on this service. - - @rtype: C{twisted.internet.defer.Deferred} - @return: A Deferred which fires with a list of C{IGroup} providers. - """ - - def getGroup(name): - """Retrieve the group by the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the group with the given - name if one exists (or if one is created due to the setting of - L{createGroupOnRequest}, or which fails with - L{twisted.words.ewords.NoSuchGroup} if no such group exists. - """ - - def createGroup(name): - """Create a new group with the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the created group, or - with fails with L{twisted.words.ewords.DuplicateGroup} if a - group by that name exists already. - """ - - def lookupGroup(name): - """Retrieve a group by name. - - Unlike C{getGroup}, this will never implicitly create a group. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the group by the given - name, or which fails with L{twisted.words.ewords.NoSuchGroup}. - """ - - def getUser(name): - """Retrieve the user by the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the user with the given - name if one exists (or if one is created due to the setting of - L{createUserOnRequest}, or which fails with - L{twisted.words.ewords.NoSuchUser} if no such user exists. - """ - - def createUser(name): - """Create a new user with the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the created user, or - with fails with L{twisted.words.ewords.DuplicateUser} if a - user by that name exists already. - """ - -__all__ = [ - 'IGroup', 'IChatClient', 'IUser', 'IChatService', - ] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/__init__.py deleted file mode 100644 index b754980..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Chat protocols. -""" - -from twisted.python import deprecate, versions - -deprecate.deprecatedModuleAttribute( - versions.Version("Twisted", 15, 1, 0), "MSN has shutdown.", __name__, - "msn") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/irc.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/irc.py deleted file mode 100644 index 1831e98..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/irc.py +++ /dev/null @@ -1,3951 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_irc -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Internet Relay Chat protocol for client and server. - -Future Plans -============ - -The way the IRCClient class works here encourages people to implement -IRC clients by subclassing the ephemeral protocol class, and it tends -to end up with way more state than it should for an object which will -be destroyed as soon as the TCP transport drops. Someone oughta do -something about that, ya know? - -The DCC support needs to have more hooks for the client for it to be -able to ask the user things like "Do you want to accept this session?" -and "Transfer #2 is 67% done." and otherwise manage the DCC sessions. - -Test coverage needs to be better. - -@var MAX_COMMAND_LENGTH: The maximum length of a command, as defined by RFC - 2812 section 2.3. - -@var attributes: Singleton instance of L{_CharacterAttributes}, used for - constructing formatted text information. - -@author: Kevin Turner - -@see: RFC 1459: Internet Relay Chat Protocol -@see: RFC 2812: Internet Relay Chat: Client Protocol -@see: U{The Client-To-Client-Protocol -<http://www.irchelp.org/irchelp/rfc/ctcpspec.html>} -""" - -import errno, os, random, re, stat, struct, sys, time, types, traceback -import operator -import string, socket -import textwrap -import shlex -from os import path - -from twisted.internet import reactor, protocol, task -from twisted.persisted import styles -from twisted.protocols import basic -from twisted.python import log, reflect, _textattributes - -NUL = chr(0) -CR = chr(015) -NL = chr(012) -LF = NL -SPC = chr(040) - -# This includes the CRLF terminator characters. -MAX_COMMAND_LENGTH = 512 - -CHANNEL_PREFIXES = '&#!+' - -class IRCBadMessage(Exception): - pass - -class IRCPasswordMismatch(Exception): - pass - - - -class IRCBadModes(ValueError): - """ - A malformed mode was encountered while attempting to parse a mode string. - """ - - - -def parsemsg(s): - """ - Breaks a message from an IRC server into its prefix, command, and - arguments. - - @param s: The message to break. - @type s: L{bytes} - - @return: A tuple of (prefix, command, args). - @rtype: L{tuple} - """ - prefix = '' - trailing = [] - if not s: - raise IRCBadMessage("Empty line.") - if s[0] == ':': - prefix, s = s[1:].split(' ', 1) - if s.find(' :') != -1: - s, trailing = s.split(' :', 1) - args = s.split() - args.append(trailing) - else: - args = s.split() - command = args.pop(0) - return prefix, command, args - - - -def split(str, length=80): - """ - Split a string into multiple lines. - - Whitespace near C{str[length]} will be preferred as a breaking point. - C{"\\n"} will also be used as a breaking point. - - @param str: The string to split. - @type str: C{str} - - @param length: The maximum length which will be allowed for any string in - the result. - @type length: C{int} - - @return: C{list} of C{str} - """ - return [chunk - for line in str.split('\n') - for chunk in textwrap.wrap(line, length)] - - -def _intOrDefault(value, default=None): - """ - Convert a value to an integer if possible. - - @rtype: C{int} or type of L{default} - @return: An integer when C{value} can be converted to an integer, - otherwise return C{default} - """ - if value: - try: - return int(value) - except (TypeError, ValueError): - pass - return default - - - -class UnhandledCommand(RuntimeError): - """ - A command dispatcher could not locate an appropriate command handler. - """ - - - -class _CommandDispatcherMixin(object): - """ - Dispatch commands to handlers based on their name. - - Command handler names should be of the form C{prefix_commandName}, - where C{prefix} is the value specified by L{prefix}, and must - accept the parameters as given to L{dispatch}. - - Attempting to mix this in more than once for a single class will cause - strange behaviour, due to L{prefix} being overwritten. - - @type prefix: C{str} - @ivar prefix: Command handler prefix, used to locate handler attributes - """ - prefix = None - - def dispatch(self, commandName, *args): - """ - Perform actual command dispatch. - """ - def _getMethodName(command): - return '%s_%s' % (self.prefix, command) - - def _getMethod(name): - return getattr(self, _getMethodName(name), None) - - method = _getMethod(commandName) - if method is not None: - return method(*args) - - method = _getMethod('unknown') - if method is None: - raise UnhandledCommand("No handler for %r could be found" % (_getMethodName(commandName),)) - return method(commandName, *args) - - - - - -def parseModes(modes, params, paramModes=('', '')): - """ - Parse an IRC mode string. - - The mode string is parsed into two lists of mode changes (added and - removed), with each mode change represented as C{(mode, param)} where mode - is the mode character, and param is the parameter passed for that mode, or - C{None} if no parameter is required. - - @type modes: C{str} - @param modes: Modes string to parse. - - @type params: C{list} - @param params: Parameters specified along with L{modes}. - - @type paramModes: C{(str, str)} - @param paramModes: A pair of strings (C{(add, remove)}) that indicate which modes take - parameters when added or removed. - - @returns: Two lists of mode changes, one for modes added and the other for - modes removed respectively, mode changes in each list are represented as - C{(mode, param)}. - """ - if len(modes) == 0: - raise IRCBadModes('Empty mode string') - - if modes[0] not in '+-': - raise IRCBadModes('Malformed modes string: %r' % (modes,)) - - changes = ([], []) - - direction = None - count = -1 - for ch in modes: - if ch in '+-': - if count == 0: - raise IRCBadModes('Empty mode sequence: %r' % (modes,)) - direction = '+-'.index(ch) - count = 0 - else: - param = None - if ch in paramModes[direction]: - try: - param = params.pop(0) - except IndexError: - raise IRCBadModes('Not enough parameters: %r' % (ch,)) - changes[direction].append((ch, param)) - count += 1 - - if len(params) > 0: - raise IRCBadModes('Too many parameters: %r %r' % (modes, params)) - - if count == 0: - raise IRCBadModes('Empty mode sequence: %r' % (modes,)) - - return changes - - - -class IRC(protocol.Protocol): - """ - Internet Relay Chat server protocol. - """ - - buffer = "" - hostname = None - - encoding = None - - def connectionMade(self): - self.channels = [] - if self.hostname is None: - self.hostname = socket.getfqdn() - - - def sendLine(self, line): - if self.encoding is not None: - if isinstance(line, unicode): - line = line.encode(self.encoding) - self.transport.write("%s%s%s" % (line, CR, LF)) - - - def sendMessage(self, command, *parameter_list, **prefix): - """ - Send a line formatted as an IRC message. - - First argument is the command, all subsequent arguments are parameters - to that command. If a prefix is desired, it may be specified with the - keyword argument 'prefix'. - """ - if not command: - raise ValueError("IRC message requires a command.") - - if ' ' in command or command[0] == ':': - # Not the ONLY way to screw up, but provides a little - # sanity checking to catch likely dumb mistakes. - raise ValueError("Somebody screwed up, 'cuz this doesn't" \ - " look like a command to me: %s" % command) - - line = ' '.join([command] + list(parameter_list)) - if 'prefix' in prefix: - line = ":%s %s" % (prefix['prefix'], line) - self.sendLine(line) - - if len(parameter_list) > 15: - log.msg("Message has %d parameters (RFC allows 15):\n%s" % - (len(parameter_list), line)) - - - def dataReceived(self, data): - """ - This hack is to support mIRC, which sends LF only, even though the RFC - says CRLF. (Also, the flexibility of LineReceiver to turn "line mode" - on and off was not required.) - """ - lines = (self.buffer + data).split(LF) - # Put the (possibly empty) element after the last LF back in the - # buffer - self.buffer = lines.pop() - - for line in lines: - if len(line) <= 2: - # This is a blank line, at best. - continue - if line[-1] == CR: - line = line[:-1] - prefix, command, params = parsemsg(line) - # mIRC is a big pile of doo-doo - command = command.upper() - # DEBUG: log.msg( "%s %s %s" % (prefix, command, params)) - - self.handleCommand(command, prefix, params) - - - def handleCommand(self, command, prefix, params): - """ - Determine the function to call for the given command and call it with - the given arguments. - - @param command: The IRC command to determine the function for. - @type command: L{bytes} - - @param prefix: The prefix of the IRC message (as returned by - L{parsemsg}). - @type prefix: L{bytes} - - @param params: A list of parameters to call the function with. - @type params: L{list} - """ - method = getattr(self, "irc_%s" % command, None) - try: - if method is not None: - method(prefix, params) - else: - self.irc_unknown(prefix, command, params) - except: - log.deferr() - - - def irc_unknown(self, prefix, command, params): - """ - Called by L{handleCommand} on a command that doesn't have a defined - handler. Subclasses should override this method. - """ - raise NotImplementedError(command, prefix, params) - - - # Helper methods - def privmsg(self, sender, recip, message): - """ - Send a message to a channel or user - - @type sender: C{str} or C{unicode} - @param sender: Who is sending this message. Should be of the form - username!ident@hostmask (unless you know better!). - - @type recip: C{str} or C{unicode} - @param recip: The recipient of this message. If a channel, it must - start with a channel prefix. - - @type message: C{str} or C{unicode} - @param message: The message being sent. - """ - self.sendLine(":%s PRIVMSG %s :%s" % (sender, recip, lowQuote(message))) - - - def notice(self, sender, recip, message): - """ - Send a "notice" to a channel or user. - - Notices differ from privmsgs in that the RFC claims they are different. - Robots are supposed to send notices and not respond to them. Clients - typically display notices differently from privmsgs. - - @type sender: C{str} or C{unicode} - @param sender: Who is sending this message. Should be of the form - username!ident@hostmask (unless you know better!). - - @type recip: C{str} or C{unicode} - @param recip: The recipient of this message. If a channel, it must - start with a channel prefix. - - @type message: C{str} or C{unicode} - @param message: The message being sent. - """ - self.sendLine(":%s NOTICE %s :%s" % (sender, recip, message)) - - - def action(self, sender, recip, message): - """ - Send an action to a channel or user. - - @type sender: C{str} or C{unicode} - @param sender: Who is sending this message. Should be of the form - username!ident@hostmask (unless you know better!). - - @type recip: C{str} or C{unicode} - @param recip: The recipient of this message. If a channel, it must - start with a channel prefix. - - @type message: C{str} or C{unicode} - @param message: The action being sent. - """ - self.sendLine(":%s ACTION %s :%s" % (sender, recip, message)) - - - def topic(self, user, channel, topic, author=None): - """ - Send the topic to a user. - - @type user: C{str} or C{unicode} - @param user: The user receiving the topic. Only their nickname, not - the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the topic. - - @type topic: C{str} or C{unicode} or C{None} - @param topic: The topic string, unquoted, or None if there is no topic. - - @type author: C{str} or C{unicode} - @param author: If the topic is being changed, the full username and - hostmask of the person changing it. - """ - if author is None: - if topic is None: - self.sendLine(':%s %s %s %s :%s' % ( - self.hostname, RPL_NOTOPIC, user, channel, 'No topic is set.')) - else: - self.sendLine(":%s %s %s %s :%s" % ( - self.hostname, RPL_TOPIC, user, channel, lowQuote(topic))) - else: - self.sendLine(":%s TOPIC %s :%s" % (author, channel, lowQuote(topic))) - - - def topicAuthor(self, user, channel, author, date): - """ - Send the author of and time at which a topic was set for the given - channel. - - This sends a 333 reply message, which is not part of the IRC RFC. - - @type user: C{str} or C{unicode} - @param user: The user receiving the topic. Only their nickname, not - the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this information is relevant. - - @type author: C{str} or C{unicode} - @param author: The nickname (without hostmask) of the user who last set - the topic. - - @type date: C{int} - @param date: A POSIX timestamp (number of seconds since the epoch) at - which the topic was last set. - """ - self.sendLine(':%s %d %s %s %s %d' % ( - self.hostname, 333, user, channel, author, date)) - - - def names(self, user, channel, names): - """ - Send the names of a channel's participants to a user. - - @type user: C{str} or C{unicode} - @param user: The user receiving the name list. Only their nickname, - not the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the namelist. - - @type names: C{list} of C{str} or C{unicode} - @param names: The names to send. - """ - # XXX If unicode is given, these limits are not quite correct - prefixLength = len(channel) + len(user) + 10 - namesLength = 512 - prefixLength - - L = [] - count = 0 - for n in names: - if count + len(n) + 1 > namesLength: - self.sendLine(":%s %s %s = %s :%s" % ( - self.hostname, RPL_NAMREPLY, user, channel, ' '.join(L))) - L = [n] - count = len(n) - else: - L.append(n) - count += len(n) + 1 - if L: - self.sendLine(":%s %s %s = %s :%s" % ( - self.hostname, RPL_NAMREPLY, user, channel, ' '.join(L))) - self.sendLine(":%s %s %s %s :End of /NAMES list" % ( - self.hostname, RPL_ENDOFNAMES, user, channel)) - - - def who(self, user, channel, memberInfo): - """ - Send a list of users participating in a channel. - - @type user: C{str} or C{unicode} - @param user: The user receiving this member information. Only their - nickname, not the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the member information. - - @type memberInfo: C{list} of C{tuples} - @param memberInfo: For each member of the given channel, a 7-tuple - containing their username, their hostmask, the server to which they - are connected, their nickname, the letter "H" or "G" (standing for - "Here" or "Gone"), the hopcount from C{user} to this member, and - this member's real name. - """ - for info in memberInfo: - (username, hostmask, server, nickname, flag, hops, realName) = info - assert flag in ("H", "G") - self.sendLine(":%s %s %s %s %s %s %s %s %s :%d %s" % ( - self.hostname, RPL_WHOREPLY, user, channel, - username, hostmask, server, nickname, flag, hops, realName)) - - self.sendLine(":%s %s %s %s :End of /WHO list." % ( - self.hostname, RPL_ENDOFWHO, user, channel)) - - - def whois(self, user, nick, username, hostname, realName, server, serverInfo, oper, idle, signOn, channels): - """ - Send information about the state of a particular user. - - @type user: C{str} or C{unicode} - @param user: The user receiving this information. Only their nickname, - not the full hostmask. - - @type nick: C{str} or C{unicode} - @param nick: The nickname of the user this information describes. - - @type username: C{str} or C{unicode} - @param username: The user's username (eg, ident response) - - @type hostname: C{str} - @param hostname: The user's hostmask - - @type realName: C{str} or C{unicode} - @param realName: The user's real name - - @type server: C{str} or C{unicode} - @param server: The name of the server to which the user is connected - - @type serverInfo: C{str} or C{unicode} - @param serverInfo: A descriptive string about that server - - @type oper: C{bool} - @param oper: Indicates whether the user is an IRC operator - - @type idle: C{int} - @param idle: The number of seconds since the user last sent a message - - @type signOn: C{int} - @param signOn: A POSIX timestamp (number of seconds since the epoch) - indicating the time the user signed on - - @type channels: C{list} of C{str} or C{unicode} - @param channels: A list of the channels which the user is participating in - """ - self.sendLine(":%s %s %s %s %s %s * :%s" % ( - self.hostname, RPL_WHOISUSER, user, nick, username, hostname, realName)) - self.sendLine(":%s %s %s %s %s :%s" % ( - self.hostname, RPL_WHOISSERVER, user, nick, server, serverInfo)) - if oper: - self.sendLine(":%s %s %s %s :is an IRC operator" % ( - self.hostname, RPL_WHOISOPERATOR, user, nick)) - self.sendLine(":%s %s %s %s %d %d :seconds idle, signon time" % ( - self.hostname, RPL_WHOISIDLE, user, nick, idle, signOn)) - self.sendLine(":%s %s %s %s :%s" % ( - self.hostname, RPL_WHOISCHANNELS, user, nick, ' '.join(channels))) - self.sendLine(":%s %s %s %s :End of WHOIS list." % ( - self.hostname, RPL_ENDOFWHOIS, user, nick)) - - - def join(self, who, where): - """ - Send a join message. - - @type who: C{str} or C{unicode} - @param who: The name of the user joining. Should be of the form - username!ident@hostmask (unless you know better!). - - @type where: C{str} or C{unicode} - @param where: The channel the user is joining. - """ - self.sendLine(":%s JOIN %s" % (who, where)) - - - def part(self, who, where, reason=None): - """ - Send a part message. - - @type who: C{str} or C{unicode} - @param who: The name of the user joining. Should be of the form - username!ident@hostmask (unless you know better!). - - @type where: C{str} or C{unicode} - @param where: The channel the user is joining. - - @type reason: C{str} or C{unicode} - @param reason: A string describing the misery which caused this poor - soul to depart. - """ - if reason: - self.sendLine(":%s PART %s :%s" % (who, where, reason)) - else: - self.sendLine(":%s PART %s" % (who, where)) - - - def channelMode(self, user, channel, mode, *args): - """ - Send information about the mode of a channel. - - @type user: C{str} or C{unicode} - @param user: The user receiving the name list. Only their nickname, - not the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the namelist. - - @type mode: C{str} - @param mode: A string describing this channel's modes. - - @param args: Any additional arguments required by the modes. - """ - self.sendLine(":%s %s %s %s %s %s" % ( - self.hostname, RPL_CHANNELMODEIS, user, channel, mode, ' '.join(args))) - - - -class ServerSupportedFeatures(_CommandDispatcherMixin): - """ - Handle ISUPPORT messages. - - Feature names match those in the ISUPPORT RFC draft identically. - - Information regarding the specifics of ISUPPORT was gleaned from - <http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt>. - """ - prefix = 'isupport' - - def __init__(self): - self._features = { - 'CHANNELLEN': 200, - 'CHANTYPES': tuple('#&'), - 'MODES': 3, - 'NICKLEN': 9, - 'PREFIX': self._parsePrefixParam('(ovh)@+%'), - # The ISUPPORT draft explicitly says that there is no default for - # CHANMODES, but we're defaulting it here to handle the case where - # the IRC server doesn't send us any ISUPPORT information, since - # IRCClient.getChannelModeParams relies on this value. - 'CHANMODES': self._parseChanModesParam(['b', '', 'lk'])} - - - def _splitParamArgs(cls, params, valueProcessor=None): - """ - Split ISUPPORT parameter arguments. - - Values can optionally be processed by C{valueProcessor}. - - For example:: - - >>> ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2']) - (('A', '1'), ('B', '2')) - - @type params: C{iterable} of C{str} - - @type valueProcessor: C{callable} taking {str} - @param valueProcessor: Callable to process argument values, or C{None} - to perform no processing - - @rtype: C{list} of C{(str, object)} - @return: Sequence of C{(name, processedValue)} - """ - if valueProcessor is None: - valueProcessor = lambda x: x - - def _parse(): - for param in params: - if ':' not in param: - param += ':' - a, b = param.split(':', 1) - yield a, valueProcessor(b) - return list(_parse()) - _splitParamArgs = classmethod(_splitParamArgs) - - - def _unescapeParamValue(cls, value): - """ - Unescape an ISUPPORT parameter. - - The only form of supported escape is C{\\xHH}, where HH must be a valid - 2-digit hexadecimal number. - - @rtype: C{str} - """ - def _unescape(): - parts = value.split('\\x') - # The first part can never be preceded by the escape. - yield parts.pop(0) - for s in parts: - octet, rest = s[:2], s[2:] - try: - octet = int(octet, 16) - except ValueError: - raise ValueError('Invalid hex octet: %r' % (octet,)) - yield chr(octet) + rest - - if '\\x' not in value: - return value - return ''.join(_unescape()) - _unescapeParamValue = classmethod(_unescapeParamValue) - - - def _splitParam(cls, param): - """ - Split an ISUPPORT parameter. - - @type param: C{str} - - @rtype: C{(str, list)} - @return C{(key, arguments)} - """ - if '=' not in param: - param += '=' - key, value = param.split('=', 1) - return key, map(cls._unescapeParamValue, value.split(',')) - _splitParam = classmethod(_splitParam) - - - def _parsePrefixParam(cls, prefix): - """ - Parse the ISUPPORT "PREFIX" parameter. - - The order in which the parameter arguments appear is significant, the - earlier a mode appears the more privileges it gives. - - @rtype: C{dict} mapping C{str} to C{(str, int)} - @return: A dictionary mapping a mode character to a two-tuple of - C({symbol, priority)}, the lower a priority (the lowest being - C{0}) the more privileges it gives - """ - if not prefix: - return None - if prefix[0] != '(' and ')' not in prefix: - raise ValueError('Malformed PREFIX parameter') - modes, symbols = prefix.split(')', 1) - symbols = zip(symbols, xrange(len(symbols))) - modes = modes[1:] - return dict(zip(modes, symbols)) - _parsePrefixParam = classmethod(_parsePrefixParam) - - - def _parseChanModesParam(self, params): - """ - Parse the ISUPPORT "CHANMODES" parameter. - - See L{isupport_CHANMODES} for a detailed explanation of this parameter. - """ - names = ('addressModes', 'param', 'setParam', 'noParam') - if len(params) > len(names): - raise ValueError( - 'Expecting a maximum of %d channel mode parameters, got %d' % ( - len(names), len(params))) - items = map(lambda key, value: (key, value or ''), names, params) - return dict(items) - _parseChanModesParam = classmethod(_parseChanModesParam) - - - def getFeature(self, feature, default=None): - """ - Get a server supported feature's value. - - A feature with the value C{None} is equivalent to the feature being - unsupported. - - @type feature: C{str} - @param feature: Feature name - - @type default: C{object} - @param default: The value to default to, assuming that C{feature} - is not supported - - @return: Feature value - """ - return self._features.get(feature, default) - - - def hasFeature(self, feature): - """ - Determine whether a feature is supported or not. - - @rtype: C{bool} - """ - return self.getFeature(feature) is not None - - - def parse(self, params): - """ - Parse ISUPPORT parameters. - - If an unknown parameter is encountered, it is simply added to the - dictionary, keyed by its name, as a tuple of the parameters provided. - - @type params: C{iterable} of C{str} - @param params: Iterable of ISUPPORT parameters to parse - """ - for param in params: - key, value = self._splitParam(param) - if key.startswith('-'): - self._features.pop(key[1:], None) - else: - self._features[key] = self.dispatch(key, value) - - - def isupport_unknown(self, command, params): - """ - Unknown ISUPPORT parameter. - """ - return tuple(params) - - - def isupport_CHANLIMIT(self, params): - """ - The maximum number of each channel type a user may join. - """ - return self._splitParamArgs(params, _intOrDefault) - - - def isupport_CHANMODES(self, params): - """ - Available channel modes. - - There are 4 categories of channel mode:: - - addressModes - Modes that add or remove an address to or from a - list, these modes always take a parameter. - - param - Modes that change a setting on a channel, these modes - always take a parameter. - - setParam - Modes that change a setting on a channel, these modes - only take a parameter when being set. - - noParam - Modes that change a setting on a channel, these modes - never take a parameter. - """ - try: - return self._parseChanModesParam(params) - except ValueError: - return self.getFeature('CHANMODES') - - - def isupport_CHANNELLEN(self, params): - """ - Maximum length of a channel name a client may create. - """ - return _intOrDefault(params[0], self.getFeature('CHANNELLEN')) - - - def isupport_CHANTYPES(self, params): - """ - Valid channel prefixes. - """ - return tuple(params[0]) - - - def isupport_EXCEPTS(self, params): - """ - Mode character for "ban exceptions". - - The presence of this parameter indicates that the server supports - this functionality. - """ - return params[0] or 'e' - - - def isupport_IDCHAN(self, params): - """ - Safe channel identifiers. - - The presence of this parameter indicates that the server supports - this functionality. - """ - return self._splitParamArgs(params) - - - def isupport_INVEX(self, params): - """ - Mode character for "invite exceptions". - - The presence of this parameter indicates that the server supports - this functionality. - """ - return params[0] or 'I' - - - def isupport_KICKLEN(self, params): - """ - Maximum length of a kick message a client may provide. - """ - return _intOrDefault(params[0]) - - - def isupport_MAXLIST(self, params): - """ - Maximum number of "list modes" a client may set on a channel at once. - - List modes are identified by the "addressModes" key in CHANMODES. - """ - return self._splitParamArgs(params, _intOrDefault) - - - def isupport_MODES(self, params): - """ - Maximum number of modes accepting parameters that may be sent, by a - client, in a single MODE command. - """ - return _intOrDefault(params[0]) - - - def isupport_NETWORK(self, params): - """ - IRC network name. - """ - return params[0] - - - def isupport_NICKLEN(self, params): - """ - Maximum length of a nickname the client may use. - """ - return _intOrDefault(params[0], self.getFeature('NICKLEN')) - - - def isupport_PREFIX(self, params): - """ - Mapping of channel modes that clients may have to status flags. - """ - try: - return self._parsePrefixParam(params[0]) - except ValueError: - return self.getFeature('PREFIX') - - - def isupport_SAFELIST(self, params): - """ - Flag indicating that a client may request a LIST without being - disconnected due to the large amount of data generated. - """ - return True - - - def isupport_STATUSMSG(self, params): - """ - The server supports sending messages to only to clients on a channel - with a specific status. - """ - return params[0] - - - def isupport_TARGMAX(self, params): - """ - Maximum number of targets allowable for commands that accept multiple - targets. - """ - return dict(self._splitParamArgs(params, _intOrDefault)) - - - def isupport_TOPICLEN(self, params): - """ - Maximum length of a topic that may be set. - """ - return _intOrDefault(params[0]) - - - -class IRCClient(basic.LineReceiver): - """ - Internet Relay Chat client protocol, with sprinkles. - - In addition to providing an interface for an IRC client protocol, - this class also contains reasonable implementations of many common - CTCP methods. - - TODO - ==== - - Limit the length of messages sent (because the IRC server probably - does). - - Add flood protection/rate limiting for my CTCP replies. - - NickServ cooperation. (a mix-in?) - - @ivar nickname: Nickname the client will use. - @ivar password: Password used to log on to the server. May be C{None}. - @ivar realname: Supplied to the server during login as the "Real name" - or "ircname". May be C{None}. - @ivar username: Supplied to the server during login as the "User name". - May be C{None} - - @ivar userinfo: Sent in reply to a C{USERINFO} CTCP query. If C{None}, no - USERINFO reply will be sent. - "This is used to transmit a string which is settable by - the user (and never should be set by the client)." - @ivar fingerReply: Sent in reply to a C{FINGER} CTCP query. If C{None}, no - FINGER reply will be sent. - @type fingerReply: Callable or String - - @ivar versionName: CTCP VERSION reply, client name. If C{None}, no VERSION - reply will be sent. - @type versionName: C{str}, or None. - @ivar versionNum: CTCP VERSION reply, client version. - @type versionNum: C{str}, or None. - @ivar versionEnv: CTCP VERSION reply, environment the client is running in. - @type versionEnv: C{str}, or None. - - @ivar sourceURL: CTCP SOURCE reply, a URL where the source code of this - client may be found. If C{None}, no SOURCE reply will be sent. - - @ivar lineRate: Minimum delay between lines sent to the server. If - C{None}, no delay will be imposed. - @type lineRate: Number of Seconds. - - @ivar motd: Either L{None} or, between receipt of I{RPL_MOTDSTART} and - I{RPL_ENDOFMOTD}, a L{list} of L{str}, each of which is the content - of an I{RPL_MOTD} message. - - @ivar erroneousNickFallback: Default nickname assigned when an unregistered - client triggers an C{ERR_ERRONEUSNICKNAME} while trying to register - with an illegal nickname. - @type erroneousNickFallback: C{str} - - @ivar _registered: Whether or not the user is registered. It becomes True - once a welcome has been received from the server. - @type _registered: C{bool} - - @ivar _attemptedNick: The nickname that will try to get registered. It may - change if it is illegal or already taken. L{nickname} becomes the - L{_attemptedNick} that is successfully registered. - @type _attemptedNick: C{str} - - @type supported: L{ServerSupportedFeatures} - @ivar supported: Available ISUPPORT features on the server - - @type hostname: C{str} - @ivar hostname: Host name of the IRC server the client is connected to. - Initially the host name is C{None} and later is set to the host name - from which the I{RPL_WELCOME} message is received. - - @type _heartbeat: L{task.LoopingCall} - @ivar _heartbeat: Looping call to perform the keepalive by calling - L{IRCClient._sendHeartbeat} every L{heartbeatInterval} seconds, or - C{None} if there is no heartbeat. - - @type heartbeatInterval: C{float} - @ivar heartbeatInterval: Interval, in seconds, to send I{PING} messages to - the server as a form of keepalive, defaults to 120 seconds. Use C{None} - to disable the heartbeat. - """ - hostname = None - motd = None - nickname = 'irc' - password = None - realname = None - username = None - ### Responses to various CTCP queries. - - userinfo = None - # fingerReply is a callable returning a string, or a str()able object. - fingerReply = None - versionName = None - versionNum = None - versionEnv = None - - sourceURL = "http://twistedmatrix.com/downloads/" - - dcc_destdir = '.' - dcc_sessions = None - - # If this is false, no attempt will be made to identify - # ourself to the server. - performLogin = 1 - - lineRate = None - _queue = None - _queueEmptying = None - - delimiter = '\n' # '\r\n' will also work (see dataReceived) - - __pychecker__ = 'unusednames=params,prefix,channel' - - _registered = False - _attemptedNick = '' - erroneousNickFallback = 'defaultnick' - - _heartbeat = None - heartbeatInterval = 120 - - - def _reallySendLine(self, line): - return basic.LineReceiver.sendLine(self, lowQuote(line) + '\r') - - def sendLine(self, line): - if self.lineRate is None: - self._reallySendLine(line) - else: - self._queue.append(line) - if not self._queueEmptying: - self._sendLine() - - def _sendLine(self): - if self._queue: - self._reallySendLine(self._queue.pop(0)) - self._queueEmptying = reactor.callLater(self.lineRate, - self._sendLine) - else: - self._queueEmptying = None - - - def connectionLost(self, reason): - basic.LineReceiver.connectionLost(self, reason) - self.stopHeartbeat() - - - def _createHeartbeat(self): - """ - Create the heartbeat L{LoopingCall}. - """ - return task.LoopingCall(self._sendHeartbeat) - - - def _sendHeartbeat(self): - """ - Send a I{PING} message to the IRC server as a form of keepalive. - """ - self.sendLine('PING ' + self.hostname) - - - def stopHeartbeat(self): - """ - Stop sending I{PING} messages to keep the connection to the server - alive. - - @since: 11.1 - """ - if self._heartbeat is not None: - self._heartbeat.stop() - self._heartbeat = None - - - def startHeartbeat(self): - """ - Start sending I{PING} messages every L{IRCClient.heartbeatInterval} - seconds to keep the connection to the server alive during periods of no - activity. - - @since: 11.1 - """ - self.stopHeartbeat() - if self.heartbeatInterval is None: - return - self._heartbeat = self._createHeartbeat() - self._heartbeat.start(self.heartbeatInterval, now=False) - - - ### Interface level client->user output methods - ### - ### You'll want to override these. - - ### Methods relating to the server itself - - def created(self, when): - """ - Called with creation date information about the server, usually at logon. - - @type when: C{str} - @param when: A string describing when the server was created, probably. - """ - - def yourHost(self, info): - """ - Called with daemon information about the server, usually at logon. - - @type info: C{str} - @param when: A string describing what software the server is running, probably. - """ - - def myInfo(self, servername, version, umodes, cmodes): - """ - Called with information about the server, usually at logon. - - @type servername: C{str} - @param servername: The hostname of this server. - - @type version: C{str} - @param version: A description of what software this server runs. - - @type umodes: C{str} - @param umodes: All the available user modes. - - @type cmodes: C{str} - @param cmodes: All the available channel modes. - """ - - def luserClient(self, info): - """ - Called with information about the number of connections, usually at logon. - - @type info: C{str} - @param info: A description of the number of clients and servers - connected to the network, probably. - """ - - def bounce(self, info): - """ - Called with information about where the client should reconnect. - - @type info: C{str} - @param info: A plaintext description of the address that should be - connected to. - """ - - def isupport(self, options): - """ - Called with various information about what the server supports. - - @type options: C{list} of C{str} - @param options: Descriptions of features or limits of the server, possibly - in the form "NAME=VALUE". - """ - - def luserChannels(self, channels): - """ - Called with the number of channels existent on the server. - - @type channels: C{int} - """ - - def luserOp(self, ops): - """ - Called with the number of ops logged on to the server. - - @type ops: C{int} - """ - - def luserMe(self, info): - """ - Called with information about the server connected to. - - @type info: C{str} - @param info: A plaintext string describing the number of users and servers - connected to this server. - """ - - ### Methods involving me directly - - def privmsg(self, user, channel, message): - """ - Called when I have a message from a user to me or a channel. - """ - pass - - def joined(self, channel): - """ - Called when I finish joining a channel. - - channel has the starting character (C{'#'}, C{'&'}, C{'!'}, or C{'+'}) - intact. - """ - - def left(self, channel): - """ - Called when I have left a channel. - - channel has the starting character (C{'#'}, C{'&'}, C{'!'}, or C{'+'}) - intact. - """ - - - def noticed(self, user, channel, message): - """ - Called when I have a notice from a user to me or a channel. - - If the client makes any automated replies, it must not do so in - response to a NOTICE message, per the RFC:: - - The difference between NOTICE and PRIVMSG is that - automatic replies MUST NEVER be sent in response to a - NOTICE message. [...] The object of this rule is to avoid - loops between clients automatically sending something in - response to something it received. - """ - - - def modeChanged(self, user, channel, set, modes, args): - """ - Called when users or channel's modes are changed. - - @type user: C{str} - @param user: The user and hostmask which instigated this change. - - @type channel: C{str} - @param channel: The channel where the modes are changed. If args is - empty the channel for which the modes are changing. If the changes are - at server level it could be equal to C{user}. - - @type set: C{bool} or C{int} - @param set: True if the mode(s) is being added, False if it is being - removed. If some modes are added and others removed at the same time - this function will be called twice, the first time with all the added - modes, the second with the removed ones. (To change this behaviour - override the irc_MODE method) - - @type modes: C{str} - @param modes: The mode or modes which are being changed. - - @type args: C{tuple} - @param args: Any additional information required for the mode - change. - """ - - def pong(self, user, secs): - """ - Called with the results of a CTCP PING query. - """ - pass - - def signedOn(self): - """ - Called after successfully signing on to the server. - """ - pass - - def kickedFrom(self, channel, kicker, message): - """ - Called when I am kicked from a channel. - """ - pass - - def nickChanged(self, nick): - """ - Called when my nick has been changed. - """ - self.nickname = nick - - - ### Things I observe other people doing in a channel. - - def userJoined(self, user, channel): - """ - Called when I see another user joining a channel. - """ - pass - - def userLeft(self, user, channel): - """ - Called when I see another user leaving a channel. - """ - pass - - def userQuit(self, user, quitMessage): - """ - Called when I see another user disconnect from the network. - """ - pass - - def userKicked(self, kickee, channel, kicker, message): - """ - Called when I observe someone else being kicked from a channel. - """ - pass - - def action(self, user, channel, data): - """ - Called when I see a user perform an ACTION on a channel. - """ - pass - - def topicUpdated(self, user, channel, newTopic): - """ - In channel, user changed the topic to newTopic. - - Also called when first joining a channel. - """ - pass - - def userRenamed(self, oldname, newname): - """ - A user changed their name from oldname to newname. - """ - pass - - ### Information from the server. - - def receivedMOTD(self, motd): - """ - I received a message-of-the-day banner from the server. - - motd is a list of strings, where each string was sent as a separate - message from the server. To display, you might want to use:: - - '\\n'.join(motd) - - to get a nicely formatted string. - """ - pass - - ### user input commands, client->server - ### Your client will want to invoke these. - - def join(self, channel, key=None): - """ - Join a channel. - - @type channel: C{str} - @param channel: The name of the channel to join. If it has no prefix, - C{'#'} will be prepended to it. - @type key: C{str} - @param key: If specified, the key used to join the channel. - """ - if channel[0] not in CHANNEL_PREFIXES: - channel = '#' + channel - if key: - self.sendLine("JOIN %s %s" % (channel, key)) - else: - self.sendLine("JOIN %s" % (channel,)) - - def leave(self, channel, reason=None): - """ - Leave a channel. - - @type channel: C{str} - @param channel: The name of the channel to leave. If it has no prefix, - C{'#'} will be prepended to it. - @type reason: C{str} - @param reason: If given, the reason for leaving. - """ - if channel[0] not in CHANNEL_PREFIXES: - channel = '#' + channel - if reason: - self.sendLine("PART %s :%s" % (channel, reason)) - else: - self.sendLine("PART %s" % (channel,)) - - def kick(self, channel, user, reason=None): - """ - Attempt to kick a user from a channel. - - @type channel: C{str} - @param channel: The name of the channel to kick the user from. If it has - no prefix, C{'#'} will be prepended to it. - @type user: C{str} - @param user: The nick of the user to kick. - @type reason: C{str} - @param reason: If given, the reason for kicking the user. - """ - if channel[0] not in CHANNEL_PREFIXES: - channel = '#' + channel - if reason: - self.sendLine("KICK %s %s :%s" % (channel, user, reason)) - else: - self.sendLine("KICK %s %s" % (channel, user)) - - part = leave - - - def invite(self, user, channel): - """ - Attempt to invite user to channel - - @type user: C{str} - @param user: The user to invite - @type channel: C{str} - @param channel: The channel to invite the user too - - @since: 11.0 - """ - if channel[0] not in CHANNEL_PREFIXES: - channel = '#' + channel - self.sendLine("INVITE %s %s" % (user, channel)) - - - def topic(self, channel, topic=None): - """ - Attempt to set the topic of the given channel, or ask what it is. - - If topic is None, then I sent a topic query instead of trying to set the - topic. The server should respond with a TOPIC message containing the - current topic of the given channel. - - @type channel: C{str} - @param channel: The name of the channel to change the topic on. If it - has no prefix, C{'#'} will be prepended to it. - @type topic: C{str} - @param topic: If specified, what to set the topic to. - """ - # << TOPIC #xtestx :fff - if channel[0] not in CHANNEL_PREFIXES: - channel = '#' + channel - if topic != None: - self.sendLine("TOPIC %s :%s" % (channel, topic)) - else: - self.sendLine("TOPIC %s" % (channel,)) - - - def mode(self, chan, set, modes, limit = None, user = None, mask = None): - """ - Change the modes on a user or channel. - - The C{limit}, C{user}, and C{mask} parameters are mutually exclusive. - - @type chan: C{str} - @param chan: The name of the channel to operate on. - @type set: C{bool} - @param set: True to give the user or channel permissions and False to - remove them. - @type modes: C{str} - @param modes: The mode flags to set on the user or channel. - @type limit: C{int} - @param limit: In conjunction with the C{'l'} mode flag, limits the - number of users on the channel. - @type user: C{str} - @param user: The user to change the mode on. - @type mask: C{str} - @param mask: In conjunction with the C{'b'} mode flag, sets a mask of - users to be banned from the channel. - """ - if set: - line = 'MODE %s +%s' % (chan, modes) - else: - line = 'MODE %s -%s' % (chan, modes) - if limit is not None: - line = '%s %d' % (line, limit) - elif user is not None: - line = '%s %s' % (line, user) - elif mask is not None: - line = '%s %s' % (line, mask) - self.sendLine(line) - - - def say(self, channel, message, length=None): - """ - Send a message to a channel - - @type channel: C{str} - @param channel: The channel to say the message on. If it has no prefix, - C{'#'} will be prepended to it. - @type message: C{str} - @param message: The message to say. - @type length: C{int} - @param length: The maximum number of octets to send at a time. This has - the effect of turning a single call to C{msg()} into multiple - commands to the server. This is useful when long messages may be - sent that would otherwise cause the server to kick us off or - silently truncate the text we are sending. If None is passed, the - entire message is always send in one command. - """ - if channel[0] not in CHANNEL_PREFIXES: - channel = '#' + channel - self.msg(channel, message, length) - - - def _safeMaximumLineLength(self, command): - """ - Estimate a safe maximum line length for the given command. - - This is done by assuming the maximum values for nickname length, - realname and hostname combined with the command that needs to be sent - and some guessing. A theoretical maximum value is used because it is - possible that our nickname, username or hostname changes (on the server - side) while the length is still being calculated. - """ - # :nickname!realname@hostname COMMAND ... - theoretical = ':%s!%s@%s %s' % ( - 'a' * self.supported.getFeature('NICKLEN'), - # This value is based on observation. - 'b' * 10, - # See <http://tools.ietf.org/html/rfc2812#section-2.3.1>. - 'c' * 63, - command) - # Fingers crossed. - fudge = 10 - return MAX_COMMAND_LENGTH - len(theoretical) - fudge - - - def msg(self, user, message, length=None): - """ - Send a message to a user or channel. - - The message will be split into multiple commands to the server if: - - The message contains any newline characters - - Any span between newline characters is longer than the given - line-length. - - @param user: Username or channel name to which to direct the - message. - @type user: C{str} - - @param message: Text to send. - @type message: C{str} - - @param length: Maximum number of octets to send in a single - command, including the IRC protocol framing. If C{None} is given - then L{IRCClient._safeMaximumLineLength} is used to determine a - value. - @type length: C{int} - """ - fmt = 'PRIVMSG %s :' % (user,) - - if length is None: - length = self._safeMaximumLineLength(fmt) - - # Account for the line terminator. - minimumLength = len(fmt) + 2 - if length <= minimumLength: - raise ValueError("Maximum length must exceed %d for message " - "to %s" % (minimumLength, user)) - for line in split(message, length - minimumLength): - self.sendLine(fmt + line) - - - def notice(self, user, message): - """ - Send a notice to a user. - - Notices are like normal message, but should never get automated - replies. - - @type user: C{str} - @param user: The user to send a notice to. - @type message: C{str} - @param message: The contents of the notice to send. - """ - self.sendLine("NOTICE %s :%s" % (user, message)) - - - def away(self, message=''): - """ - Mark this client as away. - - @type message: C{str} - @param message: If specified, the away message. - """ - self.sendLine("AWAY :%s" % message) - - - def back(self): - """ - Clear the away status. - """ - # An empty away marks us as back - self.away() - - - def whois(self, nickname, server=None): - """ - Retrieve user information about the given nickname. - - @type nickname: C{str} - @param nickname: The nickname about which to retrieve information. - - @since: 8.2 - """ - if server is None: - self.sendLine('WHOIS ' + nickname) - else: - self.sendLine('WHOIS %s %s' % (server, nickname)) - - - def register(self, nickname, hostname='foo', servername='bar'): - """ - Login to the server. - - @type nickname: C{str} - @param nickname: The nickname to register. - @type hostname: C{str} - @param hostname: If specified, the hostname to logon as. - @type servername: C{str} - @param servername: If specified, the servername to logon as. - """ - if self.password is not None: - self.sendLine("PASS %s" % self.password) - self.setNick(nickname) - if self.username is None: - self.username = nickname - self.sendLine("USER %s %s %s :%s" % (self.username, hostname, servername, self.realname)) - - - def setNick(self, nickname): - """ - Set this client's nickname. - - @type nickname: C{str} - @param nickname: The nickname to change to. - """ - self._attemptedNick = nickname - self.sendLine("NICK %s" % nickname) - - - def quit(self, message = ''): - """ - Disconnect from the server - - @type message: C{str} - - @param message: If specified, the message to give when quitting the - server. - """ - self.sendLine("QUIT :%s" % message) - - ### user input commands, client->client - - def describe(self, channel, action): - """ - Strike a pose. - - @type channel: C{str} - @param channel: The name of the channel to have an action on. If it - has no prefix, it is sent to the user of that name. - @type action: C{str} - @param action: The action to preform. - @since: 9.0 - """ - self.ctcpMakeQuery(channel, [('ACTION', action)]) - - - _pings = None - _MAX_PINGRING = 12 - - def ping(self, user, text = None): - """ - Measure round-trip delay to another IRC client. - """ - if self._pings is None: - self._pings = {} - - if text is None: - chars = string.letters + string.digits + string.punctuation - key = ''.join([random.choice(chars) for i in range(12)]) - else: - key = str(text) - self._pings[(user, key)] = time.time() - self.ctcpMakeQuery(user, [('PING', key)]) - - if len(self._pings) > self._MAX_PINGRING: - # Remove some of the oldest entries. - byValue = [(v, k) for (k, v) in self._pings.items()] - byValue.sort() - excess = self._MAX_PINGRING - len(self._pings) - for i in xrange(excess): - del self._pings[byValue[i][1]] - - - def dccSend(self, user, file): - """ - This is supposed to send a user a file directly. This generally - doesn't work on any client, and this method is included only for - backwards compatibility and completeness. - - @param user: C{str} representing the user - @param file: an open file (unknown, since this is not implemented) - """ - raise NotImplementedError( - "XXX!!! Help! I need to bind a socket, have it listen, and tell me its address. " - "(and stop accepting once we've made a single connection.)") - - - def dccResume(self, user, fileName, port, resumePos): - """ - Send a DCC RESUME request to another user. - """ - self.ctcpMakeQuery(user, [ - ('DCC', ['RESUME', fileName, port, resumePos])]) - - - def dccAcceptResume(self, user, fileName, port, resumePos): - """ - Send a DCC ACCEPT response to clients who have requested a resume. - """ - self.ctcpMakeQuery(user, [ - ('DCC', ['ACCEPT', fileName, port, resumePos])]) - - ### server->client messages - ### You might want to fiddle with these, - ### but it is safe to leave them alone. - - def irc_ERR_NICKNAMEINUSE(self, prefix, params): - """ - Called when we try to register or change to a nickname that is already - taken. - """ - self._attemptedNick = self.alterCollidedNick(self._attemptedNick) - self.setNick(self._attemptedNick) - - - def alterCollidedNick(self, nickname): - """ - Generate an altered version of a nickname that caused a collision in an - effort to create an unused related name for subsequent registration. - - @param nickname: The nickname a user is attempting to register. - @type nickname: C{str} - - @returns: A string that is in some way different from the nickname. - @rtype: C{str} - """ - return nickname + '_' - - - def irc_ERR_ERRONEUSNICKNAME(self, prefix, params): - """ - Called when we try to register or change to an illegal nickname. - - The server should send this reply when the nickname contains any - disallowed characters. The bot will stall, waiting for RPL_WELCOME, if - we don't handle this during sign-on. - - @note: The method uses the spelling I{erroneus}, as it appears in - the RFC, section 6.1. - """ - if not self._registered: - self.setNick(self.erroneousNickFallback) - - - def irc_ERR_PASSWDMISMATCH(self, prefix, params): - """ - Called when the login was incorrect. - """ - raise IRCPasswordMismatch("Password Incorrect.") - - - def irc_RPL_WELCOME(self, prefix, params): - """ - Called when we have received the welcome from the server. - """ - self.hostname = prefix - self._registered = True - self.nickname = self._attemptedNick - self.signedOn() - self.startHeartbeat() - - - def irc_JOIN(self, prefix, params): - """ - Called when a user joins a channel. - """ - nick = prefix.split('!')[0] - channel = params[-1] - if nick == self.nickname: - self.joined(channel) - else: - self.userJoined(nick, channel) - - def irc_PART(self, prefix, params): - """ - Called when a user leaves a channel. - """ - nick = prefix.split('!')[0] - channel = params[0] - if nick == self.nickname: - self.left(channel) - else: - self.userLeft(nick, channel) - - def irc_QUIT(self, prefix, params): - """ - Called when a user has quit. - """ - nick = prefix.split('!')[0] - self.userQuit(nick, params[0]) - - - def irc_MODE(self, user, params): - """ - Parse a server mode change message. - """ - channel, modes, args = params[0], params[1], params[2:] - - if modes[0] not in '-+': - modes = '+' + modes - - if channel == self.nickname: - # This is a mode change to our individual user, not a channel mode - # that involves us. - paramModes = self.getUserModeParams() - else: - paramModes = self.getChannelModeParams() - - try: - added, removed = parseModes(modes, args, paramModes) - except IRCBadModes: - log.err(None, 'An error occurred while parsing the following ' - 'MODE message: MODE %s' % (' '.join(params),)) - else: - if added: - modes, params = zip(*added) - self.modeChanged(user, channel, True, ''.join(modes), params) - - if removed: - modes, params = zip(*removed) - self.modeChanged(user, channel, False, ''.join(modes), params) - - - def irc_PING(self, prefix, params): - """ - Called when some has pinged us. - """ - self.sendLine("PONG %s" % params[-1]) - - def irc_PRIVMSG(self, prefix, params): - """ - Called when we get a message. - """ - user = prefix - channel = params[0] - message = params[-1] - - if not message: - # Don't raise an exception if we get blank message. - return - - if message[0] == X_DELIM: - m = ctcpExtract(message) - if m['extended']: - self.ctcpQuery(user, channel, m['extended']) - - if not m['normal']: - return - - message = ' '.join(m['normal']) - - self.privmsg(user, channel, message) - - def irc_NOTICE(self, prefix, params): - """ - Called when a user gets a notice. - """ - user = prefix - channel = params[0] - message = params[-1] - - if message[0]==X_DELIM: - m = ctcpExtract(message) - if m['extended']: - self.ctcpReply(user, channel, m['extended']) - - if not m['normal']: - return - - message = ' '.join(m['normal']) - - self.noticed(user, channel, message) - - def irc_NICK(self, prefix, params): - """ - Called when a user changes their nickname. - """ - nick = prefix.split('!', 1)[0] - if nick == self.nickname: - self.nickChanged(params[0]) - else: - self.userRenamed(nick, params[0]) - - def irc_KICK(self, prefix, params): - """ - Called when a user is kicked from a channel. - """ - kicker = prefix.split('!')[0] - channel = params[0] - kicked = params[1] - message = params[-1] - if kicked.lower() == self.nickname.lower(): - # Yikes! - self.kickedFrom(channel, kicker, message) - else: - self.userKicked(kicked, channel, kicker, message) - - def irc_TOPIC(self, prefix, params): - """ - Someone in the channel set the topic. - """ - user = prefix.split('!')[0] - channel = params[0] - newtopic = params[1] - self.topicUpdated(user, channel, newtopic) - - def irc_RPL_TOPIC(self, prefix, params): - """ - Called when the topic for a channel is initially reported or when it - subsequently changes. - """ - user = prefix.split('!')[0] - channel = params[1] - newtopic = params[2] - self.topicUpdated(user, channel, newtopic) - - def irc_RPL_NOTOPIC(self, prefix, params): - user = prefix.split('!')[0] - channel = params[1] - newtopic = "" - self.topicUpdated(user, channel, newtopic) - - def irc_RPL_MOTDSTART(self, prefix, params): - if params[-1].startswith("- "): - params[-1] = params[-1][2:] - self.motd = [params[-1]] - - def irc_RPL_MOTD(self, prefix, params): - if params[-1].startswith("- "): - params[-1] = params[-1][2:] - if self.motd is None: - self.motd = [] - self.motd.append(params[-1]) - - - def irc_RPL_ENDOFMOTD(self, prefix, params): - """ - I{RPL_ENDOFMOTD} indicates the end of the message of the day - messages. Deliver the accumulated lines to C{receivedMOTD}. - """ - motd = self.motd - self.motd = None - self.receivedMOTD(motd) - - - def irc_RPL_CREATED(self, prefix, params): - self.created(params[1]) - - def irc_RPL_YOURHOST(self, prefix, params): - self.yourHost(params[1]) - - def irc_RPL_MYINFO(self, prefix, params): - info = params[1].split(None, 3) - while len(info) < 4: - info.append(None) - self.myInfo(*info) - - def irc_RPL_BOUNCE(self, prefix, params): - self.bounce(params[1]) - - def irc_RPL_ISUPPORT(self, prefix, params): - args = params[1:-1] - # Several ISUPPORT messages, in no particular order, may be sent - # to the client at any given point in time (usually only on connect, - # though.) For this reason, ServerSupportedFeatures.parse is intended - # to mutate the supported feature list. - self.supported.parse(args) - self.isupport(args) - - def irc_RPL_LUSERCLIENT(self, prefix, params): - self.luserClient(params[1]) - - def irc_RPL_LUSEROP(self, prefix, params): - try: - self.luserOp(int(params[1])) - except ValueError: - pass - - def irc_RPL_LUSERCHANNELS(self, prefix, params): - try: - self.luserChannels(int(params[1])) - except ValueError: - pass - - def irc_RPL_LUSERME(self, prefix, params): - self.luserMe(params[1]) - - def irc_unknown(self, prefix, command, params): - pass - - ### Receiving a CTCP query from another party - ### It is safe to leave these alone. - - - def ctcpQuery(self, user, channel, messages): - """ - Dispatch method for any CTCP queries received. - - Duplicated CTCP queries are ignored and no dispatch is - made. Unrecognized CTCP queries invoke L{IRCClient.ctcpUnknownQuery}. - """ - seen = set() - for tag, data in messages: - method = getattr(self, 'ctcpQuery_%s' % tag, None) - if tag not in seen: - if method is not None: - method(user, channel, data) - else: - self.ctcpUnknownQuery(user, channel, tag, data) - seen.add(tag) - - - def ctcpUnknownQuery(self, user, channel, tag, data): - """ - Fallback handler for unrecognized CTCP queries. - - No CTCP I{ERRMSG} reply is made to remove a potential denial of service - avenue. - """ - log.msg('Unknown CTCP query from %r: %r %r' % (user, tag, data)) - - - def ctcpQuery_ACTION(self, user, channel, data): - self.action(user, channel, data) - - def ctcpQuery_PING(self, user, channel, data): - nick = user.split('!')[0] - self.ctcpMakeReply(nick, [("PING", data)]) - - def ctcpQuery_FINGER(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a FINGER query?" - % (user, data)) - if not self.fingerReply: - return - - if callable(self.fingerReply): - reply = self.fingerReply() - else: - reply = str(self.fingerReply) - - nick = user.split('!')[0] - self.ctcpMakeReply(nick, [('FINGER', reply)]) - - def ctcpQuery_VERSION(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a VERSION query?" - % (user, data)) - - if self.versionName: - nick = user.split('!')[0] - self.ctcpMakeReply(nick, [('VERSION', '%s:%s:%s' % - (self.versionName, - self.versionNum or '', - self.versionEnv or ''))]) - - def ctcpQuery_SOURCE(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a SOURCE query?" - % (user, data)) - if self.sourceURL: - nick = user.split('!')[0] - # The CTCP document (Zeuge, Rollo, Mesander 1994) says that SOURCE - # replies should be responded to with the location of an anonymous - # FTP server in host:directory:file format. I'm taking the liberty - # of bringing it into the 21st century by sending a URL instead. - self.ctcpMakeReply(nick, [('SOURCE', self.sourceURL), - ('SOURCE', None)]) - - def ctcpQuery_USERINFO(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a USERINFO query?" - % (user, data)) - if self.userinfo: - nick = user.split('!')[0] - self.ctcpMakeReply(nick, [('USERINFO', self.userinfo)]) - - def ctcpQuery_CLIENTINFO(self, user, channel, data): - """ - A master index of what CTCP tags this client knows. - - If no arguments are provided, respond with a list of known tags. - If an argument is provided, provide human-readable help on - the usage of that tag. - """ - - nick = user.split('!')[0] - if not data: - # XXX: prefixedMethodNames gets methods from my *class*, - # but it's entirely possible that this *instance* has more - # methods. - names = reflect.prefixedMethodNames(self.__class__, - 'ctcpQuery_') - - self.ctcpMakeReply(nick, [('CLIENTINFO', ' '.join(names))]) - else: - args = data.split() - method = getattr(self, 'ctcpQuery_%s' % (args[0],), None) - if not method: - self.ctcpMakeReply(nick, [('ERRMSG', - "CLIENTINFO %s :" - "Unknown query '%s'" - % (data, args[0]))]) - return - doc = getattr(method, '__doc__', '') - self.ctcpMakeReply(nick, [('CLIENTINFO', doc)]) - - - def ctcpQuery_ERRMSG(self, user, channel, data): - # Yeah, this seems strange, but that's what the spec says to do - # when faced with an ERRMSG query (not a reply). - nick = user.split('!')[0] - self.ctcpMakeReply(nick, [('ERRMSG', - "%s :No error has occoured." % data)]) - - def ctcpQuery_TIME(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a TIME query?" - % (user, data)) - nick = user.split('!')[0] - self.ctcpMakeReply(nick, - [('TIME', ':%s' % - time.asctime(time.localtime(time.time())))]) - - def ctcpQuery_DCC(self, user, channel, data): - """ - Initiate a Direct Client Connection - - @param user: The hostmask of the user/client. - @type user: L{bytes} - - @param channel: The name of the IRC channel. - @type channel: L{bytes} - - @param data: The DCC request message. - @type data: L{bytes} - """ - - if not data: return - dcctype = data.split(None, 1)[0].upper() - handler = getattr(self, "dcc_" + dcctype, None) - if handler: - if self.dcc_sessions is None: - self.dcc_sessions = [] - data = data[len(dcctype)+1:] - handler(user, channel, data) - else: - nick = user.split('!')[0] - self.ctcpMakeReply(nick, [('ERRMSG', - "DCC %s :Unknown DCC type '%s'" - % (data, dcctype))]) - self.quirkyMessage("%s offered unknown DCC type %s" - % (user, dcctype)) - - - def dcc_SEND(self, user, channel, data): - # Use shlex.split for those who send files with spaces in the names. - data = shlex.split(data) - if len(data) < 3: - raise IRCBadMessage("malformed DCC SEND request: %r" % (data,)) - - (filename, address, port) = data[:3] - - address = dccParseAddress(address) - try: - port = int(port) - except ValueError: - raise IRCBadMessage("Indecipherable port %r" % (port,)) - - size = -1 - if len(data) >= 4: - try: - size = int(data[3]) - except ValueError: - pass - - # XXX Should we bother passing this data? - self.dccDoSend(user, address, port, filename, size, data) - - - def dcc_ACCEPT(self, user, channel, data): - data = shlex.split(data) - if len(data) < 3: - raise IRCBadMessage("malformed DCC SEND ACCEPT request: %r" % ( - data,)) - (filename, port, resumePos) = data[:3] - try: - port = int(port) - resumePos = int(resumePos) - except ValueError: - return - - self.dccDoAcceptResume(user, filename, port, resumePos) - - - def dcc_RESUME(self, user, channel, data): - data = shlex.split(data) - if len(data) < 3: - raise IRCBadMessage("malformed DCC SEND RESUME request: %r" % ( - data,)) - (filename, port, resumePos) = data[:3] - try: - port = int(port) - resumePos = int(resumePos) - except ValueError: - return - - self.dccDoResume(user, filename, port, resumePos) - - - def dcc_CHAT(self, user, channel, data): - data = shlex.split(data) - if len(data) < 3: - raise IRCBadMessage("malformed DCC CHAT request: %r" % (data,)) - - (filename, address, port) = data[:3] - - address = dccParseAddress(address) - try: - port = int(port) - except ValueError: - raise IRCBadMessage("Indecipherable port %r" % (port,)) - - self.dccDoChat(user, channel, address, port, data) - - ### The dccDo methods are the slightly higher-level siblings of - ### common dcc_ methods; the arguments have been parsed for them. - - def dccDoSend(self, user, address, port, fileName, size, data): - """ - Called when I receive a DCC SEND offer from a client. - - By default, I do nothing here. - - @param user: The hostmask of the requesting user. - @type user: L{bytes} - - @param address: The IP address of the requesting user. - @type address: L{bytes} - - @param port: An integer representing the port of the requesting user. - @type port: L{int} - - @param fileName: The name of the file to be transferred. - @type fileName: L{bytes} - - @param size: The size of the file to be transferred, which may be C{-1} - if the size of the file was not specified in the DCC SEND request. - @type size: L{int} - - @param data: A 3-list of [fileName, address, port]. - @type data: L{list} - """ - - - def dccDoResume(self, user, file, port, resumePos): - """ - Called when a client is trying to resume an offered file via DCC send. - It should be either replied to with a DCC ACCEPT or ignored (default). - - @param user: The hostmask of the user who wants to resume the transfer - of a file previously offered via DCC send. - @type user: L{bytes} - - @param file: The name of the file to resume the transfer of. - @type file: L{bytes} - - @param port: An integer representing the port of the requesting user. - @type port: L{int} - - @param resumePos: The position in the file from where the transfer - should resume. - @type resumePos: L{int} - """ - pass - - - def dccDoAcceptResume(self, user, file, port, resumePos): - """ - Called when a client has verified and accepted a DCC resume request - made by us. By default it will do nothing. - - @param user: The hostmask of the user who has accepted the DCC resume - request. - @type user: L{bytes} - - @param file: The name of the file to resume the transfer of. - @type file: L{bytes} - - @param port: An integer representing the port of the accepting user. - @type port: L{int} - - @param resumePos: The position in the file from where the transfer - should resume. - @type resumePos: L{int} - """ - pass - - - def dccDoChat(self, user, channel, address, port, data): - pass - #factory = DccChatFactory(self, queryData=(user, channel, data)) - #reactor.connectTCP(address, port, factory) - #self.dcc_sessions.append(factory) - - #def ctcpQuery_SED(self, user, data): - # """Simple Encryption Doodoo - # - # Feel free to implement this, but no specification is available. - # """ - # raise NotImplementedError - - - def ctcpMakeReply(self, user, messages): - """ - Send one or more C{extended messages} as a CTCP reply. - - @type messages: a list of extended messages. An extended - message is a (tag, data) tuple, where 'data' may be C{None}. - """ - self.notice(user, ctcpStringify(messages)) - - ### client CTCP query commands - - def ctcpMakeQuery(self, user, messages): - """ - Send one or more C{extended messages} as a CTCP query. - - @type messages: a list of extended messages. An extended - message is a (tag, data) tuple, where 'data' may be C{None}. - """ - self.msg(user, ctcpStringify(messages)) - - ### Receiving a response to a CTCP query (presumably to one we made) - ### You may want to add methods here, or override UnknownReply. - - def ctcpReply(self, user, channel, messages): - """ - Dispatch method for any CTCP replies received. - """ - for m in messages: - method = getattr(self, "ctcpReply_%s" % m[0], None) - if method: - method(user, channel, m[1]) - else: - self.ctcpUnknownReply(user, channel, m[0], m[1]) - - def ctcpReply_PING(self, user, channel, data): - nick = user.split('!', 1)[0] - if (not self._pings) or (not self._pings.has_key((nick, data))): - raise IRCBadMessage,\ - "Bogus PING response from %s: %s" % (user, data) - - t0 = self._pings[(nick, data)] - self.pong(user, time.time() - t0) - - def ctcpUnknownReply(self, user, channel, tag, data): - """ - Called when a fitting ctcpReply_ method is not found. - - @param user: The hostmask of the user. - @type user: L{bytes} - - @param channel: The name of the IRC channel. - @type channel: L{bytes} - - @param tag: The CTCP request tag for which no fitting method is found. - @type tag: L{bytes} - - @param data: The CTCP message. - @type data: L{bytes} - """ - # FIXME:7560: - # Add code for handling arbitrary queries and not treat them as - # anomalies. - - log.msg("Unknown CTCP reply from %s: %s %s\n" - % (user, tag, data)) - - ### Error handlers - ### You may override these with something more appropriate to your UI. - - def badMessage(self, line, excType, excValue, tb): - """ - When I get a message that's so broken I can't use it. - - @param line: The indecipherable message. - @type line: L{bytes} - - @param excType: The exception type of the exception raised by the - message. - @type excType: L{type} - - @param excValue: The exception parameter of excType or its associated - value(the second argument to C{raise}). - @type excValue: L{BaseException} - - @param tb: The Traceback as a traceback object. - @type tb: L{traceback} - """ - log.msg(line) - log.msg(''.join(traceback.format_exception(excType, excValue, tb))) - - - def quirkyMessage(self, s): - """ - This is called when I receive a message which is peculiar, but not - wholly indecipherable. - - @param s: The peculiar message. - @type s: L{bytes} - """ - log.msg(s + '\n') - - ### Protocool methods - - def connectionMade(self): - self.supported = ServerSupportedFeatures() - self._queue = [] - if self.performLogin: - self.register(self.nickname) - - def dataReceived(self, data): - basic.LineReceiver.dataReceived(self, data.replace('\r', '')) - - def lineReceived(self, line): - line = lowDequote(line) - try: - prefix, command, params = parsemsg(line) - if command in numeric_to_symbolic: - command = numeric_to_symbolic[command] - self.handleCommand(command, prefix, params) - except IRCBadMessage: - self.badMessage(line, *sys.exc_info()) - - - def getUserModeParams(self): - """ - Get user modes that require parameters for correct parsing. - - @rtype: C{[str, str]} - @return C{[add, remove]} - """ - return ['', ''] - - - def getChannelModeParams(self): - """ - Get channel modes that require parameters for correct parsing. - - @rtype: C{[str, str]} - @return C{[add, remove]} - """ - # PREFIX modes are treated as "type B" CHANMODES, they always take - # parameter. - params = ['', ''] - prefixes = self.supported.getFeature('PREFIX', {}) - params[0] = params[1] = ''.join(prefixes.iterkeys()) - - chanmodes = self.supported.getFeature('CHANMODES') - if chanmodes is not None: - params[0] += chanmodes.get('addressModes', '') - params[0] += chanmodes.get('param', '') - params[1] = params[0] - params[0] += chanmodes.get('setParam', '') - return params - - - def handleCommand(self, command, prefix, params): - """ - Determine the function to call for the given command and call it with - the given arguments. - - @param command: The IRC command to determine the function for. - @type command: L{bytes} - - @param prefix: The prefix of the IRC message (as returned by - L{parsemsg}). - @type prefix: L{bytes} - - @param params: A list of parameters to call the function with. - @type params: L{list} - """ - method = getattr(self, "irc_%s" % command, None) - try: - if method is not None: - method(prefix, params) - else: - self.irc_unknown(prefix, command, params) - except: - log.deferr() - - - def __getstate__(self): - dct = self.__dict__.copy() - dct['dcc_sessions'] = None - dct['_pings'] = None - return dct - - -def dccParseAddress(address): - if '.' in address: - pass - else: - try: - address = long(address) - except ValueError: - raise IRCBadMessage,\ - "Indecipherable address %r" % (address,) - else: - address = ( - (address >> 24) & 0xFF, - (address >> 16) & 0xFF, - (address >> 8) & 0xFF, - address & 0xFF, - ) - address = '.'.join(map(str,address)) - return address - - -class DccFileReceiveBasic(protocol.Protocol, styles.Ephemeral): - """ - Bare protocol to receive a Direct Client Connection SEND stream. - - This does enough to keep the other guy talking, but you'll want to extend - my dataReceived method to *do* something with the data I get. - - @ivar bytesReceived: An integer representing the number of bytes of data - received. - @type bytesReceived: L{int} - """ - - bytesReceived = 0 - - def __init__(self, resumeOffset=0): - """ - @param resumeOffset: An integer representing the amount of bytes from - where the transfer of data should be resumed. - @type resumeOffset: L{int} - """ - self.bytesReceived = resumeOffset - self.resume = (resumeOffset != 0) - - def dataReceived(self, data): - """ - See: L{protocol.Protocol.dataReceived} - - Warning: This just acknowledges to the remote host that the data has - been received; it doesn't I{do} anything with the data, so you'll want - to override this. - """ - self.bytesReceived = self.bytesReceived + len(data) - self.transport.write(struct.pack('!i', self.bytesReceived)) - - -class DccSendProtocol(protocol.Protocol, styles.Ephemeral): - """ - Protocol for an outgoing Direct Client Connection SEND. - - @ivar blocksize: An integer representing the size of an individual block of - data. - @type blocksize: L{int} - - @ivar file: The file to be sent. This can be either a file object or - simply the name of the file. - @type file: L{file} or L{bytes} - - @ivar bytesSent: An integer representing the number of bytes sent. - @type bytesSent: L{int} - - @ivar completed: An integer representing whether the transfer has been - completed or not. - @type completed: L{int} - - @ivar connected: An integer representing whether the connection has been - established or not. - @type connected: L{int} - """ - - blocksize = 1024 - file = None - bytesSent = 0 - completed = 0 - connected = 0 - - def __init__(self, file): - if type(file) is types.StringType: - self.file = open(file, 'r') - - def connectionMade(self): - self.connected = 1 - self.sendBlock() - - def dataReceived(self, data): - # XXX: Do we need to check to see if len(data) != fmtsize? - - bytesShesGot = struct.unpack("!I", data) - if bytesShesGot < self.bytesSent: - # Wait for her. - # XXX? Add some checks to see if we've stalled out? - return - elif bytesShesGot > self.bytesSent: - # self.transport.log("DCC SEND %s: She says she has %d bytes " - # "but I've only sent %d. I'm stopping " - # "this screwy transfer." - # % (self.file, - # bytesShesGot, self.bytesSent)) - self.transport.loseConnection() - return - - self.sendBlock() - - def sendBlock(self): - block = self.file.read(self.blocksize) - if block: - self.transport.write(block) - self.bytesSent = self.bytesSent + len(block) - else: - # Nothing more to send, transfer complete. - self.transport.loseConnection() - self.completed = 1 - - def connectionLost(self, reason): - self.connected = 0 - if hasattr(self.file, "close"): - self.file.close() - - -class DccSendFactory(protocol.Factory): - protocol = DccSendProtocol - def __init__(self, file): - self.file = file - - def buildProtocol(self, connection): - p = self.protocol(self.file) - p.factory = self - return p - - -def fileSize(file): - """ - I'll try my damndest to determine the size of this file object. - - @param file: The file object to determine the size of. - @type file: L{file} - - @rtype: L{int} or L{None} - @return: The size of the file object as an integer if it can be determined, - otherwise return L{None}. - """ - size = None - if hasattr(file, "fileno"): - fileno = file.fileno() - try: - stat_ = os.fstat(fileno) - size = stat_[stat.ST_SIZE] - except: - pass - else: - return size - - if hasattr(file, "name") and path.exists(file.name): - try: - size = path.getsize(file.name) - except: - pass - else: - return size - - if hasattr(file, "seek") and hasattr(file, "tell"): - try: - try: - file.seek(0, 2) - size = file.tell() - finally: - file.seek(0, 0) - except: - pass - else: - return size - - return size - -class DccChat(basic.LineReceiver, styles.Ephemeral): - """ - Direct Client Connection protocol type CHAT. - - DCC CHAT is really just your run o' the mill basic.LineReceiver - protocol. This class only varies from that slightly, accepting - either LF or CR LF for a line delimeter for incoming messages - while always using CR LF for outgoing. - - The lineReceived method implemented here uses the DCC connection's - 'client' attribute (provided upon construction) to deliver incoming - lines from the DCC chat via IRCClient's normal privmsg interface. - That's something of a spoof, which you may well want to override. - """ - - queryData = None - delimiter = CR + NL - client = None - remoteParty = None - buffer = "" - - def __init__(self, client, queryData=None): - """ - Initialize a new DCC CHAT session. - - queryData is a 3-tuple of - (fromUser, targetUserOrChannel, data) - as received by the CTCP query. - - (To be honest, fromUser is the only thing that's currently - used here. targetUserOrChannel is potentially useful, while - the 'data' argument is soley for informational purposes.) - """ - self.client = client - if queryData: - self.queryData = queryData - self.remoteParty = self.queryData[0] - - def dataReceived(self, data): - self.buffer = self.buffer + data - lines = self.buffer.split(LF) - # Put the (possibly empty) element after the last LF back in the - # buffer - self.buffer = lines.pop() - - for line in lines: - if line[-1] == CR: - line = line[:-1] - self.lineReceived(line) - - def lineReceived(self, line): - log.msg("DCC CHAT<%s> %s" % (self.remoteParty, line)) - self.client.privmsg(self.remoteParty, - self.client.nickname, line) - - -class DccChatFactory(protocol.ClientFactory): - protocol = DccChat - noisy = 0 - def __init__(self, client, queryData): - self.client = client - self.queryData = queryData - - - def buildProtocol(self, addr): - p = self.protocol(client=self.client, queryData=self.queryData) - p.factory = self - return p - - - def clientConnectionFailed(self, unused_connector, unused_reason): - self.client.dcc_sessions.remove(self) - - def clientConnectionLost(self, unused_connector, unused_reason): - self.client.dcc_sessions.remove(self) - - -def dccDescribe(data): - """ - Given the data chunk from a DCC query, return a descriptive string. - - @param data: The data from a DCC query. - @type data: L{bytes} - - @rtype: L{bytes} - @return: A descriptive string. - """ - - orig_data = data - data = data.split() - if len(data) < 4: - return orig_data - - (dcctype, arg, address, port) = data[:4] - - if '.' in address: - pass - else: - try: - address = long(address) - except ValueError: - pass - else: - address = ( - (address >> 24) & 0xFF, - (address >> 16) & 0xFF, - (address >> 8) & 0xFF, - address & 0xFF, - ) - address = '.'.join(map(str, address)) - - if dcctype == 'SEND': - filename = arg - - size_txt = '' - if len(data) >= 5: - try: - size = int(data[4]) - size_txt = ' of size %d bytes' % (size,) - except ValueError: - pass - - dcc_text = ("SEND for file '%s'%s at host %s, port %s" - % (filename, size_txt, address, port)) - elif dcctype == 'CHAT': - dcc_text = ("CHAT for host %s, port %s" - % (address, port)) - else: - dcc_text = orig_data - - return dcc_text - - -class DccFileReceive(DccFileReceiveBasic): - """ - Higher-level coverage for getting a file from DCC SEND. - - I allow you to change the file's name and destination directory. I won't - overwrite an existing file unless I've been told it's okay to do so. If - passed the resumeOffset keyword argument I will attempt to resume the file - from that amount of bytes. - - XXX: I need to let the client know when I am finished. - XXX: I need to decide how to keep a progress indicator updated. - XXX: Client needs a way to tell me "Do not finish until I say so." - XXX: I need to make sure the client understands if the file cannot be written. - - @ivar filename: The name of the file to get. - @type filename: L{bytes} - - @ivar fileSize: The size of the file to get, which has a default value of - C{-1} if the size of the file was not specified in the DCC SEND - request. - @type fileSize: L{int} - - @ivar destDir: The destination directory for the file to be received. - @type destDir: L{bytes} - - @ivar overwrite: An integer representing whether an existing file should be - overwritten or not. This initially is an L{int} but can be modified to - be a L{bool} using the L{set_overwrite} method. - @type overwrite: L{int} or L{bool} - - @ivar queryData: queryData is a 3-tuple of (user, channel, data). - @type queryData: L{tuple} - - @ivar fromUser: This is the hostmask of the requesting user and is found at - index 0 of L{queryData}. - @type fromUser: L{bytes} - """ - - filename = 'dcc' - fileSize = -1 - destDir = '.' - overwrite = 0 - fromUser = None - queryData = None - - def __init__(self, filename, fileSize=-1, queryData=None, - destDir='.', resumeOffset=0): - DccFileReceiveBasic.__init__(self, resumeOffset=resumeOffset) - self.filename = filename - self.destDir = destDir - self.fileSize = fileSize - self._resumeOffset = resumeOffset - - if queryData: - self.queryData = queryData - self.fromUser = self.queryData[0] - - def set_directory(self, directory): - """ - Set the directory where the downloaded file will be placed. - - May raise OSError if the supplied directory path is not suitable. - - @param directory: The directory where the file to be received will be - placed. - @type directory: L{bytes} - """ - if not path.exists(directory): - raise OSError(errno.ENOENT, "You see no directory there.", - directory) - if not path.isdir(directory): - raise OSError(errno.ENOTDIR, "You cannot put a file into " - "something which is not a directory.", - directory) - if not os.access(directory, os.X_OK | os.W_OK): - raise OSError(errno.EACCES, - "This directory is too hard to write in to.", - directory) - self.destDir = directory - - def set_filename(self, filename): - """ - Change the name of the file being transferred. - - This replaces the file name provided by the sender. - - @param filename: The new name for the file. - @type filename: L{bytes} - """ - self.filename = filename - - def set_overwrite(self, boolean): - """ - May I overwrite existing files? - - @param boolean: A boolean value representing whether existing files - should be overwritten or not. - @type boolean: L{bool} - """ - self.overwrite = boolean - - - # Protocol-level methods. - - def connectionMade(self): - dst = path.abspath(path.join(self.destDir,self.filename)) - exists = path.exists(dst) - if self.resume and exists: - # I have been told I want to resume, and a file already - # exists - Here we go - self.file = open(dst, 'rb+') - self.file.seek(self._resumeOffset) - self.file.truncate() - log.msg("Attempting to resume %s - starting from %d bytes" % - (self.file, self.file.tell())) - elif self.resume and not exists: - raise OSError(errno.ENOENT, - "You cannot resume writing to a file " - "that does not exist!", - dst) - elif self.overwrite or not exists: - self.file = open(dst, 'wb') - else: - raise OSError(errno.EEXIST, - "There's a file in the way. " - "Perhaps that's why you cannot open it.", - dst) - - def dataReceived(self, data): - self.file.write(data) - DccFileReceiveBasic.dataReceived(self, data) - - # XXX: update a progress indicator here? - - def connectionLost(self, reason): - """ - When the connection is lost, I close the file. - - @param reason: The reason why the connection was lost. - @type reason: L{Failure} - """ - self.connected = 0 - logmsg = ("%s closed." % (self,)) - if self.fileSize > 0: - logmsg = ("%s %d/%d bytes received" - % (logmsg, self.bytesReceived, self.fileSize)) - if self.bytesReceived == self.fileSize: - pass # Hooray! - elif self.bytesReceived < self.fileSize: - logmsg = ("%s (Warning: %d bytes short)" - % (logmsg, self.fileSize - self.bytesReceived)) - else: - logmsg = ("%s (file larger than expected)" - % (logmsg,)) - else: - logmsg = ("%s %d bytes received" - % (logmsg, self.bytesReceived)) - - if hasattr(self, 'file'): - logmsg = "%s and written to %s.\n" % (logmsg, self.file.name) - if hasattr(self.file, 'close'): self.file.close() - - # self.transport.log(logmsg) - - def __str__(self): - if not self.connected: - return "<Unconnected DccFileReceive object at %x>" % (id(self),) - from_ = self.transport.getPeer() - if self.fromUser: - from_ = "%s (%s)" % (self.fromUser, from_) - - s = ("DCC transfer of '%s' from %s" % (self.filename, from_)) - return s - - def __repr__(self): - s = ("<%s at %x: GET %s>" - % (self.__class__, id(self), self.filename)) - return s - - - -_OFF = '\x0f' -_BOLD = '\x02' -_COLOR = '\x03' -_REVERSE_VIDEO = '\x16' -_UNDERLINE = '\x1f' - -# Mapping of IRC color names to their color values. -_IRC_COLORS = dict( - zip(['white', 'black', 'blue', 'green', 'lightRed', 'red', 'magenta', - 'orange', 'yellow', 'lightGreen', 'cyan', 'lightCyan', 'lightBlue', - 'lightMagenta', 'gray', 'lightGray'], range(16))) - -# Mapping of IRC color values to their color names. -_IRC_COLOR_NAMES = dict((code, name) for name, code in _IRC_COLORS.items()) - - - -class _CharacterAttributes(_textattributes.CharacterAttributesMixin): - """ - Factory for character attributes, including foreground and background color - and non-color attributes such as bold, reverse video and underline. - - Character attributes are applied to actual text by using object - indexing-syntax (C{obj['abc']}) after accessing a factory attribute, for - example:: - - attributes.bold['Some text'] - - These can be nested to mix attributes:: - - attributes.bold[attributes.underline['Some text']] - - And multiple values can be passed:: - - attributes.normal[attributes.bold['Some'], ' text'] - - Non-color attributes can be accessed by attribute name, available - attributes are: - - - bold - - reverseVideo - - underline - - Available colors are: - - 0. white - 1. black - 2. blue - 3. green - 4. light red - 5. red - 6. magenta - 7. orange - 8. yellow - 9. light green - 10. cyan - 11. light cyan - 12. light blue - 13. light magenta - 14. gray - 15. light gray - - @ivar fg: Foreground colors accessed by attribute name, see above - for possible names. - - @ivar bg: Background colors accessed by attribute name, see above - for possible names. - - @since: 13.1 - """ - fg = _textattributes._ColorAttribute( - _textattributes._ForegroundColorAttr, _IRC_COLORS) - bg = _textattributes._ColorAttribute( - _textattributes._BackgroundColorAttr, _IRC_COLORS) - - attrs = { - 'bold': _BOLD, - 'reverseVideo': _REVERSE_VIDEO, - 'underline': _UNDERLINE} - - - -attributes = _CharacterAttributes() - - - -class _FormattingState(_textattributes._FormattingStateMixin): - """ - Formatting state/attributes of a single character. - - Attributes include: - - Formatting nullifier - - Bold - - Underline - - Reverse video - - Foreground color - - Background color - - @since: 13.1 - """ - compareAttributes = ( - 'off', 'bold', 'underline', 'reverseVideo', 'foreground', 'background') - - - def __init__(self, off=False, bold=False, underline=False, - reverseVideo=False, foreground=None, background=None): - self.off = off - self.bold = bold - self.underline = underline - self.reverseVideo = reverseVideo - self.foreground = foreground - self.background = background - - - def toMIRCControlCodes(self): - """ - Emit a mIRC control sequence that will set up all the attributes this - formatting state has set. - - @return: A string containing mIRC control sequences that mimic this - formatting state. - """ - attrs = [] - if self.bold: - attrs.append(_BOLD) - if self.underline: - attrs.append(_UNDERLINE) - if self.reverseVideo: - attrs.append(_REVERSE_VIDEO) - if self.foreground is not None or self.background is not None: - c = '' - if self.foreground is not None: - c += '%02d' % (self.foreground,) - if self.background is not None: - c += ',%02d' % (self.background,) - attrs.append(_COLOR + c) - return _OFF + ''.join(map(str, attrs)) - - - -def _foldr(f, z, xs): - """ - Apply a function of two arguments cumulatively to the items of - a sequence, from right to left, so as to reduce the sequence to - a single value. - - @type f: C{callable} taking 2 arguments - - @param z: Initial value. - - @param xs: Sequence to reduce. - - @return: Single value resulting from reducing C{xs}. - """ - return reduce(lambda x, y: f(y, x), reversed(xs), z) - - - -class _FormattingParser(_CommandDispatcherMixin): - """ - A finite-state machine that parses formatted IRC text. - - Currently handled formatting includes: bold, reverse, underline, - mIRC color codes and the ability to remove all current formatting. - - @see: U{http://www.mirc.co.uk/help/color.txt} - - @type _formatCodes: C{dict} mapping C{str} to C{str} - @cvar _formatCodes: Mapping of format code values to names. - - @type state: C{str} - @ivar state: Current state of the finite-state machine. - - @type _buffer: C{str} - @ivar _buffer: Buffer, containing the text content, of the formatting - sequence currently being parsed, the buffer is used as the content for - L{_attrs} before being added to L{_result} and emptied upon calling - L{emit}. - - @type _attrs: C{set} - @ivar _attrs: Set of the applicable formatting states (bold, underline, - etc.) for the current L{_buffer}, these are applied to L{_buffer} when - calling L{emit}. - - @type foreground: L{_ForegroundColorAttr} - @ivar foreground: Current foreground color attribute, or C{None}. - - @type background: L{_BackgroundColorAttr} - @ivar background: Current background color attribute, or C{None}. - - @ivar _result: Current parse result. - """ - prefix = 'state' - - - _formatCodes = { - _OFF: 'off', - _BOLD: 'bold', - _COLOR: 'color', - _REVERSE_VIDEO: 'reverseVideo', - _UNDERLINE: 'underline'} - - - def __init__(self): - self.state = 'TEXT' - self._buffer = '' - self._attrs = set() - self._result = None - self.foreground = None - self.background = None - - - def process(self, ch): - """ - Handle input. - - @type ch: C{str} - @param ch: A single character of input to process - """ - self.dispatch(self.state, ch) - - - def complete(self): - """ - Flush the current buffer and return the final parsed result. - - @return: Structured text and attributes. - """ - self.emit() - if self._result is None: - self._result = attributes.normal - return self._result - - - def emit(self): - """ - Add the currently parsed input to the result. - """ - if self._buffer: - attrs = [getattr(attributes, name) for name in self._attrs] - attrs.extend(filter(None, [self.foreground, self.background])) - if not attrs: - attrs.append(attributes.normal) - attrs.append(self._buffer) - - attr = _foldr(operator.getitem, attrs.pop(), attrs) - if self._result is None: - self._result = attr - else: - self._result[attr] - self._buffer = '' - - - def state_TEXT(self, ch): - """ - Handle the "text" state. - - Along with regular text, single token formatting codes are handled - in this state too. - - @param ch: The character being processed. - """ - formatName = self._formatCodes.get(ch) - if formatName == 'color': - self.emit() - self.state = 'COLOR_FOREGROUND' - else: - if formatName is None: - self._buffer += ch - else: - self.emit() - if formatName == 'off': - self._attrs = set() - self.foreground = self.background = None - else: - self._attrs.symmetric_difference_update([formatName]) - - - def state_COLOR_FOREGROUND(self, ch): - """ - Handle the foreground color state. - - Foreground colors can consist of up to two digits and may optionally - end in a I{,}. Any non-digit or non-comma characters are treated as - invalid input and result in the state being reset to "text". - - @param ch: The character being processed. - """ - # Color codes may only be a maximum of two characters. - if ch.isdigit() and len(self._buffer) < 2: - self._buffer += ch - else: - if self._buffer: - # Wrap around for color numbers higher than we support, like - # most other IRC clients. - col = int(self._buffer) % len(_IRC_COLORS) - self.foreground = getattr(attributes.fg, _IRC_COLOR_NAMES[col]) - else: - # If there were no digits, then this has been an empty color - # code and we can reset the color state. - self.foreground = self.background = None - - if ch == ',' and self._buffer: - # If there's a comma and it's not the first thing, move on to - # the background state. - self._buffer = '' - self.state = 'COLOR_BACKGROUND' - else: - # Otherwise, this is a bogus color code, fall back to text. - self._buffer = '' - self.state = 'TEXT' - self.emit() - self.process(ch) - - - def state_COLOR_BACKGROUND(self, ch): - """ - Handle the background color state. - - Background colors can consist of up to two digits and must occur after - a foreground color and must be preceded by a I{,}. Any non-digit - character is treated as invalid input and results in the state being - set to "text". - - @param ch: The character being processed. - """ - # Color codes may only be a maximum of two characters. - if ch.isdigit() and len(self._buffer) < 2: - self._buffer += ch - else: - if self._buffer: - # Wrap around for color numbers higher than we support, like - # most other IRC clients. - col = int(self._buffer) % len(_IRC_COLORS) - self.background = getattr(attributes.bg, _IRC_COLOR_NAMES[col]) - self._buffer = '' - - self.emit() - self.state = 'TEXT' - self.process(ch) - - - -def parseFormattedText(text): - """ - Parse text containing IRC formatting codes into structured information. - - Color codes are mapped from 0 to 15 and wrap around if greater than 15. - - @type text: C{str} - @param text: Formatted text to parse. - - @return: Structured text and attributes. - - @since: 13.1 - """ - state = _FormattingParser() - for ch in text: - state.process(ch) - return state.complete() - - - -def assembleFormattedText(formatted): - """ - Assemble formatted text from structured information. - - Currently handled formatting includes: bold, reverse, underline, - mIRC color codes and the ability to remove all current formatting. - - It is worth noting that assembled text will always begin with the control - code to disable other attributes for the sake of correctness. - - For example:: - - from twisted.words.protocols.irc import attributes as A - assembleFormattedText( - A.normal[A.bold['Time: '], A.fg.lightRed['Now!']]) - - Would produce "Time: " in bold formatting, followed by "Now!" with a - foreground color of light red and without any additional formatting. - - Available attributes are: - - bold - - reverseVideo - - underline - - Available colors are: - 0. white - 1. black - 2. blue - 3. green - 4. light red - 5. red - 6. magenta - 7. orange - 8. yellow - 9. light green - 10. cyan - 11. light cyan - 12. light blue - 13. light magenta - 14. gray - 15. light gray - - @see: U{http://www.mirc.co.uk/help/color.txt} - - @param formatted: Structured text and attributes. - - @rtype: C{str} - @return: String containing mIRC control sequences that mimic those - specified by L{formatted}. - - @since: 13.1 - """ - return _textattributes.flatten( - formatted, _FormattingState(), 'toMIRCControlCodes') - - - -def stripFormatting(text): - """ - Remove all formatting codes from C{text}, leaving only the text. - - @type text: C{str} - @param text: Formatted text to parse. - - @rtype: C{str} - @return: Plain text without any control sequences. - - @since: 13.1 - """ - formatted = parseFormattedText(text) - return _textattributes.flatten( - formatted, _textattributes.DefaultFormattingState()) - - - -# CTCP constants and helper functions - -X_DELIM = chr(001) - -def ctcpExtract(message): - """ - Extract CTCP data from a string. - - @return: A C{dict} containing two keys: - - C{'extended'}: A list of CTCP (tag, data) tuples. - - C{'normal'}: A list of strings which were not inside a CTCP delimiter. - """ - extended_messages = [] - normal_messages = [] - retval = {'extended': extended_messages, - 'normal': normal_messages } - - messages = message.split(X_DELIM) - odd = 0 - - # X1 extended data X2 nomal data X3 extended data X4 normal... - while messages: - if odd: - extended_messages.append(messages.pop(0)) - else: - normal_messages.append(messages.pop(0)) - odd = not odd - - extended_messages[:] = filter(None, extended_messages) - normal_messages[:] = filter(None, normal_messages) - - extended_messages[:] = map(ctcpDequote, extended_messages) - for i in xrange(len(extended_messages)): - m = extended_messages[i].split(SPC, 1) - tag = m[0] - if len(m) > 1: - data = m[1] - else: - data = None - - extended_messages[i] = (tag, data) - - return retval - -# CTCP escaping - -M_QUOTE= chr(020) - -mQuoteTable = { - NUL: M_QUOTE + '0', - NL: M_QUOTE + 'n', - CR: M_QUOTE + 'r', - M_QUOTE: M_QUOTE + M_QUOTE - } - -mDequoteTable = {} -for k, v in mQuoteTable.items(): - mDequoteTable[v[-1]] = k -del k, v - -mEscape_re = re.compile('%s.' % (re.escape(M_QUOTE),), re.DOTALL) - -def lowQuote(s): - for c in (M_QUOTE, NUL, NL, CR): - s = s.replace(c, mQuoteTable[c]) - return s - -def lowDequote(s): - def sub(matchobj, mDequoteTable=mDequoteTable): - s = matchobj.group()[1] - try: - s = mDequoteTable[s] - except KeyError: - s = s - return s - - return mEscape_re.sub(sub, s) - -X_QUOTE = '\\' - -xQuoteTable = { - X_DELIM: X_QUOTE + 'a', - X_QUOTE: X_QUOTE + X_QUOTE - } - -xDequoteTable = {} - -for k, v in xQuoteTable.items(): - xDequoteTable[v[-1]] = k - -xEscape_re = re.compile('%s.' % (re.escape(X_QUOTE),), re.DOTALL) - -def ctcpQuote(s): - for c in (X_QUOTE, X_DELIM): - s = s.replace(c, xQuoteTable[c]) - return s - -def ctcpDequote(s): - def sub(matchobj, xDequoteTable=xDequoteTable): - s = matchobj.group()[1] - try: - s = xDequoteTable[s] - except KeyError: - s = s - return s - - return xEscape_re.sub(sub, s) - -def ctcpStringify(messages): - """ - @type messages: a list of extended messages. An extended - message is a (tag, data) tuple, where 'data' may be C{None}, a - string, or a list of strings to be joined with whitespace. - - @returns: String - """ - coded_messages = [] - for (tag, data) in messages: - if data: - if not isinstance(data, types.StringType): - try: - # data as list-of-strings - data = " ".join(map(str, data)) - except TypeError: - # No? Then use it's %s representation. - pass - m = "%s %s" % (tag, data) - else: - m = str(tag) - m = ctcpQuote(m) - m = "%s%s%s" % (X_DELIM, m, X_DELIM) - coded_messages.append(m) - - line = ''.join(coded_messages) - return line - - -# Constants (from RFC 2812) -RPL_WELCOME = '001' -RPL_YOURHOST = '002' -RPL_CREATED = '003' -RPL_MYINFO = '004' -RPL_ISUPPORT = '005' -RPL_BOUNCE = '010' -RPL_USERHOST = '302' -RPL_ISON = '303' -RPL_AWAY = '301' -RPL_UNAWAY = '305' -RPL_NOWAWAY = '306' -RPL_WHOISUSER = '311' -RPL_WHOISSERVER = '312' -RPL_WHOISOPERATOR = '313' -RPL_WHOISIDLE = '317' -RPL_ENDOFWHOIS = '318' -RPL_WHOISCHANNELS = '319' -RPL_WHOWASUSER = '314' -RPL_ENDOFWHOWAS = '369' -RPL_LISTSTART = '321' -RPL_LIST = '322' -RPL_LISTEND = '323' -RPL_UNIQOPIS = '325' -RPL_CHANNELMODEIS = '324' -RPL_NOTOPIC = '331' -RPL_TOPIC = '332' -RPL_INVITING = '341' -RPL_SUMMONING = '342' -RPL_INVITELIST = '346' -RPL_ENDOFINVITELIST = '347' -RPL_EXCEPTLIST = '348' -RPL_ENDOFEXCEPTLIST = '349' -RPL_VERSION = '351' -RPL_WHOREPLY = '352' -RPL_ENDOFWHO = '315' -RPL_NAMREPLY = '353' -RPL_ENDOFNAMES = '366' -RPL_LINKS = '364' -RPL_ENDOFLINKS = '365' -RPL_BANLIST = '367' -RPL_ENDOFBANLIST = '368' -RPL_INFO = '371' -RPL_ENDOFINFO = '374' -RPL_MOTDSTART = '375' -RPL_MOTD = '372' -RPL_ENDOFMOTD = '376' -RPL_YOUREOPER = '381' -RPL_REHASHING = '382' -RPL_YOURESERVICE = '383' -RPL_TIME = '391' -RPL_USERSSTART = '392' -RPL_USERS = '393' -RPL_ENDOFUSERS = '394' -RPL_NOUSERS = '395' -RPL_TRACELINK = '200' -RPL_TRACECONNECTING = '201' -RPL_TRACEHANDSHAKE = '202' -RPL_TRACEUNKNOWN = '203' -RPL_TRACEOPERATOR = '204' -RPL_TRACEUSER = '205' -RPL_TRACESERVER = '206' -RPL_TRACESERVICE = '207' -RPL_TRACENEWTYPE = '208' -RPL_TRACECLASS = '209' -RPL_TRACERECONNECT = '210' -RPL_TRACELOG = '261' -RPL_TRACEEND = '262' -RPL_STATSLINKINFO = '211' -RPL_STATSCOMMANDS = '212' -RPL_ENDOFSTATS = '219' -RPL_STATSUPTIME = '242' -RPL_STATSOLINE = '243' -RPL_UMODEIS = '221' -RPL_SERVLIST = '234' -RPL_SERVLISTEND = '235' -RPL_LUSERCLIENT = '251' -RPL_LUSEROP = '252' -RPL_LUSERUNKNOWN = '253' -RPL_LUSERCHANNELS = '254' -RPL_LUSERME = '255' -RPL_ADMINME = '256' -RPL_ADMINLOC = '257' -RPL_ADMINLOC = '258' -RPL_ADMINEMAIL = '259' -RPL_TRYAGAIN = '263' -ERR_NOSUCHNICK = '401' -ERR_NOSUCHSERVER = '402' -ERR_NOSUCHCHANNEL = '403' -ERR_CANNOTSENDTOCHAN = '404' -ERR_TOOMANYCHANNELS = '405' -ERR_WASNOSUCHNICK = '406' -ERR_TOOMANYTARGETS = '407' -ERR_NOSUCHSERVICE = '408' -ERR_NOORIGIN = '409' -ERR_NORECIPIENT = '411' -ERR_NOTEXTTOSEND = '412' -ERR_NOTOPLEVEL = '413' -ERR_WILDTOPLEVEL = '414' -ERR_BADMASK = '415' -ERR_UNKNOWNCOMMAND = '421' -ERR_NOMOTD = '422' -ERR_NOADMININFO = '423' -ERR_FILEERROR = '424' -ERR_NONICKNAMEGIVEN = '431' -ERR_ERRONEUSNICKNAME = '432' -ERR_NICKNAMEINUSE = '433' -ERR_NICKCOLLISION = '436' -ERR_UNAVAILRESOURCE = '437' -ERR_USERNOTINCHANNEL = '441' -ERR_NOTONCHANNEL = '442' -ERR_USERONCHANNEL = '443' -ERR_NOLOGIN = '444' -ERR_SUMMONDISABLED = '445' -ERR_USERSDISABLED = '446' -ERR_NOTREGISTERED = '451' -ERR_NEEDMOREPARAMS = '461' -ERR_ALREADYREGISTRED = '462' -ERR_NOPERMFORHOST = '463' -ERR_PASSWDMISMATCH = '464' -ERR_YOUREBANNEDCREEP = '465' -ERR_YOUWILLBEBANNED = '466' -ERR_KEYSET = '467' -ERR_CHANNELISFULL = '471' -ERR_UNKNOWNMODE = '472' -ERR_INVITEONLYCHAN = '473' -ERR_BANNEDFROMCHAN = '474' -ERR_BADCHANNELKEY = '475' -ERR_BADCHANMASK = '476' -ERR_NOCHANMODES = '477' -ERR_BANLISTFULL = '478' -ERR_NOPRIVILEGES = '481' -ERR_CHANOPRIVSNEEDED = '482' -ERR_CANTKILLSERVER = '483' -ERR_RESTRICTED = '484' -ERR_UNIQOPPRIVSNEEDED = '485' -ERR_NOOPERHOST = '491' -ERR_NOSERVICEHOST = '492' -ERR_UMODEUNKNOWNFLAG = '501' -ERR_USERSDONTMATCH = '502' - -# And hey, as long as the strings are already intern'd... -symbolic_to_numeric = { - "RPL_WELCOME": '001', - "RPL_YOURHOST": '002', - "RPL_CREATED": '003', - "RPL_MYINFO": '004', - "RPL_ISUPPORT": '005', - "RPL_BOUNCE": '010', - "RPL_USERHOST": '302', - "RPL_ISON": '303', - "RPL_AWAY": '301', - "RPL_UNAWAY": '305', - "RPL_NOWAWAY": '306', - "RPL_WHOISUSER": '311', - "RPL_WHOISSERVER": '312', - "RPL_WHOISOPERATOR": '313', - "RPL_WHOISIDLE": '317', - "RPL_ENDOFWHOIS": '318', - "RPL_WHOISCHANNELS": '319', - "RPL_WHOWASUSER": '314', - "RPL_ENDOFWHOWAS": '369', - "RPL_LISTSTART": '321', - "RPL_LIST": '322', - "RPL_LISTEND": '323', - "RPL_UNIQOPIS": '325', - "RPL_CHANNELMODEIS": '324', - "RPL_NOTOPIC": '331', - "RPL_TOPIC": '332', - "RPL_INVITING": '341', - "RPL_SUMMONING": '342', - "RPL_INVITELIST": '346', - "RPL_ENDOFINVITELIST": '347', - "RPL_EXCEPTLIST": '348', - "RPL_ENDOFEXCEPTLIST": '349', - "RPL_VERSION": '351', - "RPL_WHOREPLY": '352', - "RPL_ENDOFWHO": '315', - "RPL_NAMREPLY": '353', - "RPL_ENDOFNAMES": '366', - "RPL_LINKS": '364', - "RPL_ENDOFLINKS": '365', - "RPL_BANLIST": '367', - "RPL_ENDOFBANLIST": '368', - "RPL_INFO": '371', - "RPL_ENDOFINFO": '374', - "RPL_MOTDSTART": '375', - "RPL_MOTD": '372', - "RPL_ENDOFMOTD": '376', - "RPL_YOUREOPER": '381', - "RPL_REHASHING": '382', - "RPL_YOURESERVICE": '383', - "RPL_TIME": '391', - "RPL_USERSSTART": '392', - "RPL_USERS": '393', - "RPL_ENDOFUSERS": '394', - "RPL_NOUSERS": '395', - "RPL_TRACELINK": '200', - "RPL_TRACECONNECTING": '201', - "RPL_TRACEHANDSHAKE": '202', - "RPL_TRACEUNKNOWN": '203', - "RPL_TRACEOPERATOR": '204', - "RPL_TRACEUSER": '205', - "RPL_TRACESERVER": '206', - "RPL_TRACESERVICE": '207', - "RPL_TRACENEWTYPE": '208', - "RPL_TRACECLASS": '209', - "RPL_TRACERECONNECT": '210', - "RPL_TRACELOG": '261', - "RPL_TRACEEND": '262', - "RPL_STATSLINKINFO": '211', - "RPL_STATSCOMMANDS": '212', - "RPL_ENDOFSTATS": '219', - "RPL_STATSUPTIME": '242', - "RPL_STATSOLINE": '243', - "RPL_UMODEIS": '221', - "RPL_SERVLIST": '234', - "RPL_SERVLISTEND": '235', - "RPL_LUSERCLIENT": '251', - "RPL_LUSEROP": '252', - "RPL_LUSERUNKNOWN": '253', - "RPL_LUSERCHANNELS": '254', - "RPL_LUSERME": '255', - "RPL_ADMINME": '256', - "RPL_ADMINLOC": '257', - "RPL_ADMINLOC": '258', - "RPL_ADMINEMAIL": '259', - "RPL_TRYAGAIN": '263', - "ERR_NOSUCHNICK": '401', - "ERR_NOSUCHSERVER": '402', - "ERR_NOSUCHCHANNEL": '403', - "ERR_CANNOTSENDTOCHAN": '404', - "ERR_TOOMANYCHANNELS": '405', - "ERR_WASNOSUCHNICK": '406', - "ERR_TOOMANYTARGETS": '407', - "ERR_NOSUCHSERVICE": '408', - "ERR_NOORIGIN": '409', - "ERR_NORECIPIENT": '411', - "ERR_NOTEXTTOSEND": '412', - "ERR_NOTOPLEVEL": '413', - "ERR_WILDTOPLEVEL": '414', - "ERR_BADMASK": '415', - "ERR_UNKNOWNCOMMAND": '421', - "ERR_NOMOTD": '422', - "ERR_NOADMININFO": '423', - "ERR_FILEERROR": '424', - "ERR_NONICKNAMEGIVEN": '431', - "ERR_ERRONEUSNICKNAME": '432', - "ERR_NICKNAMEINUSE": '433', - "ERR_NICKCOLLISION": '436', - "ERR_UNAVAILRESOURCE": '437', - "ERR_USERNOTINCHANNEL": '441', - "ERR_NOTONCHANNEL": '442', - "ERR_USERONCHANNEL": '443', - "ERR_NOLOGIN": '444', - "ERR_SUMMONDISABLED": '445', - "ERR_USERSDISABLED": '446', - "ERR_NOTREGISTERED": '451', - "ERR_NEEDMOREPARAMS": '461', - "ERR_ALREADYREGISTRED": '462', - "ERR_NOPERMFORHOST": '463', - "ERR_PASSWDMISMATCH": '464', - "ERR_YOUREBANNEDCREEP": '465', - "ERR_YOUWILLBEBANNED": '466', - "ERR_KEYSET": '467', - "ERR_CHANNELISFULL": '471', - "ERR_UNKNOWNMODE": '472', - "ERR_INVITEONLYCHAN": '473', - "ERR_BANNEDFROMCHAN": '474', - "ERR_BADCHANNELKEY": '475', - "ERR_BADCHANMASK": '476', - "ERR_NOCHANMODES": '477', - "ERR_BANLISTFULL": '478', - "ERR_NOPRIVILEGES": '481', - "ERR_CHANOPRIVSNEEDED": '482', - "ERR_CANTKILLSERVER": '483', - "ERR_RESTRICTED": '484', - "ERR_UNIQOPPRIVSNEEDED": '485', - "ERR_NOOPERHOST": '491', - "ERR_NOSERVICEHOST": '492', - "ERR_UMODEUNKNOWNFLAG": '501', - "ERR_USERSDONTMATCH": '502', -} - -numeric_to_symbolic = {} -for k, v in symbolic_to_numeric.items(): - numeric_to_symbolic[v] = k diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/__init__.py deleted file mode 100644 index ad95b68..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Jabber: Jabber Protocol Helpers -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/client.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/client.py deleted file mode 100644 index a8da7f9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/client.py +++ /dev/null @@ -1,368 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberclient -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.words.xish import domish, xpath, utility -from twisted.words.protocols.jabber import xmlstream, sasl, error -from twisted.words.protocols.jabber.jid import JID - -NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams' -NS_XMPP_BIND = 'urn:ietf:params:xml:ns:xmpp-bind' -NS_XMPP_SESSION = 'urn:ietf:params:xml:ns:xmpp-session' -NS_IQ_AUTH_FEATURE = 'http://jabber.org/features/iq-auth' - -DigestAuthQry = xpath.internQuery("/iq/query/digest") -PlaintextAuthQry = xpath.internQuery("/iq/query/password") - -def basicClientFactory(jid, secret): - a = BasicAuthenticator(jid, secret) - return xmlstream.XmlStreamFactory(a) - -class IQ(domish.Element): - """ - Wrapper for a Info/Query packet. - - This provides the necessary functionality to send IQs and get notified when - a result comes back. It's a subclass from L{domish.Element}, so you can use - the standard DOM manipulation calls to add data to the outbound request. - - @type callbacks: L{utility.CallbackList} - @cvar callbacks: Callback list to be notified when response comes back - - """ - def __init__(self, xmlstream, type = "set"): - """ - @type xmlstream: L{xmlstream.XmlStream} - @param xmlstream: XmlStream to use for transmission of this IQ - - @type type: C{str} - @param type: IQ type identifier ('get' or 'set') - """ - - domish.Element.__init__(self, ("jabber:client", "iq")) - self.addUniqueId() - self["type"] = type - self._xmlstream = xmlstream - self.callbacks = utility.CallbackList() - - def addCallback(self, fn, *args, **kwargs): - """ - Register a callback for notification when the IQ result is available. - """ - - self.callbacks.addCallback(True, fn, *args, **kwargs) - - def send(self, to = None): - """ - Call this method to send this IQ request via the associated XmlStream. - - @param to: Jabber ID of the entity to send the request to - @type to: C{str} - - @returns: Callback list for this IQ. Any callbacks added to this list - will be fired when the result comes back. - """ - if to != None: - self["to"] = to - self._xmlstream.addOnetimeObserver("/iq[@id='%s']" % self["id"], \ - self._resultEvent) - self._xmlstream.send(self) - - def _resultEvent(self, iq): - self.callbacks.callback(iq) - self.callbacks = None - - - -class IQAuthInitializer(object): - """ - Non-SASL Authentication initializer for the initiating entity. - - This protocol is defined in - U{JEP-0078<http://www.jabber.org/jeps/jep-0078.html>} and mainly serves for - compatibility with pre-XMPP-1.0 server implementations. - """ - - INVALID_USER_EVENT = "//event/client/basicauth/invaliduser" - AUTH_FAILED_EVENT = "//event/client/basicauth/authfailed" - - def __init__(self, xs): - self.xmlstream = xs - - - def initialize(self): - # Send request for auth fields - iq = xmlstream.IQ(self.xmlstream, "get") - iq.addElement(("jabber:iq:auth", "query")) - jid = self.xmlstream.authenticator.jid - iq.query.addElement("username", content = jid.user) - - d = iq.send() - d.addCallbacks(self._cbAuthQuery, self._ebAuthQuery) - return d - - - def _cbAuthQuery(self, iq): - jid = self.xmlstream.authenticator.jid - password = self.xmlstream.authenticator.password - - # Construct auth request - reply = xmlstream.IQ(self.xmlstream, "set") - reply.addElement(("jabber:iq:auth", "query")) - reply.query.addElement("username", content = jid.user) - reply.query.addElement("resource", content = jid.resource) - - # Prefer digest over plaintext - if DigestAuthQry.matches(iq): - digest = xmlstream.hashPassword(self.xmlstream.sid, unicode(password)) - reply.query.addElement("digest", content = digest) - else: - reply.query.addElement("password", content = password) - - d = reply.send() - d.addCallbacks(self._cbAuth, self._ebAuth) - return d - - - def _ebAuthQuery(self, failure): - failure.trap(error.StanzaError) - e = failure.value - if e.condition == 'not-authorized': - self.xmlstream.dispatch(e.stanza, self.INVALID_USER_EVENT) - else: - self.xmlstream.dispatch(e.stanza, self.AUTH_FAILED_EVENT) - - return failure - - - def _cbAuth(self, iq): - pass - - - def _ebAuth(self, failure): - failure.trap(error.StanzaError) - self.xmlstream.dispatch(failure.value.stanza, self.AUTH_FAILED_EVENT) - return failure - - - -class BasicAuthenticator(xmlstream.ConnectAuthenticator): - """ - Authenticates an XmlStream against a Jabber server as a Client. - - This only implements non-SASL authentication, per - U{JEP-0078<http://www.jabber.org/jeps/jep-0078.html>}. Additionally, this - authenticator provides the ability to perform inline registration, per - U{JEP-0077<http://www.jabber.org/jeps/jep-0077.html>}. - - Under normal circumstances, the BasicAuthenticator generates the - L{xmlstream.STREAM_AUTHD_EVENT} once the stream has authenticated. However, - it can also generate other events, such as: - - L{INVALID_USER_EVENT} : Authentication failed, due to invalid username - - L{AUTH_FAILED_EVENT} : Authentication failed, due to invalid password - - L{REGISTER_FAILED_EVENT} : Registration failed - - If authentication fails for any reason, you can attempt to register by - calling the L{registerAccount} method. If the registration succeeds, a - L{xmlstream.STREAM_AUTHD_EVENT} will be fired. Otherwise, one of the above - errors will be generated (again). - """ - - namespace = "jabber:client" - - INVALID_USER_EVENT = IQAuthInitializer.INVALID_USER_EVENT - AUTH_FAILED_EVENT = IQAuthInitializer.AUTH_FAILED_EVENT - REGISTER_FAILED_EVENT = "//event/client/basicauth/registerfailed" - - def __init__(self, jid, password): - xmlstream.ConnectAuthenticator.__init__(self, jid.host) - self.jid = jid - self.password = password - - def associateWithStream(self, xs): - xs.version = (0, 0) - xmlstream.ConnectAuthenticator.associateWithStream(self, xs) - - inits = [ (xmlstream.TLSInitiatingInitializer, False), - (IQAuthInitializer, True), - ] - - for initClass, required in inits: - init = initClass(xs) - init.required = required - xs.initializers.append(init) - - # TODO: move registration into an Initializer? - - def registerAccount(self, username = None, password = None): - if username: - self.jid.user = username - if password: - self.password = password - - iq = IQ(self.xmlstream, "set") - iq.addElement(("jabber:iq:register", "query")) - iq.query.addElement("username", content = self.jid.user) - iq.query.addElement("password", content = self.password) - - iq.addCallback(self._registerResultEvent) - - iq.send() - - def _registerResultEvent(self, iq): - if iq["type"] == "result": - # Registration succeeded -- go ahead and auth - self.streamStarted() - else: - # Registration failed - self.xmlstream.dispatch(iq, self.REGISTER_FAILED_EVENT) - - - -class CheckVersionInitializer(object): - """ - Initializer that checks if the minimum common stream version number is 1.0. - """ - - def __init__(self, xs): - self.xmlstream = xs - - - def initialize(self): - if self.xmlstream.version < (1, 0): - raise error.StreamError('unsupported-version') - - - -class BindInitializer(xmlstream.BaseFeatureInitiatingInitializer): - """ - Initializer that implements Resource Binding for the initiating entity. - - This protocol is documented in U{RFC 3920, section - 7<http://www.xmpp.org/specs/rfc3920.html#bind>}. - """ - - feature = (NS_XMPP_BIND, 'bind') - - def start(self): - iq = xmlstream.IQ(self.xmlstream, 'set') - bind = iq.addElement((NS_XMPP_BIND, 'bind')) - resource = self.xmlstream.authenticator.jid.resource - if resource: - bind.addElement('resource', content=resource) - d = iq.send() - d.addCallback(self.onBind) - return d - - - def onBind(self, iq): - if iq.bind: - self.xmlstream.authenticator.jid = JID(unicode(iq.bind.jid)) - - - -class SessionInitializer(xmlstream.BaseFeatureInitiatingInitializer): - """ - Initializer that implements session establishment for the initiating - entity. - - This protocol is defined in U{RFC 3921, section - 3<http://www.xmpp.org/specs/rfc3921.html#session>}. - """ - - feature = (NS_XMPP_SESSION, 'session') - - def start(self): - iq = xmlstream.IQ(self.xmlstream, 'set') - iq.addElement((NS_XMPP_SESSION, 'session')) - return iq.send() - - - -def XMPPClientFactory(jid, password): - """ - Client factory for XMPP 1.0 (only). - - This returns a L{xmlstream.XmlStreamFactory} with an L{XMPPAuthenticator} - object to perform the stream initialization steps (such as authentication). - - @see: The notes at L{XMPPAuthenticator} describe how the L{jid} and - L{password} parameters are to be used. - - @param jid: Jabber ID to connect with. - @type jid: L{jid.JID} - @param password: password to authenticate with. - @type password: C{unicode} - @return: XML stream factory. - @rtype: L{xmlstream.XmlStreamFactory} - """ - a = XMPPAuthenticator(jid, password) - return xmlstream.XmlStreamFactory(a) - - - -class XMPPAuthenticator(xmlstream.ConnectAuthenticator): - """ - Initializes an XmlStream connecting to an XMPP server as a Client. - - This authenticator performs the initialization steps needed to start - exchanging XML stanzas with an XMPP server as an XMPP client. It checks if - the server advertises XML stream version 1.0, negotiates TLS (when - available), performs SASL authentication, binds a resource and establishes - a session. - - Upon successful stream initialization, the L{xmlstream.STREAM_AUTHD_EVENT} - event will be dispatched through the XML stream object. Otherwise, the - L{xmlstream.INIT_FAILED_EVENT} event will be dispatched with a failure - object. - - After inspection of the failure, initialization can then be restarted by - calling L{initializeStream}. For example, in case of authentication - failure, a user may be given the opportunity to input the correct password. - By setting the L{password} instance variable and restarting initialization, - the stream authentication step is then retried, and subsequent steps are - performed if succesful. - - @ivar jid: Jabber ID to authenticate with. This may contain a resource - part, as a suggestion to the server for resource binding. A - server may override this, though. If the resource part is left - off, the server will generate a unique resource identifier. - The server will always return the full Jabber ID in the - resource binding step, and this is stored in this instance - variable. - @type jid: L{jid.JID} - @ivar password: password to be used during SASL authentication. - @type password: C{unicode} - """ - - namespace = 'jabber:client' - - def __init__(self, jid, password): - xmlstream.ConnectAuthenticator.__init__(self, jid.host) - self.jid = jid - self.password = password - - - def associateWithStream(self, xs): - """ - Register with the XML stream. - - Populates stream's list of initializers, along with their - requiredness. This list is used by - L{ConnectAuthenticator.initializeStream} to perform the initialization - steps. - """ - xmlstream.ConnectAuthenticator.associateWithStream(self, xs) - - xs.initializers = [CheckVersionInitializer(xs)] - inits = [ (xmlstream.TLSInitiatingInitializer, False), - (sasl.SASLInitiatingInitializer, True), - (BindInitializer, False), - (SessionInitializer, False), - ] - - for initClass, required in inits: - init = initClass(xs) - init.required = required - xs.initializers.append(init) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/component.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/component.py deleted file mode 100644 index 280ac7c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/component.py +++ /dev/null @@ -1,474 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabbercomponent -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -External server-side components. - -Most Jabber server implementations allow for add-on components that act as a -separate entity on the Jabber network, but use the server-to-server -functionality of a regular Jabber IM server. These so-called 'external -components' are connected to the Jabber server using the Jabber Component -Protocol as defined in U{JEP-0114<http://www.jabber.org/jeps/jep-0114.html>}. - -This module allows for writing external server-side component by assigning one -or more services implementing L{ijabber.IService} up to L{ServiceManager}. The -ServiceManager connects to the Jabber server and is responsible for the -corresponding XML stream. -""" - -from zope.interface import implements - -from twisted.application import service -from twisted.internet import defer -from twisted.python import log -from twisted.words.xish import domish -from twisted.words.protocols.jabber import error, ijabber, jstrports, xmlstream -from twisted.words.protocols.jabber.jid import internJID as JID - -NS_COMPONENT_ACCEPT = 'jabber:component:accept' - -def componentFactory(componentid, password): - """ - XML stream factory for external server-side components. - - @param componentid: JID of the component. - @type componentid: C{unicode} - @param password: password used to authenticate to the server. - @type password: C{str} - """ - a = ConnectComponentAuthenticator(componentid, password) - return xmlstream.XmlStreamFactory(a) - -class ComponentInitiatingInitializer(object): - """ - External server-side component authentication initializer for the - initiating entity. - - @ivar xmlstream: XML stream between server and component. - @type xmlstream: L{xmlstream.XmlStream} - """ - - def __init__(self, xs): - self.xmlstream = xs - self._deferred = None - - def initialize(self): - xs = self.xmlstream - hs = domish.Element((self.xmlstream.namespace, "handshake")) - hs.addContent(xmlstream.hashPassword(xs.sid, - unicode(xs.authenticator.password))) - - # Setup observer to watch for handshake result - xs.addOnetimeObserver("/handshake", self._cbHandshake) - xs.send(hs) - self._deferred = defer.Deferred() - return self._deferred - - def _cbHandshake(self, _): - # we have successfully shaken hands and can now consider this - # entity to represent the component JID. - self.xmlstream.thisEntity = self.xmlstream.otherEntity - self._deferred.callback(None) - - - -class ConnectComponentAuthenticator(xmlstream.ConnectAuthenticator): - """ - Authenticator to permit an XmlStream to authenticate against a Jabber - server as an external component (where the Authenticator is initiating the - stream). - """ - namespace = NS_COMPONENT_ACCEPT - - def __init__(self, componentjid, password): - """ - @type componentjid: C{str} - @param componentjid: Jabber ID that this component wishes to bind to. - - @type password: C{str} - @param password: Password/secret this component uses to authenticate. - """ - # Note that we are sending 'to' our desired component JID. - xmlstream.ConnectAuthenticator.__init__(self, componentjid) - self.password = password - - def associateWithStream(self, xs): - xs.version = (0, 0) - xmlstream.ConnectAuthenticator.associateWithStream(self, xs) - - xs.initializers = [ComponentInitiatingInitializer(xs)] - - - -class ListenComponentAuthenticator(xmlstream.ListenAuthenticator): - """ - Authenticator for accepting components. - - @since: 8.2 - @ivar secret: The shared secret used to authorized incoming component - connections. - @type secret: C{unicode}. - """ - - namespace = NS_COMPONENT_ACCEPT - - def __init__(self, secret): - self.secret = secret - xmlstream.ListenAuthenticator.__init__(self) - - - def associateWithStream(self, xs): - """ - Associate the authenticator with a stream. - - This sets the stream's version to 0.0, because the XEP-0114 component - protocol was not designed for XMPP 1.0. - """ - xs.version = (0, 0) - xmlstream.ListenAuthenticator.associateWithStream(self, xs) - - - def streamStarted(self, rootElement): - """ - Called by the stream when it has started. - - This examines the default namespace of the incoming stream and whether - there is a requested hostname for the component. Then it generates a - stream identifier, sends a response header and adds an observer for - the first incoming element, triggering L{onElement}. - """ - - xmlstream.ListenAuthenticator.streamStarted(self, rootElement) - - if rootElement.defaultUri != self.namespace: - exc = error.StreamError('invalid-namespace') - self.xmlstream.sendStreamError(exc) - return - - # self.xmlstream.thisEntity is set to the address the component - # wants to assume. - if not self.xmlstream.thisEntity: - exc = error.StreamError('improper-addressing') - self.xmlstream.sendStreamError(exc) - return - - self.xmlstream.sendHeader() - self.xmlstream.addOnetimeObserver('/*', self.onElement) - - - def onElement(self, element): - """ - Called on incoming XML Stanzas. - - The very first element received should be a request for handshake. - Otherwise, the stream is dropped with a 'not-authorized' error. If a - handshake request was received, the hash is extracted and passed to - L{onHandshake}. - """ - if (element.uri, element.name) == (self.namespace, 'handshake'): - self.onHandshake(unicode(element)) - else: - exc = error.StreamError('not-authorized') - self.xmlstream.sendStreamError(exc) - - - def onHandshake(self, handshake): - """ - Called upon receiving the handshake request. - - This checks that the given hash in C{handshake} is equal to a - calculated hash, responding with a handshake reply or a stream error. - If the handshake was ok, the stream is authorized, and XML Stanzas may - be exchanged. - """ - calculatedHash = xmlstream.hashPassword(self.xmlstream.sid, - unicode(self.secret)) - if handshake != calculatedHash: - exc = error.StreamError('not-authorized', text='Invalid hash') - self.xmlstream.sendStreamError(exc) - else: - self.xmlstream.send('<handshake/>') - self.xmlstream.dispatch(self.xmlstream, - xmlstream.STREAM_AUTHD_EVENT) - - - -class Service(service.Service): - """ - External server-side component service. - """ - - implements(ijabber.IService) - - def componentConnected(self, xs): - pass - - def componentDisconnected(self): - pass - - def transportConnected(self, xs): - pass - - def send(self, obj): - """ - Send data over service parent's XML stream. - - @note: L{ServiceManager} maintains a queue for data sent using this - method when there is no current established XML stream. This data is - then sent as soon as a new stream has been established and initialized. - Subsequently, L{componentConnected} will be called again. If this - queueing is not desired, use C{send} on the XmlStream object (passed to - L{componentConnected}) directly. - - @param obj: data to be sent over the XML stream. This is usually an - object providing L{domish.IElement}, or serialized XML. See - L{xmlstream.XmlStream} for details. - """ - - self.parent.send(obj) - -class ServiceManager(service.MultiService): - """ - Business logic representing a managed component connection to a Jabber - router. - - This service maintains a single connection to a Jabber router and provides - facilities for packet routing and transmission. Business logic modules are - services implementing L{ijabber.IService} (like subclasses of L{Service}), and - added as sub-service. - """ - - def __init__(self, jid, password): - service.MultiService.__init__(self) - - # Setup defaults - self.jabberId = jid - self.xmlstream = None - - # Internal buffer of packets - self._packetQueue = [] - - # Setup the xmlstream factory - self._xsFactory = componentFactory(self.jabberId, password) - - # Register some lambda functions to keep the self.xmlstream var up to - # date - self._xsFactory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, - self._connected) - self._xsFactory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self._authd) - self._xsFactory.addBootstrap(xmlstream.STREAM_END_EVENT, - self._disconnected) - - # Map addBootstrap and removeBootstrap to the underlying factory -- is - # this right? I have no clue...but it'll work for now, until i can - # think about it more. - self.addBootstrap = self._xsFactory.addBootstrap - self.removeBootstrap = self._xsFactory.removeBootstrap - - def getFactory(self): - return self._xsFactory - - def _connected(self, xs): - self.xmlstream = xs - for c in self: - if ijabber.IService.providedBy(c): - c.transportConnected(xs) - - def _authd(self, xs): - # Flush all pending packets - for p in self._packetQueue: - self.xmlstream.send(p) - self._packetQueue = [] - - # Notify all child services which implement the IService interface - for c in self: - if ijabber.IService.providedBy(c): - c.componentConnected(xs) - - def _disconnected(self, _): - self.xmlstream = None - - # Notify all child services which implement - # the IService interface - for c in self: - if ijabber.IService.providedBy(c): - c.componentDisconnected() - - def send(self, obj): - """ - Send data over the XML stream. - - When there is no established XML stream, the data is queued and sent - out when a new XML stream has been established and initialized. - - @param obj: data to be sent over the XML stream. This is usually an - object providing L{domish.IElement}, or serialized XML. See - L{xmlstream.XmlStream} for details. - """ - - if self.xmlstream != None: - self.xmlstream.send(obj) - else: - self._packetQueue.append(obj) - -def buildServiceManager(jid, password, strport): - """ - Constructs a pre-built L{ServiceManager}, using the specified strport - string. - """ - - svc = ServiceManager(jid, password) - client_svc = jstrports.client(strport, svc.getFactory()) - client_svc.setServiceParent(svc) - return svc - - - -class Router(object): - """ - XMPP Server's Router. - - A router connects the different components of the XMPP service and routes - messages between them based on the given routing table. - - Connected components are trusted to have correct addressing in the - stanzas they offer for routing. - - A route destination of C{None} adds a default route. Traffic for which no - specific route exists, will be routed to this default route. - - @since: 8.2 - @ivar routes: Routes based on the host part of JIDs. Maps host names to the - L{EventDispatcher<utility.EventDispatcher>}s that should - receive the traffic. A key of C{None} means the default - route. - @type routes: C{dict} - """ - - def __init__(self): - self.routes = {} - - - def addRoute(self, destination, xs): - """ - Add a new route. - - The passed XML Stream C{xs} will have an observer for all stanzas - added to route its outgoing traffic. In turn, traffic for - C{destination} will be passed to this stream. - - @param destination: Destination of the route to be added as a host name - or C{None} for the default route. - @type destination: C{str} or C{NoneType}. - @param xs: XML Stream to register the route for. - @type xs: L{EventDispatcher<utility.EventDispatcher>}. - """ - self.routes[destination] = xs - xs.addObserver('/*', self.route) - - - def removeRoute(self, destination, xs): - """ - Remove a route. - - @param destination: Destination of the route that should be removed. - @type destination: C{str}. - @param xs: XML Stream to remove the route for. - @type xs: L{EventDispatcher<utility.EventDispatcher>}. - """ - xs.removeObserver('/*', self.route) - if (xs == self.routes[destination]): - del self.routes[destination] - - - def route(self, stanza): - """ - Route a stanza. - - @param stanza: The stanza to be routed. - @type stanza: L{domish.Element}. - """ - destination = JID(stanza['to']) - - log.msg("Routing to %s: %r" % (destination.full(), stanza.toXml())) - - if destination.host in self.routes: - self.routes[destination.host].send(stanza) - else: - self.routes[None].send(stanza) - - - -class XMPPComponentServerFactory(xmlstream.XmlStreamServerFactory): - """ - XMPP Component Server factory. - - This factory accepts XMPP external component connections and makes - the router service route traffic for a component's bound domain - to that component. - - @since: 8.2 - """ - - logTraffic = False - - def __init__(self, router, secret='secret'): - self.router = router - self.secret = secret - - def authenticatorFactory(): - return ListenComponentAuthenticator(self.secret) - - xmlstream.XmlStreamServerFactory.__init__(self, authenticatorFactory) - self.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, - self.onConnectionMade) - self.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, - self.onAuthenticated) - - self.serial = 0 - - - def onConnectionMade(self, xs): - """ - Called when a component connection was made. - - This enables traffic debugging on incoming streams. - """ - xs.serial = self.serial - self.serial += 1 - - def logDataIn(buf): - log.msg("RECV (%d): %r" % (xs.serial, buf)) - - def logDataOut(buf): - log.msg("SEND (%d): %r" % (xs.serial, buf)) - - if self.logTraffic: - xs.rawDataInFn = logDataIn - xs.rawDataOutFn = logDataOut - - xs.addObserver(xmlstream.STREAM_ERROR_EVENT, self.onError) - - - def onAuthenticated(self, xs): - """ - Called when a component has succesfully authenticated. - - Add the component to the routing table and establish a handler - for a closed connection. - """ - destination = xs.thisEntity.host - - self.router.addRoute(destination, xs) - xs.addObserver(xmlstream.STREAM_END_EVENT, self.onConnectionLost, 0, - destination, xs) - - - def onError(self, reason): - log.err(reason, "Stream Error") - - - def onConnectionLost(self, destination, xs, reason): - self.router.removeRoute(destination, xs) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/error.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/error.py deleted file mode 100644 index aa5e9d2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/error.py +++ /dev/null @@ -1,336 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabbererror -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XMPP Error support. -""" - -import copy - -from twisted.words.xish import domish - -NS_XML = "http://www.w3.org/XML/1998/namespace" -NS_XMPP_STREAMS = "urn:ietf:params:xml:ns:xmpp-streams" -NS_XMPP_STANZAS = "urn:ietf:params:xml:ns:xmpp-stanzas" - -STANZA_CONDITIONS = { - 'bad-request': {'code': '400', 'type': 'modify'}, - 'conflict': {'code': '409', 'type': 'cancel'}, - 'feature-not-implemented': {'code': '501', 'type': 'cancel'}, - 'forbidden': {'code': '403', 'type': 'auth'}, - 'gone': {'code': '302', 'type': 'modify'}, - 'internal-server-error': {'code': '500', 'type': 'wait'}, - 'item-not-found': {'code': '404', 'type': 'cancel'}, - 'jid-malformed': {'code': '400', 'type': 'modify'}, - 'not-acceptable': {'code': '406', 'type': 'modify'}, - 'not-allowed': {'code': '405', 'type': 'cancel'}, - 'not-authorized': {'code': '401', 'type': 'auth'}, - 'payment-required': {'code': '402', 'type': 'auth'}, - 'recipient-unavailable': {'code': '404', 'type': 'wait'}, - 'redirect': {'code': '302', 'type': 'modify'}, - 'registration-required': {'code': '407', 'type': 'auth'}, - 'remote-server-not-found': {'code': '404', 'type': 'cancel'}, - 'remote-server-timeout': {'code': '504', 'type': 'wait'}, - 'resource-constraint': {'code': '500', 'type': 'wait'}, - 'service-unavailable': {'code': '503', 'type': 'cancel'}, - 'subscription-required': {'code': '407', 'type': 'auth'}, - 'undefined-condition': {'code': '500', 'type': None}, - 'unexpected-request': {'code': '400', 'type': 'wait'}, -} - -CODES_TO_CONDITIONS = { - '302': ('gone', 'modify'), - '400': ('bad-request', 'modify'), - '401': ('not-authorized', 'auth'), - '402': ('payment-required', 'auth'), - '403': ('forbidden', 'auth'), - '404': ('item-not-found', 'cancel'), - '405': ('not-allowed', 'cancel'), - '406': ('not-acceptable', 'modify'), - '407': ('registration-required', 'auth'), - '408': ('remote-server-timeout', 'wait'), - '409': ('conflict', 'cancel'), - '500': ('internal-server-error', 'wait'), - '501': ('feature-not-implemented', 'cancel'), - '502': ('service-unavailable', 'wait'), - '503': ('service-unavailable', 'cancel'), - '504': ('remote-server-timeout', 'wait'), - '510': ('service-unavailable', 'cancel'), -} - -class BaseError(Exception): - """ - Base class for XMPP error exceptions. - - @cvar namespace: The namespace of the C{error} element generated by - C{getElement}. - @type namespace: C{str} - @ivar condition: The error condition. The valid values are defined by - subclasses of L{BaseError}. - @type contition: C{str} - @ivar text: Optional text message to supplement the condition or application - specific condition. - @type text: C{unicode} - @ivar textLang: Identifier of the language used for the message in C{text}. - Values are as described in RFC 3066. - @type textLang: C{str} - @ivar appCondition: Application specific condition element, supplementing - the error condition in C{condition}. - @type appCondition: object providing L{domish.IElement}. - """ - - namespace = None - - def __init__(self, condition, text=None, textLang=None, appCondition=None): - Exception.__init__(self) - self.condition = condition - self.text = text - self.textLang = textLang - self.appCondition = appCondition - - - def __str__(self): - message = "%s with condition %r" % (self.__class__.__name__, - self.condition) - - if self.text: - message += ': ' + self.text - - return message - - - def getElement(self): - """ - Get XML representation from self. - - The method creates an L{domish} representation of the - error data contained in this exception. - - @rtype: L{domish.Element} - """ - error = domish.Element((None, 'error')) - error.addElement((self.namespace, self.condition)) - if self.text: - text = error.addElement((self.namespace, 'text'), - content=self.text) - if self.textLang: - text[(NS_XML, 'lang')] = self.textLang - if self.appCondition: - error.addChild(self.appCondition) - return error - - - -class StreamError(BaseError): - """ - Stream Error exception. - - Refer to RFC 3920, section 4.7.3, for the allowed values for C{condition}. - """ - - namespace = NS_XMPP_STREAMS - - def getElement(self): - """ - Get XML representation from self. - - Overrides the base L{BaseError.getElement} to make sure the returned - element is in the XML Stream namespace. - - @rtype: L{domish.Element} - """ - from twisted.words.protocols.jabber.xmlstream import NS_STREAMS - - error = BaseError.getElement(self) - error.uri = NS_STREAMS - return error - - - -class StanzaError(BaseError): - """ - Stanza Error exception. - - Refer to RFC 3920, section 9.3, for the allowed values for C{condition} and - C{type}. - - @ivar type: The stanza error type. Gives a suggestion to the recipient - of the error on how to proceed. - @type type: C{str} - @ivar code: A numeric identifier for the error condition for backwards - compatibility with pre-XMPP Jabber implementations. - """ - - namespace = NS_XMPP_STANZAS - - def __init__(self, condition, type=None, text=None, textLang=None, - appCondition=None): - BaseError.__init__(self, condition, text, textLang, appCondition) - - if type is None: - try: - type = STANZA_CONDITIONS[condition]['type'] - except KeyError: - pass - self.type = type - - try: - self.code = STANZA_CONDITIONS[condition]['code'] - except KeyError: - self.code = None - - self.children = [] - self.iq = None - - - def getElement(self): - """ - Get XML representation from self. - - Overrides the base L{BaseError.getElement} to make sure the returned - element has a C{type} attribute and optionally a legacy C{code} - attribute. - - @rtype: L{domish.Element} - """ - error = BaseError.getElement(self) - error['type'] = self.type - if self.code: - error['code'] = self.code - return error - - - def toResponse(self, stanza): - """ - Construct error response stanza. - - The C{stanza} is transformed into an error response stanza by - swapping the C{to} and C{from} addresses and inserting an error - element. - - @note: This creates a shallow copy of the list of child elements of the - stanza. The child elements themselves are not copied themselves, - and references to their parent element will still point to the - original stanza element. - - The serialization of an element does not use the reference to - its parent, so the typical use case of immediately sending out - the constructed error response is not affected. - - @param stanza: the stanza to respond to - @type stanza: L{domish.Element} - """ - from twisted.words.protocols.jabber.xmlstream import toResponse - response = toResponse(stanza, stanzaType='error') - response.children = copy.copy(stanza.children) - response.addChild(self.getElement()) - return response - - -def _getText(element): - for child in element.children: - if isinstance(child, basestring): - return unicode(child) - - return None - - - -def _parseError(error, errorNamespace): - """ - Parses an error element. - - @param error: The error element to be parsed - @type error: L{domish.Element} - @param errorNamespace: The namespace of the elements that hold the error - condition and text. - @type errorNamespace: C{str} - @return: Dictionary with extracted error information. If present, keys - C{condition}, C{text}, C{textLang} have a string value, - and C{appCondition} has an L{domish.Element} value. - @rtype: C{dict} - """ - condition = None - text = None - textLang = None - appCondition = None - - for element in error.elements(): - if element.uri == errorNamespace: - if element.name == 'text': - text = _getText(element) - textLang = element.getAttribute((NS_XML, 'lang')) - else: - condition = element.name - else: - appCondition = element - - return { - 'condition': condition, - 'text': text, - 'textLang': textLang, - 'appCondition': appCondition, - } - - - -def exceptionFromStreamError(element): - """ - Build an exception object from a stream error. - - @param element: the stream error - @type element: L{domish.Element} - @return: the generated exception object - @rtype: L{StreamError} - """ - error = _parseError(element, NS_XMPP_STREAMS) - - exception = StreamError(error['condition'], - error['text'], - error['textLang'], - error['appCondition']) - - return exception - - - -def exceptionFromStanza(stanza): - """ - Build an exception object from an error stanza. - - @param stanza: the error stanza - @type stanza: L{domish.Element} - @return: the generated exception object - @rtype: L{StanzaError} - """ - children = [] - condition = text = textLang = appCondition = type = code = None - - for element in stanza.elements(): - if element.name == 'error' and element.uri == stanza.uri: - code = element.getAttribute('code') - type = element.getAttribute('type') - error = _parseError(element, NS_XMPP_STANZAS) - condition = error['condition'] - text = error['text'] - textLang = error['textLang'] - appCondition = error['appCondition'] - - if not condition and code: - condition, type = CODES_TO_CONDITIONS[code] - text = _getText(stanza.error) - else: - children.append(element) - - if condition is None: - # TODO: raise exception instead? - return StanzaError(None) - - exception = StanzaError(condition, type, text, textLang, appCondition) - - exception.children = children - exception.stanza = stanza - - return exception diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/ijabber.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/ijabber.py deleted file mode 100644 index 9cc65ff..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/ijabber.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Public Jabber Interfaces. -""" - -from zope.interface import Attribute, Interface - -class IInitializer(Interface): - """ - Interface for XML stream initializers. - - Initializers perform a step in getting the XML stream ready to be - used for the exchange of XML stanzas. - """ - - - -class IInitiatingInitializer(IInitializer): - """ - Interface for XML stream initializers for the initiating entity. - """ - - xmlstream = Attribute("""The associated XML stream""") - - def initialize(): - """ - Initiate the initialization step. - - May return a deferred when the initialization is done asynchronously. - """ - - - -class IIQResponseTracker(Interface): - """ - IQ response tracker interface. - - The XMPP stanza C{iq} has a request-response nature that fits - naturally with deferreds. You send out a request and when the response - comes back a deferred is fired. - - The L{IQ} class implements a C{send} method that returns a deferred. This - deferred is put in a dictionary that is kept in an L{XmlStream} object, - keyed by the request stanzas C{id} attribute. - - An object providing this interface (usually an instance of L{XmlStream}), - keeps the said dictionary and sets observers on the iq stanzas of type - C{result} and C{error} and lets the callback fire the associated deferred. - """ - iqDeferreds = Attribute("Dictionary of deferreds waiting for an iq " - "response") - - - -class IXMPPHandler(Interface): - """ - Interface for XMPP protocol handlers. - - Objects that provide this interface can be added to a stream manager to - handle of (part of) an XMPP extension protocol. - """ - - parent = Attribute("""XML stream manager for this handler""") - xmlstream = Attribute("""The managed XML stream""") - - def setHandlerParent(parent): - """ - Set the parent of the handler. - - @type parent: L{IXMPPHandlerCollection} - """ - - - def disownHandlerParent(parent): - """ - Remove the parent of the handler. - - @type parent: L{IXMPPHandlerCollection} - """ - - - def makeConnection(xs): - """ - A connection over the underlying transport of the XML stream has been - established. - - At this point, no traffic has been exchanged over the XML stream - given in C{xs}. - - This should setup L{xmlstream} and call L{connectionMade}. - - @type xs: L{XmlStream<twisted.words.protocols.jabber.XmlStream>} - """ - - - def connectionMade(): - """ - Called after a connection has been established. - - This method can be used to change properties of the XML Stream, its - authenticator or the stream manager prior to stream initialization - (including authentication). - """ - - - def connectionInitialized(): - """ - The XML stream has been initialized. - - At this point, authentication was successful, and XML stanzas can be - exchanged over the XML stream L{xmlstream}. This method can be - used to setup observers for incoming stanzas. - """ - - - def connectionLost(reason): - """ - The XML stream has been closed. - - Subsequent use of C{parent.send} will result in data being queued - until a new connection has been established. - - @type reason: L{twisted.python.failure.Failure} - """ - - - -class IXMPPHandlerCollection(Interface): - """ - Collection of handlers. - - Contain several handlers and manage their connection. - """ - - def __iter__(): - """ - Get an iterator over all child handlers. - """ - - - def addHandler(handler): - """ - Add a child handler. - - @type handler: L{IXMPPHandler} - """ - - - def removeHandler(handler): - """ - Remove a child handler. - - @type handler: L{IXMPPHandler} - """ - - - -class IService(Interface): - """ - External server-side component service interface. - - Services that provide this interface can be added to L{ServiceManager} to - implement (part of) the functionality of the server-side component. - """ - - def componentConnected(xs): - """ - Parent component has established a connection. - - At this point, authentication was succesful, and XML stanzas - can be exchanged over the XML stream C{xs}. This method can be used - to setup observers for incoming stanzas. - - @param xs: XML Stream that represents the established connection. - @type xs: L{xmlstream.XmlStream} - """ - - - def componentDisconnected(): - """ - Parent component has lost the connection to the Jabber server. - - Subsequent use of C{self.parent.send} will result in data being - queued until a new connection has been established. - """ - - - def transportConnected(xs): - """ - Parent component has established a connection over the underlying - transport. - - At this point, no traffic has been exchanged over the XML stream. This - method can be used to change properties of the XML Stream (in C{xs}), - the service manager or it's authenticator prior to stream - initialization (including authentication). - """ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/jid.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/jid.py deleted file mode 100644 index 9911cee..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/jid.py +++ /dev/null @@ -1,249 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberjid -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Jabber Identifier support. - -This module provides an object to represent Jabber Identifiers (JIDs) and -parse string representations into them with proper checking for illegal -characters, case folding and canonicalisation through L{stringprep<twisted.words.protocols.jabber.xmpp_stringprep>}. -""" - -from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep, resourceprep, nameprep - -class InvalidFormat(Exception): - """ - The given string could not be parsed into a valid Jabber Identifier (JID). - """ - -def parse(jidstring): - """ - Parse given JID string into its respective parts and apply stringprep. - - @param jidstring: string representation of a JID. - @type jidstring: C{unicode} - @return: tuple of (user, host, resource), each of type C{unicode} as - the parsed and stringprep'd parts of the given JID. If the - given string did not have a user or resource part, the respective - field in the tuple will hold C{None}. - @rtype: C{tuple} - """ - user = None - host = None - resource = None - - # Search for delimiters - user_sep = jidstring.find("@") - res_sep = jidstring.find("/") - - if user_sep == -1: - if res_sep == -1: - # host - host = jidstring - else: - # host/resource - host = jidstring[0:res_sep] - resource = jidstring[res_sep + 1:] or None - else: - if res_sep == -1: - # user@host - user = jidstring[0:user_sep] or None - host = jidstring[user_sep + 1:] - else: - if user_sep < res_sep: - # user@host/resource - user = jidstring[0:user_sep] or None - host = jidstring[user_sep + 1:user_sep + (res_sep - user_sep)] - resource = jidstring[res_sep + 1:] or None - else: - # host/resource (with an @ in resource) - host = jidstring[0:res_sep] - resource = jidstring[res_sep + 1:] or None - - return prep(user, host, resource) - -def prep(user, host, resource): - """ - Perform stringprep on all JID fragments. - - @param user: The user part of the JID. - @type user: C{unicode} - @param host: The host part of the JID. - @type host: C{unicode} - @param resource: The resource part of the JID. - @type resource: C{unicode} - @return: The given parts with stringprep applied. - @rtype: C{tuple} - """ - - if user: - try: - user = nodeprep.prepare(unicode(user)) - except UnicodeError: - raise InvalidFormat, "Invalid character in username" - else: - user = None - - if not host: - raise InvalidFormat, "Server address required." - else: - try: - host = nameprep.prepare(unicode(host)) - except UnicodeError: - raise InvalidFormat, "Invalid character in hostname" - - if resource: - try: - resource = resourceprep.prepare(unicode(resource)) - except UnicodeError: - raise InvalidFormat, "Invalid character in resource" - else: - resource = None - - return (user, host, resource) - -__internJIDs = {} - -def internJID(jidstring): - """ - Return interned JID. - - @rtype: L{JID} - """ - - if jidstring in __internJIDs: - return __internJIDs[jidstring] - else: - j = JID(jidstring) - __internJIDs[jidstring] = j - return j - -class JID(object): - """ - Represents a stringprep'd Jabber ID. - - JID objects are hashable so they can be used in sets and as keys in - dictionaries. - """ - - def __init__(self, str=None, tuple=None): - if not (str or tuple): - raise RuntimeError("You must provide a value for either 'str' or " - "'tuple' arguments.") - - if str: - user, host, res = parse(str) - else: - user, host, res = prep(*tuple) - - self.user = user - self.host = host - self.resource = res - - def userhost(self): - """ - Extract the bare JID as a unicode string. - - A bare JID does not have a resource part, so this returns either - C{user@host} or just C{host}. - - @rtype: C{unicode} - """ - if self.user: - return u"%s@%s" % (self.user, self.host) - else: - return self.host - - def userhostJID(self): - """ - Extract the bare JID. - - A bare JID does not have a resource part, so this returns a - L{JID} object representing either C{user@host} or just C{host}. - - If the object this method is called upon doesn't have a resource - set, it will return itself. Otherwise, the bare JID object will - be created, interned using L{internJID}. - - @rtype: L{JID} - """ - if self.resource: - return internJID(self.userhost()) - else: - return self - - def full(self): - """ - Return the string representation of this JID. - - @rtype: C{unicode} - """ - if self.user: - if self.resource: - return u"%s@%s/%s" % (self.user, self.host, self.resource) - else: - return u"%s@%s" % (self.user, self.host) - else: - if self.resource: - return u"%s/%s" % (self.host, self.resource) - else: - return self.host - - def __eq__(self, other): - """ - Equality comparison. - - L{JID}s compare equal if their user, host and resource parts all - compare equal. When comparing against instances of other types, it - uses the default comparison. - """ - if isinstance(other, JID): - return (self.user == other.user and - self.host == other.host and - self.resource == other.resource) - else: - return NotImplemented - - def __ne__(self, other): - """ - Inequality comparison. - - This negates L{__eq__} for comparison with JIDs and uses the default - comparison for other types. - """ - result = self.__eq__(other) - if result is NotImplemented: - return result - else: - return not result - - def __hash__(self): - """ - Calculate hash. - - L{JID}s with identical constituent user, host and resource parts have - equal hash values. In combination with the comparison defined on JIDs, - this allows for using L{JID}s in sets and as dictionary keys. - """ - return hash((self.user, self.host, self.resource)) - - def __unicode__(self): - """ - Get unicode representation. - - Return the string representation of this JID as a unicode string. - @see: L{full} - """ - - return self.full() - - def __repr__(self): - """ - Get object representation. - - Returns a string that would create a new JID object that compares equal - to this one. - """ - return 'JID(%r)' % self.full() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/jstrports.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/jstrports.py deleted file mode 100644 index 773b6d2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/jstrports.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" A temporary placeholder for client-capable strports, until we -sufficient use cases get identified """ - -from twisted.internet.endpoints import _parse - -def _parseTCPSSL(factory, domain, port): - """ For the moment, parse TCP or SSL connections the same """ - return (domain, int(port), factory), {} - -def _parseUNIX(factory, address): - return (address, factory), {} - - -_funcs = { "tcp" : _parseTCPSSL, - "unix" : _parseUNIX, - "ssl" : _parseTCPSSL } - - -def parse(description, factory): - args, kw = _parse(description) - return (args[0].upper(),) + _funcs[args[0]](factory, *args[1:], **kw) - -def client(description, factory): - from twisted.application import internet - name, args, kw = parse(description, factory) - return getattr(internet, name + 'Client')(*args, **kw) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/sasl.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/sasl.py deleted file mode 100644 index 0ea201d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/sasl.py +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XMPP-specific SASL profile. -""" - -from base64 import b64decode, b64encode -import re -from twisted.internet import defer -from twisted.words.protocols.jabber import sasl_mechanisms, xmlstream -from twisted.words.xish import domish - -NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl' - -def get_mechanisms(xs): - """ - Parse the SASL feature to extract the available mechanism names. - """ - mechanisms = [] - for element in xs.features[(NS_XMPP_SASL, 'mechanisms')].elements(): - if element.name == 'mechanism': - mechanisms.append(str(element)) - - return mechanisms - - -class SASLError(Exception): - """ - SASL base exception. - """ - - -class SASLNoAcceptableMechanism(SASLError): - """ - The server did not present an acceptable SASL mechanism. - """ - - -class SASLAuthError(SASLError): - """ - SASL Authentication failed. - """ - def __init__(self, condition=None): - self.condition = condition - - - def __str__(self): - return "SASLAuthError with condition %r" % self.condition - - -class SASLIncorrectEncodingError(SASLError): - """ - SASL base64 encoding was incorrect. - - RFC 3920 specifies that any characters not in the base64 alphabet - and padding characters present elsewhere than at the end of the string - MUST be rejected. See also L{fromBase64}. - - This exception is raised whenever the encoded string does not adhere - to these additional restrictions or when the decoding itself fails. - - The recommended behaviour for so-called receiving entities (like servers in - client-to-server connections, see RFC 3920 for terminology) is to fail the - SASL negotiation with a C{'incorrect-encoding'} condition. For initiating - entities, one should assume the receiving entity to be either buggy or - malevolent. The stream should be terminated and reconnecting is not - advised. - """ - -base64Pattern = re.compile("^[0-9A-Za-z+/]*[0-9A-Za-z+/=]{,2}$") - -def fromBase64(s): - """ - Decode base64 encoded string. - - This helper performs regular decoding of a base64 encoded string, but also - rejects any characters that are not in the base64 alphabet and padding - occurring elsewhere from the last or last two characters, as specified in - section 14.9 of RFC 3920. This safeguards against various attack vectors - among which the creation of a covert channel that "leaks" information. - """ - - if base64Pattern.match(s) is None: - raise SASLIncorrectEncodingError() - - try: - return b64decode(s) - except Exception, e: - raise SASLIncorrectEncodingError(str(e)) - - - -class SASLInitiatingInitializer(xmlstream.BaseFeatureInitiatingInitializer): - """ - Stream initializer that performs SASL authentication. - - The supported mechanisms by this initializer are C{DIGEST-MD5}, C{PLAIN} - and C{ANONYMOUS}. The C{ANONYMOUS} SASL mechanism is used when the JID, set - on the authenticator, does not have a localpart (username), requesting an - anonymous session where the username is generated by the server. - Otherwise, C{DIGEST-MD5} and C{PLAIN} are attempted, in that order. - """ - - feature = (NS_XMPP_SASL, 'mechanisms') - _deferred = None - - def setMechanism(self): - """ - Select and setup authentication mechanism. - - Uses the authenticator's C{jid} and C{password} attribute for the - authentication credentials. If no supported SASL mechanisms are - advertized by the receiving party, a failing deferred is returned with - a L{SASLNoAcceptableMechanism} exception. - """ - - jid = self.xmlstream.authenticator.jid - password = self.xmlstream.authenticator.password - - mechanisms = get_mechanisms(self.xmlstream) - if jid.user is not None: - if 'DIGEST-MD5' in mechanisms: - self.mechanism = sasl_mechanisms.DigestMD5('xmpp', jid.host, None, - jid.user, password) - elif 'PLAIN' in mechanisms: - self.mechanism = sasl_mechanisms.Plain(None, jid.user, password) - else: - raise SASLNoAcceptableMechanism() - else: - if 'ANONYMOUS' in mechanisms: - self.mechanism = sasl_mechanisms.Anonymous() - else: - raise SASLNoAcceptableMechanism() - - - def start(self): - """ - Start SASL authentication exchange. - """ - - self.setMechanism() - self._deferred = defer.Deferred() - self.xmlstream.addObserver('/challenge', self.onChallenge) - self.xmlstream.addOnetimeObserver('/success', self.onSuccess) - self.xmlstream.addOnetimeObserver('/failure', self.onFailure) - self.sendAuth(self.mechanism.getInitialResponse()) - return self._deferred - - - def sendAuth(self, data=None): - """ - Initiate authentication protocol exchange. - - If an initial client response is given in C{data}, it will be - sent along. - - @param data: initial client response. - @type data: C{str} or C{None}. - """ - - auth = domish.Element((NS_XMPP_SASL, 'auth')) - auth['mechanism'] = self.mechanism.name - if data is not None: - auth.addContent(b64encode(data) or '=') - self.xmlstream.send(auth) - - - def sendResponse(self, data=''): - """ - Send response to a challenge. - - @param data: client response. - @type data: C{str}. - """ - - response = domish.Element((NS_XMPP_SASL, 'response')) - if data: - response.addContent(b64encode(data)) - self.xmlstream.send(response) - - - def onChallenge(self, element): - """ - Parse challenge and send response from the mechanism. - - @param element: the challenge protocol element. - @type element: L{domish.Element}. - """ - - try: - challenge = fromBase64(str(element)) - except SASLIncorrectEncodingError: - self._deferred.errback() - else: - self.sendResponse(self.mechanism.getResponse(challenge)) - - - def onSuccess(self, success): - """ - Clean up observers, reset the XML stream and send a new header. - - @param success: the success protocol element. For now unused, but - could hold additional data. - @type success: L{domish.Element} - """ - - self.xmlstream.removeObserver('/challenge', self.onChallenge) - self.xmlstream.removeObserver('/failure', self.onFailure) - self.xmlstream.reset() - self.xmlstream.sendHeader() - self._deferred.callback(xmlstream.Reset) - - - def onFailure(self, failure): - """ - Clean up observers, parse the failure and errback the deferred. - - @param failure: the failure protocol element. Holds details on - the error condition. - @type failure: L{domish.Element} - """ - - self.xmlstream.removeObserver('/challenge', self.onChallenge) - self.xmlstream.removeObserver('/success', self.onSuccess) - try: - condition = failure.firstChildElement().name - except AttributeError: - condition = None - self._deferred.errback(SASLAuthError(condition)) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/sasl_mechanisms.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/sasl_mechanisms.py deleted file mode 100644 index a164316..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/sasl_mechanisms.py +++ /dev/null @@ -1,276 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabbersaslmechanisms -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Protocol agnostic implementations of SASL authentication mechanisms. -""" - -import binascii, random, time, os -from hashlib import md5 - -from zope.interface import Interface, Attribute, implements - - -class ISASLMechanism(Interface): - name = Attribute("""Common name for the SASL Mechanism.""") - - def getInitialResponse(): - """ - Get the initial client response, if defined for this mechanism. - - @return: initial client response string. - @rtype: C{str}. - """ - - - def getResponse(challenge): - """ - Get the response to a server challenge. - - @param challenge: server challenge. - @type challenge: C{str}. - @return: client response. - @rtype: C{str}. - """ - - - -class Anonymous(object): - """ - Implements the ANONYMOUS SASL authentication mechanism. - - This mechanism is defined in RFC 2245. - """ - implements(ISASLMechanism) - name = 'ANONYMOUS' - - def getInitialResponse(self): - return None - - - -class Plain(object): - """ - Implements the PLAIN SASL authentication mechanism. - - The PLAIN SASL authentication mechanism is defined in RFC 2595. - """ - implements(ISASLMechanism) - - name = 'PLAIN' - - def __init__(self, authzid, authcid, password): - self.authzid = authzid or '' - self.authcid = authcid or '' - self.password = password or '' - - - def getInitialResponse(self): - return "%s\x00%s\x00%s" % (self.authzid.encode('utf-8'), - self.authcid.encode('utf-8'), - self.password.encode('utf-8')) - - - -class DigestMD5(object): - """ - Implements the DIGEST-MD5 SASL authentication mechanism. - - The DIGEST-MD5 SASL authentication mechanism is defined in RFC 2831. - """ - implements(ISASLMechanism) - - name = 'DIGEST-MD5' - - def __init__(self, serv_type, host, serv_name, username, password): - """ - @param serv_type: An indication of what kind of server authentication - is being attempted against. For example, C{u"xmpp"}. - @type serv_type: C{unicode} - - @param host: The authentication hostname. Also known as the realm. - This is used as a scope to help select the right credentials. - @type host: C{unicode} - - @param serv_name: An additional identifier for the server. - @type serv_name: C{unicode} - - @param username: The authentication username to use to respond to a - challenge. - @type username: C{unicode} - - @param username: The authentication password to use to respond to a - challenge. - @type password: C{unicode} - """ - self.username = username - self.password = password - self.defaultRealm = host - - self.digest_uri = u'%s/%s' % (serv_type, host) - if serv_name is not None: - self.digest_uri += u'/%s' % (serv_name,) - - - def getInitialResponse(self): - return None - - - def getResponse(self, challenge): - directives = self._parse(challenge) - - # Compat for implementations that do not send this along with - # a succesful authentication. - if 'rspauth' in directives: - return '' - - try: - realm = directives['realm'] - except KeyError: - realm = self.defaultRealm.encode(directives['charset']) - - return self._genResponse(directives['charset'], - realm, - directives['nonce']) - - - def _parse(self, challenge): - """ - Parses the server challenge. - - Splits the challenge into a dictionary of directives with values. - - @return: challenge directives and their values. - @rtype: C{dict} of C{str} to C{str}. - """ - s = challenge - paramDict = {} - cur = 0 - remainingParams = True - while remainingParams: - # Parse a param. We can't just split on commas, because there can - # be some commas inside (quoted) param values, e.g.: - # qop="auth,auth-int" - - middle = s.index("=", cur) - name = s[cur:middle].lstrip() - middle += 1 - if s[middle] == '"': - middle += 1 - end = s.index('"', middle) - value = s[middle:end] - cur = s.find(',', end) + 1 - if cur == 0: - remainingParams = False - else: - end = s.find(',', middle) - if end == -1: - value = s[middle:].rstrip() - remainingParams = False - else: - value = s[middle:end].rstrip() - cur = end + 1 - paramDict[name] = value - - for param in ('qop', 'cipher'): - if param in paramDict: - paramDict[param] = paramDict[param].split(',') - - return paramDict - - def _unparse(self, directives): - """ - Create message string from directives. - - @param directives: dictionary of directives (names to their values). - For certain directives, extra quotes are added, as - needed. - @type directives: C{dict} of C{str} to C{str} - @return: message string. - @rtype: C{str}. - """ - - directive_list = [] - for name, value in directives.iteritems(): - if name in ('username', 'realm', 'cnonce', - 'nonce', 'digest-uri', 'authzid', 'cipher'): - directive = '%s="%s"' % (name, value) - else: - directive = '%s=%s' % (name, value) - - directive_list.append(directive) - - return ','.join(directive_list) - - - def _calculateResponse(self, cnonce, nc, nonce, - username, password, realm, uri): - """ - Calculates response with given encoded parameters. - - @return: The I{response} field of a response to a Digest-MD5 challenge - of the given parameters. - @rtype: L{bytes} - """ - def H(s): - return md5(s).digest() - - def HEX(n): - return binascii.b2a_hex(n) - - def KD(k, s): - return H('%s:%s' % (k, s)) - - a1 = "%s:%s:%s" % ( - H("%s:%s:%s" % (username, realm, password)), nonce, cnonce) - a2 = "AUTHENTICATE:%s" % (uri,) - - response = HEX(KD(HEX(H(a1)), "%s:%s:%s:%s:%s" % ( - nonce, nc, cnonce, "auth", HEX(H(a2))))) - return response - - - def _genResponse(self, charset, realm, nonce): - """ - Generate response-value. - - Creates a response to a challenge according to section 2.1.2.1 of - RFC 2831 using the C{charset}, C{realm} and C{nonce} directives - from the challenge. - """ - try: - username = self.username.encode(charset) - password = self.password.encode(charset) - digest_uri = self.digest_uri.encode(charset) - except UnicodeError: - # TODO - add error checking - raise - - nc = '%08x' % (1,) # TODO: support subsequent auth. - cnonce = self._gen_nonce() - qop = 'auth' - - # TODO - add support for authzid - response = self._calculateResponse(cnonce, nc, nonce, - username, password, realm, - digest_uri) - - directives = {'username': username, - 'realm' : realm, - 'nonce' : nonce, - 'cnonce' : cnonce, - 'nc' : nc, - 'qop' : qop, - 'digest-uri': digest_uri, - 'response': response, - 'charset': charset} - - return self._unparse(directives) - - - def _gen_nonce(self): - return md5("%s:%s:%s" % (random.random(), - time.gmtime(), - os.getpid())).hexdigest() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/xmlstream.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/xmlstream.py deleted file mode 100644 index e30508b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/xmlstream.py +++ /dev/null @@ -1,1136 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberxmlstream -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XMPP XML Streams - -Building blocks for setting up XML Streams, including helping classes for -doing authentication on either client or server side, and working with XML -Stanzas. -""" - -from hashlib import sha1 -from zope.interface import directlyProvides, implements - -from twisted.internet import defer, protocol -from twisted.internet.error import ConnectionLost -from twisted.python import failure, log, randbytes -from twisted.words.protocols.jabber import error, ijabber, jid -from twisted.words.xish import domish, xmlstream -from twisted.words.xish.xmlstream import STREAM_CONNECTED_EVENT -from twisted.words.xish.xmlstream import STREAM_START_EVENT -from twisted.words.xish.xmlstream import STREAM_END_EVENT -from twisted.words.xish.xmlstream import STREAM_ERROR_EVENT - -try: - from twisted.internet import ssl -except ImportError: - ssl = None -if ssl and not ssl.supported: - ssl = None - -STREAM_AUTHD_EVENT = intern("//event/stream/authd") -INIT_FAILED_EVENT = intern("//event/xmpp/initfailed") - -NS_STREAMS = 'http://etherx.jabber.org/streams' -NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls' - -Reset = object() - -def hashPassword(sid, password): - """ - Create a SHA1-digest string of a session identifier and password. - - @param sid: The stream session identifier. - @type sid: C{unicode}. - @param password: The password to be hashed. - @type password: C{unicode}. - """ - if not isinstance(sid, unicode): - raise TypeError("The session identifier must be a unicode object") - if not isinstance(password, unicode): - raise TypeError("The password must be a unicode object") - input = u"%s%s" % (sid, password) - return sha1(input.encode('utf-8')).hexdigest() - - - -class Authenticator: - """ - Base class for business logic of initializing an XmlStream - - Subclass this object to enable an XmlStream to initialize and authenticate - to different types of stream hosts (such as clients, components, etc.). - - Rules: - 1. The Authenticator MUST dispatch a L{STREAM_AUTHD_EVENT} when the - stream has been completely initialized. - 2. The Authenticator SHOULD reset all state information when - L{associateWithStream} is called. - 3. The Authenticator SHOULD override L{streamStarted}, and start - initialization there. - - @type xmlstream: L{XmlStream} - @ivar xmlstream: The XmlStream that needs authentication - - @note: the term authenticator is historical. Authenticators perform - all steps required to prepare the stream for the exchange - of XML stanzas. - """ - - def __init__(self): - self.xmlstream = None - - - def connectionMade(self): - """ - Called by the XmlStream when the underlying socket connection is - in place. - - This allows the Authenticator to send an initial root element, if it's - connecting, or wait for an inbound root from the peer if it's accepting - the connection. - - Subclasses can use self.xmlstream.send() to send any initial data to - the peer. - """ - - - def streamStarted(self, rootElement): - """ - Called by the XmlStream when the stream has started. - - A stream is considered to have started when the start tag of the root - element has been received. - - This examines C{rootElement} to see if there is a version attribute. - If absent, C{0.0} is assumed per RFC 3920. Subsequently, the - minimum of the version from the received stream header and the - value stored in L{xmlstream} is taken and put back in L{xmlstream}. - - Extensions of this method can extract more information from the - stream header and perform checks on them, optionally sending - stream errors and closing the stream. - """ - if rootElement.hasAttribute("version"): - version = rootElement["version"].split(".") - try: - version = (int(version[0]), int(version[1])) - except (IndexError, ValueError): - version = (0, 0) - else: - version = (0, 0) - - self.xmlstream.version = min(self.xmlstream.version, version) - - - def associateWithStream(self, xmlstream): - """ - Called by the XmlStreamFactory when a connection has been made - to the requested peer, and an XmlStream object has been - instantiated. - - The default implementation just saves a handle to the new - XmlStream. - - @type xmlstream: L{XmlStream} - @param xmlstream: The XmlStream that will be passing events to this - Authenticator. - - """ - self.xmlstream = xmlstream - - - -class ConnectAuthenticator(Authenticator): - """ - Authenticator for initiating entities. - """ - - namespace = None - - def __init__(self, otherHost): - self.otherHost = otherHost - - - def connectionMade(self): - self.xmlstream.namespace = self.namespace - self.xmlstream.otherEntity = jid.internJID(self.otherHost) - self.xmlstream.sendHeader() - - - def initializeStream(self): - """ - Perform stream initialization procedures. - - An L{XmlStream} holds a list of initializer objects in its - C{initializers} attribute. This method calls these initializers in - order and dispatches the C{STREAM_AUTHD_EVENT} event when the list has - been successfully processed. Otherwise it dispatches the - C{INIT_FAILED_EVENT} event with the failure. - - Initializers may return the special L{Reset} object to halt the - initialization processing. It signals that the current initializer was - successfully processed, but that the XML Stream has been reset. An - example is the TLSInitiatingInitializer. - """ - - def remove_first(result): - self.xmlstream.initializers.pop(0) - - return result - - def do_next(result): - """ - Take the first initializer and process it. - - On success, the initializer is removed from the list and - then next initializer will be tried. - """ - - if result is Reset: - return None - - try: - init = self.xmlstream.initializers[0] - except IndexError: - self.xmlstream.dispatch(self.xmlstream, STREAM_AUTHD_EVENT) - return None - else: - d = defer.maybeDeferred(init.initialize) - d.addCallback(remove_first) - d.addCallback(do_next) - return d - - d = defer.succeed(None) - d.addCallback(do_next) - d.addErrback(self.xmlstream.dispatch, INIT_FAILED_EVENT) - - - def streamStarted(self, rootElement): - """ - Called by the XmlStream when the stream has started. - - This extends L{Authenticator.streamStarted} to extract further stream - headers from C{rootElement}, optionally wait for stream features being - received and then call C{initializeStream}. - """ - - Authenticator.streamStarted(self, rootElement) - - self.xmlstream.sid = rootElement.getAttribute("id") - - if rootElement.hasAttribute("from"): - self.xmlstream.otherEntity = jid.internJID(rootElement["from"]) - - # Setup observer for stream features, if applicable - if self.xmlstream.version >= (1, 0): - def onFeatures(element): - features = {} - for feature in element.elements(): - features[(feature.uri, feature.name)] = feature - - self.xmlstream.features = features - self.initializeStream() - - self.xmlstream.addOnetimeObserver('/features[@xmlns="%s"]' % - NS_STREAMS, - onFeatures) - else: - self.initializeStream() - - - -class ListenAuthenticator(Authenticator): - """ - Authenticator for receiving entities. - """ - - namespace = None - - def associateWithStream(self, xmlstream): - """ - Called by the XmlStreamFactory when a connection has been made. - - Extend L{Authenticator.associateWithStream} to set the L{XmlStream} - to be non-initiating. - """ - Authenticator.associateWithStream(self, xmlstream) - self.xmlstream.initiating = False - - - def streamStarted(self, rootElement): - """ - Called by the XmlStream when the stream has started. - - This extends L{Authenticator.streamStarted} to extract further - information from the stream headers from C{rootElement}. - """ - Authenticator.streamStarted(self, rootElement) - - self.xmlstream.namespace = rootElement.defaultUri - - if rootElement.hasAttribute("to"): - self.xmlstream.thisEntity = jid.internJID(rootElement["to"]) - - self.xmlstream.prefixes = {} - for prefix, uri in rootElement.localPrefixes.iteritems(): - self.xmlstream.prefixes[uri] = prefix - - self.xmlstream.sid = unicode(randbytes.secureRandom(8).encode('hex')) - - - -class FeatureNotAdvertized(Exception): - """ - Exception indicating a stream feature was not advertized, while required by - the initiating entity. - """ - - - -class BaseFeatureInitiatingInitializer(object): - """ - Base class for initializers with a stream feature. - - This assumes the associated XmlStream represents the initiating entity - of the connection. - - @cvar feature: tuple of (uri, name) of the stream feature root element. - @type feature: tuple of (C{str}, C{str}) - @ivar required: whether the stream feature is required to be advertized - by the receiving entity. - @type required: C{bool} - """ - - implements(ijabber.IInitiatingInitializer) - - feature = None - required = False - - def __init__(self, xs): - self.xmlstream = xs - - - def initialize(self): - """ - Initiate the initialization. - - Checks if the receiving entity advertizes the stream feature. If it - does, the initialization is started. If it is not advertized, and the - C{required} instance variable is C{True}, it raises - L{FeatureNotAdvertized}. Otherwise, the initialization silently - succeeds. - """ - - if self.feature in self.xmlstream.features: - return self.start() - elif self.required: - raise FeatureNotAdvertized - else: - return None - - - def start(self): - """ - Start the actual initialization. - - May return a deferred for asynchronous initialization. - """ - - - -class TLSError(Exception): - """ - TLS base exception. - """ - - - -class TLSFailed(TLSError): - """ - Exception indicating failed TLS negotiation - """ - - - -class TLSRequired(TLSError): - """ - Exception indicating required TLS negotiation. - - This exception is raised when the receiving entity requires TLS - negotiation and the initiating does not desire to negotiate TLS. - """ - - - -class TLSNotSupported(TLSError): - """ - Exception indicating missing TLS support. - - This exception is raised when the initiating entity wants and requires to - negotiate TLS when the OpenSSL library is not available. - """ - - - -class TLSInitiatingInitializer(BaseFeatureInitiatingInitializer): - """ - TLS stream initializer for the initiating entity. - - It is strongly required to include this initializer in the list of - initializers for an XMPP stream. By default it will try to negotiate TLS. - An XMPP server may indicate that TLS is required. If TLS is not desired, - set the C{wanted} attribute to False instead of removing it from the list - of initializers, so a proper exception L{TLSRequired} can be raised. - - @cvar wanted: indicates if TLS negotiation is wanted. - @type wanted: C{bool} - """ - - feature = (NS_XMPP_TLS, 'starttls') - wanted = True - _deferred = None - - def onProceed(self, obj): - """ - Proceed with TLS negotiation and reset the XML stream. - """ - - self.xmlstream.removeObserver('/failure', self.onFailure) - ctx = ssl.CertificateOptions() - self.xmlstream.transport.startTLS(ctx) - self.xmlstream.reset() - self.xmlstream.sendHeader() - self._deferred.callback(Reset) - - - def onFailure(self, obj): - self.xmlstream.removeObserver('/proceed', self.onProceed) - self._deferred.errback(TLSFailed()) - - - def start(self): - """ - Start TLS negotiation. - - This checks if the receiving entity requires TLS, the SSL library is - available and uses the C{required} and C{wanted} instance variables to - determine what to do in the various different cases. - - For example, if the SSL library is not available, and wanted and - required by the user, it raises an exception. However if it is not - required by both parties, initialization silently succeeds, moving - on to the next step. - """ - if self.wanted: - if ssl is None: - if self.required: - return defer.fail(TLSNotSupported()) - else: - return defer.succeed(None) - else: - pass - elif self.xmlstream.features[self.feature].required: - return defer.fail(TLSRequired()) - else: - return defer.succeed(None) - - self._deferred = defer.Deferred() - self.xmlstream.addOnetimeObserver("/proceed", self.onProceed) - self.xmlstream.addOnetimeObserver("/failure", self.onFailure) - self.xmlstream.send(domish.Element((NS_XMPP_TLS, "starttls"))) - return self._deferred - - - -class XmlStream(xmlstream.XmlStream): - """ - XMPP XML Stream protocol handler. - - @ivar version: XML stream version as a tuple (major, minor). Initially, - this is set to the minimally supported version. Upon - receiving the stream header of the peer, it is set to the - minimum of that value and the version on the received - header. - @type version: (C{int}, C{int}) - @ivar namespace: default namespace URI for stream - @type namespace: C{unicode} - @ivar thisEntity: JID of this entity - @type thisEntity: L{JID} - @ivar otherEntity: JID of the peer entity - @type otherEntity: L{JID} - @ivar sid: session identifier - @type sid: C{unicode} - @ivar initiating: True if this is the initiating stream - @type initiating: C{bool} - @ivar features: map of (uri, name) to stream features element received from - the receiving entity. - @type features: C{dict} of (C{unicode}, C{unicode}) to L{domish.Element}. - @ivar prefixes: map of URI to prefixes that are to appear on stream - header. - @type prefixes: C{dict} of C{unicode} to C{unicode} - @ivar initializers: list of stream initializer objects - @type initializers: C{list} of objects that provide L{IInitializer} - @ivar authenticator: associated authenticator that uses C{initializers} to - initialize the XML stream. - """ - - version = (1, 0) - namespace = 'invalid' - thisEntity = None - otherEntity = None - sid = None - initiating = True - - _headerSent = False # True if the stream header has been sent - - def __init__(self, authenticator): - xmlstream.XmlStream.__init__(self) - - self.prefixes = {NS_STREAMS: 'stream'} - self.authenticator = authenticator - self.initializers = [] - self.features = {} - - # Reset the authenticator - authenticator.associateWithStream(self) - - - def _callLater(self, *args, **kwargs): - from twisted.internet import reactor - return reactor.callLater(*args, **kwargs) - - - def reset(self): - """ - Reset XML Stream. - - Resets the XML Parser for incoming data. This is to be used after - successfully negotiating a new layer, e.g. TLS and SASL. Note that - registered event observers will continue to be in place. - """ - self._headerSent = False - self._initializeStream() - - - def onStreamError(self, errelem): - """ - Called when a stream:error element has been received. - - Dispatches a L{STREAM_ERROR_EVENT} event with the error element to - allow for cleanup actions and drops the connection. - - @param errelem: The received error element. - @type errelem: L{domish.Element} - """ - self.dispatch(failure.Failure(error.exceptionFromStreamError(errelem)), - STREAM_ERROR_EVENT) - self.transport.loseConnection() - - - def sendHeader(self): - """ - Send stream header. - """ - # set up optional extra namespaces - localPrefixes = {} - for uri, prefix in self.prefixes.iteritems(): - if uri != NS_STREAMS: - localPrefixes[prefix] = uri - - rootElement = domish.Element((NS_STREAMS, 'stream'), self.namespace, - localPrefixes=localPrefixes) - - if self.otherEntity: - rootElement['to'] = self.otherEntity.userhost() - - if self.thisEntity: - rootElement['from'] = self.thisEntity.userhost() - - if not self.initiating and self.sid: - rootElement['id'] = self.sid - - if self.version >= (1, 0): - rootElement['version'] = "%d.%d" % self.version - - self.send(rootElement.toXml(prefixes=self.prefixes, closeElement=0)) - self._headerSent = True - - - def sendFooter(self): - """ - Send stream footer. - """ - self.send('</stream:stream>') - - - def sendStreamError(self, streamError): - """ - Send stream level error. - - If we are the receiving entity, and haven't sent the header yet, - we sent one first. - - After sending the stream error, the stream is closed and the transport - connection dropped. - - @param streamError: stream error instance - @type streamError: L{error.StreamError} - """ - if not self._headerSent and not self.initiating: - self.sendHeader() - - if self._headerSent: - self.send(streamError.getElement()) - self.sendFooter() - - self.transport.loseConnection() - - - def send(self, obj): - """ - Send data over the stream. - - This overrides L{xmlstream.Xmlstream.send} to use the default namespace - of the stream header when serializing L{domish.IElement}s. It is - assumed that if you pass an object that provides L{domish.IElement}, - it represents a direct child of the stream's root element. - """ - if domish.IElement.providedBy(obj): - obj = obj.toXml(prefixes=self.prefixes, - defaultUri=self.namespace, - prefixesInScope=self.prefixes.values()) - - xmlstream.XmlStream.send(self, obj) - - - def connectionMade(self): - """ - Called when a connection is made. - - Notifies the authenticator when a connection has been made. - """ - xmlstream.XmlStream.connectionMade(self) - self.authenticator.connectionMade() - - - def onDocumentStart(self, rootElement): - """ - Called when the stream header has been received. - - Extracts the header's C{id} and C{version} attributes from the root - element. The C{id} attribute is stored in our C{sid} attribute and the - C{version} attribute is parsed and the minimum of the version we sent - and the parsed C{version} attribute is stored as a tuple (major, minor) - in this class' C{version} attribute. If no C{version} attribute was - present, we assume version 0.0. - - If appropriate (we are the initiating stream and the minimum of our and - the other party's version is at least 1.0), a one-time observer is - registered for getting the stream features. The registered function is - C{onFeatures}. - - Ultimately, the authenticator's C{streamStarted} method will be called. - - @param rootElement: The root element. - @type rootElement: L{domish.Element} - """ - xmlstream.XmlStream.onDocumentStart(self, rootElement) - - # Setup observer for stream errors - self.addOnetimeObserver("/error[@xmlns='%s']" % NS_STREAMS, - self.onStreamError) - - self.authenticator.streamStarted(rootElement) - - - -class XmlStreamFactory(xmlstream.XmlStreamFactory): - """ - Factory for Jabber XmlStream objects as a reconnecting client. - - Note that this differs from L{xmlstream.XmlStreamFactory} in that - it generates Jabber specific L{XmlStream} instances that have - authenticators. - """ - - protocol = XmlStream - - def __init__(self, authenticator): - xmlstream.XmlStreamFactory.__init__(self, authenticator) - self.authenticator = authenticator - - - -class XmlStreamServerFactory(xmlstream.BootstrapMixin, - protocol.ServerFactory): - """ - Factory for Jabber XmlStream objects as a server. - - @since: 8.2. - @ivar authenticatorFactory: Factory callable that takes no arguments, to - create a fresh authenticator to be associated - with the XmlStream. - """ - - protocol = XmlStream - - def __init__(self, authenticatorFactory): - xmlstream.BootstrapMixin.__init__(self) - self.authenticatorFactory = authenticatorFactory - - - def buildProtocol(self, addr): - """ - Create an instance of XmlStream. - - A new authenticator instance will be created and passed to the new - XmlStream. Registered bootstrap event observers are installed as well. - """ - authenticator = self.authenticatorFactory() - xs = self.protocol(authenticator) - xs.factory = self - self.installBootstraps(xs) - return xs - - - -class TimeoutError(Exception): - """ - Exception raised when no IQ response has been received before the - configured timeout. - """ - - - -def upgradeWithIQResponseTracker(xs): - """ - Enhances an XmlStream for iq response tracking. - - This makes an L{XmlStream} object provide L{IIQResponseTracker}. When a - response is an error iq stanza, the deferred has its errback invoked with a - failure that holds a L{StanzaException<error.StanzaException>} that is - easier to examine. - """ - def callback(iq): - """ - Handle iq response by firing associated deferred. - """ - if getattr(iq, 'handled', False): - return - - try: - d = xs.iqDeferreds[iq["id"]] - except KeyError: - pass - else: - del xs.iqDeferreds[iq["id"]] - iq.handled = True - if iq['type'] == 'error': - d.errback(error.exceptionFromStanza(iq)) - else: - d.callback(iq) - - - def disconnected(_): - """ - Make sure deferreds do not linger on after disconnect. - - This errbacks all deferreds of iq's for which no response has been - received with a L{ConnectionLost} failure. Otherwise, the deferreds - will never be fired. - """ - iqDeferreds = xs.iqDeferreds - xs.iqDeferreds = {} - for d in iqDeferreds.itervalues(): - d.errback(ConnectionLost()) - - xs.iqDeferreds = {} - xs.iqDefaultTimeout = getattr(xs, 'iqDefaultTimeout', None) - xs.addObserver(xmlstream.STREAM_END_EVENT, disconnected) - xs.addObserver('/iq[@type="result"]', callback) - xs.addObserver('/iq[@type="error"]', callback) - directlyProvides(xs, ijabber.IIQResponseTracker) - - - -class IQ(domish.Element): - """ - Wrapper for an iq stanza. - - Iq stanzas are used for communications with a request-response behaviour. - Each iq request is associated with an XML stream and has its own unique id - to be able to track the response. - - @ivar timeout: if set, a timeout period after which the deferred returned - by C{send} will have its errback called with a - L{TimeoutError} failure. - @type timeout: C{float} - """ - - timeout = None - - def __init__(self, xmlstream, stanzaType="set"): - """ - @type xmlstream: L{xmlstream.XmlStream} - @param xmlstream: XmlStream to use for transmission of this IQ - - @type stanzaType: C{str} - @param stanzaType: IQ type identifier ('get' or 'set') - """ - domish.Element.__init__(self, (None, "iq")) - self.addUniqueId() - self["type"] = stanzaType - self._xmlstream = xmlstream - - - def send(self, to=None): - """ - Send out this iq. - - Returns a deferred that is fired when an iq response with the same id - is received. Result responses will be passed to the deferred callback. - Error responses will be transformed into a - L{StanzaError<error.StanzaError>} and result in the errback of the - deferred being invoked. - - @rtype: L{defer.Deferred} - """ - if to is not None: - self["to"] = to - - if not ijabber.IIQResponseTracker.providedBy(self._xmlstream): - upgradeWithIQResponseTracker(self._xmlstream) - - d = defer.Deferred() - self._xmlstream.iqDeferreds[self['id']] = d - - timeout = self.timeout or self._xmlstream.iqDefaultTimeout - if timeout is not None: - def onTimeout(): - del self._xmlstream.iqDeferreds[self['id']] - d.errback(TimeoutError("IQ timed out")) - - call = self._xmlstream._callLater(timeout, onTimeout) - - def cancelTimeout(result): - if call.active(): - call.cancel() - - return result - - d.addBoth(cancelTimeout) - - self._xmlstream.send(self) - return d - - - -def toResponse(stanza, stanzaType=None): - """ - Create a response stanza from another stanza. - - This takes the addressing and id attributes from a stanza to create a (new, - empty) response stanza. The addressing attributes are swapped and the id - copied. Optionally, the stanza type of the response can be specified. - - @param stanza: the original stanza - @type stanza: L{domish.Element} - @param stanzaType: optional response stanza type - @type stanzaType: C{str} - @return: the response stanza. - @rtype: L{domish.Element} - """ - - toAddr = stanza.getAttribute('from') - fromAddr = stanza.getAttribute('to') - stanzaID = stanza.getAttribute('id') - - response = domish.Element((None, stanza.name)) - if toAddr: - response['to'] = toAddr - if fromAddr: - response['from'] = fromAddr - if stanzaID: - response['id'] = stanzaID - if stanzaType: - response['type'] = stanzaType - - return response - - - -class XMPPHandler(object): - """ - XMPP protocol handler. - - Classes derived from this class implement (part of) one or more XMPP - extension protocols, and are referred to as a subprotocol implementation. - """ - - implements(ijabber.IXMPPHandler) - - def __init__(self): - self.parent = None - self.xmlstream = None - - - def setHandlerParent(self, parent): - self.parent = parent - self.parent.addHandler(self) - - - def disownHandlerParent(self, parent): - self.parent.removeHandler(self) - self.parent = None - - - def makeConnection(self, xs): - self.xmlstream = xs - self.connectionMade() - - - def connectionMade(self): - """ - Called after a connection has been established. - - Can be overridden to perform work before stream initialization. - """ - - - def connectionInitialized(self): - """ - The XML stream has been initialized. - - Can be overridden to perform work after stream initialization, e.g. to - set up observers and start exchanging XML stanzas. - """ - - - def connectionLost(self, reason): - """ - The XML stream has been closed. - - This method can be extended to inspect the C{reason} argument and - act on it. - """ - self.xmlstream = None - - - def send(self, obj): - """ - Send data over the managed XML stream. - - @note: The stream manager maintains a queue for data sent using this - method when there is no current initialized XML stream. This - data is then sent as soon as a new stream has been established - and initialized. Subsequently, L{connectionInitialized} will be - called again. If this queueing is not desired, use C{send} on - C{self.xmlstream}. - - @param obj: data to be sent over the XML stream. This is usually an - object providing L{domish.IElement}, or serialized XML. See - L{xmlstream.XmlStream} for details. - """ - self.parent.send(obj) - - - -class XMPPHandlerCollection(object): - """ - Collection of XMPP subprotocol handlers. - - This allows for grouping of subprotocol handlers, but is not an - L{XMPPHandler} itself, so this is not recursive. - - @ivar handlers: List of protocol handlers. - @type handlers: C{list} of objects providing - L{IXMPPHandler} - """ - - implements(ijabber.IXMPPHandlerCollection) - - def __init__(self): - self.handlers = [] - - - def __iter__(self): - """ - Act as a container for handlers. - """ - return iter(self.handlers) - - - def addHandler(self, handler): - """ - Add protocol handler. - - Protocol handlers are expected to provide L{ijabber.IXMPPHandler}. - """ - self.handlers.append(handler) - - - def removeHandler(self, handler): - """ - Remove protocol handler. - """ - self.handlers.remove(handler) - - - -class StreamManager(XMPPHandlerCollection): - """ - Business logic representing a managed XMPP connection. - - This maintains a single XMPP connection and provides facilities for packet - routing and transmission. Business logic modules are objects providing - L{ijabber.IXMPPHandler} (like subclasses of L{XMPPHandler}), and added - using L{addHandler}. - - @ivar xmlstream: currently managed XML stream - @type xmlstream: L{XmlStream} - @ivar logTraffic: if true, log all traffic. - @type logTraffic: C{bool} - @ivar _initialized: Whether the stream represented by L{xmlstream} has - been initialized. This is used when caching outgoing - stanzas. - @type _initialized: C{bool} - @ivar _packetQueue: internal buffer of unsent data. See L{send} for details. - @type _packetQueue: C{list} - """ - - logTraffic = False - - def __init__(self, factory): - XMPPHandlerCollection.__init__(self) - self.xmlstream = None - self._packetQueue = [] - self._initialized = False - - factory.addBootstrap(STREAM_CONNECTED_EVENT, self._connected) - factory.addBootstrap(STREAM_AUTHD_EVENT, self._authd) - factory.addBootstrap(INIT_FAILED_EVENT, self.initializationFailed) - factory.addBootstrap(STREAM_END_EVENT, self._disconnected) - self.factory = factory - - - def addHandler(self, handler): - """ - Add protocol handler. - - When an XML stream has already been established, the handler's - C{connectionInitialized} will be called to get it up to speed. - """ - XMPPHandlerCollection.addHandler(self, handler) - - # get protocol handler up to speed when a connection has already - # been established - if self.xmlstream and self._initialized: - handler.makeConnection(self.xmlstream) - handler.connectionInitialized() - - - def _connected(self, xs): - """ - Called when the transport connection has been established. - - Here we optionally set up traffic logging (depending on L{logTraffic}) - and call each handler's C{makeConnection} method with the L{XmlStream} - instance. - """ - def logDataIn(buf): - log.msg("RECV: %r" % buf) - - def logDataOut(buf): - log.msg("SEND: %r" % buf) - - if self.logTraffic: - xs.rawDataInFn = logDataIn - xs.rawDataOutFn = logDataOut - - self.xmlstream = xs - - for e in self: - e.makeConnection(xs) - - - def _authd(self, xs): - """ - Called when the stream has been initialized. - - Send out cached stanzas and call each handler's - C{connectionInitialized} method. - """ - # Flush all pending packets - for p in self._packetQueue: - xs.send(p) - self._packetQueue = [] - self._initialized = True - - # Notify all child services which implement - # the IService interface - for e in self: - e.connectionInitialized() - - - def initializationFailed(self, reason): - """ - Called when stream initialization has failed. - - Stream initialization has halted, with the reason indicated by - C{reason}. It may be retried by calling the authenticator's - C{initializeStream}. See the respective authenticators for details. - - @param reason: A failure instance indicating why stream initialization - failed. - @type reason: L{failure.Failure} - """ - - - def _disconnected(self, reason): - """ - Called when the stream has been closed. - - From this point on, the manager doesn't interact with the - L{XmlStream} anymore and notifies each handler that the connection - was lost by calling its C{connectionLost} method. - """ - self.xmlstream = None - self._initialized = False - - # Notify all child services which implement - # the IService interface - for e in self: - e.connectionLost(reason) - - - def send(self, obj): - """ - Send data over the XML stream. - - When there is no established XML stream, the data is queued and sent - out when a new XML stream has been established and initialized. - - @param obj: data to be sent over the XML stream. See - L{xmlstream.XmlStream.send} for details. - """ - if self._initialized: - self.xmlstream.send(obj) - else: - self._packetQueue.append(obj) - - - -__all__ = ['Authenticator', 'BaseFeatureInitiatingInitializer', - 'ConnectAuthenticator', 'FeatureNotAdvertized', - 'INIT_FAILED_EVENT', 'IQ', 'ListenAuthenticator', 'NS_STREAMS', - 'NS_XMPP_TLS', 'Reset', 'STREAM_AUTHD_EVENT', - 'STREAM_CONNECTED_EVENT', 'STREAM_END_EVENT', 'STREAM_ERROR_EVENT', - 'STREAM_START_EVENT', 'StreamManager', 'TLSError', 'TLSFailed', - 'TLSInitiatingInitializer', 'TLSNotSupported', 'TLSRequired', - 'TimeoutError', 'XMPPHandler', 'XMPPHandlerCollection', 'XmlStream', - 'XmlStreamFactory', 'XmlStreamServerFactory', 'hashPassword', - 'toResponse', 'upgradeWithIQResponseTracker'] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/xmpp_stringprep.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/xmpp_stringprep.py deleted file mode 100644 index cfdc39c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/jabber/xmpp_stringprep.py +++ /dev/null @@ -1,246 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberxmppstringprep -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -import stringprep -from encodings import idna - -# We require Unicode version 3.2. -from unicodedata import ucd_3_2_0 as unicodedata - -from twisted.python.versions import Version -from twisted.python.deprecate import deprecatedModuleAttribute - -from zope.interface import Interface, implements - - -crippled = False -deprecatedModuleAttribute( - Version("Twisted", 13, 1, 0), - "crippled is always False", - __name__, - "crippled") - - - -class ILookupTable(Interface): - """ - Interface for character lookup classes. - """ - - def lookup(c): - """ - Return whether character is in this table. - """ - - - -class IMappingTable(Interface): - """ - Interface for character mapping classes. - """ - - def map(c): - """ - Return mapping for character. - """ - - - -class LookupTableFromFunction: - - implements(ILookupTable) - - def __init__(self, in_table_function): - self.lookup = in_table_function - - - -class LookupTable: - - implements(ILookupTable) - - def __init__(self, table): - self._table = table - - def lookup(self, c): - return c in self._table - - - -class MappingTableFromFunction: - - implements(IMappingTable) - - def __init__(self, map_table_function): - self.map = map_table_function - - - -class EmptyMappingTable: - - implements(IMappingTable) - - def __init__(self, in_table_function): - self._in_table_function = in_table_function - - def map(self, c): - if self._in_table_function(c): - return None - else: - return c - - - -class Profile: - def __init__(self, mappings=[], normalize=True, prohibiteds=[], - check_unassigneds=True, check_bidi=True): - self.mappings = mappings - self.normalize = normalize - self.prohibiteds = prohibiteds - self.do_check_unassigneds = check_unassigneds - self.do_check_bidi = check_bidi - - def prepare(self, string): - result = self.map(string) - if self.normalize: - result = unicodedata.normalize("NFKC", result) - self.check_prohibiteds(result) - if self.do_check_unassigneds: - self.check_unassigneds(result) - if self.do_check_bidi: - self.check_bidirectionals(result) - return result - - def map(self, string): - result = [] - - for c in string: - result_c = c - - for mapping in self.mappings: - result_c = mapping.map(c) - if result_c != c: - break - - if result_c is not None: - result.append(result_c) - - return u"".join(result) - - def check_prohibiteds(self, string): - for c in string: - for table in self.prohibiteds: - if table.lookup(c): - raise UnicodeError, "Invalid character %s" % repr(c) - - def check_unassigneds(self, string): - for c in string: - if stringprep.in_table_a1(c): - raise UnicodeError, "Unassigned code point %s" % repr(c) - - def check_bidirectionals(self, string): - found_LCat = False - found_RandALCat = False - - for c in string: - if stringprep.in_table_d1(c): - found_RandALCat = True - if stringprep.in_table_d2(c): - found_LCat = True - - if found_LCat and found_RandALCat: - raise UnicodeError, "Violation of BIDI Requirement 2" - - if found_RandALCat and not (stringprep.in_table_d1(string[0]) and - stringprep.in_table_d1(string[-1])): - raise UnicodeError, "Violation of BIDI Requirement 3" - - -class NamePrep: - """ Implements preparation of internationalized domain names. - - This class implements preparing internationalized domain names using the - rules defined in RFC 3491, section 4 (Conversion operations). - - We do not perform step 4 since we deal with unicode representations of - domain names and do not convert from or to ASCII representations using - punycode encoding. When such a conversion is needed, the C{idna} standard - library provides the C{ToUnicode()} and C{ToASCII()} functions. Note that - C{idna} itself assumes UseSTD3ASCIIRules to be false. - - The following steps are performed by C{prepare()}: - - - Split the domain name in labels at the dots (RFC 3490, 3.1) - - Apply nameprep proper on each label (RFC 3491) - - Enforce the restrictions on ASCII characters in host names by - assuming STD3ASCIIRules to be true. (STD 3) - - Rejoin the labels using the label separator U+002E (full stop). - - """ - - # Prohibited characters. - prohibiteds = [unichr(n) for n in range(0x00, 0x2c + 1) + - range(0x2e, 0x2f + 1) + - range(0x3a, 0x40 + 1) + - range(0x5b, 0x60 + 1) + - range(0x7b, 0x7f + 1) ] - - def prepare(self, string): - result = [] - - labels = idna.dots.split(string) - - if labels and len(labels[-1]) == 0: - trailing_dot = '.' - del labels[-1] - else: - trailing_dot = '' - - for label in labels: - result.append(self.nameprep(label)) - - return ".".join(result) + trailing_dot - - def check_prohibiteds(self, string): - for c in string: - if c in self.prohibiteds: - raise UnicodeError, "Invalid character %s" % repr(c) - - def nameprep(self, label): - label = idna.nameprep(label) - self.check_prohibiteds(label) - if label[0] == '-': - raise UnicodeError, "Invalid leading hyphen-minus" - if label[-1] == '-': - raise UnicodeError, "Invalid trailing hyphen-minus" - return label - - -C_11 = LookupTableFromFunction(stringprep.in_table_c11) -C_12 = LookupTableFromFunction(stringprep.in_table_c12) -C_21 = LookupTableFromFunction(stringprep.in_table_c21) -C_22 = LookupTableFromFunction(stringprep.in_table_c22) -C_3 = LookupTableFromFunction(stringprep.in_table_c3) -C_4 = LookupTableFromFunction(stringprep.in_table_c4) -C_5 = LookupTableFromFunction(stringprep.in_table_c5) -C_6 = LookupTableFromFunction(stringprep.in_table_c6) -C_7 = LookupTableFromFunction(stringprep.in_table_c7) -C_8 = LookupTableFromFunction(stringprep.in_table_c8) -C_9 = LookupTableFromFunction(stringprep.in_table_c9) - -B_1 = EmptyMappingTable(stringprep.in_table_b1) -B_2 = MappingTableFromFunction(stringprep.map_table_b2) - -nodeprep = Profile(mappings=[B_1, B_2], - prohibiteds=[C_11, C_12, C_21, C_22, - C_3, C_4, C_5, C_6, C_7, C_8, C_9, - LookupTable([u'"', u'&', u"'", u'/', - u':', u'<', u'>', u'@'])]) - -resourceprep = Profile(mappings=[B_1,], - prohibiteds=[C_12, C_21, C_22, - C_3, C_4, C_5, C_6, C_7, C_8, C_9]) - -nameprep = NamePrep() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/msn.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/msn.py deleted file mode 100644 index 8c71dc2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/msn.py +++ /dev/null @@ -1,2479 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -MSNP8 Protocol (client only) - semi-experimental - -This module provides support for clients using the MSN Protocol (MSNP8). -There are basically 3 servers involved in any MSN session: - -I{Dispatch server} - -The DispatchClient class handles connections to the -dispatch server, which basically delegates users to a -suitable notification server. - -You will want to subclass this and handle the gotNotificationReferral -method appropriately. - -I{Notification Server} - -The NotificationClient class handles connections to the -notification server, which acts as a session server -(state updates, message negotiation etc...) - -I{Switcboard Server} - -The SwitchboardClient handles connections to switchboard -servers which are used to conduct conversations with other users. - -There are also two classes (FileSend and FileReceive) used -for file transfers. - -Clients handle events in two ways. - - - each client request requiring a response will return a Deferred, - the callback for same will be fired when the server sends the - required response - - Events which are not in response to any client request have - respective methods which should be overridden and handled in - an adequate manner - -Most client request callbacks require more than one argument, -and since Deferreds can only pass the callback one result, -most of the time the callback argument will be a tuple of -values (documented in the respective request method). -To make reading/writing code easier, callbacks can be defined in -a number of ways to handle this 'cleanly'. One way would be to -define methods like: def callBack(self, (arg1, arg2, arg)): ... -another way would be to do something like: -d.addCallback(lambda result: myCallback(*result)). - -If the server sends an error response to a client request, -the errback of the corresponding Deferred will be called, -the argument being the corresponding error code. - -B{NOTE}: -Due to the lack of an official spec for MSNP8, extra checking -than may be deemed necessary often takes place considering the -server is never 'wrong'. Thus, if gotBadLine (in any of the 3 -main clients) is called, or an MSNProtocolError is raised, it's -probably a good idea to submit a bug report. ;) -Use of this module requires that PyOpenSSL is installed. - -TODO -==== -- check message hooks with invalid x-msgsinvite messages. -- font handling -- switchboard factory - -@author: Sam Jordan -""" - -import types, operator, os -from random import randint -from urllib import quote, unquote -from hashlib import md5 - -from twisted.python import failure, log -from twisted.internet import reactor -from twisted.internet.defer import Deferred, execute -from twisted.internet.protocol import ClientFactory -try: - from twisted.internet.ssl import ClientContextFactory -except ImportError: - ClientContextFactory = None -from twisted.protocols.basic import LineReceiver -from twisted.web.http import HTTPClient - - -MSN_PROTOCOL_VERSION = "MSNP8 CVR0" # protocol version -MSN_PORT = 1863 # default dispatch server port -MSN_MAX_MESSAGE = 1664 # max message length -MSN_CHALLENGE_STR = "Q1P7W2E4J9R8U3S5" # used for server challenges -MSN_CVR_STR = "0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS" # :( - -# auth constants -LOGIN_SUCCESS = 1 -LOGIN_FAILURE = 2 -LOGIN_REDIRECT = 3 - -# list constants -FORWARD_LIST = 1 -ALLOW_LIST = 2 -BLOCK_LIST = 4 -REVERSE_LIST = 8 - -# phone constants -HOME_PHONE = "PHH" -WORK_PHONE = "PHW" -MOBILE_PHONE = "PHM" -HAS_PAGER = "MOB" - -# status constants -STATUS_ONLINE = 'NLN' -STATUS_OFFLINE = 'FLN' -STATUS_HIDDEN = 'HDN' -STATUS_IDLE = 'IDL' -STATUS_AWAY = 'AWY' -STATUS_BUSY = 'BSY' -STATUS_BRB = 'BRB' -STATUS_PHONE = 'PHN' -STATUS_LUNCH = 'LUN' - -CR = "\r" -LF = "\n" - - -class SSLRequired(Exception): - """ - This exception is raised when it is necessary to talk to a passport server - using SSL, but the necessary SSL dependencies are unavailable. - - @since: 11.0 - """ - - - -def checkParamLen(num, expected, cmd, error=None): - if error == None: - error = "Invalid Number of Parameters for %s" % cmd - if num != expected: - raise MSNProtocolError, error - -def _parseHeader(h, v): - """ - Split a certin number of known - header values with the format: - field1=val,field2=val,field3=val into - a dict mapping fields to values. - @param h: the header's key - @param v: the header's value as a string - """ - - if h in ('passporturls','authentication-info','www-authenticate'): - v = v.replace('Passport1.4','').lstrip() - fields = {} - for fieldPair in v.split(','): - try: - field,value = fieldPair.split('=',1) - fields[field.lower()] = value - except ValueError: - fields[field.lower()] = '' - return fields - else: - return v - -def _parsePrimitiveHost(host): - # Ho Ho Ho - h,p = host.replace('https://','').split('/',1) - p = '/' + p - return h,p - - -def _login(userHandle, passwd, nexusServer, cached=0, authData=''): - """ - This function is used internally and should not ever be called - directly. - - @raise SSLRequired: If there is no SSL support available. - """ - if ClientContextFactory is None: - raise SSLRequired( - 'Connecting to the Passport server requires SSL, but SSL is ' - 'unavailable.') - - cb = Deferred() - def _cb(server, auth): - loginFac = ClientFactory() - loginFac.protocol = lambda : PassportLogin(cb, userHandle, passwd, server, auth) - reactor.connectSSL(_parsePrimitiveHost(server)[0], 443, loginFac, ClientContextFactory()) - - if cached: - _cb(nexusServer, authData) - else: - fac = ClientFactory() - d = Deferred() - d.addCallbacks(_cb, callbackArgs=(authData,)) - d.addErrback(lambda f: cb.errback(f)) - fac.protocol = lambda : PassportNexus(d, nexusServer) - reactor.connectSSL(_parsePrimitiveHost(nexusServer)[0], 443, fac, ClientContextFactory()) - return cb - - -class PassportNexus(HTTPClient): - - """ - Used to obtain the URL of a valid passport - login HTTPS server. - - This class is used internally and should - not be instantiated directly -- that is, - The passport logging in process is handled - transparently by NotificationClient. - """ - - def __init__(self, deferred, host): - self.deferred = deferred - self.host, self.path = _parsePrimitiveHost(host) - - def connectionMade(self): - HTTPClient.connectionMade(self) - self.sendCommand('GET', self.path) - self.sendHeader('Host', self.host) - self.endHeaders() - self.headers = {} - - def handleHeader(self, header, value): - h = header.lower() - self.headers[h] = _parseHeader(h, value) - - def handleEndHeaders(self): - if self.connected: - self.transport.loseConnection() - if 'passporturls' not in self.headers or 'dalogin' not in self.headers['passporturls']: - self.deferred.errback(failure.Failure(failure.DefaultException("Invalid Nexus Reply"))) - self.deferred.callback('https://' + self.headers['passporturls']['dalogin']) - - def handleResponse(self, r): - pass - -class PassportLogin(HTTPClient): - """ - This class is used internally to obtain - a login ticket from a passport HTTPS - server -- it should not be used directly. - """ - - _finished = 0 - - def __init__(self, deferred, userHandle, passwd, host, authData): - self.deferred = deferred - self.userHandle = userHandle - self.passwd = passwd - self.authData = authData - self.host, self.path = _parsePrimitiveHost(host) - - def connectionMade(self): - self.sendCommand('GET', self.path) - self.sendHeader('Authorization', 'Passport1.4 OrgVerb=GET,OrgURL=http://messenger.msn.com,' + - 'sign-in=%s,pwd=%s,%s' % (quote(self.userHandle), self.passwd,self.authData)) - self.sendHeader('Host', self.host) - self.endHeaders() - self.headers = {} - - def handleHeader(self, header, value): - h = header.lower() - self.headers[h] = _parseHeader(h, value) - - def handleEndHeaders(self): - if self._finished: - return - self._finished = 1 # I think we need this because of HTTPClient - if self.connected: - self.transport.loseConnection() - authHeader = 'authentication-info' - _interHeader = 'www-authenticate' - if _interHeader in self.headers: - authHeader = _interHeader - try: - info = self.headers[authHeader] - status = info['da-status'] - handler = getattr(self, 'login_%s' % (status,), None) - if handler: - handler(info) - else: - raise Exception() - except Exception, e: - self.deferred.errback(failure.Failure(e)) - - def handleResponse(self, r): - pass - - def login_success(self, info): - ticket = info['from-pp'] - ticket = ticket[1:len(ticket)-1] - self.deferred.callback((LOGIN_SUCCESS, ticket)) - - def login_failed(self, info): - self.deferred.callback((LOGIN_FAILURE, unquote(info['cbtxt']))) - - def login_redir(self, info): - self.deferred.callback((LOGIN_REDIRECT, self.headers['location'], self.authData)) - - -class MSNProtocolError(Exception): - """ - This Exception is basically used for debugging - purposes, as the official MSN server should never - send anything _wrong_ and nobody in their right - mind would run their B{own} MSN server. - If it is raised by default command handlers - (handle_BLAH) the error will be logged. - """ - pass - - -class MSNCommandFailed(Exception): - """ - The server said that the command failed. - """ - - def __init__(self, errorCode): - self.errorCode = errorCode - - def __str__(self): - return ("Command failed: %s (error code %d)" - % (errorCodes[self.errorCode], self.errorCode)) - - -class MSNMessage: - """ - I am the class used to represent an 'instant' message. - - @ivar userHandle: The user handle (passport) of the sender - (this is only used when receiving a message) - @ivar screenName: The screen name of the sender (this is only used - when receiving a message) - @ivar message: The message - @ivar headers: The message headers - @type headers: dict - @ivar length: The message length (including headers and line endings) - @ivar ack: This variable is used to tell the server how to respond - once the message has been sent. If set to MESSAGE_ACK - (default) the server will respond with an ACK upon receiving - the message, if set to MESSAGE_NACK the server will respond - with a NACK upon failure to receive the message. - If set to MESSAGE_ACK_NONE the server will do nothing. - This is relevant for the return value of - SwitchboardClient.sendMessage (which will return - a Deferred if ack is set to either MESSAGE_ACK or MESSAGE_NACK - and will fire when the respective ACK or NACK is received). - If set to MESSAGE_ACK_NONE sendMessage will return None. - """ - MESSAGE_ACK = 'A' - MESSAGE_NACK = 'N' - MESSAGE_ACK_NONE = 'U' - - ack = MESSAGE_ACK - - def __init__(self, length=0, userHandle="", screenName="", message=""): - self.userHandle = userHandle - self.screenName = screenName - self.message = message - self.headers = {'MIME-Version' : '1.0', 'Content-Type' : 'text/plain'} - self.length = length - self.readPos = 0 - - def _calcMessageLen(self): - """ - used to calculate the number to send - as the message length when sending a message. - """ - return reduce(operator.add, [len(x[0]) + len(x[1]) + 4 for x in self.headers.items()]) + len(self.message) + 2 - - def setHeader(self, header, value): - """ set the desired header """ - self.headers[header] = value - - def getHeader(self, header): - """ - get the desired header value - @raise KeyError: if no such header exists. - """ - return self.headers[header] - - def hasHeader(self, header): - """ check to see if the desired header exists """ - return header in self.headers - - def getMessage(self): - """ return the message - not including headers """ - return self.message - - def setMessage(self, message): - """ set the message text """ - self.message = message - -class MSNContact: - - """ - This class represents a contact (user). - - @ivar userHandle: The contact's user handle (passport). - @ivar screenName: The contact's screen name. - @ivar groups: A list of all the group IDs which this - contact belongs to. - @ivar lists: An integer representing the sum of all lists - that this contact belongs to. - @ivar status: The contact's status code. - @type status: str if contact's status is known, None otherwise. - - @ivar homePhone: The contact's home phone number. - @type homePhone: str if known, otherwise None. - @ivar workPhone: The contact's work phone number. - @type workPhone: str if known, otherwise None. - @ivar mobilePhone: The contact's mobile phone number. - @type mobilePhone: str if known, otherwise None. - @ivar hasPager: Whether or not this user has a mobile pager - (true=yes, false=no) - """ - - def __init__(self, userHandle="", screenName="", lists=0, groups=[], status=None): - self.userHandle = userHandle - self.screenName = screenName - self.lists = lists - self.groups = [] # if applicable - self.status = status # current status - - # phone details - self.homePhone = None - self.workPhone = None - self.mobilePhone = None - self.hasPager = None - - def setPhone(self, phoneType, value): - """ - set phone numbers/values for this specific user. - for phoneType check the *_PHONE constants and HAS_PAGER - """ - - t = phoneType.upper() - if t == HOME_PHONE: - self.homePhone = value - elif t == WORK_PHONE: - self.workPhone = value - elif t == MOBILE_PHONE: - self.mobilePhone = value - elif t == HAS_PAGER: - self.hasPager = value - else: - raise ValueError, "Invalid Phone Type" - - def addToList(self, listType): - """ - Update the lists attribute to - reflect being part of the - given list. - """ - self.lists |= listType - - def removeFromList(self, listType): - """ - Update the lists attribute to - reflect being removed from the - given list. - """ - self.lists ^= listType - -class MSNContactList: - """ - This class represents a basic MSN contact list. - - @ivar contacts: All contacts on my various lists - @type contacts: dict (mapping user handles to MSNContact objects) - @ivar version: The current contact list version (used for list syncing) - @ivar groups: a mapping of group ids to group names - (groups can only exist on the forward list) - @type groups: dict - - B{Note}: - This is used only for storage and doesn't effect the - server's contact list. - """ - - def __init__(self): - self.contacts = {} - self.version = 0 - self.groups = {} - self.autoAdd = 0 - self.privacy = 0 - - def _getContactsFromList(self, listType): - """ - Obtain all contacts which belong - to the given list type. - """ - return dict([(uH,obj) for uH,obj in self.contacts.items() if obj.lists & listType]) - - def addContact(self, contact): - """ - Add a contact - """ - self.contacts[contact.userHandle] = contact - - def remContact(self, userHandle): - """ - Remove a contact - """ - try: - del self.contacts[userHandle] - except KeyError: - pass - - def getContact(self, userHandle): - """ - Obtain the MSNContact object - associated with the given - userHandle. - @return: the MSNContact object if - the user exists, or None. - """ - try: - return self.contacts[userHandle] - except KeyError: - return None - - def getBlockedContacts(self): - """ - Obtain all the contacts on my block list - """ - return self._getContactsFromList(BLOCK_LIST) - - def getAuthorizedContacts(self): - """ - Obtain all the contacts on my auth list. - (These are contacts which I have verified - can view my state changes). - """ - return self._getContactsFromList(ALLOW_LIST) - - def getReverseContacts(self): - """ - Get all contacts on my reverse list. - (These are contacts which have added me - to their forward list). - """ - return self._getContactsFromList(REVERSE_LIST) - - def getContacts(self): - """ - Get all contacts on my forward list. - (These are the contacts which I have added - to my list). - """ - return self._getContactsFromList(FORWARD_LIST) - - def setGroup(self, id, name): - """ - Keep a mapping from the given id - to the given name. - """ - self.groups[id] = name - - def remGroup(self, id): - """ - Removed the stored group - mapping for the given id. - """ - try: - del self.groups[id] - except KeyError: - pass - for c in self.contacts: - if id in c.groups: - c.groups.remove(id) - - -class MSNEventBase(LineReceiver): - """ - This class provides support for handling / dispatching events and is the - base class of the three main client protocols (DispatchClient, - NotificationClient, SwitchboardClient) - """ - - def __init__(self): - self.ids = {} # mapping of ids to Deferreds - self.currentID = 0 - self.connected = 0 - self.setLineMode() - self.currentMessage = None - - def connectionLost(self, reason): - self.ids = {} - self.connected = 0 - - def connectionMade(self): - self.connected = 1 - - def _fireCallback(self, id, *args): - """ - Fire the callback for the given id - if one exists and return 1, else return false - """ - if id in self.ids: - self.ids[id][0].callback(args) - del self.ids[id] - return 1 - return 0 - - def _nextTransactionID(self): - """ return a usable transaction ID """ - self.currentID += 1 - if self.currentID > 1000: - self.currentID = 1 - return self.currentID - - def _createIDMapping(self, data=None): - """ - return a unique transaction ID that is mapped internally to a - deferred .. also store arbitrary data if it is needed - """ - id = self._nextTransactionID() - d = Deferred() - self.ids[id] = (d, data) - return (id, d) - - def checkMessage(self, message): - """ - process received messages to check for file invitations and - typing notifications and other control type messages - """ - raise NotImplementedError - - def lineReceived(self, line): - if self.currentMessage: - self.currentMessage.readPos += len(line+CR+LF) - if line == "": - self.setRawMode() - if self.currentMessage.readPos == self.currentMessage.length: - self.rawDataReceived("") # :( - return - try: - header, value = line.split(':') - except ValueError: - raise MSNProtocolError, "Invalid Message Header" - self.currentMessage.setHeader(header, unquote(value).lstrip()) - return - try: - cmd, params = line.split(' ', 1) - except ValueError: - raise MSNProtocolError, "Invalid Message, %s" % repr(line) - - if len(cmd) != 3: - raise MSNProtocolError, "Invalid Command, %s" % repr(cmd) - if cmd.isdigit(): - errorCode = int(cmd) - id = int(params.split()[0]) - if id in self.ids: - self.ids[id][0].errback(MSNCommandFailed(errorCode)) - del self.ids[id] - return - else: # we received an error which doesn't map to a sent command - self.gotError(errorCode) - return - - handler = getattr(self, "handle_%s" % cmd.upper(), None) - if handler: - try: - handler(params.split()) - except MSNProtocolError, why: - self.gotBadLine(line, why) - else: - self.handle_UNKNOWN(cmd, params.split()) - - def rawDataReceived(self, data): - extra = "" - self.currentMessage.readPos += len(data) - diff = self.currentMessage.readPos - self.currentMessage.length - if diff > 0: - self.currentMessage.message += data[:-diff] - extra = data[-diff:] - elif diff == 0: - self.currentMessage.message += data - else: - self.currentMessage += data - return - del self.currentMessage.readPos - m = self.currentMessage - self.currentMessage = None - self.setLineMode(extra) - if not self.checkMessage(m): - return - self.gotMessage(m) - - ### protocol command handlers - no need to override these. - - def handle_MSG(self, params): - checkParamLen(len(params), 3, 'MSG') - try: - messageLen = int(params[2]) - except ValueError: - raise MSNProtocolError, "Invalid Parameter for MSG length argument" - self.currentMessage = MSNMessage(length=messageLen, userHandle=params[0], screenName=unquote(params[1])) - - def handle_UNKNOWN(self, cmd, params): - """ implement me in subclasses if you want to handle unknown events """ - log.msg("Received unknown command (%s), params: %s" % (cmd, params)) - - ### callbacks - - def gotMessage(self, message): - """ - called when we receive a message - override in notification - and switchboard clients - """ - raise NotImplementedError - - def gotBadLine(self, line, why): - """ called when a handler notifies me that this line is broken """ - log.msg('Error in line: %s (%s)' % (line, why)) - - def gotError(self, errorCode): - """ - called when the server sends an error which is not in - response to a sent command (ie. it has no matching transaction ID) - """ - log.msg('Error %s' % (errorCodes[errorCode])) - - - -class DispatchClient(MSNEventBase): - """ - This class provides support for clients connecting to the dispatch server - @ivar userHandle: your user handle (passport) needed before connecting. - """ - - # eventually this may become an attribute of the - # factory. - userHandle = "" - - def connectionMade(self): - MSNEventBase.connectionMade(self) - self.sendLine('VER %s %s' % (self._nextTransactionID(), MSN_PROTOCOL_VERSION)) - - ### protocol command handlers ( there is no need to override these ) - - def handle_VER(self, params): - id = self._nextTransactionID() - self.sendLine("CVR %s %s %s" % (id, MSN_CVR_STR, self.userHandle)) - - def handle_CVR(self, params): - self.sendLine("USR %s TWN I %s" % (self._nextTransactionID(), self.userHandle)) - - def handle_XFR(self, params): - if len(params) < 4: - raise MSNProtocolError, "Invalid number of parameters for XFR" - id, refType, addr = params[:3] - # was addr a host:port pair? - try: - host, port = addr.split(':') - except ValueError: - host = addr - port = MSN_PORT - if refType == "NS": - self.gotNotificationReferral(host, int(port)) - - ### callbacks - - def gotNotificationReferral(self, host, port): - """ - called when we get a referral to the notification server. - - @param host: the notification server's hostname - @param port: the port to connect to - """ - pass - - -class NotificationClient(MSNEventBase): - """ - This class provides support for clients connecting - to the notification server. - """ - - factory = None # sssh pychecker - - def __init__(self, currentID=0): - MSNEventBase.__init__(self) - self.currentID = currentID - self._state = ['DISCONNECTED', {}] - - def _setState(self, state): - self._state[0] = state - - def _getState(self): - return self._state[0] - - def _getStateData(self, key): - return self._state[1][key] - - def _setStateData(self, key, value): - self._state[1][key] = value - - def _remStateData(self, *args): - for key in args: - del self._state[1][key] - - def connectionMade(self): - MSNEventBase.connectionMade(self) - self._setState('CONNECTED') - self.sendLine("VER %s %s" % (self._nextTransactionID(), MSN_PROTOCOL_VERSION)) - - def connectionLost(self, reason): - self._setState('DISCONNECTED') - self._state[1] = {} - MSNEventBase.connectionLost(self, reason) - - def checkMessage(self, message): - """ hook used for detecting specific notification messages """ - cTypes = [s.lstrip() for s in message.getHeader('Content-Type').split(';')] - if 'text/x-msmsgsprofile' in cTypes: - self.gotProfile(message) - return 0 - return 1 - - ### protocol command handlers - no need to override these - - def handle_VER(self, params): - id = self._nextTransactionID() - self.sendLine("CVR %s %s %s" % (id, MSN_CVR_STR, self.factory.userHandle)) - - def handle_CVR(self, params): - self.sendLine("USR %s TWN I %s" % (self._nextTransactionID(), self.factory.userHandle)) - - def handle_USR(self, params): - if len(params) != 4 and len(params) != 6: - raise MSNProtocolError, "Invalid Number of Parameters for USR" - - mechanism = params[1] - if mechanism == "OK": - self.loggedIn(params[2], unquote(params[3]), int(params[4])) - elif params[2].upper() == "S": - # we need to obtain auth from a passport server - f = self.factory - d = execute( - _login, f.userHandle, f.password, f.passportServer, - authData=params[3]) - d.addCallback(self._passportLogin) - d.addErrback(self._passportError) - - def _passportLogin(self, result): - if result[0] == LOGIN_REDIRECT: - d = _login(self.factory.userHandle, self.factory.password, - result[1], cached=1, authData=result[2]) - d.addCallback(self._passportLogin) - d.addErrback(self._passportError) - elif result[0] == LOGIN_SUCCESS: - self.sendLine("USR %s TWN S %s" % (self._nextTransactionID(), result[1])) - elif result[0] == LOGIN_FAILURE: - self.loginFailure(result[1]) - - - def _passportError(self, failure): - """ - Handle a problem logging in via the Passport server, passing on the - error as a string message to the C{loginFailure} callback. - """ - if failure.check(SSLRequired): - failure = failure.getErrorMessage() - self.loginFailure("Exception while authenticating: %s" % failure) - - - def handle_CHG(self, params): - checkParamLen(len(params), 3, 'CHG') - id = int(params[0]) - if not self._fireCallback(id, params[1]): - self.statusChanged(params[1]) - - def handle_ILN(self, params): - checkParamLen(len(params), 5, 'ILN') - self.gotContactStatus(params[1], params[2], unquote(params[3])) - - def handle_CHL(self, params): - checkParamLen(len(params), 2, 'CHL') - self.sendLine("QRY %s msmsgs@msnmsgr.com 32" % self._nextTransactionID()) - self.transport.write(md5(params[1] + MSN_CHALLENGE_STR).hexdigest()) - - def handle_QRY(self, params): - pass - - def handle_NLN(self, params): - checkParamLen(len(params), 4, 'NLN') - self.contactStatusChanged(params[0], params[1], unquote(params[2])) - - def handle_FLN(self, params): - checkParamLen(len(params), 1, 'FLN') - self.contactOffline(params[0]) - - def handle_LST(self, params): - # support no longer exists for manually - # requesting lists - why do I feel cleaner now? - if self._getState() != 'SYNC': - return - contact = MSNContact(userHandle=params[0], screenName=unquote(params[1]), - lists=int(params[2])) - if contact.lists & FORWARD_LIST: - contact.groups.extend(map(int, params[3].split(','))) - self._getStateData('list').addContact(contact) - self._setStateData('last_contact', contact) - sofar = self._getStateData('lst_sofar') + 1 - if sofar == self._getStateData('lst_reply'): - # this is the best place to determine that - # a syn really has finished - msn _may_ send - # BPR information for the last contact - # which is unfortunate because it means - # that the real end of a syn is non-deterministic. - # to handle this we'll keep 'last_contact' hanging - # around in the state data and update it if we need - # to later. - self._setState('SESSION') - contacts = self._getStateData('list') - phone = self._getStateData('phone') - id = self._getStateData('synid') - self._remStateData('lst_reply', 'lsg_reply', 'lst_sofar', 'phone', 'synid', 'list') - self._fireCallback(id, contacts, phone) - else: - self._setStateData('lst_sofar',sofar) - - def handle_BLP(self, params): - # check to see if this is in response to a SYN - if self._getState() == 'SYNC': - self._getStateData('list').privacy = listCodeToID[params[0].lower()] - else: - id = int(params[0]) - self._fireCallback(id, int(params[1]), listCodeToID[params[2].lower()]) - - def handle_GTC(self, params): - # check to see if this is in response to a SYN - if self._getState() == 'SYNC': - if params[0].lower() == "a": - self._getStateData('list').autoAdd = 0 - elif params[0].lower() == "n": - self._getStateData('list').autoAdd = 1 - else: - raise MSNProtocolError, "Invalid Parameter for GTC" # debug - else: - id = int(params[0]) - if params[1].lower() == "a": - self._fireCallback(id, 0) - elif params[1].lower() == "n": - self._fireCallback(id, 1) - else: - raise MSNProtocolError, "Invalid Parameter for GTC" # debug - - def handle_SYN(self, params): - id = int(params[0]) - if len(params) == 2: - self._setState('SESSION') - self._fireCallback(id, None, None) - else: - contacts = MSNContactList() - contacts.version = int(params[1]) - self._setStateData('list', contacts) - self._setStateData('lst_reply', int(params[2])) - self._setStateData('lsg_reply', int(params[3])) - self._setStateData('lst_sofar', 0) - self._setStateData('phone', []) - - def handle_LSG(self, params): - if self._getState() == 'SYNC': - self._getStateData('list').groups[int(params[0])] = unquote(params[1]) - - # Please see the comment above the requestListGroups / requestList methods - # regarding support for this - # - #else: - # self._getStateData('groups').append((int(params[4]), unquote(params[5]))) - # if params[3] == params[4]: # this was the last group - # self._fireCallback(int(params[0]), self._getStateData('groups'), int(params[1])) - # self._remStateData('groups') - - def handle_PRP(self, params): - if self._getState() == 'SYNC': - self._getStateData('phone').append((params[0], unquote(params[1]))) - else: - self._fireCallback(int(params[0]), int(params[1]), unquote(params[3])) - - def handle_BPR(self, params): - numParams = len(params) - if numParams == 2: # part of a syn - self._getStateData('last_contact').setPhone(params[0], unquote(params[1])) - elif numParams == 4: - self.gotPhoneNumber(int(params[0]), params[1], params[2], unquote(params[3])) - - def handle_ADG(self, params): - checkParamLen(len(params), 5, 'ADG') - id = int(params[0]) - if not self._fireCallback(id, int(params[1]), unquote(params[2]), int(params[3])): - raise MSNProtocolError, "ADG response does not match up to a request" # debug - - def handle_RMG(self, params): - checkParamLen(len(params), 3, 'RMG') - id = int(params[0]) - if not self._fireCallback(id, int(params[1]), int(params[2])): - raise MSNProtocolError, "RMG response does not match up to a request" # debug - - def handle_REG(self, params): - checkParamLen(len(params), 5, 'REG') - id = int(params[0]) - if not self._fireCallback(id, int(params[1]), int(params[2]), unquote(params[3])): - raise MSNProtocolError, "REG response does not match up to a request" # debug - - def handle_ADD(self, params): - numParams = len(params) - if numParams < 5 or params[1].upper() not in ('AL','BL','RL','FL'): - raise MSNProtocolError, "Invalid Parameters for ADD" # debug - id = int(params[0]) - listType = params[1].lower() - listVer = int(params[2]) - userHandle = params[3] - groupID = None - if numParams == 6: # they sent a group id - if params[1].upper() != "FL": - raise MSNProtocolError, "Only forward list can contain groups" # debug - groupID = int(params[5]) - if not self._fireCallback(id, listCodeToID[listType], userHandle, listVer, groupID): - self.userAddedMe(userHandle, unquote(params[4]), listVer) - - def handle_REM(self, params): - numParams = len(params) - if numParams < 4 or params[1].upper() not in ('AL','BL','FL','RL'): - raise MSNProtocolError, "Invalid Parameters for REM" # debug - id = int(params[0]) - listType = params[1].lower() - listVer = int(params[2]) - userHandle = params[3] - groupID = None - if numParams == 5: - if params[1] != "FL": - raise MSNProtocolError, "Only forward list can contain groups" # debug - groupID = int(params[4]) - if not self._fireCallback(id, listCodeToID[listType], userHandle, listVer, groupID): - if listType.upper() == "RL": - self.userRemovedMe(userHandle, listVer) - - def handle_REA(self, params): - checkParamLen(len(params), 4, 'REA') - id = int(params[0]) - self._fireCallback(id, int(params[1]), unquote(params[3])) - - def handle_XFR(self, params): - checkParamLen(len(params), 5, 'XFR') - id = int(params[0]) - # check to see if they sent a host/port pair - try: - host, port = params[2].split(':') - except ValueError: - host = params[2] - port = MSN_PORT - - if not self._fireCallback(id, host, int(port), params[4]): - raise MSNProtocolError, "Got XFR (referral) that I didn't ask for .. should this happen?" # debug - - def handle_RNG(self, params): - checkParamLen(len(params), 6, 'RNG') - # check for host:port pair - try: - host, port = params[1].split(":") - port = int(port) - except ValueError: - host = params[1] - port = MSN_PORT - self.gotSwitchboardInvitation(int(params[0]), host, port, params[3], params[4], - unquote(params[5])) - - def handle_OUT(self, params): - checkParamLen(len(params), 1, 'OUT') - if params[0] == "OTH": - self.multipleLogin() - elif params[0] == "SSD": - self.serverGoingDown() - else: - raise MSNProtocolError, "Invalid Parameters received for OUT" # debug - - # callbacks - - def loggedIn(self, userHandle, screenName, verified): - """ - Called when the client has logged in. - The default behaviour of this method is to - update the factory with our screenName and - to sync the contact list (factory.contacts). - When this is complete self.listSynchronized - will be called. - - @param userHandle: our userHandle - @param screenName: our screenName - @param verified: 1 if our passport has been (verified), 0 if not. - (i'm not sure of the significance of this) - @type verified: int - """ - self.factory.screenName = screenName - if not self.factory.contacts: - listVersion = 0 - else: - listVersion = self.factory.contacts.version - self.syncList(listVersion).addCallback(self.listSynchronized) - - - def loginFailure(self, message): - """ - Called when the client fails to login. - - @param message: a message indicating the problem that was encountered - """ - - - def gotProfile(self, message): - """ - Called after logging in when the server sends an initial - message with MSN/passport specific profile information - such as country, number of kids, etc. - Check the message headers for the specific values. - - @param message: The profile message - """ - pass - - def listSynchronized(self, *args): - """ - Lists are now synchronized by default upon logging in, this - method is called after the synchronization has finished - and the factory now has the up-to-date contacts. - """ - pass - - def statusChanged(self, statusCode): - """ - Called when our status changes and it isn't in response to - a client command. By default we will update the status - attribute of the factory. - - @param statusCode: 3-letter status code - """ - self.factory.status = statusCode - - def gotContactStatus(self, statusCode, userHandle, screenName): - """ - Called after loggin in when the server sends status of online contacts. - By default we will update the status attribute of the contact stored - on the factory. - - @param statusCode: 3-letter status code - @param userHandle: the contact's user handle (passport) - @param screenName: the contact's screen name - """ - self.factory.contacts.getContact(userHandle).status = statusCode - - def contactStatusChanged(self, statusCode, userHandle, screenName): - """ - Called when we're notified that a contact's status has changed. - By default we will update the status attribute of the contact - stored on the factory. - - @param statusCode: 3-letter status code - @param userHandle: the contact's user handle (passport) - @param screenName: the contact's screen name - """ - self.factory.contacts.getContact(userHandle).status = statusCode - - def contactOffline(self, userHandle): - """ - Called when a contact goes offline. By default this method - will update the status attribute of the contact stored - on the factory. - - @param userHandle: the contact's user handle - """ - self.factory.contacts.getContact(userHandle).status = STATUS_OFFLINE - - def gotPhoneNumber(self, listVersion, userHandle, phoneType, number): - """ - Called when the server sends us phone details about - a specific user (for example after a user is added - the server will send their status, phone details etc. - By default we will update the list version for the - factory's contact list and update the phone details - for the specific user. - - @param listVersion: the new list version - @param userHandle: the contact's user handle (passport) - @param phoneType: the specific phoneType - (*_PHONE constants or HAS_PAGER) - @param number: the value/phone number. - """ - self.factory.contacts.version = listVersion - self.factory.contacts.getContact(userHandle).setPhone(phoneType, number) - - def userAddedMe(self, userHandle, screenName, listVersion): - """ - Called when a user adds me to their list. (ie. they have been added to - the reverse list. By default this method will update the version of - the factory's contact list -- that is, if the contact already exists - it will update the associated lists attribute, otherwise it will create - a new MSNContact object and store it. - - @param userHandle: the userHandle of the user - @param screenName: the screen name of the user - @param listVersion: the new list version - @type listVersion: int - """ - self.factory.contacts.version = listVersion - c = self.factory.contacts.getContact(userHandle) - if not c: - c = MSNContact(userHandle=userHandle, screenName=screenName) - self.factory.contacts.addContact(c) - c.addToList(REVERSE_LIST) - - def userRemovedMe(self, userHandle, listVersion): - """ - Called when a user removes us from their contact list - (they are no longer on our reverseContacts list. - By default this method will update the version of - the factory's contact list -- that is, the user will - be removed from the reverse list and if they are no longer - part of any lists they will be removed from the contact - list entirely. - - @param userHandle: the contact's user handle (passport) - @param listVersion: the new list version - """ - self.factory.contacts.version = listVersion - c = self.factory.contacts.getContact(userHandle) - c.removeFromList(REVERSE_LIST) - if c.lists == 0: - self.factory.contacts.remContact(c.userHandle) - - def gotSwitchboardInvitation(self, sessionID, host, port, - key, userHandle, screenName): - """ - Called when we get an invitation to a switchboard server. - This happens when a user requests a chat session with us. - - @param sessionID: session ID number, must be remembered for logging in - @param host: the hostname of the switchboard server - @param port: the port to connect to - @param key: used for authorization when connecting - @param userHandle: the user handle of the person who invited us - @param screenName: the screen name of the person who invited us - """ - pass - - def multipleLogin(self): - """ - Called when the server says there has been another login - under our account, the server should disconnect us right away. - """ - pass - - def serverGoingDown(self): - """ - Called when the server has notified us that it is going down for - maintenance. - """ - pass - - # api calls - - def changeStatus(self, status): - """ - Change my current status. This method will add - a default callback to the returned Deferred - which will update the status attribute of the - factory. - - @param status: 3-letter status code (as defined by - the STATUS_* constants) - @return: A Deferred, the callback of which will be - fired when the server confirms the change - of status. The callback argument will be - a tuple with the new status code as the - only element. - """ - - id, d = self._createIDMapping() - self.sendLine("CHG %s %s" % (id, status)) - def _cb(r): - self.factory.status = r[0] - return r - return d.addCallback(_cb) - - # I am no longer supporting the process of manually requesting - # lists or list groups -- as far as I can see this has no use - # if lists are synchronized and updated correctly, which they - # should be. If someone has a specific justified need for this - # then please contact me and i'll re-enable/fix support for it. - - #def requestList(self, listType): - # """ - # request the desired list type - # - # @param listType: (as defined by the *_LIST constants) - # @return: A Deferred, the callback of which will be - # fired when the list has been retrieved. - # The callback argument will be a tuple with - # the only element being a list of MSNContact - # objects. - # """ - # # this doesn't need to ever be used if syncing of the lists takes place - # # i.e. please don't use it! - # warnings.warn("Please do not use this method - use the list syncing process instead") - # id, d = self._createIDMapping() - # self.sendLine("LST %s %s" % (id, listIDToCode[listType].upper())) - # self._setStateData('list',[]) - # return d - - def setPrivacyMode(self, privLevel): - """ - Set my privacy mode on the server. - - B{Note}: - This only keeps the current privacy setting on - the server for later retrieval, it does not - effect the way the server works at all. - - @param privLevel: This parameter can be true, in which - case the server will keep the state as - 'al' which the official client interprets - as -> allow messages from only users on - the allow list. Alternatively it can be - false, in which case the server will keep - the state as 'bl' which the official client - interprets as -> allow messages from all - users except those on the block list. - - @return: A Deferred, the callback of which will be fired when - the server replies with the new privacy setting. - The callback argument will be a tuple, the 2 elements - of which being the list version and either 'al' - or 'bl' (the new privacy setting). - """ - - id, d = self._createIDMapping() - if privLevel: - self.sendLine("BLP %s AL" % id) - else: - self.sendLine("BLP %s BL" % id) - return d - - def syncList(self, version): - """ - Used for keeping an up-to-date contact list. - A callback is added to the returned Deferred - that updates the contact list on the factory - and also sets my state to STATUS_ONLINE. - - B{Note}: - This is called automatically upon signing - in using the version attribute of - factory.contacts, so you may want to persist - this object accordingly. Because of this there - is no real need to ever call this method - directly. - - @param version: The current known list version - - @return: A Deferred, the callback of which will be - fired when the server sends an adequate reply. - The callback argument will be a tuple with two - elements, the new list (MSNContactList) and - your current state (a dictionary). If the version - you sent _was_ the latest list version, both elements - will be None. To just request the list send a version of 0. - """ - - self._setState('SYNC') - id, d = self._createIDMapping(data=str(version)) - self._setStateData('synid',id) - self.sendLine("SYN %s %s" % (id, version)) - def _cb(r): - self.changeStatus(STATUS_ONLINE) - if r[0] is not None: - self.factory.contacts = r[0] - return r - return d.addCallback(_cb) - - - # I am no longer supporting the process of manually requesting - # lists or list groups -- as far as I can see this has no use - # if lists are synchronized and updated correctly, which they - # should be. If someone has a specific justified need for this - # then please contact me and i'll re-enable/fix support for it. - - #def requestListGroups(self): - # """ - # Request (forward) list groups. - # - # @return: A Deferred, the callback for which will be called - # when the server responds with the list groups. - # The callback argument will be a tuple with two elements, - # a dictionary mapping group IDs to group names and the - # current list version. - # """ - # - # # this doesn't need to be used if syncing of the lists takes place (which it SHOULD!) - # # i.e. please don't use it! - # warnings.warn("Please do not use this method - use the list syncing process instead") - # id, d = self._createIDMapping() - # self.sendLine("LSG %s" % id) - # self._setStateData('groups',{}) - # return d - - def setPhoneDetails(self, phoneType, value): - """ - Set/change my phone numbers stored on the server. - - @param phoneType: phoneType can be one of the following - constants - HOME_PHONE, WORK_PHONE, - MOBILE_PHONE, HAS_PAGER. - These are pretty self-explanatory, except - maybe HAS_PAGER which refers to whether or - not you have a pager. - @param value: for all of the *_PHONE constants the value is a - phone number (str), for HAS_PAGER accepted values - are 'Y' (for yes) and 'N' (for no). - - @return: A Deferred, the callback for which will be fired when - the server confirms the change has been made. The - callback argument will be a tuple with 2 elements, the - first being the new list version (int) and the second - being the new phone number value (str). - """ - # XXX: Add a default callback which updates - # factory.contacts.version and the relevant phone - # number - id, d = self._createIDMapping() - self.sendLine("PRP %s %s %s" % (id, phoneType, quote(value))) - return d - - def addListGroup(self, name): - """ - Used to create a new list group. - A default callback is added to the - returned Deferred which updates the - contacts attribute of the factory. - - @param name: The desired name of the new group. - - @return: A Deferred, the callbacck for which will be called - when the server clarifies that the new group has been - created. The callback argument will be a tuple with 3 - elements: the new list version (int), the new group name - (str) and the new group ID (int). - """ - - id, d = self._createIDMapping() - self.sendLine("ADG %s %s 0" % (id, quote(name))) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.contacts.setGroup(r[1], r[2]) - return r - return d.addCallback(_cb) - - def remListGroup(self, groupID): - """ - Used to remove a list group. - A default callback is added to the - returned Deferred which updates the - contacts attribute of the factory. - - @param groupID: the ID of the desired group to be removed. - - @return: A Deferred, the callback for which will be called when - the server clarifies the deletion of the group. - The callback argument will be a tuple with 2 elements: - the new list version (int) and the group ID (int) of - the removed group. - """ - - id, d = self._createIDMapping() - self.sendLine("RMG %s %s" % (id, groupID)) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.contacts.remGroup(r[1]) - return r - return d.addCallback(_cb) - - def renameListGroup(self, groupID, newName): - """ - Used to rename an existing list group. - A default callback is added to the returned - Deferred which updates the contacts attribute - of the factory. - - @param groupID: the ID of the desired group to rename. - @param newName: the desired new name for the group. - - @return: A Deferred, the callback for which will be called - when the server clarifies the renaming. - The callback argument will be a tuple of 3 elements, - the new list version (int), the group id (int) and - the new group name (str). - """ - - id, d = self._createIDMapping() - self.sendLine("REG %s %s %s 0" % (id, groupID, quote(newName))) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.contacts.setGroup(r[1], r[2]) - return r - return d.addCallback(_cb) - - def addContact(self, listType, userHandle, groupID=0): - """ - Used to add a contact to the desired list. - A default callback is added to the returned - Deferred which updates the contacts attribute of - the factory with the new contact information. - If you are adding a contact to the forward list - and you want to associate this contact with multiple - groups then you will need to call this method for each - group you would like to add them to, changing the groupID - parameter. The default callback will take care of updating - the group information on the factory's contact list. - - @param listType: (as defined by the *_LIST constants) - @param userHandle: the user handle (passport) of the contact - that is being added - @param groupID: the group ID for which to associate this contact - with. (default 0 - default group). Groups are only - valid for FORWARD_LIST. - - @return: A Deferred, the callback for which will be called when - the server has clarified that the user has been added. - The callback argument will be a tuple with 4 elements: - the list type, the contact's user handle, the new list - version, and the group id (if relevant, otherwise it - will be None) - """ - - id, d = self._createIDMapping() - listType = listIDToCode[listType].upper() - if listType == "FL": - self.sendLine("ADD %s FL %s %s %s" % (id, userHandle, userHandle, groupID)) - else: - self.sendLine("ADD %s %s %s %s" % (id, listType, userHandle, userHandle)) - - def _cb(r): - self.factory.contacts.version = r[2] - c = self.factory.contacts.getContact(r[1]) - if not c: - c = MSNContact(userHandle=r[1]) - if r[3]: - c.groups.append(r[3]) - c.addToList(r[0]) - return r - return d.addCallback(_cb) - - def remContact(self, listType, userHandle, groupID=0): - """ - Used to remove a contact from the desired list. - A default callback is added to the returned deferred - which updates the contacts attribute of the factory - to reflect the new contact information. If you are - removing from the forward list then you will need to - supply a groupID, if the contact is in more than one - group then they will only be removed from this group - and not the entire forward list, but if this is their - only group they will be removed from the whole list. - - @param listType: (as defined by the *_LIST constants) - @param userHandle: the user handle (passport) of the - contact being removed - @param groupID: the ID of the group to which this contact - belongs (only relevant for FORWARD_LIST, - default is 0) - - @return: A Deferred, the callback for which will be called when - the server has clarified that the user has been removed. - The callback argument will be a tuple of 4 elements: - the list type, the contact's user handle, the new list - version, and the group id (if relevant, otherwise it will - be None) - """ - - id, d = self._createIDMapping() - listType = listIDToCode[listType].upper() - if listType == "FL": - self.sendLine("REM %s FL %s %s" % (id, userHandle, groupID)) - else: - self.sendLine("REM %s %s %s" % (id, listType, userHandle)) - - def _cb(r): - l = self.factory.contacts - l.version = r[2] - c = l.getContact(r[1]) - group = r[3] - shouldRemove = 1 - if group: # they may not have been removed from the list - c.groups.remove(group) - if c.groups: - shouldRemove = 0 - if shouldRemove: - c.removeFromList(r[0]) - if c.lists == 0: - l.remContact(c.userHandle) - return r - return d.addCallback(_cb) - - def changeScreenName(self, newName): - """ - Used to change your current screen name. - A default callback is added to the returned - Deferred which updates the screenName attribute - of the factory and also updates the contact list - version. - - @param newName: the new screen name - - @return: A Deferred, the callback for which will be called - when the server sends an adequate reply. - The callback argument will be a tuple of 2 elements: - the new list version and the new screen name. - """ - - id, d = self._createIDMapping() - self.sendLine("REA %s %s %s" % (id, self.factory.userHandle, quote(newName))) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.screenName = r[1] - return r - return d.addCallback(_cb) - - def requestSwitchboardServer(self): - """ - Used to request a switchboard server to use for conversations. - - @return: A Deferred, the callback for which will be called when - the server responds with the switchboard information. - The callback argument will be a tuple with 3 elements: - the host of the switchboard server, the port and a key - used for logging in. - """ - - id, d = self._createIDMapping() - self.sendLine("XFR %s SB" % id) - return d - - def logOut(self): - """ - Used to log out of the notification server. - After running the method the server is expected - to close the connection. - """ - - self.sendLine("OUT") - -class NotificationFactory(ClientFactory): - """ - Factory for the NotificationClient protocol. - This is basically responsible for keeping - the state of the client and thus should be used - in a 1:1 situation with clients. - - @ivar contacts: An MSNContactList instance reflecting - the current contact list -- this is - generally kept up to date by the default - command handlers. - @ivar userHandle: The client's userHandle, this is expected - to be set by the client and is used by the - protocol (for logging in etc). - @ivar screenName: The client's current screen-name -- this is - generally kept up to date by the default - command handlers. - @ivar password: The client's password -- this is (obviously) - expected to be set by the client. - @ivar passportServer: This must point to an msn passport server - (the whole URL is required) - @ivar status: The status of the client -- this is generally kept - up to date by the default command handlers - """ - - contacts = None - userHandle = '' - screenName = '' - password = '' - passportServer = 'https://nexus.passport.com/rdr/pprdr.asp' - status = 'FLN' - protocol = NotificationClient - - -# XXX: A lot of the state currently kept in -# instances of SwitchboardClient is likely to -# be moved into a factory at some stage in the -# future - -class SwitchboardClient(MSNEventBase): - """ - This class provides support for clients connecting to a switchboard server. - - Switchboard servers are used for conversations with other people - on the MSN network. This means that the number of conversations at - any given time will be directly proportional to the number of - connections to varioius switchboard servers. - - MSN makes no distinction between single and group conversations, - so any number of users may be invited to join a specific conversation - taking place on a switchboard server. - - @ivar key: authorization key, obtained when receiving - invitation / requesting switchboard server. - @ivar userHandle: your user handle (passport) - @ivar sessionID: unique session ID, used if you are replying - to a switchboard invitation - @ivar reply: set this to 1 in connectionMade or before to signifiy - that you are replying to a switchboard invitation. - """ - - key = 0 - userHandle = "" - sessionID = "" - reply = 0 - - _iCookie = 0 - - def __init__(self): - MSNEventBase.__init__(self) - self.pendingUsers = {} - self.cookies = {'iCookies' : {}, 'external' : {}} # will maybe be moved to a factory in the future - - def connectionMade(self): - MSNEventBase.connectionMade(self) - print 'sending initial stuff' - self._sendInit() - - def connectionLost(self, reason): - self.cookies['iCookies'] = {} - self.cookies['external'] = {} - MSNEventBase.connectionLost(self, reason) - - def _sendInit(self): - """ - send initial data based on whether we are replying to an invitation - or starting one. - """ - id = self._nextTransactionID() - if not self.reply: - self.sendLine("USR %s %s %s" % (id, self.userHandle, self.key)) - else: - self.sendLine("ANS %s %s %s %s" % (id, self.userHandle, self.key, self.sessionID)) - - def _newInvitationCookie(self): - self._iCookie += 1 - if self._iCookie > 1000: - self._iCookie = 1 - return self._iCookie - - def _checkTyping(self, message, cTypes): - """ helper method for checkMessage """ - if 'text/x-msmsgscontrol' in cTypes and message.hasHeader('TypingUser'): - self.userTyping(message) - return 1 - - def _checkFileInvitation(self, message, info): - """ helper method for checkMessage """ - guid = info.get('Application-GUID', '').lower() - name = info.get('Application-Name', '').lower() - - # Both fields are required, but we'll let some lazy clients get away - # with only sending a name, if it is easy for us to recognize the - # name (the name is localized, so this check might fail for lazy, - # non-english clients, but I'm not about to include "file transfer" - # in 80 different languages here). - - if name != "file transfer" and guid != classNameToGUID["file transfer"]: - return 0 - try: - cookie = int(info['Invitation-Cookie']) - fileName = info['Application-File'] - fileSize = int(info['Application-FileSize']) - except KeyError: - log.msg('Received munged file transfer request ... ignoring.') - return 0 - self.gotSendRequest(fileName, fileSize, cookie, message) - return 1 - - def _checkFileResponse(self, message, info): - """ helper method for checkMessage """ - try: - cmd = info['Invitation-Command'].upper() - cookie = int(info['Invitation-Cookie']) - except KeyError: - return 0 - accept = (cmd == 'ACCEPT') and 1 or 0 - requested = self.cookies['iCookies'].get(cookie) - if not requested: - return 1 - requested[0].callback((accept, cookie, info)) - del self.cookies['iCookies'][cookie] - return 1 - - def _checkFileInfo(self, message, info): - """ helper method for checkMessage """ - try: - ip = info['IP-Address'] - iCookie = int(info['Invitation-Cookie']) - aCookie = int(info['AuthCookie']) - cmd = info['Invitation-Command'].upper() - port = int(info['Port']) - except KeyError: - return 0 - accept = (cmd == 'ACCEPT') and 1 or 0 - requested = self.cookies['external'].get(iCookie) - if not requested: - return 1 # we didn't ask for this - requested[0].callback((accept, ip, port, aCookie, info)) - del self.cookies['external'][iCookie] - return 1 - - def checkMessage(self, message): - """ - hook for detecting any notification type messages - (e.g. file transfer) - """ - cTypes = [s.lstrip() for s in message.getHeader('Content-Type').split(';')] - if self._checkTyping(message, cTypes): - return 0 - if 'text/x-msmsgsinvite' in cTypes: - # header like info is sent as part of the message body. - info = {} - for line in message.message.split('\r\n'): - try: - key, val = line.split(':') - info[key] = val.lstrip() - except ValueError: - continue - if self._checkFileInvitation(message, info) or self._checkFileInfo(message, info) or self._checkFileResponse(message, info): - return 0 - elif 'text/x-clientcaps' in cTypes: - # do something with capabilities - return 0 - return 1 - - # negotiation - def handle_USR(self, params): - checkParamLen(len(params), 4, 'USR') - if params[1] == "OK": - self.loggedIn() - - # invite a user - def handle_CAL(self, params): - checkParamLen(len(params), 3, 'CAL') - id = int(params[0]) - if params[1].upper() == "RINGING": - self._fireCallback(id, int(params[2])) # session ID as parameter - - # user joined - def handle_JOI(self, params): - checkParamLen(len(params), 2, 'JOI') - self.userJoined(params[0], unquote(params[1])) - - # users participating in the current chat - def handle_IRO(self, params): - checkParamLen(len(params), 5, 'IRO') - self.pendingUsers[params[3]] = unquote(params[4]) - if params[1] == params[2]: - self.gotChattingUsers(self.pendingUsers) - self.pendingUsers = {} - - # finished listing users - def handle_ANS(self, params): - checkParamLen(len(params), 2, 'ANS') - if params[1] == "OK": - self.loggedIn() - - def handle_ACK(self, params): - checkParamLen(len(params), 1, 'ACK') - self._fireCallback(int(params[0]), None) - - def handle_NAK(self, params): - checkParamLen(len(params), 1, 'NAK') - self._fireCallback(int(params[0]), None) - - def handle_BYE(self, params): - #checkParamLen(len(params), 1, 'BYE') # i've seen more than 1 param passed to this - self.userLeft(params[0]) - - # callbacks - - def loggedIn(self): - """ - called when all login details have been negotiated. - Messages can now be sent, or new users invited. - """ - pass - - def gotChattingUsers(self, users): - """ - called after connecting to an existing chat session. - - @param users: A dict mapping user handles to screen names - (current users taking part in the conversation) - """ - pass - - def userJoined(self, userHandle, screenName): - """ - called when a user has joined the conversation. - - @param userHandle: the user handle (passport) of the user - @param screenName: the screen name of the user - """ - pass - - def userLeft(self, userHandle): - """ - called when a user has left the conversation. - - @param userHandle: the user handle (passport) of the user. - """ - pass - - def gotMessage(self, message): - """ - called when we receive a message. - - @param message: the associated MSNMessage object - """ - pass - - def userTyping(self, message): - """ - called when we receive the special type of message notifying - us that a user is typing a message. - - @param message: the associated MSNMessage object - """ - pass - - def gotSendRequest(self, fileName, fileSize, iCookie, message): - """ - called when a contact is trying to send us a file. - To accept or reject this transfer see the - fileInvitationReply method. - - @param fileName: the name of the file - @param fileSize: the size of the file - @param iCookie: the invitation cookie, used so the client can - match up your reply with this request. - @param message: the MSNMessage object which brought about this - invitation (it may contain more information) - """ - pass - - # api calls - - def inviteUser(self, userHandle): - """ - used to invite a user to the current switchboard server. - - @param userHandle: the user handle (passport) of the desired user. - - @return: A Deferred, the callback for which will be called - when the server notifies us that the user has indeed - been invited. The callback argument will be a tuple - with 1 element, the sessionID given to the invited user. - I'm not sure if this is useful or not. - """ - - id, d = self._createIDMapping() - self.sendLine("CAL %s %s" % (id, userHandle)) - return d - - def sendMessage(self, message): - """ - used to send a message. - - @param message: the corresponding MSNMessage object. - - @return: Depending on the value of message.ack. - If set to MSNMessage.MESSAGE_ACK or - MSNMessage.MESSAGE_NACK a Deferred will be returned, - the callback for which will be fired when an ACK or - NACK is received - the callback argument will be - (None,). If set to MSNMessage.MESSAGE_ACK_NONE then - the return value is None. - """ - - if message.ack not in ('A','N'): - id, d = self._nextTransactionID(), None - else: - id, d = self._createIDMapping() - if message.length == 0: - message.length = message._calcMessageLen() - self.sendLine("MSG %s %s %s" % (id, message.ack, message.length)) - # apparently order matters with at least MIME-Version and Content-Type - self.sendLine('MIME-Version: %s' % message.getHeader('MIME-Version')) - self.sendLine('Content-Type: %s' % message.getHeader('Content-Type')) - # send the rest of the headers - for header in [h for h in message.headers.items() if h[0].lower() not in ('mime-version','content-type')]: - self.sendLine("%s: %s" % (header[0], header[1])) - self.transport.write(CR+LF) - self.transport.write(message.message) - return d - - def sendTypingNotification(self): - """ - used to send a typing notification. Upon receiving this - message the official client will display a 'user is typing' - message to all other users in the chat session for 10 seconds. - The official client sends one of these every 5 seconds (I think) - as long as you continue to type. - """ - m = MSNMessage() - m.ack = m.MESSAGE_ACK_NONE - m.setHeader('Content-Type', 'text/x-msmsgscontrol') - m.setHeader('TypingUser', self.userHandle) - m.message = "\r\n" - self.sendMessage(m) - - def sendFileInvitation(self, fileName, fileSize): - """ - send an notification that we want to send a file. - - @param fileName: the file name - @param fileSize: the file size - - @return: A Deferred, the callback of which will be fired - when the user responds to this invitation with an - appropriate message. The callback argument will be - a tuple with 3 elements, the first being 1 or 0 - depending on whether they accepted the transfer - (1=yes, 0=no), the second being an invitation cookie - to identify your follow-up responses and the third being - the message 'info' which is a dict of information they - sent in their reply (this doesn't really need to be used). - If you wish to proceed with the transfer see the - sendTransferInfo method. - """ - cookie = self._newInvitationCookie() - d = Deferred() - m = MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Application-Name: File Transfer\r\n' - m.message += 'Application-GUID: %s\r\n' % (classNameToGUID["file transfer"],) - m.message += 'Invitation-Command: INVITE\r\n' - m.message += 'Invitation-Cookie: %s\r\n' % str(cookie) - m.message += 'Application-File: %s\r\n' % fileName - m.message += 'Application-FileSize: %s\r\n\r\n' % str(fileSize) - m.ack = m.MESSAGE_ACK_NONE - self.sendMessage(m) - self.cookies['iCookies'][cookie] = (d, m) - return d - - def fileInvitationReply(self, iCookie, accept=1): - """ - used to reply to a file transfer invitation. - - @param iCookie: the invitation cookie of the initial invitation - @param accept: whether or not you accept this transfer, - 1 = yes, 0 = no, default = 1. - - @return: A Deferred, the callback for which will be fired when - the user responds with the transfer information. - The callback argument will be a tuple with 5 elements, - whether or not they wish to proceed with the transfer - (1=yes, 0=no), their ip, the port, the authentication - cookie (see FileReceive/FileSend) and the message - info (dict) (in case they send extra header-like info - like Internal-IP, this doesn't necessarily need to be - used). If you wish to proceed with the transfer see - FileReceive. - """ - d = Deferred() - m = MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: %s\r\n' % (accept and 'ACCEPT' or 'CANCEL') - m.message += 'Invitation-Cookie: %s\r\n' % str(iCookie) - if not accept: - m.message += 'Cancel-Code: REJECT\r\n' - m.message += 'Launch-Application: FALSE\r\n' - m.message += 'Request-Data: IP-Address:\r\n' - m.message += '\r\n' - m.ack = m.MESSAGE_ACK_NONE - self.sendMessage(m) - self.cookies['external'][iCookie] = (d, m) - return d - - def sendTransferInfo(self, accept, iCookie, authCookie, ip, port): - """ - send information relating to a file transfer session. - - @param accept: whether or not to go ahead with the transfer - (1=yes, 0=no) - @param iCookie: the invitation cookie of previous replies - relating to this transfer - @param authCookie: the authentication cookie obtained from - an FileSend instance - @param ip: your ip - @param port: the port on which an FileSend protocol is listening. - """ - m = MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: %s\r\n' % (accept and 'ACCEPT' or 'CANCEL') - m.message += 'Invitation-Cookie: %s\r\n' % iCookie - m.message += 'IP-Address: %s\r\n' % ip - m.message += 'Port: %s\r\n' % port - m.message += 'AuthCookie: %s\r\n' % authCookie - m.message += '\r\n' - m.ack = m.MESSAGE_NACK - self.sendMessage(m) - -class FileReceive(LineReceiver): - """ - This class provides support for receiving files from contacts. - - @ivar fileSize: the size of the receiving file. (you will have to set this) - @ivar connected: true if a connection has been established. - @ivar completed: true if the transfer is complete. - @ivar bytesReceived: number of bytes (of the file) received. - This does not include header data. - """ - - def __init__(self, auth, myUserHandle, file, directory="", overwrite=0): - """ - @param auth: auth string received in the file invitation. - @param myUserHandle: your userhandle. - @param file: A string or file object represnting the file - to save data to. - @param directory: optional parameter specifiying the directory. - Defaults to the current directory. - @param overwrite: if true and a file of the same name exists on - your system, it will be overwritten. (0 by default) - """ - self.auth = auth - self.myUserHandle = myUserHandle - self.fileSize = 0 - self.connected = 0 - self.completed = 0 - self.directory = directory - self.bytesReceived = 0 - self.overwrite = overwrite - - # used for handling current received state - self.state = 'CONNECTING' - self.segmentLength = 0 - self.buffer = '' - - if isinstance(file, types.StringType): - path = os.path.join(directory, file) - if os.path.exists(path) and not self.overwrite: - log.msg('File already exists...') - raise IOError, "File Exists" # is this all we should do here? - self.file = open(os.path.join(directory, file), 'wb') - else: - self.file = file - - def connectionMade(self): - self.connected = 1 - self.state = 'INHEADER' - self.sendLine('VER MSNFTP') - - def connectionLost(self, reason): - self.connected = 0 - self.file.close() - - def parseHeader(self, header): - """ parse the header of each 'message' to obtain the segment length """ - - if ord(header[0]) != 0: # they requested that we close the connection - self.transport.loseConnection() - return - try: - extra, factor = header[1:] - except ValueError: - # munged header, ending transfer - self.transport.loseConnection() - raise - extra = ord(extra) - factor = ord(factor) - return factor * 256 + extra - - def lineReceived(self, line): - temp = line.split() - if len(temp) == 1: - params = [] - else: - params = temp[1:] - cmd = temp[0] - handler = getattr(self, "handle_%s" % cmd.upper(), None) - if handler: - handler(params) # try/except - else: - self.handle_UNKNOWN(cmd, params) - - def rawDataReceived(self, data): - bufferLen = len(self.buffer) - if self.state == 'INHEADER': - delim = 3-bufferLen - self.buffer += data[:delim] - if len(self.buffer) == 3: - self.segmentLength = self.parseHeader(self.buffer) - if not self.segmentLength: - return # hrm - self.buffer = "" - self.state = 'INSEGMENT' - extra = data[delim:] - if len(extra) > 0: - self.rawDataReceived(extra) - return - - elif self.state == 'INSEGMENT': - dataSeg = data[:(self.segmentLength-bufferLen)] - self.buffer += dataSeg - self.bytesReceived += len(dataSeg) - if len(self.buffer) == self.segmentLength: - self.gotSegment(self.buffer) - self.buffer = "" - if self.bytesReceived == self.fileSize: - self.completed = 1 - self.buffer = "" - self.file.close() - self.sendLine("BYE 16777989") - return - self.state = 'INHEADER' - extra = data[(self.segmentLength-bufferLen):] - if len(extra) > 0: - self.rawDataReceived(extra) - return - - def handle_VER(self, params): - checkParamLen(len(params), 1, 'VER') - if params[0].upper() == "MSNFTP": - self.sendLine("USR %s %s" % (self.myUserHandle, self.auth)) - else: - log.msg('they sent the wrong version, time to quit this transfer') - self.transport.loseConnection() - - def handle_FIL(self, params): - checkParamLen(len(params), 1, 'FIL') - try: - self.fileSize = int(params[0]) - except ValueError: # they sent the wrong file size - probably want to log this - self.transport.loseConnection() - return - self.setRawMode() - self.sendLine("TFR") - - def handle_UNKNOWN(self, cmd, params): - log.msg('received unknown command (%s), params: %s' % (cmd, params)) - - def gotSegment(self, data): - """ called when a segment (block) of data arrives. """ - self.file.write(data) - -class FileSend(LineReceiver): - """ - This class provides support for sending files to other contacts. - - @ivar bytesSent: the number of bytes that have currently been sent. - @ivar completed: true if the send has completed. - @ivar connected: true if a connection has been established. - @ivar targetUser: the target user (contact). - @ivar segmentSize: the segment (block) size. - @ivar auth: the auth cookie (number) to use when sending the - transfer invitation - """ - - def __init__(self, file): - """ - @param file: A string or file object represnting the file to send. - """ - - if isinstance(file, types.StringType): - self.file = open(file, 'rb') - else: - self.file = file - - self.fileSize = 0 - self.bytesSent = 0 - self.completed = 0 - self.connected = 0 - self.targetUser = None - self.segmentSize = 2045 - self.auth = randint(0, 2**30) - self._pendingSend = None # :( - - def connectionMade(self): - self.connected = 1 - - def connectionLost(self, reason): - if self._pendingSend.active(): - self._pendingSend.cancel() - self._pendingSend = None - if self.bytesSent == self.fileSize: - self.completed = 1 - self.connected = 0 - self.file.close() - - def lineReceived(self, line): - temp = line.split() - if len(temp) == 1: - params = [] - else: - params = temp[1:] - cmd = temp[0] - handler = getattr(self, "handle_%s" % cmd.upper(), None) - if handler: - handler(params) - else: - self.handle_UNKNOWN(cmd, params) - - def handle_VER(self, params): - checkParamLen(len(params), 1, 'VER') - if params[0].upper() == "MSNFTP": - self.sendLine("VER MSNFTP") - else: # they sent some weird version during negotiation, i'm quitting. - self.transport.loseConnection() - - def handle_USR(self, params): - checkParamLen(len(params), 2, 'USR') - self.targetUser = params[0] - if self.auth == int(params[1]): - self.sendLine("FIL %s" % (self.fileSize)) - else: # they failed the auth test, disconnecting. - self.transport.loseConnection() - - def handle_TFR(self, params): - checkParamLen(len(params), 0, 'TFR') - # they are ready for me to start sending - self.sendPart() - - def handle_BYE(self, params): - self.completed = (self.bytesSent == self.fileSize) - self.transport.loseConnection() - - def handle_CCL(self, params): - self.completed = (self.bytesSent == self.fileSize) - self.transport.loseConnection() - - def handle_UNKNOWN(self, cmd, params): - log.msg('received unknown command (%s), params: %s' % (cmd, params)) - - def makeHeader(self, size): - """ make the appropriate header given a specific segment size. """ - quotient, remainder = divmod(size, 256) - return chr(0) + chr(remainder) + chr(quotient) - - def sendPart(self): - """ send a segment of data """ - if not self.connected: - self._pendingSend = None - return # may be buggy (if handle_CCL/BYE is called but self.connected is still 1) - data = self.file.read(self.segmentSize) - if data: - dataSize = len(data) - header = self.makeHeader(dataSize) - self.bytesSent += dataSize - self.transport.write(header + data) - self._pendingSend = reactor.callLater(0, self.sendPart) - else: - self._pendingSend = None - self.completed = 1 - -# mapping of error codes to error messages -errorCodes = { - - 200 : "Syntax error", - 201 : "Invalid parameter", - 205 : "Invalid user", - 206 : "Domain name missing", - 207 : "Already logged in", - 208 : "Invalid username", - 209 : "Invalid screen name", - 210 : "User list full", - 215 : "User already there", - 216 : "User already on list", - 217 : "User not online", - 218 : "Already in mode", - 219 : "User is in the opposite list", - 223 : "Too many groups", - 224 : "Invalid group", - 225 : "User not in group", - 229 : "Group name too long", - 230 : "Cannot remove group 0", - 231 : "Invalid group", - 280 : "Switchboard failed", - 281 : "Transfer to switchboard failed", - - 300 : "Required field missing", - 301 : "Too many FND responses", - 302 : "Not logged in", - - 500 : "Internal server error", - 501 : "Database server error", - 502 : "Command disabled", - 510 : "File operation failed", - 520 : "Memory allocation failed", - 540 : "Wrong CHL value sent to server", - - 600 : "Server is busy", - 601 : "Server is unavaliable", - 602 : "Peer nameserver is down", - 603 : "Database connection failed", - 604 : "Server is going down", - 605 : "Server unavailable", - - 707 : "Could not create connection", - 710 : "Invalid CVR parameters", - 711 : "Write is blocking", - 712 : "Session is overloaded", - 713 : "Too many active users", - 714 : "Too many sessions", - 715 : "Not expected", - 717 : "Bad friend file", - 731 : "Not expected", - - 800 : "Requests too rapid", - - 910 : "Server too busy", - 911 : "Authentication failed", - 912 : "Server too busy", - 913 : "Not allowed when offline", - 914 : "Server too busy", - 915 : "Server too busy", - 916 : "Server too busy", - 917 : "Server too busy", - 918 : "Server too busy", - 919 : "Server too busy", - 920 : "Not accepting new users", - 921 : "Server too busy", - 922 : "Server too busy", - 923 : "No parent consent", - 924 : "Passport account not yet verified" - -} - -# mapping of status codes to readable status format -statusCodes = { - - STATUS_ONLINE : "Online", - STATUS_OFFLINE : "Offline", - STATUS_HIDDEN : "Appear Offline", - STATUS_IDLE : "Idle", - STATUS_AWAY : "Away", - STATUS_BUSY : "Busy", - STATUS_BRB : "Be Right Back", - STATUS_PHONE : "On the Phone", - STATUS_LUNCH : "Out to Lunch" - -} - -# mapping of list ids to list codes -listIDToCode = { - - FORWARD_LIST : 'fl', - BLOCK_LIST : 'bl', - ALLOW_LIST : 'al', - REVERSE_LIST : 'rl' - -} - -# mapping of list codes to list ids -listCodeToID = {} -for id,code in listIDToCode.items(): - listCodeToID[code] = id - -del id, code - -# Mapping of class GUIDs to simple english names -guidToClassName = { - "{5D3E02AB-6190-11d3-BBBB-00C04F795683}": "file transfer", - } - -# Reverse of the above -classNameToGUID = {} -for guid, name in guidToClassName.iteritems(): - classNameToGUID[name] = guid diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/oscar.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/oscar.py deleted file mode 100644 index e28d399..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/protocols/oscar.py +++ /dev/null @@ -1,1234 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -An implementation of the OSCAR protocol, which AIM and ICQ use to communcate. - -Maintainer: Paul Swartz -""" - -import struct -import string -import socket -import random -import types -import re -from hashlib import md5 - -from twisted.internet import reactor, defer, protocol -from twisted.python import log - -def logPacketData(data): - lines = len(data)/16 - if lines*16 != len(data): lines=lines+1 - for i in range(lines): - d = tuple(data[16*i:16*i+16]) - hex = map(lambda x: "%02X"%ord(x),d) - text = map(lambda x: (len(repr(x))>3 and '.') or x, d) - log.msg(' '.join(hex)+ ' '*3*(16-len(d)) +''.join(text)) - log.msg('') - -def SNAC(fam,sub,id,data,flags=[0,0]): - header="!HHBBL" - head=struct.pack(header,fam,sub, - flags[0],flags[1], - id) - return head+str(data) - -def readSNAC(data): - header="!HHBBL" - head=list(struct.unpack(header,data[:10])) - return head+[data[10:]] - -def TLV(type,value): - header="!HH" - head=struct.pack(header,type,len(value)) - return head+str(value) - -def readTLVs(data,count=None): - header="!HH" - dict={} - while data and len(dict)!=count: - head=struct.unpack(header,data[:4]) - dict[head[0]]=data[4:4+head[1]] - data=data[4+head[1]:] - if not count: - return dict - return dict,data - -def encryptPasswordMD5(password,key): - m=md5() - m.update(key) - m.update(md5(password).digest()) - m.update("AOL Instant Messenger (SM)") - return m.digest() - -def encryptPasswordICQ(password): - key=[0xF3,0x26,0x81,0xC4,0x39,0x86,0xDB,0x92,0x71,0xA3,0xB9,0xE6,0x53,0x7A,0x95,0x7C] - bytes=map(ord,password) - r="" - for i in range(len(bytes)): - r=r+chr(bytes[i]^key[i%len(key)]) - return r - -def dehtml(text): - text=string.replace(text,"<br>","\n") - text=string.replace(text,"<BR>","\n") - text=string.replace(text,"<Br>","\n") # XXX make this a regexp - text=string.replace(text,"<bR>","\n") - text=re.sub('<.*?>','',text) - text=string.replace(text,'&gt;','>') - text=string.replace(text,'&lt;','<') - text=string.replace(text,'&nbsp;',' ') - text=string.replace(text,'&#34;','"') - text=string.replace(text,'&amp;','&') - return text - -def html(text): - text=string.replace(text,'"','&#34;') - text=string.replace(text,'&','&amp;') - text=string.replace(text,'<','&lt;') - text=string.replace(text,'>','&gt;') - text=string.replace(text,"\n","<br>") - return '<html><body bgcolor="white"><font color="black">%s</font></body></html>'%text - -class OSCARUser: - def __init__(self, name, warn, tlvs): - self.name = name - self.warning = warn - self.flags = [] - self.caps = [] - for k,v in tlvs.items(): - if k == 1: # user flags - v=struct.unpack('!H',v)[0] - for o, f in [(1,'trial'), - (2,'unknown bit 2'), - (4,'aol'), - (8,'unknown bit 4'), - (16,'aim'), - (32,'away'), - (1024,'activebuddy')]: - if v&o: self.flags.append(f) - elif k == 2: # member since date - self.memberSince = struct.unpack('!L',v)[0] - elif k == 3: # on-since - self.onSince = struct.unpack('!L',v)[0] - elif k == 4: # idle time - self.idleTime = struct.unpack('!H',v)[0] - elif k == 5: # unknown - pass - elif k == 6: # icq online status - if v[2] == '\x00': - self.icqStatus = 'online' - elif v[2] == '\x01': - self.icqStatus = 'away' - elif v[2] == '\x02': - self.icqStatus = 'dnd' - elif v[2] == '\x04': - self.icqStatus = 'out' - elif v[2] == '\x10': - self.icqStatus = 'busy' - else: - self.icqStatus = 'unknown' - elif k == 10: # icq ip address - self.icqIPaddy = socket.inet_ntoa(v) - elif k == 12: # icq random stuff - self.icqRandom = v - elif k == 13: # capabilities - caps=[] - while v: - c=v[:16] - if c==CAP_ICON: caps.append("icon") - elif c==CAP_IMAGE: caps.append("image") - elif c==CAP_VOICE: caps.append("voice") - elif c==CAP_CHAT: caps.append("chat") - elif c==CAP_GET_FILE: caps.append("getfile") - elif c==CAP_SEND_FILE: caps.append("sendfile") - elif c==CAP_SEND_LIST: caps.append("sendlist") - elif c==CAP_GAMES: caps.append("games") - else: caps.append(("unknown",c)) - v=v[16:] - caps.sort() - self.caps=caps - elif k == 14: pass - elif k == 15: # session length (aim) - self.sessionLength = struct.unpack('!L',v)[0] - elif k == 16: # session length (aol) - self.sessionLength = struct.unpack('!L',v)[0] - elif k == 30: # no idea - pass - else: - log.msg("unknown tlv for user %s\nt: %s\nv: %s"%(self.name,k,repr(v))) - - def __str__(self): - s = '<OSCARUser %s' % self.name - o = [] - if self.warning!=0: o.append('warning level %s'%self.warning) - if hasattr(self, 'flags'): o.append('flags %s'%self.flags) - if hasattr(self, 'sessionLength'): o.append('online for %i minutes' % (self.sessionLength/60,)) - if hasattr(self, 'idleTime'): o.append('idle for %i minutes' % self.idleTime) - if self.caps: o.append('caps %s'%self.caps) - if o: - s=s+', '+', '.join(o) - s=s+'>' - return s - - -class SSIGroup: - def __init__(self, name, tlvs = {}): - self.name = name - #self.tlvs = [] - #self.userIDs = [] - self.usersToID = {} - self.users = [] - #if not tlvs.has_key(0xC8): return - #buddyIDs = tlvs[0xC8] - #while buddyIDs: - # bid = struct.unpack('!H',buddyIDs[:2])[0] - # buddyIDs = buddyIDs[2:] - # self.users.append(bid) - - def findIDFor(self, user): - return self.usersToID[user] - - def addUser(self, buddyID, user): - self.usersToID[user] = buddyID - self.users.append(user) - user.group = self - - def oscarRep(self, groupID, buddyID): - tlvData = TLV(0xc8, reduce(lambda x,y:x+y, [struct.pack('!H',self.usersToID[x]) for x in self.users])) - return struct.pack('!H', len(self.name)) + self.name + \ - struct.pack('!HH', groupID, buddyID) + '\000\001' + tlvData - - -class SSIBuddy: - def __init__(self, name, tlvs = {}): - self.name = name - self.tlvs = tlvs - for k,v in tlvs.items(): - if k == 0x013c: # buddy comment - self.buddyComment = v - elif k == 0x013d: # buddy alerts - actionFlag = ord(v[0]) - whenFlag = ord(v[1]) - self.alertActions = [] - self.alertWhen = [] - if actionFlag&1: - self.alertActions.append('popup') - if actionFlag&2: - self.alertActions.append('sound') - if whenFlag&1: - self.alertWhen.append('online') - if whenFlag&2: - self.alertWhen.append('unidle') - if whenFlag&4: - self.alertWhen.append('unaway') - elif k == 0x013e: - self.alertSound = v - - def oscarRep(self, groupID, buddyID): - tlvData = reduce(lambda x,y: x+y, map(lambda (k,v):TLV(k,v), self.tlvs.items()), '\000\000') - return struct.pack('!H', len(self.name)) + self.name + \ - struct.pack('!HH', groupID, buddyID) + '\000\000' + tlvData - - -class OscarConnection(protocol.Protocol): - def connectionMade(self): - self.state="" - self.seqnum=0 - self.buf='' - self.stopKeepAliveID = None - self.setKeepAlive(4*60) # 4 minutes - - def connectionLost(self, reason): - log.msg("Connection Lost! %s" % self) - self.stopKeepAlive() - -# def connectionFailed(self): -# log.msg("Connection Failed! %s" % self) -# self.stopKeepAlive() - - def sendFLAP(self,data,channel = 0x02): - header="!cBHH" - self.seqnum=(self.seqnum+1)%0xFFFF - seqnum=self.seqnum - head=struct.pack(header,'*', channel, - seqnum, len(data)) - self.transport.write(head+str(data)) -# if isinstance(self, ChatService): -# logPacketData(head+str(data)) - - def readFlap(self): - header="!cBHH" - if len(self.buf)<6: return - flap=struct.unpack(header,self.buf[:6]) - if len(self.buf)<6+flap[3]: return - data,self.buf=self.buf[6:6+flap[3]],self.buf[6+flap[3]:] - return [flap[1],data] - - def dataReceived(self,data): -# if isinstance(self, ChatService): -# logPacketData(data) - self.buf=self.buf+data - flap=self.readFlap() - while flap: - func=getattr(self,"oscar_%s"%self.state,None) - if not func: - log.msg("no func for state: %s" % self.state) - state=func(flap) - if state: - self.state=state - flap=self.readFlap() - - def setKeepAlive(self,t): - self.keepAliveDelay=t - self.stopKeepAlive() - self.stopKeepAliveID = reactor.callLater(t, self.sendKeepAlive) - - def sendKeepAlive(self): - self.sendFLAP("",0x05) - self.stopKeepAliveID = reactor.callLater(self.keepAliveDelay, self.sendKeepAlive) - - def stopKeepAlive(self): - if self.stopKeepAliveID: - self.stopKeepAliveID.cancel() - self.stopKeepAliveID = None - - def disconnect(self): - """ - send the disconnect flap, and sever the connection - """ - self.sendFLAP('', 0x04) - def f(reason): pass - self.connectionLost = f - self.transport.loseConnection() - - -class SNACBased(OscarConnection): - snacFamilies = { - # family : (version, toolID, toolVersion) - } - def __init__(self,cookie): - self.cookie=cookie - self.lastID=0 - self.supportedFamilies = () - self.requestCallbacks={} # request id:Deferred - - def sendSNAC(self,fam,sub,data,flags=[0,0]): - """ - send a snac and wait for the response by returning a Deferred. - """ - reqid=self.lastID - self.lastID=reqid+1 - d = defer.Deferred() - d.reqid = reqid - - #d.addErrback(self._ebDeferredError,fam,sub,data) # XXX for testing - - self.requestCallbacks[reqid] = d - self.sendFLAP(SNAC(fam,sub,reqid,data)) - return d - - def _ebDeferredError(self, error, fam, sub, data): - log.msg('ERROR IN DEFERRED %s' % error) - log.msg('on sending of message, family 0x%02x, subtype 0x%02x' % (fam, sub)) - log.msg('data: %s' % repr(data)) - - def sendSNACnr(self,fam,sub,data,flags=[0,0]): - """ - send a snac, but don't bother adding a deferred, we don't care. - """ - self.sendFLAP(SNAC(fam,sub,0x10000*fam+sub,data)) - - def oscar_(self,data): - self.sendFLAP("\000\000\000\001"+TLV(6,self.cookie), 0x01) - return "Data" - - def oscar_Data(self,data): - snac=readSNAC(data[1]) - if self.requestCallbacks.has_key(snac[4]): - d = self.requestCallbacks[snac[4]] - del self.requestCallbacks[snac[4]] - if snac[1]!=1: - d.callback(snac) - else: - d.errback(snac) - return - func=getattr(self,'oscar_%02X_%02X'%(snac[0],snac[1]),None) - if not func: - self.oscar_unknown(snac) - else: - func(snac[2:]) - return "Data" - - def oscar_unknown(self,snac): - log.msg("unknown for %s" % self) - log.msg(snac) - - - def oscar_01_03(self, snac): - numFamilies = len(snac[3])/2 - self.supportedFamilies = struct.unpack("!"+str(numFamilies)+'H', snac[3]) - d = '' - for fam in self.supportedFamilies: - if self.snacFamilies.has_key(fam): - d=d+struct.pack('!2H',fam,self.snacFamilies[fam][0]) - self.sendSNACnr(0x01,0x17, d) - - def oscar_01_0A(self,snac): - """ - change of rate information. - """ - # this can be parsed, maybe we can even work it in - pass - - def oscar_01_18(self,snac): - """ - host versions, in the same format as we sent - """ - self.sendSNACnr(0x01,0x06,"") #pass - - def clientReady(self): - """ - called when the client is ready to be online - """ - d = '' - for fam in self.supportedFamilies: - if self.snacFamilies.has_key(fam): - version, toolID, toolVersion = self.snacFamilies[fam] - d = d + struct.pack('!4H',fam,version,toolID,toolVersion) - self.sendSNACnr(0x01,0x02,d) - -class BOSConnection(SNACBased): - snacFamilies = { - 0x01:(3, 0x0110, 0x059b), - 0x13:(3, 0x0110, 0x059b), - 0x02:(1, 0x0110, 0x059b), - 0x03:(1, 0x0110, 0x059b), - 0x04:(1, 0x0110, 0x059b), - 0x06:(1, 0x0110, 0x059b), - 0x08:(1, 0x0104, 0x0001), - 0x09:(1, 0x0110, 0x059b), - 0x0a:(1, 0x0110, 0x059b), - 0x0b:(1, 0x0104, 0x0001), - 0x0c:(1, 0x0104, 0x0001) - } - - capabilities = None - - def __init__(self,username,cookie): - SNACBased.__init__(self,cookie) - self.username=username - self.profile = None - self.awayMessage = None - self.services = {} - - if not self.capabilities: - self.capabilities = [CAP_CHAT] - - def parseUser(self,data,count=None): - l=ord(data[0]) - name=data[1:1+l] - warn,foo=struct.unpack("!HH",data[1+l:5+l]) - warn=int(warn/10) - tlvs=data[5+l:] - if count: - tlvs,rest = readTLVs(tlvs,foo) - else: - tlvs,rest = readTLVs(tlvs), None - u = OSCARUser(name, warn, tlvs) - if rest == None: - return u - else: - return u, rest - - def oscar_01_05(self, snac, d = None): - """ - data for a new service connection - d might be a deferred to be called back when the service is ready - """ - tlvs = readTLVs(snac[3][2:]) - service = struct.unpack('!H',tlvs[0x0d])[0] - ip = tlvs[5] - cookie = tlvs[6] - #c = serviceClasses[service](self, cookie, d) - c = protocol.ClientCreator(reactor, serviceClasses[service], self, cookie, d) - def addService(x): - self.services[service] = x - c.connectTCP(ip, 5190).addCallback(addService) - #self.services[service] = c - - def oscar_01_07(self,snac): - """ - rate parameters - """ - self.sendSNACnr(0x01,0x08,"\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05") # ack - self.initDone() - self.sendSNACnr(0x13,0x02,'') # SSI rights info - self.sendSNACnr(0x02,0x02,'') # location rights info - self.sendSNACnr(0x03,0x02,'') # buddy list rights - self.sendSNACnr(0x04,0x04,'') # ICBM parms - self.sendSNACnr(0x09,0x02,'') # BOS rights - - def oscar_01_10(self,snac): - """ - we've been warned - """ - skip = struct.unpack('!H',snac[3][:2])[0] - newLevel = struct.unpack('!H',snac[3][2+skip:4+skip])[0]/10 - if len(snac[3])>4+skip: - by = self.parseUser(snac[3][4+skip:]) - else: - by = None - self.receiveWarning(newLevel, by) - - def oscar_01_13(self,snac): - """ - MOTD - """ - pass # we don't care for now - - def oscar_02_03(self, snac): - """ - location rights response - """ - tlvs = readTLVs(snac[3]) - self.maxProfileLength = tlvs[1] - - def oscar_03_03(self, snac): - """ - buddy list rights response - """ - tlvs = readTLVs(snac[3]) - self.maxBuddies = tlvs[1] - self.maxWatchers = tlvs[2] - - def oscar_03_0B(self, snac): - """ - buddy update - """ - self.updateBuddy(self.parseUser(snac[3])) - - def oscar_03_0C(self, snac): - """ - buddy offline - """ - self.offlineBuddy(self.parseUser(snac[3])) - -# def oscar_04_03(self, snac): - - def oscar_04_05(self, snac): - """ - ICBM parms response - """ - self.sendSNACnr(0x04,0x02,'\x00\x00\x00\x00\x00\x0b\x1f@\x03\xe7\x03\xe7\x00\x00\x00\x00') # IM rights - - def oscar_04_07(self, snac): - """ - ICBM message (instant message) - """ - data = snac[3] - cookie, data = data[:8], data[8:] - channel = struct.unpack('!H',data[:2])[0] - data = data[2:] - user, data = self.parseUser(data, 1) - tlvs = readTLVs(data) - if channel == 1: # message - flags = [] - multiparts = [] - for k, v in tlvs.items(): - if k == 2: - while v: - v = v[2:] # skip bad data - messageLength, charSet, charSubSet = struct.unpack('!3H', v[:6]) - messageLength -= 4 - message = [v[6:6+messageLength]] - if charSet == 0: - pass # don't add anything special - elif charSet == 2: - message.append('unicode') - elif charSet == 3: - message.append('iso-8859-1') - elif charSet == 0xffff: - message.append('none') - if charSubSet == 0xb: - message.append('macintosh') - if messageLength > 0: multiparts.append(tuple(message)) - v = v[6+messageLength:] - elif k == 3: - flags.append('acknowledge') - elif k == 4: - flags.append('auto') - elif k == 6: - flags.append('offline') - elif k == 8: - iconLength, foo, iconSum, iconStamp = struct.unpack('!LHHL',v) - if iconLength: - flags.append('icon') - flags.append((iconLength, iconSum, iconStamp)) - elif k == 9: - flags.append('buddyrequest') - elif k == 0xb: # unknown - pass - elif k == 0x17: - flags.append('extradata') - flags.append(v) - else: - log.msg('unknown TLV for incoming IM, %04x, %s' % (k,repr(v))) - -# unknown tlv for user SNewdorf -# t: 29 -# v: '\x00\x00\x00\x05\x02\x01\xd2\x04r\x00\x01\x01\x10/\x8c\x8b\x8a\x1e\x94*\xbc\x80}\x8d\xc4;\x1dEM' -# XXX what is this? - self.receiveMessage(user, multiparts, flags) - elif channel == 2: # rondevouz - status = struct.unpack('!H',tlvs[5][:2])[0] - requestClass = tlvs[5][10:26] - moreTLVs = readTLVs(tlvs[5][26:]) - if requestClass == CAP_CHAT: # a chat request - exchange = struct.unpack('!H',moreTLVs[10001][:2])[0] - name = moreTLVs[10001][3:-2] - instance = struct.unpack('!H',moreTLVs[10001][-2:])[0] - if not self.services.has_key(SERVICE_CHATNAV): - self.connectService(SERVICE_CHATNAV,1).addCallback(lambda x: self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, instance).\ - addCallback(self._cbGetChatInfoForInvite, user, moreTLVs[12])) - else: - self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, instance).\ - addCallback(self._cbGetChatInfoForInvite, user, moreTLVs[12]) - elif requestClass == CAP_SEND_FILE: - if moreTLVs.has_key(11): # cancel - log.msg('cancelled file request') - log.msg(status) - return # handle this later - name = moreTLVs[10001][9:-7] - desc = moreTLVs[12] - log.msg('file request from %s, %s, %s' % (user, name, desc)) - self.receiveSendFileRequest(user, name, desc, cookie) - else: - log.msg('unsupported rondevouz: %s' % requestClass) - log.msg(repr(moreTLVs)) - else: - log.msg('unknown channel %02x' % channel) - log.msg(tlvs) - - def _cbGetChatInfoForInvite(self, info, user, message): - apply(self.receiveChatInvite, (user,message)+info) - - def oscar_09_03(self, snac): - """ - BOS rights response - """ - tlvs = readTLVs(snac[3]) - self.maxPermitList = tlvs[1] - self.maxDenyList = tlvs[2] - - def oscar_0B_02(self, snac): - """ - stats reporting interval - """ - self.reportingInterval = struct.unpack('!H',snac[3][:2])[0] - - def oscar_13_03(self, snac): - """ - SSI rights response - """ - #tlvs = readTLVs(snac[3]) - pass # we don't know how to parse this - - # methods to be called by the client, and their support methods - def requestSelfInfo(self): - """ - ask for the OSCARUser for ourselves - """ - d = defer.Deferred() - self.sendSNAC(0x01, 0x0E, '').addCallback(self._cbRequestSelfInfo, d) - return d - - def _cbRequestSelfInfo(self, snac, d): - d.callback(self.parseUser(snac[5])) - - def initSSI(self): - """ - this sends the rate request for family 0x13 (Server Side Information) - so we can then use it - """ - return self.sendSNAC(0x13, 0x02, '').addCallback(self._cbInitSSI) - - def _cbInitSSI(self, snac, d): - return {} # don't even bother parsing this - - def requestSSI(self, timestamp = 0, revision = 0): - """ - request the server side information - if the deferred gets None, it means the SSI is the same - """ - return self.sendSNAC(0x13, 0x05, - struct.pack('!LH',timestamp,revision)).addCallback(self._cbRequestSSI) - - def _cbRequestSSI(self, snac, args = ()): - if snac[1] == 0x0f: # same SSI as we have - return - itemdata = snac[5][3:] - if args: - revision, groups, permit, deny, permitMode, visibility = args - else: - version, revision = struct.unpack('!BH', snac[5][:3]) - groups = {} - permit = [] - deny = [] - permitMode = None - visibility = None - while len(itemdata)>4: - nameLength = struct.unpack('!H', itemdata[:2])[0] - name = itemdata[2:2+nameLength] - groupID, buddyID, itemType, restLength = \ - struct.unpack('!4H', itemdata[2+nameLength:10+nameLength]) - tlvs = readTLVs(itemdata[10+nameLength:10+nameLength+restLength]) - itemdata = itemdata[10+nameLength+restLength:] - if itemType == 0: # buddies - groups[groupID].addUser(buddyID, SSIBuddy(name, tlvs)) - elif itemType == 1: # group - g = SSIGroup(name, tlvs) - if groups.has_key(0): groups[0].addUser(groupID, g) - groups[groupID] = g - elif itemType == 2: # permit - permit.append(name) - elif itemType == 3: # deny - deny.append(name) - elif itemType == 4: # permit deny info - if not tlvs.has_key(0xcb): - continue # this happens with ICQ - permitMode = {1:'permitall',2:'denyall',3:'permitsome',4:'denysome',5:'permitbuddies'}[ord(tlvs[0xca])] - visibility = {'\xff\xff\xff\xff':'all','\x00\x00\x00\x04':'notaim'}[tlvs[0xcb]] - elif itemType == 5: # unknown (perhaps idle data)? - pass - else: - log.msg('%s %s %s %s %s' % (name, groupID, buddyID, itemType, tlvs)) - timestamp = struct.unpack('!L',itemdata)[0] - if not timestamp: # we've got more packets coming - # which means add some deferred stuff - d = defer.Deferred() - self.requestCallbacks[snac[4]] = d - d.addCallback(self._cbRequestSSI, (revision, groups, permit, deny, permitMode, visibility)) - return d - return (groups[0].users,permit,deny,permitMode,visibility,timestamp,revision) - - def activateSSI(self): - """ - active the data stored on the server (use buddy list, permit deny settings, etc.) - """ - self.sendSNACnr(0x13,0x07,'') - - def startModifySSI(self): - """ - tell the OSCAR server to be on the lookout for SSI modifications - """ - self.sendSNACnr(0x13,0x11,'') - - def addItemSSI(self, item, groupID = None, buddyID = None): - """ - add an item to the SSI server. if buddyID == 0, then this should be a group. - this gets a callback when it's finished, but you can probably ignore it. - """ - if groupID is None: - if isinstance(item, SSIGroup): - groupID = 0 - else: - groupID = item.group.group.findIDFor(item.group) - if buddyID is None: - buddyID = item.group.findIDFor(item) - return self.sendSNAC(0x13,0x08, item.oscarRep(groupID, buddyID)) - - def modifyItemSSI(self, item, groupID = None, buddyID = None): - if groupID is None: - if isinstance(item, SSIGroup): - groupID = 0 - else: - groupID = item.group.group.findIDFor(item.group) - if buddyID is None: - buddyID = item.group.findIDFor(item) - return self.sendSNAC(0x13,0x09, item.oscarRep(groupID, buddyID)) - - def delItemSSI(self, item, groupID = None, buddyID = None): - if groupID is None: - if isinstance(item, SSIGroup): - groupID = 0 - else: - groupID = item.group.group.findIDFor(item.group) - if buddyID is None: - buddyID = item.group.findIDFor(item) - return self.sendSNAC(0x13,0x0A, item.oscarRep(groupID, buddyID)) - - def endModifySSI(self): - self.sendSNACnr(0x13,0x12,'') - - def setProfile(self, profile): - """ - set the profile. - send None to not set a profile (different from '' for a blank one) - """ - self.profile = profile - tlvs = '' - if self.profile is not None: - tlvs = TLV(1,'text/aolrtf; charset="us-ascii"') + \ - TLV(2,self.profile) - - tlvs = tlvs + TLV(5, ''.join(self.capabilities)) - self.sendSNACnr(0x02, 0x04, tlvs) - - def setAway(self, away = None): - """ - set the away message, or return (if away == None) - """ - self.awayMessage = away - tlvs = TLV(3,'text/aolrtf; charset="us-ascii"') + \ - TLV(4,away or '') - self.sendSNACnr(0x02, 0x04, tlvs) - - def setIdleTime(self, idleTime): - """ - set our idle time. don't call more than once with a non-0 idle time. - """ - self.sendSNACnr(0x01, 0x11, struct.pack('!L',idleTime)) - - def sendMessage(self, user, message, wantAck = 0, autoResponse = 0, offline = 0 ): \ - #haveIcon = 0, ): - """ - send a message to user (not an OSCARUseR). - message can be a string, or a multipart tuple. - if wantAck, we return a Deferred that gets a callback when the message is sent. - if autoResponse, this message is an autoResponse, as if from an away message. - if offline, this is an offline message (ICQ only, I think) - """ - data = ''.join([chr(random.randrange(0, 127)) for i in range(8)]) # cookie - data = data + '\x00\x01' + chr(len(user)) + user - if not type(message) in (types.TupleType, types.ListType): - message = [[message,]] - if type(message[0][0]) == types.UnicodeType: - message[0].append('unicode') - messageData = '' - for part in message: - charSet = 0 - if 'unicode' in part[1:]: - charSet = 2 - part[0] = part[0].encode('utf-8') - elif 'iso-8859-1' in part[1:]: - charSet = 3 - part[0] = part[0].encode('iso-8859-1') - elif 'none' in part[1:]: - charSet = 0xffff - if 'macintosh' in part[1:]: - charSubSet = 0xb - else: - charSubSet = 0 - messageData = messageData + '\x01\x01' + \ - struct.pack('!3H',len(part[0])+4,charSet,charSubSet) - messageData = messageData + part[0] - data = data + TLV(2, '\x05\x01\x00\x03\x01\x01\x02'+messageData) - if wantAck: - data = data + TLV(3,'') - if autoResponse: - data = data + TLV(4,'') - if offline: - data = data + TLV(6,'') - if wantAck: - return self.sendSNAC(0x04, 0x06, data).addCallback(self._cbSendMessageAck, user, message) - self.sendSNACnr(0x04, 0x06, data) - - def _cbSendMessageAck(self, snac, user, message): - return user, message - - def connectService(self, service, wantCallback = 0, extraData = ''): - """ - connect to another service - if wantCallback, we return a Deferred that gets called back when the service is online. - if extraData, append that to our request. - """ - if wantCallback: - d = defer.Deferred() - self.sendSNAC(0x01,0x04,struct.pack('!H',service) + extraData).addCallback(self._cbConnectService, d) - return d - else: - self.sendSNACnr(0x01,0x04,struct.pack('!H',service)) - - def _cbConnectService(self, snac, d): - self.oscar_01_05(snac[2:], d) - - def createChat(self, shortName): - """ - create a chat room - """ - if self.services.has_key(SERVICE_CHATNAV): - return self.services[SERVICE_CHATNAV].createChat(shortName) - else: - return self.connectService(SERVICE_CHATNAV,1).addCallback(lambda s: s.createChat(shortName)) - - - def joinChat(self, exchange, fullName, instance): - """ - join a chat room - """ - #d = defer.Deferred() - return self.connectService(0x0e, 1, TLV(0x01, struct.pack('!HB',exchange, len(fullName)) + fullName + - struct.pack('!H', instance))).addCallback(self._cbJoinChat) #, d) - #return d - - def _cbJoinChat(self, chat): - del self.services[SERVICE_CHAT] - return chat - - def warnUser(self, user, anon = 0): - return self.sendSNAC(0x04, 0x08, '\x00'+chr(anon)+chr(len(user))+user).addCallback(self._cbWarnUser) - - def _cbWarnUser(self, snac): - oldLevel, newLevel = struct.unpack('!2H', snac[5]) - return oldLevel, newLevel - - def getInfo(self, user): - #if user. - return self.sendSNAC(0x02, 0x05, '\x00\x01'+chr(len(user))+user).addCallback(self._cbGetInfo) - - def _cbGetInfo(self, snac): - user, rest = self.parseUser(snac[5],1) - tlvs = readTLVs(rest) - return tlvs.get(0x02,None) - - def getAway(self, user): - return self.sendSNAC(0x02, 0x05, '\x00\x03'+chr(len(user))+user).addCallback(self._cbGetAway) - - def _cbGetAway(self, snac): - user, rest = self.parseUser(snac[5],1) - tlvs = readTLVs(rest) - return tlvs.get(0x04,None) # return None if there is no away message - - #def acceptSendFileRequest(self, - - # methods to be overridden by the client - def initDone(self): - """ - called when we get the rate information, which means we should do other init. stuff. - """ - log.msg('%s initDone' % self) - pass - - def updateBuddy(self, user): - """ - called when a buddy changes status, with the OSCARUser for that buddy. - """ - log.msg('%s updateBuddy %s' % (self, user)) - pass - - def offlineBuddy(self, user): - """ - called when a buddy goes offline - """ - log.msg('%s offlineBuddy %s' % (self, user)) - pass - - def receiveMessage(self, user, multiparts, flags): - """ - called when someone sends us a message - """ - pass - - def receiveWarning(self, newLevel, user): - """ - called when someone warns us. - user is either None (if it was anonymous) or an OSCARUser - """ - pass - - def receiveChatInvite(self, user, message, exchange, fullName, instance, shortName, inviteTime): - """ - called when someone invites us to a chat room - """ - pass - - def chatReceiveMessage(self, chat, user, message): - """ - called when someone in a chatroom sends us a message in the chat - """ - pass - - def chatMemberJoined(self, chat, member): - """ - called when a member joins the chat - """ - pass - - def chatMemberLeft(self, chat, member): - """ - called when a member leaves the chat - """ - pass - - def receiveSendFileRequest(self, user, file, description, cookie): - """ - called when someone tries to send a file to us - """ - pass - -class OSCARService(SNACBased): - def __init__(self, bos, cookie, d = None): - SNACBased.__init__(self, cookie) - self.bos = bos - self.d = d - - def connectionLost(self, reason): - for k,v in self.bos.services.items(): - if v == self: - del self.bos.services[k] - return - - def clientReady(self): - SNACBased.clientReady(self) - if self.d: - self.d.callback(self) - self.d = None - -class ChatNavService(OSCARService): - snacFamilies = { - 0x01:(3, 0x0010, 0x059b), - 0x0d:(1, 0x0010, 0x059b) - } - def oscar_01_07(self, snac): - # rate info - self.sendSNACnr(0x01, 0x08, '\000\001\000\002\000\003\000\004\000\005') - self.sendSNACnr(0x0d, 0x02, '') - - def oscar_0D_09(self, snac): - self.clientReady() - - def getChatInfo(self, exchange, name, instance): - d = defer.Deferred() - self.sendSNAC(0x0d,0x04,struct.pack('!HB',exchange,len(name)) + \ - name + struct.pack('!HB',instance,2)). \ - addCallback(self._cbGetChatInfo, d) - return d - - def _cbGetChatInfo(self, snac, d): - data = snac[5][4:] - exchange, length = struct.unpack('!HB',data[:3]) - fullName = data[3:3+length] - instance = struct.unpack('!H',data[3+length:5+length])[0] - tlvs = readTLVs(data[8+length:]) - shortName = tlvs[0x6a] - inviteTime = struct.unpack('!L',tlvs[0xca])[0] - info = (exchange,fullName,instance,shortName,inviteTime) - d.callback(info) - - def createChat(self, shortName): - #d = defer.Deferred() - data = '\x00\x04\x06create\xff\xff\x01\x00\x03' - data = data + TLV(0xd7, 'en') - data = data + TLV(0xd6, 'us-ascii') - data = data + TLV(0xd3, shortName) - return self.sendSNAC(0x0d, 0x08, data).addCallback(self._cbCreateChat) - #return d - - def _cbCreateChat(self, snac): #d): - exchange, length = struct.unpack('!HB',snac[5][4:7]) - fullName = snac[5][7:7+length] - instance = struct.unpack('!H',snac[5][7+length:9+length])[0] - #d.callback((exchange, fullName, instance)) - return exchange, fullName, instance - -class ChatService(OSCARService): - snacFamilies = { - 0x01:(3, 0x0010, 0x059b), - 0x0E:(1, 0x0010, 0x059b) - } - def __init__(self,bos,cookie, d = None): - OSCARService.__init__(self,bos,cookie,d) - self.exchange = None - self.fullName = None - self.instance = None - self.name = None - self.members = None - - clientReady = SNACBased.clientReady # we'll do our own callback - - def oscar_01_07(self,snac): - self.sendSNAC(0x01,0x08,"\000\001\000\002\000\003\000\004\000\005") - self.clientReady() - - def oscar_0E_02(self, snac): -# try: # this is EVIL -# data = snac[3][4:] -# self.exchange, length = struct.unpack('!HB',data[:3]) -# self.fullName = data[3:3+length] -# self.instance = struct.unpack('!H',data[3+length:5+length])[0] -# tlvs = readTLVs(data[8+length:]) -# self.name = tlvs[0xd3] -# self.d.callback(self) -# except KeyError: - data = snac[3] - self.exchange, length = struct.unpack('!HB',data[:3]) - self.fullName = data[3:3+length] - self.instance = struct.unpack('!H',data[3+length:5+length])[0] - tlvs = readTLVs(data[8+length:]) - self.name = tlvs[0xd3] - self.d.callback(self) - - def oscar_0E_03(self,snac): - users=[] - rest=snac[3] - while rest: - user, rest = self.bos.parseUser(rest, 1) - users.append(user) - if not self.fullName: - self.members = users - else: - self.members.append(users[0]) - self.bos.chatMemberJoined(self,users[0]) - - def oscar_0E_04(self,snac): - user=self.bos.parseUser(snac[3]) - for u in self.members: - if u.name == user.name: # same person! - self.members.remove(u) - self.bos.chatMemberLeft(self,user) - - def oscar_0E_06(self, snac): - user, rest = self.bos.parseUser(snac[3][14:], 1) - tlvs = readTLVs(rest[8:]) - message = tlvs[1] - self.bos.chatReceiveMessage(self, user, message) - - def sendMessage(self,message): - tlvs=TLV(0x02,"us-ascii")+TLV(0x03,"en")+TLV(0x01,message) - self.sendSNAC(0x0e,0x05, - "\x46\x30\x38\x30\x44\x00\x63\x00\x00\x03\x00\x01\x00\x00\x00\x06\x00\x00\x00\x05"+ - struct.pack("!H",len(tlvs))+ - tlvs) - - def leaveChat(self): - self.disconnect() - -class OscarAuthenticator(OscarConnection): - BOSClass = BOSConnection - def __init__(self,username,password,deferred=None,icq=0): - self.username=username - self.password=password - self.deferred=deferred - self.icq=icq # icq mode is disabled - #if icq and self.BOSClass==BOSConnection: - # self.BOSClass=ICQConnection - - def oscar_(self,flap): - if not self.icq: - self.sendFLAP("\000\000\000\001", 0x01) - self.sendFLAP(SNAC(0x17,0x06,0, - TLV(TLV_USERNAME,self.username)+ - TLV(0x004B,''))) - self.state="Key" - else: - encpass=encryptPasswordICQ(self.password) - self.sendFLAP('\000\000\000\001'+ - TLV(0x01,self.username)+ - TLV(0x02,encpass)+ - TLV(0x03,'ICQ Inc. - Product of ICQ (TM).2001b.5.18.1.3659.85')+ - TLV(0x16,"\x01\x0a")+ - TLV(0x17,"\x00\x05")+ - TLV(0x18,"\x00\x12")+ - TLV(0x19,"\000\001")+ - TLV(0x1a,"\x0eK")+ - TLV(0x14,"\x00\x00\x00U")+ - TLV(0x0f,"en")+ - TLV(0x0e,"us"),0x01) - self.state="Cookie" - - def oscar_Key(self,data): - snac=readSNAC(data[1]) - key=snac[5][2:] - encpass=encryptPasswordMD5(self.password,key) - self.sendFLAP(SNAC(0x17,0x02,0, - TLV(TLV_USERNAME,self.username)+ - TLV(TLV_PASSWORD,encpass)+ - TLV(0x004C, '')+ # unknown - TLV(TLV_CLIENTNAME,"AOL Instant Messenger (SM), version 4.8.2790/WIN32")+ - TLV(0x0016,"\x01\x09")+ - TLV(TLV_CLIENTMAJOR,"\000\004")+ - TLV(TLV_CLIENTMINOR,"\000\010")+ - TLV(0x0019,"\000\000")+ - TLV(TLV_CLIENTSUB,"\x0A\xE6")+ - TLV(0x0014,"\x00\x00\x00\xBB")+ - TLV(TLV_LANG,"en")+ - TLV(TLV_COUNTRY,"us")+ - TLV(TLV_USESSI,"\001"))) - return "Cookie" - - def oscar_Cookie(self,data): - snac=readSNAC(data[1]) - if self.icq: - i=snac[5].find("\000") - snac[5]=snac[5][i:] - tlvs=readTLVs(snac[5]) - if tlvs.has_key(6): - self.cookie=tlvs[6] - server,port=string.split(tlvs[5],":") - d = self.connectToBOS(server, int(port)) - d.addErrback(lambda x: log.msg("Connection Failed! Reason: %s" % x)) - if self.deferred: - d.chainDeferred(self.deferred) - self.disconnect() - elif tlvs.has_key(8): - errorcode=tlvs[8] - errorurl=tlvs[4] - if errorcode=='\000\030': - error="You are attempting to sign on again too soon. Please try again later." - elif errorcode=='\000\005': - error="Invalid Username or Password." - else: error=repr(errorcode) - self.error(error,errorurl) - else: - log.msg('hmm, weird tlvs for %s cookie packet' % str(self)) - log.msg(tlvs) - log.msg('snac') - log.msg(str(snac)) - return "None" - - def oscar_None(self,data): pass - - def connectToBOS(self, server, port): - c = protocol.ClientCreator(reactor, self.BOSClass, self.username, self.cookie) - return c.connectTCP(server, int(port)) - - def error(self,error,url): - log.msg("ERROR! %s %s" % (error,url)) - if self.deferred: self.deferred.errback((error,url)) - self.transport.loseConnection() - -FLAP_CHANNEL_NEW_CONNECTION = 0x01 -FLAP_CHANNEL_DATA = 0x02 -FLAP_CHANNEL_ERROR = 0x03 -FLAP_CHANNEL_CLOSE_CONNECTION = 0x04 - -SERVICE_CHATNAV = 0x0d -SERVICE_CHAT = 0x0e -serviceClasses = { - SERVICE_CHATNAV:ChatNavService, - SERVICE_CHAT:ChatService -} -TLV_USERNAME = 0x0001 -TLV_CLIENTNAME = 0x0003 -TLV_COUNTRY = 0x000E -TLV_LANG = 0x000F -TLV_CLIENTMAJOR = 0x0017 -TLV_CLIENTMINOR = 0x0018 -TLV_CLIENTSUB = 0x001A -TLV_PASSWORD = 0x0025 -TLV_USESSI = 0x004A - -CAP_ICON = '\011F\023FL\177\021\321\202"DEST\000\000' -CAP_VOICE = '\011F\023AL\177\021\321\202"DEST\000\000' -CAP_IMAGE = '\011F\023EL\177\021\321\202"DEST\000\000' -CAP_CHAT = 't\217$ b\207\021\321\202"DEST\000\000' -CAP_GET_FILE = '\011F\023HL\177\021\321\202"DEST\000\000' -CAP_SEND_FILE = '\011F\023CL\177\021\321\202"DEST\000\000' -CAP_GAMES = '\011F\023GL\177\021\321\202"DEST\000\000' -CAP_SEND_LIST = '\011F\023KL\177\021\321\202"DEST\000\000' -CAP_SERV_REL = '\011F\023IL\177\021\321\202"DEST\000\000' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/service.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/service.py deleted file mode 100644 index 92b7fd2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/service.py +++ /dev/null @@ -1,1224 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_service -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A module that needs a better name. - -Implements new cred things for words. - -How does this thing work? - - - Network connection on some port expecting to speak some protocol - - - Protocol-specific authentication, resulting in some kind of credentials object - - - twisted.cred.portal login using those credentials for the interface - IUser and with something implementing IChatClient as the mind - - - successful login results in an IUser avatar the protocol can call - methods on, and state added to the realm such that the mind will have - methods called on it as is necessary - - - protocol specific actions lead to calls onto the avatar; remote events - lead to calls onto the mind - - - protocol specific hangup, realm is notified, user is removed from active - play, the end. -""" - -from time import time, ctime - -from zope.interface import implements - -from twisted.words import iwords, ewords - -from twisted.python.components import registerAdapter -from twisted.cred import portal, credentials, error as ecred -from twisted.spread import pb -from twisted.words.protocols import irc -from twisted.internet import defer, protocol -from twisted.python import log, failure, reflect -from twisted import copyright - - -class Group(object): - implements(iwords.IGroup) - - def __init__(self, name): - self.name = name - self.users = {} - self.meta = { - "topic": "", - "topic_author": "", - } - - - def _ebUserCall(self, err, p): - return failure.Failure(Exception(p, err)) - - - def _cbUserCall(self, results): - for (success, result) in results: - if not success: - user, err = result.value # XXX - self.remove(user, err.getErrorMessage()) - - - def add(self, user): - assert iwords.IChatClient.providedBy(user), "%r is not a chat client" % (user,) - if user.name not in self.users: - additions = [] - self.users[user.name] = user - for p in self.users.itervalues(): - if p is not user: - d = defer.maybeDeferred(p.userJoined, self, user) - d.addErrback(self._ebUserCall, p=p) - additions.append(d) - defer.DeferredList(additions).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def remove(self, user, reason=None): - assert reason is None or isinstance(reason, unicode) - try: - del self.users[user.name] - except KeyError: - pass - else: - removals = [] - for p in self.users.itervalues(): - if p is not user: - d = defer.maybeDeferred(p.userLeft, self, user, reason) - d.addErrback(self._ebUserCall, p=p) - removals.append(d) - defer.DeferredList(removals).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def size(self): - return defer.succeed(len(self.users)) - - - def receive(self, sender, recipient, message): - assert recipient is self - receives = [] - for p in self.users.itervalues(): - if p is not sender: - d = defer.maybeDeferred(p.receive, sender, self, message) - d.addErrback(self._ebUserCall, p=p) - receives.append(d) - defer.DeferredList(receives).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def setMetadata(self, meta): - self.meta = meta - sets = [] - for p in self.users.itervalues(): - d = defer.maybeDeferred(p.groupMetaUpdate, self, meta) - d.addErrback(self._ebUserCall, p=p) - sets.append(d) - defer.DeferredList(sets).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def iterusers(self): - # XXX Deferred? - return iter(self.users.values()) - - -class User(object): - implements(iwords.IUser) - - realm = None - mind = None - - def __init__(self, name): - self.name = name - self.groups = [] - self.lastMessage = time() - - - def loggedIn(self, realm, mind): - self.realm = realm - self.mind = mind - self.signOn = time() - - - def join(self, group): - def cbJoin(result): - self.groups.append(group) - return result - return group.add(self.mind).addCallback(cbJoin) - - - def leave(self, group, reason=None): - def cbLeave(result): - self.groups.remove(group) - return result - return group.remove(self.mind, reason).addCallback(cbLeave) - - - def send(self, recipient, message): - self.lastMessage = time() - return recipient.receive(self.mind, recipient, message) - - - def itergroups(self): - return iter(self.groups) - - - def logout(self): - for g in self.groups[:]: - self.leave(g) - - -NICKSERV = 'NickServ!NickServ@services' - - -class IRCUser(irc.IRC): - """ - Protocol instance representing an IRC user connected to the server. - """ - implements(iwords.IChatClient) - - # A list of IGroups in which I am participating - groups = None - - # A no-argument callable I should invoke when I go away - logout = None - - # An IUser we use to interact with the chat service - avatar = None - - # To whence I belong - realm = None - - # How to handle unicode (TODO: Make this customizable on a per-user basis) - encoding = 'utf-8' - - # Twisted callbacks - def connectionMade(self): - self.irc_PRIVMSG = self.irc_NICKSERV_PRIVMSG - self.realm = self.factory.realm - self.hostname = self.realm.name - - - def connectionLost(self, reason): - if self.logout is not None: - self.logout() - self.avatar = None - - - # Make sendMessage a bit more useful to us - def sendMessage(self, command, *parameter_list, **kw): - if 'prefix' not in kw: - kw['prefix'] = self.hostname - if 'to' not in kw: - kw['to'] = self.name.encode(self.encoding) - - arglist = [self, command, kw['to']] + list(parameter_list) - irc.IRC.sendMessage(*arglist, **kw) - - - # IChatClient implementation - def userJoined(self, group, user): - self.join( - "%s!%s@%s" % (user.name, user.name, self.hostname), - '#' + group.name) - - - def userLeft(self, group, user, reason=None): - assert reason is None or isinstance(reason, unicode) - self.part( - "%s!%s@%s" % (user.name, user.name, self.hostname), - '#' + group.name, - (reason or u"leaving").encode(self.encoding, 'replace')) - - - def receive(self, sender, recipient, message): - #>> :glyph!glyph@adsl-64-123-27-108.dsl.austtx.swbell.net PRIVMSG glyph_ :hello - - # omg??????????? - if iwords.IGroup.providedBy(recipient): - recipientName = '#' + recipient.name - else: - recipientName = recipient.name - - text = message.get('text', '<an unrepresentable message>') - for L in text.splitlines(): - self.privmsg( - '%s!%s@%s' % (sender.name, sender.name, self.hostname), - recipientName, - L) - - - def groupMetaUpdate(self, group, meta): - if 'topic' in meta: - topic = meta['topic'] - author = meta.get('topic_author', '') - self.topic( - self.name, - '#' + group.name, - topic, - '%s!%s@%s' % (author, author, self.hostname) - ) - - # irc.IRC callbacks - starting with login related stuff. - nickname = None - password = None - - def irc_PASS(self, prefix, params): - """Password message -- Register a password. - - Parameters: <password> - - [REQUIRED] - - Note that IRC requires the client send this *before* NICK - and USER. - """ - self.password = params[-1] - - - def irc_NICK(self, prefix, params): - """Nick message -- Set your nickname. - - Parameters: <nickname> - - [REQUIRED] - """ - nickname = params[0] - try: - nickname = nickname.decode(self.encoding) - except UnicodeDecodeError: - self.privmsg( - NICKSERV, - nickname, - 'Your nickname cannot be decoded. Please use ASCII or UTF-8.') - self.transport.loseConnection() - return - - self.nickname = nickname - self.name = nickname - - for code, text in self._motdMessages: - self.sendMessage(code, text % self.factory._serverInfo) - - if self.password is None: - self.privmsg( - NICKSERV, - nickname, - 'Password?') - else: - password = self.password - self.password = None - self.logInAs(nickname, password) - - - def irc_USER(self, prefix, params): - """User message -- Set your realname. - - Parameters: <user> <mode> <unused> <realname> - """ - # Note: who gives a crap about this? The IUser has the real - # information we care about. Save it anyway, I guess, just - # for fun. - self.realname = params[-1] - - - def irc_NICKSERV_PRIVMSG(self, prefix, params): - """Send a (private) message. - - Parameters: <msgtarget> <text to be sent> - """ - target = params[0] - password = params[-1] - - if self.nickname is None: - # XXX Send an error response here - self.transport.loseConnection() - elif target.lower() != "nickserv": - self.privmsg( - NICKSERV, - self.nickname, - "Denied. Please send me (NickServ) your password.") - else: - nickname = self.nickname - self.nickname = None - self.logInAs(nickname, password) - - - def logInAs(self, nickname, password): - d = self.factory.portal.login( - credentials.UsernamePassword(nickname, password), - self, - iwords.IUser) - d.addCallbacks(self._cbLogin, self._ebLogin, errbackArgs=(nickname,)) - - - _welcomeMessages = [ - (irc.RPL_WELCOME, - ":connected to Twisted IRC"), - (irc.RPL_YOURHOST, - ":Your host is %(serviceName)s, running version %(serviceVersion)s"), - (irc.RPL_CREATED, - ":This server was created on %(creationDate)s"), - - # "Bummer. This server returned a worthless 004 numeric. - # I'll have to guess at all the values" - # -- epic - (irc.RPL_MYINFO, - # w and n are the currently supported channel and user modes - # -- specify this better - "%(serviceName)s %(serviceVersion)s w n") - ] - - _motdMessages = [ - (irc.RPL_MOTDSTART, - ":- %(serviceName)s Message of the Day - "), - (irc.RPL_ENDOFMOTD, - ":End of /MOTD command.") - ] - - def _cbLogin(self, (iface, avatar, logout)): - assert iface is iwords.IUser, "Realm is buggy, got %r" % (iface,) - - # Let them send messages to the world - del self.irc_PRIVMSG - - self.avatar = avatar - self.logout = logout - for code, text in self._welcomeMessages: - self.sendMessage(code, text % self.factory._serverInfo) - - - def _ebLogin(self, err, nickname): - if err.check(ewords.AlreadyLoggedIn): - self.privmsg( - NICKSERV, - nickname, - "Already logged in. No pod people allowed!") - elif err.check(ecred.UnauthorizedLogin): - self.privmsg( - NICKSERV, - nickname, - "Login failed. Goodbye.") - else: - log.msg("Unhandled error during login:") - log.err(err) - self.privmsg( - NICKSERV, - nickname, - "Server error during login. Sorry.") - self.transport.loseConnection() - - - # Great, now that's out of the way, here's some of the interesting - # bits - def irc_PING(self, prefix, params): - """Ping message - - Parameters: <server1> [ <server2> ] - """ - if self.realm is not None: - self.sendMessage('PONG', self.hostname) - - - def irc_QUIT(self, prefix, params): - """Quit - - Parameters: [ <Quit Message> ] - """ - self.transport.loseConnection() - - - def _channelMode(self, group, modes=None, *args): - if modes: - self.sendMessage( - irc.ERR_UNKNOWNMODE, - ":Unknown MODE flag.") - else: - self.channelMode(self.name, '#' + group.name, '+') - - - def _userMode(self, user, modes=None): - if modes: - self.sendMessage( - irc.ERR_UNKNOWNMODE, - ":Unknown MODE flag.") - elif user is self.avatar: - self.sendMessage( - irc.RPL_UMODEIS, - "+") - else: - self.sendMessage( - irc.ERR_USERSDONTMATCH, - ":You can't look at someone else's modes.") - - - def irc_MODE(self, prefix, params): - """User mode message - - Parameters: <nickname> - *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) ) - - """ - try: - channelOrUser = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, params[0], - ":No such nickname (could not decode your unicode!)") - return - - if channelOrUser.startswith('#'): - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":That channel doesn't exist.") - d = self.realm.lookupGroup(channelOrUser[1:]) - d.addCallbacks( - self._channelMode, - ebGroup, - callbackArgs=tuple(params[1:])) - else: - def ebUser(err): - self.sendMessage( - irc.ERR_NOSUCHNICK, - ":No such nickname.") - - d = self.realm.lookupUser(channelOrUser) - d.addCallbacks( - self._userMode, - ebUser, - callbackArgs=tuple(params[1:])) - - - def irc_USERHOST(self, prefix, params): - """Userhost message - - Parameters: <nickname> *( SPACE <nickname> ) - - [Optional] - """ - pass - - - def irc_PRIVMSG(self, prefix, params): - """Send a (private) message. - - Parameters: <msgtarget> <text to be sent> - """ - try: - targetName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, params[0], - ":No such nick/channel (could not decode your unicode!)") - return - - messageText = params[-1] - if targetName.startswith('#'): - target = self.realm.lookupGroup(targetName[1:]) - else: - target = self.realm.lookupUser(targetName).addCallback(lambda user: user.mind) - - def cbTarget(targ): - if targ is not None: - return self.avatar.send(targ, {"text": messageText}) - - def ebTarget(err): - self.sendMessage( - irc.ERR_NOSUCHNICK, targetName, - ":No such nick/channel.") - - target.addCallbacks(cbTarget, ebTarget) - - - def irc_JOIN(self, prefix, params): - """Join message - - Parameters: ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) - """ - try: - groupName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":No such channel (could not decode your unicode!)") - return - - if groupName.startswith('#'): - groupName = groupName[1:] - - def cbGroup(group): - def cbJoin(ign): - self.userJoined(group, self) - self.names( - self.name, - '#' + group.name, - [user.name for user in group.iterusers()]) - self._sendTopic(group) - return self.avatar.join(group).addCallback(cbJoin) - - def ebGroup(err): - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '#' + groupName, - ":No such channel.") - - self.realm.getGroup(groupName).addCallbacks(cbGroup, ebGroup) - - - def irc_PART(self, prefix, params): - """Part message - - Parameters: <channel> *( "," <channel> ) [ <Part Message> ] - """ - try: - groupName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOTONCHANNEL, params[0], - ":Could not decode your unicode!") - return - - if groupName.startswith('#'): - groupName = groupName[1:] - - if len(params) > 1: - reason = params[1].decode('utf-8') - else: - reason = None - - def cbGroup(group): - def cbLeave(result): - self.userLeft(group, self, reason) - return self.avatar.leave(group, reason).addCallback(cbLeave) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOTONCHANNEL, - '#' + groupName, - ":" + err.getErrorMessage()) - - self.realm.lookupGroup(groupName).addCallbacks(cbGroup, ebGroup) - - - def irc_NAMES(self, prefix, params): - """Names message - - Parameters: [ <channel> *( "," <channel> ) [ <target> ] ] - """ - #<< NAMES #python - #>> :benford.openprojects.net 353 glyph = #python :Orban ... @glyph ... Zymurgy skreech - #>> :benford.openprojects.net 366 glyph #python :End of /NAMES list. - try: - channel = params[-1].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[-1], - ":No such channel (could not decode your unicode!)") - return - - if channel.startswith('#'): - channel = channel[1:] - - def cbGroup(group): - self.names( - self.name, - '#' + group.name, - [user.name for user in group.iterusers()]) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - # No group? Fine, no names! - self.names( - self.name, - '#' + channel, - []) - - self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup) - - - def irc_TOPIC(self, prefix, params): - """Topic message - - Parameters: <channel> [ <topic> ] - """ - try: - channel = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, - ":That channel doesn't exist (could not decode your unicode!)") - return - - if channel.startswith('#'): - channel = channel[1:] - - if len(params) > 1: - self._setTopic(channel, params[1]) - else: - self._getTopic(channel) - - - def _sendTopic(self, group): - """ - Send the topic of the given group to this user, if it has one. - """ - topic = group.meta.get("topic") - if topic: - author = group.meta.get("topic_author") or "<noone>" - date = group.meta.get("topic_date", 0) - self.topic(self.name, '#' + group.name, topic) - self.topicAuthor(self.name, '#' + group.name, author, date) - - - def _getTopic(self, channel): - #<< TOPIC #python - #>> :benford.openprojects.net 332 glyph #python :<churchr> I really did. I sprained all my toes. - #>> :benford.openprojects.net 333 glyph #python itamar|nyc 994713482 - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '=', channel, - ":That channel doesn't exist.") - - self.realm.lookupGroup(channel).addCallbacks(self._sendTopic, ebGroup) - - - def _setTopic(self, channel, topic): - #<< TOPIC #divunal :foo - #>> :glyph!glyph@adsl-64-123-27-108.dsl.austtx.swbell.net TOPIC #divunal :foo - - def cbGroup(group): - newMeta = group.meta.copy() - newMeta['topic'] = topic - newMeta['topic_author'] = self.name - newMeta['topic_date'] = int(time()) - - def ebSet(err): - self.sendMessage( - irc.ERR_CHANOPRIVSNEEDED, - "#" + group.name, - ":You need to be a channel operator to do that.") - - return group.setMetadata(newMeta).addErrback(ebSet) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '=', channel, - ":That channel doesn't exist.") - - self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup) - - - def list(self, channels): - """Send a group of LIST response lines - - @type channel: C{list} of C{(str, int, str)} - @param channel: Information about the channels being sent: - their name, the number of participants, and their topic. - """ - for (name, size, topic) in channels: - self.sendMessage(irc.RPL_LIST, name, str(size), ":" + topic) - self.sendMessage(irc.RPL_LISTEND, ":End of /LIST") - - - def irc_LIST(self, prefix, params): - """List query - - Return information about the indicated channels, or about all - channels if none are specified. - - Parameters: [ <channel> *( "," <channel> ) [ <target> ] ] - """ - #<< list #python - #>> :orwell.freenode.net 321 exarkun Channel :Users Name - #>> :orwell.freenode.net 322 exarkun #python 358 :The Python programming language - #>> :orwell.freenode.net 323 exarkun :End of /LIST - if params: - # Return information about indicated channels - try: - channels = params[0].decode(self.encoding).split(',') - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":No such channel (could not decode your unicode!)") - return - - groups = [] - for ch in channels: - if ch.startswith('#'): - ch = ch[1:] - groups.append(self.realm.lookupGroup(ch)) - - groups = defer.DeferredList(groups, consumeErrors=True) - groups.addCallback(lambda gs: [r for (s, r) in gs if s]) - else: - # Return information about all channels - groups = self.realm.itergroups() - - def cbGroups(groups): - def gotSize(size, group): - return group.name, size, group.meta.get('topic') - d = defer.DeferredList([ - group.size().addCallback(gotSize, group) for group in groups]) - d.addCallback(lambda results: self.list([r for (s, r) in results if s])) - return d - groups.addCallback(cbGroups) - - - def _channelWho(self, group): - self.who(self.name, '#' + group.name, - [(m.name, self.hostname, self.realm.name, m.name, "H", 0, m.name) for m in group.iterusers()]) - - - def _userWho(self, user): - self.sendMessage(irc.RPL_ENDOFWHO, - ":User /WHO not implemented") - - - def irc_WHO(self, prefix, params): - """Who query - - Parameters: [ <mask> [ "o" ] ] - """ - #<< who #python - #>> :x.opn 352 glyph #python aquarius pc-62-31-193-114-du.blueyonder.co.uk y.opn Aquarius H :3 Aquarius - # ... - #>> :x.opn 352 glyph #python foobar europa.tranquility.net z.opn skreech H :0 skreech - #>> :x.opn 315 glyph #python :End of /WHO list. - ### also - #<< who glyph - #>> :x.opn 352 glyph #python glyph adsl-64-123-27-108.dsl.austtx.swbell.net x.opn glyph H :0 glyph - #>> :x.opn 315 glyph glyph :End of /WHO list. - if not params: - self.sendMessage(irc.RPL_ENDOFWHO, ":/WHO not supported.") - return - - try: - channelOrUser = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.RPL_ENDOFWHO, params[0], - ":End of /WHO list (could not decode your unicode!)") - return - - if channelOrUser.startswith('#'): - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.RPL_ENDOFWHO, channelOrUser, - ":End of /WHO list.") - d = self.realm.lookupGroup(channelOrUser[1:]) - d.addCallbacks(self._channelWho, ebGroup) - else: - def ebUser(err): - err.trap(ewords.NoSuchUser) - self.sendMessage( - irc.RPL_ENDOFWHO, channelOrUser, - ":End of /WHO list.") - d = self.realm.lookupUser(channelOrUser) - d.addCallbacks(self._userWho, ebUser) - - - - def irc_WHOIS(self, prefix, params): - """Whois query - - Parameters: [ <target> ] <mask> *( "," <mask> ) - """ - def cbUser(user): - self.whois( - self.name, - user.name, user.name, self.realm.name, - user.name, self.realm.name, 'Hi mom!', False, - int(time() - user.lastMessage), user.signOn, - ['#' + group.name for group in user.itergroups()]) - - def ebUser(err): - err.trap(ewords.NoSuchUser) - self.sendMessage( - irc.ERR_NOSUCHNICK, - params[0], - ":No such nick/channel") - - try: - user = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, - params[0], - ":No such nick/channel") - return - - self.realm.lookupUser(user).addCallbacks(cbUser, ebUser) - - - # Unsupported commands, here for legacy compatibility - def irc_OPER(self, prefix, params): - """Oper message - - Parameters: <name> <password> - """ - self.sendMessage(irc.ERR_NOOPERHOST, ":O-lines not applicable") - - -class IRCFactory(protocol.ServerFactory): - """ - IRC server that creates instances of the L{IRCUser} protocol. - - @ivar _serverInfo: A dictionary mapping: - "serviceName" to the name of the server, - "serviceVersion" to the copyright version, - "creationDate" to the time that the server was started. - """ - protocol = IRCUser - - def __init__(self, realm, portal): - self.realm = realm - self.portal = portal - self._serverInfo = { - "serviceName": self.realm.name, - "serviceVersion": copyright.version, - "creationDate": ctime() - } - - - -class PBMind(pb.Referenceable): - def __init__(self): - pass - - def jellyFor(self, jellier): - return reflect.qual(PBMind), jellier.invoker.registerReference(self) - - def remote_userJoined(self, user, group): - pass - - def remote_userLeft(self, user, group, reason): - pass - - def remote_receive(self, sender, recipient, message): - pass - - def remote_groupMetaUpdate(self, group, meta): - pass - - -class PBMindReference(pb.RemoteReference): - implements(iwords.IChatClient) - - def receive(self, sender, recipient, message): - if iwords.IGroup.providedBy(recipient): - rec = PBGroup(self.realm, self.avatar, recipient) - else: - rec = PBUser(self.realm, self.avatar, recipient) - return self.callRemote( - 'receive', - PBUser(self.realm, self.avatar, sender), - rec, - message) - - def groupMetaUpdate(self, group, meta): - return self.callRemote( - 'groupMetaUpdate', - PBGroup(self.realm, self.avatar, group), - meta) - - def userJoined(self, group, user): - return self.callRemote( - 'userJoined', - PBGroup(self.realm, self.avatar, group), - PBUser(self.realm, self.avatar, user)) - - def userLeft(self, group, user, reason=None): - assert reason is None or isinstance(reason, unicode) - return self.callRemote( - 'userLeft', - PBGroup(self.realm, self.avatar, group), - PBUser(self.realm, self.avatar, user), - reason) -pb.setUnjellyableForClass(PBMind, PBMindReference) - - -class PBGroup(pb.Referenceable): - def __init__(self, realm, avatar, group): - self.realm = realm - self.avatar = avatar - self.group = group - - - def processUniqueID(self): - return hash((self.realm.name, self.avatar.name, self.group.name)) - - - def jellyFor(self, jellier): - return reflect.qual(self.__class__), self.group.name.encode('utf-8'), jellier.invoker.registerReference(self) - - - def remote_leave(self, reason=None): - return self.avatar.leave(self.group, reason) - - - def remote_send(self, message): - return self.avatar.send(self.group, message) - - -class PBGroupReference(pb.RemoteReference): - implements(iwords.IGroup) - - def unjellyFor(self, unjellier, unjellyList): - clsName, name, ref = unjellyList - self.name = name.decode('utf-8') - return pb.RemoteReference.unjellyFor(self, unjellier, [clsName, ref]) - - def leave(self, reason=None): - return self.callRemote("leave", reason) - - def send(self, message): - return self.callRemote("send", message) -pb.setUnjellyableForClass(PBGroup, PBGroupReference) - -class PBUser(pb.Referenceable): - def __init__(self, realm, avatar, user): - self.realm = realm - self.avatar = avatar - self.user = user - - def processUniqueID(self): - return hash((self.realm.name, self.avatar.name, self.user.name)) - - -class ChatAvatar(pb.Referenceable): - implements(iwords.IChatClient) - - def __init__(self, avatar): - self.avatar = avatar - - - def jellyFor(self, jellier): - return reflect.qual(self.__class__), jellier.invoker.registerReference(self) - - - def remote_join(self, groupName): - assert isinstance(groupName, unicode) - def cbGroup(group): - def cbJoin(ignored): - return PBGroup(self.avatar.realm, self.avatar, group) - d = self.avatar.join(group) - d.addCallback(cbJoin) - return d - d = self.avatar.realm.getGroup(groupName) - d.addCallback(cbGroup) - return d -registerAdapter(ChatAvatar, iwords.IUser, pb.IPerspective) - -class AvatarReference(pb.RemoteReference): - def join(self, groupName): - return self.callRemote('join', groupName) - - def quit(self): - d = defer.Deferred() - self.broker.notifyOnDisconnect(lambda: d.callback(None)) - self.broker.transport.loseConnection() - return d - -pb.setUnjellyableForClass(ChatAvatar, AvatarReference) - - -class WordsRealm(object): - implements(portal.IRealm, iwords.IChatService) - - _encoding = 'utf-8' - - def __init__(self, name): - self.name = name - - - def userFactory(self, name): - return User(name) - - - def groupFactory(self, name): - return Group(name) - - - def logoutFactory(self, avatar, facet): - def logout(): - # XXX Deferred support here - getattr(facet, 'logout', lambda: None)() - avatar.realm = avatar.mind = None - return logout - - - def requestAvatar(self, avatarId, mind, *interfaces): - if isinstance(avatarId, str): - avatarId = avatarId.decode(self._encoding) - - def gotAvatar(avatar): - if avatar.realm is not None: - raise ewords.AlreadyLoggedIn() - for iface in interfaces: - facet = iface(avatar, None) - if facet is not None: - avatar.loggedIn(self, mind) - mind.name = avatarId - mind.realm = self - mind.avatar = avatar - return iface, facet, self.logoutFactory(avatar, facet) - raise NotImplementedError(self, interfaces) - - return self.getUser(avatarId).addCallback(gotAvatar) - - - # IChatService, mostly. - createGroupOnRequest = False - createUserOnRequest = True - - def lookupUser(self, name): - raise NotImplementedError - - - def lookupGroup(self, group): - raise NotImplementedError - - - def addUser(self, user): - """Add the given user to this service. - - This is an internal method intented to be overridden by - L{WordsRealm} subclasses, not called by external code. - - @type user: L{IUser} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with C{None} when the user is - added, or which fails with - L{twisted.words.ewords.DuplicateUser} if a user with the - same name exists already. - """ - raise NotImplementedError - - - def addGroup(self, group): - """Add the given group to this service. - - @type group: L{IGroup} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with C{None} when the group is - added, or which fails with - L{twisted.words.ewords.DuplicateGroup} if a group with the - same name exists already. - """ - raise NotImplementedError - - - def getGroup(self, name): - assert isinstance(name, unicode) - if self.createGroupOnRequest: - def ebGroup(err): - err.trap(ewords.DuplicateGroup) - return self.lookupGroup(name) - return self.createGroup(name).addErrback(ebGroup) - return self.lookupGroup(name) - - - def getUser(self, name): - assert isinstance(name, unicode) - if self.createUserOnRequest: - def ebUser(err): - err.trap(ewords.DuplicateUser) - return self.lookupUser(name) - return self.createUser(name).addErrback(ebUser) - return self.lookupUser(name) - - - def createUser(self, name): - assert isinstance(name, unicode) - def cbLookup(user): - return failure.Failure(ewords.DuplicateUser(name)) - def ebLookup(err): - err.trap(ewords.NoSuchUser) - return self.userFactory(name) - - name = name.lower() - d = self.lookupUser(name) - d.addCallbacks(cbLookup, ebLookup) - d.addCallback(self.addUser) - return d - - - def createGroup(self, name): - assert isinstance(name, unicode) - def cbLookup(group): - return failure.Failure(ewords.DuplicateGroup(name)) - def ebLookup(err): - err.trap(ewords.NoSuchGroup) - return self.groupFactory(name) - - name = name.lower() - d = self.lookupGroup(name) - d.addCallbacks(cbLookup, ebLookup) - d.addCallback(self.addGroup) - return d - - -class InMemoryWordsRealm(WordsRealm): - def __init__(self, *a, **kw): - super(InMemoryWordsRealm, self).__init__(*a, **kw) - self.users = {} - self.groups = {} - - - def itergroups(self): - return defer.succeed(self.groups.itervalues()) - - - def addUser(self, user): - if user.name in self.users: - return defer.fail(failure.Failure(ewords.DuplicateUser())) - self.users[user.name] = user - return defer.succeed(user) - - - def addGroup(self, group): - if group.name in self.groups: - return defer.fail(failure.Failure(ewords.DuplicateGroup())) - self.groups[group.name] = group - return defer.succeed(group) - - - def lookupUser(self, name): - assert isinstance(name, unicode) - name = name.lower() - try: - user = self.users[name] - except KeyError: - return defer.fail(failure.Failure(ewords.NoSuchUser(name))) - else: - return defer.succeed(user) - - - def lookupGroup(self, name): - assert isinstance(name, unicode) - name = name.lower() - try: - group = self.groups[name] - except KeyError: - return defer.fail(failure.Failure(ewords.NoSuchGroup(name))) - else: - return defer.succeed(group) - -__all__ = [ - 'Group', 'User', - - 'WordsRealm', 'InMemoryWordsRealm', - ] diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/tap.py deleted file mode 100644 index c0ba9fd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/tap.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_tap -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Shiny new words service maker -""" - -import sys, socket - -from twisted.application import strports -from twisted.application.service import MultiService -from twisted.python import usage -from twisted import plugin - -from twisted.words import iwords, service -from twisted.cred import checkers, credentials, portal, strcred - -class Options(usage.Options, strcred.AuthOptionMixin): - supportedInterfaces = [credentials.IUsernamePassword] - optParameters = [ - ('hostname', None, socket.gethostname(), - 'Name of this server; purely an informative')] - - compData = usage.Completions(multiUse=["group"]) - - interfacePlugins = {} - plg = None - for plg in plugin.getPlugins(iwords.IProtocolPlugin): - assert plg.name not in interfacePlugins - interfacePlugins[plg.name] = plg - optParameters.append(( - plg.name + '-port', - None, None, - 'strports description of the port to bind for the ' + plg.name + ' server')) - del plg - - def __init__(self, *a, **kw): - usage.Options.__init__(self, *a, **kw) - self['groups'] = [] - - def opt_group(self, name): - """Specify a group which should exist - """ - self['groups'].append(name.decode(sys.stdin.encoding)) - - def opt_passwd(self, filename): - """ - Name of a passwd-style file. (This is for - backwards-compatibility only; you should use the --auth - command instead.) - """ - self.addChecker(checkers.FilePasswordDB(filename)) - -def makeService(config): - credCheckers = config.get('credCheckers', []) - wordsRealm = service.InMemoryWordsRealm(config['hostname']) - wordsPortal = portal.Portal(wordsRealm, credCheckers) - - msvc = MultiService() - - # XXX Attribute lookup on config is kind of bad - hrm. - for plgName in config.interfacePlugins: - port = config.get(plgName + '-port') - if port is not None: - factory = config.interfacePlugins[plgName].getFactory(wordsRealm, wordsPortal) - svc = strports.service(port, factory) - svc.setServiceParent(msvc) - - # This is bogus. createGroup is async. makeService must be - # allowed to return a Deferred or some crap. - for g in config['groups']: - wordsRealm.createGroup(g) - - return msvc diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/__init__.py deleted file mode 100644 index d599f20..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"Words tests" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_basechat.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_basechat.py deleted file mode 100644 index 8347d30..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_basechat.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.im.basechat}. -""" - -from twisted.trial import unittest -from twisted.words.im import basechat, basesupport - - -class ChatUITests(unittest.TestCase): - """ - Tests for the L{basechat.ChatUI} chat client. - """ - def setUp(self): - self.ui = basechat.ChatUI() - self.account = basesupport.AbstractAccount("fooAccount", False, "foo", - "password", "host", "port") - self.person = basesupport.AbstractPerson("foo", self.account) - - - def test_contactChangedNickNoKey(self): - """ - L{basechat.ChatUI.contactChangedNick} on an - L{twisted.words.im.interfaces.IPerson} who doesn't have an account - associated with the L{basechat.ChatUI} instance has no effect. - """ - self.assertEqual(self.person.name, "foo") - self.assertEqual(self.person.account, self.account) - - self.ui.contactChangedNick(self.person, "bar") - self.assertEqual(self.person.name, "foo") - self.assertEqual(self.person.account, self.account) - - - def test_contactChangedNickNoConversation(self): - """ - L{basechat.ChatUI.contactChangedNick} changes the name for an - L{twisted.words.im.interfaces.IPerson}. - """ - self.ui.persons[self.person.name, self.person.account] = self.person - - self.assertEqual(self.person.name, "foo") - self.assertEqual(self.person.account, self.account) - - self.ui.contactChangedNick(self.person, "bar") - self.assertEqual(self.person.name, "bar") - self.assertEqual(self.person.account, self.account) - - - def test_contactChangedNickHasConversation(self): - """ - If an L{twisted.words.im.interfaces.IPerson} is in a - L{basechat.Conversation}, L{basechat.ChatUI.contactChangedNick} causes a - name change for that person in both the L{basechat.Conversation} and the - L{basechat.ChatUI}. - """ - self.ui.persons[self.person.name, self.person.account] = self.person - conversation = basechat.Conversation(self.person, self.ui) - self.ui.conversations[self.person] = conversation - - self.assertEqual(self.person.name, "foo") - self.assertEqual(self.person.account, self.account) - - self.ui.contactChangedNick(self.person, "bar") - self.assertEqual(self.person.name, "bar") - self.assertEqual(self.person.account, self.account) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_basesupport.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_basesupport.py deleted file mode 100644 index 3a81963..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_basesupport.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.words.im import basesupport -from twisted.internet import error, defer - -class DummyAccount(basesupport.AbstractAccount): - """ - An account object that will do nothing when asked to start to log on. - """ - - loginHasFailed = False - loginCallbackCalled = False - - def _startLogOn(self, *args): - """ - Set self.loginDeferred to the same as the deferred returned, allowing a - testcase to .callback or .errback. - - @return: A deferred. - """ - self.loginDeferred = defer.Deferred() - return self.loginDeferred - - def _loginFailed(self, result): - self.loginHasFailed = True - return basesupport.AbstractAccount._loginFailed(self, result) - - def _cb_logOn(self, result): - self.loginCallbackCalled = True - return basesupport.AbstractAccount._cb_logOn(self, result) - -class DummyUI(object): - """ - Provide just the interface required to be passed to AbstractAccount.logOn. - """ - clientRegistered = False - - def registerAccountClient(self, result): - self.clientRegistered = True - -class ClientMsgTests(unittest.TestCase): - def makeUI(self): - return DummyUI() - - def makeAccount(self): - return DummyAccount('la', False, 'la', None, 'localhost', 6667) - - def test_connect(self): - """ - Test that account.logOn works, and it calls the right callback when a - connection is established. - """ - account = self.makeAccount() - ui = self.makeUI() - d = account.logOn(ui) - account.loginDeferred.callback(None) - - def check(result): - self.assert_(not account.loginHasFailed, - "Login shouldn't have failed") - self.assert_(account.loginCallbackCalled, - "We should be logged in") - d.addCallback(check) - return d - - def test_failedConnect(self): - """ - Test that account.logOn works, and it calls the right callback when a - connection is established. - """ - account = self.makeAccount() - ui = self.makeUI() - d = account.logOn(ui) - account.loginDeferred.errback(Exception()) - - def err(reason): - self.assert_(account.loginHasFailed, "Login should have failed") - self.assert_(not account.loginCallbackCalled, - "We shouldn't be logged in") - self.assert_(not ui.clientRegistered, - "Client shouldn't be registered in the UI") - cb = lambda r: self.assert_(False, "Shouldn't get called back") - d.addCallbacks(cb, err) - return d - - def test_alreadyConnecting(self): - """ - Test that it can fail sensibly when someone tried to connect before - we did. - """ - account = self.makeAccount() - ui = self.makeUI() - account.logOn(ui) - self.assertRaises(error.ConnectError, account.logOn, ui) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_domish.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_domish.py deleted file mode 100644 index f40d4e0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_domish.py +++ /dev/null @@ -1,435 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.xish.domish}, a DOM-like library for XMPP. -""" - -from twisted.python.reflect import requireModule -from twisted.trial import unittest -from twisted.words.xish import domish - - -class DomishTests(unittest.TestCase): - def testEscaping(self): - s = "&<>'\"" - self.assertEqual(domish.escapeToXml(s), "&amp;&lt;&gt;'\"") - self.assertEqual(domish.escapeToXml(s, 1), "&amp;&lt;&gt;&apos;&quot;") - - def testNamespaceObject(self): - ns = domish.Namespace("testns") - self.assertEqual(ns.foo, ("testns", "foo")) - - def testElementInit(self): - e = domish.Element((None, "foo")) - self.assertEqual(e.name, "foo") - self.assertEqual(e.uri, None) - self.assertEqual(e.defaultUri, None) - self.assertEqual(e.parent, None) - - e = domish.Element(("", "foo")) - self.assertEqual(e.name, "foo") - self.assertEqual(e.uri, "") - self.assertEqual(e.defaultUri, "") - self.assertEqual(e.parent, None) - - e = domish.Element(("testns", "foo")) - self.assertEqual(e.name, "foo") - self.assertEqual(e.uri, "testns") - self.assertEqual(e.defaultUri, "testns") - self.assertEqual(e.parent, None) - - e = domish.Element(("testns", "foo"), "test2ns") - self.assertEqual(e.name, "foo") - self.assertEqual(e.uri, "testns") - self.assertEqual(e.defaultUri, "test2ns") - - def testChildOps(self): - e = domish.Element(("testns", "foo")) - e.addContent("somecontent") - b2 = e.addElement(("testns2", "bar2")) - e["attrib1"] = "value1" - e[("testns2", "attrib2")] = "value2" - e.addElement("bar") - e.addElement("bar") - e.addContent("abc") - e.addContent("123") - - # Check content merging - self.assertEqual(e.children[-1], "abc123") - - # Check str()/content extraction - self.assertEqual(str(e), "somecontent") - - # Check direct child accessor - self.assertEqual(e.bar2, b2) - e.bar2.addContent("subcontent") - e.bar2["bar2value"] = "somevalue" - - # Check child ops - self.assertEqual(e.children[1], e.bar2) - self.assertEqual(e.children[2], e.bar) - - # Check attribute ops - self.assertEqual(e["attrib1"], "value1") - del e["attrib1"] - self.assertEqual(e.hasAttribute("attrib1"), 0) - self.assertEqual(e.hasAttribute("attrib2"), 0) - self.assertEqual(e[("testns2", "attrib2")], "value2") - - - def test_elements(self): - """ - Calling C{elements} without arguments on a L{domish.Element} returns - all child elements, whatever the qualified name. - """ - e = domish.Element((u"testns", u"foo")) - c1 = e.addElement(u"name") - c2 = e.addElement((u"testns2", u"baz")) - c3 = e.addElement(u"quux") - c4 = e.addElement((u"testns", u"name")) - - elts = list(e.elements()) - - self.assertIn(c1, elts) - self.assertIn(c2, elts) - self.assertIn(c3, elts) - self.assertIn(c4, elts) - - - def test_elementsWithQN(self): - """ - Calling C{elements} with a namespace and local name on a - L{domish.Element} returns all child elements with that qualified name. - """ - e = domish.Element((u"testns", u"foo")) - c1 = e.addElement(u"name") - c2 = e.addElement((u"testns2", u"baz")) - c3 = e.addElement(u"quux") - c4 = e.addElement((u"testns", u"name")) - - elts = list(e.elements(u"testns", u"name")) - - self.assertIn(c1, elts) - self.assertNotIn(c2, elts) - self.assertNotIn(c3, elts) - self.assertIn(c4, elts) - - - -class DomishStreamTestsMixin: - """ - Mixin defining tests for different stream implementations. - - @ivar streamClass: A no-argument callable which will be used to create an - XML parser which can produce a stream of elements from incremental - input. - """ - def setUp(self): - self.doc_started = False - self.doc_ended = False - self.root = None - self.elements = [] - self.stream = self.streamClass() - self.stream.DocumentStartEvent = self._docStarted - self.stream.ElementEvent = self.elements.append - self.stream.DocumentEndEvent = self._docEnded - - def _docStarted(self, root): - self.root = root - self.doc_started = True - - def _docEnded(self): - self.doc_ended = True - - def doTest(self, xml): - self.stream.parse(xml) - - def testHarness(self): - xml = "<root><child/><child2/></root>" - self.stream.parse(xml) - self.assertEqual(self.doc_started, True) - self.assertEqual(self.root.name, 'root') - self.assertEqual(self.elements[0].name, 'child') - self.assertEqual(self.elements[1].name, 'child2') - self.assertEqual(self.doc_ended, True) - - def testBasic(self): - xml = "<stream:stream xmlns:stream='etherx' xmlns='jabber'>\n" + \ - " <message to='bar'>" + \ - " <x xmlns='xdelay'>some&amp;data&gt;</x>" + \ - " </message>" + \ - "</stream:stream>" - - self.stream.parse(xml) - self.assertEqual(self.root.name, 'stream') - self.assertEqual(self.root.uri, 'etherx') - self.assertEqual(self.elements[0].name, 'message') - self.assertEqual(self.elements[0].uri, 'jabber') - self.assertEqual(self.elements[0]['to'], 'bar') - self.assertEqual(self.elements[0].x.uri, 'xdelay') - self.assertEqual(unicode(self.elements[0].x), 'some&data>') - - def testNoRootNS(self): - xml = "<stream><error xmlns='etherx'/></stream>" - - self.stream.parse(xml) - self.assertEqual(self.root.uri, '') - self.assertEqual(self.elements[0].uri, 'etherx') - - def testNoDefaultNS(self): - xml = "<stream:stream xmlns:stream='etherx'><error/></stream:stream>""" - - self.stream.parse(xml) - self.assertEqual(self.root.uri, 'etherx') - self.assertEqual(self.root.defaultUri, '') - self.assertEqual(self.elements[0].uri, '') - self.assertEqual(self.elements[0].defaultUri, '') - - def testChildDefaultNS(self): - xml = "<root xmlns='testns'><child/></root>" - - self.stream.parse(xml) - self.assertEqual(self.root.uri, 'testns') - self.assertEqual(self.elements[0].uri, 'testns') - - def testEmptyChildNS(self): - xml = "<root xmlns='testns'><child1><child2 xmlns=''/></child1></root>" - - self.stream.parse(xml) - self.assertEqual(self.elements[0].child2.uri, '') - - - def test_namespaceWithWhitespace(self): - """ - Whitespace in an xmlns value is preserved in the resulting node's C{uri} - attribute. - """ - xml = "<root xmlns:foo=' bar baz '><foo:bar foo:baz='quux'/></root>" - self.stream.parse(xml) - self.assertEqual(self.elements[0].uri, " bar baz ") - self.assertEqual( - self.elements[0].attributes, {(" bar baz ", "baz"): "quux"}) - - - def testChildPrefix(self): - xml = "<root xmlns='testns' xmlns:foo='testns2'><foo:child/></root>" - - self.stream.parse(xml) - self.assertEqual(self.root.localPrefixes['foo'], 'testns2') - self.assertEqual(self.elements[0].uri, 'testns2') - - def testUnclosedElement(self): - self.assertRaises(domish.ParserError, self.stream.parse, - "<root><error></root>") - - def test_namespaceReuse(self): - """ - Test that reuse of namespaces does affect an element's serialization. - - When one element uses a prefix for a certain namespace, this is - stored in the C{localPrefixes} attribute of the element. We want - to make sure that elements created after such use, won't have this - prefix end up in their C{localPrefixes} attribute, too. - """ - - xml = """<root> - <foo:child1 xmlns:foo='testns'/> - <child2 xmlns='testns'/> - </root>""" - - self.stream.parse(xml) - self.assertEqual('child1', self.elements[0].name) - self.assertEqual('testns', self.elements[0].uri) - self.assertEqual('', self.elements[0].defaultUri) - self.assertEqual({'foo': 'testns'}, self.elements[0].localPrefixes) - self.assertEqual('child2', self.elements[1].name) - self.assertEqual('testns', self.elements[1].uri) - self.assertEqual('testns', self.elements[1].defaultUri) - self.assertEqual({}, self.elements[1].localPrefixes) - - - -class DomishExpatStreamTests(DomishStreamTestsMixin, unittest.TestCase): - """ - Tests for L{domish.ExpatElementStream}, the expat-based element stream - implementation. - """ - streamClass = domish.ExpatElementStream - - if requireModule('pyexpat', default=None) is None: - skip = "pyexpat is required for ExpatElementStream tests." - else: - skip = None - - - -class DomishSuxStreamTests(DomishStreamTestsMixin, unittest.TestCase): - """ - Tests for L{domish.SuxElementStream}, the L{twisted.web.sux}-based element - stream implementation. - """ - streamClass = domish.SuxElementStream - - if domish.SuxElementStream is None: - skip = "twisted.web is required for SuxElementStream tests." - - - -class SerializerTests(unittest.TestCase): - def testNoNamespace(self): - e = domish.Element((None, "foo")) - self.assertEqual(e.toXml(), "<foo/>") - self.assertEqual(e.toXml(closeElement = 0), "<foo>") - - def testDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - self.assertEqual(e.toXml(), "<foo xmlns='testns'/>") - - def testOtherNamespace(self): - e = domish.Element(("testns", "foo"), "testns2") - self.assertEqual(e.toXml({'testns': 'bar'}), - "<bar:foo xmlns:bar='testns' xmlns='testns2'/>") - - def testChildDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement("bar") - self.assertEqual(e.toXml(), "<foo xmlns='testns'><bar/></foo>") - - def testChildSameNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement(("testns", "bar")) - self.assertEqual(e.toXml(), "<foo xmlns='testns'><bar/></foo>") - - def testChildSameDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement("bar", "testns") - self.assertEqual(e.toXml(), "<foo xmlns='testns'><bar/></foo>") - - def testChildOtherDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement(("testns2", "bar"), 'testns2') - self.assertEqual(e.toXml(), "<foo xmlns='testns'><bar xmlns='testns2'/></foo>") - - def testOnlyChildDefaultNamespace(self): - e = domish.Element((None, "foo")) - e.addElement(("ns2", "bar"), 'ns2') - self.assertEqual(e.toXml(), "<foo><bar xmlns='ns2'/></foo>") - - def testOnlyChildDefaultNamespace2(self): - e = domish.Element((None, "foo")) - e.addElement("bar") - self.assertEqual(e.toXml(), "<foo><bar/></foo>") - - def testChildInDefaultNamespace(self): - e = domish.Element(("testns", "foo"), "testns2") - e.addElement(("testns2", "bar")) - self.assertEqual(e.toXml(), "<xn0:foo xmlns:xn0='testns' xmlns='testns2'><bar/></xn0:foo>") - - def testQualifiedAttribute(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - self.assertEqual(e.toXml(), "<foo xmlns:xn0='testns2' xn0:bar='baz'/>") - - def testQualifiedAttributeDefaultNS(self): - e = domish.Element(("testns", "foo"), - attribs = {("testns", "bar"): "baz"}) - self.assertEqual(e.toXml(), "<foo xmlns='testns' xmlns:xn0='testns' xn0:bar='baz'/>") - - def testTwoChilds(self): - e = domish.Element(('', "foo")) - child1 = e.addElement(("testns", "bar"), "testns2") - child1.addElement(('testns2', 'quux')) - child2 = e.addElement(("testns3", "baz"), "testns4") - child2.addElement(('testns', 'quux')) - self.assertEqual(e.toXml(), "<foo><xn0:bar xmlns:xn0='testns' xmlns='testns2'><quux/></xn0:bar><xn1:baz xmlns:xn1='testns3' xmlns='testns4'><xn0:quux xmlns:xn0='testns'/></xn1:baz></foo>") - - def testXMLNamespace(self): - e = domish.Element((None, "foo"), - attribs = {("http://www.w3.org/XML/1998/namespace", - "lang"): "en_US"}) - self.assertEqual(e.toXml(), "<foo xml:lang='en_US'/>") - - def testQualifiedAttributeGivenListOfPrefixes(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - self.assertEqual(e.toXml({"testns2": "qux"}), - "<foo xmlns:qux='testns2' qux:bar='baz'/>") - - def testNSPrefix(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - c = e.addElement(("testns2", "qux")) - c[("testns2", "bar")] = "quux" - - self.assertEqual(e.toXml(), "<foo xmlns:xn0='testns2' xn0:bar='baz'><xn0:qux xn0:bar='quux'/></foo>") - - def testDefaultNSPrefix(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - c = e.addElement(("testns2", "qux")) - c[("testns2", "bar")] = "quux" - c.addElement('foo') - - self.assertEqual(e.toXml(), "<foo xmlns:xn0='testns2' xn0:bar='baz'><xn0:qux xn0:bar='quux'><xn0:foo/></xn0:qux></foo>") - - def testPrefixScope(self): - e = domish.Element(('testns', 'foo')) - - self.assertEqual(e.toXml(prefixes={'testns': 'bar'}, - prefixesInScope=['bar']), - "<bar:foo/>") - - def testLocalPrefixes(self): - e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) - self.assertEqual(e.toXml(), "<bar:foo xmlns:bar='testns'/>") - - def testLocalPrefixesWithChild(self): - e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) - e.addElement('baz') - self.assertIdentical(e.baz.defaultUri, None) - self.assertEqual(e.toXml(), "<bar:foo xmlns:bar='testns'><baz/></bar:foo>") - - def test_prefixesReuse(self): - """ - Test that prefixes passed to serialization are not modified. - - This test makes sure that passing a dictionary of prefixes repeatedly - to C{toXml} of elements does not cause serialization errors. A - previous implementation changed the passed in dictionary internally, - causing havoc later on. - """ - prefixes = {'testns': 'foo'} - - # test passing of dictionary - s = domish.SerializerClass(prefixes=prefixes) - self.assertNotIdentical(prefixes, s.prefixes) - - # test proper serialization on prefixes reuse - e = domish.Element(('testns2', 'foo'), - localPrefixes={'quux': 'testns2'}) - self.assertEqual("<quux:foo xmlns:quux='testns2'/>", - e.toXml(prefixes=prefixes)) - e = domish.Element(('testns2', 'foo')) - self.assertEqual("<foo xmlns='testns2'/>", - e.toXml(prefixes=prefixes)) - - def testRawXMLSerialization(self): - e = domish.Element((None, "foo")) - e.addRawXml("<abc123>") - # The testcase below should NOT generate valid XML -- that's - # the whole point of using the raw XML call -- it's the callers - # responsibility to ensure that the data inserted is valid - self.assertEqual(e.toXml(), "<foo><abc123></foo>") - - def testRawXMLWithUnicodeSerialization(self): - e = domish.Element((None, "foo")) - e.addRawXml(u"<degree>\u00B0</degree>") - self.assertEqual(e.toXml(), u"<foo><degree>\u00B0</degree></foo>") - - def testUnicodeSerialization(self): - e = domish.Element((None, "foo")) - e["test"] = u"my value\u0221e" - e.addContent(u"A degree symbol...\u00B0") - self.assertEqual(e.toXml(), - u"<foo test='my value\u0221e'>A degree symbol...\u00B0</foo>") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_irc.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_irc.py deleted file mode 100644 index 66f7baa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_irc.py +++ /dev/null @@ -1,2759 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.irc}. -""" - -import errno -import operator -import time - -from twisted.trial import unittest -from twisted.trial.unittest import TestCase -from twisted.words.protocols import irc -from twisted.words.protocols.irc import IRCClient, attributes as A -from twisted.internet import protocol, task -from twisted.test.proto_helpers import StringTransport, StringIOWithoutClosing -from twisted.python.filepath import FilePath - - - -class ModeParsingTests(unittest.TestCase): - """ - Tests for L{twisted.words.protocols.irc.parseModes}. - """ - paramModes = ('klb', 'b') - - - def test_emptyModes(self): - """ - Parsing an empty mode string raises L{irc.IRCBadModes}. - """ - self.assertRaises(irc.IRCBadModes, irc.parseModes, '', []) - - - def test_emptyModeSequence(self): - """ - Parsing a mode string that contains an empty sequence (either a C{+} or - C{-} followed directly by another C{+} or C{-}, or not followed by - anything at all) raises L{irc.IRCBadModes}. - """ - self.assertRaises(irc.IRCBadModes, irc.parseModes, '++k', []) - self.assertRaises(irc.IRCBadModes, irc.parseModes, '-+k', []) - self.assertRaises(irc.IRCBadModes, irc.parseModes, '+', []) - self.assertRaises(irc.IRCBadModes, irc.parseModes, '-', []) - - - def test_malformedModes(self): - """ - Parsing a mode string that does not start with C{+} or C{-} raises - L{irc.IRCBadModes}. - """ - self.assertRaises(irc.IRCBadModes, irc.parseModes, 'foo', []) - self.assertRaises(irc.IRCBadModes, irc.parseModes, '%', []) - - - def test_nullModes(self): - """ - Parsing a mode string that contains no mode characters raises - L{irc.IRCBadModes}. - """ - self.assertRaises(irc.IRCBadModes, irc.parseModes, '+', []) - self.assertRaises(irc.IRCBadModes, irc.parseModes, '-', []) - - - def test_singleMode(self): - """ - Parsing a single mode setting with no parameters results in that mode, - with no parameters, in the "added" direction and no modes in the - "removed" direction. - """ - added, removed = irc.parseModes('+s', []) - self.assertEqual(added, [('s', None)]) - self.assertEqual(removed, []) - - added, removed = irc.parseModes('-s', []) - self.assertEqual(added, []) - self.assertEqual(removed, [('s', None)]) - - - def test_singleDirection(self): - """ - Parsing a single-direction mode setting with multiple modes and no - parameters, results in all modes falling into the same direction group. - """ - added, removed = irc.parseModes('+stn', []) - self.assertEqual(added, [('s', None), - ('t', None), - ('n', None)]) - self.assertEqual(removed, []) - - added, removed = irc.parseModes('-nt', []) - self.assertEqual(added, []) - self.assertEqual(removed, [('n', None), - ('t', None)]) - - - def test_multiDirection(self): - """ - Parsing a multi-direction mode setting with no parameters. - """ - added, removed = irc.parseModes('+s-n+ti', []) - self.assertEqual(added, [('s', None), - ('t', None), - ('i', None)]) - self.assertEqual(removed, [('n', None)]) - - - def test_consecutiveDirection(self): - """ - Parsing a multi-direction mode setting containing two consecutive mode - sequences with the same direction results in the same result as if - there were only one mode sequence in the same direction. - """ - added, removed = irc.parseModes('+sn+ti', []) - self.assertEqual(added, [('s', None), - ('n', None), - ('t', None), - ('i', None)]) - self.assertEqual(removed, []) - - - def test_mismatchedParams(self): - """ - If the number of mode parameters does not match the number of modes - expecting parameters, L{irc.IRCBadModes} is raised. - """ - self.assertRaises(irc.IRCBadModes, - irc.parseModes, - '+k', [], - self.paramModes) - self.assertRaises(irc.IRCBadModes, - irc.parseModes, - '+kl', ['foo', '10', 'lulz_extra_param'], - self.paramModes) - - - def test_parameters(self): - """ - Modes which require parameters are parsed and paired with their relevant - parameter, modes which do not require parameters do not consume any of - the parameters. - """ - added, removed = irc.parseModes( - '+klbb', - ['somekey', '42', 'nick!user@host', 'other!*@*'], - self.paramModes) - self.assertEqual(added, [('k', 'somekey'), - ('l', '42'), - ('b', 'nick!user@host'), - ('b', 'other!*@*')]) - self.assertEqual(removed, []) - - added, removed = irc.parseModes( - '-klbb', - ['nick!user@host', 'other!*@*'], - self.paramModes) - self.assertEqual(added, []) - self.assertEqual(removed, [('k', None), - ('l', None), - ('b', 'nick!user@host'), - ('b', 'other!*@*')]) - - # Mix a no-argument mode in with argument modes. - added, removed = irc.parseModes( - '+knbb', - ['somekey', 'nick!user@host', 'other!*@*'], - self.paramModes) - self.assertEqual(added, [('k', 'somekey'), - ('n', None), - ('b', 'nick!user@host'), - ('b', 'other!*@*')]) - self.assertEqual(removed, []) - - - -class MiscTests(unittest.TestCase): - """ - Tests for miscellaneous functions. - """ - def test_foldr(self): - """ - Apply a function of two arguments cumulatively to the items of - a sequence, from right to left, so as to reduce the sequence to - a single value. - """ - self.assertEqual( - irc._foldr(operator.sub, 0, [1, 2, 3, 4]), - -2) - - def insertTop(l, x): - l.insert(0, x) - return l - - self.assertEqual( - irc._foldr(insertTop, [], [[1], [2], [3], [4]]), - [[[[[], 4], 3], 2], 1]) - - - -class FormattedTextTests(unittest.TestCase): - """ - Tests for parsing and assembling formatted IRC text. - """ - def assertAssembledEqually(self, text, expectedFormatted): - """ - Assert that C{text} is parsed and assembled to the same value as what - C{expectedFormatted} is assembled to. This provides a way to ignore - meaningless differences in the formatting structure that would be - difficult to detect without rendering the structures. - """ - formatted = irc.parseFormattedText(text) - self.assertAssemblesTo(formatted, expectedFormatted) - - - def assertAssemblesTo(self, formatted, expectedFormatted): - """ - Assert that C{formatted} and C{expectedFormatted} assemble to the same - value. - """ - text = irc.assembleFormattedText(formatted) - expectedText = irc.assembleFormattedText(expectedFormatted) - self.assertEqual( - irc.assembleFormattedText(formatted), - expectedText, - '%r (%r) is not equivalent to %r (%r)' % ( - text, formatted, expectedText, expectedFormatted)) - - - def test_parseEmpty(self): - """ - An empty string parses to a I{normal} attribute with no text. - """ - self.assertAssembledEqually('', A.normal) - - - def test_assembleEmpty(self): - """ - An attribute with no text assembles to the empty string. An attribute - whose text is the empty string assembles to two control codes: C{off} - and that of the attribute. - """ - self.assertEqual( - irc.assembleFormattedText(A.normal), - '') - - # Attempting to apply an attribute to the empty string should still - # produce two control codes. - self.assertEqual( - irc.assembleFormattedText( - A.bold['']), - '\x0f\x02') - - - def test_assembleNormal(self): - """ - A I{normal} string assembles to a string prefixed with the I{off} - control code. - """ - self.assertEqual( - irc.assembleFormattedText( - A.normal['hello']), - '\x0fhello') - - - def test_assembleBold(self): - """ - A I{bold} string assembles to a string prefixed with the I{off} and - I{bold} control codes. - """ - self.assertEqual( - irc.assembleFormattedText( - A.bold['hello']), - '\x0f\x02hello') - - - def test_assembleUnderline(self): - """ - An I{underline} string assembles to a string prefixed with the I{off} - and I{underline} control codes. - """ - self.assertEqual( - irc.assembleFormattedText( - A.underline['hello']), - '\x0f\x1fhello') - - - def test_assembleReverseVideo(self): - """ - A I{reverse video} string assembles to a string prefixed with the I{off} - and I{reverse video} control codes. - """ - self.assertEqual( - irc.assembleFormattedText( - A.reverseVideo['hello']), - '\x0f\x16hello') - - - def test_assembleForegroundColor(self): - """ - A I{foreground color} string assembles to a string prefixed with the - I{off} and I{color} (followed by the relevant foreground color code) - control codes. - """ - self.assertEqual( - irc.assembleFormattedText( - A.fg.blue['hello']), - '\x0f\x0302hello') - - - def test_assembleBackgroundColor(self): - """ - A I{background color} string assembles to a string prefixed with the - I{off} and I{color} (followed by a I{,} to indicate the absence of a - foreground color, followed by the relevant background color code) - control codes. - """ - self.assertEqual( - irc.assembleFormattedText( - A.bg.blue['hello']), - '\x0f\x03,02hello') - - - def test_assembleColor(self): - """ - A I{foreground} and I{background} color string assembles to a string - prefixed with the I{off} and I{color} (followed by the relevant - foreground color, I{,} and the relevant background color code) control - codes. - """ - self.assertEqual( - irc.assembleFormattedText( - A.fg.red[A.bg.blue['hello']]), - '\x0f\x0305,02hello') - - - def test_assembleNested(self): - """ - Nested attributes retain the attributes of their parents. - """ - self.assertEqual( - irc.assembleFormattedText( - A.bold['hello', A.underline[' world']]), - '\x0f\x02hello\x0f\x02\x1f world') - - self.assertEqual( - irc.assembleFormattedText( - A.normal[ - A.fg.red[A.bg.green['hello'], ' world'], - A.reverseVideo[' yay']]), - '\x0f\x0305,03hello\x0f\x0305 world\x0f\x16 yay') - - - def test_parseUnformattedText(self): - """ - Parsing unformatted text results in text with attributes that - constitute a no-op. - """ - self.assertEqual( - irc.parseFormattedText('hello'), - A.normal['hello']) - - - def test_colorFormatting(self): - """ - Correctly formatted text with colors uses 2 digits to specify - foreground and (optionally) background. - """ - self.assertEqual( - irc.parseFormattedText('\x0301yay\x03'), - A.fg.black['yay']) - self.assertEqual( - irc.parseFormattedText('\x0301,02yay\x03'), - A.fg.black[A.bg.blue['yay']]) - self.assertEqual( - irc.parseFormattedText('\x0301yay\x0302yipee\x03'), - A.fg.black['yay', A.fg.blue['yipee']]) - - - def test_weirdColorFormatting(self): - """ - Formatted text with colors can use 1 digit for both foreground and - background, as long as the text part does not begin with a digit. - Foreground and background colors are only processed to a maximum of 2 - digits per component, anything else is treated as text. Color sequences - must begin with a digit, otherwise processing falls back to unformatted - text. - """ - self.assertAssembledEqually( - '\x031kinda valid', - A.fg.black['kinda valid']) - self.assertAssembledEqually( - '\x03999,999kinda valid', - A.fg.green['9,999kinda valid']) - self.assertAssembledEqually( - '\x031,2kinda valid', - A.fg.black[A.bg.blue['kinda valid']]) - self.assertAssembledEqually( - '\x031,999kinda valid', - A.fg.black[A.bg.green['9kinda valid']]) - self.assertAssembledEqually( - '\x031,242 is a special number', - A.fg.black[A.bg.yellow['2 is a special number']]) - self.assertAssembledEqually( - '\x03,02oops\x03', - A.normal[',02oops']) - self.assertAssembledEqually( - '\x03wrong', - A.normal['wrong']) - self.assertAssembledEqually( - '\x031,hello', - A.fg.black['hello']) - self.assertAssembledEqually( - '\x03\x03', - A.normal) - - - def test_clearColorFormatting(self): - """ - An empty color format specifier clears foreground and background - colors. - """ - self.assertAssembledEqually( - '\x0301yay\x03reset', - A.normal[A.fg.black['yay'], 'reset']) - self.assertAssembledEqually( - '\x0301,02yay\x03reset', - A.normal[A.fg.black[A.bg.blue['yay']], 'reset']) - - - def test_resetFormatting(self): - """ - A reset format specifier clears all formatting attributes. - """ - self.assertAssembledEqually( - '\x02\x1fyay\x0freset', - A.normal[A.bold[A.underline['yay']], 'reset']) - self.assertAssembledEqually( - '\x0301yay\x0freset', - A.normal[A.fg.black['yay'], 'reset']) - self.assertAssembledEqually( - '\x0301,02yay\x0freset', - A.normal[A.fg.black[A.bg.blue['yay']], 'reset']) - - - def test_stripFormatting(self): - """ - Strip formatting codes from formatted text, leaving only the text parts. - """ - self.assertEqual( - irc.stripFormatting( - irc.assembleFormattedText( - A.bold[ - A.underline[ - A.reverseVideo[A.fg.red[A.bg.green['hello']]], - ' world']])), - 'hello world') - - - -class FormattingStateAttributeTests(unittest.TestCase): - """ - Tests for L{twisted.words.protocols.irc._FormattingState}. - """ - def test_equality(self): - """ - L{irc._FormattingState}s must have matching character attribute - values (bold, underline, etc) with the same values to be considered - equal. - """ - self.assertEqual( - irc._FormattingState(), - irc._FormattingState()) - - self.assertEqual( - irc._FormattingState(), - irc._FormattingState(off=False)) - - self.assertEqual( - irc._FormattingState( - bold=True, underline=True, off=False, reverseVideo=True, - foreground=irc._IRC_COLORS['blue']), - irc._FormattingState( - bold=True, underline=True, off=False, reverseVideo=True, - foreground=irc._IRC_COLORS['blue'])) - - self.assertNotEquals( - irc._FormattingState(bold=True), - irc._FormattingState(bold=False)) - - - -stringSubjects = [ - "Hello, this is a nice string with no complications.", - "xargs%(NUL)smight%(NUL)slike%(NUL)sthis" % {'NUL': irc.NUL }, - "embedded%(CR)snewline%(CR)s%(NL)sFUN%(NL)s" % {'CR': irc.CR, - 'NL': irc.NL}, - "escape!%(X)s escape!%(M)s %(X)s%(X)sa %(M)s0" % {'X': irc.X_QUOTE, - 'M': irc.M_QUOTE} - ] - - -class QuotingTests(unittest.TestCase): - def test_lowquoteSanity(self): - """ - Testing client-server level quote/dequote. - """ - for s in stringSubjects: - self.assertEqual(s, irc.lowDequote(irc.lowQuote(s))) - - - def test_ctcpquoteSanity(self): - """ - Testing CTCP message level quote/dequote. - """ - for s in stringSubjects: - self.assertEqual(s, irc.ctcpDequote(irc.ctcpQuote(s))) - - - -class Dispatcher(irc._CommandDispatcherMixin): - """ - A dispatcher that exposes one known command and handles unknown commands. - """ - prefix = 'disp' - - def disp_working(self, a, b): - """ - A known command that returns its input. - """ - return a, b - - - def disp_unknown(self, name, a, b): - """ - Handle unknown commands by returning their name and inputs. - """ - return name, a, b - - - -class DispatcherTests(unittest.TestCase): - """ - Tests for L{irc._CommandDispatcherMixin}. - """ - def test_dispatch(self): - """ - Dispatching a command invokes the correct handler. - """ - disp = Dispatcher() - args = (1, 2) - res = disp.dispatch('working', *args) - self.assertEqual(res, args) - - - def test_dispatchUnknown(self): - """ - Dispatching an unknown command invokes the default handler. - """ - disp = Dispatcher() - name = 'missing' - args = (1, 2) - res = disp.dispatch(name, *args) - self.assertEqual(res, (name,) + args) - - - def test_dispatchMissingUnknown(self): - """ - Dispatching an unknown command, when no default handler is present, - results in an exception being raised. - """ - disp = Dispatcher() - disp.disp_unknown = None - self.assertRaises(irc.UnhandledCommand, disp.dispatch, 'bar') - - - -class ServerSupportedFeatureTests(unittest.TestCase): - """ - Tests for L{ServerSupportedFeatures} and related functions. - """ - def test_intOrDefault(self): - """ - L{_intOrDefault} converts values to C{int} if possible, otherwise - returns a default value. - """ - self.assertEqual(irc._intOrDefault(None), None) - self.assertEqual(irc._intOrDefault([]), None) - self.assertEqual(irc._intOrDefault(''), None) - self.assertEqual(irc._intOrDefault('hello', 5), 5) - self.assertEqual(irc._intOrDefault('123'), 123) - self.assertEqual(irc._intOrDefault(123), 123) - - - def test_splitParam(self): - """ - L{ServerSupportedFeatures._splitParam} splits ISUPPORT parameters - into key and values. Parameters without a separator are split into a - key and a list containing only the empty string. Escaped parameters - are unescaped. - """ - params = [('FOO', ('FOO', [''])), - ('FOO=', ('FOO', [''])), - ('FOO=1', ('FOO', ['1'])), - ('FOO=1,2,3', ('FOO', ['1', '2', '3'])), - ('FOO=A\\x20B', ('FOO', ['A B'])), - ('FOO=\\x5Cx', ('FOO', ['\\x'])), - ('FOO=\\', ('FOO', ['\\'])), - ('FOO=\\n', ('FOO', ['\\n']))] - - _splitParam = irc.ServerSupportedFeatures._splitParam - - for param, expected in params: - res = _splitParam(param) - self.assertEqual(res, expected) - - self.assertRaises(ValueError, _splitParam, 'FOO=\\x') - self.assertRaises(ValueError, _splitParam, 'FOO=\\xNN') - self.assertRaises(ValueError, _splitParam, 'FOO=\\xN') - self.assertRaises(ValueError, _splitParam, 'FOO=\\x20\\x') - - - def test_splitParamArgs(self): - """ - L{ServerSupportedFeatures._splitParamArgs} splits ISUPPORT parameter - arguments into key and value. Arguments without a separator are - split into a key and an empty string. - """ - res = irc.ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2', 'C:', 'D']) - self.assertEqual(res, [('A', '1'), - ('B', '2'), - ('C', ''), - ('D', '')]) - - - def test_splitParamArgsProcessor(self): - """ - L{ServerSupportedFeatures._splitParamArgs} uses the argument processor - passed to convert ISUPPORT argument values to some more suitable - form. - """ - res = irc.ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2', 'C'], - irc._intOrDefault) - self.assertEqual(res, [('A', 1), - ('B', 2), - ('C', None)]) - - - def test_parsePrefixParam(self): - """ - L{ServerSupportedFeatures._parsePrefixParam} parses the ISUPPORT PREFIX - parameter into a mapping from modes to prefix symbols, returns - C{None} if there is no parseable prefix parameter or raises - C{ValueError} if the prefix parameter is malformed. - """ - _parsePrefixParam = irc.ServerSupportedFeatures._parsePrefixParam - self.assertEqual(_parsePrefixParam(''), None) - self.assertRaises(ValueError, _parsePrefixParam, 'hello') - self.assertEqual(_parsePrefixParam('(ov)@+'), - {'o': ('@', 0), - 'v': ('+', 1)}) - - - def test_parseChanModesParam(self): - """ - L{ServerSupportedFeatures._parseChanModesParam} parses the ISUPPORT - CHANMODES parameter into a mapping from mode categories to mode - characters. Passing fewer than 4 parameters results in the empty string - for the relevant categories. Passing more than 4 parameters raises - C{ValueError}. - """ - _parseChanModesParam = irc.ServerSupportedFeatures._parseChanModesParam - self.assertEqual( - _parseChanModesParam([]), - {'addressModes': '', - 'param': '', - 'setParam': '', - 'noParam': ''}) - - self.assertEqual( - _parseChanModesParam(['b', 'k', 'l', 'imnpst']), - {'addressModes': 'b', - 'param': 'k', - 'setParam': 'l', - 'noParam': 'imnpst'}) - - self.assertEqual( - _parseChanModesParam(['b', 'k', 'l']), - {'addressModes': 'b', - 'param': 'k', - 'setParam': 'l', - 'noParam': ''}) - - self.assertRaises( - ValueError, - _parseChanModesParam, ['a', 'b', 'c', 'd', 'e']) - - - def test_parse(self): - """ - L{ServerSupportedFeatures.parse} changes the internal state of the - instance to reflect the features indicated by the parsed ISUPPORT - parameters, including unknown parameters and unsetting previously set - parameters. - """ - supported = irc.ServerSupportedFeatures() - supported.parse(['MODES=4', - 'CHANLIMIT=#:20,&:10', - 'INVEX', - 'EXCEPTS=Z', - 'UNKNOWN=A,B,C']) - - self.assertEqual(supported.getFeature('MODES'), 4) - self.assertEqual(supported.getFeature('CHANLIMIT'), - [('#', 20), - ('&', 10)]) - self.assertEqual(supported.getFeature('INVEX'), 'I') - self.assertEqual(supported.getFeature('EXCEPTS'), 'Z') - self.assertEqual(supported.getFeature('UNKNOWN'), ('A', 'B', 'C')) - - self.assertTrue(supported.hasFeature('INVEX')) - supported.parse(['-INVEX']) - self.assertFalse(supported.hasFeature('INVEX')) - # Unsetting a previously unset parameter should not be a problem. - supported.parse(['-INVEX']) - - - def _parse(self, features): - """ - Parse all specified features according to the ISUPPORT specifications. - - @type features: C{list} of C{(featureName, value)} - @param features: Feature names and values to parse - - @rtype: L{irc.ServerSupportedFeatures} - """ - supported = irc.ServerSupportedFeatures() - features = ['%s=%s' % (name, value or '') - for name, value in features] - supported.parse(features) - return supported - - - def _parseFeature(self, name, value=None): - """ - Parse a feature, with the given name and value, according to the - ISUPPORT specifications and return the parsed value. - """ - supported = self._parse([(name, value)]) - return supported.getFeature(name) - - - def _testIntOrDefaultFeature(self, name, default=None): - """ - Perform some common tests on a feature known to use L{_intOrDefault}. - """ - self.assertEqual( - self._parseFeature(name, None), - default) - self.assertEqual( - self._parseFeature(name, 'notanint'), - default) - self.assertEqual( - self._parseFeature(name, '42'), - 42) - - - def _testFeatureDefault(self, name, features=None): - """ - Features known to have default values are reported as being present by - L{irc.ServerSupportedFeatures.hasFeature}, and their value defaults - correctly, when they don't appear in an ISUPPORT message. - """ - default = irc.ServerSupportedFeatures()._features[name] - - if features is None: - features = [('DEFINITELY_NOT', 'a_feature')] - - supported = self._parse(features) - self.assertTrue(supported.hasFeature(name)) - self.assertEqual(supported.getFeature(name), default) - - - def test_support_CHANMODES(self): - """ - The CHANMODES ISUPPORT parameter is parsed into a C{dict} giving the - four mode categories, C{'addressModes'}, C{'param'}, C{'setParam'}, and - C{'noParam'}. - """ - self._testFeatureDefault('CHANMODES') - self._testFeatureDefault('CHANMODES', [('CHANMODES', 'b,,lk,')]) - self._testFeatureDefault('CHANMODES', [('CHANMODES', 'b,,lk,ha,ha')]) - - self.assertEqual( - self._parseFeature('CHANMODES', ''), - {'addressModes': '', - 'param': '', - 'setParam': '', - 'noParam': ''}) - - self.assertEqual( - self._parseFeature('CHANMODES', ',A'), - {'addressModes': '', - 'param': 'A', - 'setParam': '', - 'noParam': ''}) - - self.assertEqual( - self._parseFeature('CHANMODES', 'A,Bc,Def,Ghij'), - {'addressModes': 'A', - 'param': 'Bc', - 'setParam': 'Def', - 'noParam': 'Ghij'}) - - - def test_support_IDCHAN(self): - """ - The IDCHAN support parameter is parsed into a sequence of two-tuples - giving channel prefix and ID length pairs. - """ - self.assertEqual( - self._parseFeature('IDCHAN', '!:5'), - [('!', '5')]) - - - def test_support_MAXLIST(self): - """ - The MAXLIST support parameter is parsed into a sequence of two-tuples - giving modes and their limits. - """ - self.assertEqual( - self._parseFeature('MAXLIST', 'b:25,eI:50'), - [('b', 25), ('eI', 50)]) - # A non-integer parameter argument results in None. - self.assertEqual( - self._parseFeature('MAXLIST', 'b:25,eI:50,a:3.1415'), - [('b', 25), ('eI', 50), ('a', None)]) - self.assertEqual( - self._parseFeature('MAXLIST', 'b:25,eI:50,a:notanint'), - [('b', 25), ('eI', 50), ('a', None)]) - - - def test_support_NETWORK(self): - """ - The NETWORK support parameter is parsed as the network name, as - specified by the server. - """ - self.assertEqual( - self._parseFeature('NETWORK', 'IRCNet'), - 'IRCNet') - - - def test_support_SAFELIST(self): - """ - The SAFELIST support parameter is parsed into a boolean indicating - whether the safe "list" command is supported or not. - """ - self.assertEqual( - self._parseFeature('SAFELIST'), - True) - - - def test_support_STATUSMSG(self): - """ - The STATUSMSG support parameter is parsed into a string of channel - status that support the exclusive channel notice method. - """ - self.assertEqual( - self._parseFeature('STATUSMSG', '@+'), - '@+') - - - def test_support_TARGMAX(self): - """ - The TARGMAX support parameter is parsed into a dictionary, mapping - strings to integers, of the maximum number of targets for a particular - command. - """ - self.assertEqual( - self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3'), - {'PRIVMSG': 4, - 'NOTICE': 3}) - # A non-integer parameter argument results in None. - self.assertEqual( - self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3,KICK:3.1415'), - {'PRIVMSG': 4, - 'NOTICE': 3, - 'KICK': None}) - self.assertEqual( - self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3,KICK:notanint'), - {'PRIVMSG': 4, - 'NOTICE': 3, - 'KICK': None}) - - - def test_support_NICKLEN(self): - """ - The NICKLEN support parameter is parsed into an integer value - indicating the maximum length of a nickname the client may use, - otherwise, if the parameter is missing or invalid, the default value - (as specified by RFC 1459) is used. - """ - default = irc.ServerSupportedFeatures()._features['NICKLEN'] - self._testIntOrDefaultFeature('NICKLEN', default) - - - def test_support_CHANNELLEN(self): - """ - The CHANNELLEN support parameter is parsed into an integer value - indicating the maximum channel name length, otherwise, if the - parameter is missing or invalid, the default value (as specified by - RFC 1459) is used. - """ - default = irc.ServerSupportedFeatures()._features['CHANNELLEN'] - self._testIntOrDefaultFeature('CHANNELLEN', default) - - - def test_support_CHANTYPES(self): - """ - The CHANTYPES support parameter is parsed into a tuple of - valid channel prefix characters. - """ - self._testFeatureDefault('CHANTYPES') - - self.assertEqual( - self._parseFeature('CHANTYPES', '#&%'), - ('#', '&', '%')) - - - def test_support_KICKLEN(self): - """ - The KICKLEN support parameter is parsed into an integer value - indicating the maximum length of a kick message a client may use. - """ - self._testIntOrDefaultFeature('KICKLEN') - - - def test_support_PREFIX(self): - """ - The PREFIX support parameter is parsed into a dictionary mapping - modes to two-tuples of status symbol and priority. - """ - self._testFeatureDefault('PREFIX') - self._testFeatureDefault('PREFIX', [('PREFIX', 'hello')]) - - self.assertEqual( - self._parseFeature('PREFIX', None), - None) - self.assertEqual( - self._parseFeature('PREFIX', '(ohv)@%+'), - {'o': ('@', 0), - 'h': ('%', 1), - 'v': ('+', 2)}) - self.assertEqual( - self._parseFeature('PREFIX', '(hov)@%+'), - {'o': ('%', 1), - 'h': ('@', 0), - 'v': ('+', 2)}) - - - def test_support_TOPICLEN(self): - """ - The TOPICLEN support parameter is parsed into an integer value - indicating the maximum length of a topic a client may set. - """ - self._testIntOrDefaultFeature('TOPICLEN') - - - def test_support_MODES(self): - """ - The MODES support parameter is parsed into an integer value - indicating the maximum number of "variable" modes (defined as being - modes from C{addressModes}, C{param} or C{setParam} categories for - the C{CHANMODES} ISUPPORT parameter) which may by set on a channel - by a single MODE command from a client. - """ - self._testIntOrDefaultFeature('MODES') - - - def test_support_EXCEPTS(self): - """ - The EXCEPTS support parameter is parsed into the mode character - to be used for "ban exception" modes. If no parameter is specified - then the character C{e} is assumed. - """ - self.assertEqual( - self._parseFeature('EXCEPTS', 'Z'), - 'Z') - self.assertEqual( - self._parseFeature('EXCEPTS'), - 'e') - - - def test_support_INVEX(self): - """ - The INVEX support parameter is parsed into the mode character to be - used for "invite exception" modes. If no parameter is specified then - the character C{I} is assumed. - """ - self.assertEqual( - self._parseFeature('INVEX', 'Z'), - 'Z') - self.assertEqual( - self._parseFeature('INVEX'), - 'I') - - - -class IRCClientWithoutLogin(irc.IRCClient): - performLogin = 0 - - - -class CTCPTests(unittest.TestCase): - """ - Tests for L{twisted.words.protocols.irc.IRCClient} CTCP handling. - """ - def setUp(self): - self.file = StringIOWithoutClosing() - self.transport = protocol.FileWrapper(self.file) - self.client = IRCClientWithoutLogin() - self.client.makeConnection(self.transport) - - self.addCleanup(self.transport.loseConnection) - self.addCleanup(self.client.connectionLost, None) - - - def test_ERRMSG(self): - """Testing CTCP query ERRMSG. - - Not because this is this is an especially important case in the - field, but it does go through the entire dispatch/decode/encode - process. - """ - - errQuery = (":nick!guy@over.there PRIVMSG #theChan :" - "%(X)cERRMSG t%(X)c%(EOL)s" - % {'X': irc.X_DELIM, - 'EOL': irc.CR + irc.LF}) - - errReply = ("NOTICE nick :%(X)cERRMSG t :" - "No error has occoured.%(X)c%(EOL)s" - % {'X': irc.X_DELIM, - 'EOL': irc.CR + irc.LF}) - - self.client.dataReceived(errQuery) - reply = self.file.getvalue() - - self.assertEqual(errReply, reply) - - - def test_noNumbersVERSION(self): - """ - If attributes for version information on L{IRCClient} are set to - C{None}, the parts of the CTCP VERSION response they correspond to - are omitted. - """ - self.client.versionName = "FrobozzIRC" - self.client.ctcpQuery_VERSION("nick!guy@over.there", "#theChan", None) - versionReply = ("NOTICE nick :%(X)cVERSION %(vname)s::" - "%(X)c%(EOL)s" - % {'X': irc.X_DELIM, - 'EOL': irc.CR + irc.LF, - 'vname': self.client.versionName}) - reply = self.file.getvalue() - self.assertEqual(versionReply, reply) - - - def test_fullVERSION(self): - """ - The response to a CTCP VERSION query includes the version number and - environment information, as specified by L{IRCClient.versionNum} and - L{IRCClient.versionEnv}. - """ - self.client.versionName = "FrobozzIRC" - self.client.versionNum = "1.2g" - self.client.versionEnv = "ZorkOS" - self.client.ctcpQuery_VERSION("nick!guy@over.there", "#theChan", None) - versionReply = ("NOTICE nick :%(X)cVERSION %(vname)s:%(vnum)s:%(venv)s" - "%(X)c%(EOL)s" - % {'X': irc.X_DELIM, - 'EOL': irc.CR + irc.LF, - 'vname': self.client.versionName, - 'vnum': self.client.versionNum, - 'venv': self.client.versionEnv}) - reply = self.file.getvalue() - self.assertEqual(versionReply, reply) - - - def test_noDuplicateCTCPDispatch(self): - """ - Duplicated CTCP messages are ignored and no reply is made. - """ - def testCTCP(user, channel, data): - self.called += 1 - - self.called = 0 - self.client.ctcpQuery_TESTTHIS = testCTCP - - self.client.irc_PRIVMSG( - 'foo!bar@baz.quux', [ - '#chan', - '%(X)sTESTTHIS%(X)sfoo%(X)sTESTTHIS%(X)s' % {'X': irc.X_DELIM}]) - self.assertEqual( - self.file.getvalue(), - '') - self.assertEqual(self.called, 1) - - - def test_noDefaultDispatch(self): - """ - The fallback handler is invoked for unrecognized CTCP messages. - """ - def unknownQuery(user, channel, tag, data): - self.calledWith = (user, channel, tag, data) - self.called += 1 - - self.called = 0 - self.patch(self.client, 'ctcpUnknownQuery', unknownQuery) - self.client.irc_PRIVMSG( - 'foo!bar@baz.quux', [ - '#chan', - '%(X)sNOTREAL%(X)s' % {'X': irc.X_DELIM}]) - self.assertEqual( - self.file.getvalue(), - '') - self.assertEqual( - self.calledWith, - ('foo!bar@baz.quux', '#chan', 'NOTREAL', None)) - self.assertEqual(self.called, 1) - - # The fallback handler is not invoked for duplicate unknown CTCP - # messages. - self.client.irc_PRIVMSG( - 'foo!bar@baz.quux', [ - '#chan', - '%(X)sNOTREAL%(X)sfoo%(X)sNOTREAL%(X)s' % {'X': irc.X_DELIM}]) - self.assertEqual(self.called, 2) - - - -class NoticingClient(IRCClientWithoutLogin, object): - methods = { - 'created': ('when',), - 'yourHost': ('info',), - 'myInfo': ('servername', 'version', 'umodes', 'cmodes'), - 'luserClient': ('info',), - 'bounce': ('info',), - 'isupport': ('options',), - 'luserChannels': ('channels',), - 'luserOp': ('ops',), - 'luserMe': ('info',), - 'receivedMOTD': ('motd',), - - 'privmsg': ('user', 'channel', 'message'), - 'joined': ('channel',), - 'left': ('channel',), - 'noticed': ('user', 'channel', 'message'), - 'modeChanged': ('user', 'channel', 'set', 'modes', 'args'), - 'pong': ('user', 'secs'), - 'signedOn': (), - 'kickedFrom': ('channel', 'kicker', 'message'), - 'nickChanged': ('nick',), - - 'userJoined': ('user', 'channel'), - 'userLeft': ('user', 'channel'), - 'userKicked': ('user', 'channel', 'kicker', 'message'), - 'action': ('user', 'channel', 'data'), - 'topicUpdated': ('user', 'channel', 'newTopic'), - 'userRenamed': ('oldname', 'newname')} - - - def __init__(self, *a, **kw): - # It is important that IRCClient.__init__ is not called since - # traditionally it did not exist, so it is important that nothing is - # initialised there that would prevent subclasses that did not (or - # could not) invoke the base implementation. Any protocol - # initialisation should happen in connectionMode. - self.calls = [] - - - def __getattribute__(self, name): - if name.startswith('__') and name.endswith('__'): - return super(NoticingClient, self).__getattribute__(name) - try: - args = super(NoticingClient, self).__getattribute__('methods')[name] - except KeyError: - return super(NoticingClient, self).__getattribute__(name) - else: - return self.makeMethod(name, args) - - - def makeMethod(self, fname, args): - def method(*a, **kw): - if len(a) > len(args): - raise TypeError("TypeError: %s() takes %d arguments " - "(%d given)" % (fname, len(args), len(a))) - for (name, value) in zip(args, a): - if name in kw: - raise TypeError("TypeError: %s() got multiple values " - "for keyword argument '%s'" % (fname, name)) - else: - kw[name] = value - if len(kw) != len(args): - raise TypeError("TypeError: %s() takes %d arguments " - "(%d given)" % (fname, len(args), len(a))) - self.calls.append((fname, kw)) - return method - - -def pop(dict, key, default): - try: - value = dict[key] - except KeyError: - return default - else: - del dict[key] - return value - - - -class ClientImplementationTests(unittest.TestCase): - def setUp(self): - self.transport = StringTransport() - self.client = NoticingClient() - self.client.makeConnection(self.transport) - - self.addCleanup(self.transport.loseConnection) - self.addCleanup(self.client.connectionLost, None) - - - def _serverTestImpl(self, code, msg, func, **kw): - host = pop(kw, 'host', 'server.host') - nick = pop(kw, 'nick', 'nickname') - args = pop(kw, 'args', '') - - message = (":" + - host + " " + - code + " " + - nick + " " + - args + " :" + - msg + "\r\n") - - self.client.dataReceived(message) - self.assertEqual( - self.client.calls, - [(func, kw)]) - - - def testYourHost(self): - msg = "Your host is some.host[blah.blah/6667], running version server-version-3" - self._serverTestImpl("002", msg, "yourHost", info=msg) - - - def testCreated(self): - msg = "This server was cobbled together Fri Aug 13 18:00:25 UTC 2004" - self._serverTestImpl("003", msg, "created", when=msg) - - - def testMyInfo(self): - msg = "server.host server-version abcDEF bcdEHI" - self._serverTestImpl("004", msg, "myInfo", - servername="server.host", - version="server-version", - umodes="abcDEF", - cmodes="bcdEHI") - - - def testLuserClient(self): - msg = "There are 9227 victims and 9542 hiding on 24 servers" - self._serverTestImpl("251", msg, "luserClient", - info=msg) - - - def _sendISUPPORT(self): - args = ("MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 HOSTLEN=63 " - "TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 CHANTYPES=# " - "PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancer") - msg = "are available on this server" - self._serverTestImpl("005", msg, "isupport", args=args, - options=['MODES=4', - 'CHANLIMIT=#:20', - 'NICKLEN=16', - 'USERLEN=10', - 'HOSTLEN=63', - 'TOPICLEN=450', - 'KICKLEN=450', - 'CHANNELLEN=30', - 'KEYLEN=23', - 'CHANTYPES=#', - 'PREFIX=(ov)@+', - 'CASEMAPPING=ascii', - 'CAPAB', - 'IRCD=dancer']) - - - def test_ISUPPORT(self): - """ - The client parses ISUPPORT messages sent by the server and calls - L{IRCClient.isupport}. - """ - self._sendISUPPORT() - - - def testBounce(self): - msg = "Try server some.host, port 321" - self._serverTestImpl("010", msg, "bounce", - info=msg) - - - def testLuserChannels(self): - args = "7116" - msg = "channels formed" - self._serverTestImpl("254", msg, "luserChannels", args=args, - channels=int(args)) - - - def testLuserOp(self): - args = "34" - msg = "flagged staff members" - self._serverTestImpl("252", msg, "luserOp", args=args, - ops=int(args)) - - - def testLuserMe(self): - msg = "I have 1937 clients and 0 servers" - self._serverTestImpl("255", msg, "luserMe", - info=msg) - - - def test_receivedMOTD(self): - """ - Lines received in I{RPL_MOTDSTART} and I{RPL_MOTD} are delivered to - L{IRCClient.receivedMOTD} when I{RPL_ENDOFMOTD} is received. - """ - lines = [ - ":host.name 375 nickname :- host.name Message of the Day -", - ":host.name 372 nickname :- Welcome to host.name", - ":host.name 376 nickname :End of /MOTD command."] - for L in lines: - self.assertEqual(self.client.calls, []) - self.client.dataReceived(L + '\r\n') - - self.assertEqual( - self.client.calls, - [("receivedMOTD", {"motd": ["host.name Message of the Day -", "Welcome to host.name"]})]) - - # After the motd is delivered, the tracking variable should be - # reset. - self.assertIdentical(self.client.motd, None) - - - def test_withoutMOTDSTART(self): - """ - If L{IRCClient} receives I{RPL_MOTD} and I{RPL_ENDOFMOTD} without - receiving I{RPL_MOTDSTART}, L{IRCClient.receivedMOTD} is still - called with a list of MOTD lines. - """ - lines = [ - ":host.name 372 nickname :- Welcome to host.name", - ":host.name 376 nickname :End of /MOTD command."] - - for L in lines: - self.client.dataReceived(L + '\r\n') - - self.assertEqual( - self.client.calls, - [("receivedMOTD", {"motd": ["Welcome to host.name"]})]) - - - def _clientTestImpl(self, sender, group, type, msg, func, **kw): - ident = pop(kw, 'ident', 'ident') - host = pop(kw, 'host', 'host') - - wholeUser = sender + '!' + ident + '@' + host - message = (":" + - wholeUser + " " + - type + " " + - group + " :" + - msg + "\r\n") - self.client.dataReceived(message) - self.assertEqual( - self.client.calls, - [(func, kw)]) - self.client.calls = [] - - - def testPrivmsg(self): - msg = "Tooty toot toot." - self._clientTestImpl("sender", "#group", "PRIVMSG", msg, "privmsg", - ident="ident", host="host", - # Expected results below - user="sender!ident@host", - channel="#group", - message=msg) - - self._clientTestImpl("sender", "recipient", "PRIVMSG", msg, "privmsg", - ident="ident", host="host", - # Expected results below - user="sender!ident@host", - channel="recipient", - message=msg) - - - def test_getChannelModeParams(self): - """ - L{IRCClient.getChannelModeParams} uses ISUPPORT information, either - given by the server or defaults, to determine which channel modes - require arguments when being added or removed. - """ - add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEqual(add, ['b', 'h', 'k', 'l', 'o', 'v']) - self.assertEqual(remove, ['b', 'h', 'o', 'v']) - - def removeFeature(name): - name = '-' + name - msg = "are available on this server" - self._serverTestImpl( - '005', msg, 'isupport', args=name, options=[name]) - self.assertIdentical( - self.client.supported.getFeature(name), None) - self.client.calls = [] - - # Remove CHANMODES feature, causing getFeature('CHANMODES') to return - # None. - removeFeature('CHANMODES') - add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEqual(add, ['h', 'o', 'v']) - self.assertEqual(remove, ['h', 'o', 'v']) - - # Remove PREFIX feature, causing getFeature('PREFIX') to return None. - removeFeature('PREFIX') - add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEqual(add, []) - self.assertEqual(remove, []) - - # Restore ISUPPORT features. - self._sendISUPPORT() - self.assertNotIdentical( - self.client.supported.getFeature('PREFIX'), None) - - - def test_getUserModeParams(self): - """ - L{IRCClient.getUserModeParams} returns a list of user modes (modes that - the user sets on themself, outside of channel modes) that require - parameters when added and removed, respectively. - """ - add, remove = map(sorted, self.client.getUserModeParams()) - self.assertEqual(add, []) - self.assertEqual(remove, []) - - - def _sendModeChange(self, msg, args='', target=None): - """ - Build a MODE string and send it to the client. - """ - if target is None: - target = '#chan' - message = ":Wolf!~wolf@yok.utu.fi MODE %s %s %s\r\n" % ( - target, msg, args) - self.client.dataReceived(message) - - - def _parseModeChange(self, results, target=None): - """ - Parse the results, do some test and return the data to check. - """ - if target is None: - target = '#chan' - - for n, result in enumerate(results): - method, data = result - self.assertEqual(method, 'modeChanged') - self.assertEqual(data['user'], 'Wolf!~wolf@yok.utu.fi') - self.assertEqual(data['channel'], target) - results[n] = tuple([data[key] for key in ('set', 'modes', 'args')]) - return results - - - def _checkModeChange(self, expected, target=None): - """ - Compare the expected result with the one returned by the client. - """ - result = self._parseModeChange(self.client.calls, target) - self.assertEqual(result, expected) - self.client.calls = [] - - - def test_modeMissingDirection(self): - """ - Mode strings that do not begin with a directional character, C{'+'} or - C{'-'}, have C{'+'} automatically prepended. - """ - self._sendModeChange('s') - self._checkModeChange([(True, 's', (None,))]) - - - def test_noModeParameters(self): - """ - No parameters are passed to L{IRCClient.modeChanged} for modes that - don't take any parameters. - """ - self._sendModeChange('-s') - self._checkModeChange([(False, 's', (None,))]) - self._sendModeChange('+n') - self._checkModeChange([(True, 'n', (None,))]) - - - def test_oneModeParameter(self): - """ - Parameters are passed to L{IRCClient.modeChanged} for modes that take - parameters. - """ - self._sendModeChange('+o', 'a_user') - self._checkModeChange([(True, 'o', ('a_user',))]) - self._sendModeChange('-o', 'a_user') - self._checkModeChange([(False, 'o', ('a_user',))]) - - - def test_mixedModes(self): - """ - Mixing adding and removing modes that do and don't take parameters - invokes L{IRCClient.modeChanged} with mode characters and parameters - that match up. - """ - self._sendModeChange('+osv', 'a_user another_user') - self._checkModeChange([(True, 'osv', ('a_user', None, 'another_user'))]) - self._sendModeChange('+v-os', 'a_user another_user') - self._checkModeChange([(True, 'v', ('a_user',)), - (False, 'os', ('another_user', None))]) - - - def test_tooManyModeParameters(self): - """ - Passing an argument to modes that take no parameters results in - L{IRCClient.modeChanged} not being called and an error being logged. - """ - self._sendModeChange('+s', 'wrong') - self._checkModeChange([]) - errors = self.flushLoggedErrors(irc.IRCBadModes) - self.assertEqual(len(errors), 1) - self.assertSubstring( - 'Too many parameters', errors[0].getErrorMessage()) - - - def test_tooFewModeParameters(self): - """ - Passing no arguments to modes that do take parameters results in - L{IRCClient.modeChange} not being called and an error being logged. - """ - self._sendModeChange('+o') - self._checkModeChange([]) - errors = self.flushLoggedErrors(irc.IRCBadModes) - self.assertEqual(len(errors), 1) - self.assertSubstring( - 'Not enough parameters', errors[0].getErrorMessage()) - - - def test_userMode(self): - """ - A C{MODE} message whose target is our user (the nickname of our user, - to be precise), as opposed to a channel, will be parsed according to - the modes specified by L{IRCClient.getUserModeParams}. - """ - target = self.client.nickname - # Mode "o" on channels is supposed to take a parameter, but since this - # is not a channel this will not cause an exception. - self._sendModeChange('+o', target=target) - self._checkModeChange([(True, 'o', (None,))], target=target) - - def getUserModeParams(): - return ['Z', ''] - - # Introduce our own user mode that takes an argument. - self.patch(self.client, 'getUserModeParams', getUserModeParams) - - self._sendModeChange('+Z', 'an_arg', target=target) - self._checkModeChange([(True, 'Z', ('an_arg',))], target=target) - - - def test_heartbeat(self): - """ - When the I{RPL_WELCOME} message is received a heartbeat is started that - will send a I{PING} message to the IRC server every - L{irc.IRCClient.heartbeatInterval} seconds. When the transport is - closed the heartbeat looping call is stopped too. - """ - def _createHeartbeat(): - heartbeat = self._originalCreateHeartbeat() - heartbeat.clock = self.clock - return heartbeat - - self.clock = task.Clock() - self._originalCreateHeartbeat = self.client._createHeartbeat - self.patch(self.client, '_createHeartbeat', _createHeartbeat) - - self.assertIdentical(self.client._heartbeat, None) - self.client.irc_RPL_WELCOME('foo', []) - self.assertNotIdentical(self.client._heartbeat, None) - self.assertEqual(self.client.hostname, 'foo') - - # Pump the clock enough to trigger one LoopingCall. - self.assertEqual(self.transport.value(), '') - self.clock.advance(self.client.heartbeatInterval) - self.assertEqual(self.transport.value(), 'PING foo\r\n') - - # When the connection is lost the heartbeat is stopped. - self.transport.loseConnection() - self.client.connectionLost(None) - self.assertEqual( - len(self.clock.getDelayedCalls()), 0) - self.assertIdentical(self.client._heartbeat, None) - - - def test_heartbeatDisabled(self): - """ - If L{irc.IRCClient.heartbeatInterval} is set to C{None} then no - heartbeat is created. - """ - self.assertIdentical(self.client._heartbeat, None) - self.client.heartbeatInterval = None - self.client.irc_RPL_WELCOME('foo', []) - self.assertIdentical(self.client._heartbeat, None) - - - -class BasicServerFunctionalityTests(unittest.TestCase): - def setUp(self): - self.f = StringIOWithoutClosing() - self.t = protocol.FileWrapper(self.f) - self.p = irc.IRC() - self.p.makeConnection(self.t) - - - def check(self, s): - self.assertEqual(self.f.getvalue(), s) - - - def test_sendMessage(self): - """ - Passing a command and parameters to L{IRC.sendMessage} results in a - query string that consists of the command and parameters, separated by - a space, ending with '\r\n'. - """ - self.p.sendMessage('CMD', 'param1', 'param2') - self.check('CMD param1 param2\r\n') - - - def test_sendMessageNoCommand(self): - """ - Passing C{None} as the command to L{IRC.sendMessage} raises a - C{ValueError}. - """ - error = self.assertRaises(ValueError, self.p.sendMessage, None, - 'param1', 'param2') - self.assertEqual(str(error), "IRC message requires a command.") - - - def test_sendMessageInvalidCommand(self): - """ - Passing an invalid string command to L{IRC.sendMessage} raises a - C{ValueError}. - """ - error = self.assertRaises(ValueError, self.p.sendMessage, ' ', - 'param1', 'param2') - self.assertEqual(str(error), - "Somebody screwed up, 'cuz this doesn't look like a command to " - "me: ") - - - def testPrivmsg(self): - self.p.privmsg("this-is-sender", "this-is-recip", "this is message") - self.check(":this-is-sender PRIVMSG this-is-recip :this is message\r\n") - - - def testNotice(self): - self.p.notice("this-is-sender", "this-is-recip", "this is notice") - self.check(":this-is-sender NOTICE this-is-recip :this is notice\r\n") - - - def testAction(self): - self.p.action("this-is-sender", "this-is-recip", "this is action") - self.check(":this-is-sender ACTION this-is-recip :this is action\r\n") - - - def testJoin(self): - self.p.join("this-person", "#this-channel") - self.check(":this-person JOIN #this-channel\r\n") - - - def testPart(self): - self.p.part("this-person", "#that-channel") - self.check(":this-person PART #that-channel\r\n") - - - def testWhois(self): - """ - Verify that a whois by the client receives the right protocol actions - from the server. - """ - timestamp = int(time.time()-100) - hostname = self.p.hostname - req = 'requesting-nick' - targ = 'target-nick' - self.p.whois(req, targ, 'target', 'host.com', - 'Target User', 'irc.host.com', 'A fake server', False, - 12, timestamp, ['#fakeusers', '#fakemisc']) - expected = '\r\n'.join([ -':%(hostname)s 311 %(req)s %(targ)s target host.com * :Target User', -':%(hostname)s 312 %(req)s %(targ)s irc.host.com :A fake server', -':%(hostname)s 317 %(req)s %(targ)s 12 %(timestamp)s :seconds idle, signon time', -':%(hostname)s 319 %(req)s %(targ)s :#fakeusers #fakemisc', -':%(hostname)s 318 %(req)s %(targ)s :End of WHOIS list.', -'']) % dict(hostname=hostname, timestamp=timestamp, req=req, targ=targ) - self.check(expected) - - - -class DummyClient(irc.IRCClient): - """ - A L{twisted.words.protocols.irc.IRCClient} that stores sent lines in a - C{list} rather than transmitting them. - """ - def __init__(self): - self.lines = [] - - - def connectionMade(self): - irc.IRCClient.connectionMade(self) - self.lines = [] - - - def _truncateLine(self, line): - """ - Truncate an IRC line to the maximum allowed length. - """ - return line[:irc.MAX_COMMAND_LENGTH - len(self.delimiter)] - - - def lineReceived(self, line): - # Emulate IRC servers throwing away our important data. - line = self._truncateLine(line) - return irc.IRCClient.lineReceived(self, line) - - - def sendLine(self, m): - self.lines.append(self._truncateLine(m)) - - - -class ClientInviteTests(unittest.TestCase): - """ - Tests for L{IRCClient.invite}. - """ - def setUp(self): - """ - Create a L{DummyClient} to call C{invite} on in test methods. - """ - self.client = DummyClient() - - - def test_channelCorrection(self): - """ - If the channel name passed to L{IRCClient.invite} does not begin with a - channel prefix character, one is prepended to it. - """ - self.client.invite('foo', 'bar') - self.assertEqual(self.client.lines, ['INVITE foo #bar']) - - - def test_invite(self): - """ - L{IRCClient.invite} sends an I{INVITE} message with the specified - username and a channel. - """ - self.client.invite('foo', '#bar') - self.assertEqual(self.client.lines, ['INVITE foo #bar']) - - - -class ClientMsgTests(unittest.TestCase): - """ - Tests for messages sent with L{twisted.words.protocols.irc.IRCClient}. - """ - def setUp(self): - self.client = DummyClient() - self.client.connectionMade() - - - def test_singleLine(self): - """ - A message containing no newlines is sent in a single command. - """ - self.client.msg('foo', 'bar') - self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) - - - def test_invalidMaxLength(self): - """ - Specifying a C{length} value to L{IRCClient.msg} that is too short to - contain the protocol command to send a message raises C{ValueError}. - """ - self.assertRaises(ValueError, self.client.msg, 'foo', 'bar', 0) - self.assertRaises(ValueError, self.client.msg, 'foo', 'bar', 3) - - - def test_multipleLine(self): - """ - Messages longer than the C{length} parameter to L{IRCClient.msg} will - be split and sent in multiple commands. - """ - maxLen = len('PRIVMSG foo :') + 3 + 2 # 2 for line endings - self.client.msg('foo', 'barbazbo', maxLen) - self.assertEqual( - self.client.lines, - ['PRIVMSG foo :bar', - 'PRIVMSG foo :baz', - 'PRIVMSG foo :bo']) - - - def test_sufficientWidth(self): - """ - Messages exactly equal in length to the C{length} paramtere to - L{IRCClient.msg} are sent in a single command. - """ - msg = 'barbazbo' - maxLen = len('PRIVMSG foo :%s' % (msg,)) + 2 - self.client.msg('foo', msg, maxLen) - self.assertEqual(self.client.lines, ['PRIVMSG foo :%s' % (msg,)]) - self.client.lines = [] - self.client.msg('foo', msg, maxLen-1) - self.assertEqual(2, len(self.client.lines)) - self.client.lines = [] - self.client.msg('foo', msg, maxLen+1) - self.assertEqual(1, len(self.client.lines)) - - - def test_newlinesAtStart(self): - """ - An LF at the beginning of the message is ignored. - """ - self.client.lines = [] - self.client.msg('foo', '\nbar') - self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) - - - def test_newlinesAtEnd(self): - """ - An LF at the end of the message is ignored. - """ - self.client.lines = [] - self.client.msg('foo', 'bar\n') - self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) - - - def test_newlinesWithinMessage(self): - """ - An LF within a message causes a new line. - """ - self.client.lines = [] - self.client.msg('foo', 'bar\nbaz') - self.assertEqual( - self.client.lines, - ['PRIVMSG foo :bar', - 'PRIVMSG foo :baz']) - - - def test_consecutiveNewlines(self): - """ - Consecutive LFs do not cause a blank line. - """ - self.client.lines = [] - self.client.msg('foo', 'bar\n\nbaz') - self.assertEqual( - self.client.lines, - ['PRIVMSG foo :bar', - 'PRIVMSG foo :baz']) - - - def assertLongMessageSplitting(self, message, expectedNumCommands, - length=None): - """ - Assert that messages sent by L{IRCClient.msg} are split into an - expected number of commands and the original message is transmitted in - its entirety over those commands. - """ - responsePrefix = ':%s!%s@%s ' % ( - self.client.nickname, - self.client.realname, - self.client.hostname) - - self.client.msg('foo', message, length=length) - - privmsg = [] - self.patch(self.client, 'privmsg', lambda *a: privmsg.append(a)) - # Deliver these to IRCClient via the normal mechanisms. - for line in self.client.lines: - self.client.lineReceived(responsePrefix + line) - - self.assertEqual(len(privmsg), expectedNumCommands) - receivedMessage = ''.join( - message for user, target, message in privmsg) - - # Did the long message we sent arrive as intended? - self.assertEqual(message, receivedMessage) - - - def test_splitLongMessagesWithDefault(self): - """ - If a maximum message length is not provided to L{IRCClient.msg} a - best-guess effort is made to determine a safe maximum, messages longer - than this are split into multiple commands with the intent of - delivering long messages without losing data due to message truncation - when the server relays them. - """ - message = 'o' * (irc.MAX_COMMAND_LENGTH - 2) - self.assertLongMessageSplitting(message, 2) - - - def test_splitLongMessagesWithOverride(self): - """ - The maximum message length can be specified to L{IRCClient.msg}, - messages longer than this are split into multiple commands with the - intent of delivering long messages without losing data due to message - truncation when the server relays them. - """ - message = 'o' * (irc.MAX_COMMAND_LENGTH - 2) - self.assertLongMessageSplitting( - message, 3, length=irc.MAX_COMMAND_LENGTH // 2) - - - def test_newlinesBeforeLineBreaking(self): - """ - IRCClient breaks on newlines before it breaks long lines. - """ - # Because MAX_COMMAND_LENGTH includes framing characters, this long - # line is slightly longer than half the permissible message size. - longline = 'o' * (irc.MAX_COMMAND_LENGTH // 2) - - self.client.msg('foo', longline + '\n' + longline) - self.assertEqual( - self.client.lines, - ['PRIVMSG foo :' + longline, - 'PRIVMSG foo :' + longline]) - - - def test_lineBreakOnWordBoundaries(self): - """ - IRCClient prefers to break long lines at word boundaries. - """ - # Because MAX_COMMAND_LENGTH includes framing characters, this long - # line is slightly longer than half the permissible message size. - longline = 'o' * (irc.MAX_COMMAND_LENGTH // 2) - - self.client.msg('foo', longline + ' ' + longline) - self.assertEqual( - self.client.lines, - ['PRIVMSG foo :' + longline, - 'PRIVMSG foo :' + longline]) - - - def test_splitSanity(self): - """ - L{twisted.words.protocols.irc.split} raises C{ValueError} if given a - length less than or equal to C{0} and returns C{[]} when splitting - C{''}. - """ - # Whiteboxing - self.assertRaises(ValueError, irc.split, 'foo', -1) - self.assertRaises(ValueError, irc.split, 'foo', 0) - self.assertEqual([], irc.split('', 1)) - self.assertEqual([], irc.split('')) - - - def test_splitDelimiters(self): - """ - L{twisted.words.protocols.irc.split} skips any delimiter (space or - newline) that it finds at the very beginning of the string segment it - is operating on. Nothing should be added to the output list because of - it. - """ - r = irc.split("xx yyz", 2) - self.assertEqual(['xx', 'yy', 'z'], r) - r = irc.split("xx\nyyz", 2) - self.assertEqual(['xx', 'yy', 'z'], r) - - - def test_splitValidatesLength(self): - """ - L{twisted.words.protocols.irc.split} raises C{ValueError} if given a - length less than or equal to C{0}. - """ - self.assertRaises(ValueError, irc.split, "foo", 0) - self.assertRaises(ValueError, irc.split, "foo", -1) - - - def test_say(self): - """ - L{IRCClient.say} prepends the channel prefix C{"#"} if necessary and - then sends the message to the server for delivery to that channel. - """ - self.client.say("thechannel", "the message") - self.assertEquals( - self.client.lines, ["PRIVMSG #thechannel :the message"]) - - - -class ClientTests(TestCase): - """ - Tests for the protocol-level behavior of IRCClient methods intended to - be called by application code. - """ - def setUp(self): - """ - Create and connect a new L{IRCClient} to a new L{StringTransport}. - """ - self.transport = StringTransport() - self.protocol = IRCClient() - self.protocol.performLogin = False - self.protocol.makeConnection(self.transport) - - # Sanity check - we don't want anything to have happened at this - # point, since we're not in a test yet. - self.assertEqual(self.transport.value(), "") - - self.addCleanup(self.transport.loseConnection) - self.addCleanup(self.protocol.connectionLost, None) - - - def getLastLine(self, transport): - """ - Return the last IRC message in the transport buffer. - """ - return transport.value().split('\r\n')[-2] - - - def test_away(self): - """ - L{IRCClient.away} sends an AWAY command with the specified message. - """ - message = "Sorry, I'm not here." - self.protocol.away(message) - expected = [ - 'AWAY :%s' % (message,), - '', - ] - self.assertEqual(self.transport.value().split('\r\n'), expected) - - - def test_back(self): - """ - L{IRCClient.back} sends an AWAY command with an empty message. - """ - self.protocol.back() - expected = [ - 'AWAY :', - '', - ] - self.assertEqual(self.transport.value().split('\r\n'), expected) - - - def test_whois(self): - """ - L{IRCClient.whois} sends a WHOIS message. - """ - self.protocol.whois('alice') - self.assertEqual( - self.transport.value().split('\r\n'), - ['WHOIS alice', '']) - - - def test_whoisWithServer(self): - """ - L{IRCClient.whois} sends a WHOIS message with a server name if a - value is passed for the C{server} parameter. - """ - self.protocol.whois('alice', 'example.org') - self.assertEqual( - self.transport.value().split('\r\n'), - ['WHOIS example.org alice', '']) - - - def test_register(self): - """ - L{IRCClient.register} sends NICK and USER commands with the - username, name, hostname, server name, and real name specified. - """ - username = 'testuser' - hostname = 'testhost' - servername = 'testserver' - self.protocol.realname = 'testname' - self.protocol.password = None - self.protocol.register(username, hostname, servername) - expected = [ - 'NICK %s' % (username,), - 'USER %s %s %s :%s' % ( - username, hostname, servername, self.protocol.realname), - ''] - self.assertEqual(self.transport.value().split('\r\n'), expected) - - - def test_registerWithPassword(self): - """ - If the C{password} attribute of L{IRCClient} is not C{None}, the - C{register} method also sends a PASS command with it as the - argument. - """ - username = 'testuser' - hostname = 'testhost' - servername = 'testserver' - self.protocol.realname = 'testname' - self.protocol.password = 'testpass' - self.protocol.register(username, hostname, servername) - expected = [ - 'PASS %s' % (self.protocol.password,), - 'NICK %s' % (username,), - 'USER %s %s %s :%s' % ( - username, hostname, servername, self.protocol.realname), - ''] - self.assertEqual(self.transport.value().split('\r\n'), expected) - - - def test_registerWithTakenNick(self): - """ - Verify that the client repeats the L{IRCClient.setNick} method with a - new value when presented with an C{ERR_NICKNAMEINUSE} while trying to - register. - """ - username = 'testuser' - hostname = 'testhost' - servername = 'testserver' - self.protocol.realname = 'testname' - self.protocol.password = 'testpass' - self.protocol.register(username, hostname, servername) - self.protocol.irc_ERR_NICKNAMEINUSE('prefix', ['param']) - lastLine = self.getLastLine(self.transport) - self.assertNotEquals(lastLine, 'NICK %s' % (username,)) - - # Keep chaining underscores for each collision - self.protocol.irc_ERR_NICKNAMEINUSE('prefix', ['param']) - lastLine = self.getLastLine(self.transport) - self.assertEqual(lastLine, 'NICK %s' % (username + '__',)) - - - def test_overrideAlterCollidedNick(self): - """ - L{IRCClient.alterCollidedNick} determines how a nickname is altered upon - collision while a user is trying to change to that nickname. - """ - nick = 'foo' - self.protocol.alterCollidedNick = lambda nick: nick + '***' - self.protocol.register(nick) - self.protocol.irc_ERR_NICKNAMEINUSE('prefix', ['param']) - lastLine = self.getLastLine(self.transport) - self.assertEqual( - lastLine, 'NICK %s' % (nick + '***',)) - - - def test_nickChange(self): - """ - When a NICK command is sent after signon, C{IRCClient.nickname} is set - to the new nickname I{after} the server sends an acknowledgement. - """ - oldnick = 'foo' - newnick = 'bar' - self.protocol.register(oldnick) - self.protocol.irc_RPL_WELCOME('prefix', ['param']) - self.protocol.setNick(newnick) - self.assertEqual(self.protocol.nickname, oldnick) - self.protocol.irc_NICK('%s!quux@qux' % (oldnick,), [newnick]) - self.assertEqual(self.protocol.nickname, newnick) - - - def test_erroneousNick(self): - """ - Trying to register an illegal nickname results in the default legal - nickname being set, and trying to change a nickname to an illegal - nickname results in the old nickname being kept. - """ - # Registration case: change illegal nickname to erroneousNickFallback - badnick = 'foo' - self.assertEqual(self.protocol._registered, False) - self.protocol.register(badnick) - self.protocol.irc_ERR_ERRONEUSNICKNAME('prefix', ['param']) - lastLine = self.getLastLine(self.transport) - self.assertEqual( - lastLine, 'NICK %s' % (self.protocol.erroneousNickFallback,)) - self.protocol.irc_RPL_WELCOME('prefix', ['param']) - self.assertEqual(self.protocol._registered, True) - self.protocol.setNick(self.protocol.erroneousNickFallback) - self.assertEqual( - self.protocol.nickname, self.protocol.erroneousNickFallback) - - # Illegal nick change attempt after registration. Fall back to the old - # nickname instead of erroneousNickFallback. - oldnick = self.protocol.nickname - self.protocol.setNick(badnick) - self.protocol.irc_ERR_ERRONEUSNICKNAME('prefix', ['param']) - lastLine = self.getLastLine(self.transport) - self.assertEqual( - lastLine, 'NICK %s' % (badnick,)) - self.assertEqual(self.protocol.nickname, oldnick) - - - def test_describe(self): - """ - L{IRCClient.desrcibe} sends a CTCP ACTION message to the target - specified. - """ - target = 'foo' - channel = '#bar' - action = 'waves' - self.protocol.describe(target, action) - self.protocol.describe(channel, action) - expected = [ - 'PRIVMSG %s :\01ACTION %s\01' % (target, action), - 'PRIVMSG %s :\01ACTION %s\01' % (channel, action), - ''] - self.assertEqual(self.transport.value().split('\r\n'), expected) - - - def test_noticedDoesntPrivmsg(self): - """ - The default implementation of L{IRCClient.noticed} doesn't invoke - C{privmsg()} - """ - def privmsg(user, channel, message): - self.fail("privmsg() should not have been called") - self.protocol.privmsg = privmsg - self.protocol.irc_NOTICE( - 'spam', ['#greasyspooncafe', "I don't want any spam!"]) - - - -class CollectorClient(irc.IRCClient): - """ - A client that saves in a list the names of the methods that got called. - """ - def __init__(self, methodsList): - """ - @param methodsList: list of methods' names that should be replaced. - @type methodsList: C{list} - """ - self.methods = [] - self.nickname = 'Wolf' - - for method in methodsList: - def fake_method(method=method): - """ - Collects C{method}s. - """ - def inner(*args): - self.methods.append((method, args)) - return inner - setattr(self, method, fake_method()) - - - -class DccTests(unittest.TestCase): - """ - Tests for C{dcc_*} methods. - """ - def setUp(self): - methods = ['dccDoSend', 'dccDoAcceptResume', 'dccDoResume', - 'dccDoChat'] - self.user = 'Wolf!~wolf@yok.utu.fi' - self.channel = '#twisted' - self.client = CollectorClient(methods) - - - def test_dccSend(self): - """ - L{irc.IRCClient.dcc_SEND} invokes L{irc.IRCClient.dccDoSend}. - """ - self.client.dcc_SEND(self.user, self.channel, 'foo.txt 127.0.0.1 1025') - self.assertEqual(self.client.methods, - [('dccDoSend', (self.user, '127.0.0.1', 1025, 'foo.txt', -1, - ['foo.txt', '127.0.0.1', '1025']))]) - - - def test_dccSendNotImplemented(self): - """ - L{irc.IRCClient.dccDoSend} is raises C{NotImplementedError} - """ - client = irc.IRCClient() - self.assertRaises(NotImplementedError, - client.dccSend, 'username', None) - - - def test_dccSendMalformedRequest(self): - """ - L{irc.IRCClient.dcc_SEND} raises L{irc.IRCBadMessage} when it is passed - a malformed query string. - """ - result = self.assertRaises(irc.IRCBadMessage, self.client.dcc_SEND, - self.user, self.channel, 'foo') - self.assertEqual(str(result), "malformed DCC SEND request: ['foo']") - - - def test_dccSendIndecipherableAddress(self): - """ - L{irc.IRCClient.dcc_SEND} raises L{irc.IRCBadMessage} when it is passed - a query string that doesn't contain a valid address. - """ - result = self.assertRaises(irc.IRCBadMessage, self.client.dcc_SEND, - self.user, self.channel, 'foo.txt #23 sd@d') - self.assertEqual(str(result), "Indecipherable address '#23'") - - - def test_dccSendIndecipherablePort(self): - """ - L{irc.IRCClient.dcc_SEND} raises L{irc.IRCBadMessage} when it is passed - a query string that doesn't contain a valid port number. - """ - result = self.assertRaises(irc.IRCBadMessage, self.client.dcc_SEND, - self.user, self.channel, 'foo.txt 127.0.0.1 sd@d') - self.assertEqual(str(result), "Indecipherable port 'sd@d'") - - - def test_dccAccept(self): - """ - L{irc.IRCClient.dcc_ACCEPT} invokes L{irc.IRCClient.dccDoAcceptResume}. - """ - self.client.dcc_ACCEPT(self.user, self.channel, 'foo.txt 1025 2') - self.assertEqual(self.client.methods, - [('dccDoAcceptResume', (self.user, 'foo.txt', 1025, 2))]) - - - def test_dccAcceptMalformedRequest(self): - """ - L{irc.IRCClient.dcc_ACCEPT} raises L{irc.IRCBadMessage} when it is - passed a malformed query string. - """ - result = self.assertRaises(irc.IRCBadMessage, self.client.dcc_ACCEPT, - self.user, self.channel, 'foo') - self.assertEqual(str(result), - "malformed DCC SEND ACCEPT request: ['foo']") - - - def test_dccResume(self): - """ - L{irc.IRCClient.dcc_RESUME} invokes L{irc.IRCClient.dccDoResume}. - """ - self.client.dcc_RESUME(self.user, self.channel, 'foo.txt 1025 2') - self.assertEqual(self.client.methods, - [('dccDoResume', (self.user, 'foo.txt', 1025, 2))]) - - - def test_dccResumeMalformedRequest(self): - """ - L{irc.IRCClient.dcc_RESUME} raises L{irc.IRCBadMessage} when it is - passed a malformed query string. - """ - result = self.assertRaises(irc.IRCBadMessage, self.client.dcc_RESUME, - self.user, self.channel, 'foo') - self.assertEqual(str(result), - "malformed DCC SEND RESUME request: ['foo']") - - - def test_dccChat(self): - """ - L{irc.IRCClient.dcc_CHAT} invokes L{irc.IRCClient.dccDoChat}. - """ - self.client.dcc_CHAT(self.user, self.channel, 'foo.txt 127.0.0.1 1025') - self.assertEqual(self.client.methods, - [('dccDoChat', (self.user, self.channel, '127.0.0.1', 1025, - ['foo.txt', '127.0.0.1', '1025']))]) - - - def test_dccChatMalformedRequest(self): - """ - L{irc.IRCClient.dcc_CHAT} raises L{irc.IRCBadMessage} when it is - passed a malformed query string. - """ - result = self.assertRaises(irc.IRCBadMessage, self.client.dcc_CHAT, - self.user, self.channel, 'foo') - self.assertEqual(str(result), - "malformed DCC CHAT request: ['foo']") - - - def test_dccChatIndecipherablePort(self): - """ - L{irc.IRCClient.dcc_CHAT} raises L{irc.IRCBadMessage} when it is passed - a query string that doesn't contain a valid port number. - """ - result = self.assertRaises(irc.IRCBadMessage, self.client.dcc_CHAT, - self.user, self.channel, 'foo.txt 127.0.0.1 sd@d') - self.assertEqual(str(result), "Indecipherable port 'sd@d'") - - - -class ServerToClientTests(TestCase): - """ - Tests for the C{irc_*} methods sent from the server to the client. - """ - def setUp(self): - self.user = 'Wolf!~wolf@yok.utu.fi' - self.channel = '#twisted' - methods = ['joined', 'userJoined', 'left', 'userLeft', 'userQuit', - 'noticed', 'kickedFrom', 'userKicked', 'topicUpdated'] - self.client = CollectorClient(methods) - - - def test_irc_JOIN(self): - """ - L{IRCClient.joined} is called when I join a channel; - L{IRCClient.userJoined} is called when someone else joins. - """ - self.client.irc_JOIN(self.user, [self.channel]) - self.client.irc_JOIN('Svadilfari!~svadi@yok.utu.fi', ['#python']) - self.assertEqual(self.client.methods, - [('joined', (self.channel,)), - ('userJoined', ('Svadilfari', '#python'))]) - - - def test_irc_PART(self): - """ - L{IRCClient.left} is called when I part the channel; - L{IRCClient.userLeft} is called when someone else parts. - """ - self.client.irc_PART(self.user, [self.channel]) - self.client.irc_PART('Svadilfari!~svadi@yok.utu.fi', ['#python']) - self.assertEqual(self.client.methods, - [('left', (self.channel,)), - ('userLeft', ('Svadilfari', '#python'))]) - - - def test_irc_QUIT(self): - """ - L{IRCClient.userQuit} is called whenever someone quits - the channel (myself included). - """ - self.client.irc_QUIT('Svadilfari!~svadi@yok.utu.fi', ['Adios.']) - self.client.irc_QUIT(self.user, ['Farewell.']) - self.assertEqual(self.client.methods, - [('userQuit', ('Svadilfari', 'Adios.')), - ('userQuit', ('Wolf', 'Farewell.'))]) - - - def test_irc_NOTICE(self): - """ - L{IRCClient.noticed} is called when a notice is received. - """ - msg = ('%(X)cextended%(X)cdata1%(X)cextended%(X)cdata2%(X)c%(EOL)s' % - {'X': irc.X_DELIM, 'EOL': irc.CR + irc.LF}) - self.client.irc_NOTICE(self.user, [self.channel, msg]) - self.assertEqual(self.client.methods, - [('noticed', (self.user, '#twisted', 'data1 data2'))]) - - - def test_irc_KICK(self): - """ - L{IRCClient.kickedFrom} is called when I get kicked from the channel; - L{IRCClient.userKicked} is called when someone else gets kicked. - """ - # Fight! - self.client.irc_KICK('Svadilfari!~svadi@yok.utu.fi', - ['#python', 'WOLF', 'shoryuken!']) - self.client.irc_KICK(self.user, - [self.channel, 'Svadilfari', 'hadouken!']) - self.assertEqual(self.client.methods, - [('kickedFrom', - ('#python', 'Svadilfari', 'shoryuken!')), - ('userKicked', - ('Svadilfari', self.channel, 'Wolf', 'hadouken!'))]) - - - def test_irc_TOPIC(self): - """ - L{IRCClient.topicUpdated} is called when someone sets the topic. - """ - self.client.irc_TOPIC(self.user, - [self.channel, 'new topic is new']) - self.assertEqual(self.client.methods, - [('topicUpdated', - ('Wolf', self.channel, 'new topic is new'))]) - - - def test_irc_RPL_TOPIC(self): - """ - L{IRCClient.topicUpdated} is called when the topic is initially - reported. - """ - self.client.irc_RPL_TOPIC(self.user, - ['?', self.channel, 'new topic is new']) - self.assertEqual(self.client.methods, - [('topicUpdated', - ('Wolf', self.channel, 'new topic is new'))]) - - - def test_irc_RPL_NOTOPIC(self): - """ - L{IRCClient.topicUpdated} is called when the topic is removed. - """ - self.client.irc_RPL_NOTOPIC(self.user, ['?', self.channel]) - self.assertEqual(self.client.methods, - [('topicUpdated', ('Wolf', self.channel, ''))]) - - - -class CTCPQueryTests(TestCase): - """ - Tests for the C{ctcpQuery_*} methods. - """ - def setUp(self): - self.user = 'Wolf!~wolf@yok.utu.fi' - self.channel = '#twisted' - self.client = CollectorClient(['ctcpMakeReply']) - - - def test_ctcpQuery_PING(self): - """ - L{IRCClient.ctcpQuery_PING} calls L{IRCClient.ctcpMakeReply} with the - correct args. - """ - self.client.ctcpQuery_PING(self.user, self.channel, 'data') - self.assertEqual(self.client.methods, - [('ctcpMakeReply', ('Wolf', [('PING', 'data')]))]) - - - def test_ctcpQuery_FINGER(self): - """ - L{IRCClient.ctcpQuery_FINGER} calls L{IRCClient.ctcpMakeReply} with the - correct args. - """ - self.client.fingerReply = 'reply' - self.client.ctcpQuery_FINGER(self.user, self.channel, 'data') - self.assertEqual(self.client.methods, - [('ctcpMakeReply', ('Wolf', [('FINGER', 'reply')]))]) - - - def test_ctcpQuery_SOURCE(self): - """ - L{IRCClient.ctcpQuery_SOURCE} calls L{IRCClient.ctcpMakeReply} with the - correct args. - """ - self.client.sourceURL = 'url' - self.client.ctcpQuery_SOURCE(self.user, self.channel, 'data') - self.assertEqual(self.client.methods, - [('ctcpMakeReply', ('Wolf', [('SOURCE', 'url'), - ('SOURCE', None)]))]) - - - def test_ctcpQuery_USERINFO(self): - """ - L{IRCClient.ctcpQuery_USERINFO} calls L{IRCClient.ctcpMakeReply} with - the correct args. - """ - self.client.userinfo = 'info' - self.client.ctcpQuery_USERINFO(self.user, self.channel, 'data') - self.assertEqual(self.client.methods, - [('ctcpMakeReply', ('Wolf', [('USERINFO', 'info')]))]) - - - def test_ctcpQuery_CLIENTINFO(self): - """ - L{IRCClient.ctcpQuery_CLIENTINFO} calls L{IRCClient.ctcpMakeReply} with - the correct args. - """ - self.client.ctcpQuery_CLIENTINFO(self.user, self.channel, '') - self.client.ctcpQuery_CLIENTINFO(self.user, self.channel, 'PING PONG') - info = ('CLIENTINFO PING DCC SOURCE VERSION ' - 'USERINFO TIME ACTION ERRMSG FINGER') - self.assertEqual(self.client.methods, - [('ctcpMakeReply', ('Wolf', [('CLIENTINFO', info)])), - ('ctcpMakeReply', ('Wolf', [('CLIENTINFO', None)]))]) - - - def test_ctcpQuery_TIME(self): - """ - L{IRCClient.ctcpQuery_TIME} calls L{IRCClient.ctcpMakeReply} with the - correct args. - """ - self.client.ctcpQuery_TIME(self.user, self.channel, 'data') - self.assertEqual(self.client.methods[0][1][0], 'Wolf') - - - def test_ctcpQuery_DCC(self): - """ - L{IRCClient.ctcpQuery_DCC} calls L{IRCClient.ctcpMakeReply} with the - correct args. - """ - self.client.ctcpQuery_DCC(self.user, self.channel, 'data') - self.assertEqual(self.client.methods, - [('ctcpMakeReply', - ('Wolf', [('ERRMSG', - "DCC data :Unknown DCC type 'DATA'")]))]) - - - -class DccChatFactoryTests(unittest.TestCase): - """ - Tests for L{DccChatFactory}. - """ - def test_buildProtocol(self): - """ - An instance of the L{irc.DccChat} protocol is returned, which has the - factory property set to the factory which created it. - """ - queryData = ('fromUser', None, None) - factory = irc.DccChatFactory(None, queryData) - protocol = factory.buildProtocol('127.0.0.1') - self.assertIsInstance(protocol, irc.DccChat) - self.assertEqual(protocol.factory, factory) - - - -class DccDescribeTests(unittest.TestCase): - """ - Tests for L{dccDescribe}. - """ - def test_address(self): - """ - L{irc.dccDescribe} supports long IP addresses. - """ - result = irc.dccDescribe('CHAT arg 3232235522 6666') - self.assertEqual(result, "CHAT for host 192.168.0.2, port 6666") - - - -class DccFileReceiveTests(unittest.TestCase): - """ - Tests for L{DccFileReceive}. - """ - def makeConnectedDccFileReceive(self, filename, resumeOffset=0, - overwrite=None): - """ - Factory helper that returns a L{DccFileReceive} instance - for a specific test case. - - @param filename: Path to the local file where received data is stored. - @type filename: L{str} - - @param resumeOffset: An integer representing the amount of bytes from - where the transfer of data should be resumed. - @type resumeOffset: L{int} - - @param overwrite: A boolean specifying whether the file to write to - should be overwritten by calling L{DccFileReceive.set_overwrite} - or not. - @type overwrite: L{bool} - - @return: An instance of L{DccFileReceive}. - @rtype: L{DccFileReceive} - """ - protocol = irc.DccFileReceive(filename, resumeOffset=resumeOffset) - if overwrite: - protocol.set_overwrite(True) - transport = StringTransport() - protocol.makeConnection(transport) - return protocol - - - def allDataReceivedForProtocol(self, protocol, data): - """ - Arrange the protocol so that it received all data. - - @param protocol: The protocol which will receive the data. - @type: L{DccFileReceive} - - @param data: The received data. - @type data: L{bytest} - """ - protocol.dataReceived(data) - protocol.connectionLost(None) - - - def test_resumeFromResumeOffset(self): - """ - If given a resumeOffset argument, L{DccFileReceive} will attempt to - resume from that number of bytes if the file exists. - """ - fp = FilePath(self.mktemp()) - fp.setContent(b'Twisted is awesome!') - protocol = self.makeConnectedDccFileReceive(fp.path, resumeOffset=11) - - self.allDataReceivedForProtocol(protocol, b'amazing!') - - self.assertEqual(fp.getContent(), b'Twisted is amazing!') - - - def test_resumeFromResumeOffsetInTheMiddleOfAlreadyWrittenData(self): - """ - When resuming from an offset somewhere in the middle of the file, - for example, if there are 50 bytes in a file, and L{DccFileReceive} - is given a resumeOffset of 25, and after that 15 more bytes are - written to the file, then the resultant file should have just 40 - bytes of data. - """ - fp = FilePath(self.mktemp()) - fp.setContent(b'Twisted is amazing!') - protocol = self.makeConnectedDccFileReceive(fp.path, resumeOffset=11) - - self.allDataReceivedForProtocol(protocol, b'cool!') - - self.assertEqual(fp.getContent(), b'Twisted is cool!') - - - def test_setOverwrite(self): - """ - When local file already exists it can be overwritten using the - L{DccFileReceive.set_overwrite} method. - """ - fp = FilePath(self.mktemp()) - fp.setContent(b'I love contributing to Twisted!') - protocol = self.makeConnectedDccFileReceive(fp.path, overwrite=True) - - self.allDataReceivedForProtocol(protocol, b'Twisted rocks!') - - self.assertEqual(fp.getContent(), b'Twisted rocks!') - - - def test_fileDoesNotExist(self): - """ - If the file does not already exist, then L{DccFileReceive} will - create one and write the data to it. - """ - fp = FilePath(self.mktemp()) - protocol = self.makeConnectedDccFileReceive(fp.path) - - self.allDataReceivedForProtocol(protocol, b'I <3 Twisted') - - self.assertEqual(fp.getContent(), b'I <3 Twisted') - - - def test_resumeWhenFileDoesNotExist(self): - """ - If given a resumeOffset to resume writing to a file that does not - exist, L{DccFileReceive} will raise L{OSError}. - """ - fp = FilePath(self.mktemp()) - - error = self.assertRaises( - OSError, - self.makeConnectedDccFileReceive, fp.path, resumeOffset=1) - - self.assertEqual(errno.ENOENT, error.errno) - - - def test_fileAlreadyExistsNoOverwrite(self): - """ - If the file already exists and overwrite action was not asked, - L{OSError} is raised. - """ - fp = FilePath(self.mktemp()) - fp.touch() - - self.assertRaises(OSError, self.makeConnectedDccFileReceive, fp.path) - - - def test_failToOpenLocalFile(self): - """ - L{IOError} is raised when failing to open the requested path. - """ - fp = FilePath(self.mktemp()).child(u'child-with-no-existing-parent') - - self.assertRaises(IOError, self.makeConnectedDccFileReceive, fp.path) - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_irc_service.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_irc_service.py deleted file mode 100644 index a5ac8dd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_irc_service.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for IRC portions of L{twisted.words.service}. -""" - -from twisted.trial import unittest -from twisted.test import proto_helpers -from twisted.words.service import InMemoryWordsRealm, IRCFactory, IRCUser -from twisted.words.protocols import irc -from twisted.cred import checkers, portal - -class IRCUserTests(unittest.TestCase): - """ - Isolated tests for L{IRCUser} - """ - - def setUp(self): - """ - Sets up a Realm, Portal, Factory, IRCUser, Transport, and Connection - for our tests. - """ - self.wordsRealm = InMemoryWordsRealm("example.com") - self.portal = portal.Portal(self.wordsRealm, - [checkers.InMemoryUsernamePasswordDatabaseDontUse(john="pass")]) - self.factory = IRCFactory(self.wordsRealm, self.portal) - self.ircUser = self.factory.buildProtocol(None) - self.stringTransport = proto_helpers.StringTransport() - self.ircUser.makeConnection(self.stringTransport) - - - def test_sendMessage(self): - """ - Sending a message to a user after they have sent NICK, but before they - have authenticated, results in a message from "example.com". - """ - self.ircUser.irc_NICK("", ["mynick"]) - self.stringTransport.clear() - self.ircUser.sendMessage("foo") - self.assertEqual(":example.com foo mynick\r\n", - self.stringTransport.value()) - - - def test_utf8Messages(self): - """ - When a UTF8 message is sent with sendMessage and the current IRCUser - has a UTF8 nick and is set to UTF8 encoding, the message will be - written to the transport. - """ - expectedResult = (u":example.com \u0442\u0435\u0441\u0442 " - u"\u043d\u0438\u043a\r\n").encode('utf-8') - - self.ircUser.irc_NICK("", [u"\u043d\u0438\u043a".encode('utf-8')]) - self.stringTransport.clear() - self.ircUser.sendMessage(u"\u0442\u0435\u0441\u0442".encode('utf-8')) - self.assertEqual(self.stringTransport.value(), expectedResult) - - - def test_invalidEncodingNick(self): - """ - A NICK command sent with a nickname that cannot be decoded with the - current IRCUser's encoding results in a PRIVMSG from NickServ - indicating that the nickname could not be decoded. - """ - expectedResult = (b":NickServ!NickServ@services PRIVMSG " - b"\xd4\xc5\xd3\xd4 :Your nickname cannot be " - b"decoded. Please use ASCII or UTF-8.\r\n") - - self.ircUser.irc_NICK("", [b"\xd4\xc5\xd3\xd4"]) - self.assertEqual(self.stringTransport.value(), expectedResult) - - - def response(self): - """ - Grabs our responses and then clears the transport - """ - response = self.ircUser.transport.value().splitlines() - self.ircUser.transport.clear() - return map(irc.parsemsg, response) - - - def scanResponse(self, response, messageType): - """ - Gets messages out of a response - - @param response: The parsed IRC messages of the response, as returned - by L{IRCUserTests.response} - - @param messageType: The string type of the desired messages. - - @return: An iterator which yields 2-tuples of C{(index, ircMessage)} - """ - for n, message in enumerate(response): - if (message[1] == messageType): - yield n, message - - - def test_sendNickSendsGreeting(self): - """ - Receiving NICK without authenticating sends the MOTD Start and MOTD End - messages, which is required by certain popular IRC clients (such as - Pidgin) before a connection is considered to be fully established. - """ - self.ircUser.irc_NICK("", ["mynick"]) - response = self.response() - start = list(self.scanResponse(response, irc.RPL_MOTDSTART)) - end = list(self.scanResponse(response, irc.RPL_ENDOFMOTD)) - self.assertEqual(start, - [(0, ('example.com', '375', ['mynick', '- example.com Message of the Day - ']))]) - self.assertEqual(end, - [(1, ('example.com', '376', ['mynick', 'End of /MOTD command.']))]) - - - def test_fullLogin(self): - """ - Receiving USER, PASS, NICK will log in the user, and transmit the - appropriate response messages. - """ - self.ircUser.irc_USER("", ["john doe"]) - self.ircUser.irc_PASS("", ["pass"]) - self.ircUser.irc_NICK("", ["john"]) - - version = ('Your host is example.com, running version %s' % - (self.factory._serverInfo["serviceVersion"],)) - - creation = ('This server was created on %s' % - (self.factory._serverInfo["creationDate"],)) - - self.assertEqual(self.response(), - [('example.com', '375', - ['john', '- example.com Message of the Day - ']), - ('example.com', '376', ['john', 'End of /MOTD command.']), - ('example.com', '001', ['john', 'connected to Twisted IRC']), - ('example.com', '002', ['john', version]), - ('example.com', '003', ['john', creation]), - ('example.com', '004', - ['john', 'example.com', self.factory._serverInfo["serviceVersion"], - 'w', 'n'])]) - - - -class MocksyIRCUser(IRCUser): - def __init__(self): - self.mockedCodes = [] - - def sendMessage(self, code, *_, **__): - self.mockedCodes.append(code) - -BADTEXT = '\xff' - -class IRCUserBadEncodingTests(unittest.TestCase): - """ - Verifies that L{IRCUser} sends the correct error messages back to clients - when given indecipherable bytes - """ - # TODO: irc_NICK -- but NICKSERV is used for that, so it isn't as easy. - - def setUp(self): - self.ircuser = MocksyIRCUser() - - def assertChokesOnBadBytes(self, irc_x, error): - """ - Asserts that IRCUser sends the relevant error code when a given irc_x - dispatch method is given undecodable bytes. - - @param irc_x: the name of the irc_FOO method to test. - For example, irc_x = 'PRIVMSG' will check irc_PRIVMSG - - @param error: the error code irc_x should send. For example, - irc.ERR_NOTONCHANNEL - """ - getattr(self.ircuser, 'irc_%s' % irc_x)(None, [BADTEXT]) - self.assertEqual(self.ircuser.mockedCodes, [error]) - - # no such channel - - def test_JOIN(self): - """ - Tests that irc_JOIN sends ERR_NOSUCHCHANNEL if the channel name can't - be decoded. - """ - self.assertChokesOnBadBytes('JOIN', irc.ERR_NOSUCHCHANNEL) - - def test_NAMES(self): - """ - Tests that irc_NAMES sends ERR_NOSUCHCHANNEL if the channel name can't - be decoded. - """ - self.assertChokesOnBadBytes('NAMES', irc.ERR_NOSUCHCHANNEL) - - def test_TOPIC(self): - """ - Tests that irc_TOPIC sends ERR_NOSUCHCHANNEL if the channel name can't - be decoded. - """ - self.assertChokesOnBadBytes('TOPIC', irc.ERR_NOSUCHCHANNEL) - - def test_LIST(self): - """ - Tests that irc_LIST sends ERR_NOSUCHCHANNEL if the channel name can't - be decoded. - """ - self.assertChokesOnBadBytes('LIST', irc.ERR_NOSUCHCHANNEL) - - # no such nick - - def test_MODE(self): - """ - Tests that irc_MODE sends ERR_NOSUCHNICK if the target name can't - be decoded. - """ - self.assertChokesOnBadBytes('MODE', irc.ERR_NOSUCHNICK) - - def test_PRIVMSG(self): - """ - Tests that irc_PRIVMSG sends ERR_NOSUCHNICK if the target name can't - be decoded. - """ - self.assertChokesOnBadBytes('PRIVMSG', irc.ERR_NOSUCHNICK) - - def test_WHOIS(self): - """ - Tests that irc_WHOIS sends ERR_NOSUCHNICK if the target name can't - be decoded. - """ - self.assertChokesOnBadBytes('WHOIS', irc.ERR_NOSUCHNICK) - - # not on channel - - def test_PART(self): - """ - Tests that irc_PART sends ERR_NOTONCHANNEL if the target name can't - be decoded. - """ - self.assertChokesOnBadBytes('PART', irc.ERR_NOTONCHANNEL) - - # probably nothing - - def test_WHO(self): - """ - Tests that irc_WHO immediately ends the WHO list if the target name - can't be decoded. - """ - self.assertChokesOnBadBytes('WHO', irc.RPL_ENDOFWHO) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_ircsupport.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_ircsupport.py deleted file mode 100644 index d691623..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_ircsupport.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.im.ircsupport}. -""" - -from twisted.trial.unittest import TestCase -from twisted.test.proto_helpers import StringTransport - -from twisted.words.im.basechat import Conversation, ChatUI -from twisted.words.im.ircsupport import IRCAccount, IRCProto - - - -class StubConversation(Conversation): - def show(self): - pass - - - -class StubChatUI(ChatUI): - def getGroupConversation(self, group, Class=StubConversation, stayHidden=0): - return ChatUI.getGroupConversation(self, group, Class, stayHidden) - - - -class IRCProtoTests(TestCase): - """ - Tests for L{IRCProto}. - """ - def setUp(self): - self.account = IRCAccount( - "Some account", False, "alice", None, "example.com", 6667) - self.proto = IRCProto(self.account, StubChatUI(), None) - self.transport = StringTransport() - - - def test_login(self): - """ - When L{IRCProto} is connected to a transport, it sends I{NICK} and - I{USER} commands with the username from the account object. - """ - self.proto.makeConnection(self.transport) - self.assertEqual( - self.transport.value(), - "NICK alice\r\n" - "USER alice foo bar :Twisted-IM user\r\n") - - - def test_authenticate(self): - """ - If created with an account with a password, L{IRCProto} sends a - I{PASS} command before the I{NICK} and I{USER} commands. - """ - self.account.password = "secret" - self.proto.makeConnection(self.transport) - self.assertEqual( - self.transport.value(), - "PASS secret\r\n" - "NICK alice\r\n" - "USER alice foo bar :Twisted-IM user\r\n") - - - def test_channels(self): - """ - If created with an account with a list of channels, L{IRCProto} - joins each of those channels after registering. - """ - self.account.channels = ['#foo', '#bar'] - self.proto.makeConnection(self.transport) - self.assertEqual( - self.transport.value(), - "NICK alice\r\n" - "USER alice foo bar :Twisted-IM user\r\n" - "JOIN #foo\r\n" - "JOIN #bar\r\n") - - - def test_isupport(self): - """ - L{IRCProto} can interpret I{ISUPPORT} (I{005}) messages from the server - and reflect their information in its C{supported} attribute. - """ - self.proto.makeConnection(self.transport) - self.proto.dataReceived( - ":irc.example.com 005 alice MODES=4 CHANLIMIT=#:20\r\n") - self.assertEqual(4, self.proto.supported.getFeature("MODES")) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberclient.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberclient.py deleted file mode 100644 index e170b4d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberclient.py +++ /dev/null @@ -1,414 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.client} -""" -from hashlib import sha1 - -from twisted.internet import defer -from twisted.trial import unittest -from twisted.words.protocols.jabber import client, error, jid, xmlstream -from twisted.words.protocols.jabber.sasl import SASLInitiatingInitializer -from twisted.words.xish import utility - -IQ_AUTH_GET = '/iq[@type="get"]/query[@xmlns="jabber:iq:auth"]' -IQ_AUTH_SET = '/iq[@type="set"]/query[@xmlns="jabber:iq:auth"]' -NS_BIND = 'urn:ietf:params:xml:ns:xmpp-bind' -IQ_BIND_SET = '/iq[@type="set"]/bind[@xmlns="%s"]' % NS_BIND -NS_SESSION = 'urn:ietf:params:xml:ns:xmpp-session' -IQ_SESSION_SET = '/iq[@type="set"]/session[@xmlns="%s"]' % NS_SESSION - -class CheckVersionInitializerTests(unittest.TestCase): - def setUp(self): - a = xmlstream.Authenticator() - xs = xmlstream.XmlStream(a) - self.init = client.CheckVersionInitializer(xs) - - - def testSupported(self): - """ - Test supported version number 1.0 - """ - self.init.xmlstream.version = (1, 0) - self.init.initialize() - - - def testNotSupported(self): - """ - Test unsupported version number 0.0, and check exception. - """ - self.init.xmlstream.version = (0, 0) - exc = self.assertRaises(error.StreamError, self.init.initialize) - self.assertEqual('unsupported-version', exc.condition) - - - -class InitiatingInitializerHarness(object): - """ - Testing harness for interacting with XML stream initializers. - - This sets up an L{utility.XmlPipe} to create a communication channel between - the initializer and the stubbed receiving entity. It features a sink and - source side that both act similarly to a real L{xmlstream.XmlStream}. The - sink is augmented with an authenticator to which initializers can be added. - - The harness also provides some utility methods to work with event observers - and deferreds. - """ - - def setUp(self): - self.output = [] - self.pipe = utility.XmlPipe() - self.xmlstream = self.pipe.sink - self.authenticator = xmlstream.ConnectAuthenticator('example.org') - self.xmlstream.authenticator = self.authenticator - - - def waitFor(self, event, handler): - """ - Observe an output event, returning a deferred. - - The returned deferred will be fired when the given event has been - observed on the source end of the L{XmlPipe} tied to the protocol - under test. The handler is added as the first callback. - - @param event: The event to be observed. See - L{utility.EventDispatcher.addOnetimeObserver}. - @param handler: The handler to be called with the observed event object. - @rtype: L{defer.Deferred}. - """ - d = defer.Deferred() - d.addCallback(handler) - self.pipe.source.addOnetimeObserver(event, d.callback) - return d - - - -class IQAuthInitializerTests(InitiatingInitializerHarness, unittest.TestCase): - """ - Tests for L{client.IQAuthInitializer}. - """ - - def setUp(self): - super(IQAuthInitializerTests, self).setUp() - self.init = client.IQAuthInitializer(self.xmlstream) - self.authenticator.jid = jid.JID('user@example.com/resource') - self.authenticator.password = 'secret' - - - def testPlainText(self): - """ - Test plain-text authentication. - - Act as a server supporting plain-text authentication and expect the - C{password} field to be filled with the password. Then act as if - authentication succeeds. - """ - - def onAuthGet(iq): - """ - Called when the initializer sent a query for authentication methods. - - The response informs the client that plain-text authentication - is supported. - """ - - # Create server response - response = xmlstream.toResponse(iq, 'result') - response.addElement(('jabber:iq:auth', 'query')) - response.query.addElement('username') - response.query.addElement('password') - response.query.addElement('resource') - - # Set up an observer for the next request we expect. - d = self.waitFor(IQ_AUTH_SET, onAuthSet) - - # Send server response - self.pipe.source.send(response) - - return d - - def onAuthSet(iq): - """ - Called when the initializer sent the authentication request. - - The server checks the credentials and responds with an empty result - signalling success. - """ - self.assertEqual('user', unicode(iq.query.username)) - self.assertEqual('secret', unicode(iq.query.password)) - self.assertEqual('resource', unicode(iq.query.resource)) - - # Send server response - response = xmlstream.toResponse(iq, 'result') - self.pipe.source.send(response) - - # Set up an observer for the request for authentication fields - d1 = self.waitFor(IQ_AUTH_GET, onAuthGet) - - # Start the initializer - d2 = self.init.initialize() - return defer.gatherResults([d1, d2]) - - - def testDigest(self): - """ - Test digest authentication. - - Act as a server supporting digest authentication and expect the - C{digest} field to be filled with a sha1 digest of the concatenated - stream session identifier and password. Then act as if authentication - succeeds. - """ - - def onAuthGet(iq): - """ - Called when the initializer sent a query for authentication methods. - - The response informs the client that digest authentication is - supported. - """ - - # Create server response - response = xmlstream.toResponse(iq, 'result') - response.addElement(('jabber:iq:auth', 'query')) - response.query.addElement('username') - response.query.addElement('digest') - response.query.addElement('resource') - - # Set up an observer for the next request we expect. - d = self.waitFor(IQ_AUTH_SET, onAuthSet) - - # Send server response - self.pipe.source.send(response) - - return d - - def onAuthSet(iq): - """ - Called when the initializer sent the authentication request. - - The server checks the credentials and responds with an empty result - signalling success. - """ - self.assertEqual('user', unicode(iq.query.username)) - self.assertEqual(sha1('12345secret').hexdigest(), - unicode(iq.query.digest).encode('utf-8')) - self.assertEqual('resource', unicode(iq.query.resource)) - - # Send server response - response = xmlstream.toResponse(iq, 'result') - self.pipe.source.send(response) - - # Digest authentication relies on the stream session identifier. Set it. - self.xmlstream.sid = u'12345' - - # Set up an observer for the request for authentication fields - d1 = self.waitFor(IQ_AUTH_GET, onAuthGet) - - # Start the initializer - d2 = self.init.initialize() - - return defer.gatherResults([d1, d2]) - - - def testFailRequestFields(self): - """ - Test initializer failure of request for fields for authentication. - """ - def onAuthGet(iq): - """ - Called when the initializer sent a query for authentication methods. - - The server responds that the client is not authorized to authenticate. - """ - response = error.StanzaError('not-authorized').toResponse(iq) - self.pipe.source.send(response) - - # Set up an observer for the request for authentication fields - d1 = self.waitFor(IQ_AUTH_GET, onAuthGet) - - # Start the initializer - d2 = self.init.initialize() - - # The initialized should fail with a stanza error. - self.assertFailure(d2, error.StanzaError) - - return defer.gatherResults([d1, d2]) - - - def testFailAuth(self): - """ - Test initializer failure to authenticate. - """ - - def onAuthGet(iq): - """ - Called when the initializer sent a query for authentication methods. - - The response informs the client that plain-text authentication - is supported. - """ - - # Send server response - response = xmlstream.toResponse(iq, 'result') - response.addElement(('jabber:iq:auth', 'query')) - response.query.addElement('username') - response.query.addElement('password') - response.query.addElement('resource') - - # Set up an observer for the next request we expect. - d = self.waitFor(IQ_AUTH_SET, onAuthSet) - - # Send server response - self.pipe.source.send(response) - - return d - - def onAuthSet(iq): - """ - Called when the initializer sent the authentication request. - - The server checks the credentials and responds with a not-authorized - stanza error. - """ - response = error.StanzaError('not-authorized').toResponse(iq) - self.pipe.source.send(response) - - # Set up an observer for the request for authentication fields - d1 = self.waitFor(IQ_AUTH_GET, onAuthGet) - - # Start the initializer - d2 = self.init.initialize() - - # The initializer should fail with a stanza error. - self.assertFailure(d2, error.StanzaError) - - return defer.gatherResults([d1, d2]) - - - -class BindInitializerTests(InitiatingInitializerHarness, unittest.TestCase): - """ - Tests for L{client.BindInitializer}. - """ - - def setUp(self): - super(BindInitializerTests, self).setUp() - self.init = client.BindInitializer(self.xmlstream) - self.authenticator.jid = jid.JID('user@example.com/resource') - - - def testBasic(self): - """ - Set up a stream, and act as if resource binding succeeds. - """ - def onBind(iq): - response = xmlstream.toResponse(iq, 'result') - response.addElement((NS_BIND, 'bind')) - response.bind.addElement('jid', - content='user@example.com/other resource') - self.pipe.source.send(response) - - def cb(result): - self.assertEqual(jid.JID('user@example.com/other resource'), - self.authenticator.jid) - - d1 = self.waitFor(IQ_BIND_SET, onBind) - d2 = self.init.start() - d2.addCallback(cb) - return defer.gatherResults([d1, d2]) - - - def testFailure(self): - """ - Set up a stream, and act as if resource binding fails. - """ - def onBind(iq): - response = error.StanzaError('conflict').toResponse(iq) - self.pipe.source.send(response) - - d1 = self.waitFor(IQ_BIND_SET, onBind) - d2 = self.init.start() - self.assertFailure(d2, error.StanzaError) - return defer.gatherResults([d1, d2]) - - - -class SessionInitializerTests(InitiatingInitializerHarness, unittest.TestCase): - """ - Tests for L{client.SessionInitializer}. - """ - - def setUp(self): - super(SessionInitializerTests, self).setUp() - self.init = client.SessionInitializer(self.xmlstream) - - - def testSuccess(self): - """ - Set up a stream, and act as if session establishment succeeds. - """ - - def onSession(iq): - response = xmlstream.toResponse(iq, 'result') - self.pipe.source.send(response) - - d1 = self.waitFor(IQ_SESSION_SET, onSession) - d2 = self.init.start() - return defer.gatherResults([d1, d2]) - - - def testFailure(self): - """ - Set up a stream, and act as if session establishment fails. - """ - def onSession(iq): - response = error.StanzaError('forbidden').toResponse(iq) - self.pipe.source.send(response) - - d1 = self.waitFor(IQ_SESSION_SET, onSession) - d2 = self.init.start() - self.assertFailure(d2, error.StanzaError) - return defer.gatherResults([d1, d2]) - - - -class XMPPAuthenticatorTests(unittest.TestCase): - """ - Test for both XMPPAuthenticator and XMPPClientFactory. - """ - def testBasic(self): - """ - Test basic operations. - - Setup an XMPPClientFactory, which sets up an XMPPAuthenticator, and let - it produce a protocol instance. Then inspect the instance variables of - the authenticator and XML stream objects. - """ - self.client_jid = jid.JID('user@example.com/resource') - - # Get an XmlStream instance. Note that it gets initialized with the - # XMPPAuthenticator (that has its associateWithXmlStream called) that - # is in turn initialized with the arguments to the factory. - xs = client.XMPPClientFactory(self.client_jid, - 'secret').buildProtocol(None) - - # test authenticator's instance variables - self.assertEqual('example.com', xs.authenticator.otherHost) - self.assertEqual(self.client_jid, xs.authenticator.jid) - self.assertEqual('secret', xs.authenticator.password) - - # test list of initializers - version, tls, sasl, bind, session = xs.initializers - - self.assert_(isinstance(tls, xmlstream.TLSInitiatingInitializer)) - self.assert_(isinstance(sasl, SASLInitiatingInitializer)) - self.assert_(isinstance(bind, client.BindInitializer)) - self.assert_(isinstance(session, client.SessionInitializer)) - - self.assertFalse(tls.required) - self.assertTrue(sasl.required) - self.assertFalse(bind.required) - self.assertFalse(session.required) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbercomponent.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbercomponent.py deleted file mode 100644 index b365fac..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbercomponent.py +++ /dev/null @@ -1,422 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.component} -""" -from hashlib import sha1 - -from twisted.python import failure -from twisted.trial import unittest -from twisted.words.protocols.jabber import component, xmlstream -from twisted.words.protocols.jabber.jid import JID -from twisted.words.xish import domish -from twisted.words.xish.utility import XmlPipe - -class DummyTransport: - def __init__(self, list): - self.list = list - - def write(self, bytes): - self.list.append(bytes) - -class ComponentInitiatingInitializerTests(unittest.TestCase): - def setUp(self): - self.output = [] - - self.authenticator = xmlstream.Authenticator() - self.authenticator.password = 'secret' - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.namespace = 'test:component' - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived( - "<stream:stream xmlns='test:component' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345' version='1.0'>") - self.xmlstream.sid = u'12345' - self.init = component.ComponentInitiatingInitializer(self.xmlstream) - - def testHandshake(self): - """ - Test basic operations of component handshake. - """ - - d = self.init.initialize() - - # the initializer should have sent the handshake request - - handshake = self.output[-1] - self.assertEqual('handshake', handshake.name) - self.assertEqual('test:component', handshake.uri) - self.assertEqual(sha1("%s%s" % ('12345', 'secret')).hexdigest(), - unicode(handshake)) - - # successful authentication - - handshake.children = [] - self.xmlstream.dataReceived(handshake.toXml()) - - return d - -class ComponentAuthTests(unittest.TestCase): - def authPassed(self, stream): - self.authComplete = True - - def testAuth(self): - self.authComplete = False - outlist = [] - - ca = component.ConnectComponentAuthenticator("cjid", "secret") - xs = xmlstream.XmlStream(ca) - xs.transport = DummyTransport(outlist) - - xs.addObserver(xmlstream.STREAM_AUTHD_EVENT, - self.authPassed) - - # Go... - xs.connectionMade() - xs.dataReceived("<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='cjid' id='12345'>") - - # Calculate what we expect the handshake value to be - hv = sha1("%s%s" % ("12345", "secret")).hexdigest() - - self.assertEqual(outlist[1], "<handshake>%s</handshake>" % (hv)) - - xs.dataReceived("<handshake/>") - - self.assertEqual(self.authComplete, True) - - -class JabberServiceHarness(component.Service): - def __init__(self): - self.componentConnectedFlag = False - self.componentDisconnectedFlag = False - self.transportConnectedFlag = False - - def componentConnected(self, xmlstream): - self.componentConnectedFlag = True - - def componentDisconnected(self): - self.componentDisconnectedFlag = True - - def transportConnected(self, xmlstream): - self.transportConnectedFlag = True - - -class JabberServiceManagerTests(unittest.TestCase): - def testSM(self): - # Setup service manager and test harnes - sm = component.ServiceManager("foo", "password") - svc = JabberServiceHarness() - svc.setServiceParent(sm) - - # Create a write list - wlist = [] - - # Setup a XmlStream - xs = sm.getFactory().buildProtocol(None) - xs.transport = self - xs.transport.write = wlist.append - - # Indicate that it's connected - xs.connectionMade() - - # Ensure the test service harness got notified - self.assertEqual(True, svc.transportConnectedFlag) - - # Jump ahead and pretend like the stream got auth'd - xs.dispatch(xs, xmlstream.STREAM_AUTHD_EVENT) - - # Ensure the test service harness got notified - self.assertEqual(True, svc.componentConnectedFlag) - - # Pretend to drop the connection - xs.connectionLost(None) - - # Ensure the test service harness got notified - self.assertEqual(True, svc.componentDisconnectedFlag) - - - -class RouterTests(unittest.TestCase): - """ - Tests for L{component.Router}. - """ - - def test_addRoute(self): - """ - Test route registration and routing on incoming stanzas. - """ - router = component.Router() - routed = [] - router.route = lambda element: routed.append(element) - - pipe = XmlPipe() - router.addRoute('example.org', pipe.sink) - self.assertEqual(1, len(router.routes)) - self.assertEqual(pipe.sink, router.routes['example.org']) - - element = domish.Element(('testns', 'test')) - pipe.source.send(element) - self.assertEqual([element], routed) - - - def test_route(self): - """ - Test routing of a message. - """ - component1 = XmlPipe() - component2 = XmlPipe() - router = component.Router() - router.addRoute('component1.example.org', component1.sink) - router.addRoute('component2.example.org', component2.sink) - - outgoing = [] - component2.source.addObserver('/*', - lambda element: outgoing.append(element)) - stanza = domish.Element((None, 'presence')) - stanza['from'] = 'component1.example.org' - stanza['to'] = 'component2.example.org' - component1.source.send(stanza) - self.assertEqual([stanza], outgoing) - - - def test_routeDefault(self): - """ - Test routing of a message using the default route. - - The default route is the one with C{None} as its key in the - routing table. It is taken when there is no more specific route - in the routing table that matches the stanza's destination. - """ - component1 = XmlPipe() - s2s = XmlPipe() - router = component.Router() - router.addRoute('component1.example.org', component1.sink) - router.addRoute(None, s2s.sink) - - outgoing = [] - s2s.source.addObserver('/*', lambda element: outgoing.append(element)) - stanza = domish.Element((None, 'presence')) - stanza['from'] = 'component1.example.org' - stanza['to'] = 'example.com' - component1.source.send(stanza) - self.assertEqual([stanza], outgoing) - - - -class ListenComponentAuthenticatorTests(unittest.TestCase): - """ - Tests for L{component.ListenComponentAuthenticator}. - """ - - def setUp(self): - self.output = [] - authenticator = component.ListenComponentAuthenticator('secret') - self.xmlstream = xmlstream.XmlStream(authenticator) - self.xmlstream.send = self.output.append - - - def loseConnection(self): - """ - Stub loseConnection because we are a transport. - """ - self.xmlstream.connectionLost("no reason") - - - def test_streamStarted(self): - """ - The received stream header should set several attributes. - """ - observers = [] - - def addOnetimeObserver(event, observerfn): - observers.append((event, observerfn)) - - xs = self.xmlstream - xs.addOnetimeObserver = addOnetimeObserver - - xs.makeConnection(self) - self.assertIdentical(None, xs.sid) - self.assertFalse(xs._headerSent) - - xs.dataReceived("<stream:stream xmlns='jabber:component:accept' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "to='component.example.org'>") - self.assertEqual((0, 0), xs.version) - self.assertNotIdentical(None, xs.sid) - self.assertTrue(xs._headerSent) - self.assertEqual(('/*', xs.authenticator.onElement), observers[-1]) - - - def test_streamStartedWrongNamespace(self): - """ - The received stream header should have a correct namespace. - """ - streamErrors = [] - - xs = self.xmlstream - xs.sendStreamError = streamErrors.append - xs.makeConnection(self) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "to='component.example.org'>") - self.assertEqual(1, len(streamErrors)) - self.assertEqual('invalid-namespace', streamErrors[-1].condition) - - - def test_streamStartedNoTo(self): - """ - The received stream header should have a 'to' attribute. - """ - streamErrors = [] - - xs = self.xmlstream - xs.sendStreamError = streamErrors.append - xs.makeConnection(self) - xs.dataReceived("<stream:stream xmlns='jabber:component:accept' " - "xmlns:stream='http://etherx.jabber.org/streams'>") - self.assertEqual(1, len(streamErrors)) - self.assertEqual('improper-addressing', streamErrors[-1].condition) - - - def test_onElement(self): - """ - We expect a handshake element with a hash. - """ - handshakes = [] - - xs = self.xmlstream - xs.authenticator.onHandshake = handshakes.append - - handshake = domish.Element(('jabber:component:accept', 'handshake')) - handshake.addContent('1234') - xs.authenticator.onElement(handshake) - self.assertEqual('1234', handshakes[-1]) - - def test_onElementNotHandshake(self): - """ - Reject elements that are not handshakes - """ - handshakes = [] - streamErrors = [] - - xs = self.xmlstream - xs.authenticator.onHandshake = handshakes.append - xs.sendStreamError = streamErrors.append - - element = domish.Element(('jabber:component:accept', 'message')) - xs.authenticator.onElement(element) - self.assertFalse(handshakes) - self.assertEqual('not-authorized', streamErrors[-1].condition) - - - def test_onHandshake(self): - """ - Receiving a handshake matching the secret authenticates the stream. - """ - authd = [] - - def authenticated(xs): - authd.append(xs) - - xs = self.xmlstream - xs.addOnetimeObserver(xmlstream.STREAM_AUTHD_EVENT, authenticated) - xs.sid = u'1234' - theHash = '32532c0f7dbf1253c095b18b18e36d38d94c1256' - xs.authenticator.onHandshake(theHash) - self.assertEqual('<handshake/>', self.output[-1]) - self.assertEqual(1, len(authd)) - - - def test_onHandshakeWrongHash(self): - """ - Receiving a bad handshake should yield a stream error. - """ - streamErrors = [] - authd = [] - - def authenticated(xs): - authd.append(xs) - - xs = self.xmlstream - xs.addOnetimeObserver(xmlstream.STREAM_AUTHD_EVENT, authenticated) - xs.sendStreamError = streamErrors.append - - xs.sid = u'1234' - theHash = '1234' - xs.authenticator.onHandshake(theHash) - self.assertEqual('not-authorized', streamErrors[-1].condition) - self.assertEqual(0, len(authd)) - - - -class XMPPComponentServerFactoryTests(unittest.TestCase): - """ - Tests for L{component.XMPPComponentServerFactory}. - """ - - def setUp(self): - self.router = component.Router() - self.factory = component.XMPPComponentServerFactory(self.router, - 'secret') - self.xmlstream = self.factory.buildProtocol(None) - self.xmlstream.thisEntity = JID('component.example.org') - - - def test_makeConnection(self): - """ - A new connection increases the stream serial count. No logs by default. - """ - self.xmlstream.dispatch(self.xmlstream, - xmlstream.STREAM_CONNECTED_EVENT) - self.assertEqual(0, self.xmlstream.serial) - self.assertEqual(1, self.factory.serial) - self.assertIdentical(None, self.xmlstream.rawDataInFn) - self.assertIdentical(None, self.xmlstream.rawDataOutFn) - - - def test_makeConnectionLogTraffic(self): - """ - Setting logTraffic should set up raw data loggers. - """ - self.factory.logTraffic = True - self.xmlstream.dispatch(self.xmlstream, - xmlstream.STREAM_CONNECTED_EVENT) - self.assertNotIdentical(None, self.xmlstream.rawDataInFn) - self.assertNotIdentical(None, self.xmlstream.rawDataOutFn) - - - def test_onError(self): - """ - An observer for stream errors should trigger onError to log it. - """ - self.xmlstream.dispatch(self.xmlstream, - xmlstream.STREAM_CONNECTED_EVENT) - - class TestError(Exception): - pass - - reason = failure.Failure(TestError()) - self.xmlstream.dispatch(reason, xmlstream.STREAM_ERROR_EVENT) - self.assertEqual(1, len(self.flushLoggedErrors(TestError))) - - - def test_connectionInitialized(self): - """ - Make sure a new stream is added to the routing table. - """ - self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT) - self.assertIn('component.example.org', self.router.routes) - self.assertIdentical(self.xmlstream, - self.router.routes['component.example.org']) - - - def test_connectionLost(self): - """ - Make sure a stream is removed from the routing table on disconnect. - """ - self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT) - self.xmlstream.dispatch(None, xmlstream.STREAM_END_EVENT) - self.assertNotIn('component.example.org', self.router.routes) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbererror.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbererror.py deleted file mode 100644 index c08d989..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbererror.py +++ /dev/null @@ -1,330 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.error}. -""" - -from twisted.trial import unittest - -from twisted.words.protocols.jabber import error -from twisted.words.xish import domish - -NS_XML = 'http://www.w3.org/XML/1998/namespace' -NS_STREAMS = 'http://etherx.jabber.org/streams' -NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams' -NS_XMPP_STANZAS = 'urn:ietf:params:xml:ns:xmpp-stanzas' - -class BaseErrorTests(unittest.TestCase): - - def test_getElementPlain(self): - """ - Test getting an element for a plain error. - """ - e = error.BaseError('feature-not-implemented') - element = e.getElement() - self.assertIdentical(element.uri, None) - self.assertEqual(len(element.children), 1) - - def test_getElementText(self): - """ - Test getting an element for an error with a text. - """ - e = error.BaseError('feature-not-implemented', 'text') - element = e.getElement() - self.assertEqual(len(element.children), 2) - self.assertEqual(unicode(element.text), 'text') - self.assertEqual(element.text.getAttribute((NS_XML, 'lang')), None) - - def test_getElementTextLang(self): - """ - Test getting an element for an error with a text and language. - """ - e = error.BaseError('feature-not-implemented', 'text', 'en_US') - element = e.getElement() - self.assertEqual(len(element.children), 2) - self.assertEqual(unicode(element.text), 'text') - self.assertEqual(element.text[(NS_XML, 'lang')], 'en_US') - - def test_getElementAppCondition(self): - """ - Test getting an element for an error with an app specific condition. - """ - ac = domish.Element(('testns', 'myerror')) - e = error.BaseError('feature-not-implemented', appCondition=ac) - element = e.getElement() - self.assertEqual(len(element.children), 2) - self.assertEqual(element.myerror, ac) - -class StreamErrorTests(unittest.TestCase): - - def test_getElementPlain(self): - """ - Test namespace of the element representation of an error. - """ - e = error.StreamError('feature-not-implemented') - element = e.getElement() - self.assertEqual(element.uri, NS_STREAMS) - - def test_getElementConditionNamespace(self): - """ - Test that the error condition element has the correct namespace. - """ - e = error.StreamError('feature-not-implemented') - element = e.getElement() - self.assertEqual(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri) - - def test_getElementTextNamespace(self): - """ - Test that the error text element has the correct namespace. - """ - e = error.StreamError('feature-not-implemented', 'text') - element = e.getElement() - self.assertEqual(NS_XMPP_STREAMS, element.text.uri) - - - -class StanzaErrorTests(unittest.TestCase): - """ - Tests for L{error.StreamError}. - """ - - - def test_typeRemoteServerTimeout(self): - """ - Remote Server Timeout should yield type wait, code 504. - """ - e = error.StanzaError('remote-server-timeout') - self.assertEqual('wait', e.type) - self.assertEqual('504', e.code) - - - def test_getElementPlain(self): - """ - Test getting an element for a plain stanza error. - """ - e = error.StanzaError('feature-not-implemented') - element = e.getElement() - self.assertEqual(element.uri, None) - self.assertEqual(element['type'], 'cancel') - self.assertEqual(element['code'], '501') - - - def test_getElementType(self): - """ - Test getting an element for a stanza error with a given type. - """ - e = error.StanzaError('feature-not-implemented', 'auth') - element = e.getElement() - self.assertEqual(element.uri, None) - self.assertEqual(element['type'], 'auth') - self.assertEqual(element['code'], '501') - - - def test_getElementConditionNamespace(self): - """ - Test that the error condition element has the correct namespace. - """ - e = error.StanzaError('feature-not-implemented') - element = e.getElement() - self.assertEqual(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri) - - - def test_getElementTextNamespace(self): - """ - Test that the error text element has the correct namespace. - """ - e = error.StanzaError('feature-not-implemented', text='text') - element = e.getElement() - self.assertEqual(NS_XMPP_STANZAS, element.text.uri) - - - def test_toResponse(self): - """ - Test an error response is generated from a stanza. - - The addressing on the (new) response stanza should be reversed, an - error child (with proper properties) added and the type set to - C{'error'}. - """ - stanza = domish.Element(('jabber:client', 'message')) - stanza['type'] = 'chat' - stanza['to'] = 'user1@example.com' - stanza['from'] = 'user2@example.com/resource' - e = error.StanzaError('service-unavailable') - response = e.toResponse(stanza) - self.assertNotIdentical(response, stanza) - self.assertEqual(response['from'], 'user1@example.com') - self.assertEqual(response['to'], 'user2@example.com/resource') - self.assertEqual(response['type'], 'error') - self.assertEqual(response.error.children[0].name, - 'service-unavailable') - self.assertEqual(response.error['type'], 'cancel') - self.assertNotEqual(stanza.children, response.children) - - - -class ParseErrorTests(unittest.TestCase): - """ - Tests for L{error._parseError}. - """ - - - def setUp(self): - self.error = domish.Element((None, 'error')) - - - def test_empty(self): - """ - Test parsing of the empty error element. - """ - result = error._parseError(self.error, 'errorns') - self.assertEqual({'condition': None, - 'text': None, - 'textLang': None, - 'appCondition': None}, result) - - - def test_condition(self): - """ - Test parsing of an error element with a condition. - """ - self.error.addElement(('errorns', 'bad-request')) - result = error._parseError(self.error, 'errorns') - self.assertEqual('bad-request', result['condition']) - - - def test_text(self): - """ - Test parsing of an error element with a text. - """ - text = self.error.addElement(('errorns', 'text')) - text.addContent('test') - result = error._parseError(self.error, 'errorns') - self.assertEqual('test', result['text']) - self.assertEqual(None, result['textLang']) - - - def test_textLang(self): - """ - Test parsing of an error element with a text with a defined language. - """ - text = self.error.addElement(('errorns', 'text')) - text[NS_XML, 'lang'] = 'en_US' - text.addContent('test') - result = error._parseError(self.error, 'errorns') - self.assertEqual('en_US', result['textLang']) - - - def test_appCondition(self): - """ - Test parsing of an error element with an app specific condition. - """ - condition = self.error.addElement(('testns', 'condition')) - result = error._parseError(self.error, 'errorns') - self.assertEqual(condition, result['appCondition']) - - - def test_appConditionMultiple(self): - """ - Test parsing of an error element with multiple app specific conditions. - """ - self.error.addElement(('testns', 'condition')) - condition = self.error.addElement(('testns', 'condition2')) - result = error._parseError(self.error, 'errorns') - self.assertEqual(condition, result['appCondition']) - - - -class ExceptionFromStanzaTests(unittest.TestCase): - - def test_basic(self): - """ - Test basic operations of exceptionFromStanza. - - Given a realistic stanza, check if a sane exception is returned. - - Using this stanza:: - - <iq type='error' - from='pubsub.shakespeare.lit' - to='francisco@denmark.lit/barracks' - id='subscriptions1'> - <pubsub xmlns='http://jabber.org/protocol/pubsub'> - <subscriptions/> - </pubsub> - <error type='cancel'> - <feature-not-implemented - xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> - <unsupported xmlns='http://jabber.org/protocol/pubsub#errors' - feature='retrieve-subscriptions'/> - </error> - </iq> - """ - - stanza = domish.Element((None, 'stanza')) - p = stanza.addElement(('http://jabber.org/protocol/pubsub', 'pubsub')) - p.addElement('subscriptions') - e = stanza.addElement('error') - e['type'] = 'cancel' - e.addElement((NS_XMPP_STANZAS, 'feature-not-implemented')) - uc = e.addElement(('http://jabber.org/protocol/pubsub#errors', - 'unsupported')) - uc['feature'] = 'retrieve-subscriptions' - - result = error.exceptionFromStanza(stanza) - self.assert_(isinstance(result, error.StanzaError)) - self.assertEqual('feature-not-implemented', result.condition) - self.assertEqual('cancel', result.type) - self.assertEqual(uc, result.appCondition) - self.assertEqual([p], result.children) - - def test_legacy(self): - """ - Test legacy operations of exceptionFromStanza. - - Given a realistic stanza with only legacy (pre-XMPP) error information, - check if a sane exception is returned. - - Using this stanza:: - - <message type='error' - to='piers@pipetree.com/Home' - from='qmacro@jaber.org'> - <body>Are you there?</body> - <error code='502'>Unable to resolve hostname.</error> - </message> - """ - stanza = domish.Element((None, 'stanza')) - p = stanza.addElement('body', content='Are you there?') - e = stanza.addElement('error', content='Unable to resolve hostname.') - e['code'] = '502' - - result = error.exceptionFromStanza(stanza) - self.assert_(isinstance(result, error.StanzaError)) - self.assertEqual('service-unavailable', result.condition) - self.assertEqual('wait', result.type) - self.assertEqual('Unable to resolve hostname.', result.text) - self.assertEqual([p], result.children) - -class ExceptionFromStreamErrorTests(unittest.TestCase): - - def test_basic(self): - """ - Test basic operations of exceptionFromStreamError. - - Given a realistic stream error, check if a sane exception is returned. - - Using this error:: - - <stream:error xmlns:stream='http://etherx.jabber.org/streams'> - <xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> - </stream:error> - """ - - e = domish.Element(('http://etherx.jabber.org/streams', 'error')) - e.addElement((NS_XMPP_STREAMS, 'xml-not-well-formed')) - - result = error.exceptionFromStreamError(e) - self.assert_(isinstance(result, error.StreamError)) - self.assertEqual('xml-not-well-formed', result.condition) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberjid.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberjid.py deleted file mode 100644 index 74e474a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberjid.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.jid}. -""" - -from twisted.trial import unittest - -from twisted.words.protocols.jabber import jid - -class JIDParsingTests(unittest.TestCase): - def test_parse(self): - """ - Test different forms of JIDs. - """ - # Basic forms - self.assertEqual(jid.parse("user@host/resource"), - ("user", "host", "resource")) - self.assertEqual(jid.parse("user@host"), - ("user", "host", None)) - self.assertEqual(jid.parse("host"), - (None, "host", None)) - self.assertEqual(jid.parse("host/resource"), - (None, "host", "resource")) - - # More interesting forms - self.assertEqual(jid.parse("foo/bar@baz"), - (None, "foo", "bar@baz")) - self.assertEqual(jid.parse("boo@foo/bar@baz"), - ("boo", "foo", "bar@baz")) - self.assertEqual(jid.parse("boo@foo/bar/baz"), - ("boo", "foo", "bar/baz")) - self.assertEqual(jid.parse("boo/foo@bar@baz"), - (None, "boo", "foo@bar@baz")) - self.assertEqual(jid.parse("boo/foo/bar"), - (None, "boo", "foo/bar")) - self.assertEqual(jid.parse("boo//foo"), - (None, "boo", "/foo")) - - def test_noHost(self): - """ - Test for failure on no host part. - """ - self.assertRaises(jid.InvalidFormat, jid.parse, "user@") - - def test_doubleAt(self): - """ - Test for failure on double @ signs. - - This should fail because @ is not a valid character for the host - part of the JID. - """ - self.assertRaises(jid.InvalidFormat, jid.parse, "user@@host") - - def test_multipleAt(self): - """ - Test for failure on two @ signs. - - This should fail because @ is not a valid character for the host - part of the JID. - """ - self.assertRaises(jid.InvalidFormat, jid.parse, "user@host@host") - - # Basic tests for case mapping. These are fallback tests for the - # prepping done in twisted.words.protocols.jabber.xmpp_stringprep - - def test_prepCaseMapUser(self): - """ - Test case mapping of the user part of the JID. - """ - self.assertEqual(jid.prep("UsEr", "host", "resource"), - ("user", "host", "resource")) - - def test_prepCaseMapHost(self): - """ - Test case mapping of the host part of the JID. - """ - self.assertEqual(jid.prep("user", "hoST", "resource"), - ("user", "host", "resource")) - - def test_prepNoCaseMapResource(self): - """ - Test no case mapping of the resourcce part of the JID. - """ - self.assertEqual(jid.prep("user", "hoST", "resource"), - ("user", "host", "resource")) - self.assertNotEquals(jid.prep("user", "host", "Resource"), - ("user", "host", "resource")) - -class JIDTests(unittest.TestCase): - - def test_noneArguments(self): - """ - Test that using no arguments raises an exception. - """ - self.assertRaises(RuntimeError, jid.JID) - - def test_attributes(self): - """ - Test that the attributes correspond with the JID parts. - """ - j = jid.JID("user@host/resource") - self.assertEqual(j.user, "user") - self.assertEqual(j.host, "host") - self.assertEqual(j.resource, "resource") - - def test_userhost(self): - """ - Test the extraction of the bare JID. - """ - j = jid.JID("user@host/resource") - self.assertEqual("user@host", j.userhost()) - - def test_userhostOnlyHost(self): - """ - Test the extraction of the bare JID of the full form host/resource. - """ - j = jid.JID("host/resource") - self.assertEqual("host", j.userhost()) - - def test_userhostJID(self): - """ - Test getting a JID object of the bare JID. - """ - j1 = jid.JID("user@host/resource") - j2 = jid.internJID("user@host") - self.assertIdentical(j2, j1.userhostJID()) - - def test_userhostJIDNoResource(self): - """ - Test getting a JID object of the bare JID when there was no resource. - """ - j = jid.JID("user@host") - self.assertIdentical(j, j.userhostJID()) - - def test_fullHost(self): - """ - Test giving a string representation of the JID with only a host part. - """ - j = jid.JID(tuple=(None, 'host', None)) - self.assertEqual('host', j.full()) - - def test_fullHostResource(self): - """ - Test giving a string representation of the JID with host, resource. - """ - j = jid.JID(tuple=(None, 'host', 'resource')) - self.assertEqual('host/resource', j.full()) - - def test_fullUserHost(self): - """ - Test giving a string representation of the JID with user, host. - """ - j = jid.JID(tuple=('user', 'host', None)) - self.assertEqual('user@host', j.full()) - - def test_fullAll(self): - """ - Test giving a string representation of the JID. - """ - j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEqual('user@host/resource', j.full()) - - def test_equality(self): - """ - Test JID equality. - """ - j1 = jid.JID("user@host/resource") - j2 = jid.JID("user@host/resource") - self.assertNotIdentical(j1, j2) - self.assertEqual(j1, j2) - - def test_equalityWithNonJIDs(self): - """ - Test JID equality. - """ - j = jid.JID("user@host/resource") - self.assertFalse(j == 'user@host/resource') - - def test_inequality(self): - """ - Test JID inequality. - """ - j1 = jid.JID("user1@host/resource") - j2 = jid.JID("user2@host/resource") - self.assertNotEqual(j1, j2) - - def test_inequalityWithNonJIDs(self): - """ - Test JID equality. - """ - j = jid.JID("user@host/resource") - self.assertNotEqual(j, 'user@host/resource') - - def test_hashable(self): - """ - Test JID hashability. - """ - j1 = jid.JID("user@host/resource") - j2 = jid.JID("user@host/resource") - self.assertEqual(hash(j1), hash(j2)) - - def test_unicode(self): - """ - Test unicode representation of JIDs. - """ - j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEqual("user@host/resource", unicode(j)) - - def test_repr(self): - """ - Test representation of JID objects. - """ - j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEqual("JID(u'user@host/resource')", repr(j)) - -class InternJIDTests(unittest.TestCase): - def test_identity(self): - """ - Test that two interned JIDs yield the same object. - """ - j1 = jid.internJID("user@host") - j2 = jid.internJID("user@host") - self.assertIdentical(j1, j2) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberjstrports.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberjstrports.py deleted file mode 100644 index ac0c9c5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberjstrports.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.jstrports}. -""" - -from twisted.trial import unittest - -from twisted.words.protocols.jabber import jstrports -from twisted.application.internet import TCPClient - - -class JabberStrPortsPlaceHolderTests(unittest.TestCase): - """ - Tests for L{jstrports} - """ - - def test_parse(self): - """ - L{jstrports.parse} accepts an endpoint description string and returns a - tuple and dict of parsed endpoint arguments. - """ - expected = ('TCP', ('DOMAIN', 65535, 'Factory'), {}) - got = jstrports.parse("tcp:DOMAIN:65535", "Factory") - self.assertEqual(expected, got) - - - def test_client(self): - """ - L{jstrports.client} returns a L{TCPClient} service. - """ - got = jstrports.client("tcp:DOMAIN:65535", "Factory") - self.assertIsInstance(got, TCPClient) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbersasl.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbersasl.py deleted file mode 100644 index 536a893..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbersasl.py +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from zope.interface import implements -from twisted.internet import defer -from twisted.trial import unittest -from twisted.words.protocols.jabber import sasl, sasl_mechanisms, xmlstream, jid -from twisted.words.xish import domish - -NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl' - -class DummySASLMechanism(object): - """ - Dummy SASL mechanism. - - This just returns the initialResponse passed on creation, stores any - challenges and replies with an empty response. - - @ivar challenge: Last received challenge. - @type challenge: C{unicode}. - @ivar initialResponse: Initial response to be returned when requested - via C{getInitialResponse} or C{None}. - @type initialResponse: C{unicode} - """ - - implements(sasl_mechanisms.ISASLMechanism) - - challenge = None - name = "DUMMY" - - def __init__(self, initialResponse): - self.initialResponse = initialResponse - - def getInitialResponse(self): - return self.initialResponse - - def getResponse(self, challenge): - self.challenge = challenge - return "" - -class DummySASLInitiatingInitializer(sasl.SASLInitiatingInitializer): - """ - Dummy SASL Initializer for initiating entities. - - This hardwires the SASL mechanism to L{DummySASLMechanism}, that is - instantiated with the value of C{initialResponse}. - - @ivar initialResponse: The initial response to be returned by the - dummy SASL mechanism or C{None}. - @type initialResponse: C{unicode}. - """ - - initialResponse = None - - def setMechanism(self): - self.mechanism = DummySASLMechanism(self.initialResponse) - - - -class SASLInitiatingInitializerTests(unittest.TestCase): - """ - Tests for L{sasl.SASLInitiatingInitializer} - """ - - def setUp(self): - self.output = [] - - self.authenticator = xmlstream.Authenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345' version='1.0'>") - self.init = DummySASLInitiatingInitializer(self.xmlstream) - - - def test_onFailure(self): - """ - Test that the SASL error condition is correctly extracted. - """ - failure = domish.Element(('urn:ietf:params:xml:ns:xmpp-sasl', - 'failure')) - failure.addElement('not-authorized') - self.init._deferred = defer.Deferred() - self.init.onFailure(failure) - self.assertFailure(self.init._deferred, sasl.SASLAuthError) - self.init._deferred.addCallback(lambda e: - self.assertEqual('not-authorized', - e.condition)) - return self.init._deferred - - - def test_sendAuthInitialResponse(self): - """ - Test starting authentication with an initial response. - """ - self.init.initialResponse = "dummy" - self.init.start() - auth = self.output[0] - self.assertEqual(NS_XMPP_SASL, auth.uri) - self.assertEqual('auth', auth.name) - self.assertEqual('DUMMY', auth['mechanism']) - self.assertEqual('ZHVtbXk=', str(auth)) - - - def test_sendAuthNoInitialResponse(self): - """ - Test starting authentication without an initial response. - """ - self.init.initialResponse = None - self.init.start() - auth = self.output[0] - self.assertEqual('', str(auth)) - - - def test_sendAuthEmptyInitialResponse(self): - """ - Test starting authentication where the initial response is empty. - """ - self.init.initialResponse = "" - self.init.start() - auth = self.output[0] - self.assertEqual('=', str(auth)) - - - def test_onChallenge(self): - """ - Test receiving a challenge message. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('bXkgY2hhbGxlbmdl') - self.init.onChallenge(challenge) - self.assertEqual('my challenge', self.init.mechanism.challenge) - self.init.onSuccess(None) - return d - - - def test_onChallengeEmpty(self): - """ - Test receiving an empty challenge message. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - self.init.onChallenge(challenge) - self.assertEqual('', self.init.mechanism.challenge) - self.init.onSuccess(None) - return d - - - def test_onChallengeIllegalPadding(self): - """ - Test receiving a challenge message with illegal padding. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('bXkg=Y2hhbGxlbmdl') - self.init.onChallenge(challenge) - self.assertFailure(d, sasl.SASLIncorrectEncodingError) - return d - - - def test_onChallengeIllegalCharacters(self): - """ - Test receiving a challenge message with illegal characters. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('bXkg*Y2hhbGxlbmdl') - self.init.onChallenge(challenge) - self.assertFailure(d, sasl.SASLIncorrectEncodingError) - return d - - - def test_onChallengeMalformed(self): - """ - Test receiving a malformed challenge message. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('a') - self.init.onChallenge(challenge) - self.assertFailure(d, sasl.SASLIncorrectEncodingError) - return d - - -class SASLInitiatingInitializerSetMechanismTests(unittest.TestCase): - """ - Test for L{sasl.SASLInitiatingInitializer.setMechanism}. - """ - - def setUp(self): - self.output = [] - - self.authenticator = xmlstream.Authenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345' version='1.0'>") - - self.init = sasl.SASLInitiatingInitializer(self.xmlstream) - - - def _setMechanism(self, name): - """ - Set up the XML Stream to have a SASL feature with the given mechanism. - """ - feature = domish.Element((NS_XMPP_SASL, 'mechanisms')) - feature.addElement('mechanism', content=name) - self.xmlstream.features[(feature.uri, feature.name)] = feature - - self.init.setMechanism() - return self.init.mechanism.name - - - def test_anonymous(self): - """ - Test setting ANONYMOUS as the authentication mechanism. - """ - self.authenticator.jid = jid.JID('example.com') - self.authenticator.password = None - name = "ANONYMOUS" - - self.assertEqual(name, self._setMechanism(name)) - - - def test_plain(self): - """ - Test setting PLAIN as the authentication mechanism. - """ - self.authenticator.jid = jid.JID('test@example.com') - self.authenticator.password = 'secret' - name = "PLAIN" - - self.assertEqual(name, self._setMechanism(name)) - - - def test_digest(self): - """ - Test setting DIGEST-MD5 as the authentication mechanism. - """ - self.authenticator.jid = jid.JID('test@example.com') - self.authenticator.password = 'secret' - name = "DIGEST-MD5" - - self.assertEqual(name, self._setMechanism(name)) - - - def test_notAcceptable(self): - """ - Test using an unacceptable SASL authentication mechanism. - """ - - self.authenticator.jid = jid.JID('test@example.com') - self.authenticator.password = 'secret' - - self.assertRaises(sasl.SASLNoAcceptableMechanism, - self._setMechanism, 'SOMETHING_UNACCEPTABLE') - - - def test_notAcceptableWithoutUser(self): - """ - Test using an unacceptable SASL authentication mechanism with no JID. - """ - self.authenticator.jid = jid.JID('example.com') - self.authenticator.password = 'secret' - - self.assertRaises(sasl.SASLNoAcceptableMechanism, - self._setMechanism, 'SOMETHING_UNACCEPTABLE') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbersaslmechanisms.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbersaslmechanisms.py deleted file mode 100644 index 9be5e6d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabbersaslmechanisms.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.sasl_mechanisms}. -""" - -from twisted.trial import unittest - -from twisted.words.protocols.jabber import sasl_mechanisms - -class PlainTests(unittest.TestCase): - def test_getInitialResponse(self): - """ - Test the initial response. - """ - m = sasl_mechanisms.Plain(None, 'test', 'secret') - self.assertEqual(m.getInitialResponse(), '\x00test\x00secret') - - - -class AnonymousTests(unittest.TestCase): - """ - Tests for L{twisted.words.protocols.jabber.sasl_mechanisms.Anonymous}. - """ - def test_getInitialResponse(self): - """ - Test the initial response to be empty. - """ - m = sasl_mechanisms.Anonymous() - self.assertEqual(m.getInitialResponse(), None) - - - -class DigestMD5Tests(unittest.TestCase): - def setUp(self): - self.mechanism = sasl_mechanisms.DigestMD5( - u'xmpp', u'example.org', None, u'test', u'secret') - - - def test_getInitialResponse(self): - """ - Test that no initial response is generated. - """ - self.assertIdentical(self.mechanism.getInitialResponse(), None) - - - def test_getResponse(self): - """ - The response to a Digest-MD5 challenge includes the parameters from the - challenge. - """ - challenge = ( - 'realm="localhost",nonce="1234",qop="auth",charset=utf-8,' - 'algorithm=md5-sess') - directives = self.mechanism._parse( - self.mechanism.getResponse(challenge)) - del directives["cnonce"], directives["response"] - self.assertEqual({ - 'username': 'test', 'nonce': '1234', 'nc': '00000001', - 'qop': ['auth'], 'charset': 'utf-8', 'realm': 'localhost', - 'digest-uri': 'xmpp/example.org' - }, directives) - - - def test_getResponseNonAsciiRealm(self): - """ - Bytes outside the ASCII range in the challenge are nevertheless - included in the response. - """ - challenge = ('realm="\xc3\xa9chec.example.org",nonce="1234",' - 'qop="auth",charset=utf-8,algorithm=md5-sess') - directives = self.mechanism._parse( - self.mechanism.getResponse(challenge)) - del directives["cnonce"], directives["response"] - self.assertEqual({ - 'username': 'test', 'nonce': '1234', 'nc': '00000001', - 'qop': ['auth'], 'charset': 'utf-8', - 'realm': '\xc3\xa9chec.example.org', - 'digest-uri': 'xmpp/example.org'}, directives) - - - def test_getResponseNoRealm(self): - """ - The response to a challenge without a realm uses the host part of the - JID as the realm. - """ - challenge = 'nonce="1234",qop="auth",charset=utf-8,algorithm=md5-sess' - directives = self.mechanism._parse(self.mechanism.getResponse(challenge)) - self.assertEqual(directives['realm'], 'example.org') - - - def test_getResponseNoRealmIDN(self): - """ - If the challenge does not include a realm and the host part of the JID - includes bytes outside of the ASCII range, the response still includes - the host part of the JID as the realm. - """ - self.mechanism = sasl_mechanisms.DigestMD5( - u'xmpp', u'\u00e9chec.example.org', None, u'test', u'secret') - challenge = 'nonce="1234",qop="auth",charset=utf-8,algorithm=md5-sess' - directives = self.mechanism._parse( - self.mechanism.getResponse(challenge)) - self.assertEqual(directives['realm'], '\xc3\xa9chec.example.org') - - - def test_calculateResponse(self): - """ - The response to a Digest-MD5 challenge is computed according to RFC - 2831. - """ - charset = 'utf-8' - nonce = 'OA6MG9tEQGm2hh' - nc = '%08x' % (1,) - cnonce = 'OA6MHXh6VqTrRk' - - username = u'\u0418chris' - password = u'\u0418secret' - host = u'\u0418elwood.innosoft.com' - digestURI = u'imap/\u0418elwood.innosoft.com'.encode(charset) - - mechanism = sasl_mechanisms.DigestMD5( - 'imap', host, None, username, password) - response = mechanism._calculateResponse( - cnonce, nc, nonce, username.encode(charset), - password.encode(charset), host.encode(charset), digestURI) - self.assertEqual(response, '7928f233258be88392424d094453c5e3') - - - def test_parse(self): - """ - A challenge can be parsed into a L{dict} with L{bytes} or L{list} - values. - """ - challenge = ( - 'nonce="1234",qop="auth,auth-conf",charset=utf-8,' - 'algorithm=md5-sess,cipher="des,3des"') - directives = self.mechanism._parse(challenge) - self.assertEqual({ - "algorithm": "md5-sess", "nonce": "1234", "charset": "utf-8", - "qop": ['auth', 'auth-conf'], "cipher": ['des', '3des'] - }, directives) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberxmlstream.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberxmlstream.py deleted file mode 100644 index a0ccad4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberxmlstream.py +++ /dev/null @@ -1,1333 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.xmlstream}. -""" - -from twisted.trial import unittest - -from zope.interface.verify import verifyObject - -from twisted.internet import defer, task -from twisted.internet.error import ConnectionLost -from twisted.internet.interfaces import IProtocolFactory -from twisted.python import failure -from twisted.test import proto_helpers -from twisted.words.test.test_xmlstream import GenericXmlStreamFactoryTestsMixin -from twisted.words.xish import domish -from twisted.words.protocols.jabber import error, ijabber, jid, xmlstream - - - -NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls' - - - -class HashPasswordTests(unittest.TestCase): - """ - Tests for L{xmlstream.hashPassword}. - """ - - def test_basic(self): - """ - The sid and secret are concatenated to calculate sha1 hex digest. - """ - hash = xmlstream.hashPassword(u"12345", u"secret") - self.assertEqual('99567ee91b2c7cabf607f10cb9f4a3634fa820e0', hash) - - - def test_sidNotUnicode(self): - """ - The session identifier must be a unicode object. - """ - self.assertRaises(TypeError, xmlstream.hashPassword, "\xc2\xb92345", - u"secret") - - - def test_passwordNotUnicode(self): - """ - The password must be a unicode object. - """ - self.assertRaises(TypeError, xmlstream.hashPassword, u"12345", - "secr\xc3\xa9t") - - - def test_unicodeSecret(self): - """ - The concatenated sid and password must be encoded to UTF-8 before hashing. - """ - hash = xmlstream.hashPassword(u"12345", u"secr\u00e9t") - self.assertEqual('659bf88d8f8e179081f7f3b4a8e7d224652d2853', hash) - - - -class IQTests(unittest.TestCase): - """ - Tests both IQ and the associated IIQResponseTracker callback. - """ - - def setUp(self): - authenticator = xmlstream.ConnectAuthenticator('otherhost') - authenticator.namespace = 'testns' - self.xmlstream = xmlstream.XmlStream(authenticator) - self.clock = task.Clock() - self.xmlstream._callLater = self.clock.callLater - self.xmlstream.makeConnection(proto_helpers.StringTransport()) - self.xmlstream.dataReceived( - "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' " - "xmlns='testns' from='otherhost' version='1.0'>") - self.iq = xmlstream.IQ(self.xmlstream, 'get') - - - def testBasic(self): - self.assertEqual(self.iq['type'], 'get') - self.assertTrue(self.iq['id']) - - - def testSend(self): - self.xmlstream.transport.clear() - self.iq.send() - self.assertIn(self.xmlstream.transport.value(), [ - "<iq type='get' id='%s'/>" % self.iq['id'], - "<iq id='%s' type='get'/>" % self.iq['id'], - ]) - - - def testResultResponse(self): - def cb(result): - self.assertEqual(result['type'], 'result') - - d = self.iq.send() - d.addCallback(cb) - - xs = self.xmlstream - xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id']) - return d - - - def testErrorResponse(self): - d = self.iq.send() - self.assertFailure(d, error.StanzaError) - - xs = self.xmlstream - xs.dataReceived("<iq type='error' id='%s'/>" % self.iq['id']) - return d - - - def testNonTrackedResponse(self): - """ - Test that untracked iq responses don't trigger any action. - - Untracked means that the id of the incoming response iq is not - in the stream's C{iqDeferreds} dictionary. - """ - xs = self.xmlstream - xmlstream.upgradeWithIQResponseTracker(xs) - - # Make sure we aren't tracking any iq's. - self.assertFalse(xs.iqDeferreds) - - # Set up a fallback handler that checks the stanza's handled attribute. - # If that is set to True, the iq tracker claims to have handled the - # response. - def cb(iq): - self.assertFalse(getattr(iq, 'handled', False)) - - xs.addObserver("/iq", cb, -1) - - # Receive an untracked iq response - xs.dataReceived("<iq type='result' id='test'/>") - - - def testCleanup(self): - """ - Test if the deferred associated with an iq request is removed - from the list kept in the L{XmlStream} object after it has - been fired. - """ - - d = self.iq.send() - xs = self.xmlstream - xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id']) - self.assertNotIn(self.iq['id'], xs.iqDeferreds) - return d - - - def testDisconnectCleanup(self): - """ - Test if deferreds for iq's that haven't yet received a response - have their errback called on stream disconnect. - """ - - d = self.iq.send() - xs = self.xmlstream - xs.connectionLost("Closed by peer") - self.assertFailure(d, ConnectionLost) - return d - - - def testNoModifyingDict(self): - """ - Test to make sure the errbacks cannot cause the iteration of the - iqDeferreds to blow up in our face. - """ - - def eb(failure): - d = xmlstream.IQ(self.xmlstream).send() - d.addErrback(eb) - - d = self.iq.send() - d.addErrback(eb) - self.xmlstream.connectionLost("Closed by peer") - return d - - - def testRequestTimingOut(self): - """ - Test that an iq request with a defined timeout times out. - """ - self.iq.timeout = 60 - d = self.iq.send() - self.assertFailure(d, xmlstream.TimeoutError) - - self.clock.pump([1, 60]) - self.assertFalse(self.clock.calls) - self.assertFalse(self.xmlstream.iqDeferreds) - return d - - - def testRequestNotTimingOut(self): - """ - Test that an iq request with a defined timeout does not time out - when a response was received before the timeout period elapsed. - """ - self.iq.timeout = 60 - d = self.iq.send() - self.clock.callLater(1, self.xmlstream.dataReceived, - "<iq type='result' id='%s'/>" % self.iq['id']) - self.clock.pump([1, 1]) - self.assertFalse(self.clock.calls) - return d - - - def testDisconnectTimeoutCancellation(self): - """ - Test if timeouts for iq's that haven't yet received a response - are cancelled on stream disconnect. - """ - - self.iq.timeout = 60 - d = self.iq.send() - - xs = self.xmlstream - xs.connectionLost("Closed by peer") - self.assertFailure(d, ConnectionLost) - self.assertFalse(self.clock.calls) - return d - - - -class XmlStreamTests(unittest.TestCase): - - def onStreamStart(self, obj): - self.gotStreamStart = True - - - def onStreamEnd(self, obj): - self.gotStreamEnd = True - - - def onStreamError(self, obj): - self.gotStreamError = True - - - def setUp(self): - """ - Set up XmlStream and several observers. - """ - self.gotStreamStart = False - self.gotStreamEnd = False - self.gotStreamError = False - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - xs.addObserver('//event/stream/start', self.onStreamStart) - xs.addObserver('//event/stream/end', self.onStreamEnd) - xs.addObserver('//event/stream/error', self.onStreamError) - xs.makeConnection(proto_helpers.StringTransportWithDisconnection()) - xs.transport.protocol = xs - xs.namespace = 'testns' - xs.version = (1, 0) - self.xmlstream = xs - - - def test_sendHeaderBasic(self): - """ - Basic test on the header sent by sendHeader. - """ - xs = self.xmlstream - xs.sendHeader() - splitHeader = self.xmlstream.transport.value()[0:-1].split(' ') - self.assertIn("<stream:stream", splitHeader) - self.assertIn("xmlns:stream='http://etherx.jabber.org/streams'", - splitHeader) - self.assertIn("xmlns='testns'", splitHeader) - self.assertIn("version='1.0'", splitHeader) - self.assertTrue(xs._headerSent) - - - def test_sendHeaderAdditionalNamespaces(self): - """ - Test for additional namespace declarations. - """ - xs = self.xmlstream - xs.prefixes['jabber:server:dialback'] = 'db' - xs.sendHeader() - splitHeader = self.xmlstream.transport.value()[0:-1].split(' ') - self.assertIn("<stream:stream", splitHeader) - self.assertIn("xmlns:stream='http://etherx.jabber.org/streams'", - splitHeader) - self.assertIn("xmlns:db='jabber:server:dialback'", splitHeader) - self.assertIn("xmlns='testns'", splitHeader) - self.assertIn("version='1.0'", splitHeader) - self.assertTrue(xs._headerSent) - - - def test_sendHeaderInitiating(self): - """ - Test addressing when initiating a stream. - """ - xs = self.xmlstream - xs.thisEntity = jid.JID('thisHost') - xs.otherEntity = jid.JID('otherHost') - xs.initiating = True - xs.sendHeader() - splitHeader = xs.transport.value()[0:-1].split(' ') - self.assertIn("to='otherhost'", splitHeader) - self.assertIn("from='thishost'", splitHeader) - - - def test_sendHeaderReceiving(self): - """ - Test addressing when receiving a stream. - """ - xs = self.xmlstream - xs.thisEntity = jid.JID('thisHost') - xs.otherEntity = jid.JID('otherHost') - xs.initiating = False - xs.sid = 'session01' - xs.sendHeader() - splitHeader = xs.transport.value()[0:-1].split(' ') - self.assertIn("to='otherhost'", splitHeader) - self.assertIn("from='thishost'", splitHeader) - self.assertIn("id='session01'", splitHeader) - - - def test_receiveStreamError(self): - """ - Test events when a stream error is received. - """ - xs = self.xmlstream - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345' version='1.0'>") - xs.dataReceived("<stream:error/>") - self.assertTrue(self.gotStreamError) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorInitiating(self): - """ - Test sendStreamError on an initiating xmlstream with a header sent. - - An error should be sent out and the connection lost. - """ - xs = self.xmlstream - xs.initiating = True - xs.sendHeader() - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertNotEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorInitiatingNoHeader(self): - """ - Test sendStreamError on an initiating xmlstream without having sent a - header. - - In this case, no header should be generated. Also, the error should - not be sent out on the stream. Just closing the connection. - """ - xs = self.xmlstream - xs.initiating = True - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertNot(xs._headerSent) - self.assertEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorReceiving(self): - """ - Test sendStreamError on a receiving xmlstream with a header sent. - - An error should be sent out and the connection lost. - """ - xs = self.xmlstream - xs.initiating = False - xs.sendHeader() - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertNotEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorReceivingNoHeader(self): - """ - Test sendStreamError on a receiving xmlstream without having sent a - header. - - In this case, a header should be generated. Then, the error should - be sent out on the stream followed by closing the connection. - """ - xs = self.xmlstream - xs.initiating = False - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertTrue(xs._headerSent) - self.assertNotEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_reset(self): - """ - Test resetting the XML stream to start a new layer. - """ - xs = self.xmlstream - xs.sendHeader() - stream = xs.stream - xs.reset() - self.assertNotEqual(stream, xs.stream) - self.assertNot(xs._headerSent) - - - def test_send(self): - """ - Test send with various types of objects. - """ - xs = self.xmlstream - xs.send('<presence/>') - self.assertEqual(xs.transport.value(), '<presence/>') - - xs.transport.clear() - el = domish.Element(('testns', 'presence')) - xs.send(el) - self.assertEqual(xs.transport.value(), '<presence/>') - - xs.transport.clear() - el = domish.Element(('http://etherx.jabber.org/streams', 'features')) - xs.send(el) - self.assertEqual(xs.transport.value(), '<stream:features/>') - - - def test_authenticator(self): - """ - Test that the associated authenticator is correctly called. - """ - connectionMadeCalls = [] - streamStartedCalls = [] - associateWithStreamCalls = [] - - class TestAuthenticator: - def connectionMade(self): - connectionMadeCalls.append(None) - - def streamStarted(self, rootElement): - streamStartedCalls.append(rootElement) - - def associateWithStream(self, xs): - associateWithStreamCalls.append(xs) - - a = TestAuthenticator() - xs = xmlstream.XmlStream(a) - self.assertEqual([xs], associateWithStreamCalls) - xs.connectionMade() - self.assertEqual([None], connectionMadeCalls) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345'>") - self.assertEqual(1, len(streamStartedCalls)) - xs.reset() - self.assertEqual([None], connectionMadeCalls) - - - -class TestError(Exception): - pass - - - -class AuthenticatorTests(unittest.TestCase): - def setUp(self): - self.authenticator = xmlstream.Authenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - - - def test_streamStart(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.org' to='example.com' id='12345' " - "version='1.0'>") - self.assertEqual((1, 0), xs.version) - self.assertIdentical(None, xs.sid) - self.assertEqual('invalid', xs.namespace) - self.assertIdentical(None, xs.otherEntity) - self.assertEqual(None, xs.thisEntity) - - - def test_streamStartLegacy(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header for a pre-XMPP-1.0 header. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345'>") - self.assertEqual((0, 0), xs.version) - - - def test_streamBadVersionOneDigit(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header for a version with only one digit. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345' version='1'>") - self.assertEqual((0, 0), xs.version) - - - def test_streamBadVersionNoNumber(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header for a malformed version. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345' version='blah'>") - self.assertEqual((0, 0), xs.version) - - - -class ConnectAuthenticatorTests(unittest.TestCase): - - def setUp(self): - self.gotAuthenticated = False - self.initFailure = None - self.authenticator = xmlstream.ConnectAuthenticator('otherHost') - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.addObserver('//event/stream/authd', self.onAuthenticated) - self.xmlstream.addObserver('//event/xmpp/initfailed', self.onInitFailed) - - - def onAuthenticated(self, obj): - self.gotAuthenticated = True - - - def onInitFailed(self, failure): - self.initFailure = failure - - - def testSucces(self): - """ - Test successful completion of an initialization step. - """ - class Initializer: - def initialize(self): - pass - - init = Initializer() - self.xmlstream.initializers = [init] - - self.authenticator.initializeStream() - self.assertEqual([], self.xmlstream.initializers) - self.assertTrue(self.gotAuthenticated) - - - def testFailure(self): - """ - Test failure of an initialization step. - """ - class Initializer: - def initialize(self): - raise TestError - - init = Initializer() - self.xmlstream.initializers = [init] - - self.authenticator.initializeStream() - self.assertEqual([init], self.xmlstream.initializers) - self.assertFalse(self.gotAuthenticated) - self.assertNotIdentical(None, self.initFailure) - self.assertTrue(self.initFailure.check(TestError)) - - - def test_streamStart(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header. - """ - self.authenticator.namespace = 'testns' - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' to='example.org' id='12345' " - "version='1.0'>") - self.assertEqual((1, 0), xs.version) - self.assertEqual('12345', xs.sid) - self.assertEqual('testns', xs.namespace) - self.assertEqual('example.com', xs.otherEntity.host) - self.assertIdentical(None, xs.thisEntity) - self.assertNot(self.gotAuthenticated) - xs.dataReceived("<stream:features>" - "<test xmlns='testns'/>" - "</stream:features>") - self.assertIn(('testns', 'test'), xs.features) - self.assertTrue(self.gotAuthenticated) - - - -class ListenAuthenticatorTests(unittest.TestCase): - """ - Tests for L{xmlstream.ListenAuthenticator} - """ - - def setUp(self): - self.authenticator = xmlstream.ListenAuthenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - - - def test_streamStart(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - self.assertIdentical(None, xs.sid) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.org' to='example.com' id='12345' " - "version='1.0'>") - self.assertEqual((1, 0), xs.version) - self.assertNotIdentical(None, xs.sid) - self.assertNotEquals('12345', xs.sid) - self.assertEqual('jabber:client', xs.namespace) - self.assertIdentical(None, xs.otherEntity) - self.assertEqual('example.com', xs.thisEntity.host) - - - def test_streamStartUnicodeSessionID(self): - """ - The generated session id must be a unicode object. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.org' to='example.com' id='12345' " - "version='1.0'>") - self.assertIsInstance(xs.sid, unicode) - - - -class TLSInitiatingInitializerTests(unittest.TestCase): - def setUp(self): - self.output = [] - self.done = [] - - self.savedSSL = xmlstream.ssl - - self.authenticator = xmlstream.Authenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345' version='1.0'>") - self.init = xmlstream.TLSInitiatingInitializer(self.xmlstream) - - - def tearDown(self): - xmlstream.ssl = self.savedSSL - - - def testWantedSupported(self): - """ - Test start when TLS is wanted and the SSL library available. - """ - self.xmlstream.transport = proto_helpers.StringTransport() - self.xmlstream.transport.startTLS = lambda ctx: self.done.append('TLS') - self.xmlstream.reset = lambda: self.done.append('reset') - self.xmlstream.sendHeader = lambda: self.done.append('header') - - d = self.init.start() - d.addCallback(self.assertEqual, xmlstream.Reset) - starttls = self.output[0] - self.assertEqual('starttls', starttls.name) - self.assertEqual(NS_XMPP_TLS, starttls.uri) - self.xmlstream.dataReceived("<proceed xmlns='%s'/>" % NS_XMPP_TLS) - self.assertEqual(['TLS', 'reset', 'header'], self.done) - - return d - - if not xmlstream.ssl: - testWantedSupported.skip = "SSL not available" - - - def testWantedNotSupportedNotRequired(self): - """ - Test start when TLS is wanted and the SSL library available. - """ - xmlstream.ssl = None - - d = self.init.start() - d.addCallback(self.assertEqual, None) - self.assertEqual([], self.output) - - return d - - - def testWantedNotSupportedRequired(self): - """ - Test start when TLS is wanted and the SSL library available. - """ - xmlstream.ssl = None - self.init.required = True - - d = self.init.start() - self.assertFailure(d, xmlstream.TLSNotSupported) - self.assertEqual([], self.output) - - return d - - - def testNotWantedRequired(self): - """ - Test start when TLS is not wanted, but required by the server. - """ - tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls')) - tls.addElement('required') - self.xmlstream.features = {(tls.uri, tls.name): tls} - self.init.wanted = False - - d = self.init.start() - self.assertEqual([], self.output) - self.assertFailure(d, xmlstream.TLSRequired) - - return d - - - def testNotWantedNotRequired(self): - """ - Test start when TLS is not wanted, but required by the server. - """ - tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls')) - self.xmlstream.features = {(tls.uri, tls.name): tls} - self.init.wanted = False - - d = self.init.start() - d.addCallback(self.assertEqual, None) - self.assertEqual([], self.output) - return d - - - def testFailed(self): - """ - Test failed TLS negotiation. - """ - # Pretend that ssl is supported, it isn't actually used when the - # server starts out with a failure in response to our initial - # C{starttls} stanza. - xmlstream.ssl = 1 - - d = self.init.start() - self.assertFailure(d, xmlstream.TLSFailed) - self.xmlstream.dataReceived("<failure xmlns='%s'/>" % NS_XMPP_TLS) - return d - - - -class TestFeatureInitializer(xmlstream.BaseFeatureInitiatingInitializer): - feature = ('testns', 'test') - - def start(self): - return defer.succeed(None) - - - -class BaseFeatureInitiatingInitializerTests(unittest.TestCase): - - def setUp(self): - self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator()) - self.init = TestFeatureInitializer(self.xmlstream) - - - def testAdvertized(self): - """ - Test that an advertized feature results in successful initialization. - """ - self.xmlstream.features = {self.init.feature: - domish.Element(self.init.feature)} - return self.init.initialize() - - - def testNotAdvertizedRequired(self): - """ - Test that when the feature is not advertized, but required by the - initializer, an exception is raised. - """ - self.init.required = True - self.assertRaises(xmlstream.FeatureNotAdvertized, self.init.initialize) - - - def testNotAdvertizedNotRequired(self): - """ - Test that when the feature is not advertized, and not required by the - initializer, the initializer silently succeeds. - """ - self.init.required = False - self.assertIdentical(None, self.init.initialize()) - - - -class ToResponseTests(unittest.TestCase): - - def test_toResponse(self): - """ - Test that a response stanza is generated with addressing swapped. - """ - stanza = domish.Element(('jabber:client', 'iq')) - stanza['type'] = 'get' - stanza['to'] = 'user1@example.com' - stanza['from'] = 'user2@example.com/resource' - stanza['id'] = 'stanza1' - response = xmlstream.toResponse(stanza, 'result') - self.assertNotIdentical(stanza, response) - self.assertEqual(response['from'], 'user1@example.com') - self.assertEqual(response['to'], 'user2@example.com/resource') - self.assertEqual(response['type'], 'result') - self.assertEqual(response['id'], 'stanza1') - - - def test_toResponseNoFrom(self): - """ - Test that a response is generated from a stanza without a from address. - """ - stanza = domish.Element(('jabber:client', 'iq')) - stanza['type'] = 'get' - stanza['to'] = 'user1@example.com' - response = xmlstream.toResponse(stanza) - self.assertEqual(response['from'], 'user1@example.com') - self.assertFalse(response.hasAttribute('to')) - - - def test_toResponseNoTo(self): - """ - Test that a response is generated from a stanza without a to address. - """ - stanza = domish.Element(('jabber:client', 'iq')) - stanza['type'] = 'get' - stanza['from'] = 'user2@example.com/resource' - response = xmlstream.toResponse(stanza) - self.assertFalse(response.hasAttribute('from')) - self.assertEqual(response['to'], 'user2@example.com/resource') - - - def test_toResponseNoAddressing(self): - """ - Test that a response is generated from a stanza without any addressing. - """ - stanza = domish.Element(('jabber:client', 'message')) - stanza['type'] = 'chat' - response = xmlstream.toResponse(stanza) - self.assertFalse(response.hasAttribute('to')) - self.assertFalse(response.hasAttribute('from')) - - - def test_noID(self): - """ - Test that a proper response is generated without id attribute. - """ - stanza = domish.Element(('jabber:client', 'message')) - response = xmlstream.toResponse(stanza) - self.assertFalse(response.hasAttribute('id')) - - - def test_noType(self): - """ - Test that a proper response is generated without type attribute. - """ - stanza = domish.Element(('jabber:client', 'message')) - response = xmlstream.toResponse(stanza) - self.assertFalse(response.hasAttribute('type')) - - -class DummyFactory(object): - """ - Dummy XmlStream factory that only registers bootstrap observers. - """ - def __init__(self): - self.callbacks = {} - - - def addBootstrap(self, event, callback): - self.callbacks[event] = callback - - - -class DummyXMPPHandler(xmlstream.XMPPHandler): - """ - Dummy XMPP subprotocol handler to count the methods are called on it. - """ - def __init__(self): - self.doneMade = 0 - self.doneInitialized = 0 - self.doneLost = 0 - - - def makeConnection(self, xs): - self.connectionMade() - - - def connectionMade(self): - self.doneMade += 1 - - - def connectionInitialized(self): - self.doneInitialized += 1 - - - def connectionLost(self, reason): - self.doneLost += 1 - - - -class FailureReasonXMPPHandler(xmlstream.XMPPHandler): - """ - Dummy handler specifically for failure Reason tests. - """ - def __init__(self): - self.gotFailureReason = False - - - def connectionLost(self, reason): - if isinstance(reason, failure.Failure): - self.gotFailureReason = True - - - -class XMPPHandlerTests(unittest.TestCase): - """ - Tests for L{xmlstream.XMPPHandler}. - """ - - def test_interface(self): - """ - L{xmlstream.XMPPHandler} implements L{ijabber.IXMPPHandler}. - """ - verifyObject(ijabber.IXMPPHandler, xmlstream.XMPPHandler()) - - - def test_send(self): - """ - Test that data is passed on for sending by the stream manager. - """ - class DummyStreamManager(object): - def __init__(self): - self.outlist = [] - - def send(self, data): - self.outlist.append(data) - - handler = xmlstream.XMPPHandler() - handler.parent = DummyStreamManager() - handler.send('<presence/>') - self.assertEqual(['<presence/>'], handler.parent.outlist) - - - def test_makeConnection(self): - """ - Test that makeConnection saves the XML stream and calls connectionMade. - """ - class TestXMPPHandler(xmlstream.XMPPHandler): - def connectionMade(self): - self.doneMade = True - - handler = TestXMPPHandler() - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - handler.makeConnection(xs) - self.assertTrue(handler.doneMade) - self.assertIdentical(xs, handler.xmlstream) - - - def test_connectionLost(self): - """ - Test that connectionLost forgets the XML stream. - """ - handler = xmlstream.XMPPHandler() - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - handler.makeConnection(xs) - handler.connectionLost(Exception()) - self.assertIdentical(None, handler.xmlstream) - - - -class XMPPHandlerCollectionTests(unittest.TestCase): - """ - Tests for L{xmlstream.XMPPHandlerCollection}. - """ - - def setUp(self): - self.collection = xmlstream.XMPPHandlerCollection() - - - def test_interface(self): - """ - L{xmlstream.StreamManager} implements L{ijabber.IXMPPHandlerCollection}. - """ - verifyObject(ijabber.IXMPPHandlerCollection, self.collection) - - - def test_addHandler(self): - """ - Test the addition of a protocol handler. - """ - handler = DummyXMPPHandler() - handler.setHandlerParent(self.collection) - self.assertIn(handler, self.collection) - self.assertIdentical(self.collection, handler.parent) - - - def test_removeHandler(self): - """ - Test removal of a protocol handler. - """ - handler = DummyXMPPHandler() - handler.setHandlerParent(self.collection) - handler.disownHandlerParent(self.collection) - self.assertNotIn(handler, self.collection) - self.assertIdentical(None, handler.parent) - - - -class StreamManagerTests(unittest.TestCase): - """ - Tests for L{xmlstream.StreamManager}. - """ - - def setUp(self): - factory = DummyFactory() - self.streamManager = xmlstream.StreamManager(factory) - - - def test_basic(self): - """ - Test correct initialization and setup of factory observers. - """ - sm = self.streamManager - self.assertIdentical(None, sm.xmlstream) - self.assertEqual([], sm.handlers) - self.assertEqual(sm._connected, - sm.factory.callbacks['//event/stream/connected']) - self.assertEqual(sm._authd, - sm.factory.callbacks['//event/stream/authd']) - self.assertEqual(sm._disconnected, - sm.factory.callbacks['//event/stream/end']) - self.assertEqual(sm.initializationFailed, - sm.factory.callbacks['//event/xmpp/initfailed']) - - - def test_connected(self): - """ - Test that protocol handlers have their connectionMade method called - when the XML stream is connected. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - self.assertEqual(1, handler.doneMade) - self.assertEqual(0, handler.doneInitialized) - self.assertEqual(0, handler.doneLost) - - - def test_connectedLogTrafficFalse(self): - """ - Test raw data functions unset when logTraffic is set to False. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - self.assertIdentical(None, xs.rawDataInFn) - self.assertIdentical(None, xs.rawDataOutFn) - - - def test_connectedLogTrafficTrue(self): - """ - Test raw data functions set when logTraffic is set to True. - """ - sm = self.streamManager - sm.logTraffic = True - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - self.assertNotIdentical(None, xs.rawDataInFn) - self.assertNotIdentical(None, xs.rawDataOutFn) - - - def test_authd(self): - """ - Test that protocol handlers have their connectionInitialized method - called when the XML stream is initialized. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._authd(xs) - self.assertEqual(0, handler.doneMade) - self.assertEqual(1, handler.doneInitialized) - self.assertEqual(0, handler.doneLost) - - - def test_disconnected(self): - """ - Test that protocol handlers have their connectionLost method - called when the XML stream is disconnected. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._disconnected(xs) - self.assertEqual(0, handler.doneMade) - self.assertEqual(0, handler.doneInitialized) - self.assertEqual(1, handler.doneLost) - - - def test_disconnectedReason(self): - """ - A L{STREAM_END_EVENT} results in L{StreamManager} firing the handlers - L{connectionLost} methods, passing a L{failure.Failure} reason. - """ - sm = self.streamManager - handler = FailureReasonXMPPHandler() - handler.setHandlerParent(sm) - sm._disconnected(failure.Failure(Exception("no reason"))) - self.assertEqual(True, handler.gotFailureReason) - - - def test_addHandler(self): - """ - Test the addition of a protocol handler while not connected. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - - self.assertEqual(0, handler.doneMade) - self.assertEqual(0, handler.doneInitialized) - self.assertEqual(0, handler.doneLost) - - - def test_addHandlerInitialized(self): - """ - Test the addition of a protocol handler after the stream - have been initialized. - - Make sure that the handler will have the connected stream - passed via C{makeConnection} and have C{connectionInitialized} - called. - """ - sm = self.streamManager - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - sm._authd(xs) - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - - self.assertEqual(1, handler.doneMade) - self.assertEqual(1, handler.doneInitialized) - self.assertEqual(0, handler.doneLost) - - - def test_sendInitialized(self): - """ - Test send when the stream has been initialized. - - The data should be sent directly over the XML stream. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - xs = factory.buildProtocol(None) - xs.transport = proto_helpers.StringTransport() - xs.connectionMade() - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345'>") - xs.dispatch(xs, "//event/stream/authd") - sm.send("<presence/>") - self.assertEqual("<presence/>", xs.transport.value()) - - - def test_sendNotConnected(self): - """ - Test send when there is no established XML stream. - - The data should be cached until an XML stream has been established and - initialized. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - handler = DummyXMPPHandler() - sm.addHandler(handler) - - xs = factory.buildProtocol(None) - xs.transport = proto_helpers.StringTransport() - sm.send("<presence/>") - self.assertEqual("", xs.transport.value()) - self.assertEqual("<presence/>", sm._packetQueue[0]) - - xs.connectionMade() - self.assertEqual("", xs.transport.value()) - self.assertEqual("<presence/>", sm._packetQueue[0]) - - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345'>") - xs.dispatch(xs, "//event/stream/authd") - - self.assertEqual("<presence/>", xs.transport.value()) - self.assertFalse(sm._packetQueue) - - - def test_sendNotInitialized(self): - """ - Test send when the stream is connected but not yet initialized. - - The data should be cached until the XML stream has been initialized. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - xs = factory.buildProtocol(None) - xs.transport = proto_helpers.StringTransport() - xs.connectionMade() - xs.dataReceived("<stream:stream xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams' " - "from='example.com' id='12345'>") - sm.send("<presence/>") - self.assertEqual("", xs.transport.value()) - self.assertEqual("<presence/>", sm._packetQueue[0]) - - - def test_sendDisconnected(self): - """ - Test send after XML stream disconnection. - - The data should be cached until a new XML stream has been established - and initialized. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - handler = DummyXMPPHandler() - sm.addHandler(handler) - - xs = factory.buildProtocol(None) - xs.connectionMade() - xs.transport = proto_helpers.StringTransport() - xs.connectionLost(None) - - sm.send("<presence/>") - self.assertEqual("", xs.transport.value()) - self.assertEqual("<presence/>", sm._packetQueue[0]) - - - -class XmlStreamServerFactoryTests(GenericXmlStreamFactoryTestsMixin): - """ - Tests for L{xmlstream.XmlStreamServerFactory}. - """ - - def setUp(self): - """ - Set up a server factory with a authenticator factory function. - """ - class TestAuthenticator(object): - def __init__(self): - self.xmlstreams = [] - - def associateWithStream(self, xs): - self.xmlstreams.append(xs) - - def authenticatorFactory(): - return TestAuthenticator() - - self.factory = xmlstream.XmlStreamServerFactory(authenticatorFactory) - - - def test_interface(self): - """ - L{XmlStreamServerFactory} is a L{Factory}. - """ - verifyObject(IProtocolFactory, self.factory) - - - def test_buildProtocolAuthenticatorInstantiation(self): - """ - The authenticator factory should be used to instantiate the - authenticator and pass it to the protocol. - - The default protocol, L{XmlStream} stores the authenticator it is - passed, and calls its C{associateWithStream} method. so we use that to - check whether our authenticator factory is used and the protocol - instance gets an authenticator. - """ - xs = self.factory.buildProtocol(None) - self.assertEqual([xs], xs.authenticator.xmlstreams) - - - def test_buildProtocolXmlStream(self): - """ - The protocol factory creates Jabber XML Stream protocols by default. - """ - xs = self.factory.buildProtocol(None) - self.assertIsInstance(xs, xmlstream.XmlStream) - - - def test_buildProtocolTwice(self): - """ - Subsequent calls to buildProtocol should result in different instances - of the protocol, as well as their authenticators. - """ - xs1 = self.factory.buildProtocol(None) - xs2 = self.factory.buildProtocol(None) - self.assertNotIdentical(xs1, xs2) - self.assertNotIdentical(xs1.authenticator, xs2.authenticator) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberxmppstringprep.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberxmppstringprep.py deleted file mode 100644 index eadce66..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_jabberxmppstringprep.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest - -from twisted.words.protocols.jabber.xmpp_stringprep import ( - nodeprep, resourceprep, nameprep) - - - -class DeprecationTests(unittest.TestCase): - """ - Deprecations in L{twisted.words.protocols.jabber.xmpp_stringprep}. - """ - def test_crippled(self): - """ - L{xmpp_stringprep.crippled} is deprecated and always returns C{False}. - """ - from twisted.words.protocols.jabber.xmpp_stringprep import crippled - warnings = self.flushWarnings( - offendingFunctions=[self.test_crippled]) - self.assertEqual(DeprecationWarning, warnings[0]['category']) - self.assertEqual( - "twisted.words.protocols.jabber.xmpp_stringprep.crippled was " - "deprecated in Twisted 13.1.0: crippled is always False", - warnings[0]['message']) - self.assertEqual(1, len(warnings)) - self.assertEqual(crippled, False) - - - -class XMPPStringPrepTests(unittest.TestCase): - """ - The nodeprep stringprep profile is similar to the resourceprep profile, - but does an extra mapping of characters (table B.2) and disallows - more characters (table C.1.1 and eight extra punctuation characters). - Due to this similarity, the resourceprep tests are more extensive, and - the nodeprep tests only address the mappings additional restrictions. - - The nameprep profile is nearly identical to the nameprep implementation in - L{encodings.idna}, but that implementation assumes the C{UseSTD4ASCIIRules} - flag to be false. This implementation assumes it to be true, and restricts - the allowed set of characters. The tests here only check for the - differences. - """ - - def testResourcePrep(self): - self.assertEqual(resourceprep.prepare(u'resource'), u'resource') - self.assertNotEquals(resourceprep.prepare(u'Resource'), u'resource') - self.assertEqual(resourceprep.prepare(u' '), u' ') - - self.assertEqual(resourceprep.prepare(u'Henry \u2163'), u'Henry IV') - self.assertEqual(resourceprep.prepare(u'foo\xad\u034f\u1806\u180b' - u'bar\u200b\u2060' - u'baz\ufe00\ufe08\ufe0f\ufeff'), - u'foobarbaz') - self.assertEqual(resourceprep.prepare(u'\u00a0'), u' ') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u1680') - self.assertEqual(resourceprep.prepare(u'\u2000'), u' ') - self.assertEqual(resourceprep.prepare(u'\u200b'), u'') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0010\u007f') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0085') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u180e') - self.assertEqual(resourceprep.prepare(u'\ufeff'), u'') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\uf123') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000f1234') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010f234') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0008fffe') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010ffff') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\udf42') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\ufffd') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u2ff5') - self.assertEqual(resourceprep.prepare(u'\u0341'), u'\u0301') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u200e') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u202a') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0001') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0042') - self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\u05bebar') - self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\ufd50bar') - #self.assertEqual(resourceprep.prepare(u'foo\ufb38bar'), - # u'foo\u064ebar') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u06271') - self.assertEqual(resourceprep.prepare(u'\u06271\u0628'), - u'\u06271\u0628') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0002') - - - def testNodePrep(self): - self.assertEqual(nodeprep.prepare(u'user'), u'user') - self.assertEqual(nodeprep.prepare(u'User'), u'user') - self.assertRaises(UnicodeError, nodeprep.prepare, u'us&er') - - - def test_nodeprepUnassignedInUnicode32(self): - """ - Make sure unassigned code points from Unicode 3.2 are rejected. - """ - self.assertRaises(UnicodeError, nodeprep.prepare, u'\u1d39') - - - def testNamePrep(self): - self.assertEqual(nameprep.prepare(u'example.com'), u'example.com') - self.assertEqual(nameprep.prepare(u'Example.com'), u'example.com') - self.assertRaises(UnicodeError, nameprep.prepare, u'ex@mple.com') - self.assertRaises(UnicodeError, nameprep.prepare, u'-example.com') - self.assertRaises(UnicodeError, nameprep.prepare, u'example-.com') - - self.assertEqual(nameprep.prepare(u'stra\u00dfe.example.com'), - u'strasse.example.com') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_msn.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_msn.py deleted file mode 100644 index b4367f9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_msn.py +++ /dev/null @@ -1,544 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.words.protocols.msn}. -""" - -import StringIO -from hashlib import md5 - -from twisted.internet.defer import Deferred -from twisted.protocols import loopback -from twisted.python.reflect import requireModule -from twisted.test.proto_helpers import StringTransport, StringIOWithoutClosing -from twisted.trial import unittest - -# t.w.p.msn requires an HTTP client -try: - # So try to get one - do it directly instead of catching an ImportError - # from t.w.p.msn so that other problems which cause that module to fail - # to import don't cause the tests to be skipped. - requireModule('twisted.web.client') -except ImportError: - # If there isn't one, we're going to skip all the tests. - msn = None -else: - # Otherwise importing it should work, so do it. - from twisted.words.protocols import msn - - - -def printError(f): - print f - - -class PassportTests(unittest.TestCase): - - def setUp(self): - self.result = [] - self.deferred = Deferred() - self.deferred.addCallback(lambda r: self.result.append(r)) - self.deferred.addErrback(printError) - - def test_nexus(self): - """ - When L{msn.PassportNexus} receives enough information to identify the - address of the login server, it fires the L{Deferred} passed to its - initializer with that address. - """ - protocol = msn.PassportNexus(self.deferred, 'https://foobar.com/somepage.quux') - headers = { - 'Content-Length' : '0', - 'Content-Type' : 'text/html', - 'PassportURLs' : 'DARealm=Passport.Net,DALogin=login.myserver.com/,DAReg=reg.myserver.com' - } - transport = StringTransport() - protocol.makeConnection(transport) - protocol.dataReceived('HTTP/1.0 200 OK\r\n') - for (h, v) in headers.items(): - protocol.dataReceived('%s: %s\r\n' % (h,v)) - protocol.dataReceived('\r\n') - self.assertEqual(self.result[0], "https://login.myserver.com/") - - - def _doLoginTest(self, response, headers): - protocol = msn.PassportLogin(self.deferred,'foo@foo.com','testpass','https://foo.com/', 'a') - protocol.makeConnection(StringTransport()) - protocol.dataReceived(response) - for (h,v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h,v)) - protocol.dataReceived('\r\n') - - def testPassportLoginSuccess(self): - headers = { - 'Content-Length' : '0', - 'Content-Type' : 'text/html', - 'Authentication-Info' : "Passport1.4 da-status=success,tname=MSPAuth," + - "tname=MSPProf,tname=MSPSec,from-PP='somekey'," + - "ru=http://messenger.msn.com" - } - self._doLoginTest('HTTP/1.1 200 OK\r\n', headers) - self.failUnless(self.result[0] == (msn.LOGIN_SUCCESS, 'somekey')) - - def testPassportLoginFailure(self): - headers = { - 'Content-Type' : 'text/html', - 'WWW-Authenticate' : 'Passport1.4 da-status=failed,' + - 'srealm=Passport.NET,ts=-3,prompt,cburl=http://host.com,' + - 'cbtxt=the%20error%20message' - } - self._doLoginTest('HTTP/1.1 401 Unauthorized\r\n', headers) - self.failUnless(self.result[0] == (msn.LOGIN_FAILURE, 'the error message')) - - def testPassportLoginRedirect(self): - headers = { - 'Content-Type' : 'text/html', - 'Authentication-Info' : 'Passport1.4 da-status=redir', - 'Location' : 'https://newlogin.host.com/' - } - self._doLoginTest('HTTP/1.1 302 Found\r\n', headers) - self.failUnless(self.result[0] == (msn.LOGIN_REDIRECT, 'https://newlogin.host.com/', 'a')) - - -if msn is not None: - class DummySwitchboardClient(msn.SwitchboardClient): - def userTyping(self, message): - self.state = 'TYPING' - - def gotSendRequest(self, fileName, fileSize, cookie, message): - if fileName == 'foobar.ext' and fileSize == 31337 and cookie == 1234: self.state = 'INVITATION' - - - class DummyNotificationClient(msn.NotificationClient): - def loggedIn(self, userHandle, screenName, verified): - if userHandle == 'foo@bar.com' and screenName == 'Test Screen Name' and verified: - self.state = 'LOGIN' - - def gotProfile(self, message): - self.state = 'PROFILE' - - def gotContactStatus(self, code, userHandle, screenName): - if code == msn.STATUS_AWAY and userHandle == "foo@bar.com" and screenName == "Test Screen Name": - self.state = 'INITSTATUS' - - def contactStatusChanged(self, code, userHandle, screenName): - if code == msn.STATUS_LUNCH and userHandle == "foo@bar.com" and screenName == "Test Name": - self.state = 'NEWSTATUS' - - def contactOffline(self, userHandle): - if userHandle == "foo@bar.com": self.state = 'OFFLINE' - - def statusChanged(self, code): - if code == msn.STATUS_HIDDEN: self.state = 'MYSTATUS' - - def listSynchronized(self, *args): - self.state = 'GOTLIST' - - def gotPhoneNumber(self, listVersion, userHandle, phoneType, number): - msn.NotificationClient.gotPhoneNumber(self, listVersion, userHandle, phoneType, number) - self.state = 'GOTPHONE' - - def userRemovedMe(self, userHandle, listVersion): - msn.NotificationClient.userRemovedMe(self, userHandle, listVersion) - c = self.factory.contacts.getContact(userHandle) - if not c and self.factory.contacts.version == listVersion: self.state = 'USERREMOVEDME' - - def userAddedMe(self, userHandle, screenName, listVersion): - msn.NotificationClient.userAddedMe(self, userHandle, screenName, listVersion) - c = self.factory.contacts.getContact(userHandle) - if c and (c.lists | msn.REVERSE_LIST) and (self.factory.contacts.version == listVersion) and \ - (screenName == 'Screen Name'): - self.state = 'USERADDEDME' - - def gotSwitchboardInvitation(self, sessionID, host, port, key, userHandle, screenName): - if sessionID == 1234 and \ - host == '192.168.1.1' and \ - port == 1863 and \ - key == '123.456' and \ - userHandle == 'foo@foo.com' and \ - screenName == 'Screen Name': - self.state = 'SBINVITED' - - - -class DispatchTests(unittest.TestCase): - """ - Tests for L{DispatchClient}. - """ - def _versionTest(self, serverVersionResponse): - """ - Test L{DispatchClient} version negotiation. - """ - client = msn.DispatchClient() - client.userHandle = "foo" - - transport = StringTransport() - client.makeConnection(transport) - self.assertEqual( - transport.value(), "VER 1 MSNP8 CVR0\r\n") - transport.clear() - - client.dataReceived(serverVersionResponse) - self.assertEqual( - transport.value(), - "CVR 2 0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS foo\r\n") - - - def test_version(self): - """ - L{DispatchClient.connectionMade} greets the server with a I{VER} - (version) message and then L{NotificationClient.dataReceived} - handles the server's I{VER} response by sending a I{CVR} (client - version) message. - """ - self._versionTest("VER 1 MSNP8 CVR0\r\n") - - - def test_versionWithoutCVR0(self): - """ - If the server responds to a I{VER} command without including the - I{CVR0} protocol, L{DispatchClient} behaves in the same way as if - that protocol were included. - - Starting in August 2008, CVR0 disappeared from the I{VER} response. - """ - self._versionTest("VER 1 MSNP8\r\n") - - - -class NotificationTests(unittest.TestCase): - """ testing the various events in NotificationClient """ - - def setUp(self): - self.client = DummyNotificationClient() - self.client.factory = msn.NotificationFactory() - self.client.state = 'START' - - - def tearDown(self): - self.client = None - - - def _versionTest(self, serverVersionResponse): - """ - Test L{NotificationClient} version negotiation. - """ - self.client.factory.userHandle = "foo" - - transport = StringTransport() - self.client.makeConnection(transport) - self.assertEqual( - transport.value(), "VER 1 MSNP8 CVR0\r\n") - transport.clear() - - self.client.dataReceived(serverVersionResponse) - self.assertEqual( - transport.value(), - "CVR 2 0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS foo\r\n") - - - def test_version(self): - """ - L{NotificationClient.connectionMade} greets the server with a I{VER} - (version) message and then L{NotificationClient.dataReceived} - handles the server's I{VER} response by sending a I{CVR} (client - version) message. - """ - self._versionTest("VER 1 MSNP8 CVR0\r\n") - - - def test_versionWithoutCVR0(self): - """ - If the server responds to a I{VER} command without including the - I{CVR0} protocol, L{NotificationClient} behaves in the same way as - if that protocol were included. - - Starting in August 2008, CVR0 disappeared from the I{VER} response. - """ - self._versionTest("VER 1 MSNP8\r\n") - - - def test_challenge(self): - """ - L{NotificationClient} responds to a I{CHL} message by sending a I{QRY} - back which included a hash based on the parameters of the I{CHL}. - """ - transport = StringTransport() - self.client.makeConnection(transport) - transport.clear() - - challenge = "15570131571988941333" - self.client.dataReceived('CHL 0 ' + challenge + '\r\n') - # md5 of the challenge and a magic string defined by the protocol - response = "8f2f5a91b72102cd28355e9fc9000d6e" - # Sanity check - the response is what the comment above says it is. - self.assertEqual( - response, md5(challenge + "Q1P7W2E4J9R8U3S5").hexdigest()) - self.assertEqual( - transport.value(), - # 2 is the next transaction identifier. 32 is the length of the - # response. - "QRY 2 msmsgs@msnmsgr.com 32\r\n" + response) - - - def testLogin(self): - self.client.lineReceived('USR 1 OK foo@bar.com Test%20Screen%20Name 1 0') - self.failUnless((self.client.state == 'LOGIN'), msg='Failed to detect successful login') - - - def test_loginWithoutSSLFailure(self): - """ - L{NotificationClient.loginFailure} is called if the necessary SSL APIs - are unavailable. - """ - self.patch(msn, 'ClientContextFactory', None) - success = [] - self.client.loggedIn = lambda *args: success.append(args) - failure = [] - self.client.loginFailure = failure.append - - self.client.lineReceived('USR 6 TWN S opaque-string-goes-here') - self.assertEqual(success, []) - self.assertEqual( - failure, - ["Exception while authenticating: " - "Connecting to the Passport server requires SSL, but SSL is " - "unavailable."]) - - - def testProfile(self): - m = 'MSG Hotmail Hotmail 353\r\nMIME-Version: 1.0\r\nContent-Type: text/x-msmsgsprofile; charset=UTF-8\r\n' - m += 'LoginTime: 1016941010\r\nEmailEnabled: 1\r\nMemberIdHigh: 40000\r\nMemberIdLow: -600000000\r\nlang_preference: 1033\r\n' - m += 'preferredEmail: foo@bar.com\r\ncountry: AU\r\nPostalCode: 90210\r\nGender: M\r\nKid: 0\r\nAge:\r\nsid: 400\r\n' - m += 'kv: 2\r\nMSPAuth: 2CACCBCCADMoV8ORoz64BVwmjtksIg!kmR!Rj5tBBqEaW9hc4YnPHSOQ$$\r\n\r\n' - map(self.client.lineReceived, m.split('\r\n')[:-1]) - self.failUnless((self.client.state == 'PROFILE'), msg='Failed to detect initial profile') - - def testStatus(self): - t = [('ILN 1 AWY foo@bar.com Test%20Screen%20Name 0', 'INITSTATUS', 'Failed to detect initial status report'), - ('NLN LUN foo@bar.com Test%20Name 0', 'NEWSTATUS', 'Failed to detect contact status change'), - ('FLN foo@bar.com', 'OFFLINE', 'Failed to detect contact signing off'), - ('CHG 1 HDN 0', 'MYSTATUS', 'Failed to detect my status changing')] - for i in t: - self.client.lineReceived(i[0]) - self.failUnless((self.client.state == i[1]), msg=i[2]) - - def testListSync(self): - # currently this test does not take into account the fact - # that BPRs sent as part of the SYN reply may not be interpreted - # as such if they are for the last LST -- maybe I should - # factor this in later. - self.client.makeConnection(StringTransport()) - msn.NotificationClient.loggedIn(self.client, 'foo@foo.com', 'foobar', 1) - lines = [ - "SYN %s 100 1 1" % self.client.currentID, - "GTC A", - "BLP AL", - "LSG 0 Other%20Contacts 0", - "LST userHandle@email.com Some%20Name 11 0" - ] - map(self.client.lineReceived, lines) - contacts = self.client.factory.contacts - contact = contacts.getContact('userHandle@email.com') - self.failUnless(contacts.version == 100, "Invalid contact list version") - self.failUnless(contact.screenName == 'Some Name', "Invalid screen-name for user") - self.failUnless(contacts.groups == {0 : 'Other Contacts'}, "Did not get proper group list") - self.failUnless(contact.groups == [0] and contact.lists == 11, "Invalid contact list/group info") - self.failUnless(self.client.state == 'GOTLIST', "Failed to call list sync handler") - - def testAsyncPhoneChange(self): - c = msn.MSNContact(userHandle='userHandle@email.com') - self.client.factory.contacts = msn.MSNContactList() - self.client.factory.contacts.addContact(c) - self.client.makeConnection(StringTransport()) - self.client.lineReceived("BPR 101 userHandle@email.com PHH 123%20456") - c = self.client.factory.contacts.getContact('userHandle@email.com') - self.failUnless(self.client.state == 'GOTPHONE', "Did not fire phone change callback") - self.failUnless(c.homePhone == '123 456', "Did not update the contact's phone number") - self.failUnless(self.client.factory.contacts.version == 101, "Did not update list version") - - def testLateBPR(self): - """ - This test makes sure that if a BPR response that was meant - to be part of a SYN response (but came after the last LST) - is received, the correct contact is updated and all is well - """ - self.client.makeConnection(StringTransport()) - msn.NotificationClient.loggedIn(self.client, 'foo@foo.com', 'foo', 1) - lines = [ - "SYN %s 100 1 1" % self.client.currentID, - "GTC A", - "BLP AL", - "LSG 0 Other%20Contacts 0", - "LST userHandle@email.com Some%20Name 11 0", - "BPR PHH 123%20456" - ] - map(self.client.lineReceived, lines) - contact = self.client.factory.contacts.getContact('userHandle@email.com') - self.failUnless(contact.homePhone == '123 456', "Did not update contact's phone number") - - def testUserRemovedMe(self): - self.client.factory.contacts = msn.MSNContactList() - contact = msn.MSNContact(userHandle='foo@foo.com') - contact.addToList(msn.REVERSE_LIST) - self.client.factory.contacts.addContact(contact) - self.client.lineReceived("REM 0 RL 100 foo@foo.com") - self.failUnless(self.client.state == 'USERREMOVEDME', "Failed to remove user from reverse list") - - def testUserAddedMe(self): - self.client.factory.contacts = msn.MSNContactList() - self.client.lineReceived("ADD 0 RL 100 foo@foo.com Screen%20Name") - self.failUnless(self.client.state == 'USERADDEDME', "Failed to add user to reverse lise") - - def testAsyncSwitchboardInvitation(self): - self.client.lineReceived("RNG 1234 192.168.1.1:1863 CKI 123.456 foo@foo.com Screen%20Name") - self.failUnless(self.client.state == "SBINVITED") - - def testCommandFailed(self): - """ - Ensures that error responses from the server fires an errback with - MSNCommandFailed. - """ - id, d = self.client._createIDMapping() - self.client.lineReceived("201 %s" % id) - d = self.assertFailure(d, msn.MSNCommandFailed) - def assertErrorCode(exception): - self.assertEqual(201, exception.errorCode) - return d.addCallback(assertErrorCode) - - -class MessageHandlingTests(unittest.TestCase): - """ testing various message handling methods from SwichboardClient """ - - def setUp(self): - self.client = DummySwitchboardClient() - self.client.state = 'START' - - def tearDown(self): - self.client = None - - def testClientCapabilitiesCheck(self): - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-clientcaps') - self.assertEqual(self.client.checkMessage(m), 0, 'Failed to detect client capability message') - - def testTypingCheck(self): - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgscontrol') - m.setHeader('TypingUser', 'foo@bar') - self.client.checkMessage(m) - self.failUnless((self.client.state == 'TYPING'), msg='Failed to detect typing notification') - - def testFileInvitation(self, lazyClient=False): - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Application-Name: File Transfer\r\n' - if not lazyClient: - m.message += 'Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n' - m.message += 'Invitation-Command: Invite\r\n' - m.message += 'Invitation-Cookie: 1234\r\n' - m.message += 'Application-File: foobar.ext\r\n' - m.message += 'Application-FileSize: 31337\r\n\r\n' - self.client.checkMessage(m) - self.failUnless((self.client.state == 'INVITATION'), msg='Failed to detect file transfer invitation') - - def testFileInvitationMissingGUID(self): - return self.testFileInvitation(True) - - def testFileResponse(self): - d = Deferred() - d.addCallback(self.fileResponse) - self.client.cookies['iCookies'][1234] = (d, None) - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: ACCEPT\r\n' - m.message += 'Invitation-Cookie: 1234\r\n\r\n' - self.client.checkMessage(m) - self.failUnless((self.client.state == 'RESPONSE'), msg='Failed to detect file transfer response') - - def testFileInfo(self): - d = Deferred() - d.addCallback(self.fileInfo) - self.client.cookies['external'][1234] = (d, None) - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: ACCEPT\r\n' - m.message += 'Invitation-Cookie: 1234\r\n' - m.message += 'IP-Address: 192.168.0.1\r\n' - m.message += 'Port: 6891\r\n' - m.message += 'AuthCookie: 4321\r\n\r\n' - self.client.checkMessage(m) - self.failUnless((self.client.state == 'INFO'), msg='Failed to detect file transfer info') - - def fileResponse(self, (accept, cookie, info)): - if accept and cookie == 1234: self.client.state = 'RESPONSE' - - def fileInfo(self, (accept, ip, port, aCookie, info)): - if accept and ip == '192.168.0.1' and port == 6891 and aCookie == 4321: self.client.state = 'INFO' - - -class FileTransferTests(unittest.TestCase): - """ - test FileSend against FileReceive - """ - - def setUp(self): - self.input = 'a' * 7000 - self.output = StringIOWithoutClosing() - - - def tearDown(self): - self.input = None - self.output = None - - - def test_fileTransfer(self): - """ - Test L{FileSend} against L{FileReceive} using a loopback transport. - """ - auth = 1234 - sender = msn.FileSend(StringIO.StringIO(self.input)) - sender.auth = auth - sender.fileSize = 7000 - client = msn.FileReceive(auth, "foo@bar.com", self.output) - client.fileSize = 7000 - def check(ignored): - self.assertTrue( - client.completed and sender.completed, - msg="send failed to complete") - self.assertEqual( - self.input, self.output.getvalue(), - msg="saved file does not match original") - d = loopback.loopbackAsync(sender, client) - d.addCallback(check) - return d - - - -class DeprecationTests(unittest.TestCase): - """ - Test deprecation of L{twisted.words.protocols.msn} - """ - - def test_deprecation(self): - """ - Accessing L{twisted.words.protocols.msn} emits a deprecation warning - """ - requireModule('twisted.words.protocols').msn - warningsShown = self.flushWarnings([self.test_deprecation]) - self.assertEqual(len(warningsShown), 1) - self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEqual( - warningsShown[0]['message'], - 'twisted.words.protocols.msn was deprecated in Twisted 15.1.0: ' + - 'MSN has shutdown.') - - - -if msn is None: - for testClass in [DispatchTests, PassportTests, NotificationTests, - MessageHandlingTests, FileTransferTests, - DeprecationTests]: - testClass.skip = ( - "MSN requires an HTTP client but none is available, " - "skipping tests.") diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_oscar.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_oscar.py deleted file mode 100644 index f807ce5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_oscar.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.oscar}. -""" - -from twisted.trial.unittest import TestCase - -from twisted.words.protocols.oscar import encryptPasswordMD5 - - -class PasswordTests(TestCase): - """ - Tests for L{encryptPasswordMD5}. - """ - def test_encryptPasswordMD5(self): - """ - L{encryptPasswordMD5} hashes the given password and key and returns a - string suitable to use to authenticate against an OSCAR server. - """ - self.assertEqual( - encryptPasswordMD5('foo', 'bar').encode('hex'), - 'd73475c370a7b18c6c20386bcf1339f2') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_service.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_service.py deleted file mode 100644 index 5ab6b67..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_service.py +++ /dev/null @@ -1,838 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.service}. -""" - -import time - -from twisted.trial import unittest -from twisted.test import proto_helpers - -from twisted.cred import portal, credentials, checkers -from twisted.words import ewords, service -from twisted.words.protocols import irc -from twisted.spread import pb -from twisted.internet.defer import Deferred, DeferredList, maybeDeferred, succeed -from twisted.internet import address, defer, reactor - -class RealmTests(unittest.TestCase): - def _entityCreationTest(self, kind): - # Kind is "user" or "group" - realm = service.InMemoryWordsRealm("realmname") - - name = u'test' + kind.lower() - create = getattr(realm, 'create' + kind.title()) - get = getattr(realm, 'get' + kind.title()) - flag = 'create' + kind.title() + 'OnRequest' - dupExc = getattr(ewords, 'Duplicate' + kind.title()) - noSuchExc = getattr(ewords, 'NoSuch' + kind.title()) - - # Creating should succeed - p = self.successResultOf(create(name)) - self.assertEqual(name, p.name) - - # Creating the same user again should not - self.failureResultOf(create(name)).trap(dupExc) - - # Getting a non-existent user should succeed if createUserOnRequest is True - setattr(realm, flag, True) - p = self.successResultOf(get(u"new" + kind.lower())) - self.assertEqual("new" + kind.lower(), p.name) - - # Getting that user again should return the same object - newp = self.successResultOf(get(u"new" + kind.lower())) - self.assertIdentical(p, newp) - - # Getting a non-existent user should fail if createUserOnRequest is False - setattr(realm, flag, False) - self.failureResultOf(get(u"another" + kind.lower())).trap(noSuchExc) - - - def testUserCreation(self): - return self._entityCreationTest("User") - - - def testGroupCreation(self): - return self._entityCreationTest("Group") - - - def testUserRetrieval(self): - realm = service.InMemoryWordsRealm("realmname") - - # Make a user to play around with - user = self.successResultOf(realm.createUser(u"testuser")) - - # Make sure getting the user returns the same object - retrieved = self.successResultOf(realm.getUser(u"testuser")) - self.assertIdentical(user, retrieved) - - # Make sure looking up the user also returns the same object - lookedUp = self.successResultOf(realm.lookupUser(u"testuser")) - self.assertIdentical(retrieved, lookedUp) - - # Make sure looking up a user who does not exist fails - (self.failureResultOf(realm.lookupUser(u"nosuchuser")) - .trap(ewords.NoSuchUser)) - - - def testUserAddition(self): - realm = service.InMemoryWordsRealm("realmname") - - # Create and manually add a user to the realm - p = service.User("testuser") - user = self.successResultOf(realm.addUser(p)) - self.assertIdentical(p, user) - - # Make sure getting that user returns the same object - retrieved = self.successResultOf(realm.getUser(u"testuser")) - self.assertIdentical(user, retrieved) - - # Make sure looking up that user returns the same object - lookedUp = self.successResultOf(realm.lookupUser(u"testuser")) - self.assertIdentical(retrieved, lookedUp) - - - def testGroupRetrieval(self): - realm = service.InMemoryWordsRealm("realmname") - - group = self.successResultOf(realm.createGroup(u"testgroup")) - - retrieved = self.successResultOf(realm.getGroup(u"testgroup")) - - self.assertIdentical(group, retrieved) - - (self.failureResultOf(realm.getGroup(u"nosuchgroup")) - .trap(ewords.NoSuchGroup)) - - - def testGroupAddition(self): - realm = service.InMemoryWordsRealm("realmname") - - p = service.Group("testgroup") - self.successResultOf(realm.addGroup(p)) - group = self.successResultOf(realm.getGroup(u"testGroup")) - self.assertIdentical(p, group) - - - def testGroupUsernameCollision(self): - """ - Try creating a group with the same name as an existing user and - assert that it succeeds, since users and groups should not be in the - same namespace and collisions should be impossible. - """ - realm = service.InMemoryWordsRealm("realmname") - - self.successResultOf(realm.createUser(u"test")) - self.successResultOf(realm.createGroup(u"test")) - - - def testEnumeration(self): - realm = service.InMemoryWordsRealm("realmname") - self.successResultOf(realm.createGroup(u"groupone")) - - self.successResultOf(realm.createGroup(u"grouptwo")) - - groups = self.successResultOf(realm.itergroups()) - - n = [g.name for g in groups] - n.sort() - self.assertEqual(n, ["groupone", "grouptwo"]) - - -class TestGroup(object): - def __init__(self, name, size, topic): - self.name = name - self.size = lambda: size - self.meta = {'topic': topic} - - -class TestUser(object): - def __init__(self, name, groups, signOn, lastMessage): - self.name = name - self.itergroups = lambda: iter([TestGroup(g, 3, 'Hello') for g in groups]) - self.signOn = signOn - self.lastMessage = lastMessage - - -class TestPortal(object): - def __init__(self): - self.logins = [] - - - def login(self, credentials, mind, *interfaces): - d = Deferred() - self.logins.append((credentials, mind, interfaces, d)) - return d - - -class TestCaseUserAgg(object): - def __init__(self, user, realm, factory, address=address.IPv4Address('TCP', '127.0.0.1', 54321)): - self.user = user - self.transport = proto_helpers.StringTransportWithDisconnection() - self.protocol = factory.buildProtocol(address) - self.transport.protocol = self.protocol - self.user.mind = self.protocol - self.protocol.makeConnection(self.transport) - - - def write(self, stuff): - if isinstance(stuff, unicode): - stuff = stuff.encode('utf-8') - self.protocol.dataReceived(stuff) - - -class IRCProtocolTests(unittest.TestCase): - STATIC_USERS = [ - u'useruser', u'otheruser', u'someguy', u'firstuser', u'username', - u'userone', u'usertwo', u'userthree', u'someuser'] - - - def setUp(self): - self.realm = service.InMemoryWordsRealm("realmname") - self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.portal = portal.Portal(self.realm, [self.checker]) - self.factory = service.IRCFactory(self.realm, self.portal) - - c = [] - for nick in self.STATIC_USERS: - c.append(self.realm.createUser(nick)) - self.checker.addUser(nick.encode('ascii'), nick + "_password") - return DeferredList(c) - - - def _assertGreeting(self, user): - """ - The user has been greeted with the four messages that are (usually) - considered to start an IRC session. - - Asserts that the required responses were received. - """ - # Make sure we get 1-4 at least - response = self._response(user) - expected = [irc.RPL_WELCOME, irc.RPL_YOURHOST, irc.RPL_CREATED, - irc.RPL_MYINFO] - for (prefix, command, args) in response: - if command in expected: - expected.remove(command) - self.failIf(expected, "Missing responses for %r" % (expected,)) - - - def _login(self, user, nick, password=None): - if password is None: - password = nick + "_password" - user.write('PASS %s\r\n' % (password,)) - user.write('NICK %s extrainfo\r\n' % (nick,)) - - - def _loggedInUser(self, name): - user = self.successResultOf(self.realm.lookupUser(name)) - agg = TestCaseUserAgg(user, self.realm, self.factory) - self._login(agg, name) - return agg - - - def _response(self, user, messageType=None): - """ - Extracts the user's response, and returns a list of parsed lines. - If messageType is defined, only messages of that type will be returned. - """ - response = user.transport.value().splitlines() - user.transport.clear() - result = [] - for message in map(irc.parsemsg, response): - if messageType is None or message[1] == messageType: - result.append(message) - return result - - - def testPASSLogin(self): - user = self._loggedInUser(u'firstuser') - self._assertGreeting(user) - - - def test_nickServLogin(self): - """ - Sending NICK without PASS will prompt the user for their password. - When the user sends their password to NickServ, it will respond with a - Greeting. - """ - firstuser = self.successResultOf(self.realm.lookupUser(u'firstuser')) - - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - user.write('NICK firstuser extrainfo\r\n') - response = self._response(user, 'PRIVMSG') - self.assertEqual(len(response), 1) - self.assertEqual(response[0][0], service.NICKSERV) - self.assertEqual(response[0][1], 'PRIVMSG') - self.assertEqual(response[0][2], ['firstuser', 'Password?']) - user.transport.clear() - - user.write('PRIVMSG nickserv firstuser_password\r\n') - self._assertGreeting(user) - - - def testFailedLogin(self): - firstuser = self.successResultOf(self.realm.lookupUser(u'firstuser')) - - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - self._login(user, "firstuser", "wrongpass") - response = self._response(user, "PRIVMSG") - self.assertEqual(len(response), 1) - self.assertEqual(response[0][2], ['firstuser', 'Login failed. Goodbye.']) - - - def testLogout(self): - logout = [] - firstuser = self.successResultOf(self.realm.lookupUser(u'firstuser')) - - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - self._login(user, "firstuser") - user.protocol.logout = lambda: logout.append(True) - user.write('QUIT\r\n') - self.assertEqual(logout, [True]) - - - def testJoin(self): - firstuser = self.successResultOf(self.realm.lookupUser(u'firstuser')) - - somechannel = self.successResultOf( - self.realm.createGroup(u"somechannel")) - - somechannel.meta['topic'] = 'some random topic' - - # Bring in one user, make sure he gets into the channel sanely - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - self._login(user, "firstuser") - user.transport.clear() - user.write('JOIN #somechannel\r\n') - - response = self._response(user) - self.assertEqual(len(response), 5) - - # Join message - self.assertEqual(response[0][0], 'firstuser!firstuser@realmname') - self.assertEqual(response[0][1], 'JOIN') - self.assertEqual(response[0][2], ['#somechannel']) - - # User list - self.assertEqual(response[1][1], '353') - self.assertEqual(response[2][1], '366') - - # Topic (or lack thereof, as the case may be) - self.assertEqual(response[3][1], '332') - self.assertEqual(response[4][1], '333') - - - # Hook up another client! It is a CHAT SYSTEM!!!!!!! - other = self._loggedInUser(u'otheruser') - - other.transport.clear() - user.transport.clear() - other.write('JOIN #somechannel\r\n') - - # At this point, both users should be in the channel - response = self._response(other) - - event = self._response(user) - self.assertEqual(len(event), 1) - self.assertEqual(event[0][0], 'otheruser!otheruser@realmname') - self.assertEqual(event[0][1], 'JOIN') - self.assertEqual(event[0][2], ['#somechannel']) - - self.assertEqual(response[1][0], 'realmname') - self.assertEqual(response[1][1], '353') - self.assertIn(response[1][2], [ - ['otheruser', '=', '#somechannel', 'firstuser otheruser'], - ['otheruser', '=', '#somechannel', 'otheruser firstuser'], - ]) - - - def test_joinTopicless(self): - """ - When a user joins a group without a topic, no topic information is - sent to that user. - """ - firstuser = self.successResultOf(self.realm.lookupUser(u'firstuser')) - - self.successResultOf(self.realm.createGroup(u"somechannel")) - - # Bring in one user, make sure he gets into the channel sanely - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - self._login(user, "firstuser") - user.transport.clear() - user.write('JOIN #somechannel\r\n') - - response = self._response(user) - responseCodes = [r[1] for r in response] - self.assertNotIn('332', responseCodes) - self.assertNotIn('333', responseCodes) - - - def testLeave(self): - user = self._loggedInUser(u'useruser') - - self.successResultOf(self.realm.createGroup(u"somechannel")) - - user.write('JOIN #somechannel\r\n') - user.transport.clear() - - other = self._loggedInUser(u'otheruser') - - other.write('JOIN #somechannel\r\n') - - user.transport.clear() - other.transport.clear() - - user.write('PART #somechannel\r\n') - - response = self._response(user) - event = self._response(other) - - self.assertEqual(len(response), 1) - self.assertEqual(response[0][0], 'useruser!useruser@realmname') - self.assertEqual(response[0][1], 'PART') - self.assertEqual(response[0][2], ['#somechannel', 'leaving']) - self.assertEqual(response, event) - - # Now again, with a part message - user.write('JOIN #somechannel\r\n') - - user.transport.clear() - other.transport.clear() - - user.write('PART #somechannel :goodbye stupidheads\r\n') - - response = self._response(user) - event = self._response(other) - - self.assertEqual(len(response), 1) - self.assertEqual(response[0][0], 'useruser!useruser@realmname') - self.assertEqual(response[0][1], 'PART') - self.assertEqual(response[0][2], ['#somechannel', 'goodbye stupidheads']) - self.assertEqual(response, event) - - - def testGetTopic(self): - user = self._loggedInUser(u'useruser') - - group = service.Group("somechannel") - group.meta["topic"] = "This is a test topic." - group.meta["topic_author"] = "some_fellow" - group.meta["topic_date"] = 77777777 - - self.successResultOf(self.realm.addGroup(group)) - - user.transport.clear() - user.write("JOIN #somechannel\r\n") - - response = self._response(user) - - self.assertEqual(response[3][0], 'realmname') - self.assertEqual(response[3][1], '332') - - # XXX Sigh. irc.parsemsg() is not as correct as one might hope. - self.assertEqual(response[3][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEqual(response[4][1], '333') - self.assertEqual(response[4][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) - - user.transport.clear() - - user.write('TOPIC #somechannel\r\n') - - response = self._response(user) - - self.assertEqual(response[0][1], '332') - self.assertEqual(response[0][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEqual(response[1][1], '333') - self.assertEqual(response[1][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) - - - def testSetTopic(self): - user = self._loggedInUser(u'useruser') - - somechannel = self.successResultOf( - self.realm.createGroup(u"somechannel")) - - user.write("JOIN #somechannel\r\n") - - other = self._loggedInUser(u'otheruser') - - other.write("JOIN #somechannel\r\n") - - user.transport.clear() - other.transport.clear() - - other.write('TOPIC #somechannel :This is the new topic.\r\n') - - response = self._response(other) - event = self._response(user) - - self.assertEqual(response, event) - - self.assertEqual(response[0][0], 'otheruser!otheruser@realmname') - self.assertEqual(response[0][1], 'TOPIC') - self.assertEqual(response[0][2], ['#somechannel', 'This is the new topic.']) - - other.transport.clear() - - somechannel.meta['topic_date'] = 12345 - other.write('TOPIC #somechannel\r\n') - - response = self._response(other) - self.assertEqual(response[0][1], '332') - self.assertEqual(response[0][2], ['otheruser', '#somechannel', 'This is the new topic.']) - self.assertEqual(response[1][1], '333') - self.assertEqual(response[1][2], ['otheruser', '#somechannel', 'otheruser', '12345']) - - other.transport.clear() - other.write('TOPIC #asdlkjasd\r\n') - - response = self._response(other) - self.assertEqual(response[0][1], '403') - - - def testGroupMessage(self): - user = self._loggedInUser(u'useruser') - - self.successResultOf(self.realm.createGroup(u"somechannel")) - - user.write("JOIN #somechannel\r\n") - - other = self._loggedInUser(u'otheruser') - - other.write("JOIN #somechannel\r\n") - - user.transport.clear() - other.transport.clear() - - user.write('PRIVMSG #somechannel :Hello, world.\r\n') - - response = self._response(user) - event = self._response(other) - - self.failIf(response) - self.assertEqual(len(event), 1) - self.assertEqual(event[0][0], 'useruser!useruser@realmname') - self.assertEqual(event[0][1], 'PRIVMSG', -1) - self.assertEqual(event[0][2], ['#somechannel', 'Hello, world.']) - - - def testPrivateMessage(self): - user = self._loggedInUser(u'useruser') - - other = self._loggedInUser(u'otheruser') - - user.transport.clear() - other.transport.clear() - - user.write('PRIVMSG otheruser :Hello, monkey.\r\n') - - response = self._response(user) - event = self._response(other) - - self.failIf(response) - self.assertEqual(len(event), 1) - self.assertEqual(event[0][0], 'useruser!useruser@realmname') - self.assertEqual(event[0][1], 'PRIVMSG') - self.assertEqual(event[0][2], ['otheruser', 'Hello, monkey.']) - - user.write('PRIVMSG nousernamedthis :Hello, monkey.\r\n') - - response = self._response(user) - - self.assertEqual(len(response), 1) - self.assertEqual(response[0][0], 'realmname') - self.assertEqual(response[0][1], '401') - self.assertEqual(response[0][2], ['useruser', 'nousernamedthis', 'No such nick/channel.']) - - - def testOper(self): - user = self._loggedInUser(u'useruser') - - user.transport.clear() - user.write('OPER user pass\r\n') - response = self._response(user) - - self.assertEqual(len(response), 1) - self.assertEqual(response[0][1], '491') - - - def testGetUserMode(self): - user = self._loggedInUser(u'useruser') - - user.transport.clear() - user.write('MODE useruser\r\n') - - response = self._response(user) - self.assertEqual(len(response), 1) - self.assertEqual(response[0][0], 'realmname') - self.assertEqual(response[0][1], '221') - self.assertEqual(response[0][2], ['useruser', '+']) - - - def testSetUserMode(self): - user = self._loggedInUser(u'useruser') - - user.transport.clear() - user.write('MODE useruser +abcd\r\n') - - response = self._response(user) - self.assertEqual(len(response), 1) - self.assertEqual(response[0][1], '472') - - - def testGetGroupMode(self): - user = self._loggedInUser(u'useruser') - - self.successResultOf(self.realm.createGroup(u"somechannel")) - - user.write('JOIN #somechannel\r\n') - - user.transport.clear() - user.write('MODE #somechannel\r\n') - - response = self._response(user) - self.assertEqual(len(response), 1) - self.assertEqual(response[0][1], '324') - - - def testSetGroupMode(self): - user = self._loggedInUser(u'useruser') - - self.successResultOf(self.realm.createGroup(u"groupname")) - - user.write('JOIN #groupname\r\n') - - user.transport.clear() - user.write('MODE #groupname +abcd\r\n') - - response = self._response(user) - self.assertEqual(len(response), 1) - self.assertEqual(response[0][1], '472') - - - def testWho(self): - group = service.Group('groupname') - self.successResultOf(self.realm.addGroup(group)) - - users = [] - for nick in u'userone', u'usertwo', u'userthree': - u = self._loggedInUser(nick) - users.append(u) - users[-1].write('JOIN #groupname\r\n') - for user in users: - user.transport.clear() - - users[0].write('WHO #groupname\r\n') - - r = self._response(users[0]) - self.failIf(self._response(users[1])) - self.failIf(self._response(users[2])) - - wantusers = ['userone', 'usertwo', 'userthree'] - for (prefix, code, stuff) in r[:-1]: - self.assertEqual(prefix, 'realmname') - self.assertEqual(code, '352') - - (myname, group, theirname, theirhost, theirserver, theirnick, flag, extra) = stuff - self.assertEqual(myname, 'userone') - self.assertEqual(group, '#groupname') - self.failUnless(theirname in wantusers) - self.assertEqual(theirhost, 'realmname') - self.assertEqual(theirserver, 'realmname') - wantusers.remove(theirnick) - self.assertEqual(flag, 'H') - self.assertEqual(extra, '0 ' + theirnick) - self.failIf(wantusers) - - prefix, code, stuff = r[-1] - self.assertEqual(prefix, 'realmname') - self.assertEqual(code, '315') - myname, channel, extra = stuff - self.assertEqual(myname, 'userone') - self.assertEqual(channel, '#groupname') - self.assertEqual(extra, 'End of /WHO list.') - - - def testList(self): - user = self._loggedInUser(u"someuser") - user.transport.clear() - - somegroup = self.successResultOf(self.realm.createGroup(u"somegroup")) - somegroup.size = lambda: succeed(17) - somegroup.meta['topic'] = 'this is the topic woo' - - # Test one group - user.write('LIST #somegroup\r\n') - - r = self._response(user) - self.assertEqual(len(r), 2) - resp, end = r - - self.assertEqual(resp[0], 'realmname') - self.assertEqual(resp[1], '322') - self.assertEqual(resp[2][0], 'someuser') - self.assertEqual(resp[2][1], 'somegroup') - self.assertEqual(resp[2][2], '17') - self.assertEqual(resp[2][3], 'this is the topic woo') - - self.assertEqual(end[0], 'realmname') - self.assertEqual(end[1], '323') - self.assertEqual(end[2][0], 'someuser') - self.assertEqual(end[2][1], 'End of /LIST') - - user.transport.clear() - # Test all groups - - user.write('LIST\r\n') - r = self._response(user) - self.assertEqual(len(r), 2) - - fg1, end = r - - self.assertEqual(fg1[1], '322') - self.assertEqual(fg1[2][1], 'somegroup') - self.assertEqual(fg1[2][2], '17') - self.assertEqual(fg1[2][3], 'this is the topic woo') - - self.assertEqual(end[1], '323') - - - def testWhois(self): - user = self._loggedInUser(u'someguy') - - otherguy = service.User("otherguy") - otherguy.itergroups = lambda: iter([ - service.Group('groupA'), - service.Group('groupB')]) - otherguy.signOn = 10 - otherguy.lastMessage = time.time() - 15 - - self.successResultOf(self.realm.addUser(otherguy)) - - user.transport.clear() - user.write('WHOIS otherguy\r\n') - r = self._response(user) - - self.assertEqual(len(r), 5) - wuser, wserver, idle, channels, end = r - - self.assertEqual(wuser[0], 'realmname') - self.assertEqual(wuser[1], '311') - self.assertEqual(wuser[2][0], 'someguy') - self.assertEqual(wuser[2][1], 'otherguy') - self.assertEqual(wuser[2][2], 'otherguy') - self.assertEqual(wuser[2][3], 'realmname') - self.assertEqual(wuser[2][4], '*') - self.assertEqual(wuser[2][5], 'otherguy') - - self.assertEqual(wserver[0], 'realmname') - self.assertEqual(wserver[1], '312') - self.assertEqual(wserver[2][0], 'someguy') - self.assertEqual(wserver[2][1], 'otherguy') - self.assertEqual(wserver[2][2], 'realmname') - self.assertEqual(wserver[2][3], 'Hi mom!') - - self.assertEqual(idle[0], 'realmname') - self.assertEqual(idle[1], '317') - self.assertEqual(idle[2][0], 'someguy') - self.assertEqual(idle[2][1], 'otherguy') - self.assertEqual(idle[2][2], '15') - self.assertEqual(idle[2][3], '10') - self.assertEqual(idle[2][4], "seconds idle, signon time") - - self.assertEqual(channels[0], 'realmname') - self.assertEqual(channels[1], '319') - self.assertEqual(channels[2][0], 'someguy') - self.assertEqual(channels[2][1], 'otherguy') - self.assertEqual(channels[2][2], '#groupA #groupB') - - self.assertEqual(end[0], 'realmname') - self.assertEqual(end[1], '318') - self.assertEqual(end[2][0], 'someguy') - self.assertEqual(end[2][1], 'otherguy') - self.assertEqual(end[2][2], 'End of WHOIS list.') - - -class TestMind(service.PBMind): - def __init__(self, *a, **kw): - self.joins = [] - self.parts = [] - self.messages = [] - self.meta = [] - - def remote_userJoined(self, user, group): - self.joins.append((user, group)) - - - def remote_userLeft(self, user, group, reason): - self.parts.append((user, group, reason)) - - - def remote_receive(self, sender, recipient, message): - self.messages.append((sender, recipient, message)) - - - def remote_groupMetaUpdate(self, group, meta): - self.meta.append((group, meta)) -pb.setUnjellyableForClass(TestMind, service.PBMindReference) - - -class PBProtocolTests(unittest.TestCase): - def setUp(self): - self.realm = service.InMemoryWordsRealm("realmname") - self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.portal = portal.Portal( - self.realm, [self.checker]) - self.serverFactory = pb.PBServerFactory(self.portal) - self.serverFactory.protocol = self._protocolFactory - self.serverFactory.unsafeTracebacks = True - self.clientFactory = pb.PBClientFactory() - self.clientFactory.unsafeTracebacks = True - self.serverPort = reactor.listenTCP(0, self.serverFactory) - self.clientConn = reactor.connectTCP( - '127.0.0.1', - self.serverPort.getHost().port, - self.clientFactory) - - - def _protocolFactory(self, *args, **kw): - self._serverProtocol = pb.Broker(0) - return self._serverProtocol - - - def tearDown(self): - d3 = Deferred() - self._serverProtocol.notifyOnDisconnect(lambda: d3.callback(None)) - return DeferredList([ - maybeDeferred(self.serverPort.stopListening), - maybeDeferred(self.clientConn.disconnect), d3]) - - - def _loggedInAvatar(self, name, password, mind): - creds = credentials.UsernamePassword(name, password) - self.checker.addUser(name.encode('ascii'), password) - d = self.realm.createUser(name) - d.addCallback(lambda ign: self.clientFactory.login(creds, mind)) - return d - - - @defer.inlineCallbacks - def testGroups(self): - mindone = TestMind() - one = yield self._loggedInAvatar(u"one", "p1", mindone) - - mindtwo = TestMind() - two = yield self._loggedInAvatar(u"two", "p2", mindtwo) - - yield self.realm.createGroup(u"foobar") - - groupone = yield one.join(u"foobar") - - yield two.join(u"foobar") - - yield groupone.send({"text": "hello, monkeys"}) - - yield groupone.leave() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_tap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_tap.py deleted file mode 100644 index e844aa7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_tap.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.cred import credentials, error -from twisted.words import tap -from twisted.trial import unittest - - - -class WordsTapTests(unittest.TestCase): - """ - Ensures that the twisted.words.tap API works. - """ - - PASSWD_TEXT = "admin:admin\njoe:foo\n" - admin = credentials.UsernamePassword('admin', 'admin') - joeWrong = credentials.UsernamePassword('joe', 'bar') - - - def setUp(self): - """ - Create a file with two users. - """ - self.filename = self.mktemp() - self.file = open(self.filename, 'w') - self.file.write(self.PASSWD_TEXT) - self.file.flush() - - - def tearDown(self): - """ - Close the dummy user database. - """ - self.file.close() - - - def test_hostname(self): - """ - Tests that the --hostname parameter gets passed to Options. - """ - opt = tap.Options() - opt.parseOptions(['--hostname', 'myhost']) - self.assertEqual(opt['hostname'], 'myhost') - - - def test_passwd(self): - """ - Tests the --passwd command for backwards-compatibility. - """ - opt = tap.Options() - opt.parseOptions(['--passwd', self.file.name]) - self._loginTest(opt) - - - def test_auth(self): - """ - Tests that the --auth command generates a checker. - """ - opt = tap.Options() - opt.parseOptions(['--auth', 'file:'+self.file.name]) - self._loginTest(opt) - - - def _loginTest(self, opt): - """ - This method executes both positive and negative authentication - tests against whatever credentials checker has been stored in - the Options class. - - @param opt: An instance of L{tap.Options}. - """ - self.assertEqual(len(opt['credCheckers']), 1) - checker = opt['credCheckers'][0] - self.assertFailure(checker.requestAvatarId(self.joeWrong), - error.UnauthorizedLogin) - def _gotAvatar(username): - self.assertEqual(username, self.admin.username) - return checker.requestAvatarId(self.admin).addCallback(_gotAvatar) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xishutil.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xishutil.py deleted file mode 100644 index 0691e80..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xishutil.py +++ /dev/null @@ -1,345 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.words.xish.utility -""" - -from twisted.trial import unittest - -from twisted.python.util import OrderedDict -from twisted.words.xish import utility -from twisted.words.xish.domish import Element -from twisted.words.xish.utility import EventDispatcher - -class CallbackTracker: - """ - Test helper for tracking callbacks. - - Increases a counter on each call to L{call} and stores the object - passed in the call. - """ - - def __init__(self): - self.called = 0 - self.obj = None - - - def call(self, obj): - self.called = self.called + 1 - self.obj = obj - - - -class OrderedCallbackTracker: - """ - Test helper for tracking callbacks and their order. - """ - - def __init__(self): - self.callList = [] - - - def call1(self, object): - self.callList.append(self.call1) - - - def call2(self, object): - self.callList.append(self.call2) - - - def call3(self, object): - self.callList.append(self.call3) - - - -class EventDispatcherTests(unittest.TestCase): - """ - Tests for L{EventDispatcher}. - """ - - def testStuff(self): - d = EventDispatcher() - cb1 = CallbackTracker() - cb2 = CallbackTracker() - cb3 = CallbackTracker() - - d.addObserver("/message/body", cb1.call) - d.addObserver("/message", cb1.call) - d.addObserver("/presence", cb2.call) - d.addObserver("//event/testevent", cb3.call) - - msg = Element(("ns", "message")) - msg.addElement("body") - - pres = Element(("ns", "presence")) - pres.addElement("presence") - - d.dispatch(msg) - self.assertEqual(cb1.called, 2) - self.assertEqual(cb1.obj, msg) - self.assertEqual(cb2.called, 0) - - d.dispatch(pres) - self.assertEqual(cb1.called, 2) - self.assertEqual(cb2.called, 1) - self.assertEqual(cb2.obj, pres) - self.assertEqual(cb3.called, 0) - - d.dispatch(d, "//event/testevent") - self.assertEqual(cb3.called, 1) - self.assertEqual(cb3.obj, d) - - d.removeObserver("/presence", cb2.call) - d.dispatch(pres) - self.assertEqual(cb2.called, 1) - - - def test_addObserverTwice(self): - """ - Test adding two observers for the same query. - - When the event is dispath both of the observers need to be called. - """ - d = EventDispatcher() - cb1 = CallbackTracker() - cb2 = CallbackTracker() - - d.addObserver("//event/testevent", cb1.call) - d.addObserver("//event/testevent", cb2.call) - d.dispatch(d, "//event/testevent") - - self.assertEqual(cb1.called, 1) - self.assertEqual(cb1.obj, d) - self.assertEqual(cb2.called, 1) - self.assertEqual(cb2.obj, d) - - - def test_addObserverInDispatch(self): - """ - Test for registration of an observer during dispatch. - """ - d = EventDispatcher() - msg = Element(("ns", "message")) - cb = CallbackTracker() - - def onMessage(_): - d.addObserver("/message", cb.call) - - d.addOnetimeObserver("/message", onMessage) - - d.dispatch(msg) - self.assertEqual(cb.called, 0) - - d.dispatch(msg) - self.assertEqual(cb.called, 1) - - d.dispatch(msg) - self.assertEqual(cb.called, 2) - - - def test_addOnetimeObserverInDispatch(self): - """ - Test for registration of a onetime observer during dispatch. - """ - d = EventDispatcher() - msg = Element(("ns", "message")) - cb = CallbackTracker() - - def onMessage(msg): - d.addOnetimeObserver("/message", cb.call) - - d.addOnetimeObserver("/message", onMessage) - - d.dispatch(msg) - self.assertEqual(cb.called, 0) - - d.dispatch(msg) - self.assertEqual(cb.called, 1) - - d.dispatch(msg) - self.assertEqual(cb.called, 1) - - - def testOnetimeDispatch(self): - d = EventDispatcher() - msg = Element(("ns", "message")) - cb = CallbackTracker() - - d.addOnetimeObserver("/message", cb.call) - d.dispatch(msg) - self.assertEqual(cb.called, 1) - d.dispatch(msg) - self.assertEqual(cb.called, 1) - - - def testDispatcherResult(self): - d = EventDispatcher() - msg = Element(("ns", "message")) - pres = Element(("ns", "presence")) - cb = CallbackTracker() - - d.addObserver("/presence", cb.call) - result = d.dispatch(msg) - self.assertEqual(False, result) - - result = d.dispatch(pres) - self.assertEqual(True, result) - - - def testOrderedXPathDispatch(self): - d = EventDispatcher() - cb = OrderedCallbackTracker() - d.addObserver("/message/body", cb.call2) - d.addObserver("/message", cb.call3, -1) - d.addObserver("/message/body", cb.call1, 1) - - msg = Element(("ns", "message")) - msg.addElement("body") - d.dispatch(msg) - self.assertEqual(cb.callList, [cb.call1, cb.call2, cb.call3], - "Calls out of order: %s" % - repr([c.__name__ for c in cb.callList])) - - - # Observers are put into CallbackLists that are then put into dictionaries - # keyed by the event trigger. Upon removal of the last observer for a - # particular event trigger, the (now empty) CallbackList and corresponding - # event trigger should be removed from those dictionaries to prevent - # slowdown and memory leakage. - - def test_cleanUpRemoveEventObserver(self): - """ - Test observer clean-up after removeObserver for named events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - - d.addObserver('//event/test', cb.call) - d.dispatch(None, '//event/test') - self.assertEqual(1, cb.called) - d.removeObserver('//event/test', cb.call) - self.assertEqual(0, len(d._eventObservers.pop(0))) - - - def test_cleanUpRemoveXPathObserver(self): - """ - Test observer clean-up after removeObserver for XPath events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - msg = Element((None, "message")) - - d.addObserver('/message', cb.call) - d.dispatch(msg) - self.assertEqual(1, cb.called) - d.removeObserver('/message', cb.call) - self.assertEqual(0, len(d._xpathObservers.pop(0))) - - - def test_cleanUpOnetimeEventObserver(self): - """ - Test observer clean-up after onetime named events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - - d.addOnetimeObserver('//event/test', cb.call) - d.dispatch(None, '//event/test') - self.assertEqual(1, cb.called) - self.assertEqual(0, len(d._eventObservers.pop(0))) - - - def test_cleanUpOnetimeXPathObserver(self): - """ - Test observer clean-up after onetime XPath events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - msg = Element((None, "message")) - - d.addOnetimeObserver('/message', cb.call) - d.dispatch(msg) - self.assertEqual(1, cb.called) - self.assertEqual(0, len(d._xpathObservers.pop(0))) - - - def test_observerRaisingException(self): - """ - Test that exceptions in observers do not bubble up to dispatch. - - The exceptions raised in observers should be logged and other - observers should be called as if nothing happened. - """ - - class OrderedCallbackList(utility.CallbackList): - def __init__(self): - self.callbacks = OrderedDict() - - class TestError(Exception): - pass - - def raiseError(_): - raise TestError() - - d = EventDispatcher() - cb = CallbackTracker() - - originalCallbackList = utility.CallbackList - - try: - utility.CallbackList = OrderedCallbackList - - d.addObserver('//event/test', raiseError) - d.addObserver('//event/test', cb.call) - try: - d.dispatch(None, '//event/test') - except TestError: - self.fail("TestError raised. Should have been logged instead.") - - self.assertEqual(1, len(self.flushLoggedErrors(TestError))) - self.assertEqual(1, cb.called) - finally: - utility.CallbackList = originalCallbackList - - - -class XmlPipeTests(unittest.TestCase): - """ - Tests for L{twisted.words.xish.utility.XmlPipe}. - """ - - def setUp(self): - self.pipe = utility.XmlPipe() - - - def test_sendFromSource(self): - """ - Send an element from the source and observe it from the sink. - """ - def cb(obj): - called.append(obj) - - called = [] - self.pipe.sink.addObserver('/test[@xmlns="testns"]', cb) - element = Element(('testns', 'test')) - self.pipe.source.send(element) - self.assertEqual([element], called) - - - def test_sendFromSink(self): - """ - Send an element from the sink and observe it from the source. - """ - def cb(obj): - called.append(obj) - - called = [] - self.pipe.source.addObserver('/test[@xmlns="testns"]', cb) - element = Element(('testns', 'test')) - self.pipe.sink.send(element) - self.assertEqual([element], called) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xmlstream.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xmlstream.py deleted file mode 100644 index 0039891..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xmlstream.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.xish.xmlstream}. -""" - -from twisted.internet import protocol -from twisted.python import failure -from twisted.trial import unittest -from twisted.words.xish import domish, utility, xmlstream - -class XmlStreamTests(unittest.TestCase): - def setUp(self): - self.connectionLostMsg = "no reason" - self.outlist = [] - self.xmlstream = xmlstream.XmlStream() - self.xmlstream.transport = self - self.xmlstream.transport.write = self.outlist.append - - - def loseConnection(self): - """ - Stub loseConnection because we are a transport. - """ - self.xmlstream.connectionLost(failure.Failure( - Exception(self.connectionLostMsg))) - - - def test_send(self): - """ - Calling L{xmlstream.XmlStream.send} results in the data being written - to the transport. - """ - self.xmlstream.connectionMade() - self.xmlstream.send("<root>") - self.assertEqual(self.outlist[0], "<root>") - - - def test_receiveRoot(self): - """ - Receiving the starttag of the root element results in stream start. - """ - streamStarted = [] - - def streamStartEvent(rootelem): - streamStarted.append(None) - - self.xmlstream.addObserver(xmlstream.STREAM_START_EVENT, - streamStartEvent) - self.xmlstream.connectionMade() - self.xmlstream.dataReceived("<root>") - self.assertEqual(1, len(streamStarted)) - - - def test_receiveBadXML(self): - """ - Receiving malformed XML results in an L{STREAM_ERROR_EVENT}. - """ - streamError = [] - streamEnd = [] - - def streamErrorEvent(reason): - streamError.append(reason) - - def streamEndEvent(_): - streamEnd.append(None) - - self.xmlstream.addObserver(xmlstream.STREAM_ERROR_EVENT, - streamErrorEvent) - self.xmlstream.addObserver(xmlstream.STREAM_END_EVENT, - streamEndEvent) - self.xmlstream.connectionMade() - - self.xmlstream.dataReceived("<root>") - self.assertEqual(0, len(streamError)) - self.assertEqual(0, len(streamEnd)) - - self.xmlstream.dataReceived("<child><unclosed></child>") - self.assertEqual(1, len(streamError)) - self.assertTrue(streamError[0].check(domish.ParserError)) - self.assertEqual(1, len(streamEnd)) - - - def test_streamEnd(self): - """ - Ending the stream fires a L{STREAM_END_EVENT}. - """ - streamEnd = [] - - def streamEndEvent(reason): - streamEnd.append(reason) - - self.xmlstream.addObserver(xmlstream.STREAM_END_EVENT, - streamEndEvent) - self.xmlstream.connectionMade() - self.loseConnection() - self.assertEqual(1, len(streamEnd)) - self.assertIsInstance(streamEnd[0], failure.Failure) - self.assertEqual(streamEnd[0].getErrorMessage(), - self.connectionLostMsg) - - - -class DummyProtocol(protocol.Protocol, utility.EventDispatcher): - """ - I am a protocol with an event dispatcher without further processing. - - This protocol is only used for testing XmlStreamFactoryMixin to make - sure the bootstrap observers are added to the protocol instance. - """ - - def __init__(self, *args, **kwargs): - self.args = args - self.kwargs = kwargs - self.observers = [] - - utility.EventDispatcher.__init__(self) - - - -class BootstrapMixinTests(unittest.TestCase): - """ - Tests for L{xmlstream.BootstrapMixin}. - - @ivar factory: Instance of the factory or mixin under test. - """ - - def setUp(self): - self.factory = xmlstream.BootstrapMixin() - - - def test_installBootstraps(self): - """ - Dispatching an event fires registered bootstrap observers. - """ - called = [] - - def cb(data): - called.append(data) - - dispatcher = DummyProtocol() - self.factory.addBootstrap('//event/myevent', cb) - self.factory.installBootstraps(dispatcher) - - dispatcher.dispatch(None, '//event/myevent') - self.assertEqual(1, len(called)) - - - def test_addAndRemoveBootstrap(self): - """ - Test addition and removal of a bootstrap event handler. - """ - - called = [] - - def cb(data): - called.append(data) - - self.factory.addBootstrap('//event/myevent', cb) - self.factory.removeBootstrap('//event/myevent', cb) - - dispatcher = DummyProtocol() - self.factory.installBootstraps(dispatcher) - - dispatcher.dispatch(None, '//event/myevent') - self.assertFalse(called) - - - -class GenericXmlStreamFactoryTestsMixin(BootstrapMixinTests): - """ - Generic tests for L{XmlStream} factories. - """ - - def setUp(self): - self.factory = xmlstream.XmlStreamFactory() - - - def test_buildProtocolInstallsBootstraps(self): - """ - The protocol factory installs bootstrap event handlers on the protocol. - """ - called = [] - - def cb(data): - called.append(data) - - self.factory.addBootstrap('//event/myevent', cb) - - xs = self.factory.buildProtocol(None) - xs.dispatch(None, '//event/myevent') - - self.assertEqual(1, len(called)) - - - def test_buildProtocolStoresFactory(self): - """ - The protocol factory is saved in the protocol. - """ - xs = self.factory.buildProtocol(None) - self.assertIdentical(self.factory, xs.factory) - - - -class XmlStreamFactoryMixinTests(GenericXmlStreamFactoryTestsMixin): - """ - Tests for L{xmlstream.XmlStreamFactoryMixin}. - """ - - def setUp(self): - self.factory = xmlstream.XmlStreamFactoryMixin(None, test=None) - self.factory.protocol = DummyProtocol - - - def test_buildProtocolFactoryArguments(self): - """ - Arguments passed to the factory are passed to protocol on - instantiation. - """ - xs = self.factory.buildProtocol(None) - - self.assertEqual((None,), xs.args) - self.assertEqual({'test': None}, xs.kwargs) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xmpproutertap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xmpproutertap.py deleted file mode 100644 index f41bd5c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xmpproutertap.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.xmpproutertap}. -""" - -from twisted.application import internet -from twisted.trial import unittest -from twisted.words import xmpproutertap as tap -from twisted.words.protocols.jabber import component - -class XMPPRouterTapTests(unittest.TestCase): - - def test_port(self): - """ - The port option is recognised as a parameter. - """ - opt = tap.Options() - opt.parseOptions(['--port', '7001']) - self.assertEqual(opt['port'], '7001') - - - def test_portDefault(self): - """ - The port option has '5347' as default value - """ - opt = tap.Options() - opt.parseOptions([]) - self.assertEqual(opt['port'], 'tcp:5347:interface=127.0.0.1') - - - def test_secret(self): - """ - The secret option is recognised as a parameter. - """ - opt = tap.Options() - opt.parseOptions(['--secret', 'hushhush']) - self.assertEqual(opt['secret'], 'hushhush') - - - def test_secretDefault(self): - """ - The secret option has 'secret' as default value - """ - opt = tap.Options() - opt.parseOptions([]) - self.assertEqual(opt['secret'], 'secret') - - - def test_verbose(self): - """ - The verbose option is recognised as a flag. - """ - opt = tap.Options() - opt.parseOptions(['--verbose']) - self.assertTrue(opt['verbose']) - - - def test_makeService(self): - """ - The service gets set up with a router and factory. - """ - opt = tap.Options() - opt.parseOptions([]) - s = tap.makeService(opt) - self.assertIsInstance(s, internet.StreamServerEndpointService) - self.assertEqual('127.0.0.1', s.endpoint._interface) - self.assertEqual(5347, s.endpoint._port) - factory = s.factory - self.assertIsInstance(factory, component.XMPPComponentServerFactory) - self.assertIsInstance(factory.router, component.Router) - self.assertEqual('secret', factory.secret) - self.assertFalse(factory.logTraffic) - - - def test_makeServiceVerbose(self): - """ - The verbose flag enables traffic logging. - """ - opt = tap.Options() - opt.parseOptions(['--verbose']) - s = tap.makeService(opt) - self.assertTrue(s.factory.logTraffic) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xpath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xpath.py deleted file mode 100644 index f84e6e2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/test/test_xpath.py +++ /dev/null @@ -1,249 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest - -from twisted.words.xish.domish import Element -from twisted.words.xish.xpath import XPathQuery -from twisted.words.xish import xpath - -class XPathTests(unittest.TestCase): - def setUp(self): - # Build element: - # <foo xmlns='testns' attrib1='value1' attrib3="user@host/resource"> - # somecontent - # <bar> - # <foo> - # <gar>DEF</gar> - # </foo> - # </bar> - # somemorecontent - # <bar attrib2="value2"> - # <bar> - # <foo/> - # <gar>ABC</gar> - # </bar> - # <bar/> - # <bar attrib4='value4' attrib5='value5'> - # <foo/> - # <gar>JKL</gar> - # </bar> - # <bar attrib4='value4' attrib5='value4'> - # <foo/> - # <gar>MNO</gar> - # </bar> - # <bar attrib4='value4' attrib5='value6'/> - # </foo> - self.e = Element(("testns", "foo")) - self.e["attrib1"] = "value1" - self.e["attrib3"] = "user@host/resource" - self.e.addContent("somecontent") - self.bar1 = self.e.addElement("bar") - self.subfoo = self.bar1.addElement("foo") - self.gar1 = self.subfoo.addElement("gar") - self.gar1.addContent("DEF") - self.e.addContent("somemorecontent") - self.bar2 = self.e.addElement("bar") - self.bar2["attrib2"] = "value2" - self.bar3 = self.bar2.addElement("bar") - self.subfoo2 = self.bar3.addElement("foo") - self.gar2 = self.bar3.addElement("gar") - self.gar2.addContent("ABC") - self.bar4 = self.e.addElement("bar") - self.bar5 = self.e.addElement("bar") - self.bar5["attrib4"] = "value4" - self.bar5["attrib5"] = "value5" - self.subfoo3 = self.bar5.addElement("foo") - self.gar3 = self.bar5.addElement("gar") - self.gar3.addContent("JKL") - self.bar6 = self.e.addElement("bar") - self.bar6["attrib4"] = "value4" - self.bar6["attrib5"] = "value4" - self.subfoo4 = self.bar6.addElement("foo") - self.gar4 = self.bar6.addElement("gar") - self.gar4.addContent("MNO") - self.bar7 = self.e.addElement("bar") - self.bar7["attrib4"] = "value4" - self.bar7["attrib5"] = "value6" - - def test_staticMethods(self): - """ - Test basic operation of the static methods. - """ - self.assertEqual(xpath.matches("/foo/bar", self.e), - True) - self.assertEqual(xpath.queryForNodes("/foo/bar", self.e), - [self.bar1, self.bar2, self.bar4, - self.bar5, self.bar6, self.bar7]) - self.assertEqual(xpath.queryForString("/foo", self.e), - "somecontent") - self.assertEqual(xpath.queryForStringList("/foo", self.e), - ["somecontent", "somemorecontent"]) - - def test_locationFooBar(self): - """ - Test matching foo with child bar. - """ - xp = XPathQuery("/foo/bar") - self.assertEqual(xp.matches(self.e), 1) - - def test_locationFooBarFoo(self): - """ - Test finding foos at the second level. - """ - xp = XPathQuery("/foo/bar/foo") - self.assertEqual(xp.matches(self.e), 1) - self.assertEqual(xp.queryForNodes(self.e), [self.subfoo, - self.subfoo3, - self.subfoo4]) - - def test_locationNoBar3(self): - """ - Test not finding bar3. - """ - xp = XPathQuery("/foo/bar3") - self.assertEqual(xp.matches(self.e), 0) - - def test_locationAllChilds(self): - """ - Test finding childs of foo. - """ - xp = XPathQuery("/foo/*") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, - self.bar4, self.bar5, - self.bar6, self.bar7]) - - def test_attribute(self): - """ - Test matching foo with attribute. - """ - xp = XPathQuery("/foo[@attrib1]") - self.assertEqual(xp.matches(self.e), True) - - def test_attributeWithValueAny(self): - """ - Test find nodes with attribute having value. - """ - xp = XPathQuery("/foo/*[@attrib2='value2']") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.bar2]) - - def test_namespaceFound(self): - """ - Test matching node with namespace. - """ - xp = XPathQuery("/foo[@xmlns='testns']/bar") - self.assertEqual(xp.matches(self.e), 1) - - def test_namespaceNotFound(self): - """ - Test not matching node with wrong namespace. - """ - xp = XPathQuery("/foo[@xmlns='badns']/bar2") - self.assertEqual(xp.matches(self.e), 0) - - def test_attributeWithValue(self): - """ - Test matching node with attribute having value. - """ - xp = XPathQuery("/foo[@attrib1='value1']") - self.assertEqual(xp.matches(self.e), 1) - - def test_queryForString(self): - """ - Test for queryForString and queryForStringList. - """ - xp = XPathQuery("/foo") - self.assertEqual(xp.queryForString(self.e), "somecontent") - self.assertEqual(xp.queryForStringList(self.e), - ["somecontent", "somemorecontent"]) - - def test_queryForNodes(self): - """ - Test finding nodes. - """ - xp = XPathQuery("/foo/bar") - self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, - self.bar4, self.bar5, - self.bar6, self.bar7]) - - def test_textCondition(self): - """ - Test matching a node with given text. - """ - xp = XPathQuery("/foo[text() = 'somecontent']") - self.assertEqual(xp.matches(self.e), True) - - def test_textNotOperator(self): - """ - Test for not operator. - """ - xp = XPathQuery("/foo[not(@nosuchattrib)]") - self.assertEqual(xp.matches(self.e), True) - - def test_anyLocationAndText(self): - """ - Test finding any nodes named gar and getting their text contents. - """ - xp = XPathQuery("//gar") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.gar1, self.gar2, - self.gar3, self.gar4]) - self.assertEqual(xp.queryForStringList(self.e), ["DEF", "ABC", - "JKL", "MNO"]) - - def test_anyLocation(self): - """ - Test finding any nodes named bar. - """ - xp = XPathQuery("//bar") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, - self.bar3, self.bar4, - self.bar5, self.bar6, - self.bar7]) - - def test_anyLocationQueryForString(self): - """ - L{XPathQuery.queryForString} should raise a L{NotImplementedError} - for any location. - """ - xp = XPathQuery("//bar") - self.assertRaises(NotImplementedError, xp.queryForString, None) - - def test_andOperator(self): - """ - Test boolean and operator in condition. - """ - xp = XPathQuery("//bar[@attrib4='value4' and @attrib5='value5']") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.bar5]) - - def test_orOperator(self): - """ - Test boolean or operator in condition. - """ - xp = XPathQuery("//bar[@attrib5='value4' or @attrib5='value5']") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.bar5, self.bar6]) - - def test_booleanOperatorsParens(self): - """ - Test multiple boolean operators in condition with parens. - """ - xp = XPathQuery("""//bar[@attrib4='value4' and - (@attrib5='value4' or @attrib5='value6')]""") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.bar6, self.bar7]) - - def test_booleanOperatorsNoParens(self): - """ - Test multiple boolean operators in condition without parens. - """ - xp = XPathQuery("""//bar[@attrib5='value4' or - @attrib5='value5' or - @attrib5='value6']""") - self.assertEqual(xp.matches(self.e), True) - self.assertEqual(xp.queryForNodes(self.e), [self.bar5, self.bar6, self.bar7]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/NEWS b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/NEWS deleted file mode 100644 index 743cec3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/NEWS +++ /dev/null @@ -1,489 +0,0 @@ -Ticket numbers in this file can be looked up by visiting -http://twistedmatrix.com/trac/ticket/<number> - -Twisted Words 15.2.1 (2015-05-23) -================================= - -No significant changes have been made for this release. - - -Twisted Words 15.2.0 (2015-05-18) -================================= - -Bugfixes --------- - - The resumeOffset argument to - twisted.words.protocol.irc.DccFileReceive now works as it is - documented. (#7775) - - -Twisted Words 15.1.0 (2015-04-02) -================================= - -Deprecations and Removals -------------------------- - - twisted.words.protocols.msn is now deprecated (#6395) - -Other ------ - - #6494 - - -Twisted Words 15.0.0 (2015-01-24) -================================= - -No significant changes have been made for this release. - -Other ------ - - #6994, #7163, #7622 - - -Twisted Words 14.0.2 (2014-09-18) -================================= - -No significant changes have been made for this release. - - -Twisted Words 14.0.1 (2014-09-17) -================================= - -No significant changes have been made for this release. - - -Twisted Words 14.0.0 (2014-05-08) -================================= - -Bugfixes --------- - - twisted.words.protocols.jabber.sasl_mechansisms.DigestMD5 now works - with unicode arguments. (#5066) - -Other ------ - - #6696 - - -Twisted Words 13.2.0 (2013-10-29) -================================= - -Bugfixes --------- - - twisted.words.service.IRCUser now properly reports an error, in - response to NICK commands with non-UTF8 and non-ASCII symbols. - (#5780) - -Other ------ - - #5329, #5387, #6544 - - -Twisted Words 13.1.0 (2013-06-23) -================================= - -Features --------- - - twisted.words.protocols.irc.assembleFormattedText flattens a - formatting structure into mIRC-formatted markup; conversely - twisted.words.protocols.irc.stripFormatting removes all mIRC - formatting from text. (#3844) - -Deprecations and Removals -------------------------- - - The `crippled` attribute in - twisted.words.protocols.jabber.xmpp_stringprep is deprecated now. - (#5386) - -Other ------ - - #6315, #6342, #6392, #6402, #6479, #6481, #6482 - - -Twisted Words 13.0.0 (2013-03-19) -================================= - -Bugfixes --------- - - twisted.words.im.ircsupport no longer logs a failure whenever - receiving ISUPPORT messages from an IRC server. (#6263) - -Other ------ - - #6297 - - -Twisted Words 12.3.0 (2012-12-20) -================================= - -Improved Documentation ----------------------- - - The Twisted Words code examples now documents inside each example - description on how to run it. (#5589) - - -Twisted Words 12.2.0 (2012-08-26) -================================= - -No significant changes have been made for this release. - -Other ------ - - #5752, #5753 - - -Twisted Words 12.1.0 (2012-06-02) -================================= - -Bugfixes --------- - - twisted.words.protocols.irc.DccChatFactory.buildProtocol now - returns the protocol object that it creates (#3179) - - twisted.words.im no longer offers an empty threat of a rewrite on - import. (#5598) - -Other ------ - - #5555, #5595 - - -Twisted Words 12.0.0 (2012-02-10) -================================= - -Improved Documentation ----------------------- - - twisted.words.im.basechat now has improved API documentation. - (#2458) - -Other ------ - - #5401 - - -Twisted Words 11.1.0 (2011-11-15) -================================= - -Features --------- - - twisted.words.protocols.irc.IRCClient now uses a PING heartbeat as - a keepalive to avoid losing an IRC connection without being aware - of it. (#5047) - -Bugfixes --------- - - twisted.words.protocols.irc.IRCClient now replies only once to - known CTCP queries per message and not at all to unknown CTCP - queries. (#5029) - - IRCClient.msg now determines a safe maximum command length, - drastically reducing the chance of relayed text being truncated on - the server side. (#5176) - -Deprecations and Removals -------------------------- - - twisted.words.protocols.irc.IRCClient.me was deprecated in Twisted - 9.0 and has been removed. Use IRCClient.describe instead. (#5059) - -Other ------ - - #5025, #5330 - - -Twisted Words 11.0.0 (2011-04-01) -================================= - -Features --------- - - twisted.words.protocols.irc.IRCClient now has an invite method. - (#4820) - -Bugfixes --------- - - twisted.words.protocols.irc.IRCClient.say is once again able to - send messages when using the default value for the length limit - argument. (#4758) - - twisted.words.protocols.jabber.jstrports is once again able to - parse jstrport description strings. (#4771) - - twisted.words.protocols.msn.NotificationClient now calls the - loginFailure callback when it is unable to connect to the Passport - server due to missing SSL dependencies. (#4801) - - twisted.words.protocols.jabber.xmpp_stringprep now always uses - Unicode version 3.2 for stringprep normalization. (#4850) - -Improved Documentation ----------------------- - - Removed the non-working AIM bot example, depending on the obsolete - twisted.words.protocols.toc functionality. (#4007) - - Outdated GUI-related information was removed from the IM howto. - (#4054) - -Deprecations and Removals -------------------------- - - Remove twisted.words.protocols.toc, that was largely non-working - and useless since AOL disabled TOC on their AIM network. (#4363) - -Other ------ - - #4733, #4902 - - -Twisted Words 10.2.0 (2010-11-29) -================================= - -Features --------- - - twisted.words.protocols.irc.IRCClient.msg now enforces a maximum - length for messages, splitting up messages that are too long. - (#4416) - -Bugfixes --------- - - twisted.words.protocols.irc.IRCClient no longer invokes privmsg() - in the default noticed() implementation. (#4419) - - twisted.words.im.ircsupport.IRCProto now sends the correct name in - the USER command. (#4641) - -Deprecations and Removals -------------------------- - - Remove twisted.words.im.proxyui and twisted.words.im.tap. (#1823) - - -Twisted Words 10.1.0 (2010-06-27) -================================= - -Bugfixes --------- - - twisted.words.im.basechat.ChatUI now has a functional - contactChangedNick with unit tests. (#229) - - twisted.words.protocols.jabber.error.StanzaError now correctly sets - a default error type and code for the remote-server-timeout - condition (#4311) - - twisted.words.protocols.jabber.xmlstream.ListenAuthenticator now - uses unicode objects for session identifiers (#4345) - - -Twisted Words 10.0.0 (2010-03-01) -================================= - -Features --------- - - twisted.words.protocols.irc.IRCClient.irc_MODE now takes ISUPPORT - parameters into account when parsing mode messages with arguments - that take parameters (#3296) - -Bugfixes --------- - - When twisted.words.protocols.irc.IRCClient's versionNum and - versionEnv attributes are set to None, they will no longer be - included in the client's response to CTCP VERSION queries. (#3660) - - - twisted.words.protocols.jabber.xmlstream.hashPassword now only - accepts unicode as input (#3741, #3742, #3847) - -Other ------ - - #2503, #4066, #4261 - - -Twisted Words 9.0.0 (2009-11-24) -================================ - -Features --------- - - IRCClient.describe is a new method meant to replace IRCClient.me to send - CTCP ACTION messages with less confusing behavior (#3910) - - The XMPP client protocol implementation now supports ANONYMOUS SASL - authentication (#4067) - - The IRC client protocol implementation now has better support for the - ISUPPORT server->client message, storing the data in a new - ServerSupportedFeatures object accessible via IRCClient.supported (#3285) - -Fixes ------ - - The twisted.words IRC server now always sends an MOTD, which at least makes - Pidgin able to successfully connect to a twisted.words IRC server (#2385) - - The IRC client will now dispatch "RPL MOTD" messages received before a - "RPL MOTD START" instead of raising an exception (#3676) - - The IRC client protocol implementation no longer updates its 'nickname' - attribute directly; instead, that attribute will be updated when the server - acknowledges the change (#3377) - - The IRC client protocol implementation now supports falling back to another - nickname when a nick change request fails (#3377, #4010) - -Deprecations and Removals -------------------------- - - The TOC protocol implementation is now deprecated, since the protocol itself - has been deprecated and obselete for quite a long time (#3580) - - The gui "im" application has been removed, since it relied on GTK1, which is - hard to find these days (#3699, #3340) - -Other ------ - - #2763, #3540, #3647, #3750, #3895, #3968, #4050 - -Words 8.2.0 (2008-12-16) -======================== - -Feature -------- - - There is now a standalone XMPP router included in twisted.words: it can be - used with the 'twistd xmpp-router' command line (#3407) - - A server factory for Jabber XML Streams has been added (#3435) - - Domish now allows for iterating child elements with specific qualified names - (#2429) - - IRCClient now has a 'back' method which removes the away status (#3366) - - IRCClient now has a 'whois' method (#3133) - -Fixes ------ - - The IRC Client implementation can now deal with compound mode changes (#3230) - - The MSN protocol implementation no longer requires the CVR0 protocol to - be included in the VER command (#3394) - - In the IRC server implementation, topic messages will no longer be sent for - a group which has no topic (#2204) - - An infinite loop (which caused infinite memory usage) in irc.split has been - fixed. This was triggered any time a message that starts with a delimiter - was sent (#3446) - - Jabber's toResponse now generates a valid stanza even when stanzaType is not - specified (#3467) - - The lifetime of authenticator instances in XmlStreamServerFactory is no - longer artificially extended (#3464) - -Other ------ - - #3365 - - -8.1.0 (2008-05-18) -================== - -Features --------- - - JID objects now have a nice __repr__ (#3156) - - Extending XMPP protocols is now easier (#2178) - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - A bug whereby one-time XMPP observers would be enabled permanently was fixed - (#3066) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Provide function for creating XMPP response stanzas. (#2614, #2614) - - Log exceptions raised in Xish observers. (#2616) - - Add 'and' and 'or' operators for Xish XPath expressions. (#2502) - - Make JIDs hashable. (#2770) - -Fixes ------ - - Respect the hostname and servername parameters to IRCClient.register. (#1649) - - Make EventDispatcher remove empty callback lists. (#1652) - - Use legacy base64 API to support Python 2.3 (#2461) - - Fix support of DIGEST-MD5 challenge parsing with multi-valued directives. - (#2606) - - Fix reuse of dict of prefixes in domish.Element.toXml (#2609) - - Properly process XMPP stream headers (#2615) - - Use proper namespace for XMPP stream errors. (#2630) - - Properly parse XMPP stream errors. (#2771) - - Fix toResponse for XMPP stanzas without an id attribute. (#2773) - - Move XMPP stream header procesing to authenticators. (#2772) - -Misc ----- - - #2617, #2640, #2741, #2063, #2570, #2847 - - -0.5.0 (2007-01-06) -================== - -Features --------- - - (Jabber) IQ.send now optionally has a 'timeout' parameter which - specifies a time at which to errback the Deferred with a - TimeoutError (#2218) - - (Jabber) SASL authentication, resource binding and session - establishment were added. (#1046) The following were done in - support of this change: - - Rework ConnectAuthenticator to work with initializer objects that - provide a stream initialization step. - - Reimplement iq:auth as an initializer. - - Reimplement TLS negotiation as an initializer. - - Add XMPPAuthenticator as a XMPP 1.0 client authenticator (only), along - with XMPPClientFactory. - - Add support for working with pre-XMPP-1.0 error stanzas. - - Remove hasFeature() from XmlStream as you can test (uri, name) in - xs.features. - - Add sendFooter() and sendStreamError() to XmlStream - -Fixes ------ - - (Jabber) Deferreds from queries which were never resolved before - a lost connection are now errbacked (#2006) - - (Jabber) servers which didn't send a 'realm' directive in - authentication challenges no longer cause the Jabber client to - choke (#2098) - - (MSN) error responses are now properly turned into errbacks (#2019) - - (IRC) A trivial bug in IRCClient which would cause whois(oper=True) - to always raise an exception was fixed (#2089) - - (IM) Bugs in the error handling and already-connecting cases of - AbstractAccount.logOn were fixed (#2086) - -Misc ----- - - #1734, #1735, #1636, #1936, #1883, #1995, #2171, #2165, #2177 - - -0.4.0 (2006-05-21) -================== - -Features --------- - - Jabber: - - Add support for stream and stanza level errors - - Create new IQ stanza helper that works with deferreds - - Add TLS support for initiating entities to XmlStream - - Fix account registration - - Xish: - - Fix various namespace issues - - Add IElement - - Store namespace declarations in parsed XML for later serialization - - Fix user name/group collision in server service (#1655). - - Correctly recognize MSN capability messages (#861). - -Fixes ------ - - Misc: #1283, #1296, #1302, #1424 - - Fix unicode/str confusion in IRC server service. - - -0.3.0: - - Jabber: - - - Fix digest authentication in Jabber - - Add Jabber xmlstream module that contains the Jabber specific bits that - got factored out of Twisted Xish's xmlstream, and make it suitable for - implementing full XMPP support. - - Xish: - - Fixed serialization in _ListSerializer - - Removed unneeded extra whitespace generated in serialization - - Removed _Serializer in favour of _ListSerializer - - Use unicode objects for representing serialized XML, instead of utf-8 - encoded str objects. - - Properly catch XML parser errors - - Rework and fix element stream test cases - - Strip xmlstream from all Jabber specifics that moved to Twisted Words - - Added exhaustive docstrings to xmlstream. - - Words Service: - - Complete rewrite - - Not backwards compatible - -0.1.0: - - Fix some miscellaneous bugs in OSCAR - - Add QUIT notification for IRC - - Fix message wrapping - - Misc Jabber fixes - - Add stringprep support for Jabber IDs - This only works properly on 2.3.2 or higher diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/README b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/README deleted file mode 100644 index 9e71266..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/README +++ /dev/null @@ -1,5 +0,0 @@ -Twisted Words 15.2.1 - -Twisted Words depends on Twisted Core and Twisted Web. The Twisted Web -dependency is only necessary for MSN support. MSN support also requires HTTPS, -and therefore pyOpenSSL (<http://launchpad.net/pyopenssl>). diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/setup.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/setup.py deleted file mode 100644 index f13c0bd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/topfiles/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - extraMeta = dict( - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Communications :: Chat", - "Topic :: Communications :: Chat :: AOL Instant Messenger", - "Topic :: Communications :: Chat :: ICQ", - "Topic :: Communications :: Chat :: Internet Relay Chat", - "Topic :: Internet", - "Topic :: Software Development :: Libraries :: Python Modules", - ]) - - dist.setup( - twisted_subproject="words", - scripts=dist.getScripts("words"), - # metadata - name="Twisted Words", - description="Twisted Words contains Instant Messaging implementations.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - url="http://twistedmatrix.com/trac/wiki/TwistedWords", - license="MIT", - long_description="""\ -Twisted Words contains implementations of many Instant Messaging protocols, -including IRC, Jabber, OSCAR (AIM & ICQ), and some functionality for creating -bots, inter-protocol gateways, and a client application for many of the -protocols. - -In support of Jabber, Twisted Words also contains X-ish, a library for -processing XML with Twisted and Python, with support for a Pythonic DOM and -an XPath-like toolkit. -""", - **extraMeta) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/__init__.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/__init__.py deleted file mode 100644 index 1d2469f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted X-ish: XML-ish DOM and XPath-ish engine - -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/domish.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/domish.py deleted file mode 100644 index 3be7ed6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/domish.py +++ /dev/null @@ -1,848 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_domish -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -DOM-like XML processing support. - -This module provides support for parsing XML into DOM-like object structures -and serializing such structures to an XML string representation, optimized -for use in streaming XML applications. -""" - -import types - -from zope.interface import implements, Interface, Attribute - -def _splitPrefix(name): - """ Internal method for splitting a prefixed Element name into its - respective parts """ - ntok = name.split(":", 1) - if len(ntok) == 2: - return ntok - else: - return (None, ntok[0]) - -# Global map of prefixes that always get injected -# into the serializers prefix map (note, that doesn't -# mean they're always _USED_) -G_PREFIXES = { "http://www.w3.org/XML/1998/namespace":"xml" } - -class _ListSerializer: - """ Internal class which serializes an Element tree into a buffer """ - def __init__(self, prefixes=None, prefixesInScope=None): - self.writelist = [] - self.prefixes = {} - if prefixes: - self.prefixes.update(prefixes) - self.prefixes.update(G_PREFIXES) - self.prefixStack = [G_PREFIXES.values()] + (prefixesInScope or []) - self.prefixCounter = 0 - - def getValue(self): - return u"".join(self.writelist) - - def getPrefix(self, uri): - if uri not in self.prefixes: - self.prefixes[uri] = "xn%d" % (self.prefixCounter) - self.prefixCounter = self.prefixCounter + 1 - return self.prefixes[uri] - - def prefixInScope(self, prefix): - stack = self.prefixStack - for i in range(-1, (len(self.prefixStack)+1) * -1, -1): - if prefix in stack[i]: - return True - return False - - def serialize(self, elem, closeElement=1, defaultUri=''): - # Optimization shortcuts - write = self.writelist.append - - # Shortcut, check to see if elem is actually a chunk o' serialized XML - if isinstance(elem, SerializedXML): - write(elem) - return - - # Shortcut, check to see if elem is actually a string (aka Cdata) - if isinstance(elem, types.StringTypes): - write(escapeToXml(elem)) - return - - # Further optimizations - name = elem.name - uri = elem.uri - defaultUri, currentDefaultUri = elem.defaultUri, defaultUri - - for p, u in elem.localPrefixes.iteritems(): - self.prefixes[u] = p - self.prefixStack.append(elem.localPrefixes.keys()) - - # Inherit the default namespace - if defaultUri is None: - defaultUri = currentDefaultUri - - if uri is None: - uri = defaultUri - - prefix = None - if uri != defaultUri or uri in self.prefixes: - prefix = self.getPrefix(uri) - inScope = self.prefixInScope(prefix) - - # Create the starttag - - if not prefix: - write("<%s" % (name)) - else: - write("<%s:%s" % (prefix, name)) - - if not inScope: - write(" xmlns:%s='%s'" % (prefix, uri)) - self.prefixStack[-1].append(prefix) - inScope = True - - if defaultUri != currentDefaultUri and \ - (uri != defaultUri or not prefix or not inScope): - write(" xmlns='%s'" % (defaultUri)) - - for p, u in elem.localPrefixes.iteritems(): - write(" xmlns:%s='%s'" % (p, u)) - - # Serialize attributes - for k,v in elem.attributes.items(): - # If the attribute name is a tuple, it's a qualified attribute - if isinstance(k, types.TupleType): - attr_uri, attr_name = k - attr_prefix = self.getPrefix(attr_uri) - - if not self.prefixInScope(attr_prefix): - write(" xmlns:%s='%s'" % (attr_prefix, attr_uri)) - self.prefixStack[-1].append(attr_prefix) - - write(" %s:%s='%s'" % (attr_prefix, attr_name, - escapeToXml(v, 1))) - else: - write((" %s='%s'" % ( k, escapeToXml(v, 1)))) - - # Shortcut out if this is only going to return - # the element (i.e. no children) - if closeElement == 0: - write(">") - return - - # Serialize children - if len(elem.children) > 0: - write(">") - for c in elem.children: - self.serialize(c, defaultUri=defaultUri) - # Add closing tag - if not prefix: - write("</%s>" % (name)) - else: - write("</%s:%s>" % (prefix, name)) - else: - write("/>") - - self.prefixStack.pop() - - -SerializerClass = _ListSerializer - -def escapeToXml(text, isattrib = 0): - """ Escape text to proper XML form, per section 2.3 in the XML specification. - - @type text: C{str} - @param text: Text to escape - - @type isattrib: C{bool} - @param isattrib: Triggers escaping of characters necessary for use as - attribute values - """ - text = text.replace("&", "&amp;") - text = text.replace("<", "&lt;") - text = text.replace(">", "&gt;") - if isattrib == 1: - text = text.replace("'", "&apos;") - text = text.replace("\"", "&quot;") - return text - -def unescapeFromXml(text): - text = text.replace("&lt;", "<") - text = text.replace("&gt;", ">") - text = text.replace("&apos;", "'") - text = text.replace("&quot;", "\"") - text = text.replace("&amp;", "&") - return text - -def generateOnlyInterface(list, int): - """ Filters items in a list by class - """ - for n in list: - if int.providedBy(n): - yield n - -def generateElementsQNamed(list, name, uri): - """ Filters Element items in a list with matching name and URI. """ - for n in list: - if IElement.providedBy(n) and n.name == name and n.uri == uri: - yield n - -def generateElementsNamed(list, name): - """ Filters Element items in a list with matching name, regardless of URI. - """ - for n in list: - if IElement.providedBy(n) and n.name == name: - yield n - - -class SerializedXML(unicode): - """ Marker class for pre-serialized XML in the DOM. """ - pass - - -class Namespace: - """ Convenience object for tracking namespace declarations. """ - def __init__(self, uri): - self._uri = uri - def __getattr__(self, n): - return (self._uri, n) - def __getitem__(self, n): - return (self._uri, n) - -class IElement(Interface): - """ - Interface to XML element nodes. - - See L{Element} for a detailed example of its general use. - - Warning: this Interface is not yet complete! - """ - - uri = Attribute(""" Element's namespace URI """) - name = Attribute(""" Element's local name """) - defaultUri = Attribute(""" Default namespace URI of child elements """) - attributes = Attribute(""" Dictionary of element attributes """) - children = Attribute(""" List of child nodes """) - parent = Attribute(""" Reference to element's parent element """) - localPrefixes = Attribute(""" Dictionary of local prefixes """) - - def toXml(prefixes=None, closeElement=1, defaultUri='', - prefixesInScope=None): - """ Serializes object to a (partial) XML document - - @param prefixes: dictionary that maps namespace URIs to suggested - prefix names. - @type prefixes: L{dict} - @param closeElement: flag that determines whether to include the - closing tag of the element in the serialized - string. A value of C{0} only generates the - element's start tag. A value of C{1} yields a - complete serialization. - @type closeElement: C{int} - @param defaultUri: Initial default namespace URI. This is most useful - for partial rendering, where the logical parent - element (of which the starttag was already - serialized) declares a default namespace that should - be inherited. - @type defaultUri: C{str} - @param prefixesInScope: list of prefixes that are assumed to be - declared by ancestors. - @type prefixesInScope: C{list} - @return: (partial) serialized XML - @rtype: C{unicode} - """ - - def addElement(name, defaultUri = None, content = None): - """ Create an element and add as child. - - The new element is added to this element as a child, and will have - this element as its parent. - - @param name: element name. This can be either a C{unicode} object that - contains the local name, or a tuple of (uri, local_name) - for a fully qualified name. In the former case, - the namespace URI is inherited from this element. - @type name: C{unicode} or C{tuple} of (C{unicode}, C{unicode}) - @param defaultUri: default namespace URI for child elements. If - C{None}, this is inherited from this element. - @type defaultUri: C{unicode} - @param content: text contained by the new element. - @type content: C{unicode} - @return: the created element - @rtype: object providing L{IElement} - """ - - def addChild(node): - """ Adds a node as child of this element. - - The C{node} will be added to the list of childs of this element, and - will have this element set as its parent when C{node} provides - L{IElement}. - - @param node: the child node. - @type node: C{unicode} or object implementing L{IElement} - """ - -class Element(object): - """ Represents an XML element node. - - An Element contains a series of attributes (name/value pairs), content - (character data), and other child Element objects. When building a document - with markup (such as HTML or XML), use this object as the starting point. - - Element objects fully support XML Namespaces. The fully qualified name of - the XML Element it represents is stored in the C{uri} and C{name} - attributes, where C{uri} holds the namespace URI. There is also a default - namespace, for child elements. This is stored in the C{defaultUri} - attribute. Note that C{''} means the empty namespace. - - Serialization of Elements through C{toXml()} will use these attributes - for generating proper serialized XML. When both C{uri} and C{defaultUri} - are not None in the Element and all of its descendents, serialization - proceeds as expected: - - >>> from twisted.words.xish import domish - >>> root = domish.Element(('myns', 'root')) - >>> root.addElement('child', content='test') - <twisted.words.xish.domish.Element object at 0x83002ac> - >>> root.toXml() - u"<root xmlns='myns'><child>test</child></root>" - - For partial serialization, needed for streaming XML, a special value for - namespace URIs can be used: C{None}. - - Using C{None} as the value for C{uri} means: this element is in whatever - namespace inherited by the closest logical ancestor when the complete XML - document has been serialized. The serialized start tag will have a - non-prefixed name, and no xmlns declaration will be generated. - - Similarly, C{None} for C{defaultUri} means: the default namespace for my - child elements is inherited from the logical ancestors of this element, - when the complete XML document has been serialized. - - To illustrate, an example from a Jabber stream. Assume the start tag of the - root element of the stream has already been serialized, along with several - complete child elements, and sent off, looking like this:: - - <stream:stream xmlns:stream='http://etherx.jabber.org/streams' - xmlns='jabber:client' to='example.com'> - ... - - Now suppose we want to send a complete element represented by an - object C{message} created like: - - >>> message = domish.Element((None, 'message')) - >>> message['to'] = 'user@example.com' - >>> message.addElement('body', content='Hi!') - <twisted.words.xish.domish.Element object at 0x8276e8c> - >>> message.toXml() - u"<message to='user@example.com'><body>Hi!</body></message>" - - As, you can see, this XML snippet has no xmlns declaration. When sent - off, it inherits the C{jabber:client} namespace from the root element. - Note that this renders the same as using C{''} instead of C{None}: - - >>> presence = domish.Element(('', 'presence')) - >>> presence.toXml() - u"<presence/>" - - However, if this object has a parent defined, the difference becomes - clear: - - >>> child = message.addElement(('http://example.com/', 'envelope')) - >>> child.addChild(presence) - <twisted.words.xish.domish.Element object at 0x8276fac> - >>> message.toXml() - u"<message to='user@example.com'><body>Hi!</body><envelope xmlns='http://example.com/'><presence xmlns=''/></envelope></message>" - - As, you can see, the <presence/> element is now in the empty namespace, not - in the default namespace of the parent or the streams'. - - @type uri: C{unicode} or None - @ivar uri: URI of this Element's name - - @type name: C{unicode} - @ivar name: Name of this Element - - @type defaultUri: C{unicode} or None - @ivar defaultUri: URI this Element exists within - - @type children: C{list} - @ivar children: List of child Elements and content - - @type parent: L{Element} - @ivar parent: Reference to the parent Element, if any. - - @type attributes: L{dict} - @ivar attributes: Dictionary of attributes associated with this Element. - - @type localPrefixes: L{dict} - @ivar localPrefixes: Dictionary of namespace declarations on this - element. The key is the prefix to bind the - namespace uri to. - """ - - implements(IElement) - - _idCounter = 0 - - def __init__(self, qname, defaultUri=None, attribs=None, - localPrefixes=None): - """ - @param qname: Tuple of (uri, name) - @param defaultUri: The default URI of the element; defaults to the URI - specified in C{qname} - @param attribs: Dictionary of attributes - @param localPrefixes: Dictionary of namespace declarations on this - element. The key is the prefix to bind the - namespace uri to. - """ - self.localPrefixes = localPrefixes or {} - self.uri, self.name = qname - if defaultUri is None and \ - self.uri not in self.localPrefixes.itervalues(): - self.defaultUri = self.uri - else: - self.defaultUri = defaultUri - self.attributes = attribs or {} - self.children = [] - self.parent = None - - def __getattr__(self, key): - # Check child list for first Element with a name matching the key - for n in self.children: - if IElement.providedBy(n) and n.name == key: - return n - - # Tweak the behaviour so that it's more friendly about not - # finding elements -- we need to document this somewhere :) - if key.startswith('_'): - raise AttributeError(key) - else: - return None - - def __getitem__(self, key): - return self.attributes[self._dqa(key)] - - def __delitem__(self, key): - del self.attributes[self._dqa(key)]; - - def __setitem__(self, key, value): - self.attributes[self._dqa(key)] = value - - def __str__(self): - """ Retrieve the first CData (content) node - """ - for n in self.children: - if isinstance(n, types.StringTypes): return n - return "" - - def _dqa(self, attr): - """ Dequalify an attribute key as needed """ - if isinstance(attr, types.TupleType) and not attr[0]: - return attr[1] - else: - return attr - - def getAttribute(self, attribname, default = None): - """ Retrieve the value of attribname, if it exists """ - return self.attributes.get(attribname, default) - - def hasAttribute(self, attrib): - """ Determine if the specified attribute exists """ - return self._dqa(attrib) in self.attributes - - def compareAttribute(self, attrib, value): - """ Safely compare the value of an attribute against a provided value. - - C{None}-safe. - """ - return self.attributes.get(self._dqa(attrib), None) == value - - def swapAttributeValues(self, left, right): - """ Swap the values of two attribute. """ - d = self.attributes - l = d[left] - d[left] = d[right] - d[right] = l - - def addChild(self, node): - """ Add a child to this Element. """ - if IElement.providedBy(node): - node.parent = self - self.children.append(node) - return self.children[-1] - - def addContent(self, text): - """ Add some text data to this Element. """ - c = self.children - if len(c) > 0 and isinstance(c[-1], types.StringTypes): - c[-1] = c[-1] + text - else: - c.append(text) - return c[-1] - - def addElement(self, name, defaultUri = None, content = None): - result = None - if isinstance(name, type(())): - if defaultUri is None: - defaultUri = name[0] - self.children.append(Element(name, defaultUri)) - else: - if defaultUri is None: - defaultUri = self.defaultUri - self.children.append(Element((defaultUri, name), defaultUri)) - - result = self.children[-1] - result.parent = self - - if content: - result.children.append(content) - - return result - - def addRawXml(self, rawxmlstring): - """ Add a pre-serialized chunk o' XML as a child of this Element. """ - self.children.append(SerializedXML(rawxmlstring)) - - def addUniqueId(self): - """ Add a unique (across a given Python session) id attribute to this - Element. - """ - self.attributes["id"] = "H_%d" % Element._idCounter - Element._idCounter = Element._idCounter + 1 - - - def elements(self, uri=None, name=None): - """ - Iterate across all children of this Element that are Elements. - - Returns a generator over the child elements. If both the C{uri} and - C{name} parameters are set, the returned generator will only yield - on elements matching the qualified name. - - @param uri: Optional element URI. - @type uri: C{unicode} - @param name: Optional element name. - @type name: C{unicode} - @return: Iterator that yields objects implementing L{IElement}. - """ - if name is None: - return generateOnlyInterface(self.children, IElement) - else: - return generateElementsQNamed(self.children, name, uri) - - - def toXml(self, prefixes=None, closeElement=1, defaultUri='', - prefixesInScope=None): - """ Serialize this Element and all children to a string. """ - s = SerializerClass(prefixes=prefixes, prefixesInScope=prefixesInScope) - s.serialize(self, closeElement=closeElement, defaultUri=defaultUri) - return s.getValue() - - def firstChildElement(self): - for c in self.children: - if IElement.providedBy(c): - return c - return None - - -class ParserError(Exception): - """ Exception thrown when a parsing error occurs """ - pass - -def elementStream(): - """ Preferred method to construct an ElementStream - - Uses Expat-based stream if available, and falls back to Sux if necessary. - """ - try: - es = ExpatElementStream() - return es - except ImportError: - if SuxElementStream is None: - raise Exception("No parsers available :(") - es = SuxElementStream() - return es - -try: - from twisted.web import sux -except: - SuxElementStream = None -else: - class SuxElementStream(sux.XMLParser): - def __init__(self): - self.connectionMade() - self.DocumentStartEvent = None - self.ElementEvent = None - self.DocumentEndEvent = None - self.currElem = None - self.rootElem = None - self.documentStarted = False - self.defaultNsStack = [] - self.prefixStack = [] - - def parse(self, buffer): - try: - self.dataReceived(buffer) - except sux.ParseError, e: - raise ParserError, str(e) - - - def findUri(self, prefix): - # Walk prefix stack backwards, looking for the uri - # matching the specified prefix - stack = self.prefixStack - for i in range(-1, (len(self.prefixStack)+1) * -1, -1): - if prefix in stack[i]: - return stack[i][prefix] - return None - - def gotTagStart(self, name, attributes): - defaultUri = None - localPrefixes = {} - attribs = {} - uri = None - - # Pass 1 - Identify namespace decls - for k, v in attributes.items(): - if k.startswith("xmlns"): - x, p = _splitPrefix(k) - if (x is None): # I.e. default declaration - defaultUri = v - else: - localPrefixes[p] = v - del attributes[k] - - # Push namespace decls onto prefix stack - self.prefixStack.append(localPrefixes) - - # Determine default namespace for this element; if there - # is one - if defaultUri is None: - if len(self.defaultNsStack) > 0: - defaultUri = self.defaultNsStack[-1] - else: - defaultUri = '' - - # Fix up name - prefix, name = _splitPrefix(name) - if prefix is None: # This element is in the default namespace - uri = defaultUri - else: - # Find the URI for the prefix - uri = self.findUri(prefix) - - # Pass 2 - Fix up and escape attributes - for k, v in attributes.items(): - p, n = _splitPrefix(k) - if p is None: - attribs[n] = v - else: - attribs[(self.findUri(p)), n] = unescapeFromXml(v) - - # Construct the actual Element object - e = Element((uri, name), defaultUri, attribs, localPrefixes) - - # Save current default namespace - self.defaultNsStack.append(defaultUri) - - # Document already started - if self.documentStarted: - # Starting a new packet - if self.currElem is None: - self.currElem = e - # Adding to existing element - else: - self.currElem = self.currElem.addChild(e) - # New document - else: - self.rootElem = e - self.documentStarted = True - self.DocumentStartEvent(e) - - def gotText(self, data): - if self.currElem != None: - self.currElem.addContent(data) - - def gotCData(self, data): - if self.currElem != None: - self.currElem.addContent(data) - - def gotComment(self, data): - # Ignore comments for the moment - pass - - entities = { "amp" : "&", - "lt" : "<", - "gt" : ">", - "apos": "'", - "quot": "\"" } - - def gotEntityReference(self, entityRef): - # If this is an entity we know about, add it as content - # to the current element - if entityRef in SuxElementStream.entities: - self.currElem.addContent(SuxElementStream.entities[entityRef]) - - def gotTagEnd(self, name): - # Ensure the document hasn't already ended - if self.rootElem is None: - # XXX: Write more legible explanation - raise ParserError, "Element closed after end of document." - - # Fix up name - prefix, name = _splitPrefix(name) - if prefix is None: - uri = self.defaultNsStack[-1] - else: - uri = self.findUri(prefix) - - # End of document - if self.currElem is None: - # Ensure element name and uri matches - if self.rootElem.name != name or self.rootElem.uri != uri: - raise ParserError, "Mismatched root elements" - self.DocumentEndEvent() - self.rootElem = None - - # Other elements - else: - # Ensure the tag being closed matches the name of the current - # element - if self.currElem.name != name or self.currElem.uri != uri: - # XXX: Write more legible explanation - raise ParserError, "Malformed element close" - - # Pop prefix and default NS stack - self.prefixStack.pop() - self.defaultNsStack.pop() - - # Check for parent null parent of current elem; - # that's the top of the stack - if self.currElem.parent is None: - self.currElem.parent = self.rootElem - self.ElementEvent(self.currElem) - self.currElem = None - - # Anything else is just some element wrapping up - else: - self.currElem = self.currElem.parent - - -class ExpatElementStream: - def __init__(self): - import pyexpat - self.DocumentStartEvent = None - self.ElementEvent = None - self.DocumentEndEvent = None - self.error = pyexpat.error - self.parser = pyexpat.ParserCreate("UTF-8", " ") - self.parser.StartElementHandler = self._onStartElement - self.parser.EndElementHandler = self._onEndElement - self.parser.CharacterDataHandler = self._onCdata - self.parser.StartNamespaceDeclHandler = self._onStartNamespace - self.parser.EndNamespaceDeclHandler = self._onEndNamespace - self.currElem = None - self.defaultNsStack = [''] - self.documentStarted = 0 - self.localPrefixes = {} - - def parse(self, buffer): - try: - self.parser.Parse(buffer) - except self.error, e: - raise ParserError, str(e) - - def _onStartElement(self, name, attrs): - # Generate a qname tuple from the provided name. See - # http://docs.python.org/library/pyexpat.html#xml.parsers.expat.ParserCreate - # for an explanation of the formatting of name. - qname = name.rsplit(" ", 1) - if len(qname) == 1: - qname = ('', name) - - # Process attributes - for k, v in attrs.items(): - if " " in k: - aqname = k.rsplit(" ", 1) - attrs[(aqname[0], aqname[1])] = v - del attrs[k] - - # Construct the new element - e = Element(qname, self.defaultNsStack[-1], attrs, self.localPrefixes) - self.localPrefixes = {} - - # Document already started - if self.documentStarted == 1: - if self.currElem != None: - self.currElem.children.append(e) - e.parent = self.currElem - self.currElem = e - - # New document - else: - self.documentStarted = 1 - self.DocumentStartEvent(e) - - def _onEndElement(self, _): - # Check for null current elem; end of doc - if self.currElem is None: - self.DocumentEndEvent() - - # Check for parent that is None; that's - # the top of the stack - elif self.currElem.parent is None: - self.ElementEvent(self.currElem) - self.currElem = None - - # Anything else is just some element in the current - # packet wrapping up - else: - self.currElem = self.currElem.parent - - def _onCdata(self, data): - if self.currElem != None: - self.currElem.addContent(data) - - def _onStartNamespace(self, prefix, uri): - # If this is the default namespace, put - # it on the stack - if prefix is None: - self.defaultNsStack.append(uri) - else: - self.localPrefixes[prefix] = uri - - def _onEndNamespace(self, prefix): - # Remove last element on the stack - if prefix is None: - self.defaultNsStack.pop() - -## class FileParser(ElementStream): -## def __init__(self): -## ElementStream.__init__(self) -## self.DocumentStartEvent = self.docStart -## self.ElementEvent = self.elem -## self.DocumentEndEvent = self.docEnd -## self.done = 0 - -## def docStart(self, elem): -## self.document = elem - -## def elem(self, elem): -## self.document.addChild(elem) - -## def docEnd(self): -## self.done = 1 - -## def parse(self, filename): -## for l in open(filename).readlines(): -## self.parser.Parse(l) -## assert self.done == 1 -## return self.document - -## def parseFile(filename): -## return FileParser().parse(filename) - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/utility.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/utility.py deleted file mode 100644 index 5c54095..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/utility.py +++ /dev/null @@ -1,372 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_xishutil -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Event Dispatching and Callback utilities. -""" - -from twisted.python import log -from twisted.words.xish import xpath - -class _MethodWrapper(object): - """ - Internal class for tracking method calls. - """ - def __init__(self, method, *args, **kwargs): - self.method = method - self.args = args - self.kwargs = kwargs - - - def __call__(self, *args, **kwargs): - nargs = self.args + args - nkwargs = self.kwargs.copy() - nkwargs.update(kwargs) - self.method(*nargs, **nkwargs) - - - -class CallbackList: - """ - Container for callbacks. - - Event queries are linked to lists of callables. When a matching event - occurs, these callables are called in sequence. One-time callbacks - are removed from the list after the first time the event was triggered. - - Arguments to callbacks are split spread across two sets. The first set, - callback specific, is passed to C{addCallback} and is used for all - subsequent event triggers. The second set is passed to C{callback} and is - event specific. Positional arguments in the second set come after the - positional arguments of the first set. Keyword arguments in the second set - override those in the first set. - - @ivar callbacks: The registered callbacks as mapping from the callable to a - tuple of a wrapper for that callable that keeps the - callback specific arguments and a boolean that signifies - if it is to be called only once. - @type callbacks: C{dict} - """ - - def __init__(self): - self.callbacks = {} - - - def addCallback(self, onetime, method, *args, **kwargs): - """ - Add callback. - - The arguments passed are used as callback specific arguments. - - @param onetime: If C{True}, this callback is called at most once. - @type onetime: C{bool} - @param method: The callback callable to be added. - @param args: Positional arguments to the callable. - @type args: C{list} - @param kwargs: Keyword arguments to the callable. - @type kwargs: C{dict} - """ - - if not method in self.callbacks: - self.callbacks[method] = (_MethodWrapper(method, *args, **kwargs), - onetime) - - - def removeCallback(self, method): - """ - Remove callback. - - @param method: The callable to be removed. - """ - - if method in self.callbacks: - del self.callbacks[method] - - - def callback(self, *args, **kwargs): - """ - Call all registered callbacks. - - The passed arguments are event specific and augment and override - the callback specific arguments as described above. - - @note: Exceptions raised by callbacks are trapped and logged. They will - not propagate up to make sure other callbacks will still be - called, and the event dispatching always succeeds. - - @param args: Positional arguments to the callable. - @type args: C{list} - @param kwargs: Keyword arguments to the callable. - @type kwargs: C{dict} - """ - - for key, (methodwrapper, onetime) in self.callbacks.items(): - try: - methodwrapper(*args, **kwargs) - except: - log.err() - - if onetime: - del self.callbacks[key] - - - def isEmpty(self): - """ - Return if list of registered callbacks is empty. - - @rtype: C{bool} - """ - - return len(self.callbacks) == 0 - - - -class EventDispatcher: - """ - Event dispatching service. - - The C{EventDispatcher} allows observers to be registered for certain events - that are dispatched. There are two types of events: XPath events and Named - events. - - Every dispatch is triggered by calling L{dispatch} with a data object and, - for named events, the name of the event. - - When an XPath type event is dispatched, the associated object is assumed to - be an L{Element<twisted.words.xish.domish.Element>} instance, which is - matched against all registered XPath queries. For every match, the - respective observer will be called with the data object. - - A named event will simply call each registered observer for that particular - event name, with the data object. Unlike XPath type events, the data object - is not restricted to L{Element<twisted.words.xish.domish.Element>}, but can - be anything. - - When registering observers, the event that is to be observed is specified - using an L{xpath.XPathQuery} instance or a string. In the latter case, the - string can also contain the string representation of an XPath expression. - To distinguish these from named events, each named event should start with - a special prefix that is stored in C{self.prefix}. It defaults to - C{//event/}. - - Observers registered using L{addObserver} are persistent: after the - observer has been triggered by a dispatch, it remains registered for a - possible next dispatch. If instead L{addOnetimeObserver} was used to - observe an event, the observer is removed from the list of observers after - the first observed event. - - Observers can also be prioritized, by providing an optional C{priority} - parameter to the L{addObserver} and L{addOnetimeObserver} methods. Higher - priority observers are then called before lower priority observers. - - Finally, observers can be unregistered by using L{removeObserver}. - """ - - def __init__(self, eventprefix="//event/"): - self.prefix = eventprefix - self._eventObservers = {} - self._xpathObservers = {} - self._dispatchDepth = 0 # Flag indicating levels of dispatching - # in progress - self._updateQueue = [] # Queued updates for observer ops - - - def _getEventAndObservers(self, event): - if isinstance(event, xpath.XPathQuery): - # Treat as xpath - observers = self._xpathObservers - else: - if self.prefix == event[:len(self.prefix)]: - # Treat as event - observers = self._eventObservers - else: - # Treat as xpath - event = xpath.internQuery(event) - observers = self._xpathObservers - - return event, observers - - - def addOnetimeObserver(self, event, observerfn, priority=0, *args, **kwargs): - """ - Register a one-time observer for an event. - - Like L{addObserver}, but is only triggered at most once. See there - for a description of the parameters. - """ - self._addObserver(True, event, observerfn, priority, *args, **kwargs) - - - def addObserver(self, event, observerfn, priority=0, *args, **kwargs): - """ - Register an observer for an event. - - Each observer will be registered with a certain priority. Higher - priority observers get called before lower priority observers. - - @param event: Name or XPath query for the event to be monitored. - @type event: C{str} or L{xpath.XPathQuery}. - @param observerfn: Function to be called when the specified event - has been triggered. This callable takes - one parameter: the data object that triggered - the event. When specified, the C{*args} and - C{**kwargs} parameters to addObserver are being used - as additional parameters to the registered observer - callable. - @param priority: (Optional) priority of this observer in relation to - other observer that match the same event. Defaults to - C{0}. - @type priority: C{int} - """ - self._addObserver(False, event, observerfn, priority, *args, **kwargs) - - - def _addObserver(self, onetime, event, observerfn, priority, *args, **kwargs): - # If this is happening in the middle of the dispatch, queue - # it up for processing after the dispatch completes - if self._dispatchDepth > 0: - self._updateQueue.append(lambda:self._addObserver(onetime, event, observerfn, priority, *args, **kwargs)) - return - - event, observers = self._getEventAndObservers(event) - - if priority not in observers: - cbl = CallbackList() - observers[priority] = {event: cbl} - else: - priorityObservers = observers[priority] - if event not in priorityObservers: - cbl = CallbackList() - observers[priority][event] = cbl - else: - cbl = priorityObservers[event] - - cbl.addCallback(onetime, observerfn, *args, **kwargs) - - - def removeObserver(self, event, observerfn): - """ - Remove callable as observer for an event. - - The observer callable is removed for all priority levels for the - specified event. - - @param event: Event for which the observer callable was registered. - @type event: C{str} or L{xpath.XPathQuery} - @param observerfn: Observer callable to be unregistered. - """ - - # If this is happening in the middle of the dispatch, queue - # it up for processing after the dispatch completes - if self._dispatchDepth > 0: - self._updateQueue.append(lambda:self.removeObserver(event, observerfn)) - return - - event, observers = self._getEventAndObservers(event) - - emptyLists = [] - for priority, priorityObservers in observers.iteritems(): - for query, callbacklist in priorityObservers.iteritems(): - if event == query: - callbacklist.removeCallback(observerfn) - if callbacklist.isEmpty(): - emptyLists.append((priority, query)) - - for priority, query in emptyLists: - del observers[priority][query] - - - def dispatch(self, obj, event=None): - """ - Dispatch an event. - - When C{event} is C{None}, an XPath type event is triggered, and - C{obj} is assumed to be an instance of - L{Element<twisted.words.xish.domish.Element>}. Otherwise, C{event} - holds the name of the named event being triggered. In the latter case, - C{obj} can be anything. - - @param obj: The object to be dispatched. - @param event: Optional event name. - @type event: C{str} - """ - - foundTarget = False - - self._dispatchDepth += 1 - - if event != None: - # Named event - observers = self._eventObservers - match = lambda query, obj: query == event - else: - # XPath event - observers = self._xpathObservers - match = lambda query, obj: query.matches(obj) - - priorities = observers.keys() - priorities.sort() - priorities.reverse() - - emptyLists = [] - for priority in priorities: - for query, callbacklist in observers[priority].iteritems(): - if match(query, obj): - callbacklist.callback(obj) - foundTarget = True - if callbacklist.isEmpty(): - emptyLists.append((priority, query)) - - for priority, query in emptyLists: - del observers[priority][query] - - self._dispatchDepth -= 1 - - # If this is a dispatch within a dispatch, don't - # do anything with the updateQueue -- it needs to - # wait until we've back all the way out of the stack - if self._dispatchDepth == 0: - # Deal with pending update operations - for f in self._updateQueue: - f() - self._updateQueue = [] - - return foundTarget - - - -class XmlPipe(object): - """ - XML stream pipe. - - Connects two objects that communicate stanzas through an XML stream like - interface. Each of the ends of the pipe (sink and source) can be used to - send XML stanzas to the other side, or add observers to process XML stanzas - that were sent from the other side. - - XML pipes are usually used in place of regular XML streams that are - transported over TCP. This is the reason for the use of the names source - and sink for both ends of the pipe. The source side corresponds with the - entity that initiated the TCP connection, whereas the sink corresponds with - the entity that accepts that connection. In this object, though, the source - and sink are treated equally. - - Unlike Jabber - L{XmlStream<twisted.words.protocols.jabber.xmlstream.XmlStream>}s, the sink - and source objects are assumed to represent an eternal connected and - initialized XML stream. As such, events corresponding to connection, - disconnection, initialization and stream errors are not dispatched or - processed. - - @since: 8.2 - @ivar source: Source XML stream. - @ivar sink: Sink XML stream. - """ - - def __init__(self): - self.source = EventDispatcher() - self.sink = EventDispatcher() - self.source.send = lambda obj: self.sink.dispatch(obj) - self.sink.send = lambda obj: self.source.dispatch(obj) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xmlstream.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xmlstream.py deleted file mode 100644 index 3018a0e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xmlstream.py +++ /dev/null @@ -1,261 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_xmlstream -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XML Stream processing. - -An XML Stream is defined as a connection over which two XML documents are -exchanged during the lifetime of the connection, one for each direction. The -unit of interaction is a direct child element of the root element (stanza). - -The most prominent use of XML Streams is Jabber, but this module is generically -usable. See Twisted Words for Jabber specific protocol support. - -Maintainer: Ralph Meijer -""" - -from twisted.python import failure -from twisted.internet import protocol -from twisted.words.xish import domish, utility - -STREAM_CONNECTED_EVENT = intern("//event/stream/connected") -STREAM_START_EVENT = intern("//event/stream/start") -STREAM_END_EVENT = intern("//event/stream/end") -STREAM_ERROR_EVENT = intern("//event/stream/error") - -class XmlStream(protocol.Protocol, utility.EventDispatcher): - """ Generic Streaming XML protocol handler. - - This protocol handler will parse incoming data as XML and dispatch events - accordingly. Incoming stanzas can be handled by registering observers using - XPath-like expressions that are matched against each stanza. See - L{utility.EventDispatcher} for details. - """ - def __init__(self): - utility.EventDispatcher.__init__(self) - self.stream = None - self.rawDataOutFn = None - self.rawDataInFn = None - - def _initializeStream(self): - """ Sets up XML Parser. """ - self.stream = domish.elementStream() - self.stream.DocumentStartEvent = self.onDocumentStart - self.stream.ElementEvent = self.onElement - self.stream.DocumentEndEvent = self.onDocumentEnd - - ### -------------------------------------------------------------- - ### - ### Protocol events - ### - ### -------------------------------------------------------------- - - def connectionMade(self): - """ Called when a connection is made. - - Sets up the XML parser and dispatches the L{STREAM_CONNECTED_EVENT} - event indicating the connection has been established. - """ - self._initializeStream() - self.dispatch(self, STREAM_CONNECTED_EVENT) - - def dataReceived(self, data): - """ Called whenever data is received. - - Passes the data to the XML parser. This can result in calls to the - DOM handlers. If a parse error occurs, the L{STREAM_ERROR_EVENT} event - is called to allow for cleanup actions, followed by dropping the - connection. - """ - try: - if self.rawDataInFn: - self.rawDataInFn(data) - self.stream.parse(data) - except domish.ParserError: - self.dispatch(failure.Failure(), STREAM_ERROR_EVENT) - self.transport.loseConnection() - - def connectionLost(self, reason): - """ Called when the connection is shut down. - - Dispatches the L{STREAM_END_EVENT}. - """ - self.dispatch(reason, STREAM_END_EVENT) - self.stream = None - - ### -------------------------------------------------------------- - ### - ### DOM events - ### - ### -------------------------------------------------------------- - - def onDocumentStart(self, rootElement): - """ Called whenever the start tag of a root element has been received. - - Dispatches the L{STREAM_START_EVENT}. - """ - self.dispatch(self, STREAM_START_EVENT) - - def onElement(self, element): - """ Called whenever a direct child element of the root element has - been received. - - Dispatches the received element. - """ - self.dispatch(element) - - def onDocumentEnd(self): - """ Called whenever the end tag of the root element has been received. - - Closes the connection. This causes C{connectionLost} being called. - """ - self.transport.loseConnection() - - def setDispatchFn(self, fn): - """ Set another function to handle elements. """ - self.stream.ElementEvent = fn - - def resetDispatchFn(self): - """ Set the default function (C{onElement}) to handle elements. """ - self.stream.ElementEvent = self.onElement - - def send(self, obj): - """ Send data over the stream. - - Sends the given C{obj} over the connection. C{obj} may be instances of - L{domish.Element}, C{unicode} and C{str}. The first two will be - properly serialized and/or encoded. C{str} objects must be in UTF-8 - encoding. - - Note: because it is easy to make mistakes in maintaining a properly - encoded C{str} object, it is advised to use C{unicode} objects - everywhere when dealing with XML Streams. - - @param obj: Object to be sent over the stream. - @type obj: L{domish.Element}, L{domish} or C{str} - - """ - if domish.IElement.providedBy(obj): - obj = obj.toXml() - - if isinstance(obj, unicode): - obj = obj.encode('utf-8') - - if self.rawDataOutFn: - self.rawDataOutFn(obj) - - self.transport.write(obj) - - - -class BootstrapMixin(object): - """ - XmlStream factory mixin to install bootstrap event observers. - - This mixin is for factories providing - L{IProtocolFactory<twisted.internet.interfaces.IProtocolFactory>} to make - sure bootstrap event observers are set up on protocols, before incoming - data is processed. Such protocols typically derive from - L{utility.EventDispatcher}, like L{XmlStream}. - - You can set up bootstrap event observers using C{addBootstrap}. The - C{event} and C{fn} parameters correspond with the C{event} and - C{observerfn} arguments to L{utility.EventDispatcher.addObserver}. - - @since: 8.2. - @ivar bootstraps: The list of registered bootstrap event observers. - @type bootstrap: C{list} - """ - - def __init__(self): - self.bootstraps = [] - - - def installBootstraps(self, dispatcher): - """ - Install registered bootstrap observers. - - @param dispatcher: Event dispatcher to add the observers to. - @type dispatcher: L{utility.EventDispatcher} - """ - for event, fn in self.bootstraps: - dispatcher.addObserver(event, fn) - - - def addBootstrap(self, event, fn): - """ - Add a bootstrap event handler. - - @param event: The event to register an observer for. - @type event: C{str} or L{xpath.XPathQuery} - @param fn: The observer callable to be registered. - """ - self.bootstraps.append((event, fn)) - - - def removeBootstrap(self, event, fn): - """ - Remove a bootstrap event handler. - - @param event: The event the observer is registered for. - @type event: C{str} or L{xpath.XPathQuery} - @param fn: The registered observer callable. - """ - self.bootstraps.remove((event, fn)) - - - -class XmlStreamFactoryMixin(BootstrapMixin): - """ - XmlStream factory mixin that takes care of event handlers. - - All positional and keyword arguments passed to create this factory are - passed on as-is to the protocol. - - @ivar args: Positional arguments passed to the protocol upon instantiation. - @type args: C{tuple}. - @ivar kwargs: Keyword arguments passed to the protocol upon instantiation. - @type kwargs: C{dict}. - """ - - def __init__(self, *args, **kwargs): - BootstrapMixin.__init__(self) - self.args = args - self.kwargs = kwargs - - - def buildProtocol(self, addr): - """ - Create an instance of XmlStream. - - The returned instance will have bootstrap event observers registered - and will proceed to handle input on an incoming connection. - """ - xs = self.protocol(*self.args, **self.kwargs) - xs.factory = self - self.installBootstraps(xs) - return xs - - - -class XmlStreamFactory(XmlStreamFactoryMixin, - protocol.ReconnectingClientFactory): - """ - Factory for XmlStream protocol objects as a reconnection client. - """ - - protocol = XmlStream - - def buildProtocol(self, addr): - """ - Create a protocol instance. - - Overrides L{XmlStreamFactoryMixin.buildProtocol} to work with - a L{ReconnectingClientFactory}. As this is called upon having an - connection established, we are resetting the delay for reconnection - attempts when the connection is lost again. - """ - self.resetDelay() - return XmlStreamFactoryMixin.buildProtocol(self, addr) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpath.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpath.py deleted file mode 100644 index bf5b529..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpath.py +++ /dev/null @@ -1,333 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_xpath -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XPath query support. - -This module provides L{XPathQuery} to match -L{domish.Element<twisted.words.xish.domish.Element>} instances against -XPath-like expressions. -""" - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -class LiteralValue(str): - def value(self, elem): - return self - - -class IndexValue: - def __init__(self, index): - self.index = int(index) - 1 - - def value(self, elem): - return elem.children[self.index] - - -class AttribValue: - def __init__(self, attribname): - self.attribname = attribname - if self.attribname == "xmlns": - self.value = self.value_ns - - def value_ns(self, elem): - return elem.uri - - def value(self, elem): - if self.attribname in elem.attributes: - return elem.attributes[self.attribname] - else: - return None - - -class CompareValue: - def __init__(self, lhs, op, rhs): - self.lhs = lhs - self.rhs = rhs - if op == "=": - self.value = self._compareEqual - else: - self.value = self._compareNotEqual - - def _compareEqual(self, elem): - return self.lhs.value(elem) == self.rhs.value(elem) - - def _compareNotEqual(self, elem): - return self.lhs.value(elem) != self.rhs.value(elem) - - -class BooleanValue: - """ - Provide boolean XPath expression operators. - - @ivar lhs: Left hand side expression of the operator. - @ivar op: The operator. One of C{'and'}, C{'or'}. - @ivar rhs: Right hand side expression of the operator. - @ivar value: Reference to the method that will calculate the value of - this expression given an element. - """ - def __init__(self, lhs, op, rhs): - self.lhs = lhs - self.rhs = rhs - if op == "and": - self.value = self._booleanAnd - else: - self.value = self._booleanOr - - def _booleanAnd(self, elem): - """ - Calculate boolean and of the given expressions given an element. - - @param elem: The element to calculate the value of the expression from. - """ - return self.lhs.value(elem) and self.rhs.value(elem) - - def _booleanOr(self, elem): - """ - Calculate boolean or of the given expressions given an element. - - @param elem: The element to calculate the value of the expression from. - """ - return self.lhs.value(elem) or self.rhs.value(elem) - - -def Function(fname): - """ - Internal method which selects the function object - """ - klassname = "_%s_Function" % fname - c = globals()[klassname]() - return c - - -class _not_Function: - def __init__(self): - self.baseValue = None - - def setParams(self, baseValue): - self.baseValue = baseValue - - def value(self, elem): - return not self.baseValue.value(elem) - - -class _text_Function: - def setParams(self): - pass - - def value(self, elem): - return str(elem) - - -class _Location: - def __init__(self): - self.predicates = [] - self.elementName = None - self.childLocation = None - - def matchesPredicates(self, elem): - if self.elementName != None and self.elementName != elem.name: - return 0 - - for p in self.predicates: - if not p.value(elem): - return 0 - - return 1 - - def matches(self, elem): - if not self.matchesPredicates(elem): - return 0 - - if self.childLocation != None: - for c in elem.elements(): - if self.childLocation.matches(c): - return 1 - else: - return 1 - - return 0 - - def queryForString(self, elem, resultbuf): - if not self.matchesPredicates(elem): - return - - if self.childLocation != None: - for c in elem.elements(): - self.childLocation.queryForString(c, resultbuf) - else: - resultbuf.write(str(elem)) - - def queryForNodes(self, elem, resultlist): - if not self.matchesPredicates(elem): - return - - if self.childLocation != None: - for c in elem.elements(): - self.childLocation.queryForNodes(c, resultlist) - else: - resultlist.append(elem) - - def queryForStringList(self, elem, resultlist): - if not self.matchesPredicates(elem): - return - - if self.childLocation != None: - for c in elem.elements(): - self.childLocation.queryForStringList(c, resultlist) - else: - for c in elem.children: - if isinstance(c, (str, unicode)): - resultlist.append(c) - - -class _AnyLocation: - def __init__(self): - self.predicates = [] - self.elementName = None - self.childLocation = None - - def matchesPredicates(self, elem): - for p in self.predicates: - if not p.value(elem): - return 0 - return 1 - - def listParents(self, elem, parentlist): - if elem.parent != None: - self.listParents(elem.parent, parentlist) - parentlist.append(elem.name) - - def isRootMatch(self, elem): - if (self.elementName == None or self.elementName == elem.name) and \ - self.matchesPredicates(elem): - if self.childLocation != None: - for c in elem.elements(): - if self.childLocation.matches(c): - return True - else: - return True - return False - - def findFirstRootMatch(self, elem): - if (self.elementName == None or self.elementName == elem.name) and \ - self.matchesPredicates(elem): - # Thus far, the name matches and the predicates match, - # now check into the children and find the first one - # that matches the rest of the structure - # the rest of the structure - if self.childLocation != None: - for c in elem.elements(): - if self.childLocation.matches(c): - return c - return None - else: - # No children locations; this is a match! - return elem - else: - # Ok, predicates or name didn't match, so we need to start - # down each child and treat it as the root and try - # again - for c in elem.elements(): - if self.matches(c): - return c - # No children matched... - return None - - def matches(self, elem): - if self.isRootMatch(elem): - return True - else: - # Ok, initial element isn't an exact match, walk - # down each child and treat it as the root and try - # again - for c in elem.elements(): - if self.matches(c): - return True - # No children matched... - return False - - def queryForString(self, elem, resultbuf): - raise NotImplementedError( - "queryForString is not implemented for any location") - - def queryForNodes(self, elem, resultlist): - # First check to see if _this_ element is a root - if self.isRootMatch(elem): - resultlist.append(elem) - - # Now check each child - for c in elem.elements(): - self.queryForNodes(c, resultlist) - - - def queryForStringList(self, elem, resultlist): - if self.isRootMatch(elem): - for c in elem.children: - if isinstance(c, (str, unicode)): - resultlist.append(c) - for c in elem.elements(): - self.queryForStringList(c, resultlist) - - -class XPathQuery: - def __init__(self, queryStr): - self.queryStr = queryStr - from twisted.words.xish.xpathparser import parse - self.baseLocation = parse('XPATH', queryStr) - - def __hash__(self): - return self.queryStr.__hash__() - - def matches(self, elem): - return self.baseLocation.matches(elem) - - def queryForString(self, elem): - result = StringIO.StringIO() - self.baseLocation.queryForString(elem, result) - return result.getvalue() - - def queryForNodes(self, elem): - result = [] - self.baseLocation.queryForNodes(elem, result) - if len(result) == 0: - return None - else: - return result - - def queryForStringList(self, elem): - result = [] - self.baseLocation.queryForStringList(elem, result) - if len(result) == 0: - return None - else: - return result - - -__internedQueries = {} - -def internQuery(queryString): - if queryString not in __internedQueries: - __internedQueries[queryString] = XPathQuery(queryString) - return __internedQueries[queryString] - - -def matches(xpathstr, elem): - return internQuery(xpathstr).matches(elem) - - -def queryForStringList(xpathstr, elem): - return internQuery(xpathstr).queryForStringList(elem) - - -def queryForString(xpathstr, elem): - return internQuery(xpathstr).queryForString(elem) - - -def queryForNodes(xpathstr, elem): - return internQuery(xpathstr).queryForNodes(elem) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpathparser.g b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpathparser.g deleted file mode 100644 index 02c67c9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpathparser.g +++ /dev/null @@ -1,375 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# DO NOT EDIT xpathparser.py! -# -# It is generated from xpathparser.g using Yapps. Make needed changes there. -# This also means that the generated Python may not conform to Twisted's coding -# standards. - -# HOWTO Generate me: -# -# 1.) Grab a copy of yapps2, version 2.1.1: -# http://theory.stanford.edu/~amitp/Yapps/ -# -# Note: Do NOT use the package in debian/ubuntu as it has incompatible -# modifications. -# -# 2.) Generate the grammar: -# -# yapps2 xpathparser.g xpathparser.py.proto -# -# 3.) Edit the output to depend on the embedded runtime, not yappsrt. -# -# sed -e '/^import yapps/d' -e '/^[^#]/s/yappsrt\.//g' \ -# xpathparser.py.proto > xpathparser.py - -""" -XPath Parser. - -Besides the parser code produced by Yapps, this module also defines the -parse-time exception classes, a scanner class, a base class for parsers -produced by Yapps, and a context class that keeps track of the parse stack. -These have been copied from the Yapps runtime. -""" - -import sys, re - -class SyntaxError(Exception): - """When we run into an unexpected token, this is the exception to use""" - def __init__(self, charpos=-1, msg="Bad Token", context=None): - Exception.__init__(self) - self.charpos = charpos - self.msg = msg - self.context = context - - def __str__(self): - if self.charpos < 0: return 'SyntaxError' - else: return 'SyntaxError@char%s(%s)' % (repr(self.charpos), self.msg) - -class NoMoreTokens(Exception): - """Another exception object, for when we run out of tokens""" - pass - -class Scanner: - """Yapps scanner. - - The Yapps scanner can work in context sensitive or context - insensitive modes. The token(i) method is used to retrieve the - i-th token. It takes a restrict set that limits the set of tokens - it is allowed to return. In context sensitive mode, this restrict - set guides the scanner. In context insensitive mode, there is no - restriction (the set is always the full set of tokens). - - """ - - def __init__(self, patterns, ignore, input): - """Initialize the scanner. - - @param patterns: [(terminal, uncompiled regex), ...] or C{None} - @param ignore: [terminal,...] - @param input: string - - If patterns is C{None}, we assume that the subclass has defined - C{self.patterns} : [(terminal, compiled regex), ...]. Note that the - patterns parameter expects uncompiled regexes, whereas the - C{self.patterns} field expects compiled regexes. - """ - self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...] - self.restrictions = [] - self.input = input - self.pos = 0 - self.ignore = ignore - self.first_line_number = 1 - - if patterns is not None: - # Compile the regex strings into regex objects - self.patterns = [] - for terminal, regex in patterns: - self.patterns.append( (terminal, re.compile(regex)) ) - - def get_token_pos(self): - """Get the current token position in the input text.""" - return len(self.tokens) - - def get_char_pos(self): - """Get the current char position in the input text.""" - return self.pos - - def get_prev_char_pos(self, i=None): - """Get the previous position (one token back) in the input text.""" - if self.pos == 0: return 0 - if i is None: i = -1 - return self.tokens[i][0] - - def get_line_number(self): - """Get the line number of the current position in the input text.""" - # TODO: make this work at any token/char position - return self.first_line_number + self.get_input_scanned().count('\n') - - def get_column_number(self): - """Get the column number of the current position in the input text.""" - s = self.get_input_scanned() - i = s.rfind('\n') # may be -1, but that's okay in this case - return len(s) - (i+1) - - def get_input_scanned(self): - """Get the portion of the input that has been tokenized.""" - return self.input[:self.pos] - - def get_input_unscanned(self): - """Get the portion of the input that has not yet been tokenized.""" - return self.input[self.pos:] - - def token(self, i, restrict=None): - """Get the i'th token in the input. - - If C{i} is one past the end, then scan for another token. - - @param i: token index - - @param restrict: [token, ...] or C{None}; if restrict is - C{None}, then any token is allowed. You may call - token(i) more than once. However, the restrict set - may never be larger than what was passed in on the - first call to token(i). - """ - if i == len(self.tokens): - self.scan(restrict) - if i < len(self.tokens): - # Make sure the restriction is more restricted. This - # invariant is needed to avoid ruining tokenization at - # position i+1 and higher. - if restrict and self.restrictions[i]: - for r in restrict: - if r not in self.restrictions[i]: - raise NotImplementedError("Unimplemented: restriction set changed") - return self.tokens[i] - raise NoMoreTokens() - - def __repr__(self): - """Print the last 10 tokens that have been scanned in""" - output = '' - for t in self.tokens[-10:]: - output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3])) - return output - - def scan(self, restrict): - """Should scan another token and add it to the list, self.tokens, - and add the restriction to self.restrictions""" - # Keep looking for a token, ignoring any in self.ignore - while 1: - # Search the patterns for the longest match, with earlier - # tokens in the list having preference - best_match = -1 - best_pat = '(error)' - for p, regexp in self.patterns: - # First check to see if we're ignoring this token - if restrict and p not in restrict and p not in self.ignore: - continue - m = regexp.match(self.input, self.pos) - if m and len(m.group(0)) > best_match: - # We got a match that's better than the previous one - best_pat = p - best_match = len(m.group(0)) - - # If we didn't find anything, raise an error - if best_pat == '(error)' and best_match < 0: - msg = 'Bad Token' - if restrict: - msg = 'Trying to find one of '+', '.join(restrict) - raise SyntaxError(self.pos, msg) - - # If we found something that isn't to be ignored, return it - if best_pat not in self.ignore: - # Create a token with this data - token = (self.pos, self.pos+best_match, best_pat, - self.input[self.pos:self.pos+best_match]) - self.pos = self.pos + best_match - # Only add this token if it's not in the list - # (to prevent looping) - if not self.tokens or token != self.tokens[-1]: - self.tokens.append(token) - self.restrictions.append(restrict) - return - else: - # This token should be ignored .. - self.pos = self.pos + best_match - -class Parser: - """Base class for Yapps-generated parsers. - - """ - - def __init__(self, scanner): - self._scanner = scanner - self._pos = 0 - - def _peek(self, *types): - """Returns the token type for lookahead; if there are any args - then the list of args is the set of token types to allow""" - tok = self._scanner.token(self._pos, types) - return tok[2] - - def _scan(self, type): - """Returns the matched text, and moves to the next token""" - tok = self._scanner.token(self._pos, [type]) - if tok[2] != type: - raise SyntaxError(tok[0], 'Trying to find '+type+' :'+ ' ,'.join(self._scanner.restrictions[self._pos])) - self._pos = 1 + self._pos - return tok[3] - -class Context: - """Class to represent the parser's call stack. - - Every rule creates a Context that links to its parent rule. The - contexts can be used for debugging. - - """ - - def __init__(self, parent, scanner, tokenpos, rule, args=()): - """Create a new context. - - @param parent: Context object or C{None} - @param scanner: Scanner object - @param tokenpos: scanner token position - @type tokenpos: C{int} - @param rule: name of the rule - @type rule: C{str} - @param args: tuple listing parameters to the rule - - """ - self.parent = parent - self.scanner = scanner - self.tokenpos = tokenpos - self.rule = rule - self.args = args - - def __str__(self): - output = '' - if self.parent: output = str(self.parent) + ' > ' - output += self.rule - return output - -def print_line_with_pointer(text, p): - """Print the line of 'text' that includes position 'p', - along with a second line with a single caret (^) at position p""" - - # TODO: separate out the logic for determining the line/character - # location from the logic for determining how to display an - # 80-column line to stderr. - - # Now try printing part of the line - text = text[max(p-80, 0):p+80] - p = p - max(p-80, 0) - - # Strip to the left - i = text[:p].rfind('\n') - j = text[:p].rfind('\r') - if i < 0 or (0 <= j < i): i = j - if 0 <= i < p: - p = p - i - 1 - text = text[i+1:] - - # Strip to the right - i = text.find('\n', p) - j = text.find('\r', p) - if i < 0 or (0 <= j < i): i = j - if i >= 0: - text = text[:i] - - # Now shorten the text - while len(text) > 70 and p > 60: - # Cut off 10 chars - text = "..." + text[10:] - p = p - 7 - - # Now print the string, along with an indicator - print >>sys.stderr, '> ',text - print >>sys.stderr, '> ',' '*p + '^' - -def print_error(input, err, scanner): - """Print error messages, the parser stack, and the input text -- for human-readable error messages.""" - # NOTE: this function assumes 80 columns :-( - # Figure out the line number - line_number = scanner.get_line_number() - column_number = scanner.get_column_number() - print >>sys.stderr, '%d:%d: %s' % (line_number, column_number, err.msg) - - context = err.context - if not context: - print_line_with_pointer(input, err.charpos) - - while context: - # TODO: add line number - print >>sys.stderr, 'while parsing %s%s:' % (context.rule, tuple(context.args)) - print_line_with_pointer(input, context.scanner.get_prev_char_pos(context.tokenpos)) - context = context.parent - -def wrap_error_reporter(parser, rule): - try: - return getattr(parser, rule)() - except SyntaxError, e: - input = parser._scanner.input - print_error(input, e, parser._scanner) - except NoMoreTokens: - print >>sys.stderr, 'Could not complete parsing; stopped around here:' - print >>sys.stderr, parser._scanner - - -from twisted.words.xish.xpath import AttribValue, BooleanValue, CompareValue -from twisted.words.xish.xpath import Function, IndexValue, LiteralValue -from twisted.words.xish.xpath import _AnyLocation, _Location - -%% -parser XPathParser: - ignore: "\\s+" - token INDEX: "[0-9]+" - token WILDCARD: "\*" - token IDENTIFIER: "[a-zA-Z][a-zA-Z0-9_\-]*" - token ATTRIBUTE: "\@[a-zA-Z][a-zA-Z0-9_\-]*" - token FUNCNAME: "[a-zA-Z][a-zA-Z0-9_]*" - token CMP_EQ: "\=" - token CMP_NE: "\!\=" - token STR_DQ: '"([^"]|(\\"))*?"' - token STR_SQ: "'([^']|(\\'))*?'" - token OP_AND: "and" - token OP_OR: "or" - token END: "$" - - rule XPATH: PATH {{ result = PATH; current = result }} - ( PATH {{ current.childLocation = PATH; current = current.childLocation }} ) * END - {{ return result }} - - rule PATH: ("/" {{ result = _Location() }} | "//" {{ result = _AnyLocation() }} ) - ( IDENTIFIER {{ result.elementName = IDENTIFIER }} | WILDCARD {{ result.elementName = None }} ) - ( "\[" PREDICATE {{ result.predicates.append(PREDICATE) }} "\]")* - {{ return result }} - - rule PREDICATE: EXPR {{ return EXPR }} | - INDEX {{ return IndexValue(INDEX) }} - - rule EXPR: FACTOR {{ e = FACTOR }} - ( BOOLOP FACTOR {{ e = BooleanValue(e, BOOLOP, FACTOR) }} )* - {{ return e }} - - rule BOOLOP: ( OP_AND {{ return OP_AND }} | OP_OR {{ return OP_OR }} ) - - rule FACTOR: TERM {{ return TERM }} - | "\(" EXPR "\)" {{ return EXPR }} - - rule TERM: VALUE {{ t = VALUE }} - [ CMP VALUE {{ t = CompareValue(t, CMP, VALUE) }} ] - {{ return t }} - - rule VALUE: "@" IDENTIFIER {{ return AttribValue(IDENTIFIER) }} | - FUNCNAME {{ f = Function(FUNCNAME); args = [] }} - "\(" [ VALUE {{ args.append(VALUE) }} - ( - "," VALUE {{ args.append(VALUE) }} - )* - ] "\)" {{ f.setParams(*args); return f }} | - STR {{ return LiteralValue(STR[1:len(STR)-1]) }} - - rule CMP: (CMP_EQ {{ return CMP_EQ }} | CMP_NE {{ return CMP_NE }}) - rule STR: (STR_DQ {{ return STR_DQ }} | STR_SQ {{ return STR_SQ }}) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpathparser.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpathparser.py deleted file mode 100644 index 312f6ec..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xish/xpathparser.py +++ /dev/null @@ -1,508 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# DO NOT EDIT xpathparser.py! -# -# It is generated from xpathparser.g using Yapps. Make needed changes there. -# This also means that the generated Python may not conform to Twisted's coding -# standards. - -# HOWTO Generate me: -# -# 1.) Grab a copy of yapps2, version 2.1.1: -# http://theory.stanford.edu/~amitp/Yapps/ -# -# Note: Do NOT use the package in debian/ubuntu as it has incompatible -# modifications. -# -# 2.) Generate the grammar: -# -# yapps2 xpathparser.g xpathparser.py.proto -# -# 3.) Edit the output to depend on the embedded runtime, not yappsrt. -# -# sed -e '/^import yapps/d' -e '/^[^#]/s/yappsrt\.//g' \ -# xpathparser.py.proto > xpathparser.py - -""" -XPath Parser. - -Besides the parser code produced by Yapps, this module also defines the -parse-time exception classes, a scanner class, a base class for parsers -produced by Yapps, and a context class that keeps track of the parse stack. -These have been copied from the Yapps runtime. -""" - -import sys, re - -class SyntaxError(Exception): - """When we run into an unexpected token, this is the exception to use""" - def __init__(self, charpos=-1, msg="Bad Token", context=None): - Exception.__init__(self) - self.charpos = charpos - self.msg = msg - self.context = context - - def __str__(self): - if self.charpos < 0: return 'SyntaxError' - else: return 'SyntaxError@char%s(%s)' % (repr(self.charpos), self.msg) - -class NoMoreTokens(Exception): - """Another exception object, for when we run out of tokens""" - pass - -class Scanner: - """Yapps scanner. - - The Yapps scanner can work in context sensitive or context - insensitive modes. The token(i) method is used to retrieve the - i-th token. It takes a restrict set that limits the set of tokens - it is allowed to return. In context sensitive mode, this restrict - set guides the scanner. In context insensitive mode, there is no - restriction (the set is always the full set of tokens). - - """ - - def __init__(self, patterns, ignore, input): - """Initialize the scanner. - - @param patterns: [(terminal, uncompiled regex), ...] or C{None} - @param ignore: [terminal,...] - @param input: string - - If patterns is C{None}, we assume that the subclass has defined - C{self.patterns} : [(terminal, compiled regex), ...]. Note that the - patterns parameter expects uncompiled regexes, whereas the - C{self.patterns} field expects compiled regexes. - """ - self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...] - self.restrictions = [] - self.input = input - self.pos = 0 - self.ignore = ignore - self.first_line_number = 1 - - if patterns is not None: - # Compile the regex strings into regex objects - self.patterns = [] - for terminal, regex in patterns: - self.patterns.append( (terminal, re.compile(regex)) ) - - def get_token_pos(self): - """Get the current token position in the input text.""" - return len(self.tokens) - - def get_char_pos(self): - """Get the current char position in the input text.""" - return self.pos - - def get_prev_char_pos(self, i=None): - """Get the previous position (one token back) in the input text.""" - if self.pos == 0: return 0 - if i is None: i = -1 - return self.tokens[i][0] - - def get_line_number(self): - """Get the line number of the current position in the input text.""" - # TODO: make this work at any token/char position - return self.first_line_number + self.get_input_scanned().count('\n') - - def get_column_number(self): - """Get the column number of the current position in the input text.""" - s = self.get_input_scanned() - i = s.rfind('\n') # may be -1, but that's okay in this case - return len(s) - (i+1) - - def get_input_scanned(self): - """Get the portion of the input that has been tokenized.""" - return self.input[:self.pos] - - def get_input_unscanned(self): - """Get the portion of the input that has not yet been tokenized.""" - return self.input[self.pos:] - - def token(self, i, restrict=None): - """Get the i'th token in the input. - - If C{i} is one past the end, then scan for another token. - - @param i: token index - - @param restrict: [token, ...] or C{None}; if restrict is - C{None}, then any token is allowed. You may call - token(i) more than once. However, the restrict set - may never be larger than what was passed in on the - first call to token(i). - """ - if i == len(self.tokens): - self.scan(restrict) - if i < len(self.tokens): - # Make sure the restriction is more restricted. This - # invariant is needed to avoid ruining tokenization at - # position i+1 and higher. - if restrict and self.restrictions[i]: - for r in restrict: - if r not in self.restrictions[i]: - raise NotImplementedError("Unimplemented: restriction set changed") - return self.tokens[i] - raise NoMoreTokens() - - def __repr__(self): - """Print the last 10 tokens that have been scanned in""" - output = '' - for t in self.tokens[-10:]: - output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3])) - return output - - def scan(self, restrict): - """Should scan another token and add it to the list, self.tokens, - and add the restriction to self.restrictions""" - # Keep looking for a token, ignoring any in self.ignore - while 1: - # Search the patterns for the longest match, with earlier - # tokens in the list having preference - best_match = -1 - best_pat = '(error)' - for p, regexp in self.patterns: - # First check to see if we're ignoring this token - if restrict and p not in restrict and p not in self.ignore: - continue - m = regexp.match(self.input, self.pos) - if m and len(m.group(0)) > best_match: - # We got a match that's better than the previous one - best_pat = p - best_match = len(m.group(0)) - - # If we didn't find anything, raise an error - if best_pat == '(error)' and best_match < 0: - msg = 'Bad Token' - if restrict: - msg = 'Trying to find one of '+', '.join(restrict) - raise SyntaxError(self.pos, msg) - - # If we found something that isn't to be ignored, return it - if best_pat not in self.ignore: - # Create a token with this data - token = (self.pos, self.pos+best_match, best_pat, - self.input[self.pos:self.pos+best_match]) - self.pos = self.pos + best_match - # Only add this token if it's not in the list - # (to prevent looping) - if not self.tokens or token != self.tokens[-1]: - self.tokens.append(token) - self.restrictions.append(restrict) - return - else: - # This token should be ignored .. - self.pos = self.pos + best_match - -class Parser: - """Base class for Yapps-generated parsers. - - """ - - def __init__(self, scanner): - self._scanner = scanner - self._pos = 0 - - def _peek(self, *types): - """Returns the token type for lookahead; if there are any args - then the list of args is the set of token types to allow""" - tok = self._scanner.token(self._pos, types) - return tok[2] - - def _scan(self, type): - """Returns the matched text, and moves to the next token""" - tok = self._scanner.token(self._pos, [type]) - if tok[2] != type: - raise SyntaxError(tok[0], 'Trying to find '+type+' :'+ ' ,'.join(self._scanner.restrictions[self._pos])) - self._pos = 1 + self._pos - return tok[3] - -class Context: - """Class to represent the parser's call stack. - - Every rule creates a Context that links to its parent rule. The - contexts can be used for debugging. - - """ - - def __init__(self, parent, scanner, tokenpos, rule, args=()): - """Create a new context. - - @param parent: Context object or C{None} - @param scanner: Scanner object - @param tokenpos: scanner token position - @type tokenpos: C{int} - @param rule: name of the rule - @type rule: C{str} - @param args: tuple listing parameters to the rule - - """ - self.parent = parent - self.scanner = scanner - self.tokenpos = tokenpos - self.rule = rule - self.args = args - - def __str__(self): - output = '' - if self.parent: output = str(self.parent) + ' > ' - output += self.rule - return output - -def print_line_with_pointer(text, p): - """Print the line of 'text' that includes position 'p', - along with a second line with a single caret (^) at position p""" - - # TODO: separate out the logic for determining the line/character - # location from the logic for determining how to display an - # 80-column line to stderr. - - # Now try printing part of the line - text = text[max(p-80, 0):p+80] - p = p - max(p-80, 0) - - # Strip to the left - i = text[:p].rfind('\n') - j = text[:p].rfind('\r') - if i < 0 or (0 <= j < i): i = j - if 0 <= i < p: - p = p - i - 1 - text = text[i+1:] - - # Strip to the right - i = text.find('\n', p) - j = text.find('\r', p) - if i < 0 or (0 <= j < i): i = j - if i >= 0: - text = text[:i] - - # Now shorten the text - while len(text) > 70 and p > 60: - # Cut off 10 chars - text = "..." + text[10:] - p = p - 7 - - # Now print the string, along with an indicator - print >>sys.stderr, '> ',text - print >>sys.stderr, '> ',' '*p + '^' - -def print_error(input, err, scanner): - """Print error messages, the parser stack, and the input text -- for human-readable error messages.""" - # NOTE: this function assumes 80 columns :-( - # Figure out the line number - line_number = scanner.get_line_number() - column_number = scanner.get_column_number() - print >>sys.stderr, '%d:%d: %s' % (line_number, column_number, err.msg) - - context = err.context - if not context: - print_line_with_pointer(input, err.charpos) - - while context: - # TODO: add line number - print >>sys.stderr, 'while parsing %s%s:' % (context.rule, tuple(context.args)) - print_line_with_pointer(input, context.scanner.get_prev_char_pos(context.tokenpos)) - context = context.parent - -def wrap_error_reporter(parser, rule): - try: - return getattr(parser, rule)() - except SyntaxError, e: - input = parser._scanner.input - print_error(input, e, parser._scanner) - except NoMoreTokens: - print >>sys.stderr, 'Could not complete parsing; stopped around here:' - print >>sys.stderr, parser._scanner - - -from twisted.words.xish.xpath import AttribValue, BooleanValue, CompareValue -from twisted.words.xish.xpath import Function, IndexValue, LiteralValue -from twisted.words.xish.xpath import _AnyLocation, _Location - - -# Begin -- grammar generated by Yapps -import sys, re - -class XPathParserScanner(Scanner): - patterns = [ - ('","', re.compile(',')), - ('"@"', re.compile('@')), - ('"\\)"', re.compile('\\)')), - ('"\\("', re.compile('\\(')), - ('"\\]"', re.compile('\\]')), - ('"\\["', re.compile('\\[')), - ('"//"', re.compile('//')), - ('"/"', re.compile('/')), - ('\\s+', re.compile('\\s+')), - ('INDEX', re.compile('[0-9]+')), - ('WILDCARD', re.compile('\\*')), - ('IDENTIFIER', re.compile('[a-zA-Z][a-zA-Z0-9_\\-]*')), - ('ATTRIBUTE', re.compile('\\@[a-zA-Z][a-zA-Z0-9_\\-]*')), - ('FUNCNAME', re.compile('[a-zA-Z][a-zA-Z0-9_]*')), - ('CMP_EQ', re.compile('\\=')), - ('CMP_NE', re.compile('\\!\\=')), - ('STR_DQ', re.compile('"([^"]|(\\"))*?"')), - ('STR_SQ', re.compile("'([^']|(\\'))*?'")), - ('OP_AND', re.compile('and')), - ('OP_OR', re.compile('or')), - ('END', re.compile('$')), - ] - def __init__(self, str): - Scanner.__init__(self,None,['\\s+'],str) - -class XPathParser(Parser): - Context = Context - def XPATH(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'XPATH', []) - PATH = self.PATH(_context) - result = PATH; current = result - while self._peek('END', '"/"', '"//"') != 'END': - PATH = self.PATH(_context) - current.childLocation = PATH; current = current.childLocation - if self._peek() not in ['END', '"/"', '"//"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['END', '"/"', '"//"'])) - END = self._scan('END') - return result - - def PATH(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'PATH', []) - _token = self._peek('"/"', '"//"') - if _token == '"/"': - self._scan('"/"') - result = _Location() - else: # == '"//"' - self._scan('"//"') - result = _AnyLocation() - _token = self._peek('IDENTIFIER', 'WILDCARD') - if _token == 'IDENTIFIER': - IDENTIFIER = self._scan('IDENTIFIER') - result.elementName = IDENTIFIER - else: # == 'WILDCARD' - WILDCARD = self._scan('WILDCARD') - result.elementName = None - while self._peek('"\\["', 'END', '"/"', '"//"') == '"\\["': - self._scan('"\\["') - PREDICATE = self.PREDICATE(_context) - result.predicates.append(PREDICATE) - self._scan('"\\]"') - if self._peek() not in ['"\\["', 'END', '"/"', '"//"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['"\\["', 'END', '"/"', '"//"'])) - return result - - def PREDICATE(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'PREDICATE', []) - _token = self._peek('INDEX', '"\\("', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ') - if _token != 'INDEX': - EXPR = self.EXPR(_context) - return EXPR - else: # == 'INDEX' - INDEX = self._scan('INDEX') - return IndexValue(INDEX) - - def EXPR(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'EXPR', []) - FACTOR = self.FACTOR(_context) - e = FACTOR - while self._peek('OP_AND', 'OP_OR', '"\\)"', '"\\]"') in ['OP_AND', 'OP_OR']: - BOOLOP = self.BOOLOP(_context) - FACTOR = self.FACTOR(_context) - e = BooleanValue(e, BOOLOP, FACTOR) - if self._peek() not in ['OP_AND', 'OP_OR', '"\\)"', '"\\]"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['OP_AND', 'OP_OR', '"\\)"', '"\\]"'])) - return e - - def BOOLOP(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'BOOLOP', []) - _token = self._peek('OP_AND', 'OP_OR') - if _token == 'OP_AND': - OP_AND = self._scan('OP_AND') - return OP_AND - else: # == 'OP_OR' - OP_OR = self._scan('OP_OR') - return OP_OR - - def FACTOR(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'FACTOR', []) - _token = self._peek('"\\("', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ') - if _token != '"\\("': - TERM = self.TERM(_context) - return TERM - else: # == '"\\("' - self._scan('"\\("') - EXPR = self.EXPR(_context) - self._scan('"\\)"') - return EXPR - - def TERM(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'TERM', []) - VALUE = self.VALUE(_context) - t = VALUE - if self._peek('CMP_EQ', 'CMP_NE', 'OP_AND', 'OP_OR', '"\\)"', '"\\]"') in ['CMP_EQ', 'CMP_NE']: - CMP = self.CMP(_context) - VALUE = self.VALUE(_context) - t = CompareValue(t, CMP, VALUE) - return t - - def VALUE(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'VALUE', []) - _token = self._peek('"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ') - if _token == '"@"': - self._scan('"@"') - IDENTIFIER = self._scan('IDENTIFIER') - return AttribValue(IDENTIFIER) - elif _token == 'FUNCNAME': - FUNCNAME = self._scan('FUNCNAME') - f = Function(FUNCNAME); args = [] - self._scan('"\\("') - if self._peek('"\\)"', '"@"', 'FUNCNAME', '","', 'STR_DQ', 'STR_SQ') not in ['"\\)"', '","']: - VALUE = self.VALUE(_context) - args.append(VALUE) - while self._peek('","', '"\\)"') == '","': - self._scan('","') - VALUE = self.VALUE(_context) - args.append(VALUE) - if self._peek() not in ['","', '"\\)"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['","', '"\\)"'])) - self._scan('"\\)"') - f.setParams(*args); return f - else: # in ['STR_DQ', 'STR_SQ'] - STR = self.STR(_context) - return LiteralValue(STR[1:len(STR)-1]) - - def CMP(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'CMP', []) - _token = self._peek('CMP_EQ', 'CMP_NE') - if _token == 'CMP_EQ': - CMP_EQ = self._scan('CMP_EQ') - return CMP_EQ - else: # == 'CMP_NE' - CMP_NE = self._scan('CMP_NE') - return CMP_NE - - def STR(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'STR', []) - _token = self._peek('STR_DQ', 'STR_SQ') - if _token == 'STR_DQ': - STR_DQ = self._scan('STR_DQ') - return STR_DQ - else: # == 'STR_SQ' - STR_SQ = self._scan('STR_SQ') - return STR_SQ - - -def parse(rule, text): - P = XPathParser(XPathParserScanner(text)) - return wrap_error_reporter(P, rule) - -if __name__ == '__main__': - from sys import argv, stdin - if len(argv) >= 2: - if len(argv) >= 3: - f = open(argv[2],'r') - else: - f = stdin - print parse(argv[1], f.read()) - else: print >>sys.stderr, 'Args: <rule> [<filename>]' -# End -- grammar generated by Yapps diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xmpproutertap.py b/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xmpproutertap.py deleted file mode 100644 index 0bdae0a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/Twisted-15.2.1-source/twisted/words/xmpproutertap.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_xmpproutertap -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application import strports -from twisted.python import usage -from twisted.words.protocols.jabber import component - -class Options(usage.Options): - optParameters = [ - ('port', None, 'tcp:5347:interface=127.0.0.1', - 'Port components connect to'), - ('secret', None, 'secret', 'Router secret'), - ] - - optFlags = [ - ('verbose', 'v', 'Log traffic'), - ] - - - -def makeService(config): - router = component.Router() - factory = component.XMPPComponentServerFactory(router, config['secret']) - - if config['verbose']: - factory.logTraffic = True - - return strports.service(config['port'], factory) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/CacheUtils.py b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/CacheUtils.py deleted file mode 100644 index a25784a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/CacheUtils.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -import urllib -import urllib2 -import json -class CacheUtils: - def download(self, url, local): - #urllib.urlretrieve(url, local, self.cbk) - urllib.urlretrieve(url, local) - - def parseUrl2FileName(self, url): - fileName = url.split('/')[-1] - #deal with pure url - if fileName == "": - fileName = url.split("//")[-1].replace('/', '') - return fileName - - def cache(self, url, range): - fileName = self.parseUrl2FileName(url) - req = urllib2.Request(url) - req.add_header('Range', 'bytes=' + range) - response = urllib2.urlopen(req) - buffer = response.read() - with open("./cache/" + fileName + range, "a+") as fp: - fp.write(buffer) - - def saveReq(self, url, range): - # Reading data back - with open('data.json', 'r') as fp: - data = json.load(fp) - data[url] = range - # Writing JSON data - with open('data.json', 'w') as fp: - json.dump(data, fp) - - def delReq(sel, url): - # Reading data back - with open('data.json', 'r') as fp: - data = json.load(fp) - if data.get(url): - del data[url] - # Writing JSON data - with open('data.json', 'w') as fp: - json.dump(data, fp) - - def checkReq(self, url): - # Reading data back - with open('data.json', 'r') as fp: - data = json.load(fp) - if data.get(url): - fileName = url.split('/')[-1] - with open('GotIt.txt', 'a+') as fp: - if data[url] == "None": - fp.write("the file you request has been downloaded: ./download/" + fileName + "\n") - else: - fp.write("the file you request has been cached: ./cache/" + fileName + " " + data[url] + "\n") - return True - else: - return False - - -""" - @staticmethod - def cbk(a, b, c): - '''''回调函数 - @a: å·²ç»ä¸‹è½½çš„æ•°æ®å— - @b: æ•°æ®å—çš„å¤§å° - @c: è¿œç¨‹æ–‡ä»¶çš„å¤§å° - ''' - per = 100.0 * a * b / c - if per > 100: - per = 100 - print '%.2f%%' % per - -if __name__ == '__main__': - cacheUtils = CacheUtils() - cacheUtils.delReq("http://static.youku.com/v1.0.1029/cms/img/zy.png") - #url = "http://www.sina.com.cn" - #fileName = url.split('/')[-1] - #cacheUtils.download(url, "./cache/" + fileName) - - #cacheUtils.cache("http://www.baidu.com") - #cacheUtils.cache("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png", "0-7000") - #cacheUtils.cache("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png", "7001-14175") - - - #cacheUtils.saveReq("http://www.sina.com.cn") - - #cacheUtils.loadReq() -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/CacheUtils.pyc b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/CacheUtils.pyc deleted file mode 100644 index a3457c5..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/CacheUtils.pyc and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/GotIt.txt b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/GotIt.txt deleted file mode 100644 index b78242f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/GotIt.txt +++ /dev/null @@ -1,11 +0,0 @@ -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/GotIt.txt~ b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/GotIt.txt~ deleted file mode 100644 index be44d4b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/GotIt.txt~ +++ /dev/null @@ -1,80 +0,0 @@ -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/ 0-7000 -the file you request has been cached: ./cache/50 0-7000 -the file you request has been cached: ./cache/0130391F4854DE23ABDA71085AD8AF4040077C-72D6-D10E-A8E2-281A83037160 0-7000 -the file you request has been cached: ./cache/0130391F48533B991848F6139B1FA448622DEF-D1C2-EF5A-894E-76ACA2B7040B 0-7000 -the file you request has been cached: ./cache/05100000557A941567BC3D7F2B0633B8 0-7000 -the file you request has been cached: ./cache/05100000546F10836737B34B7E03A098 0-7000 -the file you request has been cached: ./cache/05100000556821A267BC3D2CB10AD9A2 0-7000 -the file you request has been cached: ./cache/05100000556821B667BC3D2ABE042C2E 0-7000 -the file you request has been cached: ./cache/051000005465C14F6737B3325A0955CE 0-7000 -the file you request has been cached: ./cache/05100000547705646737B340AA0A959D 0-7000 -the file you request has been cached: ./cache/0130391F4553E22B8C361A0646F416ED804189-16D1-22B0-6592-2DE9528C4EBC 0-7000 -the file you request has been cached: ./cache/0130391F45530DBD99CBF3150EABFA52F54356-2481-BECE-753B-DC8FAD62B933 0-7000 -the file you request has been cached: ./cache/0130391F4554F20EC3A786189FF021190DA8B8-2BDB-69B6-1264-95CA09BEB5AC 0-7000 -the file you request has been cached: ./cache/0130391F485236FCB7B2B50504571BC3F0882E-1B2F-29BF-4FB3-546E15DFD5E5 0-7000 -the file you request has been cached: ./cache/0130391F4550C6E8234FC20830E1366754DB3E-08E4-6423-5297-D1C992589702 0-7000 -the file you request has been cached: ./cache/0130391F455463233C4D1A1BA985B0A18CFBF7-9827-5003-58E8-966A559DED6C 0-7000 -the file you request has been cached: ./cache/0130391F45533B8CE4A5E7030C71A035A2D08D-1CBC-D104-230C-A9F53170EE77 0-7000 -the file you request has been cached: ./cache/0130391F4554C59AB6E5630023C04A1E86AF52-68DD-5B50-DDC7-3543E9FB93EB 0-7000 -the file you request has been cached: ./cache/0130391F4554DC5277E951181CBEAD9761A8B9-B30B-B81C-5B88-F6AC54AB1057 0-7000 -the file you request has been cached: ./cache/0130391F4553BDFD01FB0D04A0DAFB54F6F014-8FDF-60AD-0854-2F756AC1692C 0-7000 -the file you request has been cached: ./cache/yk.css 0-7000 -the file you request has been cached: ./cache/grid_pc.css 0-7000 -the file you request has been cached: ./cache/ykhome.css 0-7000 -the file you request has been cached: ./cache/jquery.js 0-7000 -the file you request has been cached: ./cache/prototype.js 0-7000 -the file you request has been cached: ./cache/common.js 0-7000 -the file you request has been cached: ./cache/cmsCommon.js 0-7000 -the file you request has been cached: ./cache/cmsDatafromPrototype.js 0-7000 -the file you request has been cached: ./cache/compiler.js 0-7000 -the file you request has been cached: ./cache/resize.js 0-7000 -the file you request has been cached: ./cache/qheader.css 0-7000 -the file you request has been cached: ./cache/user-grade-icon.css 0-7000 -the file you request has been cached: ./cache/chuda.js 0-7000 -the file you request has been cached: ./cache/qheader.js 0-7000 -the file you request has been cached: ./cache/qwindow.js 0-7000 -the file you request has been cached: ./cache/popup.js 0-7000 -the file you request has been cached: ./cache/lsidetoolresize.js 0-7000 -the file you request has been cached: ./cache/lsidetool.css 0-7000 -the file you request has been cached: ./cache/lsidetool.js 0-7000 -the file you request has been cached: ./cache/cmsFriends.js 0-7000 -the file you request has been cached: ./cache/seedVideo.js 0-7000 -the file you request has been cached: ./cache/youku_laifeng_v3.js 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/qfooter.css 0-7000 -the file you request has been cached: ./cache/iresearch.js 0-7000 -the file you request has been cached: ./cache/cps.js 0-7000 -the file you request has been cached: ./cache/sideTool.css 0-7000 -the file you request has been cached: ./cache/sideTool.js 0-7000 -the file you request has been cached: ./cache/tdstat.js 0-7000 -the file you request has been cached: ./cache/ani.js 0-7000 -the file you request has been cached: ./cache/hover.js 0-7000 -the file you request has been cached: ./cache/gridTab.js 0-7000 -the file you request has been cached: ./cache/ykRecommend.js 0-7000 -the file you request has been cached: ./cache/chuda.css 0-7000 -the file you request has been cached: ./cache/share_msg.js 0-7000 -the file you request has been cached: ./cache/get.json 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/;stok=a094fa1c55f2125e2a34caadef198da8 0-7000 -the file you request has been cached: ./cache/beacon.js 0-7000 -the file you request has been cached: ./cache/MTFlashStore.swf 0-7000 -the file you request has been cached: ./cache/html 0-7000 -the file you request has been cached: ./cache/loader.swf 0-7000 -the file you request has been cached: ./cache/0130391F45540F219F90571975D51733572DE9-180A-C171-DDB1-75757E59B4F4 0-7000 -the file you request has been cached: ./cache/yklogo_h.png 0-7000 -the file you request has been cached: ./cache/header.png 0-7000 -the file you request has been cached: ./cache/vip.png 0-7000 -the file you request has been cached: ./cache/toolbar.png 0-7000 -the file you request has been cached: ./cache/050C00005583B8C567BC3D6F5E07F183 0-7000 -the file you request has been cached: ./cache/051500005583850C67BC3D22B40DD3C4 0-7000 -the file you request has been cached: ./cache/051500005583904D67BC3D29510BD425 0-7000 -the file you request has been cached: ./cache/list.json 0-7000 -the file you request has been cached: ./cache/getRankData 0-7000 diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4653A2B540C6F60414569C20E0B182-2A0A-71C0-7E7F-CC19FCD5724C0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4653A2B540C6F60414569C20E0B182-2A0A-71C0-7E7F-CC19FCD5724C0-7000 deleted file mode 100644 index 31f89d2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4653A2B540C6F60414569C20E0B182-2A0A-71C0-7E7F-CC19FCD5724C0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4653D768233BE001963F4937519C71-2016-F477-11BC-63A6154F90680-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4653D768233BE001963F4937519C71-2016-F477-11BC-63A6154F90680-7000 deleted file mode 100644 index cf7398a..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4653D768233BE001963F4937519C71-2016-F477-11BC-63A6154F90680-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46549B16F4244C0309545BF3AFB0B0-369D-FF3C-5166-5DE789FB51AA0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46549B16F4244C0309545BF3AFB0B0-369D-FF3C-5166-5DE789FB51AA0-7000 deleted file mode 100644 index d1d116d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46549B16F4244C0309545BF3AFB0B0-369D-FF3C-5166-5DE789FB51AA0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4654C10E0439130381150BAA5AD25D-3E86-C49F-51CC-B1900F76D4B80-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4654C10E0439130381150BAA5AD25D-3E86-C49F-51CC-B1900F76D4B80-7000 deleted file mode 100644 index 5936d85..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4654C10E0439130381150BAA5AD25D-3E86-C49F-51CC-B1900F76D4B80-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46556481A0D4350558C2B7056D2567-E140-E9EA-53E4-8A1535C671270-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46556481A0D4350558C2B7056D2567-E140-E9EA-53E4-8A1535C671270-7000 deleted file mode 100644 index 4d3baa6..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46556481A0D4350558C2B7056D2567-E140-E9EA-53E4-8A1535C671270-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4655685D5E374D04034D20302195D7-C33B-D192-AC6C-AF9F271C4C1D0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4655685D5E374D04034D20302195D7-C33B-D192-AC6C-AF9F271C4C1D0-7000 deleted file mode 100644 index 29c7807..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F4655685D5E374D04034D20302195D7-C33B-D192-AC6C-AF9F271C4C1D0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46556BCA66A6790945A1DB973566E5-BE5C-2B30-DC7B-918FB15F384F0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46556BCA66A6790945A1DB973566E5-BE5C-2B30-DC7B-918FB15F384F0-7000 deleted file mode 100644 index ae8657e..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46556BCA66A6790945A1DB973566E5-BE5C-2B30-DC7B-918FB15F384F0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557B6A1382530064DE1D3F5F87B4-39BF-0849-7D22-156D4127404B0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557B6A1382530064DE1D3F5F87B4-39BF-0849-7D22-156D4127404B0-7000 deleted file mode 100644 index 15c1412..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557B6A1382530064DE1D3F5F87B4-39BF-0849-7D22-156D4127404B0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557ED70EFC9B053F14D114D38641-39F8-9BCC-22E3-7E35AE57069F0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557ED70EFC9B053F14D114D38641-39F8-9BCC-22E3-7E35AE57069F0-7000 deleted file mode 100644 index fe99a91..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557ED70EFC9B053F14D114D38641-39F8-9BCC-22E3-7E35AE57069F0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557FE65B99CB154C5F2A10701786-4968-7D5E-89EA-BB61473AFDCC0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557FE65B99CB154C5F2A10701786-4968-7D5E-89EA-BB61473AFDCC0-7000 deleted file mode 100644 index f0bedc4..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F46557FE65B99CB154C5F2A10701786-4968-7D5E-89EA-BB61473AFDCC0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465582899FAE7F04FF5D68602306AC-2941-1C75-9A04-A5449A48608F0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465582899FAE7F04FF5D68602306AC-2941-1C75-9A04-A5449A48608F0-7000 deleted file mode 100644 index 4ef7853..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465582899FAE7F04FF5D68602306AC-2941-1C75-9A04-A5449A48608F0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465582E7EB5E5105BB0734254F8937-F2A3-13AF-E6F5-1418A4E1B9DF0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465582E7EB5E5105BB0734254F8937-F2A3-13AF-E6F5-1418A4E1B9DF0-7000 deleted file mode 100644 index 71eebc8..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465582E7EB5E5105BB0734254F8937-F2A3-13AF-E6F5-1418A4E1B9DF0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583949F9F8B035C40D23631B19F-7100-519A-4AF5-920A50F2C4590-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583949F9F8B035C40D23631B19F-7100-519A-4AF5-920A50F2C4590-7000 deleted file mode 100644 index 055b8a3..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583949F9F8B035C40D23631B19F-7100-519A-4AF5-920A50F2C4590-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583AB307649019DBA843A8902E6-57D9-CDB4-9797-79A0537F31810-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583AB307649019DBA843A8902E6-57D9-CDB4-9797-79A0537F31810-7000 deleted file mode 100644 index dcaac39..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583AB307649019DBA843A8902E6-57D9-CDB4-9797-79A0537F31810-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583C9D2605D058DBBB006045D0D-6A74-3295-3DB8-6980C32011110-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583C9D2605D058DBBB006045D0D-6A74-3295-3DB8-6980C32011110-7000 deleted file mode 100644 index 41620b1..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583C9D2605D058DBBB006045D0D-6A74-3295-3DB8-6980C32011110-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583D3F04A5700E80CB75F5BCF7B-8020-9C8F-4515-81E495F8611F0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583D3F04A5700E80CB75F5BCF7B-8020-9C8F-4515-81E495F8611F0-7000 deleted file mode 100644 index 48aff7b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0100641F465583D3F04A5700E80CB75F5BCF7B-8020-9C8F-4515-81E495F8611F0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45502C70118BE9058DBBB029BC8227-CBC8-BBE7-60CD-EC0810E9F2200-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45502C70118BE9058DBBB029BC8227-CBC8-BBE7-60CD-EC0810E9F2200-7000 deleted file mode 100644 index 5c97d5c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45502C70118BE9058DBBB029BC8227-CBC8-BBE7-60CD-EC0810E9F2200-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4550C6E8234FC20830E1366754DB3E-08E4-6423-5297-D1C9925897020-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4550C6E8234FC20830E1366754DB3E-08E4-6423-5297-D1C9925897020-7000 deleted file mode 100644 index 2cf0b69..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4550C6E8234FC20830E1366754DB3E-08E4-6423-5297-D1C9925897020-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551777BED444A04034D2005CB13D8-FC2F-D1B7-8851-E9433C59CB240-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551777BED444A04034D2005CB13D8-FC2F-D1B7-8851-E9433C59CB240-7000 deleted file mode 100644 index 1298b92..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551777BED444A04034D2005CB13D8-FC2F-D1B7-8851-E9433C59CB240-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551C51ED81F47000BF9C241A7F60B-4D56-EF7B-85B5-2E0D815B11D40-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551C51ED81F47000BF9C241A7F60B-4D56-EF7B-85B5-2E0D815B11D40-7000 deleted file mode 100644 index 1dbe517..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551C51ED81F47000BF9C241A7F60B-4D56-EF7B-85B5-2E0D815B11D40-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551F64E09FE210558C2B738E36237-DA9D-BB3C-2F71-216A21B8D9EE0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551F64E09FE210558C2B738E36237-DA9D-BB3C-2F71-216A21B8D9EE0-7000 deleted file mode 100644 index e95071c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4551F64E09FE210558C2B738E36237-DA9D-BB3C-2F71-216A21B8D9EE0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45524569901F6A131478AB447A2FEC-55F2-01FC-3B9C-1CDB6B1AFA300-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45524569901F6A131478AB447A2FEC-55F2-01FC-3B9C-1CDB6B1AFA300-7000 deleted file mode 100644 index 0460b1d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45524569901F6A131478AB447A2FEC-55F2-01FC-3B9C-1CDB6B1AFA300-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455269DDF4FAFF08565B2626163821-113D-8012-C8DD-2591F23004530-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455269DDF4FAFF08565B2626163821-113D-8012-C8DD-2591F23004530-7000 deleted file mode 100644 index 70362e8..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455269DDF4FAFF08565B2626163821-113D-8012-C8DD-2591F23004530-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45530C4DA78A25019DBA844C3DDB4C-443A-5C79-2FD6-E846C2065EC50-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45530C4DA78A25019DBA844C3DDB4C-443A-5C79-2FD6-E846C2065EC50-7000 deleted file mode 100644 index 0f13ca2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45530C4DA78A25019DBA844C3DDB4C-443A-5C79-2FD6-E846C2065EC50-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45530DBD99CBF3150EABFA52F54356-2481-BECE-753B-DC8FAD62B9330-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45530DBD99CBF3150EABFA52F54356-2481-BECE-753B-DC8FAD62B9330-7000 deleted file mode 100644 index 6f62030..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45530DBD99CBF3150EABFA52F54356-2481-BECE-753B-DC8FAD62B9330-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45531D77AFBA7F053F14D16A6F3894-23FF-5592-3946-B1B122D18CA30-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45531D77AFBA7F053F14D16A6F3894-23FF-5592-3946-B1B122D18CA30-7000 deleted file mode 100644 index 69f8d3a..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45531D77AFBA7F053F14D16A6F3894-23FF-5592-3946-B1B122D18CA30-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45533B8CE4A5E7030C71A035A2D08D-1CBC-D104-230C-A9F53170EE770-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45533B8CE4A5E7030C71A035A2D08D-1CBC-D104-230C-A9F53170EE770-7000 deleted file mode 100644 index a3b3fc4..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45533B8CE4A5E7030C71A035A2D08D-1CBC-D104-230C-A9F53170EE770-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455343A27D3516154C5F2A7A7A1CE3-3CB4-2AEB-EFC8-01634479C14C0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455343A27D3516154C5F2A7A7A1CE3-3CB4-2AEB-EFC8-01634479C14C0-7000 deleted file mode 100644 index a7bb454..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455343A27D3516154C5F2A7A7A1CE3-3CB4-2AEB-EFC8-01634479C14C0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45539E8674235C0114FBEFF03375B3-6BE5-711A-1C82-0F6D99594D750-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45539E8674235C0114FBEFF03375B3-6BE5-711A-1C82-0F6D99594D750-7000 deleted file mode 100644 index b7f8ee5..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45539E8674235C0114FBEFF03375B3-6BE5-711A-1C82-0F6D99594D750-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4553BDFD01FB0D04A0DAFB54F6F014-8FDF-60AD-0854-2F756AC1692C0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4553BDFD01FB0D04A0DAFB54F6F014-8FDF-60AD-0854-2F756AC1692C0-7000 deleted file mode 100644 index e3c2eee..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4553BDFD01FB0D04A0DAFB54F6F014-8FDF-60AD-0854-2F756AC1692C0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4553E22B8C361A0646F416ED804189-16D1-22B0-6592-2DE9528C4EBC0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4553E22B8C361A0646F416ED804189-16D1-22B0-6592-2DE9528C4EBC0-7000 deleted file mode 100644 index bf17ded..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4553E22B8C361A0646F416ED804189-16D1-22B0-6592-2DE9528C4EBC0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45540F219F90571975D51733572DE9-180A-C171-DDB1-75757E59B4F40-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45540F219F90571975D51733572DE9-180A-C171-DDB1-75757E59B4F40-7000 deleted file mode 100644 index ee144fa..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45540F219F90571975D51733572DE9-180A-C171-DDB1-75757E59B4F40-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455443B94F99C60309545B4E6A9869-B6C0-ECA5-264D-37E90D4A62EA0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455443B94F99C60309545B4E6A9869-B6C0-ECA5-264D-37E90D4A62EA0-7000 deleted file mode 100644 index cbb1cb3..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455443B94F99C60309545B4E6A9869-B6C0-ECA5-264D-37E90D4A62EA0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455463233C4D1A1BA985B0A18CFBF7-9827-5003-58E8-966A559DED6C0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455463233C4D1A1BA985B0A18CFBF7-9827-5003-58E8-966A559DED6C0-7000 deleted file mode 100644 index 5877786..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455463233C4D1A1BA985B0A18CFBF7-9827-5003-58E8-966A559DED6C0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554897F747485132160689D03CD26-3A52-8330-6935-E427C6D30D430-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554897F747485132160689D03CD26-3A52-8330-6935-E427C6D30D430-7000 deleted file mode 100644 index c28d4ef..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554897F747485132160689D03CD26-3A52-8330-6935-E427C6D30D430-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45549CD39F378202E272768B8E6D32-B9FC-5BB8-7460-8CE54D81E96D0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45549CD39F378202E272768B8E6D32-B9FC-5BB8-7460-8CE54D81E96D0-7000 deleted file mode 100644 index 2251d66..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45549CD39F378202E272768B8E6D32-B9FC-5BB8-7460-8CE54D81E96D0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554B34D520590019C3C1C25B031CE-29D3-4997-82BB-7B54B693C5F50-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554B34D520590019C3C1C25B031CE-29D3-4997-82BB-7B54B693C5F50-7000 deleted file mode 100644 index 99bb007..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554B34D520590019C3C1C25B031CE-29D3-4997-82BB-7B54B693C5F50-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554C59AB6E5630023C04A1E86AF52-68DD-5B50-DDC7-3543E9FB93EB0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554C59AB6E5630023C04A1E86AF52-68DD-5B50-DDC7-3543E9FB93EB0-7000 deleted file mode 100644 index 532ab5b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554C59AB6E5630023C04A1E86AF52-68DD-5B50-DDC7-3543E9FB93EB0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554DC5277E951181CBEAD9761A8B9-B30B-B81C-5B88-F6AC54AB10570-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554DC5277E951181CBEAD9761A8B9-B30B-B81C-5B88-F6AC54AB10570-7000 deleted file mode 100644 index 42e5d32..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554DC5277E951181CBEAD9761A8B9-B30B-B81C-5B88-F6AC54AB10570-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554F20EC3A786189FF021190DA8B8-2BDB-69B6-1264-95CA09BEB5AC0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554F20EC3A786189FF021190DA8B8-2BDB-69B6-1264-95CA09BEB5AC0-7000 deleted file mode 100644 index bb769cb..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554F20EC3A786189FF021190DA8B8-2BDB-69B6-1264-95CA09BEB5AC0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554FAD43BE691196BAADA00E99E44-BC12-8945-722D-C4510FDD9CB30-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554FAD43BE691196BAADA00E99E44-BC12-8945-722D-C4510FDD9CB30-7000 deleted file mode 100644 index ff71b12..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554FAD43BE691196BAADA00E99E44-BC12-8945-722D-C4510FDD9CB30-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554FD024F373800E80CB7CBB177A0-CE0D-F46A-6E9C-452073CBC94B0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554FD024F373800E80CB7CBB177A0-CE0D-F46A-6E9C-452073CBC94B0-7000 deleted file mode 100644 index a72ac53..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4554FD024F373800E80CB7CBB177A0-CE0D-F46A-6E9C-452073CBC94B0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455518AD375BCE149CC8F8C957D3C4-4230-0AFD-7631-A945BA2736EE0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455518AD375BCE149CC8F8C957D3C4-4230-0AFD-7631-A945BA2736EE0-7000 deleted file mode 100644 index 81f2994..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455518AD375BCE149CC8F8C957D3C4-4230-0AFD-7631-A945BA2736EE0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45552FCEB2AA4107ED621339A761B9-B2E9-64CF-65E8-2C2B5F5757DF0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45552FCEB2AA4107ED621339A761B9-B2E9-64CF-65E8-2C2B5F5757DF0-7000 deleted file mode 100644 index 198788b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45552FCEB2AA4107ED621339A761B9-B2E9-64CF-65E8-2C2B5F5757DF0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455541295236022CF4CEEAF7692162-E86D-18B9-EAE0-80FA62A3E9770-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455541295236022CF4CEEAF7692162-E86D-18B9-EAE0-80FA62A3E9770-7000 deleted file mode 100644 index 08f8a1b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455541295236022CF4CEEAF7692162-E86D-18B9-EAE0-80FA62A3E9770-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455546D8A9E2D41CAD43974209F70D-FD38-03D4-66C7-270F40BEEC1A0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455546D8A9E2D41CAD43974209F70D-FD38-03D4-66C7-270F40BEEC1A0-7000 deleted file mode 100644 index a868c8e..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F455546D8A9E2D41CAD43974209F70D-FD38-03D4-66C7-270F40BEEC1A0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45554F303059ED095CD25C6DC27A06-69C1-4830-2735-1BA36537DBCF0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45554F303059ED095CD25C6DC27A06-69C1-4830-2735-1BA36537DBCF0-7000 deleted file mode 100644 index debcc2b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45554F303059ED095CD25C6DC27A06-69C1-4830-2735-1BA36537DBCF0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45556565BF3FC618BEA3B9F65CB7BC-DB27-4D1B-43BC-EA5F44B1C7A90-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45556565BF3FC618BEA3B9F65CB7BC-DB27-4D1B-43BC-EA5F44B1C7A90-7000 deleted file mode 100644 index bec28bd..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45556565BF3FC618BEA3B9F65CB7BC-DB27-4D1B-43BC-EA5F44B1C7A90-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45556F1846579404FF5D68AF1B7579-816E-8BBA-D238-2775DE6D85FD0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45556F1846579404FF5D68AF1B7579-816E-8BBA-D238-2775DE6D85FD0-7000 deleted file mode 100644 index 0451757..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45556F1846579404FF5D68AF1B7579-816E-8BBA-D238-2775DE6D85FD0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45557E1E713AB118B1115CBAC7937B-E152-14B4-1E78-D105283364160-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45557E1E713AB118B1115CBAC7937B-E152-14B4-1E78-D105283364160-7000 deleted file mode 100644 index 875b821..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45557E1E713AB118B1115CBAC7937B-E152-14B4-1E78-D105283364160-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45557E872C1A542BBEAFBCA52959D6-31D1-5EB2-DA76-499D3ACCB4750-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45557E872C1A542BBEAFBCA52959D6-31D1-5EB2-DA76-499D3ACCB4750-7000 deleted file mode 100644 index cfa012d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F45557E872C1A542BBEAFBCA52959D6-31D1-5EB2-DA76-499D3ACCB4750-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484B9E3E4AA935035C40D293C76276-0DA3-0C1C-7B62-D715A4501FBC0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484B9E3E4AA935035C40D293C76276-0DA3-0C1C-7B62-D715A4501FBC0-7000 deleted file mode 100644 index 982c861..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484B9E3E4AA935035C40D293C76276-0DA3-0C1C-7B62-D715A4501FBC0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484C319D5D421B0414569CC88BC50F-47D2-7856-3E92-10DE0D8759B00-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484C319D5D421B0414569CC88BC50F-47D2-7856-3E92-10DE0D8759B00-7000 deleted file mode 100644 index ee345c4..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484C319D5D421B0414569CC88BC50F-47D2-7856-3E92-10DE0D8759B00-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484E951B5D2D5A059C8CE6264DAA6D-BEF3-4F0F-59C6-02074EC0EFF10-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484E951B5D2D5A059C8CE6264DAA6D-BEF3-4F0F-59C6-02074EC0EFF10-7000 deleted file mode 100644 index f1711af..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F484E951B5D2D5A059C8CE6264DAA6D-BEF3-4F0F-59C6-02074EC0EFF10-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48516FC3DB3050087AC092F0EC398D-8D7B-4EC8-713B-C0C180F4B9180-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48516FC3DB3050087AC092F0EC398D-8D7B-4EC8-713B-C0C180F4B9180-7000 deleted file mode 100644 index ca506a7..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48516FC3DB3050087AC092F0EC398D-8D7B-4EC8-713B-C0C180F4B9180-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F485236FCB7B2B50504571BC3F0882E-1B2F-29BF-4FB3-546E15DFD5E50-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F485236FCB7B2B50504571BC3F0882E-1B2F-29BF-4FB3-546E15DFD5E50-7000 deleted file mode 100644 index 888f201..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F485236FCB7B2B50504571BC3F0882E-1B2F-29BF-4FB3-546E15DFD5E50-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48533B991848F6139B1FA448622DEF-D1C2-EF5A-894E-76ACA2B7040B0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48533B991848F6139B1FA448622DEF-D1C2-EF5A-894E-76ACA2B7040B0-7000 deleted file mode 100644 index 56091a8..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48533B991848F6139B1FA448622DEF-D1C2-EF5A-894E-76ACA2B7040B0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48535D4FF8C1A1025A18B5F1B790C5-B05C-A83B-D4DB-98C60684E03C0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48535D4FF8C1A1025A18B5F1B790C5-B05C-A83B-D4DB-98C60684E03C0-7000 deleted file mode 100644 index 1b229a4..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F48535D4FF8C1A1025A18B5F1B790C5-B05C-A83B-D4DB-98C60684E03C0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4853C64EAF7E3F01963F4910007905-F37F-D6B9-ABEF-7BC345633A400-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4853C64EAF7E3F01963F4910007905-F37F-D6B9-ABEF-7BC345633A400-7000 deleted file mode 100644 index 2beb683..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4853C64EAF7E3F01963F4910007905-F37F-D6B9-ABEF-7BC345633A400-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4853F7111D30AC18B4BF7F24AD0453-006A-4D5E-1A0C-8C6FE3F2EFB50-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4853F7111D30AC18B4BF7F24AD0453-006A-4D5E-1A0C-8C6FE3F2EFB50-7000 deleted file mode 100644 index e78ad5a..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4853F7111D30AC18B4BF7F24AD0453-006A-4D5E-1A0C-8C6FE3F2EFB50-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4854D0895D6A8805BB073478A9822B-5C97-3887-415F-2E6180EC77560-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4854D0895D6A8805BB073478A9822B-5C97-3887-415F-2E6180EC77560-7000 deleted file mode 100644 index 1f62b46..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4854D0895D6A8805BB073478A9822B-5C97-3887-415F-2E6180EC77560-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4854DE23ABDA71085AD8AF4040077C-72D6-D10E-A8E2-281A830371600-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4854DE23ABDA71085AD8AF4040077C-72D6-D10E-A8E2-281A830371600-7000 deleted file mode 100644 index e2dd2f2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0130391F4854DE23ABDA71085AD8AF4040077C-72D6-D10E-A8E2-281A830371600-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/050C00005583B8C567BC3D6F5E07F1830-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/050C00005583B8C567BC3D6F5E07F1830-7000 deleted file mode 100644 index ae5d0ba..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/050C00005583B8C567BC3D6F5E07F1830-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC516737B324DE0AC1F20-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC516737B324DE0AC1F20-7000 deleted file mode 100644 index 061533c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC516737B324DE0AC1F20-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B324D20A73CC0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B324D20A73CC0-7000 deleted file mode 100644 index 686def5..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B324D20A73CC0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B324FF0DE0DD0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B324FF0DE0DD0-7000 deleted file mode 100644 index 5f9589e..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B324FF0DE0DD0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B3562D0BA4920-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B3562D0BA4920-7000 deleted file mode 100644 index 3320bd5..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BAC936737B3562D0BA4920-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACCF6737B325220573FE0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACCF6737B325220573FE0-7000 deleted file mode 100644 index b798a1d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACCF6737B325220573FE0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B30E4C0AACCA0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B30E4C0AACCA0-7000 deleted file mode 100644 index 3e4e570..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B30E4C0AACCA0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B324F7010C740-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B324F7010C740-7000 deleted file mode 100644 index 50f8d2c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B324F7010C740-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B324F80448270-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B324F80448270-7000 deleted file mode 100644 index 5f146e7..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD06737B324F80448270-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD16737B3250E0CFD700-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD16737B3250E0CFD700-7000 deleted file mode 100644 index b4d4a26..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD16737B3250E0CFD700-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD16737B36D870ADB5F0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD16737B36D870ADB5F0-7000 deleted file mode 100644 index 9bc374d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BACD16737B36D870ADB5F0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD076737B3250308E2160-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD076737B3250308E2160-7000 deleted file mode 100644 index 1d1d041..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD076737B3250308E2160-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B3251A049E210-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B3251A049E210-7000 deleted file mode 100644 index 9cf7c8c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B3251A049E210-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B3340202B8E30-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B3340202B8E30-7000 deleted file mode 100644 index f3b5607..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B3340202B8E30-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B37D420839260-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B37D420839260-7000 deleted file mode 100644 index 90c684a..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD086737B37D420839260-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B325200C8DA80-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B325200C8DA80-7000 deleted file mode 100644 index 9456538..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B325200C8DA80-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B3252D0AFCFF0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B3252D0AFCFF0-7000 deleted file mode 100644 index 17f679b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B3252D0AFCFF0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B37AF104C6F00-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B37AF104C6F00-7000 deleted file mode 100644 index a56c2dd..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD096737B37AF104C6F00-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD0A6737B308AE066CC00-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD0A6737B308AE066CC00-7000 deleted file mode 100644 index 80418dc..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD0A6737B308AE066CC00-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD0A6737B325300D6F0B0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD0A6737B325300D6F0B0-7000 deleted file mode 100644 index 1c2522f..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD0A6737B325300D6F0B0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B3253703FCC70-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B3253703FCC70-7000 deleted file mode 100644 index 9dd597a..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B3253703FCC70-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B349090CEA210-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B349090CEA210-7000 deleted file mode 100644 index fd42611..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B349090CEA210-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B35F790A9FC70-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B35F790A9FC70-7000 deleted file mode 100644 index f1d47c0..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD246737B35F790A9FC70-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B324D10D395E0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B324D10D395E0-7000 deleted file mode 100644 index ba6b387..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B324D10D395E0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B3253A0C33260-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B3253A0C33260-7000 deleted file mode 100644 index a62e1ed..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B3253A0C33260-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B35F7208971D0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B35F7208971D0-7000 deleted file mode 100644 index 045ebe0..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD256737B35F7208971D0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD2E6737B371B30A9BDA0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD2E6737B371B30A9BDA0-7000 deleted file mode 100644 index a6644cf..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541BFD2E6737B371B30A9BDA0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF16737B324E90D1E7E0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF16737B324E90D1E7E0-7000 deleted file mode 100644 index 0cd0682..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF16737B324E90D1E7E0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF26737B324F60BE6B00-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF26737B324F60BE6B00-7000 deleted file mode 100644 index 56cb911..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF26737B324F60BE6B00-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF26737B3636E0429E70-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF26737B3636E0429E70-7000 deleted file mode 100644 index 6ee1715..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FBFF26737B3636E0429E70-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FF4DE6737B325270C62130-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FF4DE6737B325270C62130-7000 deleted file mode 100644 index 4713f90..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000541FF4DE6737B325270C62130-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005420056E6737B303C10BA44F0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005420056E6737B303C10BA44F0-7000 deleted file mode 100644 index 8505a8d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005420056E6737B303C10BA44F0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005465C14F6737B3325A0955CE0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005465C14F6737B3325A0955CE0-7000 deleted file mode 100644 index b82de2b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005465C14F6737B3325A0955CE0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000546F10836737B34B7E03A0980-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000546F10836737B34B7E03A0980-7000 deleted file mode 100644 index 4f712ff..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000546F10836737B34B7E03A0980-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000547705646737B340AA0A959D0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000547705646737B340AA0A959D0-7000 deleted file mode 100644 index 926b618..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000547705646737B340AA0A959D0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000054D335C46737B35DA20A3BAD.jpg0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000054D335C46737B35DA20A3BAD.jpg0-7000 deleted file mode 100644 index 88017f2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000054D335C46737B35DA20A3BAD.jpg0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000054FD72CF6737B34B240EFFBA0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000054FD72CF6737B34B240EFFBA0-7000 deleted file mode 100644 index aa30e3e..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000054FD72CF6737B34B240EFFBA0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000055015FA56737B3297D0A1C7B0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000055015FA56737B3297D0A1C7B0-7000 deleted file mode 100644 index fe5fce9..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/0510000055015FA56737B3297D0A1C7B0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000552E1B996737B353C90605CC0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000552E1B996737B353C90605CC0-7000 deleted file mode 100644 index 2d87f20..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000552E1B996737B353C90605CC0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000552E1B996737B3642106DE840-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000552E1B996737B3642106DE840-7000 deleted file mode 100644 index 735bff2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000552E1B996737B3642106DE840-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553705DB67BC3D67110609FA0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553705DB67BC3D67110609FA0-7000 deleted file mode 100644 index 618988e..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553705DB67BC3D67110609FA0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553705DC67BC3D302B0846940-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553705DC67BC3D302B0846940-7000 deleted file mode 100644 index ab26f70..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553705DC67BC3D302B0846940-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7D67BC3D082C0D42390-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7D67BC3D082C0D42390-7000 deleted file mode 100644 index fb6b9d2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7D67BC3D082C0D42390-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7D67BC3D224004FF650-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7D67BC3D224004FF650-7000 deleted file mode 100644 index 9e0f195..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7D67BC3D224004FF650-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7E67BC3D6D44065FB50-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7E67BC3D6D44065FB50-7000 deleted file mode 100644 index 4161329..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000553F5B7E67BC3D6D44065FB50-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000556821A267BC3D2CB10AD9A20-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000556821A267BC3D2CB10AD9A20-7000 deleted file mode 100644 index 9e2d55d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000556821A267BC3D2CB10AD9A20-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000556821B667BC3D2ABE042C2E0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000556821B667BC3D2ABE042C2E0-7000 deleted file mode 100644 index 4920cf3..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000556821B667BC3D2ABE042C2E0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000557A941567BC3D7F2B0633B80-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000557A941567BC3D7F2B0633B80-7000 deleted file mode 100644 index ce7e21f..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05100000557A941567BC3D7F2B0633B80-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005583663E67BC3D20A50C87170-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005583663E67BC3D20A50C87170-7000 deleted file mode 100644 index 0d18cb7..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005583663E67BC3D20A50C87170-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005583663E67BC3D341D028BED0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005583663E67BC3D341D028BED0-7000 deleted file mode 100644 index 0151bee..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051000005583663E67BC3D341D028BED0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558365C267BC3D28E2014B9D0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558365C267BC3D28E2014B9D0-7000 deleted file mode 100644 index 8b11a85..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558365C267BC3D28E2014B9D0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558365EA67BC3D67A20737D50-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558365EA67BC3D67A20737D50-7000 deleted file mode 100644 index 726145e..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558365EA67BC3D67A20737D50-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051500005583850C67BC3D22B40DD3C40-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051500005583850C67BC3D22B40DD3C40-7000 deleted file mode 100644 index fc0e37b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051500005583850C67BC3D22B40DD3C40-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051500005583904D67BC3D29510BD4250-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051500005583904D67BC3D29510BD4250-7000 deleted file mode 100644 index 20379c7..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/051500005583904D67BC3D29510BD4250-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558393A567BC3D189B076DAD0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558393A567BC3D189B076DAD0-7000 deleted file mode 100644 index 12bb53d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558393A567BC3D189B076DAD0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558393E567BC3D441F0F22C50-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558393E567BC3D441F0F22C50-7000 deleted file mode 100644 index 6547196..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/05150000558393E567BC3D441F0F22C50-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/500-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/500-7000 deleted file mode 100644 index 18bceb2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/500-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/53.jpg0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/53.jpg0-7000 deleted file mode 100644 index d22af44..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/53.jpg0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/;stok=a094fa1c55f2125e2a34caadef198da80-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/;stok=a094fa1c55f2125e2a34caadef198da80-7000 deleted file mode 100644 index 57a6074..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/;stok=a094fa1c55f2125e2a34caadef198da80-7000 +++ /dev/null @@ -1,672 +0,0 @@ -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - -<!DOCTYPE html> -<html lang="zh-cn"> - <head> - <meta charset="utf-8"> - <title>OpenWrt - LuCI</title> - <!--[if lt IE 9]><script src="/luci-static/bootstrap/html5.js"></script><![endif]--> - <meta name="viewport" content="initial-scale=1.0"> - <link rel="stylesheet" href="/luci-static/bootstrap/cascade.css"> - <link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="/luci-static/bootstrap/mobile.css" type="text/css" /> - <link rel="shortcut icon" href="/luci-static/bootstrap/favicon.ico"> - <script src="/luci-static/resources/xhr.js"></script> - </head> - - <body class="lang_zh-cn"> - <header> - <div class="fill"> - <div class="container"> - <a class="brand" href="#"><span style="color:yellow;padding-right: 3px;"> MediaTek </span>OpenWrt</a> - <ul class="nav"> - </ul> - - - </div> - </div> - </header><div id="maincontent" class="container"> - - - - -<form method="post" action="/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8"> - <div class="cbi-map"> - <h2><a id="content" name="content">Authorization Required</a></h2> - <div class="cbi-map-descr"> - Please enter your username and password.</div> - <fieldset class="cbi-section"><fieldset class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title">Username</label> - <div class="cbi-value-field"> - <input class="cbi-input-user" type="text" name="username" value="admin" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title">Password</label> - <div class="cbi-value-field"> - <input id="focus_password" class="cbi-input-password" type="password" name="password" /> - </div> - </div> - </fieldset></fieldset> - </div> - - <div> - <input type="submit" value="Login" class="cbi-button cbi-button-apply" /> - <input type="reset" value="Reset" class="cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementById('focus_password'); - if (input) - input.focus(); -//]]></script> - - - - - <footer><a href="http://luci.subsignal.org/">Powered by LuCI Trunk (git-f8ff740)</a> - - OpenWrt MZ-R13P 9.0.15061810 RELEASE - - - <ul class="breadcrumb pull-right" id="modemenu"> - - <li><a href="/cgi-bin/luci/api/">api</a> <span class="divider">|</span></li> - - <li><a href="/cgi-bin/luci/admin/">Administration</a> <span class="divider">|</span></li> - - </ul> - - </footer> - </div> - </div> - </body> -</html> - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ani.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ani.js0-7000 deleted file mode 100644 index 7a83bce..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ani.js0-7000 +++ /dev/null @@ -1,69 +0,0 @@ -var Ani = Class.create(); - -Ani.prototype = { - time : 600, - sepTime: 20, - autoStart: true, - - //回调函数 - onstart : function(){}, - onevery : function(){}, - onpause : function(){}, - onstop : function(){}, - - initialize: function(el,opt){ - this._el = el; - Object.extend(this,opt); - if(this.autoStart)this.start(); - }, - - start : function(){ - if(this.running){return;} - - this.running = true; - //进度计数 - this._kicks = parseInt( this.time / this.sepTime ) + 1; - - this.onstart.call(this, this._el); - this._timer = setInterval(this.every.bind(this), this.sepTime); - this._startTime = +( new Date() ); - }, - - every : function(){ - var now = +( new Date() ); - this.percent = ( now - this._startTime )/this.time; - if( this.percent > 0.98 ){ - this.stop(); - }else{ - this.onevery.call(this, this._el, this.percent); - } - }, - - pause : function(){ - this.remainTime = -(new Date()) + this._startTime + this.time; - if(this.remainTime < 0){ - this.remainTime = 0; - this.percent = 1; - this.stop(); - }else{ - clearInterval(this._timer); - } - }, - - stop : function(){ - clearInterval(this._timer); - this.onstop.call(this, this._el); - this.running = false; - }, - - /** - * 转æ¢è¿›åº¦å€¼ä¸ºæ•°å€¼, 模拟easein easeout效果 - */ - _valueFn: function(percent){ - /** 这里使用三次函数f(x)=(3-2x)*x^2, 作为增长的转æ¢å‡½æ•° - * 特点 是f'(x)连续,å˜åŒ–连续,先加快,åŽå‡é€Ÿ - f(0) = f'(0) = 0, f(1) = f'(1) =1, f(0.5) = 0.5 - */ - return percent * percent * ( 3 - 2 * percent ); - } -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_large.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_large.png0-7000 deleted file mode 100644 index 486b45d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_large.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_mini.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_mini.png0-7000 deleted file mode 100644 index de0be53..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_mini.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_small.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_small.png0-7000 deleted file mode 100644 index 8d5353c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/bg_video_small.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/blanksprite.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/blanksprite.png0-7000 deleted file mode 100644 index 222707d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/blanksprite.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/chuda.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/chuda.css0-7000 deleted file mode 100644 index 884096f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/chuda.css0-7000 +++ /dev/null @@ -1 +0,0 @@ -@charset "utf-8";.cd-hpanel-ico{background:transparent url("../img/index/header-lv.png") no-repeat}.dropdown .panel .cd-hpanel-loading{position:absolute;top:0;left:0;width:100%;height:100%}.dropdown .panel .cd-hpanel-loading .ico-loading-64{width:64px;height:64px;background:url(../img/index/loading_64.gif) no-repeat;display:block;position:absolute;top:50%;left:50%;margin-top:-32px;margin-left:-32px;z-index:1}#qheader_username_panel{width:330px;height:445px;position:absolute;top:60px;background:#fff;z-index:10;zoom:1;border-left:1px solid #ccc;text-align:left;color:#555;box-shadow:0 0 10px #bbb;-webkit-box-shadow:0 0 10px #bbb;-moz-box-shadow:0 0 10px #bbb;left:-205px;box-sizing:border-box;padding:0}#qheader_username_panel .cd-hpanel-ico.ico-arrow-top-grey{z-index:11}#qheader_username_panel .cd-hpanel-oauth-login{border-bottom:solid 1px #ddd;margin:20px 20px 0 20px;position:relative;padding-bottom:20px;font-size:0;overflow:hidden}#qheader_username_panel .cd-hpanel-oauth-login .btn-large{font-size:20px;display:block;height:40px;width:100%;margin:0 0 10px 0}#qheader_username_panel .cd-hpanel-oauth-login .cd-hpanel-ico{margin-right:10px;display:inline;float:left}#qheader_username_panel .cd-hpanel-oauth-login .extend{font-size:12px;position:absolute;right:20px;bottom:20px}#qheader_username_panel .cd-hpanel-oauth-login a{color:#3399e0}#qheader_username_panel .ico-myspace{display:block;background-position:-43px -205px;height:20px;width:20px;margin:0 auto 5px auto;position:relative;top:0;left:0}#qheader_username_panel .ico-vip,#qheader_username_panel .ico__vipsuper{background:transparent url("../img/index/yk.8.png") no-repeat}#qheader_username_panel .ico-vip,#qheader_username_panel .ico__vipsuper{background-position:-30px -180px}#qheader_username_panel .ico-videomanage{margin-right:10px;width:20px;height:20px;background-position:-22px -205px;position:relative;top:0;left:0;margin:0 auto 5px auto;display:block}#qheader_username_panel .ico-yourfavor{display:block;background-position:-65px -205px;margin:0 auto 5px auto;width:25px;height:20px;position:relative;top:0;left:0}#qheader_username_panel .ico-subscribe{background-position:0 -205px;height:20px;width:22px;margin:0 auto 5px auto;position:relative;top:0;left:0;display:block}#qheader_username_panel .ico__vipsuper_no{display:inline-block;*display:inline;*zoom:1;width:16px;height:16px;background-position:-82px -44px;vertical-align:middle}#qheader_username_panel .ico-qq{display:inline-block;*display:inline;*zoom:1;width:24px;height:24px;background-position:-121px -12px;vertical-align:middle}#qheader_username_panel .ico-weibo{display:inline-block;*display:inline;*zoom:1;width:24px;height:24px;background-position:-93px -160px;vertical-align:middle}#qheader_username_panel .ico-alipay{display:inline-block;*display:inline;*zoom:1;width:24px;height:24px;background-position:-125px -160px;vertical-align:middle}#qheader_username_panel .cd-hpanel-user-info{background:#f5f5f5;padding:20px 0 20px 20px;position:relative}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-avatar{float:left;margin-right:10px;width:70px}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-avatar a img{width:70px;height:70px}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile{overflow:visible;zoom:1;position:relative;z-index:10}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-name{height:18px;line-height:18px;margin-bottom:10px;font-size:18px;color:#3399e0;position:relative}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-name a{color:#3399e0;font-size:18px;height:18px;line-height:18px;display:inline-block;*display:inline;*zoom:1}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit{height:16px;line-height:16px;position:relative;z-index:11}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-ico{margin-right:3px;margin-left:3px}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .ico__vipsuper{vertical-align:middle}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-user-valid{height:16px;line-height:16px;display:inline-block;*display:inline;*zoom:1;position:relative;z-index:12}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-user-valid .ico-valid-email{width:18px;height:16px;display:inline-block;*display:inline;*zoom:1}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-user-valid .qtips_valid{width:145px;height:24px;box-sizing:border-box;padding:0;top:26px;left:-20px}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-user-valid .qtips_valid .ico-arrow-left{height:8px;width:14px;position:absolute;top:-7px;left:17px;background-position:-80px -140px}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-user-valid .qtips_valid .content{position:relative;text-align:left;padding-left:10px;line-height:22px;height:22px}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-user-valid .qtips_valid .content .ico-min-close{position:absolute;top:50%;right:5px;height:8px;width:9px;cursor:pointer;margin-top:-4px;background-position:-125px -205px}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .cd-hpanel-user-valid .qtips_valid .content a{cursor:pointer;color:#06a7e1;text-decoration:none}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .ico-valid-email-done{background-position:-106px -205px;width:15px;height:16px;display:inline-block;*display:inline;*zoom:1;vertical-align:bottom}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .ico-valid-email{background-position:-106px -226px;width:15px;height:16px;display:inline-block;*display:inline;*zoom:1;vertical-align:bottom}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .ico-valid-phone-done{background-position:-90px -204px;width:15px;height:16px;display:inline-block;*display:inline;*zoom:1;vertical-align:bottom}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-credit .ico-valid-phone{background-position:-90px -226px;width:15px;height:16px;display:inline-block;*display:inline;*zoom:1;vertical-align:bottom}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-finance{color:#909090;margin-top:12px;font-size:14px;height:14px;line-height:14px;position:relative;z-index:7}#qheader_username_panel .cd-hpanel-user-info .cd-hpanel-user-profile .cd-hpanel-user-finance .finance-item{display:inline-block;*display:inline;*zoom:1;color:#909090;font-size:14px;height:14px;line-height:14p \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/chuda.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/chuda.js0-7000 deleted file mode 100644 index d8300a9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/chuda.js0-7000 +++ /dev/null @@ -1 +0,0 @@ -!function(){var t={Cookie:{set:function(t,e,a,s,i){var n="";if(a&&"number"==typeof a){var o=new Date;o.setTime(o.getTime()+24*a*60*60*1e3),n="; expires="+o.toGMTString()}var s=s||"/",i=i||".youku.com";document.cookie=[t,"=",e,n,";domain=",i,";path=",s].join("")},get:function(t){for(var e=t+"=",a=document.cookie?document.cookie.split("; "):[],s=0;s<a.length;s++){for(var i=a[s];" "==i.charAt(0);)i=i.substring(1,i.length);if(0==i.indexOf(e))return i.substring(e.length,i.length)}return null},remove:function(t){this.set(t,"",-1)}},Common:{decodeBase64:function(t){if(!t)return"";var e,a,s,i,n,o,l,c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",r="",d=0;t=t.replace(/[^A-Za-z0-9\+\/\=]/g,"");do i=c.indexOf(t.charAt(d++)),n=c.indexOf(t.charAt(d++)),o=c.indexOf(t.charAt(d++)),l=c.indexOf(t.charAt(d++)),e=i<<2|n>>4,a=(15&n)<<4|o>>2,s=(3&o)<<6|l,r+=String.fromCharCode(e),64!=o&&(r+=String.fromCharCode(a)),64!=l&&(r+=String.fromCharCode(s));while(d<t.length);return this.utf8To16(r)},utf8To16:function(t){var e,a,s,i,n,o=[];for(a=t.length,e=0;a>e;)switch(s=t.charCodeAt(e++),s>>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:o.push(t.charAt(e-1));break;case 12:case 13:i=t.charCodeAt(e++),o.push(String.fromCharCode((31&s)<<6|63&i));break;case 14:i=t.charCodeAt(e++),n=t.charCodeAt(e++),o.push(String.fromCharCode((15&s)<<12|(63&i)<<6|(63&n)<<0))}return o.join("")},cutStr:function(t,e,s){var t=t.replace(/</g,"&lt;").replace(/>/g,"&gt;"),i=this._strLen(t);if(e>=i)return t;var n=0,o=0;str_cut=new String,o=t.length;for(var l=0;o>l;l++){if(n++,a=t.charAt(l),escape(a).length>4&&n++,n>e)return s&&(str_cut=str_cut.concat(s)),str_cut;str_cut=str_cut.concat(a)}},_strLen:function(t){if(!t)return 0;var e=0,s=0;s=t.length;for(var i=0;s>i;i++)e++,a=t.charAt(i),escape(a).length>4&&e++;return e},serialize:function(t){return JSON.stringify(t)},deserialize:function(t){if("string"!=typeof t)return void 0;try{return JSON.parse(t)}catch(e){return t||void 0}},getBrowser:function(){var t,e={},a=navigator.userAgent.toLowerCase();return(t=a.match(/rv:([\d.]+)\) like gecko/))?e.ie=t[1]:(t=a.match(/msie ([\d.]+)/))?e.ie=t[1]:(t=a.match(/firefox\/([\d.]+)/))?e.firefox=t[1]:(t=a.match(/chrome\/([\d.]+)/))?e.chrome=t[1]:(t=a.match(/opera.([\d.]+)/))?e.opera=t[1]:(t=a.match(/version\/([\d.]+).*safari/))?e.safari=t[1]:0,e},bind:function(t,e,a){t.attachEvent?t.attachEvent("on"+e,function(){return function(e){window.event.cancelBubble=!0,t.attachEvent=[a.apply(t)]}}(t),!1):t.addEventListener&&t.addEventListener(e,function(t){t.stopPropagation(),a.apply(this)},!1)},Md5:function(t){var e,a,s,i,n,o,l,c,r,d=function(t,e){return t<<e|t>>>32-e},u=function(t,e){var a,s,i,n,o;return i=2147483648&t,n=2147483648&e,a=1073741824&t,s=1073741824&e,o=(1073741823&t)+(1073741823&e),a&s?2147483648^o^i^n:a|s?1073741824&o?3221225472^o^i^n:1073741824^o^i^n:o^i^n},m=function(t,e,a){return t&e|~t&a},p=function(t,e,a){return t&a|e&~a},v=function(t,e,a){return t^e^a},h=function(t,e,a){return e^(t|~a)},g=function(t,e,a,s,i,n,o){return t=u(t,u(u(m(e,a,s),i),o)),u(d(t,n),e)},_=function(t,e,a,s,i,n,o){return t=u(t,u(u(p(e,a,s),i),o)),u(d(t,n),e)},f=function(t,e,a,s,i,n,o){return t=u(t,u(u(v(e,a,s),i),o)),u(d(t,n),e)},k=function(t,e,a,s,i,n,o){return t=u(t,u(u(h(e,a,s),i),o)),u(d(t,n),e)},b=function(t){for(var e,a=t.length,s=a+8,i=(s-s%64)/64,n=16*(i+1),o=Array(n-1),l=0,c=0;a>c;)e=(c-c%4)/4,l=c%4*8,o[e]=o[e]|t.charCodeAt(c)<<l,c++;return e=(c-c%4)/4,l=c%4*8,o[e]=o[e]|128<<l,o[n-2]=a<<3,o[n-1]=a>>>29,o},y=function(t){var e,a,s="",i="";for(a=0;3>=a;a++)e=t>>>8*a&255,i="0"+e.toString(16),s+=i.substr(i.length-2,2);return s},w=function(t){t=t.replace(/\x0d\x0a/g,"\n");for(var e="",a=0;a<t.length;a++){var s=t.charCodeAt(a);128>s?e+=String.fromCharCode(s):s>127&&2048>s?(e+=String.fromCharCode(s>>6|192),e+=String.fromCharCode(63&s|128)):(e+=String.fromCharCode(s>>12|224),e+=String.fromCharCode(s>>6&63|128),e+=String.fromCharCode(63&s|128))}return e},D=Array(),C=7,A=12,N=17,U=22,I=5,O=9,H=14,M=20,T=4,x=11,L=16,S=23,E=6,q=10,j=15,Q=21;for(t=w(t),D=b(t),o=1732584193,l=4023233417,c=2562383102,r=271733878,e=0;e<D.length;e+=16)a=o,s=l,i=c,n=r,o=g(o,l,c,r,D[e+0],C,3614090360),r=g(r,o,l,c,D[e+1],A,3905402710),c=g(c,r,o,l,D[e+2],N,606105819),l=g(l,c,r,o,D[e+3],U,3250441966),o=g(o,l,c,r,D[e+4],C,4118548399),r=g(r,o,l,c,D[e+5],A,1200080426),c=g(c,r,o,l,D[e+6],N,2821735955),l=g(l,c,r,o,D[e+7],U,4249261313),o=g(o,l,c,r,D[e+8],C,1770035416),r=g(r,o,l,c,D[e+9],A,2336552879),c=g(c,r,o,l,D[e+10],N,4294925233),l=g(l,c,r,o,D[e+11],U,2304563134),o=g(o,l,c,r,D[e+12],C,1804603682),r=g(r,o,l,c,D[e+13],A,4254626195),c=g(c,r,o,l,D[e+14],N,2792965006),l=g(l,c,r,o,D[e+15],U,1236535329),o=_(o,l,c,r,D[e+1],I,4129170786),r=_(r,o,l,c,D[e+6],O,3225465664),c=_(c,r,o,l,D[e+11],H,643717713),l=_(l,c,r,o,D[e+0],M,3921069994),o=_(o,l,c,r,D[e+5],I,3593408605),r=_(r,o,l,c,D[e+10],O,38016083),c=_(c,r,o,l,D[e+15],H,3634488961),l=_(l,c,r,o,D[e+4],M,3889429448),o=_(o,l,c,r,D[e+9],I,568446438),r=_(r,o,l,c,D[e+14],O,3275163606),c=_(c,r,o,l,D[e+3],H,4107603335),l=_(l,c,r,o,D[e+8],M,1163531501),o=_(o,l,c,r,D[e+13],I,2850285829),r=_(r,o,l,c,D[e+2],O,4243563512),c=_(c,r,o,l,D[e+7],H,1735328473),l=_(l,c,r,o,D[e+12],M,2368359562),o=f(o,l,c,r,D[e+5],T,4294588738),r=f(r,o,l,c,D[e+8],x,2272392833),c=f(c,r,o,l,D[e+11],L,1839030562),l=f(l,c,r,o,D[e+14],S,4259657740),o=f(o,l,c,r,D[e+1],T,2763975236),r=f(r,o,l,c,D[e+4],x,1272893353),c=f(c,r,o,l,D[e+7],L,4139469664),l=f(l,c,r,o,D[e+10],S,3200236656),o=f(o,l,c,r,D[e+13],T,681279174),r=f(r,o,l,c,D[e+0],x,3936430074),c=f(c,r,o,l,D[e+3],L,3572445317),l=f(l,c,r,o,D[e+6],S,76029189),o=f(o,l,c,r,D[e+9],T,3654602809),r=f(r,o,l,c,D[e+12],x,3873151461),c=f(c,r,o,l,D[e+15],L,530742520),l=f(l,c,r,o,D[e+2],S,3299628645),o=k(o,l,c,r,D[e+0],E,4096336452),r=k(r,o,l,c,D[e+7],q,1126891415),c=k(c,r,o,l,D[e+14],j,2878612391),l=k(l,c,r,o,D[e+5],Q,4237533241),o=k(o,l,c,r,D[e+12],E,1700485571),r=k(r,o,l,c,D[e+3],q,2399980690),c=k(c,r,o,l,D[e+10],j,4293915773),l=k(l,c,r,o,D[e+1],Q,2240044497),o=k(o,l,c,r,D[e+8],E,1873313359),r=k(r,o,l,c,D[e+15],q,4264355552),c=k(c,r,o,l,D[e+6],j,2734768916),l=k(l,c,r,o,D[e+13],Q,1309151649),o=k(o,l,c,r,D[e+4],E,4149444226),r=k(r,o,l,c,D[e+11],q,3174756917),c=k(c,r,o,l,D[e+2],j,718787259),l=k(l,c,r,o,D[e+9],Q,3951481745),o=u(o,a),l=u(l,s),c=u(c,i),r=u(r,n);var P=y(o)+y(l)+y(c)+y(r);return P.toLowerCase()}},User:{getYKToken:function(){return t.Cookie.get("yktk")},getUserName:function(){var e=this.getYKToken();if(e){var a=t.Common.decodeBase64(decodeURIComponent(e).split("|")[3]);if(a.indexOf(",")>-1&&a.indexOf("nn:")>-1&&a.indexOf("id:")>-1)return a.split(",")[1].split(":")[1]}return 0},getUID:function(){var e=this.getYKToken();if(e){var a=t.Common.decodeBase64(decodeURIComponent(e).split("|")[3]);if(a.indexOf(",")>-1&&a.indexOf("nn:")>-1&&a.indexOf("id:")>-1)return parseInt(a.split(",")[0].split(":")[1])}return 0},getLoginStatus:function(){return 0!==this.getUID()}},Ajax:{getScript:function(t,e,a){if("string"==typeof argument \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsCommon.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsCommon.js0-7000 deleted file mode 100644 index c75c794..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsCommon.js0-7000 +++ /dev/null @@ -1,40 +0,0 @@ -(function(){ - OST = {}; - var osType = { - isWin:'Win', - isMac:'Mac', - isSafari:'Safari', - isChrome:'Chrome', - isIPAD: 'iPad', - isIPHONE: 'iPhone', - isIPOD: 'iPod', - isLEPAD: 'lepad_hls', - isMIUI: 'MI-ONE', - isAndroid:'Android', - isAndroid4: 'Android 4.', - isAndroid41: 'Android 4.1', - isSonyDTV: "SonyDTV", - isBlackBerry:"BlackBerry", - isMQQBrowser:'MQQBrowser', - isMobile:'Mobile' - }; - for(var os in osType){ - if(navigator.userAgent.indexOf(osType[os]) !== -1){ - OST[os] = true; - }else{ - OST[os] = false; - } - } - OST.isIos = ((OST.isIPAD || OST.isIPHONE || OST.isIPOD) || OST.isMac ); - OST.isPhone = (OST.isIPHONE || OST.isIPOD || (OST.isAndroid&&OST.isMobile)); - OST.isPad = (OST.isIPAD || (OST.isAndroid && !OST.isMobile)); -})(); - -var cms_request_ad = function(url){ - if(!url) return; - url += "&aw=w"; - if(logPvid){ url += "&sid="+logPvid; }; - if(OST.isPad){ url += "&bt=pad"; }else if(OST.isPhone){ url += "&bt=phone"; }; - if(OST.isIos){ url += "&os=ios"; }else if(OST.isAndroid){ url += "&os=Android"; }; - Nova.addScript(url); -} \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsDatafromPrototype.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsDatafromPrototype.js0-7000 deleted file mode 100644 index 4b9901a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsDatafromPrototype.js0-7000 +++ /dev/null @@ -1,114 +0,0 @@ -(function(o){ - if (!o) { - return false; - } - - if (!o.Event) { - return false; - } - - o.nova_init_hook_data_from = function() { - o.Event.observe(document, 'click', function(ev) { - if (!ev) { - ev = o.event; - } - - var target = ev.target || ev.srcElement; - if(!target) { - return ; - } - if (target.tagName !== 'A') { - if (!target.parentNode || (target.parentNode.tagName !== 'A')) { - return ; - } - target = target.parentNode; - } - - target = Element.extend(target); - CmsDatafromPrototype.addDataFrom(target); - }); - } - })(window); - -var CmsDatafromPrototype = { - getFromA: function() { - //from:a - var a = 'y1'; - if (OST.isIPAD) { - a = 'y8'; - } else if (OST.isIPHONE) { - a = 'y9'; - } else if (OST.isPad) { - a = 'y10'; - } else if (OST.isPhone) { - a = 'y11'; - } else if (OST.isMobile) { - a = 'y7' - } else if (OST.isWin || OST.isMac) { - a = 'y1'; - } - - return a; - }, - - getFromB: function() { - //from:b - var b = pagetype + '-' + domain + '-' + pageurl + '-' + topicIdNum + '-' + pageIdNum; - - return b; - }, - - getFromC: function(obj) { - if ((typeof obj !== 'object') || (typeof obj.ancestors !== 'function')) { - return ''; - } - - var pids = ''; - var oParents = obj.ancestors(); - var oParent = null; - for (var i = 0; i < oParents.length; ++i) { - oParent = oParents[i]; - if ((typeof oParent.id === 'undefined') || (oParent.id.substring(0, 2) !== 'm_')) { - continue; - } - pids = oParent.id.substring(2) + '-' + pids; - } - if (pids !== '') { - return pids.substring(0, pids.length - 1); - } - - return ''; - }, - - cancatFromParams: function(obj) { - var orginDatafrom = obj.readAttribute('data-from'); - if (empty(orginDatafrom)) { - return false; - } - - var a = CmsDatafromPrototype.getFromA(); - var b = CmsDatafromPrototype.getFromB(); - var c = CmsDatafromPrototype.getFromC(obj); - if (c === '') { - return false; - } - - return a + '.' + b + '.' + c + '.' + orginDatafrom; - }, - - addDataFrom: function(obj) { - var href = obj.readAttribute('href'); - if(empty(href)) { - return false; - } - - if(href.indexOf('http') === 0 && href.indexOf('?from') === -1 && href.indexOf('&from') === -1) { - var datafrom = CmsDatafromPrototype.cancatFromParams(obj); - if (!datafrom) { - return false; - } - var connector = (href.indexOf('?') !== -1) ? '&' : '?'; - obj.writeAttribute('href', href + connector + 'from=' + encodeURIComponent(datafrom)); - } - } -}; \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsFriends.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsFriends.js0-7000 deleted file mode 100644 index d9a6c4b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cmsFriends.js0-7000 +++ /dev/null @@ -1,228 +0,0 @@ -//关注明星 -var cms_friends = { - sources : null, - errTips : null, - scriptId : '', - preText : '', - tmpdiv : null, - friendId : 0, - - getUserId: function() { - var user = get_username('all'); - - return (typeof user.userid == 'undefined') ? 0 : user.userid; - }, - - follow: function(event) { - if(!islogin()) { - login(function() {window.location.reload()}); - return false; - } - - var loading = '<span class="ico__loading_16" style="width:20px;margin-left:10px;"></span>'; - - this.sources = Element.extend(Event.element(event)); - this.friendId = this.sources.getAttribute('_uid'); - - if (this.friendId == cms_friends.getUserId()) { - cms_friends.showError('ä¸èƒ½è®¢é˜…自己!'); - return false; - } - - this.tmpdiv = this.sources.up('.follow_state'); - this.preText = this.tmpdiv.innerHTML; - this.tmpdiv.innerHTML = loading; - - cms_friends.getJson('/QCms/~ajax/follow?uid=' + cms_friends.getUserId() + '&friend_uid=' + this.friendId, 'cms_friends.follow_callback'); - - return true; - }, - - follow_callback: function(res) { - cms_friends.tmpdiv.innerHTML = cms_friends.preText; - cms_friends.removeScript(); - - try { - res = (typeof res == 'object') ? res : res.stripScripts().evalJSON(1); - } catch(e) { - cms_friends.showError('æ“作失败, 请ç¨å€™å†è¯•!'); - return false; - } - - if (res.error != 1) { - cms_friends.showError(res.zh); - return false; - } - - $$('[_cmsfollow="' + cms_friends.friendId + '"]').each(function(o){o.style.display ='none';}); - $$('[_cmsfollowed="' + cms_friends.friendId + '"]').each(function(o){o.style.display = '';}); - $$('[_cmsfollowers="' + cms_friends.friendId + '"]').each(function(o){o.innerHTML = res.friend.followers_count;}); - - return true; - }, - - removeScript: function() { - var oScript = document.getElementById(cms_friends.scriptId); - if (oScript) { - document.getElementsByTagName("head")[0].removeChild(oScript); - } - - return true; - }, - - showError: function(errmsg) { - if(!cms_friends.errTips){ - cms_friends.errTips = new Qwindow({ - title: '', - showmask: false, - size: {width:300, height:100}, - content: {type: 'html', value: '<div class="talk_tips" style="text-align:center;padding-top:40px;"><div class="msg"><span class="ico__info"></span><span class="txt">11</span></div></div>'} - }); - } - $(cms_friends.errTips.dom.winbody).down('.txt').update(errmsg); - cms_friends.errTips.show(); - setTimeout(function(){cms_friends.errTips.hide()}, 2000); - - return true; - }, - - callBackScript: function(){ - return true; - }, - - getJson: function(url, callBack){ - var _script = document.createElement("script"); - _script.type = "text/javascript"; - _script.id = 'script_' + Date.parse(new Date()) + '_' + Math.round(Math.random() * 1000000); - _script.src = url + '&callback=' + callBack + '&scriptId=' + _script.id; - cms_friends.scriptId = _script.id; - - if (!/*@cc_on!@*/0) { - _script.onload = cms_friends.callBackScript; - } else { - _script.onreadystatechange = function(){ - if (_script.readyState == 'loaded' || _script.readyState == 'complete') { - cms_friends.callBackScript(); - } - } - } - document.getElementsByTagName("head")[0].appendChild(_script); - - return true; - } -}; - -//关注用户 -var cms_follow_videoupdate = { - sources : null, - errTips : null, - preText : '', - tmpdiv : null, - friendId : 0, - - getUserId: function() { - var user = get_username('all'); - - return (typeof user.userid == 'undefined') ? 0 : user.userid; - }, - - //å•ä¸ªå…³æ³¨ - follow: function(event) { - if(!islogin()) { - login({type:'cms_index_sc', callBack:'', isrefresh:true}); - return; - } - - var loading = '<span class="ico__loading_16" style="width:20px;margin-left:10px;"></span>'; - - this.sources = Element.extend(Event.element(event)); - this.friendId = this.sources.getAttribute('_uid'); - - if (this.friendId == cms_follow_videoupdate.getUserId()) { - cms_follow_videoupdate.showError('ä¸èƒ½è®¢é˜…自己!'); - return false; - } - - this.tmpdiv = this.sources.up(); - this.preText = this.tmpdiv.innerHTML; - this.tmpdiv.innerHTML = loading; - - Nova.QCms.followVideoUpdate({uid : cms_follow_videoupdate.getUserId(), friend_uid : this.friendId, follow_type: 'video_update'}, cms_follow_videoupdate.follow_callback, null); - - return true; - }, - - follow_callback: function(res) { - cms_follow_videoupdate.tmpdiv.innerHTML = cms_follow_videoupdate.preText; - - try { - res = (typeof res == 'object') ? res : res.stripScripts().evalJSON(1); - } catch(e) { - cms_follow_videoupdate.showError('æ“作失败, 请ç¨å€™å†è¯•!'); - return false; - } - - if (res.error != 1) { - cms_follow_videoupdate.showError(res.zh); - return false; - } - - $$('[_cms_follow_video="' + cms_follow_videoupdate.friendId + '"]').each(function(o){o.style.display ='none';}); - $$('[_cms_followed_video="' + cms_follow_videoupdate.friendId + '"]').each(function(o){o.style.display = '';}); - $$('[_cms_followers_video="' + cms_follow_videoupdate.friendId + '"]').each(function(o){o.innerHTML = res.friend.followers_count;}); - - return true; - }, - - //批é‡å…³æ³¨ - follow_batch: function(event, pageRegionModuleId) { - if(!islogin()) { - login(function() {window.location.reload()}); - return; - } - - var loading = '<span class="ico__loading_16" style="width:20px;margin-left:10px;"></span>'; - var friendUids = $('hidBatchFollowUids_' + pageRegionModuleId).value; - if ((friendUids !== '')) { - friendUids = friendUids.replace(/(^,+)|(,+$)/g, ''); - } - - this.sources = Element.extend(Event.element(event)); - this.tmpdiv = this.sources.up(); - this.preText = this.tmpdiv.innerHTML; - this.tmpdiv.innerHTML = loading; - this.friendId = friendUids; - - - Nova.QCms.followBatch({uid : cms_follow_videoupdate.getUserId(), friend_uids : '[' + this.friendId +']', mid : pageRegionModuleId}, cms_follow_videoupdate.follow_batch_callback, null); - - return true; - }, - - follow_batch_callback: function(res) { - cms_follow_videoupdate.tmpdiv.innerHTML = cms_follow_videoupdate.preText; - - try { - res = (typeof res == 'object') ? res : res.stripScripts().evalJSON(1); - } catch(e) { - cms_follow_videoupdate.showError('æ“作失败, 请ç¨å€™å†è¯•!'); - return false; - } - - if (res.error == -302) { - cms_follow_videoupdate.showError('ä½ å·²ç»è®¢é˜…了所有用户!'); - return true; - } else if (res.error != 1) { - cms_follow_videoupdate.showError(res.zh); - return false; - } else if ((typeof res.friends === 'undefined')) { - cms_follow_videoupdate.showError('æ“作失败, 请ç¨å€™å†è¯•!'); - return false; - } - - var objectUser = null; - for (var index in res.friends) { - objectUser = res.friends[index]; - if ((typeof objectUser.id !== 'undefined')) { - $$('[_cms_follow_batch="' + objectUser.id + '"]').each(function(o){o.style.display ='none';}); - $$('[_cms_followed_bat \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/common.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/common.js0-7000 deleted file mode 100644 index 897734e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/common.js0-7000 +++ /dev/null @@ -1,191 +0,0 @@ -//hack console error -(function(){ - if(window['console']){ return; } - window['console'] = { - log: function(){} - ,clear: function(){} - ,debug: function(){} - ,error: function(){} - ,info: function(){} - ,count: function(){} - ,time: function(){} - ,trace: function(){} - ,warn: function(){} - } -})(); - -//for script include static -//global function: cdn_jsurl, cdn_cssurl, cdn_imgurl -(function(){ - var url = 'Bad url, watch browser console error.', - Local = window.Local, - err = function(msg){ if(console && console.error){ console.error('[cdn function error] '+ msg + '.'); } }, - cdn = function(path, type){ - //path rule - if(path.charAt(0) != '/'){ err('@param path: relative to root start by /'); return url; } - //global block - if(!Local){ err('@see BETA-18932: template funciton {nova->globaJS}'); return url; } - var key = 'RELEASE_TAG', version = Local[key]; - //version define - if(!version){ err('@see local: ' + key + ' not defined'); return url; } - //server define - key = type.toUpperCase() + 'SERVER', server = Local[key]; - if(!server){ err('@see local: ' + key + ' not defined.'); return url; } - //bad server define - if(!server.match(/^(http|https)/)){ err('@see local: ' + key + ' is server, add protocol'); return url; } - if(server.match(/\/$/)){ err('@see local: ' + key + ' is server, not ending by \/'); return url; } - url = server+ '/' + version + path; - return url; - }; - window.cdn_jsurl = function(path){ return cdn(path, 'js'); }; - window.cdn_cssurl = function(path){ return cdn(path, 'css'); }; - window.cdn_imgurl = function(path){ return cdn(path, 'img'); }; -})(); - -//page load time for log -var logPageStartTime = (new Date()).getTime();//毫秒 -window.uepflag = 1;//uep统计å‘é€å¼€å…³ - -(function(){ - var scripts = document.getElementsByTagName('script'); - var currJssrc = scripts[scripts.length-1].src; - window.currJs_domain_version = currJssrc.split('/')[2]+ '/'+ currJssrc.split('/')[3]; -})(window) - -if((window.location.href.indexOf("www.youku.com") !== -1 || window.location.href.indexOf("v.youku.com") !== -1) && Math.round(Math.random()*1000) > 100) { - window.uepflag = 0;//抽样å‘é€ -} -//用户路径å‚æ•° -(function(o){ - o.nova_init_hook_rpvid = function(){ - o.Event.observe(document, "mousedown", function(ev){ - if(!ev) ev = o.event; - var target = ev.target || ev.srcElement; - if(!target) {return;} - Nova.Cookie.set("rpvid", window.logPvid + "-" + (new Date()).getTime());//记录用户路径 - }); - o.Event.observe(document, "touchend", function(ev){ - if(!ev) ev = o.event; - var target = ev.target || ev.srcElement; - if(!target) {return;} - Nova.Cookie.set("rpvid", window.logPvid + "-" + (new Date()).getTime());//记录用户路径 - }); - } -})(window); - -//监å¬å…¨ç«™çš„链接点击事件,检查是å¦å­˜åœ¨data-from属性,并添加fromå‚数至href属性中 -(function(o){ - if(!o) {return false;} - if(!o.Event) {return false;} - var checkFromDomain = function(href){ - var domain = ["youku.com/v_show/","youku.com/show_page/","youku.com/u/U"]; - for(var i=0,length=domain.length; i<length; i++){ - if(href.indexOf(domain[i]) !== -1) { - return true; - } - } - } - o.nova_init_hook_data_from = function(){ - o.Event.observe(document, "click", function(ev){ - if(!ev) ev = o.event; - var target = ev.target || ev.srcElement; - if(!target) {return;} - if(target.tagName != 'A' && target.parentNode) { - target = target.parentNode; - } - if(target.tagName == 'A') { - var data_from = target.getAttribute("data-from"); - var from = data_from || window.pvDataFrom; - var href = target.getAttribute("href"); - if(from && from != '') { - if(href && href.indexOf('http') === 0 && href.indexOf('?from') === -1 && href.indexOf('&from') === -1 && checkFromDomain(href)) { - from = encodeURIComponent(from); - if(href.indexOf('?') !== -1){ - target.setAttribute("href", href+'&from='+from); - }else{ - target.setAttribute("href", href+'?from='+from); - } - } - } - } - }); - } - })(window); - - - -window["nova_init_hook_logpagetime"] = function(){ - var logPageEndTime = (new Date()).getTime();//毫秒 - var loadTime = logPageEndTime - window.logPageStartTime; - if(loadTime <= 0 || isNaN(loadTime)) { - loadTime = -1; - var err = 1001; - } - if(loadTime >= 100 * 1000 || isNaN(loadTime)){ - loadTime = -1; - var err = 1002; - } - var logParam = "pid="+window.logPvid+"&m=web&st="+window.logPageStartTime+"&s="+loadTime+"&et="+logPageEndTime+"&u="+encodeURIComponent(window.location.href); - if(err){ - logParam += "&e="+err; - } - var type1 = ''; - var pagetype1 = ''; - if(new RegExp('^http:\/\/www.youku.com(\/)?$').test(window.location.href)){ - if(window.uepflag == 0) return false; - type1 = 'homepage';//index - pagetype1 = 1; - }else if(new RegExp('^http:\/\/v.youku.com/v_show/.*$').test(window.location.href)){ - if(window.uepflag == 0) return false;//抽样å‘é€ - type1 = 'playerpage';//video play page - pagetype1 = 2; - var vid = window.videoId || 0; - var ct = window.cateStr || ''; - var cs = window.subCatId || ''; - logParam += "&ct="+ct+"&cs="+cs+"&v="+vid; - }else if(new RegExp('^http:\/\/i.youku.com/u/home.*$').test(window.location.href)){ - type1 = 'usercenter';//user center page - pagetype1 = 4; - var ct = window.cateStr || ''; - logParam += "&ct="+ct; - }else if(!new RegExp('^http:\/\/(www)|(v)|(i).youku.com/.*$').test(window.location.href)){ - type1 = 'channelpage';//channel - pagetype1 = 3; - var ct = window.cateStr || ''; - logParam += "&ct="+ct; - }else{ - type1 = 'channelpage';//channel - pagetype1 = 3; - var ct = window.cateStr || ''; - logParam += "&ct="+ct; - } - logParam += "&t="+type1+"&p="+pagetype1+"&"+Math.random(); - var img = new Image(); - img.src = "http://v.l.youku.com/uep?"+logParam; -}; - - -//ucenter APT -(function(o){ - - if(!o || o.QUcenter){ return; } - - var winsub = null; - var uidsub = 0;//记录当å‰è¯·æ±‚订阅的uid - var handle_fake = null;//定ä½å‚考点 - o.QUcenter = { - bindFollow: function(handle, uid, addtion, callback, config){ - if(!arguments[0] || !arguments[1]){ return this; } - var callback = typeof(arguments[3]) == 'function' ? callback : null; - var config_default = { showwin: true }; - var config = arguments[3] ? arguments[3] : config_default; - config.showwin = typeof(config.showwin) != 'undefined' ? Boolean(config.showwin) : config_default.showwin; - var _this = this; - if(document.domain != 'youku.com'){ document.domain = 'youku.com'; } - handle.observe('click', function(e){ - if(typeof(window['passport'] == 'undefined')){ window.passport = '1'; } - if(!window['islogin'] && !window['Qwindow'] ){ return; } - if(!islogin()){ loginregGuide({from: 'follow', callBack: function(){ - _this.follow(uid, addtion, function(rs){ - handle.removeAttribute('lock'); - if(config.showwin){ _ \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/compiler.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/compiler.js0-7000 deleted file mode 100644 index 8485604..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/compiler.js0-7000 +++ /dev/null @@ -1 +0,0 @@ -window.nova_init_hook_main_login_status=function(){};var loadScript=function(e,t,i){var r=document.createElement("script"),o=document.getElementsByTagName("head")[0];r.type="text/javascript",r.src=e,r.onload=r.onreadystatechange=function(){this.readyState&&"loaded"!=this.readyState&&"complete"!=this.readyState||(t&&"function"==typeof t&&t(),i&&o.removeChild(r))},o.appendChild(r)},cmsModuleHtmlCallback=function(e,t){var i=YOUKU_HOME;if(e&&t){var r=i.STATUS_AREA["m_"+e]||"middle";i.Dom_appendModule(jQuery(t),r),toTop.getOnTop()}},toTop={MAXCOUNT_TOTOP:3,STEP_ANI:200,isAni:!0,$btns:null,$box:null,$dragmodules:null,$modulesOnTop:null,slideTimer:400,aniTimer:void 0,boxOffset:null,firstOffset:null,unitHeight:150,ClassRowIndex:"yk-row-index dragmodule",ClassOnTop:"dragmodule-top",ID_ORIGIN:"_origin",init:function(e){var t=this;t.isAni="boolean"==typeof e?e:!0,t.$box=jQuery(".s-body .yk-con"),t.$box.css("position","relative"),t.getOnTop()},getOnTop:function(){var e=this;e.$dragmodules=e.$box.find(".dragmodule").parent(),e.$btns=e.$dragmodules.find(".act-list .item-totop"),e.$dragmodules.removeClass(e.ClassOnTop),e.$modulesOnTop=jQuery("."+e.ClassOnTop).parent(),e.firstOffset=YOUKU_HOME.$drawer_top8.position().top+YOUKU_HOME.$drawer_top8.height(),YOUKU_HOME.$drawer_subscribe&&0!==YOUKU_HOME.$drawer_subscribe.length&&(e.firstOffset=YOUKU_HOME.$drawer_subscribe.position().top+YOUKU_HOME.$drawer_subscribe.height()),e.bindAct()},bindAct:function(){var e=this;e.$btns.html("置顶"),e.$modulesOnTop.find(".act-list .item-totop").html("å–消置顶"),YOUKU_HOME.LOGINSTATUS?(e.$btns.unbind("click").click(e.toTopDriver),e.$modulesOnTop.find(".act-list .item-totop").unbind("click").click(e.cancelTopDriver)):e.$btns.unbind("click").bind("click",YOUKU_HOME.Act_mylogin)},toTopDriver:function(e){var t=toTop,i=e||window.event;i.preventDefault&&(i.preventDefault(),i.stopPropagation());var r=jQuery(i.target);jQuery(".yk-drawer-act").removeClass("yk-drawer-act-hover"),YOUKU_HOME.LOGINSTATUS?t.toTopAct(r):YOUKU_HOME.mylogin()},cancelTopDriver:function(e){var t=toTop,i=e||window.event;i.preventDefault&&(i.preventDefault(),i.stopPropagation());var r=jQuery(i.target);jQuery(".yk-drawer-act").removeClass("yk-drawer-act-hover"),YOUKU_HOME.LOGINSTATUS?t.cancelTopAct(r,!0):YOUKU_HOME.Act_mylogin()},toTopAct:function(e){var t=toTop,i=e.parents(".dragmodule").parent(),r=YOUKU_HOME.$drawer_subscribe||YOUKU_HOME.$drawer_top8,o=t.firstOffset,a=i.attr("id"),n=i.height(),d=i.width(),s=parseInt(i.css("margin-bottom").split("px")[0]),c=i.position();t.getOnTop();var l=0===jQuery("#"+a+t.ID_ORIGIN).length?jQuery("<div></div>").attr("id",a+t.ID_ORIGIN):jQuery("#"+a+t.ID_ORIGIN);if(YOUKU_HOME.isIE||!t.isAni)return l.insertBefore(i).hide(),e.parents(".dragmodule").addClass(t.ClassOnTop),i.insertAfter(r),t.getOnTop(),void YOUKU_HOME.Post_personalData({mod_id:a,action:"top_mod"});if(Math.abs(c.top-o)<t.STEP_ANI)l.insertBefore(i).hide(),i.insertAfter(r),e.parents(".dragmodule").addClass(t.ClassOnTop),t.getOnTop();else{var u=i.clone().css({position:"absolute",top:c.top+"px",width:d+"px",height:n+"px",zIndex:200,display:"none"}).appendTo(t.$box);t.aniTimer=t.slideTimer*Math.round((c.top-t.firstOffset)/t.unitHeight),t.aniTimer>800&&(t.aniTimer=800),e.parents(".dragmodule").addClass(t.ClassOnTop),l.css({height:n+s+"px",marginBottom:0,width:d+"px",overflow:"hidden",visibility:"hidden"}).insertBefore(i),i.css({height:0,marginBottom:0,opacity:0}).insertAfter(r),t.getOnTop(),YOUKU_HOME.Post_personalData({mod_id:a,action:"top_mod"}),l.animate({height:0},t.slideTimer,function(){jQuery(this).css({visibility:"hidden",display:"none"})}),i.animate({height:n+s+"px",opacity:1},t.slideTimer,function(){jQuery(this).css({height:n+"px",marginBottom:s+"px"})}),u.css({display:"block",opacity:1}).animate({opacity:.2,top:o+"px"},t.aniTimer,function(){jQuery(this).remove()})}},cancelTopAct:function(e,t){var i,r,o=toTop,a=e.parents(".dragmodule").parent(),n=a.attr("id"),d=jQuery("#"+n+o.ID_ORIGIN);t&&YOUKU_HOME.Post_personalData({mod_id:n,action:"ctop_mod"}),e.parents(".dragmodule").removeClass(o.ClassOnTop),i=0!==d.length?jQuery(d.prevAll(":visible")[0]):YOUKU_HOME.$drawer_hidden.prev(),r=i.position().top+i.height()-a.height();var s=a.height(),c=a.width(),l=parseInt(a.css("margin-bottom").split("px")[0]),u=a.position();if(YOUKU_HOME.isIE||!o.isAni){a.insertAfter(i);try{d.remove()}catch(_){}return void o.getOnTop()}if(Math.abs(u.top-r)<o.STEP_ANI)a.insertAfter(i),o.getOnTop();else{var m=a.clone().attr("id",n+"_clone").css({position:"absolute",top:u.top+"px",width:c+"px",height:s+"px",zIndex:200,display:"none"}).appendTo(o.$box);o.$box.css("position","relative"),o.aniTimer=o.slideTimer*Math.round(Math.abs((u.top-r)/o.unitHeight)),o.aniTimer>800&&(o.aniTimer=800);var p=jQuery("<div></div>").css({height:s+l+"px",marginBottom:0,width:c+"px",overflow:"hidden",visibility:"hidden"}).insertAfter(a);a.css({height:0}).insertAfter(i),p.animate({height:0},o.slideTimer,function(){jQuery(this).remove()}),a.animate({height:s+"px",marginBottom:l+"px"},o.slideTimer,function(){d.remove(),o.getOnTop()}),m.css({display:"block",opacity:1}).animate({opacity:.2,top:r+"px"},o.aniTimer,function(){jQuery(this).remove()})}}},YOUKU_HOME={UA:null,MAXTIMER:3e3,MAXTIMER_GETSUBREC:2e3,MAXCOUNT_GETSUBREC:3,MAXCOUNT_GETSUB:3,MAXCOUNT_POSTPERSONAL:3,MAXCOUNT_TOTOP:3,REG_ID:"20",REGEXP_ID:null,REG_QUATE:new RegExp("&amp;","g"),URL_JQUERY:"http://static.youku.com/js/jquery.js",URL_HSLIDER:"http://r3.ykimg.com/05100000551D0EC26737B363E00BE98B.js?hslider",URL_GETPERSONAL:"http://www.youku.com/index/personal/fun_getCloudData?cloudvar=",URL_SETPERSONAL:"http://www.youku.com/index/personal/fun_changeCloudData?",URL_GETSUBSCRIBE:"http://www.youku.com/index/getUserFeedsForIndexMix",URL_GETSUBSCRIBEREC:"http://ykrec.youku.com/uploader/packed/list.json",URL_GETMODULE:"http://module.youku.com/",URL_GETRECOMMEND:"http://ykrec.youku.com/personal/packed/list.json",URL_GETUSERINFO:"http://nc.youku.com/index/getUserinfo",URL_GETSUBVLINK:" http://nc.youku.com/index_playWaitLogPage",URL_GETFRIENDSHIPS:"http://yws.youku.com/friendships/js_show.json",VAR_GETPERSONAL_ALL:"all",VAR_GETPERSONAL_CUSTOM:"customized",VAR_GETPERSONAL_TOP:"top",VAR_GETPERSONAL_HIDE:"hide",VAR_NUM_SUBRECUSER:20,VAR_NUM_SUBRECVIDEO:10,VAR_NUM_SUBRECMOREUSER:5,VAR_HEIGHT_SUBINIT:105,VAR_TRYFREQUENCY:300,ID_DRAWERSUB:"yk-slide-u-subscribe",ID_DRAWERSUBREC:"",ID_AD_BOTTOM:"m_206045",ID_DRAWER_HIDDEN:"m_206263",ID_TOP8:"m_205805",CLASS_DRAWER_HIDDEN:"yk-drawer-hidden",CLASS_ON_TOP:"dragmodule-top",CLASS_HIDDEN_SHOW:"yk-drawer-hidden-show",LOGINSTATUS:!1,COUNT_GETSUBREC:0,COUNT_GETSUB:0,COUNT_POSTPERSONAL:0,STATUS_AREA:{},isIE:!1,isSubRecInited:!1,isHiddenInited:!1,isLazyLoaded:!1,cookieUid:"",cookieYsuid:"",loadingstyle:"position:fixed;_position:absolute;z-index: 9999;width: 100%;height:100%;top: 0;margin-top:550px;background:#fff;",loadingicon:"<i class='ico-loading-64'></i>",prestyleStr:"body{height:100%;overflow:hidden;overflow- \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cps.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cps.js0-7000 deleted file mode 100644 index 8209790..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/cps.js0-7000 +++ /dev/null @@ -1,105 +0,0 @@ -//premium cps -(function(){ - - var base64_decode = function(data){ - var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,ac = 0,dec = "",tmp_arr = []; - if (!data) { return data; } - data += ''; - do { - h1 = b64.indexOf(data.charAt(i++)); - h2 = b64.indexOf(data.charAt(i++)); - h3 = b64.indexOf(data.charAt(i++)); - h4 = b64.indexOf(data.charAt(i++)); - bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; - o1 = bits >> 16 & 0xff; - o2 = bits >> 8 & 0xff; - o3 = bits & 0xff; - if (h3 == 64) { - tmp_arr[ac++] = String.fromCharCode(o1); - } else if (h4 == 64) { - tmp_arr[ac++] = String.fromCharCode(o1, o2); - } else { - tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); - } - } while (i < data.length); - dec = tmp_arr.join(''); - dec = utf8_decode(dec); - return dec; - } - - var utf8_decode = function(str_data){ - var tmp_arr = [],i = 0,ac = 0,c1 = 0,c2 = 0,c3 = 0;str_data += ''; - while (i < str_data.length) { - c1 = str_data.charCodeAt(i); - if (c1 < 128) { - tmp_arr[ac++] = String.fromCharCode(c1); - i++; - } else if (c1 > 191 && c1 < 224) { - c2 = str_data.charCodeAt(i + 1); - tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); - i += 2; - } else { - c2 = str_data.charCodeAt(i + 1); - c3 = str_data.charCodeAt(i + 2); - tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } - } - return tmp_arr.join(''); - } - - var cps_name = "premium_cps",yktk_name = "yktk",cps_val = null,yktk_val = null,uid = 0,tid = 0,ytid = 0,log = ""; - var cookies = document.cookie; - if(cookies == "") return; - var cookies_arr = cookies.split(";"); - for(var i=0;i<cookies_arr.length;i++){ - var cookie_value = cookies_arr[i].replace( /^\s+|\s+$/g,""); - if (cookie_value.substring(0, cps_name.length+1) == (cps_name + "=")) { - cps_val = cookie_value.substring(cps_name.length+1); - } - if (cookie_value.substring(0, yktk_name.length+1) == (yktk_name + "=")) { - yktk_val = cookie_value.substring(yktk_name.length+1); - } - } - if(!cps_val) return; - if(yktk_val){ - yktk_val = unescape(yktk_val); - var yktk_arr = yktk_val.split("|"); - var users = yktk_arr[3]; - users.replace(":","=").replace(",","&"); - var user_info = base64_decode(users); - var user_info_arr = user_info.split(","); - uid = user_info_arr[0].substring("id:".length); - ytid = user_info_arr[3].substring("ytid:".length); - tid = user_info_arr[4].substring("tid:".length); - } - cps_val = unescape(cps_val); - var cps_val_arr = cps_val.split("_"); - var ip = cps_val_arr[0]; - for(var i=1;i<cps_val_arr.length;i++){ - if(cps_val_arr[i]!=""){ - var cps_val_item_arr = cps_val_arr[i].split("|"); - log = [ '"ip":'+ip, - '"lvid":'+i, - '"mid":'+cps_val_item_arr[0], - '"cid":'+cps_val_item_arr[1], - '"pid":'+cps_val_item_arr[2], - '"lpid":'+cps_val_item_arr[3], - '"uid":'+uid, - '"uri":"'+encodeURIComponent(window.location)+'"', - '"ytid":'+ytid, - '"tid":'+tid - ].join(','); - - var url = "http://passport-log.youku.com/logsys/logstorage/append?project=paysys&log={"+log+"}"; - var img= document.createElement('IMG'); - img.width = 0; - img.height = 0; - img.src = url; - } - - } - //document.body.appendChild(img); - -})(); diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/drama.8.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/drama.8.png0-7000 deleted file mode 100644 index 9a1b841..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/drama.8.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ent.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ent.png0-7000 deleted file mode 100644 index 915463a..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ent.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/film.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/film.png0-7000 deleted file mode 100644 index cbfb971..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/film.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/get.json0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/get.json0-7000 deleted file mode 100644 index 28f8f46..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/get.json0-7000 +++ /dev/null @@ -1,8 +0,0 @@ -{ - "e":{ - "code":-101, - "provider":"notify", - "desc":"" - }, - "cost":"0.000003" -} \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/gridTab.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/gridTab.js0-7000 deleted file mode 100644 index 72a74f7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/gridTab.js0-7000 +++ /dev/null @@ -1,138 +0,0 @@ -/** - * GridTab专用 js 文件 - */ -// 页é¢åŠ è½½å®ŒæˆåŽåˆå§‹åŒ–页é¢äº‹ä»¶ -window.nova_init_hook_event = function(){ - var s = "MSIE", u = navigator.userAgent, i = -1; - if ((i = u.indexOf(s)) >= 0) { - var v = parseFloat(u.substr(i + s.length)); - if(v == 6){ try{ document.execCommand("BackgroundImageCache", false, true); } catch(e){} } - } - - var tabctls = $$('ul[focus="tabControl"]'); - for(var i=0; i<tabctls.length; ++i){//处ç†æ‰€æœ‰æ ‡ç­¾å®¹å™¨ - var ul = tabctls; - var li = Element.down(tabctls[i],'li'); - var switchtype = tabctls[i].attributes.getNamedItem('switchtype').nodeValue; - while(!empty(li)){ - if(switchtype === 'auto'){ - Event.observe(li,'mouseover',attachTabMouseover); - Event.observe(li,'mouseout',attachTabMouseOut); - }else if(switchtype === 'click'){ - Event.observe(li,'click',attachTabClick); - }else{ - Event.observe(li,'mouseover',attachTabEvent); - } - li = Element.next(li,'li'); - } - if(switchtype === 'auto'){ - ul[0].id = 'thTabHeaderUl_'+i;//增加id标识,用于é”定标签 - topic_start_switch(i); - } - } -} - -//äº‹ä»¶å¤„ç† -var attachTabMouseover = function(event){ - var event = event || window.event; - var ul = Event.findElement(event, 'ul'); - attachTabEvent(event); - var temp = ul.id; - splits = temp.split('_'); - topic_stop_switch(splits[1]); -} -var attachTabMouseOut = function(event){ - var event = event || window.event; - var ul = Event.findElement(event, 'ul'); - var temp = ul.id; - splits = temp.split('_'); - topic_start_switch(splits[1]); -} -var attachTabClick = function(event){ - var event = event || window.event; - var ul = Event.findElement(event, 'ul'); - attachTabEvent(event); - var temp = ul.id; - splits = temp.split('_'); - topic_stop_switch(splits[1]); -} -var attachTabEvent = function(event){ - var event = event || window.event; - var culi = Event.findElement(event, 'li'); - // 如果已ç»æ˜¯å½“å‰æ ‡ç­¾ï¼Œåˆ™è¿”回 - if ( culi && $(culi).hasClassName('current') ) { - return false; - } - var ul = Event.findElement(event, 'ul'); - var li = Element.down(ul, 'li'); - //éšè—所有标签对应内容区 - while(!empty(li)){ - var splits = li.id.split('_'); - $('tab_'+splits[1]+'_'+splits[2]).hide(); - Element.removeClassName(li, 'current'); - li = Element.next(li, 'li'); - } - //显示触å‘事件的标签åŠå†…容区 - Element.addClassName(culi, 'current'); - splits = culi.id.split('_'); - $('tab_'+splits[1]+'_'+splits[2]).show(); - $('tab_'+splits[1]+'_'+splits[2]).innerHTML.evalScripts(); - if($('tab_'+splits[1]+'_'+splits[2]+'tabarea')){ - $('tab_'+splits[1]+'_'+splits[2]+'tabarea').show(); - imgs = $A($('tab_'+splits[1]+'_'+splits[2]).getElementsByTagName('img')); - imgs.each(function(o){ - Element.extend(o); - if (o.readAttribute('_src')) { - o.src = o.readAttribute('_src'); - } - }); - } -} - -//è‡ªåŠ¨è½¬æ¢ -var tabItvls = {}; -function topic_start_switch(ii){ - tabItvls['intval'+ii] = self.setInterval('topic_tab_switch('+ii+')',30000); -} -function topic_stop_switch(ii){ - if(!empty(tabItvls['intval'+ii])) tabItvls['intval'+ii] = window.clearInterval(tabItvls['intval'+ii]); -} - -//æ ‡ç­¾è½¬æ¢ -function topic_tab_switch(ii){ - var tabctls = $$('ul[focus="tabControl"]'); - for(var i=0; i<tabctls.length; ++i){ - if(i === ii){//é”定所è¦æ“作的标签 - //找到当å‰li - var li = Element.down(tabctls[i], 'li'); - while(!empty(li)){ - if(li.className == 'current') break; - li = Element.next(li, 'li'); - } - //把当å‰li对应的内容域éšè— - var splits = li.id.split('_'); - $('tab_'+splits[1]+'_'+splits[2]).hide(); - Element.removeClassName(li, 'current'); - //å–循环的下一个li - li = Element.next(li, 'li'); - if(empty(li)){ - li = Element.down(tabctls[i], 'li'); - } - //显示下一个liåŠå¯¹åº”内容区 - Element.addClassName(li, 'current'); - splits = li.id.split('_'); - $('tab_'+splits[1]+'_'+splits[2]).show(); - $('tab_'+splits[1]+'_'+splits[2]).innerHTML.evalScripts(); - if($('tab_'+splits[1]+'_'+splits[2]+'tabarea')){ - $('tab_'+splits[1]+'_'+splits[2]+'tabarea').show(); - imgs = $A($('tab_'+splits[1]+'_'+splits[2]).getElementsByTagName('img')); - imgs.each(function(o){ - Element.extend(o); - if (o.readAttribute('_src')) { - o.src = o.readAttribute('_src'); - } - }); - } - } - } -} diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/grid_pc.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/grid_pc.css0-7000 deleted file mode 100644 index 2afffb3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/grid_pc.css0-7000 +++ /dev/null @@ -1,103 +0,0 @@ -@charset "utf-8"; - -body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, button, select, option, textarea, p, blockquote, th, td{ - padding: 0; - margin: 0; - font: 12px/20px arial, helvetica, verdana, tahoma, sans-serif; -} -body,.yk-con{background-color: #fff;} -ul{list-style:none;} - -/* */ -.v, -.p, -.v-mini-group{margin-bottom:20px;} -.v-mini-group .v{margin-bottom:10px;} -.v-small-group .v{margin-bottom:30px;} -.v .vb-oneline{*padding:0;} -.v .vb-oneline .v-meta-title, -.yk-v-oneline .v .v-meta-title{margin-top:18px;} -.v .vb-oneline .v-meta-overlay, -.yk-v-oneline .v .v-meta-overlay{ -background: url("/index/img/2013/video/bg_video_mini.png") no-repeat left bottom; -_background: none; -_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/video/bg_video_mini.png"); -} -.v-hover .vb-oneline .v-meta-overlay, -.yk-v-oneline .v-hover .v-meta-overlay{ - background: #000; - filter: alpha(opacity=70); -} -.v .vb-oneline .v-meta-tagrt{ - display: none; -} -.yk-v-oneline .v-hover .v-meta-title, -.v-hover .vb-oneline .v-meta-title{ - margin-top:0; -} - -.yk-row-through{margin-bottom:40px;} - - -/* yk-box */ -.yk-box .yk-head .yk-title span{color:#909090;} -/* tab */ -.yk-tab li a{cursor: pointer;line-height:20px;padding:5px 10px;font-family:"Microsoft YaHei","微软雅黑", SimHei, helvetica, arial, verdana, tahoma, sans-serif;} -.yk-tab-large li a{padding:0 20px;font-size:20px;line-height:30px;font-family:"Microsoft YaHei","微软雅黑", SimHei, helvetica, arial, verdana, tahoma, sans-serif;} - - -/* æ»‘å— */ -.yk-slide{overflow:hidden;position:relative;} -.yk-slide .yk-slide-pages{position:absolute;left:0;top:0;} -.yk-slide .yk-slide-pager{overflow:hidden;z-index:10;position:absolute;bottom:0;left:0;width:100%;height:10px;padding-top:10px;text-align:center;} -.yk-slide .yk-slide-pager div{cursor:pointer;overflow:hidden;display:inline-block;*display:inline;*zoom:1;width:10px;height:10px;margin:0 5px;vertical-align:top;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;background:#c3c3c3;} -.yk-slide .yk-slide-pager div:hover{background:#aaa;} -.yk-slide .yk-slide-pager div.current{cursor:default;background:#69aaec;} -.yk-slide .yk-slide-btnprev, -.yk-slide .yk-slide-btnnext{cursor:pointer;visibility:hidden;z-index:10;position:absolute;top:0;width:90px;height:100%;display:block;} -.yk-slide .yk-slide-btnprev, -.yk-slide .yk-slide-btnnext{-moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;user-select: none;} -.yk-slide .yk-slide-btnprev i, -.yk-slide .yk-slide-btnnext i{position:absolute;top:50%;width:45px;height:45px;margin-top:-23px;} -.yk-slide .yk-slide-btnprev i{left:0;background:url("/index/img/2013/slide_prev_btn.png") no-repeat;_background:none;_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/slide_prev_btn.png");} -.yk-slide .yk-slide-btnnext i{right:0;background:url("/index/img/2013/slide_next_btn.png") no-repeat;_background:none;_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/slide_next_btn.png");} -.yk-slide .yk-slide-btnprev{left:0;background:url("/index/img/2013/slide_prev_bg.png") no-repeat;_background:none;_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/slide_prev_bg.png");} -.yk-slide .yk-slide-btnnext{right:0;background:url("/index/img/2013/slide_next_bg.png") no-repeat;_background:none;_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/slide_next_bg.png");} -.yk-slide .yk-slide-btnprev:hover{background:url("/index/img/2013/slide_prev_hover_bg.png") no-repeat;_background:none;_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/slide_prev_hover_bg.png");} -.yk-slide .yk-slide-btnnext:hover{background:url("/index/img/2013/slide_next_hover_bg.png") no-repeat;_background:none;_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/slide_next_hover_bg.png");} -.yk-slide-v1{height:110px;} -.yk-slide-v2{height:160px;} -.yk-slide-v3{height:200px;} -.yk-slide-p1{height:320px;} -.yk-slide-p1 .yk-slide-btnprev, -.yk-slide-p1 .yk-slide-btnnext{height:300px;} - - -/* 排行榜 */ -.yk-rank{overflow:visible;margin:0;} -.yk-rank .item{*zoom:1;overflow:hidden;position:relative;width:auto;height:20px;line-height:20px;padding-left:30px;margin:10px 0 0;font-family:"Microsoft YaHei","微软雅黑",helvetica,arial,verdana,tahoma,sans-serif;} -.yk-rank .item:before, -.yk-rank .item:after{display:table;content:"";line-height:0;} -.yk-rank .item:after{clear:both;} -.yk-rank .item label{position:absolute;top:0;left:0;width:20px;height:20px;background:#03a7e1;color:#fff;display:inline-block;text-align:center;margin-right:10px;font:12px/20px "Microsoft YaHei","微软雅黑",helvetica,arial,verdana,tahoma,sans-serif;} -.yk-rank .item label.hot{background:#ef3f22;} -.yk-rank .item .name{display:block;float:left;font-size:14px;} -.yk-rank .item .extend{display:block;float:right;color:#909090;font-size:14px;} -.yk-rank .item a.extend:hover{color:#c31;} -.yk-rank .line{overflow:hidden;float:left;width:155px;margin-top:-10px;} -.yk-rank .yk-rank-desc{height:20px;padding:5px 0;margin-top:-20px;} -.yk-rank .yk-rank-desc span{color:#909090;} -.yk-rank .yk-rank-link{clear:both;font-size:12px;line-height:20px;padding-top: 10px} -.yk-rank .yk-rank-link a{margin-right:15px;font-family:simsun,"\5B8B\4F53","宋体";} -.yk-rank .item-thumb{height:50px;} -.yk-rank .item-thumb .thumb{float:left;overflow:hidden;width:90px;height:50px;margin-left:-30px;margin-right:10px;} -.yk-rank .item-thumb .thumb img{width:100%;} -.yk-rank .item-thumb .name, -.yk-rank .item-thumb .extend{float:none;} -.yk-rank .item-thumb .rating{position:absolute;top:0;right:0;color:#bbb;font-size:14px;} -.yk-rank .item-subscribe{position:relative; height: 50px; overflow: hidden; margin-bottom: 20px; padding-left: 0;} -.yk-rank .item-subscribe:hover{background: #f5f5f5;} -.yk-rank .item-subscribe:hover .sub-btn{display: block;} -.yk-rank .item-subscribe .sub-btn{display: none; position: absolute; top: 0px; right: 0px; width: 66px; height: 50px; font-size: 14px; color:#fff; font-family: "Microsoft Yahei", "微软雅黑", "黑体", Arial, sans-serif; line-height: 50px; text-indent: 27px; background:#11b9f5 url("http://r2.ykimg.com/051000005464214D6737B331FC04641D") no-repeat 9px 17px; cursor: pointer; -moz-box-shadow: -50px 0px 50px #f5f5f5; -webkit-box-shadow: -50px 0px 50px #f5f5f5; -o-box-shadow: -50px 0px 50px #f5f5f5; box-shadow: -50px 0px 50px #f5f5f5;} -.yk-rank .item-subscribe .userinfo{padding-top: 5px; margin-left: 10px;} -.yk-rank .item-subscribe label{position: absolute; top: 0; left:0; width: 20px; height: 20px; background: #03a7e1; color: #fff; line-he \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/header.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/header.png0-7000 deleted file mode 100644 index ffcca61..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/header.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/hover.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/hover.js0-7000 deleted file mode 100644 index d9d933a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/hover.js0-7000 +++ /dev/null @@ -1,62 +0,0 @@ -/** - * 视频组件hoveré®ç½©æ•ˆæžœ - * @param selector 需è¦hover效果的视频组件CSS选择器 - * @require Ani.js 动画类 - */ -var VideoHover=function(){}; -if(navigator.userAgent.indexOf('iPad') === -1){ - //é历所有现存的视频组件 - VideoHover = function(selector) { - - $$(selector).each(function(el, i){ - //视频组件 - var parent = el; - //跳过首页第一个视频组件 - if(parent.hasClassName('focusVideo')){ - return; - } - - if(parent.hasClassName('v')){ - parent.hoverClass = 'v-hover'; - parent.linkSel = '.v-link a'; - } else { - parent.hoverClass = 'p-hover'; - parent.linkSel = '.p-link a'; - } - - //监å¬mouseenter事件 - // å–消下移动画,开始(é‡å¯)上移动画 - parent.observe('mouseenter',function(evt){ - parent.addClassName(parent.hoverClass); - }); - - //监å¬mouseleave事件 - // å–消下移动画,开始(é‡å¯)上移动画 - parent.observe('mouseleave',function(evt){ - parent.removeClassName(parent.hoverClass); - }); - - try{ - var meta=parent.select('.vb, .p-meta'); - meta[0]&&meta[0].observe('click',function(evt){ - var target = evt.element(), - href = target.getAttribute('href'); - if(target.match('a') && href!="" && href!="#"){ - ; - }else{ - evt.stop(); - - var link=parent.select(parent.linkSel)[0]; - if(link){ - window.TUDO && window.TUDO.clickStat && window.TUDO.clickStat.send(evt, link); - link.click(); - } - //parent.select('.v-link a').invoke('click'); - } - }) - }catch(e){ - debugger; - } - }); - }; -} \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/html0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/html0-7000 deleted file mode 100644 index e69de29..0000000 diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ico-cert.24.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ico-cert.24.png0-7000 deleted file mode 100644 index d7ac3b3..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ico-cert.24.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/iresearch.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/iresearch.js0-7000 deleted file mode 100644 index 631b41b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/iresearch.js0-7000 +++ /dev/null @@ -1,4 +0,0 @@ -var _iwt_no_flash=0; -var _iwt_UA="UA-youku-000001"; - -(function(a,b,c){function y(){}function z(b){d&&a.console&&a.console.log&&a.console.log("MTFlashStore:"+b)}function H(){o.get(i,function(a){a?(D._getQueryStrByName(j)!=""?m=f+a+"&_iwt_cid="+D._getQueryStrByName(j)+"&_iwt_UA="+D._getUAId():m=f+a+"&_iwt_UA="+D._getUAId(),I(m,function(a){o.set(i,a),k=a})):(D._getQueryStrByName(j)!=""?m=f+"&_iwt_cid="+D._getQueryStrByName(j)+"&_iwt_UA="+D._getUAId():m=f+"&_iwt_UA="+D._getUAId(),I(m,function(a){o.set(i,a),k=a}))})}function I(d,e){var f=b.createElement("script"),g=o.guid();a[g]=function(){try{e.apply(a,arguments),n.removeChild(f)}catch(b){}a[g]=c},f.setAttribute("type","text/javascript"),f.setAttribute("charset","utf-8");var h=d+"&jsonp="+g+"&";typeof _iwt_p1=="undefined"?h+="_iwt_p1=&":h=h+"_iwt_p1="+_iwt_p1+"&",typeof _iwt_p2=="undefined"?h+="_iwt_p2=&":h=h+"_iwt_p2="+_iwt_p2+"&",typeof _iwt_p3=="undefined"?h+="_iwt_p3=&":h=h+"_iwt_p3="+_iwt_p3+"&";if(typeof _iwt_no_referrer!="undefined"&&!_iwt_no_referrer){var i=D.getReferrer();i!=""&&(h=h+"ref="+encodeURIComponent(i)+"&")}f.setAttribute("src",h),n.firstChild?n.insertBefore(f,n.firstChild):n.appendChild(f)}var d=!1,e=!-[1],f="http://irs01.com/irt?_iwt_id=",g="http://irs01.net/MTFlashStore.swf#",h="http://irs01.com/_iwt.gif",i="_iwt_id",j="_iwt_cid",k="",l="",m="",n=b.getElementsByTagName("head")[0],o={available:!1,guid:function(){return["MT",(+(new Date)+p++).toString(36),(Math.random()*1e18).toString(36)].join("").slice(0,16).toUpperCase()},get:function(a,b){return o._sendFlashMsg(b,"jGetItem",a)},set:function(a,b,c){return o._sendFlashMsg(c,"jSetItem",a,b)},clear:function(a,b){return o._sendFlashMsg(b,"jClearItem",a)},clearAll:function(a){return o._sendFlashMsg(a,"jClearAllItems")},_sendFlashMsg:function(b,c,d,e){b=b||y;var f=o.guid();a[f]=b;switch(arguments.length){case 2:u[c](f);break;case 3:u[c](d,f);break;case 4:u[c](d,e,f)}},initSWF:function(a,b){if(!o.available)return b&&b();if(o.inited)return a&&setTimeout(a,0);a&&q.push(a),b&&r.push(b)}},p=1,q=[],r=[],s="",t,u,v,w=b.createElement("DIV"),x=o.guid();if(!a._iwt_no_flash){try{t=a.navigator.plugins["Shockwave Flash"]||a.ActiveXObject,s=t.description||function(){return(new t("ShockwaveFlash.ShockwaveFlash")).GetVariable("$version")}()}catch(A){}s=(s.match(/\d+/g)||[0])[0];if(s<9)o.available=!1;else{o.available=!0,a[x]=function(b,c){switch(b){case"onecall":if(!a[c])return;a[c].apply(a,[].slice.call(arguments,2)),delete a[c];break;case"error":o.available=!1;while(v=r.shift())v();z(c);break;case"load":z("Flash load success!"),o.inited=!0,o.available=!0;while(v=q.shift())setTimeout(v,0)}};function B(){w.setAttribute("style","display:block;clear:both;float:none;position:absolute;right:0;bottom:0;border:none;"),b.body.firstChild?b.body.insertBefore(w,b.body.firstChild):b.body.appendChild(w),w.innerHTML='<object id="'+o.guid()+(e?' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ':"")+'" data="'+g+'" type="application/x-shockwave-flash" '+' width="10" height="10" style="position:absolute;right:0;bottom:0;border:none;" >'+'<param name="movie" value="'+g+'" />'+'<param name="wmode" value="transparent" />'+'<param name="version" value="10" />'+'<param name="allowScriptAccess" value="always" />'+'<param name="flashvars" value="jsproxyfunction='+x+'" />'+"</object>",u=w.firstChild,o.swf=u}var C=setInterval(function(){b.body&&(B(),clearInterval(C))},100)}}var D={track:function(){o.available?(o.initSWF(H),setTimeout(function(){o.inited||(o.available=!1,a[x]=y,D.track())},3e3)):(this._getQueryStrByName(j)!=""?m=f+"&_iwt_cid="+this._getQueryStrByName(j)+"&_iwt_UA="+this._getUAId():m=f+"&_iwt_UA="+this._getUAId(),I(m,function(a){var b=a;k=a}))},record_video_api:function(a,b,c,d){if(d+""=="0"){l=this._getHashId(),this._feedBack_video(a,b,c,d);return}this._feedBack_video(a,b,c,d)},_feedBack_video:function(a,b,c,d){var e=["ta="+d,"eid="+l,"pt="+encodeURIComponent(document.title),"vid="+a,"du="+b,"la="+c,"_iwt_id="+k,"_iwt_UA="+this._getUAId(),"r="+(new Date).getTime()].join("&"),f=h+"?"+e;this._img=new Image,this._img.src=f},_getHashId:function(){var a=location.href,b=(new Date).valueOf(),c=navigator.userAgent,d="";return d=this._md5([location.host,a,c,b,Math.random()].join("")),d},_getUAId:function(){return typeof _iwt_UA=="undefined"?"":_iwt_UA},_getQueryStrByName:function(a){var b=location.search.match(new RegExp("[?&]"+a+"=([^&]+)","i"));return b==null||b.length<1?"":b[1]},_getCookie:function(a){var b,c,d,e=document.cookie.split(";");for(b=0;b<e.length;b++){c=e[b].substr(0,e[b].indexOf("=")),d=e[b].substr(e[b].indexOf("=")+1),c=c.replace(/^\s+|\s+$/g,"");if(c==a)return unescape(d)}},getReferrer:function(){var a="";try{a=window.top.document.referrer}catch(b){if(window.parent)try{a=window.parent.document.referrer}catch(c){a=""}}return a==""&&(a=document.referrer),a},_md5:function(a){function b(a,b){return a<<b|a>>>32-b}function c(a,b){var c,d,e,f,g;return e=a&2147483648,f=b&2147483648,c=a&1073741824,d=b&1073741824,g=(a&1073741823)+(b&1073741823),c&d?g^2147483648^e^f:c|d?g&1073741824?g^3221225472^e^f:g^1073741824^e^f:g^e^f}function d(a,b,c){return a&b|~a&c}function e(a,b,c){return a&c|b&~c}function f(a,b,c){return a^b^c}function g(a,b,c){return b^(a|~c)}function h(a,e,f,g,h,i,j){return a=c(a,c(c(d(e,f,g),h),j)),c(b(a,i),e)}function i(a,d,f,g,h,i,j){return a=c(a,c(c(e(d,f,g),h),j)),c(b(a,i),d)}function j(a,d,e,g,h,i,j){return a=c(a,c(c(f(d,e,g),h),j)),c(b(a,i),d)}function k(a,d,e,f,h,i,j){return a=c(a,c(c(g(d,e,f),h),j)),c(b(a,i),d)}function l(a){var b,c=a.length,d=c+8,e=(d-d%64)/64,f=(e+1)*16,g=Array(f-1),h=0,i=0;while(i<c)b=(i-i%4)/4,h=i%4*8,g[b]=g[b]|a.charCodeAt(i)<<h,i++;return b=(i-i%4)/4,h=i%4*8,g[b]=g[b]|128<<h,g[f-2]=c<<3,g[f-1]=c>>>29,g}function m(a){var b="",c="",d,e;for(e=0;e<=3;e++)d=a>>>e*8&255,c="0"+d.toString(16),b+=c.substr(c.length-2,2);return b}function n(a){a=a.replace(/\r\n/g,"\n");var b="";for(var c=0;c<a.length;c++){var d=a.charCodeAt(c);d<128?b+=String.fromCharCode(d):d>127&&d<2048?(b+=String.fromCharCode(d>>6|192),b+=String.fromCharCode(d&63|128)):(b+=String.fromCharCode(d>>12|224),b+=String.fromCharCode(d>>6&63|128),b+=String.fromCharCode(d&63|128))}return b}var o=Array(),p,q,r,s,t,u,v,w,x,y=7,z=12,A=17,B=22,C=5,D=9,E=14,F=20,G=4,H=11,I=16,J=23,K=6,L=10,M=15,N=21;a=n(a),o=l(a),u=1732584193,v=4023233417,w=2562383102,x=271733878;for(p=0;p<o.length;p+=16)q=u,r=v,s=w,t=x,u=h(u,v,w,x,o[p+0],y,3614090360),x=h(x,u,v,w,o[p+1],z,3905402710),w=h(w,x,u,v,o[p+2],A,606105819),v=h(v,w,x,u,o[p+3],B,3250441966),u=h(u,v,w,x,o[p+4],y,4118548399),x=h(x,u,v,w,o[p+5],z,1200080426),w=h(w,x,u,v,o[p+6],A,2821735955),v=h(v,w,x,u,o[p+7],B,4249261313),u=h(u,v,w,x,o[p+8],y,1770035416),x=h(x,u,v,w,o[p+9],z,2336552879),w=h(w,x,u,v,o[p+10],A,4294925233),v=h(v,w,x,u,o[p+11],B,2304563134),u=h(u,v,w,x,o[p+12],y,1804603682),x=h(x,u,v,w,o[p+13],z,4254626195),w=h(w,x,u,v,o[p+14],A,2792965006),v=h(v,w,x,u,o[p+15],B,1236535329),u=i(u,v,w,x,o[p+1],C,4129170786),x=i(x,u,v,w,o[p+6],D,322546566 \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/jquery.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/jquery.js0-7000 deleted file mode 100644 index 6894a66..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/jquery.js0-7000 +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license*/ -(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/loader.swf0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/loader.swf0-7000 deleted file mode 100644 index 44cad26..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/loader.swf0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetool.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetool.css0-7000 deleted file mode 100644 index 0515125..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetool.css0-7000 +++ /dev/null @@ -1 +0,0 @@ -.yk-w1190{overflow-x:hidden}.body-offset-w1190{padding-left:160px;overflow-x:hidden}.body-offset-w970{padding-left:50px}.body-offset-mini{padding-left:20px}.yk-sidebar-position{position:fixed;_position:absolute;left:0;top:0}.yk-sidebar{width:160px;height:100%;background:#f5f5f5;z-index:997;overflow:hidden}.yk-sidebar .split{width:160px;height:1px;border-bottom:1px solid #e1e1e1}.yk-sidebar .yk-side-menu .ykSideMenu{margin-top:60px;padding:15px 0 10px}.yk-sidebar .yk-side-menu .ykSideMenu li a{display:block;width:160px;height:40px;font-size:14px;color:#555;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:40px;text-indent:3.5em;position:relative;text-decoration:none}.yk-sidebar .yk-side-menu .ykSideMenu li a.selected:hover,.yk-sidebar .yk-side-menu .ykSideMenu li a.selected{background:#06a7e1;color:#fff}.yk-sidebar .yk-side-menu .ykSideMenu li a.selected:hover .icon-1,.yk-sidebar .yk-side-menu .ykSideMenu li a.selected .icon-1{background:url("../img/toolbar.png") no-repeat 0 0}.yk-sidebar .yk-side-menu .ykSideMenu li a.selected:hover .icon-2,.yk-sidebar .yk-side-menu .ykSideMenu li a.selected .icon-2{background:url("../img/toolbar.png") no-repeat 0 -30px}.yk-sidebar .yk-side-menu .ykSideMenu li a.selected:hover .icon-3,.yk-sidebar .yk-side-menu .ykSideMenu li a.selected .icon-3{background:url("../img/toolbar.png") no-repeat 0 -60px}.yk-sidebar .yk-side-menu .ykSideMenu li a.selected:hover .icon-4,.yk-sidebar .yk-side-menu .ykSideMenu li a.selected .icon-4{background:url("../img/toolbar.png") no-repeat 0 -90px}.yk-sidebar .yk-side-menu .ykSideMenu li a.selected:hover .icon-5,.yk-sidebar .yk-side-menu .ykSideMenu li a.selected .icon-5{background:url("../img/toolbar.png") no-repeat 0 -120px}.yk-sidebar .yk-side-menu .ykSideMenu li a:hover{background:#e7e7e7}.yk-sidebar .yk-side-menu .ykSideMenu li a div{position:absolute;top:50%;left:22px;margin-top:-8px;width:18px;height:16px}.yk-sidebar .yk-side-menu .ykSideMenu li a .icon-1{background:url("../img/toolbar.png") no-repeat -30px 0}.yk-sidebar .yk-side-menu .ykSideMenu li a .icon-2{background:url("../img/toolbar.png") no-repeat -30px -30px}.yk-sidebar .yk-side-menu .ykSideMenu li a .icon-3{background:url("../img/toolbar.png") no-repeat -30px -60px}.yk-sidebar .yk-side-menu .ykSideMenu li a .icon-4{background:url("../img/toolbar.png") no-repeat -30px -90px}.yk-sidebar .yk-side-menu .ykSideMenu li a .icon-5{background:url("../img/toolbar.png") no-repeat -30px -120px}.yk-sidebar .yk-side-menu .ykSideMenu li a .sub-update{width:8px;height:8px;border-radius:10px;position:absolute;top:14px;left:33px;background:#f00}.yk-sidebar .yk-side-menu .ykSideMenu li a .sub-update-num{background:#f00;border-radius:50%;color:#fff;text-indent:0;text-align:center;height:20px;line-height:20px;font-size:12px;width:20px;position:absolute;top:50%;margin-top:-10px;right:27px;left:auto}.yk-sidebar .yk-side-menu .ykSideMenu li a .sub-update-nonum{line-height:12px}.yk-sidebar .yk-side-sub{overflow-y:hidden;position:relative}.yk-sidebar .yk-side-sub .header{width:120px;height:18px;margin:15px auto;position:relative}.yk-sidebar .yk-side-sub .header h2{display:inline;margin-right:6px;font-size:14px;color:#909090;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:18px}.yk-sidebar .yk-side-sub .header a{font-size:12px;color:#555;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:18px}.yk-sidebar .yk-side-sub .header a:hover{color:#cd3311}.yk-sidebar .yk-side-sub .header .more-icon{display:block;position:absolute;cursor:pointer;top:0;right:0;width:14px;height:18px;background:url("../img/toolbar.png") no-repeat -50px -28px}.yk-sidebar .yk-side-sub .header .more-icon:hover{background:url("../img/toolbar.png") no-repeat -50px -58px}.yk-sidebar .yk-side-sub .sub-bd{min-height:150px}.yk-sidebar .yk-side-sub .sub-bd .mySub{margin-bottom:15px}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li.new-item{display:none;padding:0;height:30px;width:100%;position:relative}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li.new-item .bg-layer{width:100%;height:100%;background:#90d7f6;text-indent:9.5em;color:#fff;line-height:30px;font-size:12px}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li.new-item .content-layer{position:absolute;height:30px;padding:0 20px}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li.new-item .content-layer a{word-wrap:break-word;white-space:nowrap;text-overflow:ellipsis;height:30px;width:90px;text-decoration:none;overflow:hidden;display:inline-block;font-size:12px;color:#fff;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:30px}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li.new-item .content-layer a img{width:20px;height:20px;margin-right:10px;vertical-align:middle}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li{position:relative;height:30px;padding:0 20px}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li a{word-wrap:break-word;white-space:nowrap;text-overflow:ellipsis;height:30px;width:90px;text-decoration:none;overflow:hidden;display:inline-block;font-size:12px;color:#555;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:30px}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li a img{width:20px;height:20px;margin-right:10px;vertical-align:middle}.yk-sidebar .yk-side-sub .sub-bd .mySub ul.mySub-list li .updateNum{height:30px;font-size:12px;color:#909090;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:30px;position:absolute;top:0;right:20px}.yk-sidebar .yk-side-sub .sub-bd .split-inner{width:120px;height:1px;border-bottom:1px solid #e1e1e1;margin:0 auto}.yk-sidebar .yk-side-sub .sub-bd .recommend ul.rec-list li{position:relative;height:30px;padding:0 20px}.yk-sidebar .yk-side-sub .sub-bd .recommend ul.rec-list li a.info{word-wrap:break-word;white-space:nowrap;text-overflow:ellipsis;height:30px;width:90px;text-decoration:none;overflow:hidden;display:inline-block;font-size:12px;color:#555;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:30px}.yk-sidebar .yk-side-sub .sub-bd .recommend ul.rec-list li a.info img{width:20px;height:20px;margin-right:10px;vertical-align:middle}.yk-sidebar .yk-side-sub .sub-bd .recommend ul.rec-list li a.subBtn{display:none;cursor:pointer;text-decoration:none;font-size:12px;color:#3399e0;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:30px;position:absolute;top:0;right:15px}.yk-sidebar .yk-side-sub .sub-bd .recommend ul.rec-list li a.subBtn:hover{color:#cd3311}.yk-sidebar .yk-side-manage{width:160px;height:40px;font-size:14px;color:#3399e0;font-family:"Microsoft Yahei","微软雅黑","SimHei","黑体",Arial,sans-serif;line-height:40px;text-indent:4em;position:absolute;left:0;bottom:0;cursor:pointer;border-top:1px solid #e1e1e1;border- \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetool.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetool.js0-7000 deleted file mode 100644 index 2e42e01..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetool.js0-7000 +++ /dev/null @@ -1 +0,0 @@ -var sidebar={sideBar:null,sideBar_w970:null,sideBar_w970_custom:null,subEle:null,rightSidebar:null,closeIcon:null,subData:null,recData:null,isWide:!1,loadingImg:null,userInfoTip:null,sidebarMask:null,haveLoaded:!1,nHaveLoaded:!1,isNsidebarPopout:!1,init:function(){var e=this;e.initGlobalValue(),e.switchLinkOpen(),e.initSize(),e.checkToolSize(),e.hideNarrowBarInVpageInIE8AtLowWidth(),e.initGlobalEvents(),e.appendShowSubBtnInVpage()},initGlobalValue:function(){var e=this;e.sideBar=jQuery("#ykSideBar"),e.sideBar_w970=jQuery("#ykSidebar_w970"),e.sideBar_w970_custom=jQuery("#ykSidebar_w970_custom"),e.subEle=jQuery("#ykSideSub"),e.nSubEle=jQuery("#yknSideSub"),e.rightSidebar=jQuery("#rightSidebar"),e.closeIcon=e.rightSidebar.find(".closeIcon"),e.sidebarMask=jQuery("#sidebarMask"),e.loadingImg=jQuery('<img style="width: 64px;height: 62px;position: relative;top: 50%;left: 50%;margin:-31px 0 0 -32px; " src="http://static.youku.com/index/img/2013/loading_64.gif" alt="正在加载"/>'),e.userInfoTip=jQuery('<div class="detailTip"><iframe class="detailTip_mask" frameBorder="0" scrolling="no"></iframe><img src=""/><h2 class="userName"></h2><div id="tipSub" class="sub-btn">订阅</div><div class="arrow"></div></div>'),e.miniSidebar=jQuery("#miniSidebar")},initSize:function(){var e=sidebar,i=e.sideBar.height(),a=i-330,s=e.subEle.find("#subscribeBody")[0];if(e.subEle.height(a),s){var t=e.subEle.height()-48;jQuery(s).height(t)}var r=e.sideBar_w970[0]?e.sideBar_w970:e.sideBar_w970_custom,o=r.height(),n=o-410,d=jQuery("#yknSideSub");d.height(n)},checkToolSize:function(){var e=this,i=i=window.innerWidth||"CSS1Compat"==document.compatMode?document.documentElement.clientWidth:document.body.clientWidth,a=e.sideBar_w970[0],s=e.sideBar_w970[0]?e.sideBar_w970:e.sideBar_w970_custom;a&&(1400>i&&i>=1075?(e.isWide=!1,e.nHaveLoaded||e.loadSubDataToNsidebar(),e.sidebarMask.css({left:"-110px"})):i>=1400?(e.isWide=!0,e.haveLoaded||e.loadSubscribeData(),e.sidebarMask.css({left:"0px"})):1075>i&&(e.isWide=!1,e.sidebarMask.css({left:"-141px"}),s.css({display:"block",left:"-50px"})))},appendShowSubBtnInVpage:function(){var e=this,i=jQuery('<a class="showSubBtn"><p class = "text">订阅<br/>列表</p><div class="icon"></div></a>');if(e.sideBar_w970_custom[0]){var a=e.sideBar_w970_custom.find("#yknSideSub");i.on("click",function(){i.remove(),e.loadSubDataToNsidebar()}).appendTo(a)}},switchLinkOpen:function(){var e=this,i=document.location.href,a=/v\.youku\.com\/v_show/i,s=a.test(i);s?(e.sideBar.find("a:not(.subBtn)").attr("target","lsidetool"),e.sideBar_w970_custom.find("a").attr("target","lsidetool")):(e.sideBar.find("a:not(.subBtn)").attr("target","_self"),e.sideBar_w970.find("a").attr("target","_self"))},hideNarrowBarInVpageInIE8AtLowWidth:function(){var e=this,i=document.location.href,a=/v\.youku\.com\/v_show/i,s=a.test(i);if(s){var t=window.innerWidth;"number"!=typeof t&&(t="CSS1Compat"==document.compatMode?document.documentElement.clientWidth:document.body.clientWidth,1100>t||t>1255&&1290>t?(e.sideBar_w970_custom.hide(),e.sidebarMask.css({left:"-160px"})):(e.sideBar_w970_custom.show(),e.sidebarMask.css({left:"-110px"})))}},switchLsideTool:function(){var e=this,i=jQuery(document.body),a=window.innerWidth,s=e.sideBar_w970.children().length,t=e.sideBar_w970[0]?e.sideBar_w970:e.sideBar_w970_custom;switch("number"!=typeof a&&(a="CSS1Compat"==document.compatMode?document.documentElement.clientWidth:document.body.clientWidth),!0){case 1075>a:e.isWide=!1,t.is(":animated")||t.css({display:"block"}).animate({left:"-50px"},200,function(){e.miniSidebar.show(),e.isNsidebarPopout=!0}),e.sideBar.is(":animated")||e.sidebarMask.is(":animated")||e.sideBar.animate({left:"-160px"},300),e.sidebarMask.css({left:"-141px"}),i.hasClass("body-offset-w1190")?i.removeClass("body-offset-w1190").addClass("body-offset-mini"):i.hasClass("body-offset-w970")?i.removeClass("body-offset-w970").addClass("body-offset-mini"):i.addClass("body-offset-mini");break;case 1400>a&&a>=1075:e.isWide=!1,t.is(":animated")||t.css({display:"block"}).animate({left:"0px"},200,function(){e.miniSidebar.hide(),e.isNsidebarPopout=!1}),e.sidebarMask.css({left:"-110px"}),s&&(e.nHaveLoaded||e.loadSubDataToNsidebar(),e.sideBar.is(":animated")||e.sidebarMask.is(":animated")||e.sideBar.animate({left:"-160px"},300)),i.hasClass("body-offset-w1190")?i.removeClass("body-offset-w1190").addClass("body-offset-w970"):i.hasClass("body-offset-mini")?i.removeClass("body-offset-mini").addClass("body-offset-w970"):i.addClass("body-offset-w970");break;case a>=1400:e.isNsidebarPopout=!1,s?(e.isWide=!0,i.hasClass("body-offset-w970")?i.removeClass("body-offset-w970").addClass("body-offset-w1190"):i.hasClass("body-offset-mini")?i.removeClass("body-offset-mini").addClass("body-offset-w1190"):i.addClass("body-offset-w1190"),e.sidebarMask.css({left:"0px"}),e.sideBar.is(":animated")||e.sidebarMask.is(":animated")||e.sideBar.css({display:"block"}).animate({left:"0px"},300,function(){e.sideBar_w970.css({display:"block",left:"-50px"}),e.haveLoaded||e.loadSubscribeData()})):(e.sidebarMask.css({left:"-110px"}),t.is(":animated")||"-50px"!=t.css("left")||t.css({display:"block"}).animate({left:"0px"},200,function(){e.miniSidebar.hide()}))}},switchNavTab:function(e){var i,a,s=jQuery(".ykSideMenu"),t=s.length;if(t)for(var r=0;t>r;r++)a=jQuery(s[r]),i=a.children(),jQuery(i[e]).find("a").addClass("selected")},initGlobalEvents:function(){var e=this,i=null,a=e.sideBar_w970[0]?e.sideBar_w970:e.sideBar_w970_custom;jQuery(window).resize(function(){e.initSize(),e.switchLsideTool(),e.hideNarrowBarInVpageInIE8AtLowWidth()}),e.miniSidebar.on("click",function(){e.sidebarMask.css({left:"-110px"}),a.css({display:"block",left:"-50px"}).animate({left:"0px"},300,function(){e.miniSidebar.hide(),e.isNsidebarPopout=!0,e.sideBar_w970[0]&&!e.nHaveLoaded&&e.loadSubDataToNsidebar()})}),a.on("mouseleave",function(){e.userInfoTip.remove(),e.isNsidebarPopout&&"0px"==a.css("left")&&(i=setTimeout(function(){e.sidebarMask.css({left:"-160px"}),a.is(":animated")||a.animate({left:"-50px"},200,function(){e.miniSidebar.show(),clearTimeout(i)})},3e3))}).on("mouseenter",function(){clearTimeout(i)}).on("click",function(e){e.stopPropagation()}),jQuery("body").on("click",function(){e.isNsidebarPopout&&"0px"==a.css("left")&&(e.sidebarMask.css({left:"-160px"}),a.is(":animated")||a.animate({left:"-50px"},200,function(){e.miniSidebar.show(),clearTimeout(i)}))})},loadSubDataToNsidebar:function(){var e=this,i=jQuery("#yknSideSub").height(),a=i/44;a=Math.floor(a),a=a>15?15:a,e.loadSubscribeData(a,2)},loadSubscribeData:function(e,i){var a=this,s={page_length:e||20,type:i||2};a.isWide?a.loadingImg.css({width:"64px",height:"62px",margin:"-31px 0 0 -32px"}).appendTo(a.subEle):a.loadingImg.css({width:"40px",height:"40px",margin:"-20px 0 0 -20px"}).appendTo(a.nSubEle),jQuery.ajax({url:"http://www.youku.com/index/getUserSubList",type:"GET",data:s,dataType:"JSONP",timeout:5e3,success:function(i){a.subData=i,0===i.length?(e-=1,a.getRecmmondData(e)):a.i \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetoolresize.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetoolresize.js0-7000 deleted file mode 100644 index 0f3e8a3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/lsidetoolresize.js0-7000 +++ /dev/null @@ -1,16 +0,0 @@ - (function() { - var preSet = function() { - var w = document.documentElement ? document.documentElement.clientWidth : document.body.clientWidth, - R = 1400, - r = 1075, - b = Element.extend(document.body); - if(w < R && w >= r){ - b.addClassName('body-offset-w970').removeClassName('body-offset-w1190'); - }else if(w >= R && lsidetooltype == "w"){ - b.addClassName('body-offset-w1190').removeClassName('body-offset-w970'); - }else if(w < r){ - b.addClassName('body-offset-mini').removeClassName('body-offset-w970').removeClassName('body-offset-w1190'); - } - }; - preSet(); -})(); diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/music.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/music.png0-7000 deleted file mode 100644 index 86717da..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/music.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/popup.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/popup.js0-7000 deleted file mode 100644 index 2cc903c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/popup.js0-7000 +++ /dev/null @@ -1,64 +0,0 @@ -if(!Array.prototype.push){Array.prototype.push=function (){var startLength=this.length;for(var i=0;i<arguments.length;i++)this[startLength+i]=arguments[i];return this.length;}}; -function G(){var elements=new Array();for(var i=0;i<arguments.length;i++){var element=arguments[i];if(typeof element=='string')element=document.getElementById(element);if(arguments.length==1)return element;elements.push(element);};return elements;}; -Function.prototype.bindAsEventListener=function (object){var __method=this;return function (event){__method.call(object,event||window.event);};}; -Object.extend_p=function (destination,source){for(property in source){destination[property]=source[property];};return destination;}; -if(!window.Event){var Event=new Object();};Object.extend_p(Event,{observers:false,element:function (event){return event.target||event.srcElement;},isLeftClick:function (event){return (((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},pointerX:function (event){return event.pageX||(event.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft));},pointerY:function (event){return event.pageY||(event.clientY+(document.documentElement.scrollTop||document.body.scrollTop));},stop:function (event){if(event.preventDefault){event.preventDefault();event.stopPropagation();}else {event.returnValue=false;event.cancelBubble=true;};},findElement:function (event,tagName){var element=Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase())))element=element.parentNode;return element;},_observeAndCache:function (element,name,observer,useCapture){if(!this.observers)this.observers=[];if(element.addEventListener){this.observers.push([element,name,observer,useCapture]);element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){this.observers.push([element,name,observer,useCapture]);element.attachEvent('on'+name,observer);};},unloadCache:function (){if(!Event.observers)return ;for(var i=0;i<Event.observers.length;i++){Event.stopObserving.apply(this,Event.observers[i]);Event.observers[i][0]=null;};Event.observers=false;},observe:function (element,name,observer,useCapture){var element=G(element);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent))name='keydown';this._observeAndCache(element,name,observer,useCapture);},stopObserving:function (element,name,observer,useCapture){var element=G(element);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent))name='keydown';if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element.detachEvent){element.detachEvent('on'+name,observer);};}});Event.observe(window,'unload',Event.unloadCache,false); -var Class_Pop=function (){var _class=function (){this.initialize.apply(this,arguments);};for(i=0;i<arguments.length;i++){superClass=arguments[i];for(member in superClass.prototype){_class.prototype[member]=superClass.prototype[member];};};_class.child=function (){return new Class(this);};_class.extend_p=function (f){for(property in f){_class.prototype[property]=f[property];};};return _class;}; -function space(flag){if(flag=="begin"){var ele=document.getElementById("ft");if(typeof(ele)!="undefined"&&ele!=null)ele.id="ft_popup";ele=document.getElementById("usrbar");if(typeof(ele)!="undefined"&&ele!=null)ele.id="usrbar_popup";}else if(flag=="end"){var ele=document.getElementById("ft_popup");if(typeof(ele)!="undefined"&&ele!=null)ele.id="ft";ele=document.getElementById("usrbar_popup");if(typeof(ele)!="undefined"&&ele!=null)ele.id="usrbar";};}; -var Popup=new Class_Pop(); -Popup.prototype={ - iframeIdName:'ifr_popup', - initialize:function (config){ - this.config=Object.extend_p({contentType:1,isHaveTitle:true,scrollType:'no',isBackgroundCanClick:false,isSupportDraging:true,isShowShadow:true,isReloadOnClose:true,width:400,height:300,boxstyle:'blue'},config||{}); - this.info={shadowWidth:4,title:"",contentUrl:"",contentHtml:"",callBack:null,parameter:null,confirmCon:"",alertCon:"",someHiddenTag:"select,object,video",someHiddenEle:"",overlay:0,coverOpacity:60,framename:'ifr_popup'}; - this.color={cColor:"#000000",bColor:"#FFFFFF",tColor:"#709CD2",wColor:"#FFFFFF"}; - this.winform = null; - this.winbox = null; - this.overlay = null; - this.dropClass = null; - this.someToHidden=[]; - if(!this.config.isHaveTitle)this.config.isSupportDraging=false; - this.iniBuild(); - }, - setContent:function (arrt,val){ - if(val!=''){ - switch(arrt){ - case 'width':this.config.width=val; break; - case 'height':this.config.height=val;break; - case 'title':this.info.title=val;break; - case 'contentUrl':this.info.contentUrl=val;break; - case 'contentHtml':this.info.contentHtml=val;break; - case 'callBack':this.info.callBack=val;break; - case 'parameter':this.info.parameter=val;break; - case 'confirmCon':this.info.confirmCon=val;break; - case 'alertCon':this.info.alertCon=val;break; - case 'someHiddenTag':this.info.someHiddenTag=val;break; - case 'someHiddenEle':this.info.someHiddenEle=val;break; - case 'overlay':this.info.overlay=val;break; - case 'framename':this.info.framename=val;break; - case 'boxstyle':this.config.boxstyle=val;break; - }; - }; - }, - setContents:function(options){ - if(null == options || {} == options) return; - for(var key in options) this.setContent(key, options[key]); - }, - iniBuild:function (){ - this.winform = document.createElement('div'); - document.body.appendChild(this.winform); - }, - build:function (){ - var pos = this.getPos(); - var barheight = this.config.boxstyle=='gray' ? 31 : 40; - this.config.height += this.config.boxstyle=='gray' ? 0 : 18; - var poshandley = barheight/2; - var bordercolor = this.config.boxstyle=='gray' ? '#c6c6c6' : '#9dccf6'; - var formstyle = 'z-index:10000;position:absolute;top:0;left:0;width:100%;height:100%;'; - var winstyle = 'z-index:2;position:absolute;top:'+pos.y+'px;left:'+pos.x+'px;width:'+this.config.width+'px;height:'+this.config.height+'px;' - var boxstyle = 'z-index:2;position:absolute;top:0;left:0;width:'+this.config.width+'px;height:'+this.config.height+'px;background:#fff;border:1px solid '+bordercolor+';'; - var barstyle = this.config.boxstyle=='gray' ? - 'position:relative;height:20ppx;padding:5px 10px;overflow:hidden;border-bottom:1px solid #c6c6c6;background:#e6e6e6 url(http://static.youku.com/index/img/master.png) repeat-x 0 -1568px;': - 'position:relative;height:20px;padding:10px;overflow:hidden;' - var handlestyle = 'cursor:pointer;position:absolute;right:10px;top:'+poshandley+'px;margin-top:-9px;width:18px;height:18px;overflow:hidden;background:url(http://static.youku.com/index/img/master.png) no-repeat -192px -172px;'; - var shadowstyle = 'z-index:1;position:absolute;top:6px;left:6px;width:'+this.config.width+'px;hei \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/prototype.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/prototype.js0-7000 deleted file mode 100644 index ff52e1e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/prototype.js0-7000 +++ /dev/null @@ -1 +0,0 @@ -eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('E 1k={by:\'1.6.1\',2V:(q(){E 7a=7P.7X;E cG=L.1x.2o.1M(1g.g9)==\'[17 77]\';o{56:!!1g.7h&&!cG,77:cG,67:7a.2I(\'gK/\')>-1,8Q:7a.2I(\'8Q\')>-1&&7a.2I(\'dc\')===-1,cY:/gN.*gz.*dd/.28(7a)}})(),3J:{8F:!!U.31,aL:!!U.aG,6N:(q(){E 80=1g.I||1g.7Y;o!!(80&&80.1x)})(),8q:(q(){if(2d 1g.gR!==\'1H\')o 1h;E 1P=U.2h(\'1P\');E 1r=U.2h(\'1r\');E cH=1d;if(1P[\'5D\']&&(1P[\'5D\']!==1r[\'5D\'])){cH=1h}1P=1r=14;o cH})()},9i:\'<4C[^>]*>([\\\\S\\\\s]*?)<\\/4C>\',fi:/^\\/\\*-i0-([\\s\\S]*)\\*\\/\\s*$/,3q:q(){},K:q(x){o x}};if(1k.2V.cY)1k.3J.8q=1d;E 5B={};E fW={fV:q(){E 9X;Y(E i=0,M=1y.M;i<M;i++){E d5=1y[i];1J{9X=d5();2m}1N(e){}}o 9X}};E 2x=(q(){q cF(){};q 2l(){E 2k=14,3s=$A(1y);if(L.2T(3s[0]))2k=3s.bM();q 2c(){C.2p.3x(C,1y)}L.18(2c,2x.1e);2c.cx=2k;2c.er=[];if(2k){cF.1x=2k.1x;2c.1x=1q cF;2k.er.1f(2c)}Y(E i=0;i<3s.M;i++)2c.52(3s[i]);if(!2c.1x.2p)2c.1x.2p=1k.3q;2c.1x.80=2c;o 2c}q 52(2a){E 4n=C.cx&&C.cx.1x;E 3s=L.4L(2a);if(!L.4L({2o:1h}).M){if(2a.2o!=L.1x.2o)3s.1f("2o");if(2a.7c!=L.1x.7c)3s.1f("7c")}Y(E i=0,M=3s.M;i<M;i++){E 1B=3s[i],G=2a[1B];if(4n&&L.2T(G)&&G.9f().3F()=="$4U"){E 1z=G;G=(q(m){o q(){o 4n[m].3x(C,1y)}})(1B).4A(1z);G.7c=1z.7c.2q(1z);G.2o=1z.2o.2q(1z)}C.1x[1B]=G}o C}o{2l:2l,1e:{52:52}}})();(q(){E 9g=L.1x.2o;q 18(6v,2a){Y(E 1B in 2a)6v[1B]=2a[1B];o 6v}q 20(17){1J{if(26(17))o\'1H\';if(17===14)o\'14\';o 17.20?17.20():2f(17)}1N(e){if(e 8R hD)o\'...\';4K e}}q 2g(17){E 1t=2d 17;5d(1t){2s\'1H\':2s\'q\':2s\'hG\':o;2s\'f2\':o 17.2o()}if(17===14)o\'14\';if(17.2g)o 17.2g();if(4w(17))o;E V=[];Y(E 1B in 17){E G=2g(17[1B]);if(!26(G))V.1f(1B.2g()+\': \'+G)}o\'{\'+V.2W(\', \')+\'}\'}q 3X(17){o $H(17).3X()}q 4y(17){o 17&&17.4y?17.4y():2f.6y(17)}q 4L(17){E V=[];Y(E 1B in 17)V.1f(1B);o V}q 29(17){E V=[];Y(E 1B in 17)V.1f(17[1B]);o V}q 1V(17){o 18({},17)}q 4w(17){o!!(17&&17.3u==1)}q 4u(17){o 9g.1M(17)=="[17 4B]"}q 7f(17){o 17 8R 53}q 2T(17){o 2d 17==="q"}q 3e(17){o 9g.1M(17)=="[17 2f]"}q 4E(17){o 9g.1M(17)=="[17 5s]"}q 26(17){o 2d 17==="1H"}18(L,{18:18,20:20,2g:2g,3X:3X,4y:4y,4L:4L,29:29,1V:1V,4w:4w,4u:4u,7f:7f,2T:2T,3e:3e,4E:4E,26:26})})();L.18(hI.1x,(q(){E 1Z=4B.1x.1Z;q 2S(22,25){E 93=22.M,M=25.M;1R(M--)22[93+M]=25[M];o 22}q 72(22,25){22=1Z.1M(22,0);o 2S(22,25)}q 9f(){E 3T=C.2o().1j(/^[\\s\\(]*q[^(]*\\(([^)]*)\\)/)[1].1A(/\\/\\/.*?[\\r\\n]|\\/\\*(?:.|[\\r\\n])*?\\*\\//g,\'\').1A(/\\s+/g,\'\').3h(\',\');o 3T.M==1&&!3T[0]?[]:3T}q 2q(1G){if(1y.M<2&&L.26(1y[0]))o C;E 3Q=C,25=1Z.1M(1y,1);o q(){E a=72(25,1y);o 3Q.3x(1G,a)}}q 9d(1G){E 3Q=C,25=1Z.1M(1y,1);o q(19){E a=2S([19||1g.19],25);o 3Q.3x(1G,a)}}q 5R(){if(!1y.M)o C;E 3Q=C,25=1Z.1M(1y,0);o q(){E a=72(25,1y);o 3Q.3x(C,a)}}q 7b(6K){E 3Q=C,25=1Z.1M(1y,1);6K=6K*bd;o 1g.9u(q(){o 3Q.3x(3Q,25)},6K)}q 4x(){E 25=2S([0.hB],1y);o C.7b.3x(C,25)}q 4A(3P){E 3Q=C;o q(){E a=2S([3Q.2q(C)],1y);o 3P.3x(C,a)}}q 4N(){if(C.bZ)o C.bZ;E 3Q=C;o C.bZ=q(){E a=2S([C],1y);o 3Q.3x(14,a)}}o{9f:9f,2q:2q,9d:9d,5R:5R,7b:7b,4x:4x,4A:4A,4N:4N}})());dY.1x.2g=q(){o\'"\'+C.hU()+\'-\'+(C.hZ()+1).4v(2)+\'-\'+C.hS().4v(2)+\'T\'+C.hN().4v(2)+\':\'+C.hQ().4v(2)+\':\'+C.hs().4v(2)+\'Z"\'};41.1x.1j=41.1x.28;41.9D=q(6Y){o 2f(6Y).1A(/([.*+?^=!:${}()|[\\]\\/\\\\])/g,\'\\\\$1\')};E d8=2x.2l({2p:q(1T,4T){C.1T=1T;C.4T=4T;C.7d=1d;C.82()},82:q(){C.3p=ef(C.7e.2q(C),C.4T*bd)},cD:q(){C.1T(C)},84:q(){if(!C.3p)o;cW(C.3p);C.3p=14},7e:q(){if(!C.7d){1J{C.7d=1h;C.cD();C.7d=1d}1N(e){C.7d=1d;4K e}}}});L.18(2f,{6y:q(G){o G==14?\'\':2f(G)},c1:{\'\\b\':\'\\\\b\',\'\\t\':\'\\\\t\',\'\\n\':\'\\\\n\',\'\\f\':\'\\\\f\',\'\\r\':\'\\\\r\',\'\\\\\':\'\\\\\\\\\'}});L.18(2f.1x,(q(){q ch(2X){if(L.2T(2X))o 2X;E 6Z=1q 3v(2X);o q(1j){o 6Z.31(1j)}}q 6U(23,2X){E 1v=\'\',2a=C,1j;2X=ch(2X);if(L.3e(23))23=41.9D(23);if(!(23.M||23.2a)){2X=2X(\'\');o 2X+2a.3h(\'\').2W(2X)+2X}1R(2a.M>0){if(1j=2a.1j(23)){1v+=2a.1Z(0,1j.1l);1v+=2f.6y(2X(1j));2a=2a.1Z(1j.1l+1j[0].M)}1a{1v+=2a,2a=\'\'}}o 1v}q cz(23,2X,48){2X=ch(2X);48=L.26(48)?1:48;o C.6U(23,q(1j){if(--48<0)o 1j[0];o 2X(1j)})}q 8Y(23,1o){C.6U(23,1o);o 2f(C)}q cB(M,6X){M=M||30;6X=L.26(6X)?\'...\':6X;o C.M>M?C.1Z(0,M-6X.M)+6X:2f(C)}q 3M(){o C.1A(/^\\s+/,\'\').1A(/\\s+$/,\'\')}q 9m(){o C.1A(/<\\w+(\\s+("[^"]*"|\'[^\']*\'|[^>])+)?>|<\\/\\w+>/gi,\'\')}q 4f(){o C.1A(1q 41(1k.9i,\'6d\'),\'\')}q 7s(){E gq=1q 41(1k.9i,\'6d\');E gw=1q 41(1k.9i,\'im\');o(C.1j(gq)||[]).3g(q(gu){o(gu.1j(gw)||[\'\',\'\'])[1]})}q 4J(){o C.7s().3g(q(4C){o 55(4C)})}q cC(){E 9j=1y.M>0?1y[0]:1h;E s=C.1A(/&/g,\'&gs;\').1A(/</g,\'&gv;\').1A(/>/g,\'&gt;\');if(9j)s=s.1A(/"/g,\'&ga;\').1A(/\\\'/g,\'&#gb;\');o s}q cE(){E 9j=1y.M>0?1y[0]:1h;E s=C.9m().1A(/&gv;/g,\'<\').1A(/&gt;/g,\'>\').1A(/&gs;/g,\'&\');if(9j)s=s.1A(/&ga;/g,\'"\').1A(/&#gb;/g,"\'");o s}q 61(g0){E 1j=C.3M().1j(/([^?#]*)(#.*)?$/);if(!1j)o{};o 1j[1].3h(g0||\'&\').3L({},q(3k,1K){if((1K=1K.3h(\'=\'))[0]){E 1s=bI(1K.bM());E G=1K.M>1?1K.2W(\'=\'):1K[0];if(G!=1H)G=bI(G);if(1s in 3k){if(!L.4u(3k[1s]))3k[1s]=[3k[1s]];3k[1s].1f(G)}1a 3k[1s]=G}o 3k})}q 3n(){o C.3h(\'\')}q 5x(){o C.1Z(0,C.M-1)+2f.hm(C.c3(C.M-1)+1)}q 51(48){o 48<1?\'\':1q 4B(48+1).2W(C)}q 6I(){E 5f=C.3h(\'-\'),4c=5f.M;if(4c==1)o 5f[0];E cw=C.6D(0)==\'-\'?5f[0].6D(0).2r()+5f[0].4Y(1):5f[0];Y(E i=1;i<4c;i++)cw+=5f[i].6D(0).2r()+5f[i].4Y(1);o cw}q 6u(){o C.6D(0).2r()+C.4Y(1).2B()}q bA(){o C.1A(/::/g,\'/\').1A(/([A-Z]+)([A-Z][a-z])/g,\'$f1$2\').1A(/([a-z\\d])([A-Z])/g,\'$f1$2\').1A(/-/g,\'8C\').2B()}q aA(){o C.1A(/8C/g,\'-\')}q 20(fq){E c4=C.1A(/[\\bY-\\c8\\\\]/g,q(9n){if(9n in 2f.c1){o 2f.c1[9n]}o\'\\\\fs\'+9n.c3().4v(2,16)});if(fq)o\'"\'+c4.1A(/"/g,\'\\\\"\')+\'"\';o"\'"+c4.1A(/\'/g,\'\\\\\\\'\')+"\'"}q 2g(){o C.20(1h)}q 7n(2C){o C.1A(2C||1k.fi,\'$1\')}q 9l(){E 6Y=C;if(6Y.4H())o 1d;6Y=C.1A(/\\\\./g,\'@\').1A(/"[^"\\\\\\n\\r]*"/g,\'\');o(/^[,:{}\\[\\]0-9.\\-+gp-u \\n\\r\\t]*$/).28(6Y)}q 4V(f3){E 3O=C.7n();1J{if(!f3||3O.9l())o 55(\'(\'+3O+\')\')}1N(e){}4K 1q hc(\'hf hg 78 2Z: \'+C.20())}q 1F(23){o C.2I(23)>-1}q 7N(23){o C.2I(23)===0}q 8V(23){E d=C.M-23.M;o d>=0&&C.7r(23)===d}q 59(){o C==\'\'}q 4H(){o/^\\s*$/.28(C)}q 98(17,23){o 1q 3v(C,23).31(17)}o{6U:6U,cz:cz,8Y:8Y,cB:cB,3M:2f.1x.eX?2f.1x.eX:3M,9m:9m,4f:4f,7s:7s,4J:4J,cC:cC,cE:cE,61:61,hh:61,3n:3n,5x:5x,51:51,6I:6I,6u:6u,bA:bA,aA:aA,20:20,2g:2g,7n:7n,9l:9l,4V:4V,1F:1F,7N:7N,8V:8V,59:59,4H:4H,98:98}})());E 3v=2x.2l({2p:q(6Z,23){C.6Z=6Z.2o();C.23=23||3v.fd},31:q(17){if(17&&L.2T(17.ag))17=17.ag();o C.6Z.6U(C.23,q(1j){if(17==14)o(1j[1]+\'\');E 5N=1j[1]||\'\';if(5N==\'\\\\\')o 1j[2];E 7p=17,7o=1j[3];E 23=/^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/;1j=23.aP(7o);if(1j==14)o 5N;1R(1j!=14){E fr=1j[1].7N(\'[\')?1j[2].1A(/\\\\\\\\]/g,\']\'):1j[1];7p=7p[fr];if(14==7p||\'\'==1j[3])2m;7o=7o.4Y(\'[\'==1j[3]?1j[1].M:1j[0].M);1j=23.aP(7o)}o 5N+2f.6y(7p)})}});3v.fd=/(^|.|\\r|\\n)(#\\{(.*?)\\})/;E $2m={};E 5w=(q(){q 1E(1o,1G){E 1l=0;1J{C.3a(q(G){1o.1M(1G,G,1l++)})}1N( \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qfooter.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qfooter.css0-7000 deleted file mode 100644 index 30aa130..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qfooter.css0-7000 +++ /dev/null @@ -1,38 +0,0 @@ -@charset "utf-8"; -.yk-footer{min-width:990px;margin-bottom:20px;_margin-bottom:0;} -.yk-footer a,.yk-footer label,.yk-footer p,.yk-footer b,.yk-footer .copyright{line-height:20px;font-family:arial, helvetica, verdana, tahoma, sans-serif;} -.yk-footer .yk-footer-con{border-top:2px solid #ddd;overflow:hidden;width:970px;margin-left:auto;margin-right:auto;} -.yk-footer a{color:#555555;text-decoration:none;} -.yk-footer a:hover{color:#cc3311;} -.yk-footer ul,.yk-footer li,.yk-footer p{white-space:nowrap;padding:0;margin:0;} -.yk-footer .icon-footer-icp,.yk-footer .icon-footer-union,.yk-footer .icon-footer-report,.yk-footer .icon-footer-submit,.yk-footer .icon-footer-icbu, -.yk-footer .qcode,.yk-footer button{background-image:url("/index/img/footer/footer.png");background-repeat:no-repeat;} -.yk-footer .icon-footer-icp,.yk-footer .icon-footer-union,.yk-footer .icon-footer-report,.yk-footer .icon-footer-submit,.yk-footer .icon-footer-icbu{width:16px;height:16px;vertical-align:middle;*line-height:10px;*float:left;display:inline-block;*display:inline;*zoom:1;*font-size:0;} -.yk-footer .icon-footer-icp{background-position:0 0;} -.yk-footer .icon-footer-union{background-position:-16px 0;} -.yk-footer .icon-footer-report{background-position:-32px 0;} -.yk-footer .icon-footer-submit{background-position:-48px 0;} -.yk-footer .icon-footer-icbu{background-position:-64px 0;} -.yk-footer .footer-link{font-size:0;margin:20px 0 40px;margin-right:-40px;word-spacing:-3px} -.yk-footer ul{list-style:none;display:inline-block;*display:inline;*zoom:1;margin-right:26px;font-size:0;word-spacing:-6px;} -.yk-footer .narrow{margin-right:5px;*margin-right:15px;} -.yk-footer li{color:#909090;margin-bottom:8px;*margin-left:-12px;*margin-right:-12px;font-size:0;word-spacing:-3px;line-height:1em;word-spacing:-3px} -.yk-footer li a{margin-right:12px;font-size:12px;word-spacing:0;} -.yk-footer li label{font-size:12px;} -.yk-footer label a{margin-right:0;} -.yk-footer .cert{margin:20px 0 40px;margin-right:-100px;color:#909090;font-size:0;vertical-align:top;} -.yk-footer .cert .cert-list{display:inline-block;*display:inline;*zoom:1;font-size:12px;margin-right:48px;*margin-right:55px;vertical-align:top;} -.yk-footer .cert p{line-height:16px;margin-bottom:8px;vertical-align:middle;} -.yk-footer .cert p span,.yk-footer .cert p a{font-size:12px;*display:inline;line-height:16px;} -.yk-footer .cert b{font-weight:normal;} -.yk-footer .qcode{background-position:0 -65px;width:105px;height:90px;display:inline-block;*display:inline;*zoom:1;padding-left:110px;} -.yk-footer .qcode .wrap{display:inline-block;padding:18px 0;line-height:25px;} -.yk-footer .qcode .title{font-size:16px;display:inline-block;} -.yk-footer .copyright{clear:both;text-align:center;color:#909090;font-size:12px;} -.yk-w970 .yk-footer-con{width:970px;} -.yk-w1190 .yk-footer-con{width:1190px;} -.yk-w1190 .yk-footer .footer-link{margin-right:-80px;} -.yk-w1190 .yk-footer ul{margin-right:76px;} -.yk-w1190 .yk-footer .narrow{margin-right:10px;*margin-right:20px;} -.yk-w1190 .yk-footer .cert{margin-right:-123px;*margin-right:-90px;} -.yk-w1190 .yk-footer .cert-list{margin-right:108px;*margin-right:115px;} diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qheader.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qheader.css0-7000 deleted file mode 100644 index 53900aa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qheader.css0-7000 +++ /dev/null @@ -1 +0,0 @@ -@charset "utf-8";.yk-header .ico-user-l2,.yk-header .ico-myspace-l2,.yk-header .ico-channels-l2,.yk-header .ico-videomanage-l2,.yk-header .ico-notifications-l2,.yk-header .ico-upload-l2,.yk-header .ico-mydrama-l2,.yk-header .ico-member-l2,.yk-header .ico-VR-l2,.yk-header .ico-subscription-l2,.yk-header .ico-favorite-l2,.yk-header .ico-record-l2,.yk-header .ico-sharing-l2,.yk-header .caret,.yk-header .yk-hpanel-ico,.yk-nav .caret,.yk-nav .ico-toggle,.yk-nav .ico-setting,.yk-nav .ico-addsub,.yk-ucenter .yk-playrecords .yk-records .records-list .r-del,.yk-ucenter .yk-playrecords .yk-notice .yk-notice-success .ico-notice-ok,.yk-header .yk-so-box button,.yk-ucenter .yk-msgbox .handle i,.yk-ucenter .yk-msgbox .videomsg .hint i,.yk-ucenter .yk-playrecords .yk-records .records-list .r-stat i{background:transparent url("/index/img/header/header.png") no-repeat}.reward-entry-integral{font-style:normal}.reward-integral-fake{z-index:999999;font-size:14px;color:#909090}.yk-header a,.yk-nav a{cursor:pointer;text-decoration:none;color:#555}.yk-header a:hover,.yk-nav a:hover{text-decoration:none;color:#c31}.yk-header ul,.yk-nav ul{list-style:none;padding:0;margin:0}.yk-header .splite,.yk-nav .splite{color:#909090}.yk-header .caret,.yk-nav .caret{overflow:hidden;display:inline-block;*display:inline;*zoom:1;width:8px;height:4px;line-height:0;font-size:0;vertical-align:middle;background-position:-120px -4px}.yk-header .ico-toggle,.yk-nav .ico-toggle{display:inline-block;*display:inline;*zoom:1;width:14px;height:12px;margin-top:-1px;*margin-top:3px;margin-right:5px;line-height:0;font-size:0;vertical-align:middle;background-position:0 -140px}.yk-header .ico-setting,.yk-nav .ico-setting{display:inline-block;*display:inline;*zoom:1;width:12px;height:12px;line-height:0;font-size:0;vertical-align:middle;background-position:-60px -140px;margin:-2px 5px 0 0}.yk-header .dropdown,.yk-nav .dropdown{position:relative}.yk-header .dropdown .handle,.yk-nav .dropdown .handle{cursor:default;z-index:3;position:absolute;top:0;left:0;padding:0 10px}.yk-header .dropdown .handle .caret,.yk-nav .dropdown .handle .caret{position:absolute;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;-o-transition:all .3s ease-in;transition:all .3s ease-in;-ms-transition:transform .3s ease-in}.yk-header .dropdown .panel,.yk-nav .dropdown .panel{display:none;z-index:2;position:absolute;top:100%;left:0;padding:19px}.yk-header .dropdown .mask,.yk-nav .dropdown .mask{display:none;z-index:1;position:absolute;top:60px;left:0;opacity:0;filter:alpha(opacity=0);width:0;height:0;border:none;background:#fff}.yk-header .dropdown-open .handle,.yk-nav .dropdown-open .handle,.yk-header .dropdown-open .panel,.yk-nav .dropdown-open .panel{border:1px solid #ddd;background:#fff}.yk-header .dropdown-open .handle,.yk-nav .dropdown-open .handle{border-bottom:none}.yk-header .dropdown-open .handle .caret,.yk-nav .dropdown-open .handle .caret{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);-ms-transform:rotate(0)}.yk-header .dropdown-open .panel,.yk-nav .dropdown-open .panel,.yk-header .dropdown-open .ico-arrow-top-grey,.yk-nav .dropdown-open .ico-arrow-top-grey,.yk-header .dropdown-open .mask,.yk-nav .dropdown-open .mask{display:block}.yk-header .w970-show,.yk-nav .w970-show{display:block}.yk-header .w1190-show,.yk-nav .w1190-show{display:none}.yk-header .ico-user-l2,.yk-header .ico-myspace-l2,.yk-header .ico-channels-l2,.yk-header .ico-videomanage-l2,.yk-header .ico-notifications-l2,.yk-header .ico-upload-l2,.yk-header .ico-mydrama-l2,.yk-header .ico-member-l2,.yk-header .ico-VR-l2,.yk-header .ico-subscription-l2,.yk-header .ico-favorite-l2,.yk-header .ico-record-l2,.yk-header .ico-sharing-l2{display:inline-block;*display:inline;*zoom:1;font-size:0;line-height:0;vertical-align:middle}.yk-header .ico-user-l2,.yk-header .ico-myspace-l2,.yk-header .ico-channels-l2,.yk-header .ico-videomanage-l2,.yk-header .ico-notifications-l2,.yk-header .ico-upload-l2,.yk-header .ico-mydrama-l2,.yk-header .ico-member-l2,.yk-header .ico-VR-l2,.yk-header .ico-subscription-l2,.yk-header .ico-favorite-l2,.yk-header .ico-record-l2,.yk-header .ico-sharing-l2{width:20px;height:20px}.yk-header .ico-user-l2{background-position:0 0}.yk-header .ico-myspace-l2{background-position:-20px 0}.yk-header .ico-channels-l2{background-position:-40px 0}.yk-header .ico-videomanage-l2{background-position:0 -20px}.yk-header .ico-notifications-l2{background-position:-20px -20px}.yk-header .ico-upload-l2{background-position:-40px -20px}.yk-header .ico-mydrama-l2{background-position:0 -40px}.yk-header .ico-member-l2{background-position:-20px -40px}.yk-header .ico-VR-l2{background-position:-40px -40px}.yk-header .ico-subscription-l2{background-position:0 -60px}.yk-header .ico-favorite-l2{background-position:-20px -60px}.yk-header .ico-record-l2{background-position:-40px -60px}.yk-header .ico-sharing-l2{background-position:0 -80px}.yk-header a:hover .ico-user-l2{background-position:-60px 0}.yk-header a:hover .ico-myspace-l2{background-position:-80px 0}.yk-header a:hover .ico-channels-l2{background-position:-100px 0}.yk-header a:hover .ico-videomanage-l2{background-position:-60px -20px}.yk-header a:hover .ico-notifications-l2{background-position:-80px -20px}.yk-header a:hover .ico-upload-l2{background-position:-100px -20px}.yk-header a:hover .ico-mydrama-l2{background-position:-60px -40px}.yk-header a:hover .ico-member-l2{background-position:-80px -40px}.yk-header a:hover .ico-VR-l2{background-position:-100px -40px}.yk-header a:hover .ico-subscription-l2{background-position:-60px -60px}.yk-header a:hover .ico-favorite-l2{background-position:-80px -60px}.yk-header a:hover .ico-record-l2{background-position:-100px -60px}.yk-header a:hover .ico-sharing-l2{background-position:-60px -80px}.yk-ucenter .yk-msgbox .handle i{background-position:-120px -11px}.yk-ucenter .yk-msgbox .handle:hover i{background-position:-120px -20px}.yk-ucenter .yk-msgbox .videomsg .hint .ico-new{background-position:-120px -60px}.yk-ucenter .yk-msgbox .videomsg .hint .ico-success{background-position:-120px -100px}.yk-ucenter .yk-msgbox .videomsg .hint .ico-notice{background-position:-120px -120px}.yk-ucenter .yk-msgbox .videomsg .hint .ico-subscription{background-position:-120px -185px}.dropdown .panel .yk-hpanel-loading{position:absolute;top:0;left:0;width:100%;height:100%}.dropdown .panel .yk-hpanel-loading .ico-loading-64{width:64px;height:64px;background:url(/index/img/2013/loading_64.gif) no-repeat;display:block;position:absolute;top:50%;left:50%;margin-top:-32px;margin-left:-32px;z-index:1}.yk-header{height:60px;position:absolute;top:0;left:0;width:100%}.yk-header-container{*zoom:1;width:100%;min-width:990px;background:#fff;border-bottom:solid 1px #e1e1e1;box-sizing:border-box;height:61px}.yk-header-container *{font-family:"Microsoft YaHei","微软雅黑",helvetica,arial,verdana,tahoma,sans-serif}.yk-header-container .mask{position:abso \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qheader.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qheader.js0-7000 deleted file mode 100644 index a82e803..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qheader.js0-7000 +++ /dev/null @@ -1,264 +0,0 @@ -(function(o){ -if(!o || o.QHeader){ return; } - -//global domain -document.domain = 'youku.com'; - -//define variable -var toDomain = function(s){ s = s.replace('http://', ''); if(s[s.length -1] == '/'){ s = s.substr(0, s.length-1); }; return s; } -var DOMAIN_NC = toDomain(nc_domain) - ,DOMAIN_NOTICE = toDomain(notice_domain) - ,LOADING = '<img src="http://static.youku.com/index/img/2013/loading_16.gif" width="16" height="16" border="0">' - ,isIE6 = document.all && !window.XMLHttpRequest ? true : false; - -//header class -var QHeader = { - ids: {'headerbox': 'qheader_box', 'header': 'qheader'}, - dropmenuGroup: null, - node: null, - jsres: typeof(qheaderjs) == 'object' ? qheaderjs : null, - ready: false, - status: 'static', - rule: '',//å–消顶导fixed - init: function(){ - this.header = document.getElementById(this.ids.header); - this.headerbox = document.getElementById(this.ids.headerbox); - if(!this.header){ return; } - //优先执行的功能ä¸ä¾èµ–资æºåŠ è½½ - this.Nav.findStick();//å¯¼èˆªæ›¿æ¢ - this.Search.init();//æœç´¢åŠŸèƒ½ - //ç™»å½•çŠ¶æ€ common.js ready - if(typeof(islogin) == 'function' && !islogin()){ - document.getElementById('qheader_logbefore').style.display = 'block'; - } - this.bind(); - //ä¾èµ–打å°ä»£ç ä¸­çš„资æºå£°æ˜Žæ‰“å° - if(!this.jsres){ return; } - var _this = this, canrun = false, runed = false; - - //è¿è¡Œæ—¶æ£€æµ‹ä¾èµ–脚本, 如加载立å³è¿è¡Œ - var timer = setInterval(function(){ - if(_this.chkres('relyon')){ - canrun = true; - clearInterval(timer); - if(!runed){ - _this.bindfns(); runed = true; - } - } - }, 10); - - //domreadyåŽæ£€æµ‹ä¾èµ–脚本, 添加未包å«çš„脚本, 并加载附加功能 - domReady(function(){ - clearInterval(timer); timer = null; - canrun = canrun || _this.chkres('relyon'); - - var addons = function(){ - _this.chkres('addons'); - _this.loadres('addons', function(){ - if(typeof(XBox) != 'undefined'){ - XBox.init({"site":14}); - - var f = document.getElementById('qheader_search'); - if(f){ - var b = f.getElementsByTagName('button')[0]; - if(b){ - addEvent(b, 'click', function(){ - _this.Search.doSearch(); - }); - } - } - } - }); - } - - if(!canrun){ - _this.loadres('relyon', function(){ - var relyon = _this.jsres.relyon; - for(var i=0; i<relyon.length; i++){ - if(relyon[i].ready !== true){ return; } - } - if(!runed){ _this.bindfns(); runed = true;} - addons(); - }); - }else{ - if(!runed){ _this.bindfns(); runed = true; } - addons(); - } - }); - }, - bind: function(){ - var _this = this; - addEvent(window, 'scroll', function(){ - if(_this.rule == 'fixed'){ - _this.changePos('scroll'); - } - }); - }, - bindfns: function(){ - this.ready = true; - this.dropmenuGroup = new DropmenuGroup(); - this.Userlog.init(); - this.Channel.init(); - this.Nav.init(); - this.Upload.init(); - this.NoticeNew.init(); - }, - dofix: function(){ - return this.changeRule('fixed'); - }, - unfix: function(){ - return this.changeRule('static'); - }, - changeRule: function(rule){ - if(rule != this.rule){ - this.rule = rule; - this.changePos('rule'); - } - return this; - }, - changePos: function(type){ - var ready = typeof(Element) == 'function' ? true : false;//prototype ready - var fixpos = false, inview = true; - var scrolltop = document.documentElement.scrollTop || document.body.scrollTop; - var posheader = getElementPos(this.header); - - if(scrolltop >= this.header.offsetHeight + posheader.y){ inview = false; } - if(scrolltop >= posheader.y){ fixpos = true; } - - var _this = this - ,header = ready ? Element.extend(this.header) : this.header - ,headerbox = ready ? Element.extend(this.headerbox) : this.headerbox; - - if(this.rule == 'fixed'){ - if(fixpos){ - if(this.status != 'fixed'){ - if(!isIE6){ headerbox.style.position = 'fixed'; } - this.status = 'fixed'; - } - }else{ - if(this.status != 'static'){ - if(!isIE6){ headerbox.style.position = 'relative'; } - this.status = 'static'; - } - } - }else{ - if(this.status != 'static'){ - if(!isIE6){ headerbox.style.position = 'relative'; } - this.status = 'static'; - } - } - - return this; - }, - loadres: function(key, callback){ - var res = this.jsres[key]; - var _this = this; - var callback = typeof(callback) == 'function' ? callback : function(){}; - for(var i=0; i<res.length; i++){ - (function(i){ - if(res[i].ready === false){ - _this.jsres[key][i].ready = 'loading'; - addScript(_this.jsres[key][i].src, function(){ - _this.jsres[key][i].ready = true; - callback(); - }); - } - })(i); - } - }, - chkres: function(key){//åŒæ­¥åŠ è½½çŠ¶æ€ä¸‹ 检测ä¾èµ–çš„JSèµ„æº - var res = this.jsres[key]; - if(!res){ return true; } - var _this = this; - var scripts = document.getElementsByTagName('script'); - for(var i=0; i<scripts.length; i++){ - var script = scripts[i]; - for(var j=0; j<res.length; j++){ - if(script.src && script.src == res[j].src){ - - (function(script, key, j){ - if(!_this.jsres[key][j].ready && eval(_this.jsres[key][j].condition)){ - _this.jsres[key][j].ready = true; - } - })(script, key, j); - } - } - } - for(var i=0; i<this.jsres[key].length; i++){ - if(this.jsres[key][i].ready !== true){ - return false; - } - } - return true; - } -} - -QHeader.Userlog = { - uid: 0, - lock: false, - first: true, - init: function(){ - this.logbefore = $('qheader_logbefore'); - this.logafter = $('qheader_logafter'); - if(!this.logbefore || !this.logafter){ return; } - var node = $('qheader_username');; - if(!node){ return; } - - this.dp = new Dropmenu({ - 'group': QHeader.dropmenuGroup, - 'node': node, - 'fire': 'hover' - }); - this.dp.setCallback('show', function(){ - QheaderModule.showUserMsg(); - }); - this.update(); - this.bind(); - QheaderModule.noticePoll(); - }, - bind: function(){ - var _this = this; - $('qheader_login').observe('click', function(e){ - login({type:'header', callBack:''}); preventDefault(e); - }); - window['update_login_status_hook_qheader'] = function(){ - var uid = _this.getUID(); - if(_this.uid != uid){//第一次header自身获å–ä¿¡æ¯ï¼Œ 其他区域登录且更æ¢è´¦å·å†æ¬¡èŽ·å– - _this.update(); - } - } - }, - getLogStatus: function(){ - if(islogin()){ return true; } - return false; - }, - update: function(){ - var st = this.getLogStatus(); - this.uid = this.getUID(); - this.username = this.getUserName(); - if(st){ - this.logbefore.hide(); - this.logafter.show(); - this.getUserinfo(); - }else{ - this.logbefore.show(); - this.logafter.hide(); - this.uid = 0; - } - return this; - }, - getUserinfo: function(){ - if(this.lock){ return; } - this.lock = true; - if(this.username){ - $('qheader_username_show').update('<div style="text-align:center;margin-top:5px;">'+ LOADING +'</div>'); - } - QheaderModule.initHeaderUser(); - }, - getUID: function(){ - if(!islogin()){ return 0; } - var ckie = Nova.Cookie.get('yktk'); - var uid = 0; - if(ckie){ - try{ - var u_info = decode64(decodeURIComponent(ckie).split( \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qwindow.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qwindow.js0-7000 deleted file mode 100644 index 28906c4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/qwindow.js0-7000 +++ /dev/null @@ -1,201 +0,0 @@ -var Qwindow = function(params){ - //default config - this.config = { - title: '', - size:{ width:320, height:200 }, - mode: 'normal', - posrefer: window, - pos:{ top:'middle', left:'center' }, - content: { type:'html', value: '' }, - maskstyle: { color: '#545454', opacity: 0.5 }, - showmask: true, - showhandle: true, - zindex: 30000, - scrolling: false, - elements: 'object,embed,select', - onshow: function(){}, - onhide: function(){}, - ondestroy: function(){} - } - this.config = arguments[0] ? (typeof(arguments[0])=='object' ? this._mergeConfig(this.config, params) : params) : this.config; - - this.isIE = (document.all) ? true : false; - this.isIE6 = this.isIE && !window.XMLHttpRequest; - //sogou - //var ua = navigator.userAgent.toLowerCase(); - //ua.indexOf('se 2.x') != -1 ? true : false; - this.init(); -} -Qwindow.prototype = { - init: function(){ - this.status = 'hide'; - this.isDestroy = false; - this.dom = {}; - this.dom.win = document.createElement('div'); this.dom.win.className = 'qwindow'; - this.dom.winbox = document.createElement('div'); this.dom.winbox.className = 'winbox'; - this.dom.winbg = document.createElement('div'); this.dom.winbg.className = 'winbg'; - - this.dom.winhead = document.createElement('div'); this.dom.winhead.className = 'winhead'; - this.dom.wintitle = document.createElement('div'); this.dom.wintitle.className = 'wintitle'; - this.dom.winclose = document.createElement('div'); this.dom.winclose.className = 'winclose'; - this.dom.winbody = document.createElement('div'); this.dom.winbody.className = 'winbody'; - - this.dom.winmask = document.createElement('div'); this.dom.winmask.className = 'qwindow_mask'; - - if(this.config.title){ this.setTitle(this.config.title).showTitle(); } - if(this.config.size){ this.setSize(this.config.size.width, this.config.size.height); } - if(this.config.content){ this.setContent(this.config.content.type, this.config.content.value); } - if(this.config.mode == 'fixed'){ this.setMode('fixed'); } - if(this.config.showhandle){ this.showHandle(); } - - this.setMaskstyle(this.config.maskstyle.color, this.config.maskstyle.opacity); - this.setElements(this.config.elements); - this.setzIndex(this.config.zindex); - - this.dom.winhead.appendChild(this.dom.wintitle); - this.dom.winhead.appendChild(this.dom.winclose); - this.dom.winbox.appendChild(this.dom.winhead); - this.dom.winbox.appendChild(this.dom.winbody); - this.dom.win.appendChild(this.dom.winbox); - this.dom.win.appendChild(this.dom.winbg); - document.body.appendChild(this.dom.winmask); - document.body.appendChild(this.dom.win); - - this.bind(); - - }, - destroy: function(){ - if( this.isDestroy || - !this.dom.win || - !this.dom.winmask || - !this.dom.win.parentNode || - !this.dom.winmask.parentNode){ return false; } - - this.isDestroy = true; - if(typeof(this.config.ondestroy) == 'function'){ this.config.ondestroy(); } - - var iframe = this.dom.win.getElementsByTagName('iframe')[0]; - if(iframe){ iframe.parentNode.removeChild(iframe); } - this.dom.win.parentNode.removeChild(this.dom.win); - this.dom.winmask.parentNode.removeChild(this.dom.winmask); - - return true; - }, - bind: function(){ - var _this = this; - this.dom.winclose.onclick = function(){ _this.hide(); } - var resetwin = function(){ - var status = _this.getStatus(); - if(status == 'show'){ - _this.rePos().resizeMask();; - } - } - if(window.addEventListener){ - window.addEventListener('resize',function(){setTimeout(resetwin, 10)}, false); - }else if(window.attachEvent){ - window.attachEvent('onresize',function(){setTimeout(resetwin, 10)}); - } - return this; - }, - _setOpacity: function(element, opacity){ - if(!element){ return false; } - if(!document.all){ - element.style.opacity = opacity; - }else{ - element.style.filter = 'alpha(opacity=' + opacity*100 + ')'; - } - return true; - }, - show: function(){ - var pos = this.getPos(); - this.setPos(pos.top, pos.left); - this.hideElements(); - if(!this.isIE){ - this._setOpacity(this.dom.win, 1); - } - this.dom.win.style.visibility = 'visible'; - this.status = 'show'; - if(this.config.showmask){ this.resizeMask(); this.dom.winmask.style.display = 'block'; } - if(typeof(this.config.onshow) == 'function'){ this.config.onshow(); } - return this; - }, - hide: function(){ - this.showElements(); - if(!this.isIE){ - this._setOpacity(this.dom.win, 0); - } - this.dom.win.style.visibility = 'hidden'; - this.dom.winmask.style.display = 'none'; - this.status = 'hide'; - if(typeof(this.config.onhide) == 'function'){ this.config.onhide(); } - return this; - }, - getStatus: function(){ - return this.status; - }, - toggle: function(){ - var status = this.getStatus(); - if(status == 'show'){ this.hide(); }else if(status == 'hide'){ this.show(); } - return this; - }, - reload: function(){}, - clearContent: function(){ - var iframe = this.dom.win.getElementsByTagName('iframe')[0]; - if(iframe){ iframe.parentNode.removeChild(iframe); } - this.dom.winbody.innerHTML = ''; - return this; - }, - setMode: function(mode){ - var m = 'normal'; - if(mode == 'fixed'){ m = 'fixed'; } - else{ m = 'normal';} - if(this.config.posrefer == window && !this.isIE6){ - this.dom.win.style.position = (m =='fixed') ? 'fixed' : 'absolute'; - this.config.mode = m; - this.rePos(); - } - return this; - }, - setContent: function(type, value){ - this.config.content.type = type; - this.config.content.value = value; - this.clearContent(); - if(type == 'html' || type == 'element'){ - if(type == 'html'){ - this.dom.winbody.innerHTML = value; - }else{ - if(!value){ return false; } - this.dom.winbody.appendChild(value); - } - if(this.config.scrolling){ this.dom.winbody.style.overflow = 'auto'; } - else{ this.dom.winbody.style.overflow = 'hidden'; } - }else if(type == 'iframe'){ - this.dom.winbody.style.overflow = 'hidden'; - var iframe = document.createElement('iframe'); - iframe.frameBorder = '0'; - iframe.scrolling = this.config.scrolling ? 'auto' : 'no'; - this.dom.winbody.appendChild(iframe); - setTimeout(function() {iframe.src = value}, 10); //for ie6 - } - return this; - }, - setScrolling: function(bool){ - if(this.config.scrolling != bool){ - this.config.scrolling = bool; - if(this.config.content.type == 'iframe'){ - iframe = this.dom.winbody.getElementsByTagName('iframe')[0]; - if(iframe){ - this.dom.winbody.style.overflow = 'hidden'; - var iframe_new = document.createElement('iframe'); - iframe_new.frameBorder = '0'; - iframe_new.scrolling = bool ? 'auto' : 'no';; - iframe_new.src = this.config.content.value; - iframe.parentNode.removeChild(iframe); - this.dom.winbody.appendChild(iframe_new); - } - }else{ - if(bool){ this.dom.winbody.style.overflow = 'auto'; } - else{ this.dom.winbody.style.overflow = 'hidden'; } - } - } - retur \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/resize.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/resize.js0-7000 deleted file mode 100644 index d002aac..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/resize.js0-7000 +++ /dev/null @@ -1,38 +0,0 @@ -(function() { - if (navigator.userAgent.indexOf('iPad') !== -1) { - var b = Element.extend(document.body); - if (document.body.className.indexOf('yk-w970') != -1) { - b.removeClassName('yk-w970'); - } - document.body.className += ' yk-w1190'; - document.body.style.paddingRight = "50px"; - var vp = document.createElement('meta'); - vp.setAttribute('name', 'viewport'); - vp.setAttribute('content', 'width=1270px'); - document.head.appendChild(vp); - return; - } - var fn = function() { - var w = document.documentElement ? document.documentElement.clientWidth : document.body.clientWidth, - r = 1255, - b = Element.extend(document.body), - classname = b.className; - if (w < r) { - b.addClassName('yk-w970').removeClassName('yk-w1190'); - } else { - b.addClassName('yk-w1190').removeClassName('yk-w970'); - } - } - if (navigator.userAgent.indexOf('iPad') == -1) { - if (window.addEventListener) { - window.addEventListener('resize', function() { - fn(); - }); - } else if (window.attachEvent) { - window.attachEvent('onresize', function() { - fn(); - }); - } - } - fn(); -})(); \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/seedVideo.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/seedVideo.js0-7000 deleted file mode 100644 index e039d75..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/seedVideo.js0-7000 +++ /dev/null @@ -1,67 +0,0 @@ -(function(window) { - if ((typeof window.SeedVideo === 'object') && window.SeedVideo) { - return ; - } - - var SeedVideo = { - cookie : {}, - is_inited : false - }; - - SeedVideo.init = function() { - if (SeedVideo.is_inited) { - return ; - } - - try { - var cookie_advideo = Nova.Cookie.get('advideo').evalJSON(true); - if ((typeof cookie_advideo === 'object') && cookie_advideo) { - SeedVideo.cookie = cookie_advideo; - } - } catch (e) {} - - SeedVideo.is_inited = true; - } - - SeedVideo.set_last_index = function (key, num) { - var obj_first = $(key + '_1'); - if (!obj_first) { - return ; - } - - var obj_tab_container = obj_first.up('[contab="contab"]'); - if (obj_tab_container && (obj_tab_container.style.display === 'none')) { - return ; - } - SeedVideo.cookie[key] = !SeedVideo.cookie[key] ? Math.floor(num * Math.random() + 1) : ((SeedVideo.cookie[key] % num) + 1); - - var is_display_one = false; - var obj_advideo = null; - for (var i = 1; i <= num; ++i) { - obj_advideo = $(key + '_' + i); - if (!obj_advideo) { - continue; - } - - if (i == SeedVideo.cookie[key]) { - obj_advideo.style.display = ''; - is_display_one = true; - } else { - obj_advideo.style.display = 'none'; - } - } - if (!is_display_one) { - obj_first.style.display = ''; - } - } - - SeedVideo.save_cookie = function() { - Nova.Cookie.set('advideo', Object.toJSON(SeedVideo.cookie), 30); - } - - window.SeedVideo = SeedVideo; - window.SeedVideo.init(); - Element.observe(window, 'load', function() { - window.SeedVideo.save_cookie(); - }); -})(window); \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/share_msg.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/share_msg.js0-7000 deleted file mode 100644 index 1202754..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/share_msg.js0-7000 +++ /dev/null @@ -1,2 +0,0 @@ - -NoLoginTip.TipCallback([]) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sideTool.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sideTool.css0-7000 deleted file mode 100644 index b455714..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sideTool.css0-7000 +++ /dev/null @@ -1,297 +0,0 @@ -.right-sideBar { - position: fixed; - _position: absolute; - bottom: 60px; - right: 0px; - z-index: 996; - color: #fff; -} -.right-sideBar ul { - border: 1px solid #ddd; -} -.right-sideBar ul .callback { - border-bottom: none; -} -.right-sideBar ul li { - width: 38px; - height: 38px; - border-bottom: 1px solid #ddd; - background: #fff; -} -.right-sideBar ul li .toolbar { - position: relative; - display: block; - width: 100%; - height: 100%; -} -.right-sideBar ul li .cart-selected { - background: #90d7f6 url("/index/img/toolbar/toolbar.png") no-repeat -113px 10px; -} -.right-sideBar ul li .icon-1 { - background: url("/index/img/toolbar/toolbar.png") no-repeat -83px 10px; -} -.right-sideBar ul li .icon-2 { - background: url("/index/img/toolbar/toolbar.png") no-repeat -80px -20px; -} -.right-sideBar ul li .icon-3 { - background: url("/index/img/toolbar/toolbar.png") no-repeat -80px -50px; -} -.right-sideBar ul li .icon-4 { - background: url("/index/img/toolbar/toolbar.png") no-repeat -78px -83px; -} -.right-sideBar ul li .icon-1:hover { - background: #e7e7e7 url("/index/img/toolbar/toolbar.png") no-repeat - -83px 10px; -} -.right-sideBar ul li .icon-2:hover { - background: #e7e7e7 url("/index/img/toolbar/toolbar.png") no-repeat - -80px -20px; -} -.right-sideBar ul li .icon-3:hover { - background: #e7e7e7 url("/index/img/toolbar/toolbar.png") no-repeat - -80px -50px; -} -.right-sideBar ul li .icon-4:hover { - background: #e7e7e7 url("/index/img/toolbar/toolbar.png") no-repeat -78px -83px; -} -.right-sideBar ul li .ac-small { - background: url("/index/img/toolbar/reward.png") no-repeat 4px -14px; -} -.right-sideBar ul .bigImg { - width: 120px; - height: 180px; - position: absolute; - top: -180px; - right: 0px; - border: none; - background: transparent; -} -.right-sideBar ul .bigImg .closeIcon { - cursor: pointer; - position: absolute; - top: 0px; - left: 0px; - width: 13px; - height: 13px; - background: url("/index/img/toolbar/reward.png") no-repeat 0px 0px; -} -.right-sideBar ul .bigImg a { - width: 100%; - height: 100%; - background: url("/index/img/toolbar/reward.png") no-repeat 0px -51px; -} -.btn { - -moz-user-select: none; - -webkit-user-select: none; - cursor: pointer; - display: inline-block; - *display: inline; - *zoom: 1; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - margin: 0; - vertical-align: middle; - text-decoration: none; - text-align: center; - white-space: nowrap; - border: 1px solid; - line-height: 20px; - font-family: arial, helvetica, verdana, tahoma, sans-serif -} -.btn:hover, .btn:focus { - outline: none -} -.btn, .btn-medium { - min-width: 80px; - _width: 80px; - padding: 4px 9px; - font-size: 12px -} -.btn-small { - min-width: 56px; - _width: 56px; - padding: 1px 9px; - _padding-top: 4px; - font-size: 12px -} -.btn-large { - min-width: 100px; - _width: 100px; - padding: 9px 14px; - font-size: 14px; - font-family: "Microsoft YaHei", "微软雅黑", helvetica, arial, verdana, tahoma, sans-serif -} -.btn, .btn-major { - color: #ffffff; - border-color: #007dcc; - background-color: #1c98e7 -} -.btn:link, .btn:visited, .btn-major:link, .btn-major:visited { - color: #ffffff -} -.btn:hover, .btn:focus, .btn-major:hover, .btn-major:focus { - border-color: #1092e5; - background-color: #25a3f3 -} -.btn:active, .btn-major:active { - border-color: #007dcc; - background-color: #108bd9 -} -.btn-minor { - color: #555555; - border-color: #d1d1d1; - background-color: #f2f2f2 -} -.btn-minor:link, .btn-minor:visited { - color: #555555 -} -.btn-minor:hover, .btn-minor:focus { - border-color: #e2e2e2; - background-color: #f4f7fa -} -.btn-minor:active { - border-color: #dbdbdb; - background-color: #eaeaea -} -.btn-pay { - color: #ffffff; - border-color: #e44b15; - background-color: #ff6600 -} -.btn-pay:link, .btn-pay:visited { - color: #ffffff -} -.btn-pay:hover, .btn-pay:focus { - border-color: #e86813; - background-color: #ff7f18 -} -.btn-pay:active { - border-color: #c95c14; - background-color: #f06000 -} -.btn-follow { - color: #ffffff; - border-color: #951d09; - background-color: #d23015 -} -.btn-follow:link, .btn-follow:visited { - color: #ffffff -} -.btn-follow:hover, .btn-follow:focus { - border-color: #be1c00; - background-color: #ed3718 -} -.btn-follow:active { - border-color: #951d09; - background-color: #c5250a -} -.btn-disabled { - cursor: default; - color: #bbbbbb; - border-color: #cad4e4 -} -.btn-disabled:link, .btn-disabled:visited { - color: #bbbbbb -} -.btn-disabled, .btn-disabled:hover, .btn-disabled:focus, .btn-disabled:active { - border-color: #dfe6f1; - background-color: #ecf0f5 -} -button.btn::-moz-focus-inner, input.btn::-moz-focus-inner { - padding: 0; - border: 0 -} -button.btn, input.btn, button.btn-medius, input.btn-medius { - *padding-top: 2px; - *padding-bottom: 3px -} -button.btn-large, input.btn-large { - *padding-top: 7px; - *padding-bottom: 7px -} -button.btn-small, input.btn-small { - *padding-top: 0; - *padding-bottom: 0 -} -.btn, .btn-medium { - min-width: 60px\0 -} -.btn-small { - min-width: 36px\0 -} -.btn-large { - min-width: 70px\0 -} -div.btn, a.btn, span.btn, div.btn-medium, a.btn-medium, span.btn-medium { - *min-width: 60px; - _width: 60px -} -div.btn-small, a.btn-small, span.btn-small { - *min-width: 36px; - _width: 36px -} -div.btn-large, a.btn-large, span.btn-large { - *min-width: 70px; - _width: 70px -} -.right-sideBar .yk-toolbar-util .yk-toolbar-group { - width: 50px; - height: 40px; - position: relative; - margin-bottom: 0 -} -.right-sideBar .yk-toolbar-group-open { - background: #ffffff; - border-right: 1px solid #ccc; -} -.right-sideBar .yk-toolbar-group-open .yk-toolbar-group-item-txt { - color: #3fccff -} -.right-sideBar .yk-toolbar-group-item { - width: 100%; - height: 100%; - overflow: hidden; - cursor: pointer; - z-index: 20 -} -.right-sideBar .yk-toolbar-group-hover { - background: #878787; - z-index: 50 -} -.right-sideBar .yk-toolbar-setting { - z-index: 50 -} -.right-sideBar .yk-toolbar-util { - position: absolute; - bottom: 50px; - left: 0; - z-index: 50 -} -.right-sideBar .yk-toolbar-util .yk-toolbar-group-item { - padding: 10px 0; - height: 20px -} -.right-sideBar .yk-toolbar-group-item-txt { - font-size: 12px; - line-height: 24px; - font-family: "microsoft yahei", "微软雅黑", "黑体" -} -.right-sideBar .yk-toolbar-spacer { - position: relative; - z-index: 30; - height: 1px; - overflow: hidden; - background: #878787; - margin: 0 2px -} -.right-sideBar ul, .yk-toolbar li { - padding: 0; - margin: 0; - list-style: none; - line-height: 140% -} -.right-sideBar a, .right-sideBar p, .right-sideBar span, .right-sideBar div, .right-sideBar button { - font-family: "Microsoft YaHei", "微软雅黑", helvetica, arial, verdana, tahoma, sans-serif -} -.right-sideBar .ico-watchlevel-0, .right-sideBar .ico-watchlevel-1, .right-sideBar .ico-watchlevel-2, .right-sideBar .ico-watchlevel-3, .right-sideBar .ico-watchlevel-4, .right-sideBar .ico-watchlevel-0-middle, .right-sideBar .ico-watchlevel-1-middle, .right-sideBar .ico-watchlevel-2-middle, .right-sideBar .ico-watchlevel-3-middle, .right-sideBar .ico-watchlevel-4-middle, .right-sideBar .ico-watchlevel-0-small, .right-sideBar .ico-watchlevel-1-small, .right-side \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sideTool.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sideTool.js0-7000 deleted file mode 100644 index 8b1fcdf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sideTool.js0-7000 +++ /dev/null @@ -1,133 +0,0 @@ -/** - * ä¾§è¾¹æ  - * @author fuwenqing@youku.com - * - */ -(function(){ - - UC_DOMAIN = window.UC_DOMAIN || "i.youku.com"; - - var SideTool = { - tool: 'sideTool', - token: '', - curpanel: '', - loginUID: 0, - tmpUID: 0, - isfirstcome: true, - shoppingisshow: true, - gotopisshow: true, - - classOpen: 'yk-toolbar-group-open', - classHover: 'yk-toolbar-group-hover', - $curOpenGroup:null, - scrollBarWidth:null, - - modleicon:{ - eshop: {modlename:'eshop',modleitemid:'iconitemshopping',modlegroupid:'icongroupshopping',callback:'SideTool.showShoppingList',isshow:true}, - gotop: {modlename:'gotop',modleitemid:'iconitemgotop',modlegroupid:'icongroupgotop',callback:'',isshow:true}, - lightoff: {modlename:'lightoff',modleitemid:'iconitemlighton',modlegroupid:'lightoff',callback:'',isshow:true}, - feedback: {modlename:'feedback',modleitemid:'iconitemfeedback',modlegroupid:'icongroupfeedback',callback:'',isshow:true} - }, - panel: { - shopping: 'panelshopping', - shoppinginfo: 'panelshoppinginfo', - shoppinglist: 'panelshoppinglist' - }, - toolbar:{ - service: 'toolbarservice' - }, - light:{ - isshow: false, - lstatus: 'on', - mask: 'playshow_mask', - dark: 'sideToolDark', - on: 'lighton', - cookie: { name: 'light', value: { on: 'on', off: 'off' }, expires: 3600 } - }, - tips:{ - eshop: {showmodle:'icongroupshopping',modleotherid:'cart',text:'',cookietime:365,isshow:false} - }, - - logoutshopping: '<div class="yk-toolbar-subscript-nologin"><span>登录åŽï¼Œè´­ç‰©è½¦ä¸­çš„商å“将永久ä¿å­˜~</span><a class="yk-toolbar-link-block yk-toolbar-link-block-blue" href="javascript:;" onclick="login({type:\'toolbar\',callBack:\'SideTool.showModleEvent\'},SideTool.modleicon.eshop);return false;">ç«‹å³ç™»å½•</a></div>', - shoppingfooter: '<div class="yk-toolbar-mod-ft"><img src="http://static.youku.com/index/img/toolbar/scroll_cover_ft.png" class="yk-toolbar-scover yk-toolbar-scover-ft"><div class="yk-toolbar-mod-links "><a href="http://'+UC_DOMAIN+'/i/">查看全部</a></div></div>', - noshoppingfooter: '<div class="yk-toolbar-mod-ft"><img src="http://static.youku.com/index/img/toolbar/scroll_cover_ft.png" class="yk-toolbar-scover yk-toolbar-scover-ft"><div class="yk-toolbar-mod-links "><a href="http://'+UC_DOMAIN+'/i/">查看全部</a></div></div>', - shoppingheader: '<div class="yk-toolbar-mod-hd"><img src="http://static.youku.com/index/img/toolbar/scroll_cover_hd.png" class="yk-toolbar-scover yk-toolbar-scover-hd"><div class="yk-toolbar-mod-title"><a class="mod-title-link mod-title-link-extend"><span class="yk-toolbar-group-item-icon yk-toolbar-group-item-icon-extend icon-cart-hd"></span><span class="yk-toolbar-mod-title-txt">购物车</span></a></div><!--<span class="hd-cart-num" id="goodsnum"></span>--><a id="newhot" onclick="SideTool._eshopStatisticsClothCoad(\'click\',\'cart_link \',\'\',\'\',\'\',\'\',\''+encodeURIComponent('http://wanhuo.tudou.com/')+'\',\'\');" href="http://wanhuo.tudou.com/" target="_blank" class="hd-cart-activity"><i class="yk-toolbar-ico icon-flame"></i>æ–°å“热å–<span class="yk-toolbar-notice-aim" id="iconnewhot"></span></a></div>', - shoppingnull: '<div class="yk-toolbar-mod-bd"><div class="yk-toolbar-cart-11ad"><a onclick="SideTool._eshopStatisticsClothCoad(\'click\',\'cart_banner \',\'\',\'\',\'\',\'\',\''+encodeURIComponent('http://c.youku.com/bkbm/index')+'\',\'\');" href="http://c.youku.com/bkbm/index.html" target="_blank"></a></div><div class="yk-toolbar-subscript-nologin"><span>您还没有选购商å“å‘¢~</span></div><img class="cart-tips" src="http://static.youku.com/index/img/toolbar/toolbar_tips_04.png"></div>', - - loading: '<div class="yk-toolbar-loading-wrap" style="display:;"><div class="yk-toolbar-loading"><span class="ico__loading_64"></span></div></div>', - - init:function(){ - - var _this = this; - var isHide = _this.isHideSideTool(); - if(isHide){ - return; - } - _this.initSideToolFrame(); - setTimeout(function(){ - _this.initSideTool(); - _this.bind(); - },100); - }, - isHideSideTool: function(){ - if($(this.light.mask) && $(this.light.dark)){ - this.light.isshow = true; - } - if(typeof(window.isshoweshop) != "undefined" && window.isshoweshop == "false"){ - this.shoppingisshow = false; //首页å±è”½è´­ç‰©è½¦ - } - if(typeof(window.isshowtop) != "undefined" && window.isshowtop == "false"){ - this.gotopisshow = false; - window.lottery_open_sidetool = false; //订阅页ä¸éœ€è¦è¿è¥ä½å’Œå›žåˆ°é¡¶éƒ¨å›¾æ ‡ - } - if(typeof(window.yk_toolbar_close) != "undefined"){ - return true; - } - var ua = navigator.userAgent.toLowerCase(); - if(ua.match(/iphone|ipod|itouch|android|windows phone|ipad/i) && $('padsideTool')){ - return true; - } - }, - initSideToolFrame: function(){ - var sideTool = document.createElement('div'); - sideTool.setAttribute("id","sideTool"); - sideTool.className = "right-sideBar"; - - var sideToolService = document.createElement('ul'); - sideToolService.className = "yk-toolbar-service js-toolbar"; - sideToolService.setAttribute("id","toolbarservice"); - sideToolService.setAttribute("data-stat-role","ck"); - - //活动大图展示 - if(window.lottery_open_sidetool){ - var sideToollotteryBig = document.createElement('li'); - sideToollotteryBig.className = "bigImg yk-toolbar-draw js-draw"; - sideToollotteryBig.style.cssText = "display:none;"; - sideToollotteryBig.setAttribute('id' , 'lotteryToolbarBig'); - sideToolService.appendChild(sideToollotteryBig); - sideTool.appendChild(sideToolService); - } - - //活动入å£(å°å›¾) - if(window.lottery_open_sidetool){ - var sideToollottery = document.createElement('li'); - sideToollottery.className = "yk-toolbar-draw js-draw"; - sideToollottery.style.cssText = "display:none;"; - sideToollottery.setAttribute('id' , 'lotteryToolbar'); - sideToolService.appendChild(sideToollottery); - sideTool.appendChild(sideToolService); - } - - //购物车 - if(this.shoppingisshow){ - var sideToolshopping = document.createElement('li'); - sideToolshopping.className = "yk-toolbar-group"; - sideToolshopping.innerHTML = '<a class="toolbar icon-1" id="icongroupshopping"><div class="yk-toolbar-group-item yk-toolbar-group-item-top js-dest-cart" id="iconitemshopping" data-stat-role="ck"><div class="yk-toolbar-notice-aim yk-toolbar-notice-aim-extend" id="newnoticeiconshopping" style="display:none"></div></div><div class="yk-toolbar-group-panel" id="panelshoppinginfo"><div class="right-side-arrow"></div><div class="yk-toolbar-mod" id="panelshoppinglist"></div></div><iframe class="mask" scrolling="0" frameborder="0" id="shoppingmask"></iframe></a>'; - sideToolService.appendChild(sideToolshopping); - sideTool.appendChild(sideToolService); - } - - //点击回到顶部按钮 - if(this.gotopisshow){ - var sideToolgotop = document.createElement('li'); - sideToolgotop.className = "yk-toolba \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/slide_next_btn_new.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/slide_next_btn_new.png0-7000 deleted file mode 100644 index 23cc628..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/slide_next_btn_new.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sport.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sport.png0-7000 deleted file mode 100644 index 1704a71..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sport.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sprite.gif0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sprite.gif0-7000 deleted file mode 100644 index 35d42e8..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/sprite.gif0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/tdstat.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/tdstat.js0-7000 deleted file mode 100644 index cec2de4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/tdstat.js0-7000 +++ /dev/null @@ -1,232 +0,0 @@ -/** - * 土豆CK统计 - * @mail: zhoubaochuan@youku.com - * @date: 2012-11-22 - */ -(function(){ - var TAG_ABBR = { - // 缩写常用标签 - "UL": 1, "OL": 2, "LI": 3, "INPUT": 4, "DIV": 5, "BODY": 6, "STRONG": 7, "SPAN": 8, "FORM": 9, "BUTTON": 10, "CAPTION": 11, - "FIELDSET": 12, "COLGROUP": 13, "TFOOT": 14, "LABEL": 15, "LEGEND": 16, "THEAD": 17, "OPTGROUP": 18, "OPTION": 19, "SELECT": 20, "TABLE": 21, "TBODY": 22, - // 过滤éžå¸ƒå±€æ ‡ç­¾å’Œé—­åˆæ ‡ç­¾ï¼ˆä¸ä¼šå‡ºçŽ°åœ¨çˆ¶èŠ‚点里,也ä¸ä¼šè®°å½•ç‚¹å‡»ï¼‰ - "IFRAME": 0, "SCRIPT": 0, "OBJECT": 0, "EMBED": 0, "IMG": 0 - }, - TUDO = function() { - return TUDO.prototype.init(); - }; - TUDO.prototype = { - // 扩展原型对象 - TUDO: "1.0.0", - init: function() { - return this; - }, - juid: function(){ - return ( +new Date()*10000 + Math.random(1)*10000 ).toString(32); - }, - getRequest: function(url){ - var img = new Image(); - //阻止IE下的自动垃圾回收引起的请求未å‘出状况 - img.onload = function(){}; - img.src = url; - } - } - TUDO.prototype.init.prototype = TUDO.prototype; - - TUDO.request = function(url) { - var img = new Image(); - //阻止IE下的自动垃圾回收引起的请求未å‘出状况 - img.onload = function(){}; - img.src = url; - } - - TUDO.event = { - add: function(elem, type, handler){ - var events, eventHandle; - - // ä¸é™„加事件到没有数æ®æˆ–文本节点 - if(elem.nodeType === 3 || elem.nodeType === 8 || !type || !handler){ - return; - } - - if( elem.addEventListener ){ - elem.addEventListener( type, handler, false); - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, handler); - } - - } - } - - TUDO.link = { - equalUrl: function(urlA, urlB){ - return urlA.replace(/\/?#.*|\/$/, '') === urlB.replace(/\/?#.*|\/$/, ''); - }, - getTrueLink: function(p){ - var link = p.getAttribute('href'); - if (!link) { - return ''; - } - if (/^(javascript:|#)/i.test(link)) { - return ''; - } - var url = location.href; - var domain = url.replace(/(https?:\/\/[^\/]+).*/, "$1"); - var path = domain === url ? domain + '/' - : url.replace(/[#?].*/, "").replace(/[^\/]*$/, ""); - return link.replace(/^\.[\.\/]+/g, function(s){ - var n = (s.match(/\.\.\//g) || []).length; - for (var i = 0; i < n; i++) - path = path.replace(/[^\/]+\/$/, ''); - return path; - }).replace(/&amp;/g, "&") - .replace(/^\//, domain + "\/") - .replace(/^[^\h\/]/, path + "$&"); - }, - getPositionCode: function( element ) { - var paths = []; - - if(element.id) - return '#' + element.id; - - for (; element; element = element.parentNode) - { - var tagName = element.nodeName.toUpperCase(); - if(tagName == 'BODY') break; - if(element.id && element.getAttribute('cs') != 'i'){ - paths.splice(0, 0, '#' + element.id); - return paths.join('~'); - } - var index = 0; - for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) - { - var sTagName = sibling.nodeName.toUpperCase(); - // Ignore document type declaration. - if (TAG_ABBR[sTagName] === 0) - continue; - if (sTagName == tagName) - ++index; - } - tagName = TAG_ABBR[tagName] || tagName; - var pathIndex = (index ? "!" + (index+1) : ""); - paths.splice(0, 0, tagName + pathIndex); - } - - return paths.length ? paths.join("~") : null; - } - } - - TUDO.cookie = function(win, n, v, op){ - if(typeof win == "string") { - op = v; - v = n; - n = win; - win = window; - } - if(v !== undefined) { - op = op || {}; - var date, expires = ""; - if(op.expires) { - if(op.expires.constructor == Date) { - date = op.expires; - } else { - date = new Date(); - date.setTime(date.getTime() + (op.expires * 24 * 60 * 60 * 1000)); - } - expires = '; expires=' + date.toGMTString(); - } - var path = op.path ? '; path=' + op.path : ''; - var domain = op.domain ? '; domain=' + op.domain : ''; - var secure = op.secure ? '; secure' : ''; - win.document.cookie = [n, '=', encodeURIComponent(v), expires, path, domain, secure].join(''); - } else { - v = win.document.cookie.match( new RegExp( "(?:\\s|^)" + n + "\\=([^;]*)") ); - return v ? decodeURIComponent(v[1]) : null; - } - }; - - window.TUDO = TUDO; -})(); - -//var tudou_pvid = TUDO().juid(); -var tudou_juidStr = 1, tudou_seid; -TUDO['init'] = function() { - tudou_juidStr = (typeof(MiniHeader) != 'undefined' && MiniHeader.islogin()) ? MiniHeader.userid : 1, - tudou_seid = TUDO().juid(); -} - - - -TUDO[ 'clickStat' ] = { - winWidth : window.document.documentElement[ "clientWidth" ], - winHeight : window.document.documentElement[ "clientHeight" ], - getDocWidth : function( ) { - var elem = document, - doc = elem.documentElement, - name = 'Width'; - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - - }, - getStatTarget : function(p){ - var check = {'A': 1, 'INPUT': 1, 'BUTTON': 1}; - - if (p.getAttribute && p.getAttribute('data-stat-role') == 'ck') { - return p; - } else { - var parent = p.parentNode; - if (parent && parent.getAttribute && parent.getAttribute('data-stat-role') == 'ck') { - return parent; - } - } - - if (!check[p.nodeName]) { // åªè®°å½•é“¾æŽ¥å’ŒæŒ‰é’®çš„点击 - p = p.parentNode || {}; // 链接里å¯èƒ½æœ‰å­å…ƒç´ ï¼Œæ¯”如img - if (!check[p.nodeName]) - return false; - } - return p; - }, - send: function( event , target) { - var d, p, body, - isButton = false, - win = window, - self = this, - targetUrl; - if( !event.target ) { - event.target = event.srcElement || document; - } - if( event.pageX == null && event.clientX != null){ - var d = document.documentElement; - var body = document.body; - event.pageX = self.clientX + (d && d.scrollLeft || body && body.scrollLeft || 0) - (d && d.clientLeft || body && body.clientLeft || 0); - event.pageY = self.clientY + (d && d.scrollTop || body && body.scrollTop || 0) - (d && d.clientTop || body && body.clientTop || 0); - } - - // 通过JS触å‘事件时,ä¸åº”该å‘é€CK统计 - if (typeof event.pageX == 'undefined') { - return; - } - - p = self.getStatTarget(target || event.target); - if( !p ) return; - - targetUrl = TUDO.link.getTrueLink(p); - if (p.nodeName !== 'A' || targetUrl === '' || TUDO.link.equalUrl(targetUrl, location.href)) { - isButton = true; - } - - this.request({ - eventId : isButton ? 2 : 1, - //pvid : tudou_pvid, - targetUrl : isButton ? '' : targetUrl, - pageX : event.pageX, - pageY : event.pageY, - scrollLeft : ('pageXOffset' in win) ? win[ 'pageXOffset' ] : win.document.documentElement[ 'scrollLeft' ], - scrollTop : ('pageYOffset' in win) ? win[ 'pageYOffset' ] : win.document.documentElement[ 'scrollTop' ], - positionCode : TUDO.link.getPositionCode( p ) - }); - }, - request: \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/toolbar.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/toolbar.png0-7000 deleted file mode 100644 index 81dfe33..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/toolbar.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/topic.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/topic.png0-7000 deleted file mode 100644 index b79ae10..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/topic.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/tv.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/tv.png0-7000 deleted file mode 100644 index 6226e3b..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/tv.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/user-grade-icon.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/user-grade-icon.css0-7000 deleted file mode 100644 index ef444b4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/user-grade-icon.css0-7000 +++ /dev/null @@ -1,101 +0,0 @@ -.user-grade-icon { display:inline-block;width:22px;height:16px;background-image:url(http://static.youku.com/lvip/img/rank/rank-icons.png);background-repeat:no-repeat;vertical-align:middle;margin-top:-3px;} -.user-grade-lv1 { background-position: 0 0px;} -.user-grade-lv2 { background-position: 0 -16px;} -.user-grade-lv3 { background-position: 0 -32px;} -.user-grade-lv4 { background-position: 0 -48px;} -.user-grade-lv5 { background-position: 0 -64px;} -.user-grade-lv6 { background-position: 0 -80px;} -.user-grade-lv7 { background-position: 0 -96px;} -.user-grade-lv8 { background-position: 0 -112px;} -.user-grade-lv9 { background-position: 0 -128px;} -.user-grade-lv10 { background-position: 0 -144px;} -.user-grade-lv11 { background-position: 0 -160px;} -.user-grade-lv12 { background-position: 0 -176px;} -.user-grade-lv13 { background-position: 0 -192px;} -.user-grade-lv14 { background-position: 0 -208px;} -.user-grade-lv15 { background-position: 0 -224px;} -.user-grade-lv16 { background-position: 0 -240px;} -.user-grade-lv17 { background-position: 0 -256px;} -.user-grade-lv18 { background-position: 0 -272px;} -.user-grade-lv19 { background-position: 0 -288px;} -.user-grade-lv20 { background-position: 0 -304px;} -.user-grade-lv21 { background-position: 0 -320px;} -.user-grade-lv22 { background-position: 0 -336px;} -.user-grade-lv23 { background-position: 0 -352px;} -.user-grade-lv24 { background-position: 0 -368px;} -.user-grade-lv25 { background-position: 0 -384px;} -.user-grade-lv26 { background-position: 0 -400px;} -.user-grade-lv27 { background-position: 0 -416px;} -.user-grade-lv28 { background-position: 0 -432px;} -.user-grade-lv29 { background-position: 0 -448px;} -.user-grade-lv30 { background-position: 0 -464px;} -.user-grade-lv31 { background-position: 0 -480px;} -.user-grade-lv32 { background-position: 0 -496px;} -.user-grade-lv33 { background-position: 0 -512px;} -.user-grade-lv34 { background-position: 0 -528px;} -.user-grade-lv35 { background-position: 0 -544px;} -.user-grade-lv36 { background-position: 0 -560px;} -.user-grade-lv37 { background-position: 0 -576px;} -.user-grade-lv38 { background-position: 0 -592px;} -.user-grade-lv39 { background-position: 0 -608px;} -.user-grade-lv40 { background-position: 0 -624px;} -.user-grade-lv41 { background-position: 0 -640px;} -.user-grade-lv42 { background-position: 0 -656px;} -.user-grade-lv43 { background-position: 0 -672px;} -.user-grade-lv44 { background-position: 0 -688px;} -.user-grade-lv45 { background-position: 0 -704px;} -.user-grade-lv46 { background-position: 0 -720px;} -.user-grade-lv47 { background-position: 0 -736px;} -.user-grade-lv48 { background-position: 0 -752px;} -.user-grade-lv49 { background-position: 0 -768px;} -.user-grade-lv50 { background-position: 0 -784px;} -.user-grade-lv51 { background-position: 0 -800px;} -.user-grade-lv52 { background-position: 0 -816px;} -.user-grade-lv53 { background-position: 0 -832px;} -.user-grade-lv54 { background-position: 0 -848px;} -.user-grade-lv55 { background-position: 0 -864px;} -.user-grade-lv56 { background-position: 0 -880px;} -.user-grade-lv57 { background-position: 0 -896px;} -.user-grade-lv58 { background-position: 0 -912px;} -.user-grade-lv59 { background-position: 0 -928px;} -.user-grade-lv60 { background-position: 0 -944px;} -.user-grade-lv61 { background-position: 0 -960px;} -.user-grade-lv62 { background-position: 0 -976px;} -.user-grade-lv63 { background-position: 0 -992px;} -.user-grade-lv64 { background-position: 0 -1008px;} -.user-grade-lv65 { background-position: 0 -1024px;} -.user-grade-lv66 { background-position: 0 -1040px;} -.user-grade-lv67 { background-position: 0 -1056px;} -.user-grade-lv68 { background-position: 0 -1072px;} -.user-grade-lv69 { background-position: 0 -1088px;} -.user-grade-lv70 { background-position: 0 -1104px;} -.user-grade-lv71 { background-position: 0 -1120px;} -.user-grade-lv72 { background-position: 0 -1136px;} -.user-grade-lv73 { background-position: 0 -1152px;} -.user-grade-lv74 { background-position: 0 -1168px;} -.user-grade-lv75 { background-position: 0 -1184px;} -.user-grade-lv76 { background-position: 0 -1200px;} -.user-grade-lv77 { background-position: 0 -1216px;} -.user-grade-lv78 { background-position: 0 -1232px;} -.user-grade-lv79 { background-position: 0 -1248px;} -.user-grade-lv80 { background-position: 0 -1264px;} -.user-grade-lv81 { background-position: 0 -1280px;} -.user-grade-lv82 { background-position: 0 -1296px;} -.user-grade-lv83 { background-position: 0 -1312px;} -.user-grade-lv84 { background-position: 0 -1328px;} -.user-grade-lv85 { background-position: 0 -1344px;} -.user-grade-lv86 { background-position: 0 -1360px;} -.user-grade-lv87 { background-position: 0 -1376px;} -.user-grade-lv88 { background-position: 0 -1392px;} -.user-grade-lv89 { background-position: 0 -1408px;} -.user-grade-lv90 { background-position: 0 -1424px;} -.user-grade-lv91 { background-position: 0 -1440px;} -.user-grade-lv92 { background-position: 0 -1456px;} -.user-grade-lv93 { background-position: 0 -1472px;} -.user-grade-lv94 { background-position: 0 -1488px;} -.user-grade-lv95 { background-position: 0 -1504px;} -.user-grade-lv96 { background-position: 0 -1520px;} -.user-grade-lv97 { background-position: 0 -1536px;} -.user-grade-lv98 { background-position: 0 -1552px;} -.user-grade-lv99 { background-position: 0 -1568px;} -.user-grade-lv100 { background-position: 0 -1584px;width: 24px;} diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_200x110.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_200x110.png0-7000 deleted file mode 100644 index a285b66..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_200x110.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_420x240.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_420x240.png0-7000 deleted file mode 100644 index 8ab055c..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_420x240.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_90x50.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_90x50.png0-7000 deleted file mode 100644 index 94d3dc6..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/video_default_90x50.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/vip.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/vip.png0-7000 deleted file mode 100644 index f09b1b4..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/vip.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/www.youku.com0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/www.youku.com0-7000 deleted file mode 100644 index b152793..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/www.youku.com0-7000 +++ /dev/null @@ -1,85 +0,0 @@ - -<!DOCTYPE html> -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<meta http-equiv="X-UA-Compatible" content="IE=Edge" /> -<meta http-equiv="Content-Language" content="zh-CN"/> -<meta name="title" content="优酷-中国领先视频网站,æ供视频播放,视频å‘布,视频æœç´¢" /> -<meta name="keywords" content="视频,视频分享,视频æœç´¢,视频播放,优酷视频" /> -<meta name="description" content="优酷-中国领先视频网站,æ供视频播放,视频å‘布,视频æœç´¢ - 视频æœåŠ¡å¹³å°,æ供视频播放,视频å‘布,视频æœç´¢,视频分享 - 优酷视频" /> -<link type="application/rss+xml" rel="alternate" title="优酷视频-推è视频" href="/index/rss_cool_v" /> -<link rel="search" type="application/opensearchdescription+xml" title="优酷视频æœç´¢" href="http://desktop.youku.com/opensearch/youku.xml"> -<link href="http://static.youku.com/v1.0.1064/index/css/yk.css" type="text/css" rel="stylesheet" /> -<link href="http://static.youku.com/v1.0.1064/cms/css/grid_pc.css" type="text/css" rel="stylesheet" /> -<link href="http://static.youku.com/v1.0.1064/index/css/ykhome.css" type="text/css" rel="stylesheet" /> -<link rel="Shortcut Icon" href="http://static.youku.com/v1.0.1064/index/img/favicon.ico" /> -<meta name="application-name" content="优酷网" /> -<meta name="msapplication-starturl" content="http://www.youku.com/" /> -<meta name="msapplication-task" content="name=上传视频;action-uri=http://www.youku.com/v/upload/;icon-uri=http://www.youku.com/favicon.ico" /> -<meta name="msapplication-task" content="name=我的点播å•;action-uri=http://www.youku.com/v_showlist/type_99.html#playlist;icon-uri=http://www.youku.com/favicon.ico" /> -<meta name="msapplication-task" content="name=我的优盘;action-uri=http://u.youku.com/my/;icon-uri=http://www.youku.com/favicon.ico" /> -<script src="http://static.youku.com/v1.0.1064/js/jquery.js"></script><script>jQuery.noConflict();</script> -<script src="http://static.youku.com/v1.0.1064/js/prototype.js"></script><script>if(!window.Nova){Nova={};}if(!window.NovaOptions){NovaOptions={};NovaOptions.compatibleMode=true;}</script> -<script>if(!window.Local){Local={"RELEASE_TAG":"v1.0.1064","PLAYER_RELEASE_TAG":"v1.0.0541","YOUKU_DOMAIN":"youku.com","YOUKU_HOMEURL":"www.youku.com","IMGSERVER":"http:\/\/static.youku.com","JSSERVER":"http:\/\/static.youku.com","CSSSERVER":"http:\/\/static.youku.com","VIDEO_PLAYPAGE_DOMAIN":"v.youku.com","PASSPORT_DOMAIN":"passport.youku.com","LOGIN_DOMAIN":"login.youku.com","UC_DOMAIN":"i.youku.com","SPACE_DOMAIN":"u.youku.com","INDEX_DOMAIN":"index.youku.com","NOTICE_DOMAIN":"notice.youku.com","COMMENT_DOMAIN":"comments.youku.com","NC_DOMAIN":"nc.youku.com","CMS_DOMAIN":"youku.com","WIDGET_DOMAIN":"comments.youku.com"};}</script> -<script src="http://static.youku.com/v1.0.1064/index/js/common.js"></script> -<script type="text/javascript" src="http://static.youku.com/v1.0.1064/cms/js/cmsCommon.js"></script> -<script type="text/javascript" src="http://static.youku.com/v1.0.1064/cms/js/cmsDatafromPrototype.js"></script> -<script type="text/javascript">NovaOptions={compatibleMode:true};__LOG__=function(){};var ncDomain = 'nc.youku.com';</script> -<title>优酷-中国领先视频网站,æ供视频播放,视频å‘布,视频æœç´¢ - 优酷视频</title> - -<style type="text/css"> - - - - - - - -/* huge AD */ -.yk-AD-flash{position:relative;z-index:10;} - -.my-watchgrade{padding:20px 10px;height:150px;width:180px;background:#f5f5f5 url(http://r4.ykimg.com/0510000053181BD66714C02D73051E73.jpg) no-repeat;;position:absolute;right:110px;top:0;z-index:10;} -.my-watchgrade *{color:#909090;font-size:12px;} -.my-watchgrade h6{font-size:20px;font-style:normal;margin-bottom:10px;line-height:24px;} -.my-watchgrade .yk-userlog-grade-detail{margin-bottom:10px;} -.my-watchgrade .yk-userlog-grade-detail em{font-style:normal;} -.my-watchgrade .yk-watchgrade{position:relative;margin-bottom:15px;} -.my-watchgrade .yk-watchgrade .yk-watchgrade-bar{position:relative;height:22px;line-height:0;font-size:0;background:#e7e7e7;margin:0 3px;} -.my-watchgrade .yk-watchgrade .yk-watchgrade-bar div{height:100%;line-height:0;font-size:0;background:#d3ec98;z-index:10;} -.my-watchgrade .yk-watchgrade .yk-watchgrade-level{position:absolute;top:-1px;z-index:15;} -.my-watchgrade .yk-watchgrade .right{right:-7px;} -.my-watchgrade .yk-watchgrade .left{left:-7px;} -.my-watchgrade .yk-userlogin p{margin-bottom:5px;font-size:14px;font-family:"Microsoft Yahei","微软雅黑";} -.my-watchgrade .yk-userlogin-btn a{display:block;height:35px;background:#06a7e1;color:#ffffff;text-align:center;line-height:35px;} -.my-watchgrade .yk-watchgrade-time{position:absolute;left:0;top:2px;width:180px;text-align:center;color:#597937;z-index:20;font-size:12px;} - -.yk-slide-index{position:relative;overflow:hidden;height:110px;margin-bottom:20px} .yk-slide-index .yk-slide-btnnext{visibility:visible}.yk-slide-pages{position:relative;width:5000px;height:100%}.yk-slide-page{float:left;width:150px;height:100%;margin-right:10px;background:green}.empty{background:#00f} .yk-slide-index .yk-slide-pager{color:#999;right:0;width:50px;height:15px;left:auto;padding-top:0;background:#fff;line-height: 16px;} .yk-slide-index .yk-slide-btnprev{visibility:visible} .yk-slide-index .yk-slide-pager .yk-slide-btnnext, .yk-slide-index .yk-slide-pager .yk-slide-btnprev{background:#a9a9a9 url(http://r3.ykimg.com/05100000520DB4626714C04A600AD598) 50% -10px no-repeat;height:15px;width:12px;line-height:16px;} .yk-slide-index .yk-slide-pager .yk-slide-btnprev{ background-position: 50% 4px; } .yk-slide-index .yk-slide-pager .yk-slide-btnnext:hover, .yk-slide-index .yk-slide-pager .yk-slide-btnprev:hover{background-color:#cb3511} .yk-slide-index .v-mini-group{float:left;width:310px;} - -.yk-AD-310x50{overflow:hidden;width:310px;height:50px;} -.yk-AD-1190x100{overflow:hidden;width:1190px;height:100px;} -.focusVideo .v-meta-play{ -*background:none; -*filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/mobile/ico_1N_play.png"); -} - - -#m_206045 .yk-AD-tong{height:100px;} -#m_206045 .yk-AD-tong .ad-con{width:1190px;} -#m_206015 .v-meta-title {height:40px;} - -#m_205805 .v .vb .v-meta-title a{color:#f1f1f1;font-size:14px;font-family:font-family: "Microsoft YaHei","微软雅黑", helvetica, arial, verdana, tahoma, sans-serif;} -#m_205805 .v-large .vb .v-meta-title a{font-size:16px;} - -#m_205805 .v .vb .v-meta-overlay{ -height:50px; -zoom:1; -background: url("http://static.youku.com/index/img/2013/video/bg_video_mini.png") left bottom no-repeat; -_background: none; -_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.youku.com/index/img/2013/video/bg_video_mini.png"); -} -#m_205805 .v-large .vb .v-meta-overlay{ -height:110px; -background: url("http://static.youku.com/index/img/2013/video/bg_video_large.png") left bottom no-repeat; -_background: none; -_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://static.y \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yk.8.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yk.8.png0-7000 deleted file mode 100644 index de4a3f2..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yk.8.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yk.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yk.css0-7000 deleted file mode 100644 index aad245f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yk.css0-7000 +++ /dev/null @@ -1,343 +0,0 @@ -@charset "utf-8"; - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -nav, -section { - display: block; -} -audio, -canvas, -video { - display: inline-block; - *display: inline; - *zoom: 1; -} -audio:not([controls]) { - display: none; -} -html { - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} -a:focus { - outline: thin dotted #333; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -a:hover, -a:active { - outline: 0; -} -figure { - padding: 0; - margin: 0; -} -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} -sup { - top: -0.5em; -} -sub { - bottom: -0.25em; -} -img { - vertical-align: middle; - border: 0; - -ms-interpolation-mode: bicubic; -} -#map_canvas img, -.google-maps img { - max-width: none; -} -button, -input, -select, -textarea { - margin: 0; - font-size: 100%; - vertical-align: middle; -} -button, -input { - *overflow: visible; - line-height: normal; -} -button::-moz-focus-inner, -input::-moz-focus-inner { - /* 在ç«ç‹ä¸‹çš„input或者button默认显示并没有达到ç»å¯¹çš„垂直居中,文字整体居中å下的ä½ç½®ï¼Œè€Œä¸”当点击按钮之åŽï¼ŒæŒ‰é’®ä¸Šä¼šå‡ºçŽ°ä¸€åœˆè™šçº¿ */ - padding: 0; - border: 0; -} -button, -input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; -} -input[type="search"] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield; -} -input[type="search"]::-webkit-search-decoration, -input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; -} -textarea { - overflow: auto; - vertical-align: top; -} -ol, -ul, -dl { - list-style: none; -} -body, -p, -ol, -ul, -dl { - padding: 0; - margin: 0; -} -a:link, -a:visited { - text-decoration: none; - color: #555555; -} -a:hover { - color: #cc3311; -} -a.white{ - color: #ffffff; -} - -a.blue { - color: #3399e0; -} - - -.yk-w970 .yk-w970-col18,.yk-w970 .yk-w970-col17,.yk-w970 .yk-w970-col16,.yk-w970 .yk-w970-col15,.yk-w970 .yk-w970-col14,.yk-w970 .yk-w970-col13,.yk-w970 .yk-w970-col12,.yk-w970 .yk-w970-col11,.yk-w970 .yk-w970-col10,.yk-w970 .yk-w970-col9,.yk-w970 .yk-w970-col8,.yk-w970 .yk-w970-col7,.yk-w970 .yk-w970-col6,.yk-w970 .yk-w970-col5,.yk-w970 .yk-w970-col4,.yk-w970 .yk-w970-col3,.yk-w970 .yk-w970-col2,.yk-w970 .yk-w970-col1 { - float: left; - min-height: 1px; - margin-left: 10px; - margin-right: 10px; - _display: inline; -} -.yk-w970 .yk-con, .yk-w970 .yk-AD-tong { - width: 970px; -} -.yk-w1190 .yk-w1190-col22,.yk-w1190 .yk-w1190-col21,.yk-w1190 .yk-w1190-col20,.yk-w1190 .yk-w1190-col19,.yk-w1190 .yk-w1190-col18,.yk-w1190 .yk-w1190-col17,.yk-w1190 .yk-w1190-col16,.yk-w1190 .yk-w1190-col15,.yk-w1190 .yk-w1190-col14,.yk-w1190 .yk-w1190-col13,.yk-w1190 .yk-w1190-col12,.yk-w1190 .yk-w1190-col11,.yk-w1190 .yk-w1190-col10,.yk-w1190 .yk-w1190-col9,.yk-w1190 .yk-w1190-col8,.yk-w1190 .yk-w1190-col7,.yk-w1190 .yk-w1190-col6,.yk-w1190 .yk-w1190-col5,.yk-w1190 .yk-w1190-col4,.yk-w1190 .yk-w1190-col3,.yk-w1190 .yk-w1190-col2,.yk-w1190 .yk-w1190-col1 { - float: left; - min-height: 1px; - margin-left: 10px; - margin-right: 10px; - _display: inline; -} -.yk-w1190 .yk-con, .yk-w190 .yk-AD-tong{ - width: 1190px; -} -.yk-w970 .yk-w970-col1, .yk-w1190 .yk-w1190-col1 { - width: 35px; -} -.yk-w970 .yk-w970-col2, .yk-w1190 .yk-w1190-col2 { - width: 90px; -} -.yk-w970 .yk-w970-col3, .yk-w1190 .yk-w1190-col3 { - width: 145px; -} -.yk-w970 .yk-w970-col4, .yk-w1190 .yk-w1190-col4 { - width: 200px; -} -.yk-w970 .yk-w970-col5, .yk-w1190 .yk-w1190-col5 { - width: 255px; -} -.yk-w970 .yk-w970-col6, .yk-w1190 .yk-w1190-col6 { - width: 310px; -} -.yk-w970 .yk-w970-col7, .yk-w1190 .yk-w1190-col7 { - width: 365px; -} -.yk-w970 .yk-w970-col8, .yk-w1190 .yk-w1190-col8 { - width: 420px; -} -.yk-w970 .yk-w970-col9, .yk-w1190 .yk-w1190-col9 { - width: 475px; -} -.yk-w970 .yk-w970-col10, .yk-w1190 .yk-w1190-col10 { - width: 530px; -} -.yk-w970 .yk-w970-col11, .yk-w1190 .yk-w1190-col11 { - width: 585px; -} -.yk-w970 .yk-w970-col12, .yk-w1190 .yk-w1190-col12 { - width: 640px; -} -.yk-w970 .yk-w970-col13, .yk-w1190 .yk-w1190-col13 { - width: 695px; -} -.yk-w970 .yk-w970-col14, .yk-w1190 .yk-w1190-col14 { - width: 750px; -} -.yk-w970 .yk-w970-col15, .yk-w1190 .yk-w1190-col15 { - width: 805px; -} -.yk-w970 .yk-w970-col16, .yk-w1190 .yk-w1190-col16 { - width: 860px; -} -.yk-w970 .yk-w970-col17, .yk-w1190 .yk-w1190-col17 { - width: 915px; -} -.yk-w970 .yk-w970-col18, .yk-w1190 .yk-w1190-col18, .yk-w970 .yk-tong{ - width: 970px; -} -.yk-w970 .yk-w970-col19, .yk-w1190 .yk-w1190-col19 { - width: 1025px; -} -.yk-w970 .yk-w970-col20, .yk-w1190 .yk-w1190-col20 { - width: 1080px; -} -.yk-w970 .yk-w970-col21, .yk-w1190 .yk-w1190-col21 { - width: 1135px; -} -.yk-w970 .yk-w970-col22, .yk-w1190 .yk-w1190-col22, .yk-w1190 .yk-tong{ - width: 1190px; -} -.yk-w970 .yk-w970-hide, -.yk-w1190 .yk-w1190-hide { - display: none; - visibility: hidden; -} -.yk-box { - width: 100%; -} -.yk-box .yk-head { - margin-bottom: 20px; - height: 30px; - font-size: 0; - line-height: 30px; - font-family: "Microsoft YaHei","微软雅黑", helvetica, arial, verdana, tahoma, sans-serif; - position: relative; - color: #555555; -} -.yk-box .yk-head .yk-title, -.yk-box .yk-head .yk-append, -.yk-box .yk-head .yk-extend { - font-size:12px; - display: inline-block; - *display: inline; - /* IE7 inline-block hack */ - *zoom: 1; - - vertical-align: bottom; -} -.yk-box .yk-head .yk-append, -.yk-box .yk-head .yk-extend { - font-family: normal; -} -.yk-box .yk-head .yk-append{ - /*position: absolute;*/ -} -.yk-box .yk-head .yk-title { - margin-right: 20px; - font: 26px/30px "Microsoft YaHei","微软雅黑", SimHei,helvetica, arial, verdana, tahoma, sans-serif; - *margin-top:-3px; -} -.yk-box .yk-head .yk-title, -.yk-box .yk-head .yk-title span, -.yk-box .yk-head .yk-title a { - color: #909090; - line-height:30px; -} - -/*.yk-box .yk-head .yk-title a, -.yk-box .yk-head .yk-title span{ - *position:relative; - *top:-1px; -} -*/ -.yk-box .yk-head .yk-title a:hover { - color: #cc3311; -} -.yk-box .yk-head .yk-extend { - position: absolute; - right: 0; - bottom: 3px; -} -.yk-box .yk-body { - position: relative; -} -.yk-box .yk-body-hair { - position: absolute; - top: -40px; - width:100%; -} -.yk-box .yk-body-hair .yk-AD{ - position: absolute; - right: 0; -} -.yk-box .yk-foot { - clear: both; -} -html { - -webkit-text-size-adjust: 100%; -} -.v, -.p { - margin: 0; - padding: 0; - position: relative; -} -.v *, -.p * { - font: 12px/20px arial, helvetica, verdana, tahoma, sans-serif; -} -.v img, -.p img { - display: block; - border: 0 none; -} -.v a, -.p a { - text-decoration: none; - color: #555555; -} -.v .vb a{ - color: #fff; -} -.v a:hover, -.p a:hover { - color: #c31; -} -.v .v-thumb, -.p .p-thumb { - overflow: hidden; - position: relative; - background-color: #999; - background-repeat: no-repeat; - background-position: center center; -} -.v .v-thumb img, -.p .p-thumb img { - width: 100%; -} -.v .v-thumb .v-thumb-taglt, -.p .p-thumb .p-thumb-taglt { - z-index: 3; - position: absolute; - top: 0; - left: 0 \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykRecommend.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykRecommend.js0-7000 deleted file mode 100644 index 46ffbf2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykRecommend.js0-7000 +++ /dev/null @@ -1,227 +0,0 @@ -var MYYOUKUREC = { - // Config - MAXHEIGHT: 486, - ANONYMOUSMAXHEIGHT: 296, - TRYJSONTIMES: 3, - SHOWNUMBER: 10, - ANONYMOUSRECOMMENDNUMBER: 5, - TITLELENGTH: 24, - LOGINSTAT: false, - RANDOMARRAY: [], - REQ_ID: '', - ANONYMOUSRECNUMBER: 25, - RECNUMBER: 20, - REFRESHCOUNT: 0, - MAXREFRESHCOUNT: 5, - - UserInfo: null, - - // Timer - timer: null, - timerData: null, - timerAnonymous: null, - timeSpan: 800, - - // Data - dataList: [], - dataRecommend: [], - dataShow: [], - dataShowInsert: [], - dataAnonymous: [], - - // Dom - dom: null, - domRecommend: null, - $domLoading: null, - - // Flag - flagRecommend: false, - - // Cookies - cookieYsuid: '', - cookieUid: '', - - // Lock - lockData: true, - lockAnonymousRecommend: true, - - // Data interface - getRecommendJson: 'http://ykrec.youku.com/personal/packed/list.json?', - getUserinfoJson: 'http://nc.youku.com/index/getUserinfo?nu=1&__callback=MYYOUKUREC.getUserinfo&timestamp=', - getAnonymousRecommendJson: 'http://ykrec.youku.com/personal/packed/list.json?', - - // URL - urlVideo: 'http://v.youku.com/v_show/id_', - urlUser: 'http://yikan.youku.com/u/home?from=y1.1-1.0.1', - urlOfficial: 'http://i.youku.com/u/official', - - // String - strLoading: "<i class='ico-loading-64'></i>", - - // IE Hack - isIE: document.all, - - init: function() { - var _this = this; - // init dom - _this.$dom = jQuery('#MYYOUKU-REC'); - _this.$domRecommend = _this.$dom.find('#MYYOUKU-REC-box'); - _this.dom = _this.$dom[0]; - _this.domRecommend = _this.$domRecommend[0]; - if (!_this.dom || !_this.domRecommend) { - return; - } - jQuery(_this.dom).append(jQuery(_this.strLoading)); - _this.$domLoading = jQuery(_this.dom).find(".ico-loading-64"); - // get cookies - // 此处获å–uid的逻辑请自行实现 start - _this.cookieYsuid = _this.cookiesGet('__ysuid'); - _this.cookieUid = get_username('all').userid; - _this.LOGINSTAT = islogin(); - // 此处获å–uid的逻辑请自行实现 end - _this.getRandomNumber(); - - _this.REQ_ID = _this.randomStr(3); - - _this.routeBaseUser(); - _this.bindRecRefresh(); - }, - - // Bind - bindRecRefresh: function() { - var _this = this; - _this.$dom.find("#MYYOUKU-REC-container .yk-rec-refresh").unbind("click").bind("click", function(e) { - _this.domRecommend.style.display = "none"; - _this.showLoading(); - - _this.REFRESHCOUNT++; - if (_this.REFRESHCOUNT >= _this.MAXREFRESHCOUNT) { - _this.REFRESHCOUNT = 0; - } - _this.refreshDom(); - }); - }, - - routeBaseUser: function() { - var _this = this; - // logon - if (_this.LOGINSTAT) { - _this.getRecommendJson += 'atrEnable=true&apptype=1&pg=8&module=1&pl=' + _this.RECNUMBER + '&uid=' + _this.cookieUid + '&guid=' + _this.cookieYsuid + '&picSize=1&module=1&callback=MYYOUKUREC.getRecommendData&pz=30&req_id=' + _this.REQ_ID + '&timestamp=' - _this.getJson(_this.getRecommendJson); - _this.getJson(_this.getUserinfoJson); - _this.timerData = setInterval(function() { - if (!_this.lockRecommend) { - try { - _this.initRecommendDom(_this.dataRecommend, _this.domRecommend, 0, _this.SHOWNUMBER); - _this.showContent(_this.MAXHEIGHT); - clearInterval(_this.timerData); - } catch (e) {} - // clearInterval(_this.timerData); - _this.lockData = false; - } - }, _this.timeSpan); - _this.dom.parentNode.setAttribute('class', 'MYYOUKUREC-loginAfter'); - } else { - _this.cookieUid = ''; - _this.getAnonymousRecommendJson += 'atrEnable=true&apptype=1&pg=8&module=3&pl=' + _this.ANONYMOUSRECNUMBER + '&guid=' + _this.cookieYsuid + '&picSize=1&callback=MYYOUKUREC.getAnonymousRecommendData&pz=30&req_id=' + _this.REQ_ID + '&timestamp=' - _this.getJson(_this.getAnonymousRecommendJson); - _this.timerAnonymous = setInterval(function() { - if (!_this.lockAnonymousRecommend) { - _this.showContent(_this.ANONYMOUSMAXHEIGHT); - clearInterval(_this.timerAnonymous); - } - }, _this.timeSpan); - _this.dom.parentNode.setAttribute('class', 'MYYOUKUREC-loginBefore'); - jQuery(_this.dom).addClass("dragmodule-top"); - } - _this.$dom.attr("inited", true); - }, - - refreshDom: function() { - var _this = this; - // logon - if (_this.LOGINSTAT) { - _this.timerData = setInterval(function() { - if (!_this.lockRecommend) { - try { - _this.initRecommendDom(_this.dataRecommend, _this.domRecommend, _this.REFRESHCOUNT * _this.SHOWNUMBER, (_this.REFRESHCOUNT + 1) * _this.SHOWNUMBER); - _this.showContent(_this.MAXHEIGHT); - } catch (e) {} - clearInterval(_this.timerData); - _this.lockData = false; - } - }, 300); - _this.$dom.find("#MYYOUKU-REC-container .yk-rec-refresh").hide(); - _this.$dom.find("#MYYOUKU-REC-container .yk-rec-relocate").show(); - } else { - _this.timerAnonymous = setInterval(function() { - if (!_this.lockAnonymousRecommend) { - _this.initRecommendDom(_this.dataAnonymous, _this.domRecommend, _this.REFRESHCOUNT * _this.ANONYMOUSRECOMMENDNUMBER, (_this.REFRESHCOUNT + 1) * _this.ANONYMOUSRECOMMENDNUMBER); - _this.showContent(_this.ANONYMOUSMAXHEIGHT); - clearInterval(_this.timerAnonymous); - } - }, 300); - } - }, - - getRecommendData: function(dt) { - var data = dt.data; - if (typeof data == 'undefined') { - return false; - } - if (data.length < this.SHOWNUMBER) { - if (this.CURRENTRECOMMENDSTATUS < this.TRYJSONTIMES) { - this.tryRequest(this.getRecommendJson); - this.CURRENTRECOMMENDSTATUS++; - } else { - this.hideDom(this.dom); - return false; - } - } else { - this.initData(data, this.dataRecommend); - this.lockRecommend = false; - } - - }, - - getUserinfo: function(data) { - if (typeof data == 'undefined') { - return false; - } - this.UserInfo = data; - }, - - getAnonymousRecommendData: function(dt) { - var data = dt.data; - var len = 0; - if (!!data.length) { - len = data.length; - } - if (len > this.ANONYMOUSRECOMMENDNUMBER) { - this.initData(data, this.dataAnonymous); - this.initAnonymousRecommendDom(this.dataAnonymous); - } else { - if (this.GETANONYMOUSDATANUMBER < this.TRYTIMES) { - this.getJson(this.getAnonymousComJson + this.randomStr(10)); - this.GETANONYMOUSDATANUMBER++; - } - } - }, - - // 3 Times - tryRequest: function(url) { - this.getJson(url); - }, - - // Init Data - initData: function(data, o, num) { - var dataLen = 0; - if (!!data.length) { - var dataLen = data.length; - } - if (!!num && num < dataLen) { - len = this.MAXSHOWNUMBER; - } else { - len = dataLen; - } - for (var i = 0; i < len; i++) { \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykhome.css0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykhome.css0-7000 deleted file mode 100644 index 596e071..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykhome.css0-7000 +++ /dev/null @@ -1 +0,0 @@ -#m_205805 .yk-row-index{margin-bottom:10px}.yk-con{padding-top:30px}.uhome-ico{background:url("/index/img/2015/ykhome.png") no-repeat}.uhome-ico-dots{width:7px;height:27px;background-position:-63px -46px;display:inline-block}.uhome-ico-dots:hover{background-position:-87px -46px}.uhome-ico-subupdate{background-position:-113px -76px;display:inline-block;width:29px;height:29px;vertical-align:bottom;margin-right:10px}.uhome-ico-subrec{background-position:-113px 0;width:30px;height:30px;display:inline-block}.uhome-ico-arrow-right{background-position:-89px -26px;height:12px;width:6px}.uhome-ico-sub-mini{height:12px;width:12px;display:inline-block;background-position:-61px -26px}.ico-loading-64{width:64px;height:64px;background:url(/index/img/2013/loading_64.gif) no-repeat;display:block;margin:0 auto}.yk-drawer{margin-bottom:0;box-sizing:border-box;border-top:solid #e9e9e9 1px;padding:20px 10px 10px 10px;margin-left:-10px;margin-right:-10px;position:relative}.yk-slide-tv{height:390px}.yk-slide-tv .yk-slide-pages .yk-slide-tv-page{float:left;margin-left:0;margin-right:0}.yk-slide-new .yk-slide-btnnext{width:1px;box-shadow:6px 0 10px 4px #000;-webkit-box-shadow:6px 0 10px 4px #000;-moz-box-shadow:6px 0 10px 4px #000;-o-box-shadow:6px 0 10px 4px #000;-ms-box-shadow:6px 0 10px 4px #000;right:-1px;background:none}.yk-slide-new .yk-slide-btnnext:hover{background:none}.yk-slide-new .yk-slide-btnnext i{background:url("/index/img/2013/slide_next_btn_new.png") no-repeat;width:24px;height:80px;margin-top:-40px}.yk-slide-new .yk-slide-btnnext i:hover{opacity:.7}.yk-slide-new .yk-slide-btnprev{width:1px;box-shadow:-6px 0 10px 4px #000;-webkit-box-shadow:-6px 0 10px 4px #000;-moz-box-shadow:-6px 0 10px 4px #000;-o-box-shadow:-6px 0 10px 4px #000;-ms-box-shadow:-6px 0 10px 4px #000;left:-1px;background:none}.yk-slide-new .yk-slide-btnprev:hover{background:none}.yk-slide-new .yk-slide-btnprev i{background:url("/index/img/2013/slide_prev_btn_new.png") no-repeat;width:24px;height:80px;margin-top:-40px}.yk-slide-new .yk-slide-btnprev i:hover{opacity:.7}.ico-drawer-ontop{display:none;width:36px;height:18px;vertical-align:middle;*vertical-align:bottom;_vertical-align:bottom;margin-left:10px;margin-bottom:5px}.yk-drawer-box .yk-head{height:35px;margin-bottom:20px}.yk-drawer-box .yk-head .yk-title{line-height:44px}.yk-drawer-box .yk-head .yk-title .yk-drawer-title{line-height:44px}.yk-drawer-box .yk-head .yk-title img{width:35px;height:35px;margin-right:10px;vertical-align:top}.yk-drawer-box .yk-head .yk-title .ico-drawer-ontop{margin-bottom:0}.yk-drawer-box .yk-head .yk-append{margin-bottom:5px}.yk-drawer-box .yk-head .yk-append .yk-tab li{margin-bottom:2px}.yk-drawer-box .yk-topic-head{height:20px}.yk-drawer-box .yk-topic-head .yk-title{line-height:20px}.yk-drawer-box .yk-body .yk-row-index{margin-bottom:0}.yk-side-range{margin-top:55px;margin-bottom:10px}.yk-side-range .yk-head{margin-bottom:10px}.yk-side-range .yk-act-link{background:none}.yk-drawer-act{padding-right:20px;width:20px;height:30px;position:absolute;top:25px;right:-10px;text-align:right;cursor:pointer}.yk-drawer-act:hover .uhome-ico-dots{background-position:-87px -46px}.yk-drawer-act .act-list{display:none;position:absolute;border:solid 1px #e9e9e9;top:0;right:37px;width:110px;height:64px;font-size:14px;font-family:"Microsoft YaHei","微软雅黑",SimHei,helvetica,arial,verdana,tahoma,sans-serif;background:#fff;padding:2px;box-shadow:0 0 10px #ddd;-webkit-box-shadow:0 0 10px #ddd;-moz-box-shadow:0 0 10px #ddd;-o-box-shadow:0 0 10px #ddd;-ms-box-shadow:0 0 10px #ddd;box-sizing:border-box}.yk-drawer-act .act-list .act-item{display:block;width:100%;text-align:center;height:30px;line-height:30px}.yk-drawer-act .act-list .act-item:hover{background:#eee}.yk-drawer-act-hover{z-index:100}.yk-drawer-act-hover .act-list{display:block}.yk-drawer-act-hover .uhome-ico-dots{background-position:-87px -46px}.yk-drawer-mixin .yk-drawer-box .yk-head{height:30px;line-height:30px;margin-bottom:20px}.yk-drawer-mixin .yk-drawer-box .yk-head .yk-title{height:30px;line-height:30px}.yk-drawer-mixin .yk-drawer-box .yk-head .yk-title span{height:30px;line-height:30px;display:block}.yk-drawer-mixin .yk-drawer-box .yk-head .yk-title .yk-drawer-title{height:30px;line-height:30px;display:block}.yk-drawer-notitle .yk-drawer-box .yk-head{height:30px}.dragmodule-top .ico-drawer-ontop{display:inline-block}.v .va{background:none}.ico-dot-left{background-position:0 -85px}.ico-dot-right{background-position:0 -94px}.yk-drawer-hidden{padding-bottom:0;padding-top:0}.yk-drawer-hidden .yk-row{*width:100%;_width:100%}.yk-drawer-hidden .hidden-list{overflow:hidden;display:none;margin-top:20px}.yk-drawer-hidden .hidden-list .hidden-item{float:left;margin:0 10px 20px 10px;width:90px;height:90px;position:relative;display:none}.yk-drawer-hidden .hidden-list .hidden-item .hidden-img{width:100%;height:100%}.yk-drawer-hidden .hidden-list .hidden-item .hidden-cover{position:absolute;width:100%;height:100%;text-align:center;color:#3399e0;background:#fff;opacity:.8;font-size:16px;font-family:"Microsoft YaHei","微软雅黑",SimHei,helvetica,arial,verdana,tahoma,sans-serif;cursor:pointer;display:none}.yk-drawer-hidden .hidden-list .hidden-item .hidden-cover .ico-add{width:35px;height:35px;display:block;vertical-align:middle;margin:15px auto 10px auto;background-position:-18px -26px}.yk-drawer-hidden .hidden-list .hidden-item:hover .hidden-cover{display:block}.yk-drawer-hidden .hidden-list:after{content:"";display:block;clear:both}.yk-drawer-hidden .hidden-hint{text-align:center;font-family:"Microsoft YaHei","微软雅黑",SimHei,helvetica,arial,verdana,tahoma,sans-serif;font-size:14px;height:14px;line-height:14px;padding:20px 0;position:relative;cursor:pointer}.yk-drawer-hidden .hidden-hint:hover{background:#f5f5f5}.yk-drawer-hidden .hidden-hint .hint{display:inline-block;font-family:"Microsoft YaHei","微软雅黑",SimHei,helvetica,arial,verdana,tahoma,sans-serif;font-size:14px;height:14px;line-height:14px;color:#555;margin-right:20px}.yk-drawer-hidden .hidden-hint .hidden-act{color:#3399e0;cursor:pointer;height:14px;line-height:14px;display:inline-block}.yk-drawer-hidden .hidden-hint .act-reset{position:absolute;right:10px;top:0;display:none}.yk-drawer-hidden .hidden-hint .act-reset:hover{color:#c31}.yk-drawer-hidden .hidden-hint .act-reset-hide{display:none}.yk-drawer-hidden-show{padding-bottom:10px}.yk-drawer-hidden-show .hidden-hint .act-reset{display:none}.yk-drawer-subscribe{padding-top:30px;padding-bottom:0;height:auto}.yk-drawer-subscribe .yk-drawer-box .yk-head{height:26px;line-height:26px;margin-bottom:20px}.yk-drawer-subscribe .yk-drawer-box .yk-head .yk-title{height:26px}.yk-drawer-subscribe .yk-drawer-box .yk-head .yk-title .yk-drawer-title{line-height:26px;display:block;height:26px}.yk-drawer-subscribe .yk-drawer-box .yk-head .yk-append{margin-bottom:0}.yk-drawer-subscribe .yk-drawer-box .yk-head .link-subscribe{font-family:"Microsoft YaHei","微软雅黑",helvetica,arial \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykhome.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykhome.png0-7000 deleted file mode 100644 index 11a233d..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/ykhome.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yklogo_h.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yklogo_h.png0-7000 deleted file mode 100644 index 9fca8d3..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/yklogo_h.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/youku_laifeng_v3.js0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/youku_laifeng_v3.js0-7000 deleted file mode 100644 index 586cd8d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/youku_laifeng_v3.js0-7000 +++ /dev/null @@ -1,167 +0,0 @@ -(function(){ - - var _isRequest = false; - ready(function(){ - bind(window,'scroll',function(){ - loadLaifeng(); - }); - loadLaifeng(); - }); - - - function loadLaifeng() { - if(_isRequest) return false; - var _laifeng = document.getElementById('LAIFENG_REQUEST'); - var _top = _laifeng.parentNode.parentNode.parentNode.parentNode.offsetTop; - var ele = (document.documentElement && document.documentElement.scrollTop)?document.documentElement:document.body; - if(ele.scrollTop+800>_top) { - _isRequest = true; - xmloadingjs('http://www.laifeng.com/cms/youku/home_channel?_t='+new Date().getTime(),function(){ - readData(); - }); - } - } - - function readData() { - var _xm_container = document.getElementById('LAIFENG_REQUEST'); - if(!_xm_container || typeof lf_live_data=='undefined') return; - var data = lf_live_data; - var html = ''; - //左侧 - html+='<div class="yk-w970-col12 yk-w1190-col16 yk-drawer-box"><div class="yk-box">'; - html+='<div class="yk-head">'+ - '<div class="yk-title">'+ - '<a target="_blank" href="http://www.laifeng.com/anchor/search" class="yk-drawer-title"><img src="http://static.youku.com/ddshow/img/youku/laifeng.png">æ¥ç–¯äº’动直播</a>'+ - '</div>'+ - '</div>'; - html+='<div class="yk-body"><div class="yk-v-190"><div class="yk-row">'+loadConnect(data)+'</div></div></div>'; - html+='</div></div></div>'; - //å³ä¾§ - html+='<div class="yk-col6"><div class="yk-side-range"><div class="yk-box"><div class="yk-body">'; - html+=loadRank(data,4)+'</div></div></div></div>'; - // - html+='<div class="yk-drawer-act">'+ - '<i class="act-btn uhome-ico uhome-ico-dots" data-stat-role="ck"></i>'+ - '<div class="act-list">'+ - '<span class="act-item item-totop" data-stat-role="ck">置顶</span>'+ - '<span class="act-item item-hide" data-stat-role="ck">éšè—</span>'+ - '</div>'+ - '</div>'; - _xm_container.innerHTML = html; - } - - //加载内容体 - function loadConnect(DATA) { - var _html = ''; - for(var i=0;i<Math.min(DATA.length,4);i++) { - var data = DATA[i]; - if(i==3) { - _html+='<div class="yk-col4 yk-w970-hide">'; - } - else { - _html+='<div class="yk-col4">'; - } - _html+='<div class="v">'+ - '<div class="v-thumb">'+ - '<img alt="'+data.title+'" src="'+data.faceUrl+'">'; - if(data.showing) { - _html+='<div style="background:url(http://r4.ykimg.com/0510000052B92FFA6714C031CB064428) no-repeat;height:32px;position: absolute;right: 0;top: 0;width: 33px;"></div>'; - } - _html+='</div>'+ - '<div class="v-link">'+ - '<a title="'+data.title+'" target="_blank" href="'+data.url+'"></a>'+ - '</div>'+ - '<div class="v-meta va">'+ - '<div class="v-meta-title">'+ - '<a target="_blank" href="'+data.url+'">'+data.title+'</a>'+ - '</div>'+ - '<div class="v-meta-entry">'+ - '<i title="播放" class="ico-statplay"></i><span class="v-num">'; - if(data.showing && !data.livehouse){ - _html+=data.people+'人正在观看'; - }else{ - _html+='<a target="_blank" href="'+data.url+'">查看详情</a>'; - } - _html+='</span></div>'+ - '</div></div></div>'; - } - return _html; - } - - //加载排行榜 - function loadRank(DATA,n) { - var html = ''; - if(DATA.length<=n) return html; - for(var i=n;i<Math.min(DATA.length,7);i++) { - var data = DATA[i]; - html+='<div class="v v-mini v-horiz" >'; - html+='<div class="v-thumb"><img alt="'+data.title+'" src="'+data.faceUrl+'">'; - html+='</div>'; - html+='<div class="v-link"><a href="'+data.url+'" target="_blank" title="'+data.title+'"></a></div>'; - html+='<div class="v-meta">'+ - '<div class="v-meta-title">'+ - '<a href="'+data.url+'" target="_blank">'+data.title+'</a>'+ - '</div>'+ - '<div class="v-meta-entry"><span>'; - if(data.showing && !data.livehouse){ - html+=data.people+'人正在观看'; - } - html+='</span></div></div></div>'; - } - return html; - } - - function xmloadingjs(url,callback,id) { - var road = document.createElement('script'); - road.type = 'text/javascript'; - road.src = url; - if(typeof id !='undefined') road.id = id; - document.getElementsByTagName('head')[0].appendChild(road); - if(road.readyState) { - road.onreadystatechange = function() { - if(road.readyState == 'loaded' || road.readyState == 'complete') { - road.onreadystatechange = null; - if(callback && Object.prototype.toString.call(callback)==='[object Function]') callback(road); - } - } - } - else { - road.onload = function() { - callback(road); - } - } - } - - function bind(ele, name, fn) { - if (ele.attachEvent) { - ele['e' + name + fn] = fn; - ele[name + fn] = function () { - ele['e' + name + fn](window.event); - } - ele.attachEvent('on' + name, ele[name + fn]); - } - else ele.addEventListener(name, fn, false); - } - - //返回元素的ä½ç½® - function LFpos(el) { - if(el.parentNode === null || el.style.display == 'none') return false; - var parent = null,pos = [],box; - if (el.getBoundingClientRect) { - box = el.getBoundingClientRect(); - var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop); - var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft); - return { - x: box.left + scrollLeft, - y: box.top + scrollTop - }; - } - else - if (document.getBoxObjectFor) { - box = document.getBoxObjectFor(el); - var borderLeft = (el.style.borderLeftWidth) ? parseInt(el.style.borderLeftWidth) : 0; - var borderTop = (el.style.borderTopWidth) ? parseInt(el.style.borderTopWidth) : 0; - pos = [box.x - borderLeft, box.y - borderTop]; - } - else { - pos \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/zy.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/zy.png0-7000 deleted file mode 100644 index 90cf102..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/cache/zy.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/client.py b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/client.py deleted file mode 100644 index 665e80e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/client.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python -# coding=UTF-8 -# Copyright (c) 2014, Peter Ruibal. All rights reserved. -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. -# -from twisted.internet import protocol, reactor -from twisted.internet.error import CannotListenError, ConnectError -from twisted.internet.interfaces import IReactorTCP, IReactorSSL - -from twisted.protocols import tls -from twisted.python import log - -from twisted.web import http - -from zope.interface import implements - - -class ProxyConnectError(ConnectError): - pass - - -class HTTPProxyConnector(object): - """Helper to wrap reactor connection API (TCP, SSL) via a CONNECT proxy.""" - implements(IReactorTCP, IReactorSSL) - - def __init__(self, proxy_host, proxy_port, - reactor=reactor): - self.proxy_host = proxy_host - self.proxy_port = proxy_port - self.reactor = reactor - - def listenTCP(port, factory, backlog=50, interface=''): - raise CannotListenError("Cannot BIND via HTTP proxies") - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - f = HTTPProxiedClientFactory(factory, host, port) - self.reactor.connectTCP(self.proxy_host, - self.proxy_port, - f, timeout, bindAddress) - - def listenSSL(self, port, factory, contextFactory, backlog=50, interface=''): - raise CannotListenError("Cannot BIND via HTTP proxies") - - def connectSSL(self, host, port, factory, contextFactory, timeout=30, - bindAddress=None): - tlsFactory = tls.TLSMemoryBIOFactory(contextFactory, True, factory) - return self.connectTCP(host, port, tlsFactory, timeout, bindAddress) - - -class HTTPProxiedClientFactory(protocol.ClientFactory): - """ClientFactory wrapper that triggers an HTTP proxy CONNECT on connect""" - def __init__(self, delegate, dst_host, dst_port): - self.delegate = delegate - self.dst_host = dst_host - self.dst_port = dst_port - - def startedConnecting(self, connector): - return self.delegate.startedConnecting(connector) - - def buildProtocol(self, addr): - p = HTTPConnectTunneler(self.dst_host, self.dst_port, addr) - p.factory = self - return p - - def clientConnectionFailed(self, connector, reason): - return self.delegate.clientConnectionFailed(connector, reason) - - def clientConnectionLost(self, connector, reason): - return self.delegate.clientConnectionLost(connector, reason) - - -class HTTPConnectTunneler(protocol.Protocol): - """Protocol that wraps transport with CONNECT proxy handshake on connect - - `factory` MUST be assigned in order to use this Protocol, and the value - *must* have a `delegate` attribute to trigger wrapped, post-connect, - factory (creation) methods. - """ - http = None - otherConn = None - noisy = True - - def __init__(self, host, port, orig_addr): - self.host = host - self.port = port - self.orig_addr = orig_addr - - def connectionMade(self): - self.http = HTTPConnectSetup(self.host, self.port) - self.http.parent = self - self.http.makeConnection(self.transport) - - def connectionLost(self, reason): - if self.noisy: - log.msg("HTTPConnectTunneler connectionLost", reason) - - if self.otherConn is not None: - self.otherConn.connectionLost(reason) - if self.http is not None: - self.http.connectionLost(reason) - - def proxyConnected(self): - # TODO: Bail if `self.factory` is unassigned or - # does not have a `delegate` - self.otherConn = self.factory.delegate.buildProtocol(self.orig_addr) - self.otherConn.makeConnection(self.transport) - - # Get any pending data from the http buf and forward it to otherConn - buf = self.http.clearLineBuffer() - if buf: - self.otherConn.dataReceived(buf) - - def dataReceived(self, data): - if self.otherConn is not None: - if self.noisy: - log.msg("%d bytes for otherConn %s" % - (len(data), self.otherConn)) - return self.otherConn.dataReceived(data) - elif self.http is not None: - if self.noisy: - log.msg("%d bytes for proxy %s" % - (len(data), self.otherConn)) - return self.http.dataReceived(data) - else: - raise Exception("No handler for received data... :(") - - -class HTTPConnectSetup(http.HTTPClient): - """HTTPClient protocol to send a CONNECT message for proxies. - - `parent` MUST be assigned to an HTTPConnectTunneler instance, or have a - `proxyConnected` method that will be invoked post-CONNECT (http request) - """ - noisy = True - - def __init__(self, host, port): - self.host = host - self.port = port - - def connectionMade(self): - self.sendCommand('CONNECT', '%s:%d' % (self.host, self.port)) - self.endHeaders() - - def handleStatus(self, version, status, message): - if self.noisy: - log.msg("Got Status :: %s %s %s" % (status, message, version)) - if str(status) != "200": - raise ProxyConnectError("Unexpected status on CONNECT: %s" % status) - - def handleHeader(self, key, val): - if self.noisy: - log.msg("Got Header :: %s: %s" % (key, val)) - - def handleEndHeaders(self): - if self.noisy: - log.msg("End Headers") - # TODO: Make sure parent is assigned, and has a proxyConnected callback - self.parent.proxyConnected() - - def handleResponse(self, body): - if self.noisy: - log.msg("Got Response :: %s" % (body)) - - -if __name__ == '__main__': - import sys - import argparse - - log.startLogging(sys.stderr) - - ap = argparse.ArgumentParser() - ap.add_argument('--proxy-host', default='localhost') - ap.add_argument('--proxy-port', default=8080, type=int) - ns = ap.parse_args() - - proxy = HTTPProxyConnector(proxy_host=ns.proxy_host, - proxy_port=ns.proxy_port) - - def cb(*args, **kwargs): - log.msg("Got callback: args=%s, kwargs=%s" % - (args, kwargs)) - - import twisted.web.client - agent = twisted.web.client.Agent(reactor=proxy) - #d = agent.request('GET', 'https://www.google.com/robots.txt') - #d = agent.request('GET', 'http://www.baidu.com') - d = agent.request('CONNECT', 'https://www.baidu.com') - d.addCallback(cb) - - reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/data.json b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/data.json deleted file mode 100644 index 052ea04..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/data.json +++ /dev/null @@ -1 +0,0 @@ -{"http://static.youku.com/v1.0.1029/cms/img/zy.png": "0-7000", "http://static.youku.com/v1.0.1029/cms/img/ent.png": "0-7000", "http://static.youku.com/index/img/2013/video/video_default_90x50.png": "0-7000", "http://r1.ykimg.com/0510000054D335C46737B35DA20A3BAD.jpg": "0-7000", "http://r4.ykimg.com/051000005420056E6737B303C10BA44F": "0-7000", "http://static.youku.com/v1.0.1064/js/prototype.js": "0-7000", "http://g4.ykimg.com/0100641F465582E7EB5E5105BB0734254F8937-F2A3-13AF-E6F5-1418A4E1B9DF": "0-7000", "http://r2.ykimg.com/05100000541BFD256737B3253A0C3326": "0-7000", "http://static.youku.com/ddshow/img/static/js/youku_laifeng_v3.js": "0-7000", "http://r2.ykimg.com/05100000541BACD06737B324F8044827": "0-7000", "http://g2.ykimg.com/0130391F4853F7111D30AC18B4BF7F24AD0453-006A-4D5E-1A0C-8C6FE3F2EFB5": "0-7000", "http://static.youku.com/index/img/2013/video/bg_video_small.png": "0-7000", "http://static.youku.com/v1.0.1064/index/js/popup.js": "0-7000", "http://r1.ykimg.com/05100000541BFD086737B37D42083926": "0-7000", "http://static.youku.com/v1.0.1064/index/js/qwindow.js": "0-7000", "http://static.youku.com/lvip/css/chuda.css": "0-7000", "http://r2.ykimg.com/05100000541BFD256737B324D10D395E": "0-7000", "http://r1.ykimg.com/0510000054FD72CF6737B34B240EFFBA": "0-7000", "http://r3.ykimg.com/051500005583904D67BC3D29510BD425": "0-7000", "http://r3.ykimg.com/05100000541FF4DE6737B325270C6213": "0-7000", "http://static.youku.com/v1.0.1064/cms/js/cmsCommon.js": "0-7000", "http://static.youku.com/v1.0.1064/index/css/yk.css": "0-7000", "http://static.youku.com/v1.0.1064/index/css/qfooter.css": "0-7000", "http://g4.ykimg.com/0130391F4854DE23ABDA71085AD8AF4040077C-72D6-D10E-A8E2-281A83037160": "0-7000", "http://notify.youku.com/notify/get.json": "0-7000", "http://r1.ykimg.com/05100000541BACD06737B324F7010C74": "0-7000", "http://r3.ykimg.com/05100000541BFD0A6737B308AE066CC0": "0-7000", "http://r1.ykimg.com/05100000541BACCF6737B325220573FE": "0-7000", "http://g1.ykimg.com/0100641F46556481A0D4350558C2B7056D2567-E140-E9EA-53E4-8A1535C67127": "0-7000", "http://r1.ykimg.com/05100000553705DB67BC3D67110609FA": "0-7000", "http://r2.ykimg.com/05100000552E1B996737B3642106DE84": "0-7000", "http://g2.ykimg.com/0130391F455343A27D3516154C5F2A7A7A1CE3-3CB4-2AEB-EFC8-01634479C14C": "0-7000", "http://r2.ykimg.com/05100000553F5B7D67BC3D224004FF65": "0-7000", "http://static.youku.com/index/img/2013/video/video_default_200x110.png": "0-7000", "http://static.youku.com/v1.0.1063/index/js/tdstat.js": "0-7000", "http://g3.ykimg.com/0130391F4554C59AB6E5630023C04A1E86AF52-68DD-5B50-DDC7-3543E9FB93EB": "0-7000", "http://static.youku.com/v1.0.1063/index/js/resize.js": "0-7000", "http://r3.ykimg.com/05100000541FBFF26737B324F60BE6B0": "0-7000", "http://static.youku.com/v1.0.1064/cms/js/seedVideo.js": "0-7000", "http://static.youku.com/index/img/2013/video/drama.8.png": "0-7000", "http://r4.ykimg.com/051000005583663E67BC3D341D028BED": "0-7000", "http://r2.ykimg.com/05100000541BFD096737B3252D0AFCFF": "0-7000", "http://g1.ykimg.com/0100641F465583D3F04A5700E80CB75F5BCF7B-8020-9C8F-4515-81E495F8611F": "0-7000", "http://r1.ykimg.com/05100000541BFD086737B3251A049E21": "0-7000", "http://g3.ykimg.com/0130391F4554B34D520590019C3C1C25B031CE-29D3-4997-82BB-7B54B693C5F5": "0-7000", "http://g4.ykimg.com/0100641F46557B6A1382530064DE1D3F5F87B4-39BF-0849-7D22-156D4127404B": "0-7000", "http://static.youku.com/v1.0.1064/index/img/toolbar.png": "0-7000", "http://g4.ykimg.com/0130391F4554DC5277E951181CBEAD9761A8B9-B30B-B81C-5B88-F6AC54AB1057": "0-7000", "http://static.youku.com/v1.0.1064/index/js/lsidetoolresize.js": "0-7000", "http://r3.ykimg.com/05100000553F5B7E67BC3D6D44065FB5": "0-7000", "http://r1.ykimg.com/05100000553705DC67BC3D302B084694": "0-7000", "http://g4.ykimg.com/0130391F455518AD375BCE149CC8F8C957D3C4-4230-0AFD-7631-A945BA2736EE": "0-7000", "http://g4.ykimg.com/0100641F4653D768233BE001963F4937519C71-2016-F477-11BC-63A6154F9068": "0-7000", "http://static.youku.com/index/img/header/yklogo_h.png": "0-7000", "http://g1.ykimg.com/0130391F48533B991848F6139B1FA448622DEF-D1C2-EF5A-894E-76ACA2B7040B": "0-7000", "http://g3.ykimg.com/0100641F46556BCA66A6790945A1DB973566E5-BE5C-2B30-DC7B-918FB15F384F": "0-7000", "http://html.atm.youku.com/html": "0-7000", "http://192.168.232.1/cgi-bin/luci/;stok=a094fa1c55f2125e2a34caadef198da8": "0-7000", "http://r2.ykimg.com/05100000541BFD256737B35F7208971D": "0-7000", "http://g4.ykimg.com/0130391F455443B94F99C60309545B4E6A9869-B6C0-ECA5-264D-37E90D4A62EA": "0-7000", "http://www.youku.com/": "0-7000", "http://static.youku.com/index/img/2013/ico-cert.24.png": "0-7000", "http://g4.ykimg.com/0130391F45540F219F90571975D51733572DE9-180A-C171-DDB1-75757E59B4F4": "0-7000", "http://g2.ykimg.com/0130391F45530DBD99CBF3150EABFA52F54356-2481-BECE-753B-DC8FAD62B933": "0-7000", "http://static.youku.com/v1.0.1063/cms/js/ani.js": "0-7000", "http://static.youku.com/lvip/msg/share_msg.js": "0-7000", "http://r4.ykimg.com/05150000558365EA67BC3D67A20737D5": "0-7000", "http://r4.ykimg.com/05100000541BAC936737B324D20A73CC": "0-7000", "http://g2.ykimg.com/0130391F4854D0895D6A8805BB073478A9822B-5C97-3887-415F-2E6180EC7756": "0-7000", "http://r1.ykimg.com/05100000541BAC936737B324FF0DE0DD": "0-7000", "http://static.youku.com/v1.0.1064/js/jquery.js": "0-7000", "http://static.youku.com/v1.0.1029/cms/img/tv.png": "0-7000", "http://r1.ykimg.com/05100000541BFD246737B3253703FCC7": "0-7000", "http://g1.ykimg.com/0100641F46549B16F4244C0309545BF3AFB0B0-369D-FF3C-5166-5DE789FB51AA": "0-7000", "http://g3.ykimg.com/0130391F484B9E3E4AA935035C40D293C76276-0DA3-0C1C-7B62-D715A4501FBC": "0-7000", "http://g2.ykimg.com/0130391F4553BDFD01FB0D04A0DAFB54F6F014-8FDF-60AD-0854-2F756AC1692C": "0-7000", "http://static.youku.com/lvip/js/chuda.js": "0-7000", "http://g4.ykimg.com/0130391F45556565BF3FC618BEA3B9F65CB7BC-DB27-4D1B-43BC-EA5F44B1C7A9": "0-7000", "http://r1.ykimg.com/05100000541BACD06737B30E4C0AACCA": "0-7000", "http://r1.ykimg.com/05100000541BFD086737B3340202B8E3": "0-7000", "http://g3.ykimg.com/0100641F465583C9D2605D058DBBB006045D0D-6A74-3295-3DB8-6980C3201111": "0-7000", "http://r3.ykimg.com/05100000541FBFF16737B324E90D1E7E": "0-7000", "http://static.youku.com/v1.0.1064/index/css/ykhome.css": "0-7000", "http://static.youku.com/index/img/header/header.png": "0-7000", "http://static.youku.com/v1.0.1063/index/js/compiler.js": "0-7000", "http://static.youku.com/v1.0.1064/cms/js/cmsDatafromPrototype.js": "0-7000", "http://static.youku.com/index/img/header/vip.png": "0-7000", "http://static.youku.com/v1.0.1029/cms/img/vip.png": "0-7000", "http://g2.ykimg.com/0130391F45502C70118BE9058DBBB029BC8227-CBC8-BBE7-60CD-EC0810E9F220": "0-7000", "http://r4.ykimg.com/05100000541BAC936737B3562D0BA492": "0-7000", "http://static.youku.com/v1.0.1064/index/css/lsidetool.css": "0-7000", "http://g4.ykimg.com/0130391F45530C4DA78A25019DBA844C3DDB4C-443A-5C79-2FD6-E846C2065EC5": "0-7000", "http://static.youku.com/v1.0.0223/v/swf/loader.swf": "0-7000", "http://g2.ykimg.com/0130391F455546D8A9E2D41CAD43974209F70D-FD38-03D4-66C7-270F40BEEC1A": "0-7000", "http://qzapp.qlogo.cn/qzapp/200004/6B16A4E9B53D0465CD6B3B239C938EFE/50": "0-7000", "http://r3.ykimg.com/05100000541FBFF26737B3636E0429E7": "0-7000", "http://g4.ykimg.com/0130391F4550C6E8234FC20830E1366754DB3E-08E4-6423-5297-D1C992589702": "0-7000", "http://g1.ykimg.com/0130391F455269DDF4FAFF08565B2626163821-113D-8012-C8DD-2591F2300453": "0-7000", "http://static.youku.com/index/img/2013/video/bg_video_mini.png": "0-7000", "http://g1.ykimg.com/0130391F4554897F747485132160689D03CD26-3A52-8330-6935-E427C6D30D43": "0-7000", "http://static.youku.com/user/img/avatar/50/53.jpg": "0-7000", "http://r3.ykimg.com/051000005583663E67BC3D20A50C8717": "0-7000", "http://g1.ykimg.com/0130391F48535D4FF8C1A1025A18B5F1B790C5-B05C-A83B-D4DB-98C60684E03C": "0-7000", "http://r2.ykimg.com/05100000541BFD246737B35F790A9FC7": "0-7000", "http://static.youku.com/v1.0.1064/index/js/common.js": "0-7000", "http://r2.ykimg.com/05100000553F5B7D67BC3D082C0D4239": "0-7000", "http://static.youku.com/v1.0.1064/index/js/iresearch.js": "0-7000", "http://g1.ykimg.com/0130391F45554F303059ED095CD25C6DC27A06-69C1-4830-2735-1BA36537DBCF": "0-7000", "http://g4.ykimg.com/0100641F465583949F9F8B035C40D23631B19F-7100-519A-4AF5-920A50F2C459": "0-7000", "http://r2.ykimg.com/05100000541BACD16737B36D870ADB5F": "0-7000", "http://g3.ykimg.com/0100641F46557ED70EFC9B053F14D114D38641-39F8-9BCC-22E3-7E35AE57069F": "0-7000", "http://g1.ykimg.com/0130391F455463233C4D1A1BA985B0A18CFBF7-9827-5003-58E8-966A559DED6C": "0-7000", "http://static.youku.com/v1.0.1064/paycenter/js/cps.js": "0-7000", "http://r3.ykimg.com/05100000541BFD0A6737B325300D6F0B": "0-7000", "http://g4.ykimg.com/0130391F485236FCB7B2B50504571BC3F0882E-1B2F-29BF-4FB3-546E15DFD5E5": "0-7000", "http://g2.ykimg.com/0130391F484E951B5D2D5A059C8CE6264DAA6D-BEF3-4F0F-59C6-02074EC0EFF1": "0-7000", "http://static.youku.com/index/img/2013/video/video_default_420x240.png": "0-7000", "http://r2.ykimg.com/051500005583850C67BC3D22B40DD3C4": "0-7000", "http://r2.ykimg.com/05100000541BFD096737B37AF104C6F0": "0-7000", "http://r2.ykimg.com/05100000541BFD096737B325200C8DA8": "0-7000", "http://g1.ykimg.com/0100641F4654C10E0439130381150BAA5AD25D-3E86-C49F-51CC-B1900F76D4B8": "0-7000", "http://g4.ykimg.com/0130391F4554FD024F373800E80CB7CBB177A0-CE0D-F46A-6E9C-452073CBC94B": "0-7000", "http://g4.ykimg.com/0100641F46557FE65B99CB154C5F2A10701786-4968-7D5E-89EA-BB61473AFDCC": "0-7000", "http://static.youku.com/v1.0.1063/index/js/sideTool.js": "0-7000", "http://r2.ykimg.com/05100000541BACD16737B3250E0CFD70": "0-7000", "http://r3.ykimg.com/05100000556821A267BC3D2CB10AD9A2": "0-7000", "http://g3.ykimg.com/0130391F45552FCEB2AA4107ED621339A761B9-B2E9-64CF-65E8-2C2B5F5757DF": "0-7000", "http://static.youku.com/v1.0.1063/index/css/sideTool.css": "0-7000", "http://g4.ykimg.com/0130391F45549CD39F378202E272768B8E6D32-B9FC-5BB8-7460-8CE54D81E96D": "0-7000", "http://static.youku.com/index/img/2013/video/yk.8.png": "0-7000", "http://static.youku.com/v1.0.1063/cms/js/ykRecommend.js": "0-7000", "http://r1.ykimg.com/05100000541BFD246737B349090CEA21": "0-7000", "http://r3.ykimg.com/05100000541BFD2E6737B371B30A9BDA": "0-7000", "http://g4.ykimg.com/0130391F4554F20EC3A786189FF021190DA8B8-2BDB-69B6-1264-95CA09BEB5AC": "0-7000", "http://static.youku.com/v1.0.1029/cms/img/music.png": "0-7000", "http://r4.ykimg.com/05100000556821B667BC3D2ABE042C2E": "0-7000", "http://static.youku.com/v1.0.1029/cms/img/film.png": "0-7000", "http://r1.ykimg.com/05100000541BFD076737B3250308E216": "0-7000", "http://static.youku.com/v1.0.1064/index/css/user-grade-icon.css": "0-7000", "http://g3.ykimg.com/0130391F45556F1846579404FF5D68AF1B7579-816E-8BBA-D238-2775DE6D85FD": "0-7000", "http://g1.ykimg.com/0130391F45533B8CE4A5E7030C71A035A2D08D-1CBC-D104-230C-A9F53170EE77": "0-7000", "http://g2.ykimg.com/0130391F4551F64E09FE210558C2B738E36237-DA9D-BB3C-2F71-216A21B8D9EE": "0-7000", "http://static.youku.com/v1.0.1064/cms/js/cmsFriends.js": "0-7000", "http://g4.ykimg.com/0130391F48516FC3DB3050087AC092F0EC398D-8D7B-4EC8-713B-C0C180F4B918": "0-7000", "http://r2.ykimg.com/0510000055015FA56737B3297D0A1C7B": "0-7000", "http://r2.ykimg.com/05100000541BAC516737B324DE0AC1F2": "0-7000", "http://r3.ykimg.com/05150000558393E567BC3D441F0F22C5": "0-7000", "http://static.youku.com/index/img/2015/ykhome.png": "0-7000", "http://static.youku.com/v1.0.1029/cms/img/topic.png": "0-7000", "http://g1.ykimg.com/0130391F45557E872C1A542BBEAFBCA52959D6-31D1-5EB2-DA76-499D3ACCB475": "0-7000", "http://g4.ykimg.com/0130391F45531D77AFBA7F053F14D16A6F3894-23FF-5592-3946-B1B122D18CA3": "0-7000", "http://r3.ykimg.com/05100000557A941567BC3D7F2B0633B8": "0-7000", "http://g1.ykimg.com/0100641F465583AB307649019DBA843A8902E6-57D9-CDB4-9797-79A0537F3181": "0-7000", "http://g4.ykimg.com/0130391F4853C64EAF7E3F01963F4910007905-F37F-D6B9-ABEF-7BC345633A40": "0-7000", "http://static.youku.com/v1.0.1064/index/js/lsidetool.js": "0-7000", "http://g4.ykimg.com/0100641F465582899FAE7F04FF5D68602306AC-2941-1C75-9A04-A5449A48608F": "0-7000", "http://static.youku.com/v1.0.1029/cms/img/sport.png": "0-7000", "http://g1.ykimg.com/0100641F4653A2B540C6F60414569C20E0B182-2A0A-71C0-7E7F-CC19FCD5724C": "0-7000", "http://static.youku.com/index/img/2013/slide_next_btn_new.png": "0-7000", "http://static.youku.com/v1.0.1064/index/js/qheader.js": "0-7000", "http://g3.ykimg.com/0130391F455541295236022CF4CEEAF7692162-E86D-18B9-EAE0-80FA62A3E977": "0-7000", "http://g3.ykimg.com/0100641F4655685D5E374D04034D20302195D7-C33B-D192-AC6C-AF9F271C4C1D": "0-7000", "http://r1.ykimg.com/05100000546F10836737B34B7E03A098": "0-7000", "http://static.youku.com/v1.0.1064/index/css/qheader.css": "0-7000", "http://static.youku.com/index/img/2013/video/bg_video_large.png": "0-7000", "http://g1.ykimg.com/0130391F4553E22B8C361A0646F416ED804189-16D1-22B0-6592-2DE9528C4EBC": "0-7000", "http://g4.ykimg.com/0130391F4554FAD43BE691196BAADA00E99E44-BC12-8945-722D-C4510FDD9CB3": "0-7000", "http://static.youku.com/v1.0.1064/index/img/sprite.gif": "0-7000", "http://r1.ykimg.com/05100000547705646737B340AA0A959D": "0-7000", "http://g1.ykimg.com/0130391F45524569901F6A131478AB447A2FEC-55F2-01FC-3B9C-1CDB6B1AFA30": "0-7000", "http://static.youku.com/v1.0.1063/cms/js/hover.js": "0-7000", "http://static.youku.com/v1.0.1064/cms/css/grid_pc.css": "0-7000", "http://g2.ykimg.com/0130391F45557E1E713AB118B1115CBAC7937B-E152-14B4-1E78-D10528336416": "0-7000", "http://g2.ykimg.com/0130391F4551777BED444A04034D2005CB13D8-FC2F-D1B7-8851-E9433C59CB24": "0-7000", "http://static.youku.com/v1.0.1063/cms/js/gridTab.js": "0-7000", "http://g2.ykimg.com/0130391F484C319D5D421B0414569CC88BC50F-47D2-7856-3E92-10DE0D8759B0": "0-7000", "http://r4.ykimg.com/051000005465C14F6737B3325A0955CE": "0-7000", "http://static.youku.com/index/img/2013/video/blanksprite.png": "0-7000", "http://r4.ykimg.com/05150000558365C267BC3D28E2014B9D": "0-7000", "http://r2.ykimg.com/050C00005583B8C567BC3D6F5E07F183": "0-7000", "http://r2.ykimg.com/05100000552E1B996737B353C90605CC": "0-7000", "http://r3.ykimg.com/05150000558393A567BC3D189B076DAD": "0-7000", "http://g1.ykimg.com/0130391F4551C51ED81F47000BF9C241A7F60B-4D56-EF7B-85B5-2E0D815B11D4": "0-7000", "http://g1.ykimg.com/0130391F45539E8674235C0114FBEFF03375B3-6BE5-711A-1C82-0F6D99594D75": "0-7000"} \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/data.json~ b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/data.json~ deleted file mode 100644 index e69de29..0000000 diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/server.py b/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/server.py deleted file mode 100644 index e26c5ad..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/my-twisted-connect-proxy/server.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python -# coding=UTF-8 -# Copyright (c) 2014, Peter Ruibal. All rights reserved. -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. -# -from twisted.internet.protocol import Protocol, ClientFactory -from twisted.web.proxy import Proxy, ProxyRequest -from twisted.python import log -from CacheUtils import CacheUtils - -import urlparse - -cacheUtils = CacheUtils() - -class ConnectProxyRequest(ProxyRequest): - """HTTP ProxyRequest handler (factory) that supports CONNECT""" - - connectedProtocol = None - - def process(self): - #download all - #fileName = cacheUtils.parseUrl2FileName(self.path) - #cacheUtils.download(self.path, "./download/" + fileName) - - #download cache - range = "0-7000" - cacheUtils.cache(self.path, range) - - #checkReq & save url & range - if False == cacheUtils.checkReq(self.path): - cacheUtils.saveReq(self.path, range) - #cacheUtils.saveReq(self.path, str(self.getHeader("Range"))) - - # CONNECTå¦å†™å‡½æ•°processConnectRequest实现 - if self.method == 'CONNECT': - self.processConnectRequest() - else: - ProxyRequest.process(self) - - def fail(self, message, body): - cacheUtils.delReq(self.path) - - self.setResponseCode(501, message) - self.responseHeaders.addRawHeader("Content-Type", "text/html") - self.write(body) - self.finish() - - def splitHostPort(self, hostport, default_port): - port = default_port - parts = hostport.split(':', 1) - if len(parts) == 2: - try: - port = int(parts[1]) - except ValueError: - pass - return parts[0], port - - def processConnectRequest(self): - parsed = urlparse.urlparse(self.uri) - default_port = self.ports.get(parsed.scheme) - - host, port = self.splitHostPort(parsed.netloc or parsed.path, - default_port) - if port is None: - self.fail("Bad CONNECT Request", - "Unable to parse port from URI: %s" % repr(self.uri)) - return - - clientFactory = ConnectProxyClientFactory(host, port, self) - - # TODO provide an API to set proxy connect timeouts - self.reactor.connectTCP(host, port, clientFactory) - -#类似protocol,在这里作为客户端的角色 -class ConnectProxy(Proxy): - """HTTP Server Protocol that supports CONNECT""" - requestFactory = ConnectProxyRequest - connectedRemote = None - - def requestDone(self, request): - """connect请求 && 属于远程客户端的请求,则将该客户端改æˆå½“å‰ä»£ç†æœåŠ¡å™¨""" - if request.method == 'CONNECT' and self.connectedRemote is not None: - self.connectedRemote.connectedClient = self - else: - Proxy.requestDone(self, request) - - def connectionLost(self, reason): - """代ç†æœåŠ¡å™¨è¯·æ±‚webæœåŠ¡å™¨æ—¶ï¼Œè¿žæŽ¥æ–­å¼€äº† - ,也è¦é€šçŸ¥å¹¶æ–­å¼€ä»£ç†æœåŠ¡å™¨ä¸Žå®¢æˆ·ç«¯çš„连接""" - if self.connectedRemote is not None: - self.connectedRemote.transport.loseConnection() - Proxy.connectionLost(self, reason) - - def dataReceived(self, data): - # æ•°æ®æ”¶åˆ°åŽï¼Œå¦‚果代ç†æœåŠ¡å™¨è‡ªå·±çš„请求,自己接收, - if self.connectedRemote is None: - Proxy.dataReceived(self, data) - else: - # Once proxy is connected, forward all bytes received - # from the original client to the remote server. - # 如果是远程客户端的请求,则将数æ®ä¼ ç»™è¿œç¨‹å®¢æˆ·ç«¯ - self.connectedRemote.transport.write(data) - -#作为普通server角色 -class ConnectProxyClient(Protocol): - connectedClient = None - - def connectionMade(self): - self.factory.request.channel.connectedRemote = self - self.factory.request.setResponseCode(200, "CONNECT OK") - self.factory.request.setHeader('X-Connected-IP', - self.transport.realAddress[0]) - self.factory.request.setHeader('Content-Length', '0') - self.factory.request.finish() - - def connectionLost(self, reason): - if self.connectedClient is not None: - self.connectedClient.transport.loseConnection() - - def dataReceived(self, data): - if self.connectedClient is not None: - # Forward all bytes from the remote server back to the - # original connected client - self.connectedClient.transport.write(data) - else: - log.msg("UNEXPECTED DATA RECEIVED:", data) - -#æ•°æ®æ”¶åˆ°åŽä¼šæ¿€æ´»è¯¥å¯¹è±¡ -class ConnectProxyClientFactory(ClientFactory): - protocol = ConnectProxyClient - - def __init__(self, host, port, request): - self.request = request - self.host = host - self.port = port - - def clientConnectionFailed(self, connector, reason): - self.request.fail("Gateway Error", str(reason)) - - -if __name__ == '__main__': - import sys - log.startLogging(sys.stderr) - - import argparse - ap = argparse.ArgumentParser() - ap.add_argument('port', default=8080, nargs='?', type=int) - ap.add_argument('--ssl-cert', type=str) - ap.add_argument('--ssl-key', type=str) - ns = ap.parse_args() - - import twisted.web.http - factory = twisted.web.http.HTTPFactory() - factory.protocol = ConnectProxy - - import twisted.internet - if ns.ssl_key and not ns.ssl_cert: - log.msg("--ssl-key must be used with --ssl-cert") - sys.exit(1) - if ns.ssl_cert: - from twisted.internet import ssl - with open(ns.ssl_cert, 'rb') as fp: - ssl_cert = fp.read() - if ns.ssl_key: - from OpenSSL import crypto - with open(ns.ssl_key, 'rb') as fp: - ssl_key = fp.read() - certificate = ssl.PrivateCertificate.load( - ssl_cert, - ssl.KeyPair.load(ssl_key, crypto.FILETYPE_PEM), - crypto.FILETYPE_PEM) - else: - certificate = ssl.PrivateCertificate.loadPEM(ssl_cert) - twisted.internet.reactor.listenSSL(ns.port, factory, - certificate.options()) - else: - twisted.internet.reactor.listenTCP(ns.port, factory) - twisted.internet.reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/img.htm b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/img.htm deleted file mode 100644 index f56749e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/img.htm +++ /dev/null @@ -1,104 +0,0 @@ -<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="content-type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge"><meta content="always" name="referrer"><meta name="theme-color" content="#2932e1"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu.svg"><link rel="dns-prefetch" href="//s1.bdstatic.com"/><link rel="dns-prefetch" href="//t1.baidu.com"/><link rel="dns-prefetch" href="//t2.baidu.com"/><link rel="dns-prefetch" href="//t3.baidu.com"/><link rel="dns-prefetch" href="//t10.baidu.com"/><link rel="dns-prefetch" href="//t11.baidu.com"/><link rel="dns-prefetch" href="//t12.baidu.com"/><link rel="dns-prefetch" href="//b1.bdstatic.com"/><title>百度一下,你就知é“</title> -<style index="index" id="css_index">html,body{height:100%}html{overflow-y:auto}#wrapper{position:relative;_position:;min-height:100%}#head{padding-bottom:100px;text-align:center;*z-index:1}#ftCon{height:100px;position:absolute;bottom:44px;text-align:center;width:100%;margin:0 auto;z-index:0;overflow:hidden}#ftConw{width:720px;margin:0 auto}body{font:12px arial;text-align:;background:#fff}body,p,form,ul,li{margin:0;padding:0;list-style:none}body,form,#fm{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}.bg{background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png);background-repeat:no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif)}.bg_tuiguang_browser{width:16px;height:16px;background-position:-600px 0;display:inline-block;vertical-align:text-bottom;font-style:normal;overflow:hidden;margin-right:5px}.bg_tuiguang_browser_big{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-600px -24px} -.bg_tuiguang_weishi{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-672px -24px}.c-icon{display:inline-block;width:14px;height:14px;vertical-align:text-bottom;font-style normal;overflow:hidden;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png) no-repeat 0 0;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif)}.c-icon-triangle-down-blue{background-position:-480px -168px}.c-icon-chevron-unfold2{background-position:-504px -168px}#m{width:720px;margin:0 auto}#nv a,#nv b,.btn,#lk{font-size:14px}input{border:0;padding:0}#nv{height:19px;font-size:16px;margin:0 0 4px;text-align:left;text-indent:137px}.s_btn{width:95px;height:32px;padding-top:2px\9;font-size:14px;background-color:#ddd;background-position:0 -48px;cursor:pointer}.s_btn_h{background-position:-240px -48px}.s_btn_wr{width:97px;height:34px;display:inline-block;background-position:-120px -48px;*position:relative;z-index:0;vertical-align:top} -#lk{margin:33px 0}#lk span{font:14px "宋体"}#lh{margin:16px 0 5px}#cp,#cp a{color:#666}#cp .c-icon-icrlogo{width:14px;height:17px;display:inline-block;overflow:hidden;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png) no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif);background-position:-600px -96px;position:relative;top:3px}#shouji{margin-right:14px}#u{display:none}#c-tips-container{display:none}#wrapper{min-width:810px;height:100%;min-height:600px}#head{position:relative;padding-bottom:0;height:100%;min-height:600px}#head .head_wrapper{height:100%}#m{position:relative}#fm{padding-left:40px;top:-37px}#lh a{margin:0 10px}#lk{position:absolute;display:none;top:0;right:0}#nv{position:absolute;display:none;top:0;right:0}#lm{color:#666;width:100%;height:60px;margin-top:60px;line-height:15px;font-size:13px;position:absolute;top:0;left:0}#lm a{color:#666}#pad-version{line-height:40px} -.s_ipt_wr.bg,.s_btn_wr.bg,#su.bg{background-image:none}.s_btn_wr{width:auto;height:auto;border-bottom:1px solid transparent;*border-bottom:0}.s_btn{width:100px;height:36px;color:white;font-size:15px;letter-spacing:1px;background:#3385ff;border-bottom:1px solid #2d78f4;outline:medium;*border-bottom:0;-webkit-appearance:none;-webkit-border-radius:0}.s_btn.btnhover{background:#317ef3;border-bottom:1px solid #2868c8;*border-bottom:0;box-shadow:1px 1px 1px #ccc}.s_btn_h{background:#3075dc;box-shadow:inset 1px 1px 5px #2964bb;-webkit-box-shadow:inset 1px 1px 5px #2964bb;-moz-box-shadow:inset 1px 1px 5px #2964bb;-o-box-shadow:inset 1px 1px 5px #2964bb}#result_logo{display:none}#index_logo img{display:inline-block;width:270px;height:129px}#s_tab{display:none}.s_form{position:relative;top:38.2%}.s_form_wrapper{position:relative;top:-191px}.s_ipt_wr{height:34px}#head .c-icon-bear-round{display:none}#form{margin:22px auto 0;width:641px;text-align:left;z-index:100}#form .bdsug,#fm .bdsug{top:35px} -.bdsug{display:none;position:absolute;width:538px;background:#fff;border:1px solid #ccc;_overflow:hidden;box-shadow:1px 1px 3px #ededed;-webkit-box-shadow:1px 1px 3px #ededed;-moz-box-shadow:1px 1px 3px #ededed;-o-box-shadow:1px 1px 3px #ededed}.bdsug.bdsugbg ul{background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/sugbg_6a9201c2.png) 100% 100% no-repeat;background-size:100px 110px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/sugbg_d24a0811.gif)\9}.bdsug li{width:522px;color:#000;font:14px arial;line-height:25px;padding:0 8px;position:relative;cursor:default}.bdsug li.bdsug-s{background:#f0f0f0}.bdsug-store span,.bdsug-store b{color:#7a77c8}.bdsug-store-del{font-size:12px;color:#666;text-decoration:underline;position:absolute;right:8px;top:0;cursor:pointer;display:none}.bdsug-s .bdsug-store-del{display:inline-block}.bdsug-ala{display:inline-block;border-bottom:1px solid #e6e6e6}.bdsug-ala h3{line-height:14px;background:url(//www.baidu.com/img/sug_bd.png) no-repeat left center;margin:8px 0 5px 0;font-size:12px;font-weight:normal;color:#7b7b7b;padding-left:20px} -.bdsug-ala p{font-size:14px;font-weight:bold;padding-left:20px}.bdsug .bdsug-direct{width:auto;padding:0;border-bottom:1px solid #f1f1f1}.bdsug .bdsug-direct p{color:#00c;font-weight:bold;line-height:34px;padding:0 8px;cursor:pointer;white-space:nowrap;overflow:hidden}.bdsug .bdsug-direct p img{width:16px;height:16px;margin:7px 6px 9px 0;vertical-align:middle}.bdsug .bdsug-direct p span{margin-left:8px}.bdsug .bdsug-direct p i{font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;background-color:#2b99ff;display:inline;text-align:center;padding:1px 5px;*padding:2px 5px 0 5px;margin-left:8px;overflow:hidden}.bdsug .bdsug-pcDirect{color:#000;font-size:14px;line-height:30px;height:30px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip{position:absolute;right:15px;top:8px;width:55px;height:15px;display:block;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-s{background-color:#f0f0f0} -.bdsug .bdsug-pcDirect-is{color:#000;font-size:14px;line-height:22px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip-is{position:absolute;right:15px;top:3px;width:55px;height:15px;display:block;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-is-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-s .bdsug-pc-direct-tip,.bdsug .bdsug-pcDirect-is-s .bdsug-pc-direct-tip-is{background-position:0 -15px}.tools{position:absolute;right:-75px}#mHolder{width:62px;position:relative;z-index:296;display:none}#mCon{height:18px;line-height:18px;position:absolute;cursor:pointer}#mCon span{color:#00c;cursor:default;display:block;width:24px}#mCon .hw{text-decoration:underline;cursor:pointer;display:inline-block}#mCon .pinyin{display:inline-block}#mCon .c-icon-chevron-unfold2{margin-left:5px}#mMenu a{width:100%;height:100%;display:block;line-height:22px;text-indent:6px;text-decoration:none;filter:none\9}#mMenu,#user ul{box-shadow:1px 1px 2px #ccc;-moz-box-shadow:1px 1px 2px #ccc;-webkit-box-shadow:1px 1px 2px #ccc;filter:progid:DXImageTransform.Microsoft.Shadow(Strength=2,Direction=135,Color="#cccccc")\9} -#mMenu{width:56px;border:1px solid #9b9b9b;list-style:none;position:absolute;right:27px;top:28px;display:none;background:#fff}#mMenu a:hover{background:#ebebeb}#mMenu .ln{height:1px;background:#ebebeb;overflow:hidden;font-size:1px;line-height:1px;margin-top:-1px}#u1 a:link,#u1 a:visited{color:#666;text-decoration:none}#u1 a:hover,#u1 a:active{text-decoration:underline}#u1 a:active{color:#00c}#u1{z-index:2;color:white;position:absolute;right:0;top:0;margin:19px 0 5px 0;padding:0 96px 0 0}#u1 .reg{display:none}#u1 a.pf,#u1 a.pf:visited{display:inline-block;float:left;color:#333;line-height:24px;font-size:13px;margin-left:20px;overflow:hidden;text-decoration:underline}#u1 a.lb,#u1 a.lb:visited,#u1 a.username{display:inline-block;float:left;color:#333;font-size:13px;line-height:24px;margin-left:20px;text-decoration:underline}#u1 a.bri,#u1 a.bri:visited{display:inline-block;position:absolute;right:10px;width:60px;height:23px;float:left;color:white;background:#38f;line-height:24px;font-size:13px;text-align:center;overflow:hidden;border-bottom:1px solid #38f;margin-left:19px;margin-right:2px} -#u1 a.bri.brihover{display:none;text-decoration:none;color:#333;background:0;border-bottom:1px solid transparent;margin-left:19px}#u1 #lm a{color:#00c;text-decoration:underline}#u1 a.mnav,#u1 a.mnav:visited{float:left;color:#333;font-weight:bold;line-height:24px;margin-left:20px;font-size:13px;text-decoration:underline}#u1 a.pf:hover,#u1 a.lb:hover,#u1 a.mnav:hover{color:#00c}.briiconsbg{background-repeat:no-repeat;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png);background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9}.bdpfmenu{background-color:#fff;border:1px solid #d1d1d1;position:absolute;right:160px;width:68px;top:36px;margin-top:-1px;_margin-top:-3px;z-index:2;box-shadow:1px 1px 5px #d1d1d1;-webkit-box-shadow:1px 1px 5px #d1d1d1;-moz-box-shadow:1px 1px 5px #d1d1d1;-o-box-shadow:1px 1px 5px #d1d1d1}.bdpfmenu a{display:block;text-align:left;margin:0!important;padding:0 9px;line-height:26px;text-decoration:none} -#wrapper .bdpfmenu a:link,#wrapper .bdpfmenu a:visited{background:white;color:#333}#wrapper .bdpfmenu a:hover,#wrapper .bdpfmenu a:active{background:#38f;text-decoration:none;color:white}#wrapper .bdnuarrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-10px;left:50%;margin-left:-5px}#wrapper .bdnuarrow em,#wrapper .bdnuarrow i{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:5px solid transparent;border-style:dashed dashed solid dashed}#wrapper .bdnuarrow em{border-bottom-color:#d8d8d8;top:-1px}#wrapper .bdnuarrow i{border-bottom-color:#fff;top:0}.s-isindex-wrap #wrapper .bdnuarrow{height:13px;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png) no-repeat -90px -1px}#wrapper .bdnuarrow.bdbriarrow{right:104px;display:none!important}#wrapper .bdbri{width:85px;min-height:100px;border-left:1px solid #e7e7e7;position:absolute;background-color:#f9f9f9;overflow:hidden;z-index:2;right:0;top:0}#prefpanel{background:#fafafa;display:none;opacity:0;position:fixed;_position:absolute;top:-359px;z-index:1000;width:100%;min-width:960px;border-bottom:1px solid #ebebeb} -#prefpanel form{_width:850px}#wrapper .bdbriimgtitle{color:#333;text-align:center;width:66px;height:43px;line-height:43px;padding-top:9px;margin:0 auto;border-bottom:#f0f0f0 1px solid;font-size:13px;cursor:default}#wrapper .briscrollwrapper{overflow:hidden}#wrapper .briscrollwrapperContainer{position:relative}#wrapper .bdbri.bdbriimg .bdmainlink a,#wrapper .bdbri.bdbriimg .bdothlink a{display:block;text-align:center;width:66px;height:76px;margin:0 auto;border-bottom:#f0f0f0 1px solid;color:#666;text-decoration:none;overflow:hidden}#wrapper .bdbri.bdbriimg .bdmainlink a:visited,#wrapper .bdbri.bdbriimg .bdothlink a:visited{color:#666}#wrapper .bdbri.bdbriimg .bdmainlink a:hover,#wrapper .bdbri.bdbriimg .bdothlink a:hover{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdmainlink a:active,#wrapper .bdbri.bdbriimg .bdothlink a:active{color:#00c;text-decoration:underline}#wrapper .bdbri.bdbriimg span{width:36px;height:36px;display:block;margin:10px auto 5px;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/logos/bdbri_icons_737be4e5.png) no-repeat;cursor:pointer} -#wrapper .bdbri.bdbriimg .bdbrimore,#wrapper .bdbri.bdbriimg .bdbrievenmore{clear:both;text-align:center}#wrapper .bdbri.bdbriimg .bdbrievenmore{margin-top:15px;height:30px;width:85px;overflow:hidden}#wrapper .bdbri.bdbriimg span.bdbriimgitem_1{background-position:0 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_2{background-position:-36px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_3{width:40px;background-position:-72px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_4{background-position:-112px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_5{background-position:-148px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_6{background-position:-184px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_7{background-position:-220px 0}#wrapper .bdbri.bdbriimg .bdbrievenmore a:link,#wrapper .bdbri.bdbriimg .bdbrievenmore a:visited{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdbrievenmore a:hover{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdbrievenmore a:active{color:#00c} -.bdbriscroll-ctrl-scroll{position:absolute;top:10px;right:1px;width:8px;border-top:1px solid #e4e4e4;border-left:1px solid #e4e4e4;cursor:default;-webkit-user-select:none;-moz-user-select:none}.bdbriscroll-ctrl-scroll .bdbriscroll-axis{width:8px;left:0;z-index:0;position:absolute;background:#f2f2f2}.bdbriscroll-ctrl-scroll-touch .bdbriscroll-axis{width:7px;background:#f2f2f2}.bdbriscroll-ctrl-scroll-hover .bdbriscroll-axis{background:#f2f2f2}.bdbriscroll-ctrl-scroll .bdbriscroll-slider{overflow:hidden;width:7px;height:14px;position:absolute;left:0;z-index:10;display:none;background:#d9d9d9;margin-top:-1px;margin-left:-1px;border-right:1px solid #cecece;border-bottom:1px solid #cecece;cursor:default}.bdbriscroll-ctrl-scroll-touch .bdbriscroll-slider,.bdbriscroll-ctrl-scroll-hover .bdbriscroll-slider{background:#b8b8b8;border-right:1px solid #afafaf;border-bottom:1px solid #afafaf}</style><!--[if lte IE 8]><style index="index" >#head{height:480px\9}.s_form{top:260px}</style><![endif]--><!--[if IE 8]><style index="index" >#u1 a.mnav,#u1 a.mnav:visited,#u1 a.lb,#u1 a.lb:visited,#u1 a.pf,#u1 a.pf:visited,#u1 a.bri,#u1 a.bri:visited{font-family:simsun}</style><![endif]--><style data-for="debug">#debug{display:none!important}</style><style data-for="result" id="css_index_result">#seth{display:none;behavior:url(#default#homepage)}#setf{display:none}#sekj{margin-left:14px}#st,#sekj{display:none}.s_ipt_wr{border:1px solid #b6b6b6;border-color:#7b7b7b #b6b6b6 #b6b6b6 #7b7b7b;background:#fff;display:inline-block;vertical-align:top;width:539px;margin-right:0;border-right-width:0;border-color:#b8b8b8 transparent #ccc #b8b8b8;overflow:hidden}.wrapper_s .s_ipt_wr{width:439px}.wrapper_s .s_ipt{width:434px}.wrapper_s .s_ipt_tip{width:434px}.s_ipt_wr:hover,.s_ipt_wr.ipthover{border-color:#999 transparent #b3b3b3 #999}.s_ipt_wr.iptfocus{border-color:#4791ff transparent #4791ff #4791ff}.s_ipt_tip{color:#aaa;position:absolute;z-index:-10;font:16px/22px arial;height:32px;line-height:32px;padding-left:7px;overflow:hidden;width:526px}.s_ipt{width:526px;height:22px;font:16px/18px arial;line-height:22px\9;margin:6px 0 0 7px;padding:0;background:transparent;border:0;outline:0;-webkit-appearance:none}#kw{position:relative}#u .username i{background-position:-408px -144px}.bdpfmenu,.usermenu{border:1px solid #d1d1d1;position:absolute;width:105px;top:36px;z-index:302;box-shadow:1px 1px 5px #d1d1d1;-webkit-box-shadow:1px 1px 5px #d1d1d1;-moz-box-shadow:1px 1px 5px #d1d1d1;-o-box-shadow:1px 1px 5px #d1d1d1} -.bdpfmenu{font-size:12px;background-color:#fff}.bdpfmenu a,.usermenu a{display:block;text-align:left;margin:0!important;padding:0 9px;line-height:26px;text-decoration:none}.briiconsbg{background-repeat:no-repeat;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png);background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9}#u{z-index:301;position:absolute;right:0;top:0;margin:21px 9px 5px 0;padding:0}.wrapper_s #u{margin-right:3px}#u a{text-decoration:underline;color:#333;margin:0 7px}.wrapper_s #u a{margin-right:0 6px}#u div a{text-decoration:none}#u a:hover{text-decoration:underline}#u .back_org{color:#666;float:left;display:inline-block;height:24px;line-height:24px}#u .bri{display:inline-block;width:24px;height:24px;float:left;line-height:24px;color:transparent;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png) no-repeat 4px 3px;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9;overflow:hidden} -#u .bri:hover,#u .bri.brihover{background-position:-18px 3px}#mCon #imeSIcon{background-position:-408px -144px;margin-left:0}#mCon span{color:#333}.bdpfmenu a:link,.bdpfmenu a:visited,#u .usermenu a:link,#u .usermenu a:visited{background:white;color:#333}.bdpfmenu a:hover,.bdpfmenu a:active,#u .usermenu a:hover,#u .usermenu a:active{background:#38f;text-decoration:none;color:white}.bdpfmenu{width:70px}.usermenu{width:68px;right:8px}#wrapper .bdnuarrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-10px;left:50%;margin-left:-5px}#wrapper .bdnuarrow em,#wrapper .bdnuarrow i{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:5px solid transparent;border-style:dashed dashed solid dashed}#wrapper .bdnuarrow em{border-bottom-color:#d8d8d8;top:-1px}#wrapper .bdnuarrow i{border-bottom-color:#fff;top:0}#prefpanel{background:#fafafa;display:none;opacity:0;position:fixed;_position:absolute;top:-359px;z-index:500;width:100%;min-width:960px;border-bottom:1px solid #ebebeb} -#prefpanel form{_width:850px}#kw_tip{cursor:default;display:none;margin-top:1px}#bds-message-wrapper{top:43px}.quickdelete-wrap{position:relative}.quickdelete-wrap input{width:500px}.wrapper_l .quickdelete-wrap input{width:500px}.wrapper_s .quickdelete-wrap input{width:402px}input::-ms-clear{display:none}.quickdelete{width:32px;height:32px;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/quickdelete_9c14b01a.png) no-repeat;background-position:10px 10px;position:absolute;display:block}.quickdelete:hover{background-position:10px -24px}</style><script >function h(obj){obj.style.behavior='url(#default#homepage)';var a = obj.setHomePage('//www.baidu.com/');}</script><noscript><meta http-equiv="refresh" content="0; url=/baidu.html?from=noscript"/></noscript><script>window._ASYNC_START=new Date().getTime();</script></head><body link="#0000cc"><script>if (/Chrome\/37.0.2062.94/i.test(navigator.userAgent) && (/(windows 7)|(windows nt 6.1)/i.test(navigator.userAgent))) {var _chrome_37_fix = document.createElement("style"); _chrome_37_fix.type="text/css";_chrome_37_fix.setAttribute("data-for","result");_chrome_37_fix.innerHTML = ".t,.f16,#kw,.s_ipt,.c-title,.c-title-size,.to_zhidao,.to_tieba,.to_zhidao_bottom{font-size:15px;} .ec-hospital-info-main h2,.ad-widget-gx_sck-ylzx-doctor-info h2,.ec-card-main h2,.ad-widget-h1 h2,.ad-widget-title h2,.ad-widget-small-head h2,.ad-widget-small-head h2 a,.ad-widget-header .ec-figcaption h2{font-size: 15px !important;}";document.getElementsByTagName("head")[0].appendChild(_chrome_37_fix); }</script><div id="wrapper" style="display:none;"><script>if(window.bds&&bds.util&&bds.util.setContainerWidth){bds.util.setContainerWidth();}</script><div id="head"><div class="head_wrapper"><div class="s_form"><div class="s_form_wrapper"><div id="lg"><img hidefocus="true" src="//www.baidu.com/img/bd_logo1.png" width="270" height="129"></div><a href="/" id="result_logo" onmousedown="return c({'fm':'tab','tab':'logo'})"><img src="//www.baidu.com/img/baidu_jgylogo3.gif" alt="到百度首页" title="到百度首页"></a><form id="form" name="f" action="/s" class="fm"><input type="hidden" name="ie" value="utf-8"><input type="hidden" name="f" value="8"><input type="hidden" name="rsv_bp" value="1"><input type="hidden" name="rsv_idx" value="1"><input type=hidden name=ch value=""><input type=hidden name=tn value="baidu"><input type=hidden name=bar value=""><span class="bg s_ipt_wr"><input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off"></span><span class="bg s_btn_wr"><input type="submit" id="su" value="百度一下" class="bg s_btn"></span><span class="tools"><span id="mHolder"><div id="mCon"><span>输入法</span></div><ul id="mMenu"><li><a href="javascript:;" name="ime_hw">手写</a></li><li><a href="javascript:;" name="ime_py">拼音</a></li><li class="ln"></li><li><a href="javascript:;" name="ime_cl">关闭</a></li></ul></span></span><input type="hidden" name="rn" value=""><input type="hidden" name="rsv_pq" value="f298a147000073cb"><input type="hidden" name="rsv_t" value="a94cvYVF4dZ09OuO3xH/upeB4CFuDZ5EWpRLTXv0Ho+UtD7dkIZfzQxzYq0"></form><div id="m"><p id="lm"><font>6.18特惠:<a href="http://click.union.jd.com/JdClick/?unionId=291540637&siteid=baidu_wzl235&to=http://sale.jd.com/act/cwMpj4ytUFA.html" title="京东商城" target="_blank">京东商城</a>&nbsp;&nbsp;<a href="http://www.nuomi.com/?cid=bdsywzl" title="百度糯米" target="_blank">百度糯米</a>&nbsp;&nbsp;<a href="http://click.union.vip.com/redirect.php?url=eyJjaGFuIjoiYmFpZHVjb213emwiLCJhZGNvZGUiOiIiLCJzY2hlbWVjb2RlIjoiZDVkNTMzMmUiLCJ1Y29kZSI6InhzcmVzYmNiIn0=" title="唯å“会" target="_blank">唯å“会</a></font></p></div></div></div><div id="u"><a class="toindex" href="/">百度首页</a><a href="javascript:;" name="tj_settingicon" class="pf">设置<i class="c-icon c-icon-triangle-down"></i></a><a href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F" name="tj_login" class="lb" onclick="return false;">登录</a></div><div id="u1"><a href="http://news.baidu.com" name="tj_trnews" class="mnav">æ–°é—»</a><a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a><a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a><a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a><a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">è´´å§</a><a href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F" name="tj_login" class="lb" onclick="return false;">登录</a><a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf" class="">设置</a><a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产å“</a></div></div></div><div class="s_tab" id="s_tab"><b>网页</b><a href="http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'news'})">æ–°é—»</a><a href="http://tieba.baidu.com/f?kw=&fr=wwwt" wdfield="kw" onmousedown="return c({'fm':'tab','tab':'tieba'})">è´´å§</a><a href="http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=&fr=wwwt" wdfield="word" onmousedown="return c({'fm':'tab','tab':'zhidao'})">知é“</a><a href="http://music.baidu.com/search?fr=ps&ie=utf-8&key=" wdfield="key" onmousedown="return c({'fm':'tab','tab':'music'})">音ä¹</a><a href="http://image.baidu.com/i?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'pic'})">图片</a><a href="http://v.baidu.com/v?ct=301989888&rn=20&pn=0&db=0&s=25&ie=utf-8&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'video'})">视频</a><a href="http://map.baidu.com/m?word=&fr=ps01000" wdfield="word" onmousedown="return c({'fm':'tab','tab':'map'})">地图</a><a href="http://wenku.baidu.com/search?word=&lm=0&od=0&ie=utf-8" wdfield="word" onmousedown="return c({'fm':'tab','tab':'wenku'})">文库</a><a href="//www.baidu.com/more/" onmousedown="return c({'fm':'tab','tab':'more'})">更多»</a></div><div id="ftCon"><div id="ftConw"><p id="lh"><a id="seth" onClick="h(this)" href="/" onmousedown="return ns_c({'fm':'behs','tab':'homepage','pos':0})">把百度设为主页</a><a id="setf" href="//www.baidu.com/cache/sethelp/help.html" onmousedown="return ns_c({'fm':'behs','tab':'favorites','pos':0})" target="_blank">把百度设为主页</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about'})" href="http://home.baidu.com">关于百度</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about_en'})" href="http://ir.baidu.com">About&nbsp;&nbsp;Baidu</a></p><p id="cp">&copy;2015&nbsp;Baidu&nbsp;<a href="http://www.baidu.com/duty/" onmousedown="return ns_c({'fm':'behs','tab':'tj_duty'})">使用百度å‰å¿…读</a>&nbsp;<a href="http://jianyi.baidu.com/" class="cp-feedback" onmousedown="return ns_c({'fm':'behs','tab':'tj_homefb'})">æ„è§å馈</a>&nbsp;京ICPè¯030173å·&nbsp;<i class="c-icon-icrlogo"></i></p></div></div><div id="wrapper_wrapper"></div></div><div class="c-tips-container" id="c-tips-container"></div><script>window.__async_strategy=2;</script><script>var bds={se:{},su:{urdata:[],urSendClick:function(){}},util:{},use:{},comm : {domain:"http://www.baidu.com",ubsurl : "http://sclick.baidu.com/w.gif",tn:"baidu",queryEnc:"",queryId:"",inter:"",templateName:"baidu",sugHost : "http://suggestion.baidu.com/su",query : "",qid : "f298a147000073cb",cid : "0",sid : "14767_1447_13349_13245_14509_14444_12826_14430_10212_12867_14622_14461_14871_12723_14537_14484_14919_14902_11602_13936",indexSid : "14767_1447_13349_13245_14509_14444_12826_14430_10212_12867_14622_14461_14871_12723_14537_14484_14919_14902_11602_13936",stoken : "",serverTime : "1434605501",user : "",username : "",userid : "0",isBaixiaoduOn : "",loginAction : [],useFavo : "",pinyin : "",favoOn : "",cookie : {"language":"cn","H_PS_PSSID":"13456_14593_1464_14861_14444_14429_12868_14622_13201_14871_12723_14535_14485_14919_14902_11712_13936","BD_HOME":"0","BDSVRTM":"0"},curResultNum:"0",rightResultExist:false,protectNum:0,zxlNum:0,pageNum:1,pageSize:10,newindex:0,async:2,maxPreloadThread:5,maxPreloadTimes:10,preloadMouseMoveDistance:5,switchAddMask:false,isDebug:false,ishome : 1,flagTranslateResult:0,globalLogFlag:0,encTn:'a94cvYVF4dZ09OuO3xH/upeB4CFuDZ5EWpRLTXv0Ho+UtD7dkIZfzQxzYq0'}};var name,navigate,al_arr=[];var selfOpen = window.open;eval("var open = selfOpen;");var isIE=navigator.userAgent.indexOf("MSIE")!=-1&&!window.opera;var E = bds.ecom= {};bds.se.mon = {'loadedItems':[],'load':function(){},'srvt':-1};try {bds.se.mon.srvt = parseInt(document.cookie.match(new RegExp("(^| )BDSVRTM=([^;]*)(;|$)"))[2]);document.cookie="BDSVRTM=;expires=Sat, 01 Jan 2000 00:00:00 GMT"; }catch(e){}var bdUser = bds.comm.user?bds.comm.user:null,bdQuery = bds.comm.query,bdUseFavo = bds.comm.useFavo,bdFavoOn = bds.comm.favoOn,bdCid = bds.comm.cid,bdSid = bds.comm.sid,bdServerTime = bds.comm.serverTime,bdQid = bds.comm.queryId,bdstoken = bds.comm.stoken,login_success = [];bds.util.domain = (function(){var list = {"vse.baidu.com":"http://vse.baidu.com","hdpreload.baidu.com":"http://hdpreload.baidu.com","lcr.open.baidu.com":"http://lcr.open.baidu.com","kankan.baidu.com":"http://kankan.baidu.com","xapp.baidu.com":"http://xapp.baidu.com","dr.dh.baidu.com":"http://dr.dh.baidu.com","xiaodu.baidu.com":"http://xiaodu.baidu.com","s1.bdstatic.com":"http://s1.bdstatic.com","olime.baidu.com":"http://olime.baidu.com","app.baidu.com":"http://app.baidu.com","i.baidu.com":"http://i.baidu.com","c.baidu.com":"http://c.baidu.com","sclick.baidu.com":"http://sclick.baidu.com","nsclick.baidu.com":"http://nsclick.baidu.com","eclick.baidu.com":"http://eclick.baidu.com","api.map.baidu.com":"http://api.map.baidu.com","ecma.bdimg.com":"http://ecma.bdimg.com","t10.baidu.com":"http://t10.baidu.com","t11.baidu.com":"http://t11.baidu.com","t12.baidu.com":"http://t12.baidu.com","i7.baidu.com":"http://i7.baidu.com","i8.baidu.com":"http://i8.baidu.com","i9.baidu.com":"http://i9.baidu.com","b1.bdstatic.com":"http://b1.bdstatic.com","ss.bdimg.com":"http://ss.bdimg.com","opendata.baidu.com":"http://opendata.baidu.com","api.open.baidu.com":"http://api.open.baidu.com","tag.baidu.com":"http://tag.baidu.com","f3.baidu.com":"http://f3.baidu.com","s.share.baidu.com":"http://s.share.baidu.com","bdimg.share.baidu.com":"http://bdimg.share.baidu.com"};var get = function(url) {if(location.protocol === "http") {return url;}var reg = /^(http[s]?:\/\/)?([^\/]+)(.*)/,matches = url.match(reg);url = list.hasOwnProperty(matches[2])&&(list[matches[2]] + matches[3]) || url;return url;},set = function(kdomain,vdomain) {list[kdomain] = vdomain;}; return {get : get,set : set}})();</script><script>if(!location.hash.match(/[^a-zA-Z0-9]wd=/)){document.getElementById("wrapper").style.display='block';setTimeout(function(){try{var kw=document.getElementById("kw");kw.focus();kw.parentNode.className="bg s_ipt_wr iptfocus quickdelete-wrap";}catch(e){}},0);}</script><script type="text/javascript" src="http://s1.bdstatic.com/r/www/cache/static/jquery/jquery-1.10.2.min_f2fb5194.js"></script><script>(function(){var result_common_css="<style data-for=\"result\" id=\"css_result\">body{color:#333;background:#fff;padding:6px 0 0;margin:0;position:relative;min-width:900px}body,th,td,.p1,.p2{font-family:arial}p,form,ol,ul,li,dl,dt,dd,h3{margin:0;padding:0;list-style:none}input{padding-top:0;padding-bottom:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}table,img{border:0}td{font-size:9pt;line-height:18px}em{font-style:normal;color:#c00}a em{text-decoration:underline}cite{font-style:normal;color:#008000}.m,a.m{color:#666}a.m:visited{color:#606}.g,a.g{color:#008000}.c{color:#77c}.f14{font-size:14px}.f10{font-size:10.5pt}.f16{font-size:16px}.f13{font-size:13px}.bg{background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_4e7241a3.png);background-repeat:no-repeat;_background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_d160197c.gif);background-repeat:no-repeat}.bg_tuiguang_browser{width:16px;height:16px;background-position:-600px 0;display:inline-block;vertical-align:text-bottom;font-style:normal;overflow:hidden;margin-right:5px}.bg_tuiguang_browser_big{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-600px -24px}.bg_tuiguang_weishi{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-672px -24px}#u,#head,#tool,#search,#foot{font-size:12px}.logo{width:117px;height:38px;cursor:pointer}.p1{line-height:120%;margin-left:-12pt}.p2{width:100%;line-height:120%;margin-left:-12pt}#wrapper{_zoom:1}#container{word-break:break-all;word-wrap:break-word}.container_s{width:1002px}.container_l{width:1222px}#content_left{width:636px;float:left;padding-left:35px}#content_right{border-left:1px solid #e1e1e1;float:right}.container_s #content_right{width:271px}.container_l #content_right{width:434px}.content_none{padding-left:35px}#u{color:#999;white-space:nowrap;position:absolute;right:10px;top:4px;z-index:299}#u a{color:#00c;margin:0 5px}#u .reg{margin:0}#u .last{margin-right:0}#u .un{font-weight:bold;margin-right:5px}#u ul{width:100%;background:#fff;border:1px solid #9b9b9b}#u li{height:25px}#u li a{width:100%;height:25px;line-height:25px;display:block;text-align:left;text-decoration:none;text-indent:6px;margin:0;filter:none\\9}#u li a:hover{background:#ebebeb}#u li.nl{border-top:1px solid #ebebeb}#user{display:inline-block}#user_center{position:relative;display:inline-block}#user_center .user_center_btn{margin-right:5px}.userMenu{width:64px;position:absolute;right:7px;_right:2px;top:15px;top:14px\\9;*top:15px;padding-top:4px;display:none;*background:#fff}#head{padding-left:35px;margin-bottom:20px;width:900px}.fm{clear:both;position:relative;z-index:297}.nv a,.nv b,.btn,#page,#more{font-size:14px}.s_nav{height:45px}.s_nav .s_logo{margin-right:20px;float:left}.s_nav .s_logo img{border:0;display:block}.s_tab{line-height:18px;padding:20px 0 0;float:left}.s_nav a{color:#00c;font-size:14px}.s_nav b{font-size:14px}.s_ipt_wr{width:536px;height:30px;display:inline-block;margin-right:5px;background-position:0 -96px;border:1px solid #b6b6b6;border-color:#7b7b7b #b6b6b6 #b6b6b6 #7b7b7b;vertical-align:top}.s_ipt{width:523px;height:22px;font:16px\/18px arial;line-height:22px\\9;margin:5px 0 0 7px;padding:0;background:#fff;border:0;outline:0;-webkit-appearance:none}.s_btn{width:95px;height:32px;padding-top:2px\\9;font-size:14px;padding:0;background-color:#ddd;background-position:0 -48px;border:0;cursor:pointer}.s_btn_h{background-position:-240px -48px}.s_btn_wr{width:97px;height:34px;display:inline-block;background-position:-120px -48px;*position:relative;z-index:0;vertical-align:top}.sethf{padding:0;margin:0;font-size:14px}.set_h{display:none;behavior:url(#default#homepage)}.set_f{display:none}.shouji{margin-left:19px}.shouji a{text-decoration:none}#head .bdsug{top:33px}#search form{position:relative}#search form .bdsug{bottom:33px}.bdsug{display:none;position:absolute;z-index:1;width:538px;background:#fff;border:1px solid #ccc;_overflow:hidden;box-shadow:1px 1px 3px #ededed;-webkit-box-shadow:1px 1px 3px #ededed;-moz-box-shadow:1px 1px 3px #ededed;-o-box-shadow:1px 1px 3px #ededed}.bdsug.bdsugbg ul{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/home\/img\/sugbg_6a9201c2.png) 100% 100% no-repeat;background-size:100px 110px;background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/home\/img\/sugbg_d24a0811.gif)\\9}.bdsug li{width:522px;color:#000;font:14px arial;line-height:22px;padding:0 8px;position:relative;cursor:default}.bdsug li.bdsug-s{background:#f0f0f0}.bdsug-store span,.bdsug-store b{color:#7a77c8}.bdsug-store-del{font-size:12px;color:#666;text-decoration:underline;position:absolute;right:8px;top:0;cursor:pointer;display:none}.bdsug-s .bdsug-store-del{display:inline-block}.bdsug-ala{display:inline-block;border-bottom:1px solid #e6e6e6}.bdsug-ala h3{line-height:14px;background:url(\/\/www.baidu.com\/img\/sug_bd.png) no-repeat left center;margin:8px 0 5px 0;font-size:12px;font-weight:normal;color:#7b7b7b;padding-left:20px}.bdsug-ala p{font-size:14px;font-weight:bold;padding-left:20px}.bdsug .bdsug-direct{width:auto;padding:0;border-bottom:1px solid #f1f1f1}.bdsug .bdsug-direct p{color:#00c;font-weight:bold;line-height:34px;padding:0 8px;cursor:pointer;white-space:nowrap;overflow:hidden}.bdsug .bdsug-direct p img{width:16px;height:16px;margin:7px 6px 9px 0;vertical-align:middle}.bdsug .bdsug-direct p span{margin-left:8px}.bdsug .bdsug-direct p i{font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;background-color:#2b99ff;display:inline;text-align:center;padding:1px 5px;*padding:2px 5px 0 5px;margin-left:8px;overflow:hidden}.bdsug .bdsug-pcDirect{color:#000;font-size:14px;line-height:30px;height:30px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip{position:absolute;right:15px;top:8px;width:55px;height:15px;display:block;background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-is{color:#000;font-size:14px;line-height:22px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip-is{position:absolute;right:15px;top:3px;width:55px;height:15px;display:block;background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-is-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-s .bdsug-pc-direct-tip,.bdsug .bdsug-pcDirect-is-s .bdsug-pc-direct-tip-is{background-position:0 -15px}#tb_mr{color:#00c;cursor:pointer;position:relative;z-index:298}#tb_mr b{font-weight:normal;text-decoration:underline}#tb_mr small{font-size:11px}#page{font:14px arial;white-space:nowrap;padding-left:35px}#page a,#page strong{display:inline-block;vertical-align:text-bottom;height:66px;text-align:center;line-height:34px;text-decoration:none;overflow:hidden;margin-right:9px;background:white}#page a{cursor:pointer}#page a:hover{background:0}#page .n:hover,#page a:hover .pc{background:#f2f8ff;border:1px solid #38f}#page .n{height:34px;padding:0 18px;border:1px solid #e1e2e3}#page span{display:block}#page .pc{width:34px;height:34px;border:1px solid #e1e2e3;cursor:pointer}#page .fk{width:24px;height:24px;margin-bottom:6px;margin-left:6px;cursor:pointer}#page strong .fk,#page strong .pc{cursor:auto}#page .fk .c-icon-bear-pn{top:-3px;position:relative}#page .fkd .c-icon-bear-pn{top:3px;position:relative}#page .fk_cur .c-icon-bear-p{top:-2px;position:relative}#page strong .pc{border:0;width:36px;height:36px;line-height:36px}#page .nums{display:inline-block;vertical-align:text-bottom;height:36px;line-height:36px;margin-left:10px}#rs{width:900px;background:#fff;padding:8px 0;margin:20px 0 0 15px}#rs td{width:5%}#rs th{font-size:14px;font-weight:normal;line-height:19px;white-space:nowrap;text-align:left;vertical-align:top}#rs .tt{font-weight:bold;padding:0 10px 0 20px}#rs_top{font-size:14px;margin-bottom:22px}#rs_top a{margin-right:18px}#container .rs{margin:30px 0 20px 0;padding:5px 0 15px 0;font-size:14px;width:540px;padding-left:121px;position:relative;background-color:#fafafa}#container .noback{background-color:#fff}#content_left .rs{margin-left:-121px}#container .rs table{width:540px}#container .rs td{width:5px}#container .rs th{font-size:14px;font-weight:normal;white-space:nowrap;text-align:left;vertical-align:top;width:175px;line-height:22px}#container .rs .tt{font-weight:bold;padding:0 10px 0 20px;padding:0;line-height:30px;font-size:16px}#container .rs a{margin:0;height:24px;width:173px;display:inline-block;line-height:25px;border:1px solid #ebebeb;text-align:center;vertical-align:middle;overflow:hidden;outline:0;color:#333;background-color:#fff;text-decoration:none}#container .rs a:hover{border-color:#388bff}.c-tip-con .c-tip-menu-b ul{width:100px}.c-tip-con .c-tip-menu-b ul{text-align:center}.c-tip-con .c-tip-menu-b li a{display:block;text-decoration:none;cursor:pointer;background-color:#fff;padding:3px 0;color:#666}.c-tip-con .c-tip-menu-b li a:hover{display:block;background-color:#ebebeb}#search{width:900px;padding:35px 0 16px 35px}#search .s_help{position:relative;top:10px}#foot{height:20px;line-height:20px;color:#77c;background:#e6e6e6;text-align:center}#foot span{color:#666}.site_tip{font-size:12px;margin-bottom:20px}.site_tip_icon{width:56px;height:56px;background:url(\/\/www.baidu.com\/aladdin\/img\/tools\/tools-3.png) -288px 0 no-repeat}.to_zhidao,.to_tieba,.to_zhidao_bottom{font-size:16px;line-height:24px;margin:20px 0 0 35px}.to_tieba .c-icon-tieba{float:left}.f{line-height:115%;*line-height:120%;font-size:100%;width:33.7em;word-break:break-all;word-wrap:break-word}.h{margin-left:8px;width:100%}.r{word-break:break-all;cursor:hand;width:238px}.t{font-weight:normal;font-size:medium;margin-bottom:1px}.pl{padding-left:3px;height:8px;padding-right:2px;font-size:14px}.mo,a.mo:link,a.mo:visited{color:#666;font-size:100%;line-height:10px}.htb{margin-bottom:5px}.jc a{color:#c00}a font[size=\"3\"] font,font[size=\"3\"] a font{text-decoration:underline}div.blog,div.bbs{color:#707070;padding-top:2px;font-size:13px}.result{width:33.7em;table-layout:fixed}.result-op .f{word-wrap:normal}.nums{font-size:12px;color:#999}.tools{position:absolute;top:10px;white-space:nowrap}#mHolder{width:62px;position:relative;z-index:296;top:-18px;margin-left:9px;margin-right:-12px;display:none}#mCon{height:18px;position:absolute;top:3px;top:6px\\9;cursor:pointer;line-height:18px}.wrapper_l #mCon{right:7px}#mCon span{color:#00c;cursor:default;display:block}#mCon .hw{text-decoration:underline;cursor:pointer;display:inline-block}#mCon .pinyin{display:inline-block}#mCon .c-icon-chevron-unfold2{margin-left:5px}#mMenu{width:56px;border:1px solid #9b9b9b;position:absolute;right:7px;top:23px;display:none;background:#fff}#mMenu a{width:100%;height:100%;color:#00c;display:block;line-height:22px;text-indent:6px;text-decoration:none;filter:none\\9}#mMenu a:hover{background:#ebebeb}#mMenu .ln{height:1px;background:#ebebeb;overflow:hidden;font-size:1px;line-height:1px;margin-top:-1px}.op_LAMP{background:url(\"\/cache\/global\/img\/aladdinIcon-1.0.gif\") no-repeat 0 2px;color:#77C;display:inline-block;font-size:13px;height:12px;*height:14px;width:16px;text-decoration:none;zoom:1}.EC_mr15{margin-left:0}.pd15{padding-left:0}.map_1{width:30em;font-size:80%;line-height:145%}.map_2{width:25em;font-size:80%;line-height:145%}.favurl{background-repeat:no-repeat;background-position:0 1px;padding-left:20px}.dan_tip{font-size:12px;margin-top:4px}.dan_tip a{color:#b95b07}#more,#u ul,#mMenu,.msg_holder{box-shadow:1px 1px 2px #ccc;-moz-box-shadow:1px 1px 2px #ccc;-webkit-box-shadow:1px 1px 2px #ccc;filter:progid:DXImageTransform.Microsoft.Shadow(Strength=2,Direction=135,Color=\"#cccccc\")\\9}.hit_top{line-height:18px;margin:0 15px 10px 0;width:516px}.hit_top .c-icon-bear{height:18px;margin-right:4px}#rs_top_new,.hit_top_new{width:538px;font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all;margin:0 0 14px 0}.zhannei-si{margin:0 0 10px 121px}.zhannei-si-none{margin:10px 0 -10px 121px}.zhannei-search{margin:10px 0 0 121px;color:#999;font-size:14px}.f a font[size=\"3\"] font,.f font[size=\"-1\"] a font{text-decoration:underline}h3 a font{text-decoration:underline}.c-title{font-weight:normal;font-size:16px}.c-title-size{font-size:16px}.c-abstract{font-size:13px}.c-abstract-size{font-size:13px}.c-showurl{color:#008000;font-size:13px}.c-showurl-color{color:#008000}.c-cache-color{color:#666}.c-lightblue{color:#77C}.c-highlight-color{color:#C00}.c-clearfix:after{content:\".\";display:block;height:0;clear:both;visibility:hidden}.c-clearfix{zoom:1}.c-wrap{word-break:break-all;word-wrap:break-word}.c-icons-outer{overflow:hidden;display:inline-block;vertical-align:bottom;*vertical-align:-1px;_vertical-align:bottom}.c-icons-inner{margin-left:-4px}.c-container table.result,.c-container table.result-op{width:100%}.c-container td.f{font-size:13px;line-height:1.54;width:auto}.c-container .vd_newest_main{width:auto}.c-customicon{display:inline-block;width:16px;height:16px;vertical-align:text-bottom;font-style:normal;overflow:hidden}.c-tip-icon i{display:inline-block;cursor:pointer}.c-tip-con{position:absolute;z-index:1;top:22px;left:-35px;background:#fff;border:1px solid #dcdcdc;border:1px solid rgba(0,0,0,0.2);-webkit-transition:opacity .218s;transition:opacity .218s;-webkit-box-shadow:0 2px 4px rgba(0,0,0,0.2);box-shadow:0 2px 4px rgba(0,0,0,0.2);padding:5px 0 5px 0;display:none;font-size:12px;line-height:20px}.c-tip-arrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-16px}.c-tip-arrow-down{top:auto;bottom:0}.c-tip-arrow em,.c-tip-arrow ins{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:8px solid transparent;border-style:dashed dashed solid dashed}.c-tip-arrow em{border-bottom-color:#d8d8d8}.c-tip-arrow ins{border-bottom-color:#fff;top:2px}.c-tip-arrow-down em,.c-tip-arrow-down ins{border-style:solid dashed dashed dashed;border-color:transparent}.c-tip-arrow-down em{border-top-color:#d8d8d8}.c-tip-arrow-down ins{border-top-color:#fff;top:-2px}.c-tip-con h3{font-size:12px}.c-tip-con .c-tip-title{margin:0 10px;display:inline-block;width:239px}.c-tip-con .c-tip-info{color:#666;margin:0 10px 1px 10px;width:239px}.c-tip-con .c-tip-cer{width:354px;color:#666;margin:0 10px 1px 10px}.c-tip-con .c-tip-title{width:auto;_width:354px}.c-tip-con .c-tip-item-i{padding:3px 0 3px 20px;line-height:14px}.c-tip-con .c-tip-item-i .c-tip-item-icon{margin-left:-20px}.c-tip-con .c-tip-menu ul{width:74px}.c-tip-con .c-tip-menu ul{text-align:center}.c-tip-con .c-tip-menu li a{display:block;text-decoration:none;cursor:pointer;background-color:#fff;padding:3px 0;color:#0000d0}.c-tip-con .c-tip-menu li a:hover{display:block;background-color:#ebebeb}.c-tip-con .c-tip-notice{width:239px;padding:0 10px}.c-tip-con .c-tip-notice .c-tip-notice-succ{color:#4cbd37}.c-tip-con .c-tip-notice .c-tip-notice-fail{color:#f13f40}.c-tip-con .c-tip-notice .c-tip-item-succ{color:#444}.c-tip-con .c-tip-notice .c-tip-item-fail{color:#aaa}.c-tip-con .c-tip-notice .c-tip-item-fail a{color:#aaa}.c-tip-close{right:10px;position:absolute;cursor:pointer}.ecard{height:86px;overflow:hidden}.c-tools{display:inline}.c-tools-share{width:239px;padding:0 10px}.c-fanyi{display:none;width:20px;height:20px;border:solid 1px #d1d1d1;cursor:pointer;position:absolute;margin-left:516px;text-align:center;color:#333;line-height:22px;opacity:.9;background-color:#fff}.c-fanyi:hover{background-color:#39f;color:#fff;border-color:#39f;opacity:1}.c-fanyi-title,.c-fanyi-abstract{display:none}.icp_info{color:#666;margin-top:2px;font-size:13px}.icon-gw,.icon-unsafe-icon{background:#2c99ff;vertical-align:text-bottom;*vertical-align:baseline;height:16px;padding-top:0;padding-bottom:0;padding-left:6px;padding-right:6px;line-height:16px;_padding-top:2px;_height:14px;_line-height:14px;font-size:12px;font-family:simsun;margin-left:10px;overflow:hidden;display:inline-block;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px;color:#fff}a.icon-gw{color:#fff;background:#2196ff;text-decoration:none;cursor:pointer}a.icon-gw:hover{background:#1e87ef}a.icon-gw:active{height:15px;_height:13px;line-height:15px;_line-height:13px;padding-left:5px;background:#1c80d9;border-left:1px solid #145997;border-top:1px solid #145997}.icon-unsafe-icon{background:#e54d4b}#con-at{margin-bottom:11px;padding-left:121px;border-bottom:1px #ebebeb solid}#con-at .result-op{font-size:13px;line-height:1.52em}.wrapper_l #con-at .result-op{width:1058px}.wrapper_s #con-at .result-op{width:869px}#con-ar{margin-bottom:40px}#con-ar .result-op{margin-bottom:28px;font-size:13px;line-height:1.52em}.result_hidden{position:absolute;top:-10000px;left:-10000px}#content_left .result-op,#content_left .result{margin-bottom:14px;border-collapse:collapse}#content_left .c-border .result-op,#content_left .c-border .result{margin-bottom:25px}#content_left .c-border .result-op:last-child,#content_left .c-border .result:last-child{margin-bottom:12px}#content_left .result .f,#content_left .result-op .f{padding:0}.subLink_factory{border-collapse:collapse}.subLink_factory td{padding:0}.subLink_factory td.middle,.subLink_factory td.last{color:#666}.subLink_factory td a{text-decoration:underline}.subLink_factory td.rightTd{text-align:right}.subLink_factory_right{width:100%}.subLink_factory_left td{padding-right:26px}.subLink_factory_left td.last{padding:0}.subLink_factory_left td.first{padding-right:75px}.subLink_factory_right td{width:90px}.subLink_factory_right td.first{width:auto}.general_image_pic a{background:#fff no-repeat center center;text-decoration:none;display:block;overflow:hidden;text-align:left}.res_top_banner{height:36px;text-align:left;border-bottom:1px solid #e3e3e3;background:#f7f7f7;font-size:13px;padding-left:8px;color:#333;position:relative;z-index:302}.res_top_banner span{_zoom:1}.res_top_banner .res_top_banner_icon{background-position:0 -216px;width:18px;height:18px;margin:9px 10px 0 0}.res_top_banner .res_top_banner_icon_baiduapp{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/baiduappLogo_7db5fd3c.png) no-repeat 0 0;width:24px;height:24px;margin:3px 10px 0 0;position:relative;top:3px}.res_top_banner .res_top_banner_download{display:inline-block;width:65px;line-height:21px;_padding-top:1px;margin:0 0 0 10px;color:#333;background:#fbfbfb;border:1px solid #b4b6b8;text-align:center;text-decoration:none}.res_top_banner .res_top_banner_download:hover{border:1px solid #38f}.res_top_banner .res_top_banner_download:active{background:#f0f0f0;border:1px solid #b4b6b8}.res_top_banner .res_top_banner_close{background-position:-672px -144px;cursor:pointer;position:absolute;right:10px;top:10px}.res-gap-right16{margin-right:16px}.res-border-top{border-top:1px solid #f3f3f3}.res-border-bottom{border-bottom:1px solid #f3f3f3}.res-queryext-pos{position:relative;top:1px;_top:0}.c-trust-ecard{height:86px;_height:97px;overflow:hidden}@-moz-document url-prefix(){.result,.f{width:538px}}body{min-width:1000px}#ftCon{display:none}#pad-version{display:none}#index_guide{display:none}#index_logo{display:none}#u1{display:none}.s_ipt_wr{height:32px}body{padding:0}.s_form:after,.s_tab:after{content:\".\";display:block;height:0;clear:both;visibility:hidden}.s_form{zoom:1;height:55px;padding:0 0 0 10px}#result_logo{float:left;margin:7px 0 0}#result_logo img{width:101px}#head{padding:0;margin:0;width:100%;position:absolute;z-index:301;min-width:1000px;background:#fff;border-bottom:1px solid #ebebeb;position:fixed;_position:absolute;-webkit-transform:translateZ(0)}#head .head_wrapper{_width:1000px}#head.s_down{box-shadow:0 0 5px #888}.fm{clear:none;float:left;margin:11px 0 0 10px}#s_tab{background:#f8f8f8;line-height:36px;height:38px;padding:55px 0 0 121px;float:none;zoom:1}#s_tab a,#s_tab b{width:54px;display:inline-block;text-decoration:none;text-align:center;color:#666;font-size:14px}#s_tab b{border-bottom:2px solid #38f;font-weight:bold;color:#323232}#s_tab a:hover{color:#323232}#content_left{width:540px;padding-left:121px;padding-top:5px}#content_right{margin-top:45px}#page{padding:0 0 0 121px;margin:30px 0 40px 0}.to_tieba,.to_zhidao_bottom{margin:10px 0 0 121px}.nums{margin:0 0 0 121px;height:42px;line-height:42px}#rs{padding:0;margin:6px 0 0 121px;width:600px}#rs th{width:175px;line-height:22px}#rs .tt{padding:0;line-height:30px}#rs td{width:5px}#rs table{width:540px}#help{background:#f5f6f5;zoom:1;padding:0 0 0 50px;float:right}#help a{color:#777;padding:0 15px;text-decoration:none}#help a:hover{color:#333}#foot{background:#f5f6f5;border-top:1px solid #ebebeb;text-align:left;height:42px;line-height:42px;margin-top:40px;*margin-top:0}#foot .foot_c{float:left;padding:0 0 0 121px}.content_none{padding:45px 0 25px 121px}.nors p{font-size:18px;font-family:microsoft yahei;color:#000}.nors p em{color:#c00}.nors .tip_head{color:#666;font-size:13px;line-height:28px}.nors li{color:#333;line-height:28px;font-size:13px;font-family:'\u5b8b\u4f53';padding-left:30px;list-style-position:inside;list-style-type:disc}#mCon{top:5px}.s_ipt_wr.bg,.s_btn_wr.bg,#su.bg{background-image:none}.s_ipt_wr.bg{background:0}.s_btn_wr{width:auto;height:auto;border-bottom:1px solid transparent;*border-bottom:0}.s_btn{width:100px;height:34px;color:white;letter-spacing:1px;background:#3385ff;border-bottom:1px solid #2d78f4;outline:medium;*border-bottom:0;-webkit-appearance:none;-webkit-border-radius:0}.s_btn.btnhover{background:#317ef3;border-bottom:1px solid #2868c8;*border-bottom:0;box-shadow:1px 1px 1px #ccc}.s_btn_h{background:#3075dc;box-shadow:inset 1px 1px 3px #2964bb;-webkit-box-shadow:inset 1px 1px 3px #2964bb;-moz-box-shadow:inset 1px 1px 3px #2964bb;-o-box-shadow:inset 1px 1px 3px #2964bb}#wrapper_wrapper .container_l .EC_ppim_top,#wrapper_wrapper .container_xl .EC_ppim_top{width:640px}#wrapper_wrapper .container_s .EC_ppim_top{width:570px}#head .c-icon-bear-round{display:none}.container_l #content_right{width:384px}.container_l{width:1212px}.container_xl #content_right{width:384px}.container_xl{width:1257px}.index_tab_top{display:none}.index_tab_bottom{display:none}#lg{display:none}#m{display:none}#ftCon{display:none}#ent_sug{position:absolute;margin:141px 0 0 130px;font-size:13px;color:#666}.foot_fixed_bottom{position:fixed;bottom:0;width:100%;_position:absolute;_bottom:auto}#head .headBlock{margin:-5px 0 6px 121px}#content_left .leftBlock{margin-bottom:14px;padding-bottom:5px;border-bottom:1px solid #f3f3f3}.hint_toprq_tips{position:relative;width:537px;height:19px;line-height:19px;overflow:hidden;display:none}.hint_toprq_tips span{color:#666}.hint_toprq_icon{margin:0 4px 0 0}.hint_toprq_tips_items{width:444px;_width:440px;max-height:38px;position:absolute;left:95px;top:1px}.hint_toprq_tips_items div{display:inline-block;float:left;height:19px;margin-right:18px;white-space:nowrap;word-break:keep-all}.nums{width:538px}.search_tool{_padding-top:15px}.head_nums_cont_outer{height:40px;overflow:hidden;position:relative}.head_nums_cont_inner{position:relative}.search_tool_conter .c-gap-left{margin-left:23px}.search_tool_conter .c-icon-triangle-down{opacity:.6}.search_tool_conter .c-icon-triangle-down:hover{opacity:1}.search_tool,.search_tool_close{float:right}.search_tool,.search_tool_conter span{cursor:pointer;color:#666}.search_tool:hover,.search_tool_conter span:hover{color:#333}.search_tool_conter{font-size:12px;color:#666;margin:0 0 0 121px;height:42px;width:538px;line-height:42px;*height:auto;*line-height:normal;*padding:14px 0}.search_tool_conter span strong{color:#666}.c-tip-con .c-tip-langfilter ul{width:80px;text-align:left;color:#666}.c-tip-con .c-tip-langfilter li a{text-indent:15px;color:#666}.c-tip-con .c-tip-langfilter li span{text-indent:15px;padding:3px 0;color:#999;display:block}.c-tip-con .c-tip-timerfilter ul{width:115px;text-align:left;color:#666}.c-tip-con .c-tip-timerfilter-ft ul{width:180px}.c-tip-con .c-tip-timerfilter-si ul{width:206px;padding:7px 10px 10px}.c-tip-con .c-tip-timerfilter li a{text-indent:15px;color:#666}.c-tip-con .c-tip-timerfilter li span{text-indent:15px;padding:3px 0;color:#999;display:block}.c-tip-con .c-tip-timerfilter-ft li a,.c-tip-con .c-tip-timerfilter-ft li span{text-indent:20px}.c-tip-custom{padding:0 15px 10px 15px;position:relative;zoom:1}.c-tip-custom hr{border:0;height:0;border-top:1px solid #ebebeb}.c-tip-custom p{color:#b6b6b6;height:25px;line-height:25px;margin:2px 0}.c-tip-custom .c-tip-custom-et{margin-bottom:7px}.c-tip-custom-input,.c-tip-si-input{display:inline-block;font-size:11px;color:#333;margin-left:4px;padding:0 2px;width:74%;height:16px;line-height:16px\\9;border:1px solid #ebebeb;outline:0;box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;overflow:hidden;position:relative}.c-tip-custom-input-init{color:#d4d4d4}.c-tip-custom-input-focus,.c-tip-si-input-focus{border:1px solid #3385ff}.c-tip-timerfilter-si .c-tip-si-input{width:138px;height:22px;line-height:22px;vertical-align:0;*vertical-align:-6px;_vertical-align:-5px;padding:0 5px;margin-left:0}.c-tip-con .c-tip-timerfilter li .c-tip-custom-submit,.c-tip-con .c-tip-timerfilter li .c-tip-timerfilter-si-submit{display:inline;padding:4px 10px;margin:0;color:#333;border:1px solid #d8d8d8;font-family:inherit;font-weight:normal;text-align:center;vertical-align:0;background-color:#f9f9f9;outline:0}.c-tip-con .c-tip-timerfilter li .c-tip-custom-submit:hover,.c-tip-con .c-tip-timerfilter li .c-tip-timerfilter-si-submit:hover{display:inline;border-color:#388bff}.c-tip-timerfilter-si-error,.c-tip-timerfilter-custom-error{display:none;color:#3385ff;padding-left:4px}.c-tip-timerfilter-custom-error{padding:0;margin:-5px -13px 7px 0}#c-tip-custom-calenderCont{position:absolute;background:#fff;white-space:nowrap;padding:5px 10px;color:#000;border:1px solid #e4e4e4;-webkit-box-shadow:0 2px 4px rgba(0,0,0,0.2);box-shadow:0 2px 4px rgba(0,0,0,0.2)}#c-tip-custom-calenderCont p{text-align:center;padding:2px 0 4px;*padding:4px 0}#c-tip-custom-calenderCont p i{color:#8e9977;cursor:pointer;text-decoration:underline;font-size:13px}#c-tip-custom-calenderCont .op_cal{background:#fff}.op_cal table{background:#eeefea;margin:0;border-collapse:separate}.op_btn_pre_month,.op_btn_next_month{cursor:pointer;display:block;margin-top:6px}.op_btn_pre_month{float:left;background-position:0 -46px}.op_btn_next_month{float:right;background-position:-18px -46px}.op_cal .op_mon_pre1{padding:0}.op_mon th{text-align:center;font-size:12px;background:#FFF;font-weight:bold;border:1px solid #FFF;padding:0}.op_mon td{text-align:center;cursor:pointer}.op_mon h5{margin:0;padding:0 4px;text-align:center;font-size:14px;background:#FFF;height:28px;line-height:28px;border-bottom:1px solid #f5f5f5;margin-bottom:5px}.op_mon strong{font-weight:bold}.op_mon td{padding:0 5px;border:1px solid #fff;font-size:12px;background:#fff;height:100%}.op_mon td.op_mon_pre_month{color:#a4a4a4}.op_mon td.op_mon_cur_month{color:#00c}.op_mon td.op_mon_next_month{color:#a4a4a4}.op_mon td.op_mon_day_hover{color:#000;border:1px solid #278df2}.op_mon td.op_mon_day_selected{color:#FFF;border:1px solid #278df2;background:#278df2}.op_mon td.op_mon_day_disabled{cursor:not-allowed;color:#ddd}.zhannei-si-none,.zhannei-si,.hit_quet,.zhannei-search{display:none}#c-tip-custom-calenderCont .op_mon td.op_mon_cur_month{color:#000}#c-tip-custom-calenderCont .op_mon td.op_mon_day_selected{color:#fff}.c-frame{margin-bottom:18px}.c-offset{padding-left:10px}.c-gray{color:#666}.c-gap-top-small{margin-top:5px}.c-gap-top{margin-top:10px}.c-gap-bottom-small{margin-bottom:5px}.c-gap-bottom{margin-bottom:10px}.c-gap-left{margin-left:12px}.c-gap-left-small{margin-left:6px}.c-gap-right{margin-right:12px}.c-gap-right-small{margin-right:6px}.c-gap-right-large{margin-right:16px}.c-gap-left-large{margin-left:16px}.c-gap-icon-right-small{margin-right:5px}.c-gap-icon-right{margin-right:10px}.c-gap-icon-left-small{margin-left:5px}.c-gap-icon-left{margin-left:10px}.c-container{width:538px;font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all}.c-container .c-container{width:auto}.c-container table{border-collapse:collapse;border-spacing:0}.c-container td{font-size:13px;line-height:1.54}.c-default{font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all}.c-container .t,.c-default .t{line-height:1.54}.c-default .t{margin-bottom:0}.cr-content{width:259px;font-size:13px;line-height:1.54;color:#333;word-wrap:break-word;word-break:normal}.cr-content table{border-collapse:collapse;border-spacing:0}.cr-content td{font-size:13px;line-height:1.54;vertical-align:top}.cr-offset{padding-left:17px}.cr-title{font-size:14px;line-height:1.29;font-weight:bold}.cr-title-sub{float:right;font-size:13px;font-weight:normal}.c-row{*zoom:1}.c-row:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-span2{width:29px}.c-span3{width:52px}.c-span4{width:75px}.c-span5{width:98px}.c-span6{width:121px}.c-span7{width:144px}.c-span8{width:167px}.c-span9{width:190px}.c-span10{width:213px}.c-span11{width:236px}.c-span12{width:259px}.c-span13{width:282px}.c-span14{width:305px}.c-span15{width:328px}.c-span16{width:351px}.c-span17{width:374px}.c-span18{width:397px}.c-span19{width:420px}.c-span20{width:443px}.c-span21{width:466px}.c-span22{width:489px}.c-span23{width:512px}.c-span24{width:535px}.c-span2,.c-span3,.c-span4,.c-span5,.c-span6,.c-span7,.c-span8,.c-span9,.c-span10,.c-span11,.c-span12,.c-span13,.c-span14,.c-span15,.c-span16,.c-span17,.c-span18,.c-span19,.c-span20,.c-span21,.c-span22,.c-span23,.c-span24{float:left;_display:inline;margin-right:17px;list-style:none}.c-span-last{margin-right:0}.c-span-last-s{margin-right:0}.container_l .cr-content{width:351px}.container_l .cr-content .c-span-last-s{margin-right:17px}.container_l .cr-content-narrow{width:259px}.container_l .cr-content-narrow .c-span-last-s{margin-right:0}.c-border{width:518px;padding:9px;border:1px solid #e3e3e3;border-bottom-color:#e0e0e0;border-right-color:#ececec;box-shadow:1px 2px 1px rgba(0,0,0,0.072);-webkit-box-shadow:1px 2px 1px rgba(0,0,0,0.072);-moz-box-shadow:1px 2px 1px rgba(0,0,0,0.072);-o-box-shadow:1px 2px 1px rgba(0,0,0,0.072)}.c-border .c-gap-left{margin-left:10px}.c-border .c-gap-left-small{margin-left:5px}.c-border .c-gap-right{margin-right:10px}.c-border .c-gap-right-small{margin-right:5px}.c-border .c-border{width:auto;padding:0;border:0;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;-o-box-shadow:none}.c-border .c-span2{width:34px}.c-border .c-span3{width:56px}.c-border .c-span4{width:78px}.c-border .c-span5{width:100px}.c-border .c-span6{width:122px}.c-border .c-span7{width:144px}.c-border .c-span8{width:166px}.c-border .c-span9{width:188px}.c-border .c-span10{width:210px}.c-border .c-span11{width:232px}.c-border .c-span12{width:254px}.c-border .c-span13{width:276px}.c-border .c-span14{width:298px}.c-border .c-span15{width:320px}.c-border .c-span16{width:342px}.c-border .c-span17{width:364px}.c-border .c-span18{width:386px}.c-border .c-span19{width:408px}.c-border .c-span20{width:430px}.c-border .c-span21{width:452px}.c-border .c-span22{width:474px}.c-border .c-span23{width:496px}.c-border .c-span24{width:518px}.c-border .c-span2,.c-border .c-span3,.c-border .c-span4,.c-border .c-span5,.c-border .c-span6,.c-border .c-span7,.c-border .c-span8,.c-border .c-span9,.c-border .c-span10,.c-border .c-span11,.c-border .c-span12,.c-border .c-span13,.c-border .c-span14,.c-border .c-span15,.c-border .c-span16,.c-border .c-span17,.c-border .c-span18,.c-border .c-span19,.c-border .c-span20,.c-border .c-span21,.c-border .c-span22,.c-border .c-span23,.c-border .c-span24{margin-right:10px}.c-border .c-span-last{margin-right:0}.c-loading{display:block;width:50px;height:50px;background:url(\"\/\/www.baidu.com\/aladdin\/img\/tools\/loading.gif\") no-repeat 0 0}.c-vline{display:inline-block;margin:0 3px;border-left:1px solid #ddd;width:0;height:12px;_vertical-align:middle;_overflow:hidden}.c-icon{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_4e7241a3.png) no-repeat 0 0;_background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_d160197c.gif)}.c-icon{display:inline-block;width:14px;height:14px;vertical-align:text-bottom;font-style:normal;overflow:hidden}.c-icon-unfold,.c-icon-fold,.c-icon-chevron-unfold,.c-icon-chevron-fold{width:12px;height:12px}.c-icon-star,.c-icon-star-gray{width:60px}.c-icon-qa-empty,.c-icon-safeguard,.c-icon-register-empty,.c-icon-zan,.c-icon-music,.c-icon-music-gray,.c-icon-location,.c-icon-warning,.c-icon-doc,.c-icon-xls,.c-icon-ppt,.c-icon-pdf,.c-icon-txt,.c-icon-play-black,.c-icon-gift,.c-icon-baidu-share,.c-icon-bear,.c-icon-bear-border,.c-icon-location-blue,.c-icon-hotAirBall,.c-icon-moon,.c-icon-streetMap,.c-icon-mv,.c-icon-zhidao-s,.c-icon-shopping{width:16px;height:16px}.c-icon-bear-circle,.c-icon-warning-circle,.c-icon-warning-triangle,.c-icon-warning-circle-gray{width:18px;height:18px}.c-icon-tieba,.c-icon-zhidao,.c-icon-bear-p,.c-icon-bear-pn{width:24px;height:24px}.c-icon-ball-blue,.c-icon-ball-red{width:38px;height:38px}.c-icon-unfold:hover,.c-icon-fold:hover,.c-icon-chevron-unfold:hover,.c-icon-chevron-fold:hover,.c-icon-download:hover,.c-icon-lyric:hover,.c-icon-v:hover,.c-icon-hui:hover,.c-icon-bao:hover,.c-icon-person:hover,.c-icon-high-v:hover,.c-icon-phone:hover,.c-icon-nuo:hover,.c-icon-med:hover,.c-icon-air:hover,.c-icon-share2:hover,.c-icon-v1:hover,.c-icon-v2:hover,.c-icon-v3:hover,.c-icon-write:hover{border-color:#388bff}.c-icon-unfold:active,.c-icon-fold:active,.c-icon-chevron-unfold:active,.c-icon-chevron-fold:active,.c-icon-download:active,.c-icon-lyric:active,.c-icon-v:active,.c-icon-hui:active,.c-icon-bao:active,.c-icon-person:active,.c-icon-high-v:active,.c-icon-phone:active,.c-icon-nuo:active,.c-icon-med:active,.c-icon-air:active,.c-icon-share2:active,.c-icon-v1:active,.c-icon-v2:active,.c-icon-v3:active,.c-icon-write:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}.c-icon-unfold,.c-icon-fold,.c-icon-chevron-unfold,.c-icon-chevron-fold,.c-icon-download,.c-icon-lyric{border:1px solid #d8d8d8;cursor:pointer}.c-icon-v,.c-icon-hui,.c-icon-bao,.c-icon-person,.c-icon-high-v,.c-icon-phone,.c-icon-nuo,.c-icon-med,.c-icon-air,.c-icon-share2,.c-icon-v1,.c-icon-v2,.c-icon-v3,.c-icon-write{border:1px solid #d8d8d8;cursor:pointer;border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347)}.c-icon-v1,.c-icon-v2,.c-icon-v3,.c-icon-v1-noborder,.c-icon-v2-noborder,.c-icon-v3-noborder,.c-icon-v1-noborder-disable,.c-icon-v2-noborder-disable,.c-icon-v3-noborder-disable{width:19px}.c-icon-download,.c-icon-lyric{width:16px;height:16px}.c-icon-play-circle,.c-icon-stop-circle{width:18px;height:18px}.c-icon-play-circle-middle,.c-icon-stop-circle-middle{width:24px;height:24px}.c-icon-play-black-large,.c-icon-stop-black-large{width:36px;height:36px}.c-icon-play-black-larger,.c-icon-stop-black-larger{width:52px;height:52px}.c-icon-flag{background-position:0 -144px}.c-icon-bus{background-position:-24px -144px}.c-icon-calendar{background-position:-48px -144px}.c-icon-street{background-position:-72px -144px}.c-icon-map{background-position:-96px -144px}.c-icon-bag{background-position:-120px -144px}.c-icon-money{background-position:-144px -144px}.c-icon-game{background-position:-168px -144px}.c-icon-user{background-position:-192px -144px}.c-icon-globe{background-position:-216px -144px}.c-icon-lock{background-position:-240px -144px}.c-icon-plane{background-position:-264px -144px}.c-icon-list{background-position:-288px -144px}.c-icon-star-gray{background-position:-312px -144px}.c-icon-circle-gray{background-position:-384px -144px}.c-icon-triangle-down{background-position:-408px -144px}.c-icon-triangle-up{background-position:-432px -144px}.c-icon-triangle-up-empty{background-position:-456px -144px}.c-icon-sort-gray{background-position:-480px -144px}.c-icon-sort-up{background-position:-504px -144px}.c-icon-sort-down{background-position:-528px -144px}.c-icon-down-gray{background-position:-552px -144px}.c-icon-up-gray{background-position:-576px -144px}.c-icon-download-noborder{background-position:-600px -144px}.c-icon-lyric-noborder{background-position:-624px -144px}.c-icon-download-white{background-position:-648px -144px}.c-icon-close{background-position:-672px -144px}.c-icon-fail{background-position:-696px -144px}.c-icon-success{background-position:-720px -144px}.c-icon-triangle-down-g{background-position:-744px -144px}.c-icon-refresh{background-position:-768px -144px}.c-icon-chevron-left-gray{background-position:-816px -144px}.c-icon-chevron-right-gray{background-position:-840px -144px}.c-icon-setting{background-position:-864px -144px}.c-icon-close2{background-position:-888px -144px}.c-icon-chevron-top-gray-s{background-position:-912px -144px}.c-icon-fullscreen{background-position:0 -168px}.c-icon-safe{background-position:-24px -168px}.c-icon-exchange{background-position:-48px -168px}.c-icon-chevron-bottom{background-position:-72px -168px}.c-icon-chevron-top{background-position:-96px -168px}.c-icon-unfold{background-position:-120px -168px}.c-icon-fold{background-position:-144px -168px}.c-icon-chevron-unfold{background-position:-168px -168px}.c-icon-qa{background-position:-192px -168px}.c-icon-register{background-position:-216px -168px}.c-icon-star{background-position:-240px -168px}.c-icon-star-gray{position:relative}.c-icon-star-gray .c-icon-star{position:absolute;top:0;left:0}.c-icon-play-blue{background-position:-312px -168px}.c-icon-pic{width:16px;background-position:-336px -168px}.c-icon-chevron-fold{background-position:-360px -168px}.c-icon-video{width:18px;background-position:-384px -168px}.c-icon-circle-blue{background-position:-408px -168px}.c-icon-circle-yellow{background-position:-432px -168px}.c-icon-play-white{background-position:-456px -168px}.c-icon-triangle-down-blue{background-position:-480px -168px}.c-icon-chevron-unfold2{background-position:-504px -168px}.c-icon-right{background-position:-528px -168px}.c-icon-right-empty{background-position:-552px -168px}.c-icon-new-corner{width:15px;background-position:-576px -168px}.c-icon-horn{background-position:-600px -168px}.c-icon-right-large{width:18px;background-position:-624px -168px}.c-icon-wrong-large{background-position:-648px -168px}.c-icon-circle-blue-s{background-position:-672px -168px}.c-icon-play-gray{background-position:-696px -168px}.c-icon-up{background-position:-720px -168px}.c-icon-down{background-position:-744px -168px}.c-icon-stable{background-position:-768px -168px}.c-icon-calendar-blue{background-position:-792px -168px}.c-icon-triangle-down-blue2{background-position:-816px -168px}.c-icon-triangle-up-blue2{background-position:-840px -168px}.c-icon-down-blue{background-position:-864px -168px}.c-icon-up-blue{background-position:-888px -168px}.c-icon-ting{background-position:-912px -168px}.c-icon-piao{background-position:-936px -168px}.c-icon-wrong-empty{background-position:-960px -168px}.c-icon-warning-circle-s{background-position:-984px -168px}.c-icon-chevron-left{background-position:-1008px -168px}.c-icon-chevron-right{background-position:-1032px -168px}.c-icon-circle-gray-s{background-position:-1056px -168px}.c-icon-v,.c-icon-v-noborder{background-position:0 -192px}.c-icon-hui{background-position:-24px -192px}.c-icon-bao{background-position:-48px -192px}.c-icon-phone{background-position:-72px -192px}.c-icon-qa-empty{background-position:-96px -192px}.c-icon-safeguard{background-position:-120px -192px}.c-icon-register-empty{background-position:-144px -192px}.c-icon-zan{background-position:-168px -192px}.c-icon-music{background-position:-192px -192px}.c-icon-music-gray{background-position:-216px -192px}.c-icon-location{background-position:-240px -192px}.c-icon-warning{background-position:-264px -192px}.c-icon-doc{background-position:-288px -192px}.c-icon-xls{background-position:-312px -192px}.c-icon-ppt{background-position:-336px -192px}.c-icon-pdf{background-position:-360px -192px}.c-icon-txt{background-position:-384px -192px}.c-icon-play-black{background-position:-408px -192px}.c-icon-play-black:hover{background-position:-432px -192px}.c-icon-gift{background-position:-456px -192px}.c-icon-baidu-share{background-position:-480px -192px}.c-icon-bear{background-position:-504px -192px}.c-icon-bear-border{background-position:-576px -192px}.c-icon-person,.c-icon-person-noborder{background-position:-600px -192px}.c-icon-location-blue{background-position:-624px -192px}.c-icon-hotAirBall{background-position:-648px -192px}.c-icon-moon{background-position:-672px -192px}.c-icon-streetMap{background-position:-696px -192px}.c-icon-high-v,.c-icon-high-v-noborder{background-position:-720px -192px}.c-icon-nuo{background-position:-744px -192px}.c-icon-mv{background-position:-768px -192px}.c-icon-med{background-position:-816px -192px}.c-icon-air{background-position:-840px -192px}.c-icon-share2{background-position:-864px -192px}.c-icon-v1,.c-icon-v1-noborder{background-position:-888px -192px}.c-icon-v2,.c-icon-v2-noborder{background-position:-912px -192px}.c-icon-v3,.c-icon-v3-noborder{background-position:-936px -192px}.c-icon-v1-noborder-disable{background-position:-960px -192px}.c-icon-v2-noborder-disable{background-position:-984px -192px}.c-icon-v3-noborder-disable{background-position:-1008px -192px}.c-icon-write{background-position:-1032px -192px}.c-icon-zhidao-s{background-position:-1056px -192px}.c-icon-shopping{background-position:-1080px -192px}.c-icon-bear-circle{background-position:0 -216px}.c-icon-warning-circle{background-position:-24px -216px}.c-icon-warning-triangle{width:24px;background-position:-48px -216px}.c-icon-warning-circle-gray{background-position:-72px -216px}.c-icon-ball-red{background-position:0 -240px}.c-icon-ball-blue{background-position:-48px -240px}.c-icon-tieba{background-position:0 -288px}.c-icon-zhidao{background-position:-48px -288px}.c-icon-bear-p{background-position:-96px -288px}.c-icon-bear-pn{background-position:-144px -288px}.c-icon-download{background-position:0 -336px}.c-icon-lyric{background-position:-24px -336px}.c-icon-play-circle{background-position:-48px -336px}.c-icon-play-circle:hover{background-position:-72px -336px}.c-icon-stop-circle{background-position:-96px -336px}.c-icon-stop-circle:hover{background-position:-120px -336px}.c-icon-play-circle-middle{background-position:0 -360px}.c-icon-play-circle-middle:hover{background-position:-48px -360px}.c-icon-stop-circle-middle{background-position:-96px -360px}.c-icon-stop-circle-middle:hover{background-position:-144px -360px}.c-icon-play-black-large{background-position:0 -408px}.c-icon-play-black-large:hover{background-position:-48px -408px}.c-icon-stop-black-large{background-position:-96px -408px}.c-icon-stop-black-large:hover{background-position:-144px -408px}.c-icon-play-black-larger{background-position:0 -456px}.c-icon-play-black-larger:hover{background-position:-72px -456px}.c-icon-stop-black-larger{background-position:-144px -456px}.c-icon-stop-black-larger:hover{background-position:-216px -456px}.c-recommend{font-size:0;padding:5px 0;border:1px solid #f3f3f3;border-left:none;border-right:0}.c-recommend .c-icon{margin-bottom:-4px}.c-recommend .c-gray,.c-recommend a{font-size:13px}.c-recommend-notopline{padding-top:0;border-top:0}.c-recommend-vline{display:inline-block;margin:0 10px -2px;border-left:1px solid #d8d8d8;width:0;height:12px;_vertical-align:middle;_overflow:hidden}.c-text{display:inline-block;padding:2px;text-align:center;vertical-align:text-bottom;font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;overflow:hidden}a.c-text{text-decoration:none}.c-text-new{background-color:#f13f40}.c-text-info{padding-left:0;padding-right:0;font-weight:bold;color:#2b99ff;*vertical-align:baseline;_position:relative;_top:2px}.c-text-info b{_position:relative;_top:-1px}.c-text-info span{padding:0 2px;font-weight:normal}.c-text-important{background-color:#1cb7fd}.c-text-public{background-color:#2b99ff}.c-text-warning{background-color:#ff830f}.c-text-prompt{background-color:#f5c537}.c-text-danger{background-color:#f13f40}.c-text-safe{background-color:#52c277}.c-text-empty{padding-top:1px;padding-bottom:1px;border:1px solid #d8d8d8;cursor:pointer;color:#23b9fd;background-color:#fff}.c-text-empty:hover{border-color:#388bff}.c-text-empty:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}.c-text-mult{padding-left:5px;padding-right:5px}.c-text-gray{background-color:#666}.c-btn,.c-btn:visited{color:#333!important}.c-btn{display:inline-block;padding:0 14px;margin:0;height:24px;line-height:25px;font-size:13px;filter:chroma(color=#000000);*zoom:1;border:1px solid #d8d8d8;cursor:pointer;font-family:inherit;font-weight:normal;text-align:center;vertical-align:middle;background-color:#f9f9f9;overflow:hidden;outline:0}.c-btn:hover{border-color:#388bff}.c-btn:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}a.c-btn{text-decoration:none}button.c-btn{height:26px;_line-height:18px;*overflow:visible}button.c-btn::-moz-focus-inner{padding:0;border:0}.c-btn .c-icon{margin-top:5px}.c-btn-disable{color:#999!important}.c-btn-disable:visited{color:#999!important}.c-btn-disable:hover{border:1px solid #d8d8d8;cursor:default}.c-btn-disable:active{border-color:#d8d8d8;background-color:#f9f9f9;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;-o-box-shadow:none}.c-btn-mini{padding-left:5px;padding-right:5px;height:18px;line-height:18px;font-size:12px}button.c-btn-mini{height:20px;_height:18px;_line-height:14px}.c-btn-mini .c-icon{margin-top:2px}.c-btn-large{height:28px;line-height:28px;font-size:14px;font-family:\"\u5fae\u8f6f\u96c5\u9ed1\",\"\u9ed1\u4f53\"}button.c-btn-large{height:30px;_line-height:24px}.c-btn-large .c-icon{margin-top:7px;_margin-top:6px}.c-btn-primary,.c-btn-primary:visited{color:#fff!important}.c-btn-primary{background-color:#388bff;border-color:#3c8dff #408ffe #3680e6}.c-btn-primary:hover{border-color:#2678ec #2575e7 #1c6fe2 #2677e7;background-color:#388bff;background-image:url(data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAMAAACuX0YVAAAABlBMVEVnpv85i\/9PO5r4AAAAD0lEQVR42gEEAPv\/AAAAAQAFAAIros7PAAAAAElFTkSuQmCC);*background-image:none;background-repeat:repeat-x;box-shadow:1px 1px 1px rgba(0,0,0,0.4);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.4);-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.4);-o-box-shadow:1px 1px 1px rgba(0,0,0,0.4)}.c-btn-primary:active{border-color:#178ee3 #1784d0 #177bbf #1780ca;background-color:#388bff;background-image:none;box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-o-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15)}.c-btn .c-icon{float:left}.c-dropdown2{position:relative;display:inline-block;width:100%;height:26px;line-height:26px;font-size:13px;vertical-align:middle;outline:0;_font-family:SimSun;background-color:#fff;word-wrap:normal;word-break:normal}.c-dropdown2 .c-dropdown2-btn-group{position:relative;height:24px;border:1px solid #999;border-bottom-color:#d8d8d8;border-right-color:#d8d8d8;-moz-user-select:none;-webkit-user-select:none;user-select:none}.c-dropdown2:hover .c-dropdown2-btn-group,.c-dropdown2-hover .c-dropdown2-btn-group{box-shadow:inset 1px 1px 0 0 #d8d8d8;-webkit-box-shadow:inset 1px 1px 0 0 #d8d8d8;-moz-box-shadow:inset 1px 1px 0 0 #d8d8d8;-o-box-shadow:inset 1px 1px 0 0 #d8d8d8}.c-dropdown2:hover .c-dropdown2-btn-icon,.c-dropdown2-hover .c-dropdown2-btn-icon{box-shadow:inset 0 1px 0 0 #d8d8d8;-webkit-box-shadow:inset 0 1px 0 0 #d8d8d8;-moz-box-shadow:inset 0 1px 0 0 #d8d8d8;-o-box-shadow:inset 0 1px 0 0 #d8d8d8}.c-dropdown2:hover .c-dropdown2-btn-icon-border,.c-dropdown2-hover .c-dropdown2-btn-icon-border{background-color:#f2f2f2}.c-dropdown2 .c-dropdown2-btn{height:24px;padding-left:10px;padding-right:10px;cursor:default;overflow:hidden;white-space:nowrap}.c-dropdown2 .c-dropdown2-btn-icon{position:absolute;top:0;right:0;width:23px;height:24px;line-height:24px;background-color:#fff;padding:0 1px 0 10px}.c-dropdown2 .c-dropdown2-btn-icon-border{height:24px;width:23px;border-left:1px solid #d9d9d9;text-align:center;zoom:1}.c-dropdown2 .c-icon-triangle-down{*margin-top:5px;_margin-left:2px}.c-dropdown2 .c-dropdown2-menu{position:absolute;left:0;top:100%;_margin-top:0;width:100%;overflow:hidden;border:1px solid #bbb;background:#fff;visibility:hidden}.c-dropdown2 .c-dropdown2-menu-inner{overflow:hidden}.c-dropdown2 .c-dropdown2-option{background-color:#fff;cursor:pointer}.c-dropdown2 .c-dropdown2-selected{background-color:#f5f5f5}.c-dropdown2-common ul,.c-dropdown2-common li{margin:0;padding:0;list-style:none}.c-dropdown2-common .c-dropdown2-option{height:26px;line-height:26px;font-size:12px;color:#333;white-space:nowrap;cursor:pointer;padding-left:10px}.c-dropdown2-common .c-dropdown2-selected{background-color:#f5f5f5}.c-dropdown2-common .c-dropdown2-menu-group .c-dropdown2-group{padding-left:10px;font-weight:bold;cursor:default}.c-dropdown2-common .c-dropdown2-menu-group .c-dropdown2-option{padding-left:20px}.c-img{display:block;min-height:1px;border:none 0}.c-img3{width:52px}.c-img4{width:75px}.c-img6{width:121px}.c-img7{width:144px}.c-img12{width:259px}.c-img15{width:328px}.c-img18{width:397px}.c-border .c-img3{width:56px}.c-border .c-img4{width:78px}.c-border .c-img7{width:144px}.c-border .c-img12{width:254px}.c-border .c-img15{width:320px}.c-border .c-img18{width:386px}.c-index{display:inline-block;padding:1px 0;color:#fff;width:14px;line-height:100%;font-size:12px;text-align:center;background-color:#8eb9f5}.c-index-hot,.c-index-hot1{background-color:#f54545}.c-index-hot2{background-color:#ff8547}.c-index-hot3{background-color:#ffac38}.c-input{display:inline-block;padding:0 4px;height:24px;line-height:24px\\9;font-size:13px;border:1px solid #999;border-bottom-color:#d8d8d8;border-right-color:#d8d8d8;outline:0;box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;vertical-align:top;overflow:hidden}.c-input:hover{box-shadow:inset 1px 1px 1px 0 #d8d8d8;-webkit-box-shadow:inset 1px 1px 1px 0 #d8d8d8;-moz-box-shadow:inset 1px 1px 1px 0 #d8d8d8;-o-box-shadow:inset 1px 1px 1px 0 #d8d8d8}.c-input .c-icon{float:right;margin-top:6px}.c-input .c-icon-left{float:left;margin-right:4px}.c-input input{float:left;height:22px;*padding-top:4px;margin-top:2px;font-size:13px;border:0;outline:0}.c-input{width:180px}.c-input input{width:162px}.c-input-xmini{width:65px}.c-input-xmini input{width:47px}.c-input-mini{width:88px}.c-input-mini input{width:70px}.c-input-small{width:157px}.c-input-small input{width:139px}.c-input-large{width:203px}.c-input-large input{width:185px}.c-input-xlarge{width:341px}.c-input-xlarge input{width:323px}.c-input12{width:249px}.c-input12 input{width:231px}.c-input20{width:433px}.c-input20 input{width:415px}.c-border .c-input{width:178px}.c-border .c-input input{width:160px}.c-border .c-input-xmini{width:68px}.c-border .c-input-xmini input{width:50px}.c-border .c-input-mini{width:90px}.c-border .c-input-mini input{width:72px}.c-border .c-input-small{width:156px}.c-border .c-input-small input{width:138px}.c-border .c-input-large{width:200px}.c-border .c-input-large input{width:182px}.c-border .c-input-xlarge{width:332px}.c-border .c-input-xlarge input{width:314px}.c-border .c-input12{width:244px}.c-border .c-input12 input{width:226px}.c-border .c-input20{width:420px}.c-border .c-input20 input{width:402px}.c-numberset{*zoom:1}.c-numberset:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-numberset li{float:left;margin-right:17px;list-style:none}.c-numberset .c-numberset-last{margin-right:0}.c-numberset a{display:block;width:50px;text-decoration:none;text-align:center;border:1px solid #d8d8d8;cursor:pointer}.c-numberset a:hover{border-color:#388bff}.c-border .c-numberset li{margin-right:10px}.c-border .c-numberset .c-numberset-last{margin-right:0}.c-border .c-numberset a{width:54px}.c-table{width:100%;border-collapse:collapse;border-spacing:0}.c-table th,.c-table td{padding-left:10px;line-height:1.54;font-size:13px;border-bottom:1px solid #f3f3f3;text-align:left}.cr-content .c-table th:first-child,.cr-content .c-table td:first-child{padding-left:0}.c-table th{padding-top:4px;padding-bottom:4px;font-weight:normal;color:#666;border-color:#f0f0f0;white-space:nowrap;background-color:#fafafa}.c-table td{padding-top:6.5px;padding-bottom:6.5px}.c-table-hasimg td{padding-top:10px;padding-bottom:10px}.c-table a,.c-table em{text-decoration:none}.c-table a:hover,.c-table a:hover em{text-decoration:underline}.c-table a.c-icon:hover{text-decoration:none}.c-table .c-btn:hover,.c-table .c-btn:hover em{text-decoration:none}.c-table-nohihead th{background-color:transparent}.c-table-noborder td{border-bottom:0}.c-tabs-nav-movetop{margin:-10px -9px 0 -10px;position:relative}.c-tabs-nav{border-bottom:1px solid #d9d9d9;background-color:#fafafa;line-height:1.54;font-size:0;*zoom:1;_overflow-x:hidden;_position:relative}.c-tabs-nav:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-tabs-nav .c-tabs-nav-btn{float:right;_position:absolute;_top:0;_right:0;_z-index:1;background:#fafafa}.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-prev,.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-next{float:left;padding:6px 2px;cursor:pointer}.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-disable{cursor:default}.c-tabs-nav .c-tabs-nav-view{_position:relative;overflow:hidden;*zoom:1;margin-bottom:-1px}.c-tabs-nav .c-tabs-nav-view .c-tabs-nav-li{margin-bottom:0}.c-tabs-nav .c-tabs-nav-more{float:left;white-space:nowrap}.c-tabs-nav li,.c-tabs-nav a{color:#666;font-size:13px;*zoom:1}.c-tabs-nav li{display:inline-block;margin-bottom:-1px;*display:inline;padding:3px 15px;vertical-align:bottom;border-style:solid;border-width:2px 1px 0 1px;border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347);list-style:none;cursor:pointer;white-space:nowrap;overflow:hidden}.c-tabs-nav a{text-decoration:none}.c-tabs-nav .c-tabs-nav-sep{height:16px;width:0;padding:0;margin-bottom:4px;border-style:solid;border-width:0 1px 0;border-color:transparent #fff transparent #dedede}.c-tabs-nav .c-tabs-nav-selected{_position:relative;border-color:#2c99ff #e4e4e4 #fff #dedede;background-color:#fff;color:#000;cursor:default}.c-tabs-nav-one .c-tabs-nav-selected{border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347);background-color:transparent;color:#666}.c-tabs .c-tabs .c-tabs-nav{padding:10px 0 5px;border:none 0;background-color:#fff}.c-tabs .c-tabs .c-tabs-nav li,.c-tabs .c-tabs .c-tabs-nav a{color:#00c}.c-tabs .c-tabs .c-tabs-nav li{padding:0 5px;position:static;margin:0 10px;border:none 0;cursor:pointer;white-space:nowrap}.c-tabs .c-tabs .c-tabs-nav .c-tabs-nav-sep{height:11px;width:0;padding:0;margin:0 0 4px 0;border:none 0;border-left:1px solid #d8d8d8}.c-tabs .c-tabs .c-tabs-nav .c-tabs-nav-selected{background-color:#2c99ff;color:#fff;cursor:default}.c-tag{padding-top:3px;margin-bottom:3px;height:1.7em;font-size:13px;line-height:1.4em;transition:height .3s ease-in;-webkit-transition:height .3s ease-in;-moz-transition:height .3s ease-in;-ms-transition:height .3s ease-in;-o-transition:height .3s ease-in;*zoom:1;overflow:hidden}.c-tag:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-tag-cont{overflow:hidden;*zoom:1}.c-tag-type,.c-tag-li,.c-tag-more,.c-tag-cont span{margin:2px 0}.c-tag-type,.c-tag-li,.c-tag-cont span{float:left}.c-tag-type,.c-tag-more{color:#666}.c-tag-li,.c-tag-cont span{padding:0 4px;display:inline-block;margin-right:12px;white-space:nowrap;cursor:pointer;color:#00c}.c-tag .c-tag-selected{background:#388bff;color:#fff}.c-tag-more{float:right;background:#fff;cursor:pointer;*height:18px}.c-tool{display:inline-block;width:56px;height:56px;background:url(\"\/\/www.baidu.com\/aladdin\/img\/tools\/tools-5.png\") no-repeat}.c-tool-region{background-position:0 0}.c-tool-calendar{background-position:-72px 0}.c-tool-city{background-position:-144px 0}.c-tool-phone-pos{background-position:-216px 0}.c-tool-other{background-position:-288px 0}.c-tool-midnight{background-position:-360px 0}.c-tool-kefu{width:121px;background-position:-432px 0}.c-tool-phone{background-position:-576px 0}.c-tool-car{background-position:-648px 0}.c-tool-station{background-position:0 -72px}.c-tool-cheat{background-position:-72px -72px}.c-tool-counter{background-position:-144px -72px}.c-tool-time{background-position:-216px -72px}.c-tool-zip{background-position:-288px -72px}.c-tool-warning{background-position:-360px -72px}.c-tool-ip{background-position:0 -144px}.c-tool-unit{background-position:-72px -144px}.c-tool-rate{background-position:-144px -144px}.c-tool-conversion{background-position:-288px -144px}.c-tool-ads{background-position:-360px -144px}<\/style>";result_common_css=$(result_common_css);result_common_css.attr("data-for","result");var index_css= $('head [index]');var wrapper=$("#wrapper");window.index_on=function(){index_css.insertAfter("meta:eq(0)");result_common_css.remove();wrapper.show();if(bds.su&&bds.su.U&&bds.su.U.homeInit){bds.su.U.homeInit();}};window.index_off=function(){result_common_css.insertAfter("meta:eq(0)");wrapper.show();index_css.remove();};})();</script> -<script type="text/javascript">var Cookie={set:function(c,e,d,f,a,b){document.cookie=c+"="+(b?e:escape(e))+((a)?"; expires="+a.toGMTString():"")+((f)?"; path="+f:"; path=/")+((d)?"; domain="+d:"")},get:function(c,b){var a=document.cookie.match(new RegExp("(^| )"+c+"=([^;]*)(;|$)"));if(a!=null){return unescape(a[2])}return b},clear:function(a,c,b){if(this.get(a)){document.cookie=a+"="+((c)?"; path="+c:"; path=/")+((b)?"; domain="+b:"")+";expires=Fri, 02-Jan-1970 00:00:00 GMT"}}};(function(){var defaultOptions={sugSet:1,sugStoreSet:1,isSwitch:1,isJumpHttps:1,imeSwitch:0,resultNum:10,skinOpen:1,resultLang:0},options={},tmpName;var expire30y=new Date();expire30y.setTime(expire30y.getTime()+30*365*86400000);try{if(bds&&bds.comm&&bds.comm.personalData){if(typeof bds.comm.personalData=="string"){bds.comm.personalData=eval("("+bds.comm.personalData+")")}if(!bds.comm.personalData){return}for(tmpName in bds.comm.personalData){if(defaultOptions.hasOwnProperty(tmpName)&&bds.comm.personalData.hasOwnProperty(tmpName)){if(bds.comm.personalData[tmpName].ErrMsg=="SUCCESS"){options[tmpName]=bds.comm.personalData[tmpName].value -}}}}try{if(!parseInt(options.resultNum)){delete (options.resultNum)}if(!parseInt(options.resultLang)&&options.resultLang!="0"){delete (options.resultLang)}}catch(e){}writeCookie();if(!("sugSet" in options)){options.sugSet=(Cookie.get("sug",3)!=3?0:1)}if(!("sugStoreSet" in options)){options.sugStoreSet=Cookie.get("sugstore",0)}var BAIDUID=Cookie.get("BAIDUID");if(!("resultNum" in options)){if(/NR=(\d+)/.test(BAIDUID)){options.resultNum=RegExp.$1?parseInt(RegExp.$1):10}else{options.resultNum=10}}if(!("resultLang" in options)){if(/SL=(\d+)/.test(BAIDUID)){options.resultLang=RegExp.$1?parseInt(RegExp.$1):0}else{options.resultLang=0}}if(!("isSwitch" in options)){options.isSwitch=(Cookie.get("ORIGIN",0)==2?0:(Cookie.get("ORIGIN",0)==1?2:1))}if(!("imeSwitch" in options)){options.imeSwitch=Cookie.get("bdime",0)}}catch(e){}function save(callback){var optionsStr=[];for(tmpName in options){if(options.hasOwnProperty(tmpName)){optionsStr.push('"'+tmpName+'":"'+options[tmpName]+'"')}}var str="{"+optionsStr.join(",")+"}"; -if(bds.comm.personalData){$.ajax({url:"//www.baidu.com/ups/submit/addtips/?product=ps&tips="+encodeURIComponent(str)+"&_r="+new Date().getTime(),success:function(){writeCookie();if(typeof callback=="function"){callback()}}})}else{writeCookie();if(typeof callback=="function"){setTimeout(callback,0)}}}function set(optionName,value){options[optionName]=value}function get(optionName){return options[optionName]}function writeCookie(){if(options.hasOwnProperty("sugSet")){var value=options.sugSet=="0"?"0":"3";clearCookie("sug");Cookie.set("sug",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("sugStoreSet")){var value=options.sugStoreSet==0?"0":"1";clearCookie("sugstore");Cookie.set("sugstore",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("isSwitch")){var ORINGIN_MAP={0:"2",1:"0",2:"1"};var value=ORINGIN_MAP[options.isSwitch];clearCookie("ORIGIN");Cookie.set("ORIGIN",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("imeSwitch")){var value=options.imeSwitch; -clearCookie("bdime");Cookie.set("bdime",value,document.domain,"/",expire30y)}}function writeBAIDUID(){var BAIDUID=Cookie.get("BAIDUID"),NR,FG,SL;if(/FG=(\d+)/.test(BAIDUID)){FG=RegExp.$1}if(/SL=(\d+)/.test(BAIDUID)){SL=RegExp.$1}if(/NR=(\d+)/.test(BAIDUID)){NR=RegExp.$1}if(options.hasOwnProperty("resultNum")){NR=options.resultNum}if(options.hasOwnProperty("resultLang")){SL=options.resultLang}Cookie.set("BAIDUID",BAIDUID.replace(/:.*$/,"")+(typeof SL!="undefined"?":SL="+SL:"")+(typeof NR!="undefined"?":NR="+NR:"")+(typeof FG!="undefined"?":FG="+FG:""),".baidu.com","/",expire30y,true)}function clearCookie(name){Cookie.clear(name,"/");Cookie.clear(name,"/",document.domain);Cookie.clear(name,"/","."+document.domain);Cookie.clear(name,"/",".baidu.com")}function reset(callback){options=defaultOptions;save(callback)}window.UPS={writeBAIDUID:writeBAIDUID,reset:reset,get:get,set:set,save:save}})();(function(){var c=(navigator&&navigator.userAgent)?navigator.userAgent:"";var b=(document&&document.cookie)?document.cookie:""; -var a=!!(c.match(/(msie [2-8])/i)||(c.match(/windows.*safari/i)&&!c.match(/chrome/i))||c.match(/(linux.*firefox)/i)||c.match(/Chrome\/29/i)||c.match(/mac os x.*firefox/i)||b.match(/\bISSW=1/)||UPS.get("isSwitch")==0);if(bds&&bds.comm){bds.comm.supportis=!a;bds.comm.isui=true;bds.comm.did=(function(){var d="";for(var e=0;e<32;e++){d+=Math.floor(Math.random()*16).toString(16)}return d})()}window.__restart_confirm_timeout=true;window.__confirm_timeout=8000;window.__disable_is_guide=true;window.__disable_swap_to_empty=true;window.__switch_add_mask=true;if(window._async_merge){if(a||window.__disable_predict||window.__disable_preload){document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_async_popstate1_99fb5a68.js'><\/script>")}else{document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_instant_search1_39b2f307.js'><\/script>")}}else{document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_async_search_2132d328.js'><\/script>") -}if(bds.comm.newindex){$(window).on("index_off",function(){$('<div class="c-tips-container" id="c-tips-container"></div>').insertAfter("#wrapper");if(window.__sample_dynamic_tab){$("#s_tab").remove()}})}if(!c.match(/(msie 6)/i)){$(function(){setTimeout(function(){$.ajax({url:"http://s1.bdstatic.com/r/www/cache/static/baiduia/baiduia_b45d552b.js",cache:true,dataType:"script"})},0)})}$(function(){setTimeout(function(){$.ajax({url:"http://s1.bdstatic.com/r/www/cache/static/plugins/every_cookie_9643229f.js",cache:true,dataType:"script"})},0)});if(bds.comm&&bds.comm.ishome&&Cookie.get("H_PS_PSSID")){bds.comm.indexSid=Cookie.get("H_PS_PSSID")}})();</script><script>if(bds.comm.supportis){window.__restart_confirm_timeout=true;window.__confirm_timeout=8000;window.__disable_is_guide=true;window.__disable_swap_to_empty=true;}initPreload({'isui':true,'index_form':"#form",'index_kw':"#kw",'result_form':"#form",'result_kw':"#kw"});</script><script>if(navigator.cookieEnabled){document.cookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT";}</script></body></html><script>(function(){var C=G("lm").getElementsByTagName("A");for(var B=0,A=C.length;B<A;B++){var D=C[B];addEV(D,"mousedown",(function(E,F){return function(){ns_c({fm:"behs",tab:"bdlnk",p1:F+1,title:E.innerHTML,url:E.href})}})(D,B))}})();</script> -<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="content-type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge"><meta content="always" name="referrer"><meta name="theme-color" content="#2932e1"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu.svg"><link rel="dns-prefetch" href="//s1.bdstatic.com"/><link rel="dns-prefetch" href="//t1.baidu.com"/><link rel="dns-prefetch" href="//t2.baidu.com"/><link rel="dns-prefetch" href="//t3.baidu.com"/><link rel="dns-prefetch" href="//t10.baidu.com"/><link rel="dns-prefetch" href="//t11.baidu.com"/><link rel="dns-prefetch" href="//t12.baidu.com"/><link rel="dns-prefetch" href="//b1.bdstatic.com"/><title>百度一下,你就知é“</title> -<style index="index" id="css_index">html,body{height:100%}html{overflow-y:auto}#wrapper{position:relative;_position:;min-height:100%}#head{padding-bottom:100px;text-align:center;*z-index:1}#ftCon{height:100px;position:absolute;bottom:44px;text-align:center;width:100%;margin:0 auto;z-index:0;overflow:hidden}#ftConw{width:720px;margin:0 auto}body{font:12px arial;text-align:;background:#fff}body,p,form,ul,li{margin:0;padding:0;list-style:none}body,form,#fm{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}.bg{background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png);background-repeat:no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif)}.bg_tuiguang_browser{width:16px;height:16px;background-position:-600px 0;display:inline-block;vertical-align:text-bottom;font-style:normal;overflow:hidden;margin-right:5px}.bg_tuiguang_browser_big{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-600px -24px} -.bg_tuiguang_weishi{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-672px -24px}.c-icon{display:inline-block;width:14px;height:14px;vertical-align:text-bottom;font-style normal;overflow:hidden;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png) no-repeat 0 0;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif)}.c-icon-triangle-down-blue{background-position:-480px -168px}.c-icon-chevron-unfold2{background-position:-504px -168px}#m{width:720px;margin:0 auto}#nv a,#nv b,.btn,#lk{font-size:14px}input{border:0;padding:0}#nv{height:19px;font-size:16px;margin:0 0 4px;text-align:left;text-indent:137px}.s_btn{width:95px;height:32px;padding-top:2px\9;font-size:14px;background-color:#ddd;background-position:0 -48px;cursor:pointer}.s_btn_h{background-position:-240px -48px}.s_btn_wr{width:97px;height:34px;display:inline-block;background-position:-120px -48px;*position:relative;z-index:0;vertical-align:top} -#lk{margin:33px 0}#lk span{font:14px "宋体"}#lh{margin:16px 0 5px}#cp,#cp a{color:#666}#cp .c-icon-icrlogo{width:14px;height:17px;display:inline-block;overflow:hidden;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png) no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif);background-position:-600px -96px;position:relative;top:3px}#shouji{margin-right:14px}#u{display:none}#c-tips-container{display:none}#wrapper{min-width:810px;height:100%;min-height:600px}#head{position:relative;padding-bottom:0;height:100%;min-height:600px}#head .head_wrapper{height:100%}#m{position:relative}#fm{padding-left:40px;top:-37px}#lh a{margin:0 10px}#lk{position:absolute;display:none;top:0;right:0}#nv{position:absolute;display:none;top:0;right:0}#lm{color:#666;width:100%;height:60px;margin-top:60px;line-height:15px;font-size:13px;position:absolute;top:0;left:0}#lm a{color:#666}#pad-version{line-height:40px} -.s_ipt_wr.bg,.s_btn_wr.bg,#su.bg{background-image:none}.s_btn_wr{width:auto;height:auto;border-bottom:1px solid transparent;*border-bottom:0}.s_btn{width:100px;height:36px;color:white;font-size:15px;letter-spacing:1px;background:#3385ff;border-bottom:1px solid #2d78f4;outline:medium;*border-bottom:0;-webkit-appearance:none;-webkit-border-radius:0}.s_btn.btnhover{background:#317ef3;border-bottom:1px solid #2868c8;*border-bottom:0;box-shadow:1px 1px 1px #ccc}.s_btn_h{background:#3075dc;box-shadow:inset 1px 1px 5px #2964bb;-webkit-box-shadow:inset 1px 1px 5px #2964bb;-moz-box-shadow:inset 1px 1px 5px #2964bb;-o-box-shadow:inset 1px 1px 5px #2964bb}#result_logo{display:none}#index_logo img{display:inline-block;width:270px;height:129px}#s_tab{display:none}.s_form{position:relative;top:38.2%}.s_form_wrapper{position:relative;top:-191px}.s_ipt_wr{height:34px}#head .c-icon-bear-round{display:none}#form{margin:22px auto 0;width:641px;text-align:left;z-index:100}#form .bdsug,#fm .bdsug{top:35px} -.bdsug{display:none;position:absolute;width:538px;background:#fff;border:1px solid #ccc;_overflow:hidden;box-shadow:1px 1px 3px #ededed;-webkit-box-shadow:1px 1px 3px #ededed;-moz-box-shadow:1px 1px 3px #ededed;-o-box-shadow:1px 1px 3px #ededed}.bdsug.bdsugbg ul{background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/sugbg_6a9201c2.png) 100% 100% no-repeat;background-size:100px 110px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/sugbg_d24a0811.gif)\9}.bdsug li{width:522px;color:#000;font:14px arial;line-height:25px;padding:0 8px;position:relative;cursor:default}.bdsug li.bdsug-s{background:#f0f0f0}.bdsug-store span,.bdsug-store b{color:#7a77c8}.bdsug-store-del{font-size:12px;color:#666;text-decoration:underline;position:absolute;right:8px;top:0;cursor:pointer;display:none}.bdsug-s .bdsug-store-del{display:inline-block}.bdsug-ala{display:inline-block;border-bottom:1px solid #e6e6e6}.bdsug-ala h3{line-height:14px;background:url(//www.baidu.com/img/sug_bd.png) no-repeat left center;margin:8px 0 5px 0;font-size:12px;font-weight:normal;color:#7b7b7b;padding-left:20px} -.bdsug-ala p{font-size:14px;font-weight:bold;padding-left:20px}.bdsug .bdsug-direct{width:auto;padding:0;border-bottom:1px solid #f1f1f1}.bdsug .bdsug-direct p{color:#00c;font-weight:bold;line-height:34px;padding:0 8px;cursor:pointer;white-space:nowrap;overflow:hidden}.bdsug .bdsug-direct p img{width:16px;height:16px;margin:7px 6px 9px 0;vertical-align:middle}.bdsug .bdsug-direct p span{margin-left:8px}.bdsug .bdsug-direct p i{font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;background-color:#2b99ff;display:inline;text-align:center;padding:1px 5px;*padding:2px 5px 0 5px;margin-left:8px;overflow:hidden}.bdsug .bdsug-pcDirect{color:#000;font-size:14px;line-height:30px;height:30px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip{position:absolute;right:15px;top:8px;width:55px;height:15px;display:block;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-s{background-color:#f0f0f0} -.bdsug .bdsug-pcDirect-is{color:#000;font-size:14px;line-height:22px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip-is{position:absolute;right:15px;top:3px;width:55px;height:15px;display:block;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-is-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-s .bdsug-pc-direct-tip,.bdsug .bdsug-pcDirect-is-s .bdsug-pc-direct-tip-is{background-position:0 -15px}.tools{position:absolute;right:-75px}#mHolder{width:62px;position:relative;z-index:296;display:none}#mCon{height:18px;line-height:18px;position:absolute;cursor:pointer}#mCon span{color:#00c;cursor:default;display:block;width:24px}#mCon .hw{text-decoration:underline;cursor:pointer;display:inline-block}#mCon .pinyin{display:inline-block}#mCon .c-icon-chevron-unfold2{margin-left:5px}#mMenu a{width:100%;height:100%;display:block;line-height:22px;text-indent:6px;text-decoration:none;filter:none\9}#mMenu,#user ul{box-shadow:1px 1px 2px #ccc;-moz-box-shadow:1px 1px 2px #ccc;-webkit-box-shadow:1px 1px 2px #ccc;filter:progid:DXImageTransform.Microsoft.Shadow(Strength=2,Direction=135,Color="#cccccc")\9} -#mMenu{width:56px;border:1px solid #9b9b9b;list-style:none;position:absolute;right:27px;top:28px;display:none;background:#fff}#mMenu a:hover{background:#ebebeb}#mMenu .ln{height:1px;background:#ebebeb;overflow:hidden;font-size:1px;line-height:1px;margin-top:-1px}#u1 a:link,#u1 a:visited{color:#666;text-decoration:none}#u1 a:hover,#u1 a:active{text-decoration:underline}#u1 a:active{color:#00c}#u1{z-index:2;color:white;position:absolute;right:0;top:0;margin:19px 0 5px 0;padding:0 96px 0 0}#u1 .reg{display:none}#u1 a.pf,#u1 a.pf:visited{display:inline-block;float:left;color:#333;line-height:24px;font-size:13px;margin-left:20px;overflow:hidden;text-decoration:underline}#u1 a.lb,#u1 a.lb:visited,#u1 a.username{display:inline-block;float:left;color:#333;font-size:13px;line-height:24px;margin-left:20px;text-decoration:underline}#u1 a.bri,#u1 a.bri:visited{display:inline-block;position:absolute;right:10px;width:60px;height:23px;float:left;color:white;background:#38f;line-height:24px;font-size:13px;text-align:center;overflow:hidden;border-bottom:1px solid #38f;margin-left:19px;margin-right:2px} -#u1 a.bri.brihover{display:none;text-decoration:none;color:#333;background:0;border-bottom:1px solid transparent;margin-left:19px}#u1 #lm a{color:#00c;text-decoration:underline}#u1 a.mnav,#u1 a.mnav:visited{float:left;color:#333;font-weight:bold;line-height:24px;margin-left:20px;font-size:13px;text-decoration:underline}#u1 a.pf:hover,#u1 a.lb:hover,#u1 a.mnav:hover{color:#00c}.briiconsbg{background-repeat:no-repeat;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png);background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9}.bdpfmenu{background-color:#fff;border:1px solid #d1d1d1;position:absolute;right:160px;width:68px;top:36px;margin-top:-1px;_margin-top:-3px;z-index:2;box-shadow:1px 1px 5px #d1d1d1;-webkit-box-shadow:1px 1px 5px #d1d1d1;-moz-box-shadow:1px 1px 5px #d1d1d1;-o-box-shadow:1px 1px 5px #d1d1d1}.bdpfmenu a{display:block;text-align:left;margin:0!important;padding:0 9px;line-height:26px;text-decoration:none} -#wrapper .bdpfmenu a:link,#wrapper .bdpfmenu a:visited{background:white;color:#333}#wrapper .bdpfmenu a:hover,#wrapper .bdpfmenu a:active{background:#38f;text-decoration:none;color:white}#wrapper .bdnuarrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-10px;left:50%;margin-left:-5px}#wrapper .bdnuarrow em,#wrapper .bdnuarrow i{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:5px solid transparent;border-style:dashed dashed solid dashed}#wrapper .bdnuarrow em{border-bottom-color:#d8d8d8;top:-1px}#wrapper .bdnuarrow i{border-bottom-color:#fff;top:0}.s-isindex-wrap #wrapper .bdnuarrow{height:13px;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png) no-repeat -90px -1px}#wrapper .bdnuarrow.bdbriarrow{right:104px;display:none!important}#wrapper .bdbri{width:85px;min-height:100px;border-left:1px solid #e7e7e7;position:absolute;background-color:#f9f9f9;overflow:hidden;z-index:2;right:0;top:0}#prefpanel{background:#fafafa;display:none;opacity:0;position:fixed;_position:absolute;top:-359px;z-index:1000;width:100%;min-width:960px;border-bottom:1px solid #ebebeb} -#prefpanel form{_width:850px}#wrapper .bdbriimgtitle{color:#333;text-align:center;width:66px;height:43px;line-height:43px;padding-top:9px;margin:0 auto;border-bottom:#f0f0f0 1px solid;font-size:13px;cursor:default}#wrapper .briscrollwrapper{overflow:hidden}#wrapper .briscrollwrapperContainer{position:relative}#wrapper .bdbri.bdbriimg .bdmainlink a,#wrapper .bdbri.bdbriimg .bdothlink a{display:block;text-align:center;width:66px;height:76px;margin:0 auto;border-bottom:#f0f0f0 1px solid;color:#666;text-decoration:none;overflow:hidden}#wrapper .bdbri.bdbriimg .bdmainlink a:visited,#wrapper .bdbri.bdbriimg .bdothlink a:visited{color:#666}#wrapper .bdbri.bdbriimg .bdmainlink a:hover,#wrapper .bdbri.bdbriimg .bdothlink a:hover{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdmainlink a:active,#wrapper .bdbri.bdbriimg .bdothlink a:active{color:#00c;text-decoration:underline}#wrapper .bdbri.bdbriimg span{width:36px;height:36px;display:block;margin:10px auto 5px;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/logos/bdbri_icons_737be4e5.png) no-repeat;cursor:pointer} -#wrapper .bdbri.bdbriimg .bdbrimore,#wrapper .bdbri.bdbriimg .bdbrievenmore{clear:both;text-align:center}#wrapper .bdbri.bdbriimg .bdbrievenmore{margin-top:15px;height:30px;width:85px;overflow:hidden}#wrapper .bdbri.bdbriimg span.bdbriimgitem_1{background-position:0 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_2{background-position:-36px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_3{width:40px;background-position:-72px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_4{background-position:-112px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_5{background-position:-148px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_6{background-position:-184px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_7{background-position:-220px 0}#wrapper .bdbri.bdbriimg .bdbrievenmore a:link,#wrapper .bdbri.bdbriimg .bdbrievenmore a:visited{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdbrievenmore a:hover{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdbrievenmore a:active{color:#00c} -.bdbriscroll-ctrl-scroll{position:absolute;top:10px;right:1px;width:8px;border-top:1px solid #e4e4e4;border-left:1px solid #e4e4e4;cursor:default;-webkit-user-select:none;-moz-user-select:none}.bdbriscroll-ctrl-scroll .bdbriscroll-axis{width:8px;left:0;z-index:0;position:absolute;background:#f2f2f2}.bdbriscroll-ctrl-scroll-touch .bdbriscroll-axis{width:7px;background:#f2f2f2}.bdbriscroll-ctrl-scroll-hover .bdbriscroll-axis{background:#f2f2f2}.bdbriscroll-ctrl-scroll .bdbriscroll-slider{overflow:hidden;width:7px;height:14px;position:absolute;left:0;z-index:10;display:none;background:#d9d9d9;margin-top:-1px;margin-left:-1px;border-right:1px solid #cecece;border-bottom:1px solid #cecece;cursor:default}.bdbriscroll-ctrl-scroll-touch .bdbriscroll-slider,.bdbriscroll-ctrl-scroll-hover .bdbriscroll-slider{background:#b8b8b8;border-right:1px solid #afafaf;border-bottom:1px solid #afafaf}</style><!--[if lte IE 8]><style index="index" >#head{height:480px\9}.s_form{top:260px}</style><![endif]--><!--[if IE 8]><style index="index" >#u1 a.mnav,#u1 a.mnav:visited,#u1 a.lb,#u1 a.lb:visited,#u1 a.pf,#u1 a.pf:visited,#u1 a.bri,#u1 a.bri:visited{font-family:simsun}</style><![endif]--><style data-for="debug">#debug{display:none!important}</style><style data-for="result" id="css_index_result">#seth{display:none;behavior:url(#default#homepage)}#setf{display:none}#sekj{margin-left:14px}#st,#sekj{display:none}.s_ipt_wr{border:1px solid #b6b6b6;border-color:#7b7b7b #b6b6b6 #b6b6b6 #7b7b7b;background:#fff;display:inline-block;vertical-align:top;width:539px;margin-right:0;border-right-width:0;border-color:#b8b8b8 transparent #ccc #b8b8b8;overflow:hidden}.wrapper_s .s_ipt_wr{width:439px}.wrapper_s .s_ipt{width:434px}.wrapper_s .s_ipt_tip{width:434px}.s_ipt_wr:hover,.s_ipt_wr.ipthover{border-color:#999 transparent #b3b3b3 #999}.s_ipt_wr.iptfocus{border-color:#4791ff transparent #4791ff #4791ff}.s_ipt_tip{color:#aaa;position:absolute;z-index:-10;font:16px/22px arial;height:32px;line-height:32px;padding-left:7px;overflow:hidden;width:526px}.s_ipt{width:526px;height:22px;font:16px/18px arial;line-height:22px\9;margin:6px 0 0 7px;padding:0;background:transparent;border:0;outline:0;-webkit-appearance:none}#kw{position:relative}#u .username i{background-position:-408px -144px}.bdpfmenu,.usermenu{border:1px solid #d1d1d1;position:absolute;width:105px;top:36px;z-index:302;box-shadow:1px 1px 5px #d1d1d1;-webkit-box-shadow:1px 1px 5px #d1d1d1;-moz-box-shadow:1px 1px 5px #d1d1d1;-o-box-shadow:1px 1px 5px #d1d1d1} -.bdpfmenu{font-size:12px;background-color:#fff}.bdpfmenu a,.usermenu a{display:block;text-align:left;margin:0!important;padding:0 9px;line-height:26px;text-decoration:none}.briiconsbg{background-repeat:no-repeat;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png);background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9}#u{z-index:301;position:absolute;right:0;top:0;margin:21px 9px 5px 0;padding:0}.wrapper_s #u{margin-right:3px}#u a{text-decoration:underline;color:#333;margin:0 7px}.wrapper_s #u a{margin-right:0 6px}#u div a{text-decoration:none}#u a:hover{text-decoration:underline}#u .back_org{color:#666;float:left;display:inline-block;height:24px;line-height:24px}#u .bri{display:inline-block;width:24px;height:24px;float:left;line-height:24px;color:transparent;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png) no-repeat 4px 3px;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9;overflow:hidden} -#u .bri:hover,#u .bri.brihover{background-position:-18px 3px}#mCon #imeSIcon{background-position:-408px -144px;margin-left:0}#mCon span{color:#333}.bdpfmenu a:link,.bdpfmenu a:visited,#u .usermenu a:link,#u .usermenu a:visited{background:white;color:#333}.bdpfmenu a:hover,.bdpfmenu a:active,#u .usermenu a:hover,#u .usermenu a:active{background:#38f;text-decoration:none;color:white}.bdpfmenu{width:70px}.usermenu{width:68px;right:8px}#wrapper .bdnuarrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-10px;left:50%;margin-left:-5px}#wrapper .bdnuarrow em,#wrapper .bdnuarrow i{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:5px solid transparent;border-style:dashed dashed solid dashed}#wrapper .bdnuarrow em{border-bottom-color:#d8d8d8;top:-1px}#wrapper .bdnuarrow i{border-bottom-color:#fff;top:0}#prefpanel{background:#fafafa;display:none;opacity:0;position:fixed;_position:absolute;top:-359px;z-index:500;width:100%;min-width:960px;border-bottom:1px solid #ebebeb} -#prefpanel form{_width:850px}#kw_tip{cursor:default;display:none;margin-top:1px}#bds-message-wrapper{top:43px}.quickdelete-wrap{position:relative}.quickdelete-wrap input{width:500px}.wrapper_l .quickdelete-wrap input{width:500px}.wrapper_s .quickdelete-wrap input{width:402px}input::-ms-clear{display:none}.quickdelete{width:32px;height:32px;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/quickdelete_9c14b01a.png) no-repeat;background-position:10px 10px;position:absolute;display:block}.quickdelete:hover{background-position:10px -24px}</style><script >function h(obj){obj.style.behavior='url(#default#homepage)';var a = obj.setHomePage('//www.baidu.com/');}</script><noscript><meta http-equiv="refresh" content="0; url=/baidu.html?from=noscript"/></noscript><script>window._ASYNC_START=new Date().getTime();</script></head><body link="#0000cc"><script>if (/Chrome\/37.0.2062.94/i.test(navigator.userAgent) && (/(windows 7)|(windows nt 6.1)/i.test(navigator.userAgent))) {var _chrome_37_fix = document.createElement("style"); _chrome_37_fix.type="text/css";_chrome_37_fix.setAttribute("data-for","result");_chrome_37_fix.innerHTML = ".t,.f16,#kw,.s_ipt,.c-title,.c-title-size,.to_zhidao,.to_tieba,.to_zhidao_bottom{font-size:15px;} .ec-hospital-info-main h2,.ad-widget-gx_sck-ylzx-doctor-info h2,.ec-card-main h2,.ad-widget-h1 h2,.ad-widget-title h2,.ad-widget-small-head h2,.ad-widget-small-head h2 a,.ad-widget-header .ec-figcaption h2{font-size: 15px !important;}";document.getElementsByTagName("head")[0].appendChild(_chrome_37_fix); }</script><div id="wrapper" style="display:none;"><script>if(window.bds&&bds.util&&bds.util.setContainerWidth){bds.util.setContainerWidth();}</script><div id="head"><div class="head_wrapper"><div class="s_form"><div class="s_form_wrapper"><div id="lg"><img hidefocus="true" src="//www.baidu.com/img/bd_logo1.png" width="270" height="129"></div><a href="/" id="result_logo" onmousedown="return c({'fm':'tab','tab':'logo'})"><img src="//www.baidu.com/img/baidu_jgylogo3.gif" alt="到百度首页" title="到百度首页"></a><form id="form" name="f" action="/s" class="fm"><input type="hidden" name="ie" value="utf-8"><input type="hidden" name="f" value="8"><input type="hidden" name="rsv_bp" value="1"><input type="hidden" name="rsv_idx" value="1"><input type=hidden name=ch value=""><input type=hidden name=tn value="baidu"><input type=hidden name=bar value=""><span class="bg s_ipt_wr"><input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off"></span><span class="bg s_btn_wr"><input type="submit" id="su" value="百度一下" class="bg s_btn"></span><span class="tools"><span id="mHolder"><div id="mCon"><span>输入法</span></div><ul id="mMenu"><li><a href="javascript:;" name="ime_hw">手写</a></li><li><a href="javascript:;" name="ime_py">拼音</a></li><li class="ln"></li><li><a href="javascript:;" name="ime_cl">关闭</a></li></ul></span></span><input type="hidden" name="rn" value=""><input type="hidden" name="rsv_pq" value="c3414a56000074e1"><input type="hidden" name="rsv_t" value="b2ff/RbyPSLTuaaaq6YlY+Wuex3fgM7l8vG0/+n0kgi2fgvlMsXKqvu6294"></form><div id="m"><p id="lm"><font>6.18特惠:<a href="http://click.union.jd.com/JdClick/?unionId=291540637&siteid=baidu_wzl235&to=http://sale.jd.com/act/cwMpj4ytUFA.html" title="京东商城" target="_blank">京东商城</a>&nbsp;&nbsp;<a href="http://www.nuomi.com/?cid=bdsywzl" title="百度糯米" target="_blank">百度糯米</a>&nbsp;&nbsp;<a href="http://click.union.vip.com/redirect.php?url=eyJjaGFuIjoiYmFpZHVjb213emwiLCJhZGNvZGUiOiIiLCJzY2hlbWVjb2RlIjoiZDVkNTMzMmUiLCJ1Y29kZSI6InhzcmVzYmNiIn0=" title="唯å“会" target="_blank">唯å“会</a></font></p></div></div></div><div id="u"><a class="toindex" href="/">百度首页</a><a href="javascript:;" name="tj_settingicon" class="pf">设置<i class="c-icon c-icon-triangle-down"></i></a><a href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F" name="tj_login" class="lb" onclick="return false;">登录</a></div><div id="u1"><a href="http://news.baidu.com" name="tj_trnews" class="mnav">æ–°é—»</a><a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a><a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a><a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a><a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">è´´å§</a><a href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F" name="tj_login" class="lb" onclick="return false;">登录</a><a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf" class="">设置</a><a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产å“</a></div></div></div><div class="s_tab" id="s_tab"><b>网页</b><a href="http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'news'})">æ–°é—»</a><a href="http://tieba.baidu.com/f?kw=&fr=wwwt" wdfield="kw" onmousedown="return c({'fm':'tab','tab':'tieba'})">è´´å§</a><a href="http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=&fr=wwwt" wdfield="word" onmousedown="return c({'fm':'tab','tab':'zhidao'})">知é“</a><a href="http://music.baidu.com/search?fr=ps&ie=utf-8&key=" wdfield="key" onmousedown="return c({'fm':'tab','tab':'music'})">音ä¹</a><a href="http://image.baidu.com/i?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'pic'})">图片</a><a href="http://v.baidu.com/v?ct=301989888&rn=20&pn=0&db=0&s=25&ie=utf-8&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'video'})">视频</a><a href="http://map.baidu.com/m?word=&fr=ps01000" wdfield="word" onmousedown="return c({'fm':'tab','tab':'map'})">地图</a><a href="http://wenku.baidu.com/search?word=&lm=0&od=0&ie=utf-8" wdfield="word" onmousedown="return c({'fm':'tab','tab':'wenku'})">文库</a><a href="//www.baidu.com/more/" onmousedown="return c({'fm':'tab','tab':'more'})">更多»</a></div><div id="ftCon"><div id="ftConw"><p id="lh"><a id="seth" onClick="h(this)" href="/" onmousedown="return ns_c({'fm':'behs','tab':'homepage','pos':0})">把百度设为主页</a><a id="setf" href="//www.baidu.com/cache/sethelp/help.html" onmousedown="return ns_c({'fm':'behs','tab':'favorites','pos':0})" target="_blank">把百度设为主页</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about'})" href="http://home.baidu.com">关于百度</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about_en'})" href="http://ir.baidu.com">About&nbsp;&nbsp;Baidu</a></p><p id="cp">&copy;2015&nbsp;Baidu&nbsp;<a href="http://www.baidu.com/duty/" onmousedown="return ns_c({'fm':'behs','tab':'tj_duty'})">使用百度å‰å¿…读</a>&nbsp;<a href="http://jianyi.baidu.com/" class="cp-feedback" onmousedown="return ns_c({'fm':'behs','tab':'tj_homefb'})">æ„è§å馈</a>&nbsp;京ICPè¯030173å·&nbsp;<i class="c-icon-icrlogo"></i></p></div></div><div id="wrapper_wrapper"></div></div><div class="c-tips-container" id="c-tips-container"></div><script>window.__async_strategy=2;</script><script>var bds={se:{},su:{urdata:[],urSendClick:function(){}},util:{},use:{},comm : {domain:"http://www.baidu.com",ubsurl : "http://sclick.baidu.com/w.gif",tn:"baidu",queryEnc:"",queryId:"",inter:"",templateName:"baidu",sugHost : "http://suggestion.baidu.com/su",query : "",qid : "c3414a56000074e1",cid : "0",sid : "14579_14804_1430_7477_12658_14510_14444_12824_10812_14429_12867_14621_13201_14871_12723_14532_14485_14919_14902_12247_13936",indexSid : "14579_14804_1430_7477_12658_14510_14444_12824_10812_14429_12867_14621_13201_14871_12723_14532_14485_14919_14902_12247_13936",stoken : "",serverTime : "1434605565",user : "",username : "",userid : "0",isBaixiaoduOn : "",loginAction : [],useFavo : "",pinyin : "",favoOn : "",cookie : {"BIDUPSID":"FA4F72A8875617C6B27495B923824EDF","PSTM":"1433320511","BAIDUID":"A3D363D340BBC998D2EB5C21ADDAC2C2:FG=1","H_PS_PSSID":"14579_14804_1430_7477_12658_14510_14444_12824_10812_14429_12867_14621_13201_14871_12723_14532_14485_14919_14902_12247_13936","BDSVRTM":"0","BD_HOME":"0"},curResultNum:"0",rightResultExist:false,protectNum:0,zxlNum:0,pageNum:1,pageSize:10,newindex:0,async:2,maxPreloadThread:5,maxPreloadTimes:10,preloadMouseMoveDistance:5,switchAddMask:false,isDebug:false,ishome : 1,flagTranslateResult:0,globalLogFlag:0,encTn:'b2ff/RbyPSLTuaaaq6YlY+Wuex3fgM7l8vG0/+n0kgi2fgvlMsXKqvu6294'}};var name,navigate,al_arr=[];var selfOpen = window.open;eval("var open = selfOpen;");var isIE=navigator.userAgent.indexOf("MSIE")!=-1&&!window.opera;var E = bds.ecom= {};bds.se.mon = {'loadedItems':[],'load':function(){},'srvt':-1};try {bds.se.mon.srvt = parseInt(document.cookie.match(new RegExp("(^| )BDSVRTM=([^;]*)(;|$)"))[2]);document.cookie="BDSVRTM=;expires=Sat, 01 Jan 2000 00:00:00 GMT"; }catch(e){}var bdUser = bds.comm.user?bds.comm.user:null,bdQuery = bds.comm.query,bdUseFavo = bds.comm.useFavo,bdFavoOn = bds.comm.favoOn,bdCid = bds.comm.cid,bdSid = bds.comm.sid,bdServerTime = bds.comm.serverTime,bdQid = bds.comm.queryId,bdstoken = bds.comm.stoken,login_success = [];bds.util.domain = (function(){var list = {"vse.baidu.com":"http://vse.baidu.com","hdpreload.baidu.com":"http://hdpreload.baidu.com","lcr.open.baidu.com":"http://lcr.open.baidu.com","kankan.baidu.com":"http://kankan.baidu.com","xapp.baidu.com":"http://xapp.baidu.com","dr.dh.baidu.com":"http://dr.dh.baidu.com","xiaodu.baidu.com":"http://xiaodu.baidu.com","s1.bdstatic.com":"http://s1.bdstatic.com","olime.baidu.com":"http://olime.baidu.com","app.baidu.com":"http://app.baidu.com","i.baidu.com":"http://i.baidu.com","c.baidu.com":"http://c.baidu.com","sclick.baidu.com":"http://sclick.baidu.com","nsclick.baidu.com":"http://nsclick.baidu.com","eclick.baidu.com":"http://eclick.baidu.com","api.map.baidu.com":"http://api.map.baidu.com","ecma.bdimg.com":"http://ecma.bdimg.com","t10.baidu.com":"http://t10.baidu.com","t11.baidu.com":"http://t11.baidu.com","t12.baidu.com":"http://t12.baidu.com","i7.baidu.com":"http://i7.baidu.com","i8.baidu.com":"http://i8.baidu.com","i9.baidu.com":"http://i9.baidu.com","b1.bdstatic.com":"http://b1.bdstatic.com","ss.bdimg.com":"http://ss.bdimg.com","opendata.baidu.com":"http://opendata.baidu.com","api.open.baidu.com":"http://api.open.baidu.com","tag.baidu.com":"http://tag.baidu.com","f3.baidu.com":"http://f3.baidu.com","s.share.baidu.com":"http://s.share.baidu.com","bdimg.share.baidu.com":"http://bdimg.share.baidu.com"};var get = function(url) {if(location.protocol === "http") {return url;}var reg = /^(http[s]?:\/\/)?([^\/]+)(.*)/,matches = url.match(reg);url = list.hasOwnProperty(matches[2])&&(list[matches[2]] + matches[3]) || url;return url;},set = function(kdomain,vdomain) {list[kdomain] = vdomain;}; return {get : get,set : set}})();</script><script>if(!location.hash.match(/[^a-zA-Z0-9]wd=/)){document.getElementById("wrapper").style.display='block';setTimeout(function(){try{var kw=document.getElementById("kw");kw.focus();kw.parentNode.className="bg s_ipt_wr iptfocus quickdelete-wrap";}catch(e){}},0);}</script><script type="text/javascript" src="http://s1.bdstatic.com/r/www/cache/static/jquery/jquery-1.10.2.min_f2fb5194.js"></script><script>(function(){var result_common_css="<style data-for=\"result\" id=\"css_result\">body{color:#333;background:#fff;padding:6px 0 0;margin:0;position:relative;min-width:900px}body,th,td,.p1,.p2{font-family:arial}p,form,ol,ul,li,dl,dt,dd,h3{margin:0;padding:0;list-style:none}input{padding-top:0;padding-bottom:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}table,img{border:0}td{font-size:9pt;line-height:18px}em{font-style:normal;color:#c00}a em{text-decoration:underline}cite{font-style:normal;color:#008000}.m,a.m{color:#666}a.m:visited{color:#606}.g,a.g{color:#008000}.c{color:#77c}.f14{font-size:14px}.f10{font-size:10.5pt}.f16{font-size:16px}.f13{font-size:13px}.bg{background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_4e7241a3.png);background-repeat:no-repeat;_background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_d160197c.gif);background-repeat:no-repeat}.bg_tuiguang_browser{width:16px;height:16px;background-position:-600px 0;display:inline-block;vertical-align:text-bottom;font-style:normal;overflow:hidden;margin-right:5px}.bg_tuiguang_browser_big{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-600px -24px}.bg_tuiguang_weishi{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-672px -24px}#u,#head,#tool,#search,#foot{font-size:12px}.logo{width:117px;height:38px;cursor:pointer}.p1{line-height:120%;margin-left:-12pt}.p2{width:100%;line-height:120%;margin-left:-12pt}#wrapper{_zoom:1}#container{word-break:break-all;word-wrap:break-word}.container_s{width:1002px}.container_l{width:1222px}#content_left{width:636px;float:left;padding-left:35px}#content_right{border-left:1px solid #e1e1e1;float:right}.container_s #content_right{width:271px}.container_l #content_right{width:434px}.content_none{padding-left:35px}#u{color:#999;white-space:nowrap;position:absolute;right:10px;top:4px;z-index:299}#u a{color:#00c;margin:0 5px}#u .reg{margin:0}#u .last{margin-right:0}#u .un{font-weight:bold;margin-right:5px}#u ul{width:100%;background:#fff;border:1px solid #9b9b9b}#u li{height:25px}#u li a{width:100%;height:25px;line-height:25px;display:block;text-align:left;text-decoration:none;text-indent:6px;margin:0;filter:none\\9}#u li a:hover{background:#ebebeb}#u li.nl{border-top:1px solid #ebebeb}#user{display:inline-block}#user_center{position:relative;display:inline-block}#user_center .user_center_btn{margin-right:5px}.userMenu{width:64px;position:absolute;right:7px;_right:2px;top:15px;top:14px\\9;*top:15px;padding-top:4px;display:none;*background:#fff}#head{padding-left:35px;margin-bottom:20px;width:900px}.fm{clear:both;position:relative;z-index:297}.nv a,.nv b,.btn,#page,#more{font-size:14px}.s_nav{height:45px}.s_nav .s_logo{margin-right:20px;float:left}.s_nav .s_logo img{border:0;display:block}.s_tab{line-height:18px;padding:20px 0 0;float:left}.s_nav a{color:#00c;font-size:14px}.s_nav b{font-size:14px}.s_ipt_wr{width:536px;height:30px;display:inline-block;margin-right:5px;background-position:0 -96px;border:1px solid #b6b6b6;border-color:#7b7b7b #b6b6b6 #b6b6b6 #7b7b7b;vertical-align:top}.s_ipt{width:523px;height:22px;font:16px\/18px arial;line-height:22px\\9;margin:5px 0 0 7px;padding:0;background:#fff;border:0;outline:0;-webkit-appearance:none}.s_btn{width:95px;height:32px;padding-top:2px\\9;font-size:14px;padding:0;background-color:#ddd;background-position:0 -48px;border:0;cursor:pointer}.s_btn_h{background-position:-240px -48px}.s_btn_wr{width:97px;height:34px;display:inline-block;background-position:-120px -48px;*position:relative;z-index:0;vertical-align:top}.sethf{padding:0;margin:0;font-size:14px}.set_h{display:none;behavior:url(#default#homepage)}.set_f{display:none}.shouji{margin-left:19px}.shouji a{text-decoration:none}#head .bdsug{top:33px}#search form{position:relative}#search form .bdsug{bottom:33px}.bdsug{display:none;position:absolute;z-index:1;width:538px;background:#fff;border:1px solid #ccc;_overflow:hidden;box-shadow:1px 1px 3px #ededed;-webkit-box-shadow:1px 1px 3px #ededed;-moz-box-shadow:1px 1px 3px #ededed;-o-box-shadow:1px 1px 3px #ededed}.bdsug.bdsugbg ul{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/home\/img\/sugbg_6a9201c2.png) 100% 100% no-repeat;background-size:100px 110px;background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/home\/img\/sugbg_d24a0811.gif)\\9}.bdsug li{width:522px;color:#000;font:14px arial;line-height:22px;padding:0 8px;position:relative;cursor:default}.bdsug li.bdsug-s{background:#f0f0f0}.bdsug-store span,.bdsug-store b{color:#7a77c8}.bdsug-store-del{font-size:12px;color:#666;text-decoration:underline;position:absolute;right:8px;top:0;cursor:pointer;display:none}.bdsug-s .bdsug-store-del{display:inline-block}.bdsug-ala{display:inline-block;border-bottom:1px solid #e6e6e6}.bdsug-ala h3{line-height:14px;background:url(\/\/www.baidu.com\/img\/sug_bd.png) no-repeat left center;margin:8px 0 5px 0;font-size:12px;font-weight:normal;color:#7b7b7b;padding-left:20px}.bdsug-ala p{font-size:14px;font-weight:bold;padding-left:20px}.bdsug .bdsug-direct{width:auto;padding:0;border-bottom:1px solid #f1f1f1}.bdsug .bdsug-direct p{color:#00c;font-weight:bold;line-height:34px;padding:0 8px;cursor:pointer;white-space:nowrap;overflow:hidden}.bdsug .bdsug-direct p img{width:16px;height:16px;margin:7px 6px 9px 0;vertical-align:middle}.bdsug .bdsug-direct p span{margin-left:8px}.bdsug .bdsug-direct p i{font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;background-color:#2b99ff;display:inline;text-align:center;padding:1px 5px;*padding:2px 5px 0 5px;margin-left:8px;overflow:hidden}.bdsug .bdsug-pcDirect{color:#000;font-size:14px;line-height:30px;height:30px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip{position:absolute;right:15px;top:8px;width:55px;height:15px;display:block;background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-is{color:#000;font-size:14px;line-height:22px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip-is{position:absolute;right:15px;top:3px;width:55px;height:15px;display:block;background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-is-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-s .bdsug-pc-direct-tip,.bdsug .bdsug-pcDirect-is-s .bdsug-pc-direct-tip-is{background-position:0 -15px}#tb_mr{color:#00c;cursor:pointer;position:relative;z-index:298}#tb_mr b{font-weight:normal;text-decoration:underline}#tb_mr small{font-size:11px}#page{font:14px arial;white-space:nowrap;padding-left:35px}#page a,#page strong{display:inline-block;vertical-align:text-bottom;height:66px;text-align:center;line-height:34px;text-decoration:none;overflow:hidden;margin-right:9px;background:white}#page a{cursor:pointer}#page a:hover{background:0}#page .n:hover,#page a:hover .pc{background:#f2f8ff;border:1px solid #38f}#page .n{height:34px;padding:0 18px;border:1px solid #e1e2e3}#page span{display:block}#page .pc{width:34px;height:34px;border:1px solid #e1e2e3;cursor:pointer}#page .fk{width:24px;height:24px;margin-bottom:6px;margin-left:6px;cursor:pointer}#page strong .fk,#page strong .pc{cursor:auto}#page .fk .c-icon-bear-pn{top:-3px;position:relative}#page .fkd .c-icon-bear-pn{top:3px;position:relative}#page .fk_cur .c-icon-bear-p{top:-2px;position:relative}#page strong .pc{border:0;width:36px;height:36px;line-height:36px}#page .nums{display:inline-block;vertical-align:text-bottom;height:36px;line-height:36px;margin-left:10px}#rs{width:900px;background:#fff;padding:8px 0;margin:20px 0 0 15px}#rs td{width:5%}#rs th{font-size:14px;font-weight:normal;line-height:19px;white-space:nowrap;text-align:left;vertical-align:top}#rs .tt{font-weight:bold;padding:0 10px 0 20px}#rs_top{font-size:14px;margin-bottom:22px}#rs_top a{margin-right:18px}#container .rs{margin:30px 0 20px 0;padding:5px 0 15px 0;font-size:14px;width:540px;padding-left:121px;position:relative;background-color:#fafafa}#container .noback{background-color:#fff}#content_left .rs{margin-left:-121px}#container .rs table{width:540px}#container .rs td{width:5px}#container .rs th{font-size:14px;font-weight:normal;white-space:nowrap;text-align:left;vertical-align:top;width:175px;line-height:22px}#container .rs .tt{font-weight:bold;padding:0 10px 0 20px;padding:0;line-height:30px;font-size:16px}#container .rs a{margin:0;height:24px;width:173px;display:inline-block;line-height:25px;border:1px solid #ebebeb;text-align:center;vertical-align:middle;overflow:hidden;outline:0;color:#333;background-color:#fff;text-decoration:none}#container .rs a:hover{border-color:#388bff}.c-tip-con .c-tip-menu-b ul{width:100px}.c-tip-con .c-tip-menu-b ul{text-align:center}.c-tip-con .c-tip-menu-b li a{display:block;text-decoration:none;cursor:pointer;background-color:#fff;padding:3px 0;color:#666}.c-tip-con .c-tip-menu-b li a:hover{display:block;background-color:#ebebeb}#search{width:900px;padding:35px 0 16px 35px}#search .s_help{position:relative;top:10px}#foot{height:20px;line-height:20px;color:#77c;background:#e6e6e6;text-align:center}#foot span{color:#666}.site_tip{font-size:12px;margin-bottom:20px}.site_tip_icon{width:56px;height:56px;background:url(\/\/www.baidu.com\/aladdin\/img\/tools\/tools-3.png) -288px 0 no-repeat}.to_zhidao,.to_tieba,.to_zhidao_bottom{font-size:16px;line-height:24px;margin:20px 0 0 35px}.to_tieba .c-icon-tieba{float:left}.f{line-height:115%;*line-height:120%;font-size:100%;width:33.7em;word-break:break-all;word-wrap:break-word}.h{margin-left:8px;width:100%}.r{word-break:break-all;cursor:hand;width:238px}.t{font-weight:normal;font-size:medium;margin-bottom:1px}.pl{padding-left:3px;height:8px;padding-right:2px;font-size:14px}.mo,a.mo:link,a.mo:visited{color:#666;font-size:100%;line-height:10px}.htb{margin-bottom:5px}.jc a{color:#c00}a font[size=\"3\"] font,font[size=\"3\"] a font{text-decoration:underline}div.blog,div.bbs{color:#707070;padding-top:2px;font-size:13px}.result{width:33.7em;table-layout:fixed}.result-op .f{word-wrap:normal}.nums{font-size:12px;color:#999}.tools{position:absolute;top:10px;white-space:nowrap}#mHolder{width:62px;position:relative;z-index:296;top:-18px;margin-left:9px;margin-right:-12px;display:none}#mCon{height:18px;position:absolute;top:3px;top:6px\\9;cursor:pointer;line-height:18px}.wrapper_l #mCon{right:7px}#mCon span{color:#00c;cursor:default;display:block}#mCon .hw{text-decoration:underline;cursor:pointer;display:inline-block}#mCon .pinyin{display:inline-block}#mCon .c-icon-chevron-unfold2{margin-left:5px}#mMenu{width:56px;border:1px solid #9b9b9b;position:absolute;right:7px;top:23px;display:none;background:#fff}#mMenu a{width:100%;height:100%;color:#00c;display:block;line-height:22px;text-indent:6px;text-decoration:none;filter:none\\9}#mMenu a:hover{background:#ebebeb}#mMenu .ln{height:1px;background:#ebebeb;overflow:hidden;font-size:1px;line-height:1px;margin-top:-1px}.op_LAMP{background:url(\"\/cache\/global\/img\/aladdinIcon-1.0.gif\") no-repeat 0 2px;color:#77C;display:inline-block;font-size:13px;height:12px;*height:14px;width:16px;text-decoration:none;zoom:1}.EC_mr15{margin-left:0}.pd15{padding-left:0}.map_1{width:30em;font-size:80%;line-height:145%}.map_2{width:25em;font-size:80%;line-height:145%}.favurl{background-repeat:no-repeat;background-position:0 1px;padding-left:20px}.dan_tip{font-size:12px;margin-top:4px}.dan_tip a{color:#b95b07}#more,#u ul,#mMenu,.msg_holder{box-shadow:1px 1px 2px #ccc;-moz-box-shadow:1px 1px 2px #ccc;-webkit-box-shadow:1px 1px 2px #ccc;filter:progid:DXImageTransform.Microsoft.Shadow(Strength=2,Direction=135,Color=\"#cccccc\")\\9}.hit_top{line-height:18px;margin:0 15px 10px 0;width:516px}.hit_top .c-icon-bear{height:18px;margin-right:4px}#rs_top_new,.hit_top_new{width:538px;font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all;margin:0 0 14px 0}.zhannei-si{margin:0 0 10px 121px}.zhannei-si-none{margin:10px 0 -10px 121px}.zhannei-search{margin:10px 0 0 121px;color:#999;font-size:14px}.f a font[size=\"3\"] font,.f font[size=\"-1\"] a font{text-decoration:underline}h3 a font{text-decoration:underline}.c-title{font-weight:normal;font-size:16px}.c-title-size{font-size:16px}.c-abstract{font-size:13px}.c-abstract-size{font-size:13px}.c-showurl{color:#008000;font-size:13px}.c-showurl-color{color:#008000}.c-cache-color{color:#666}.c-lightblue{color:#77C}.c-highlight-color{color:#C00}.c-clearfix:after{content:\".\";display:block;height:0;clear:both;visibility:hidden}.c-clearfix{zoom:1}.c-wrap{word-break:break-all;word-wrap:break-word}.c-icons-outer{overflow:hidden;display:inline-block;vertical-align:bottom;*vertical-align:-1px;_vertical-align:bottom}.c-icons-inner{margin-left:-4px}.c-container table.result,.c-container table.result-op{width:100%}.c-container td.f{font-size:13px;line-height:1.54;width:auto}.c-container .vd_newest_main{width:auto}.c-customicon{display:inline-block;width:16px;height:16px;vertical-align:text-bottom;font-style:normal;overflow:hidden}.c-tip-icon i{display:inline-block;cursor:pointer}.c-tip-con{position:absolute;z-index:1;top:22px;left:-35px;background:#fff;border:1px solid #dcdcdc;border:1px solid rgba(0,0,0,0.2);-webkit-transition:opacity .218s;transition:opacity .218s;-webkit-box-shadow:0 2px 4px rgba(0,0,0,0.2);box-shadow:0 2px 4px rgba(0,0,0,0.2);padding:5px 0 5px 0;display:none;font-size:12px;line-height:20px}.c-tip-arrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-16px}.c-tip-arrow-down{top:auto;bottom:0}.c-tip-arrow em,.c-tip-arrow ins{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:8px solid transparent;border-style:dashed dashed solid dashed}.c-tip-arrow em{border-bottom-color:#d8d8d8}.c-tip-arrow ins{border-bottom-color:#fff;top:2px}.c-tip-arrow-down em,.c-tip-arrow-down ins{border-style:solid dashed dashed dashed;border-color:transparent}.c-tip-arrow-down em{border-top-color:#d8d8d8}.c-tip-arrow-down ins{border-top-color:#fff;top:-2px}.c-tip-con h3{font-size:12px}.c-tip-con .c-tip-title{margin:0 10px;display:inline-block;width:239px}.c-tip-con .c-tip-info{color:#666;margin:0 10px 1px 10px;width:239px}.c-tip-con .c-tip-cer{width:354px;color:#666;margin:0 10px 1px 10px}.c-tip-con .c-tip-title{width:auto;_width:354px}.c-tip-con .c-tip-item-i{padding:3px 0 3px 20px;line-height:14px}.c-tip-con .c-tip-item-i .c-tip-item-icon{margin-left:-20px}.c-tip-con .c-tip-menu ul{width:74px}.c-tip-con .c-tip-menu ul{text-align:center}.c-tip-con .c-tip-menu li a{display:block;text-decoration:none;cursor:pointer;background-color:#fff;padding:3px 0;color:#0000d0}.c-tip-con .c-tip-menu li a:hover{display:block;background-color:#ebebeb}.c-tip-con .c-tip-notice{width:239px;padding:0 10px}.c-tip-con .c-tip-notice .c-tip-notice-succ{color:#4cbd37}.c-tip-con .c-tip-notice .c-tip-notice-fail{color:#f13f40}.c-tip-con .c-tip-notice .c-tip-item-succ{color:#444}.c-tip-con .c-tip-notice .c-tip-item-fail{color:#aaa}.c-tip-con .c-tip-notice .c-tip-item-fail a{color:#aaa}.c-tip-close{right:10px;position:absolute;cursor:pointer}.ecard{height:86px;overflow:hidden}.c-tools{display:inline}.c-tools-share{width:239px;padding:0 10px}.c-fanyi{display:none;width:20px;height:20px;border:solid 1px #d1d1d1;cursor:pointer;position:absolute;margin-left:516px;text-align:center;color:#333;line-height:22px;opacity:.9;background-color:#fff}.c-fanyi:hover{background-color:#39f;color:#fff;border-color:#39f;opacity:1}.c-fanyi-title,.c-fanyi-abstract{display:none}.icp_info{color:#666;margin-top:2px;font-size:13px}.icon-gw,.icon-unsafe-icon{background:#2c99ff;vertical-align:text-bottom;*vertical-align:baseline;height:16px;padding-top:0;padding-bottom:0;padding-left:6px;padding-right:6px;line-height:16px;_padding-top:2px;_height:14px;_line-height:14px;font-size:12px;font-family:simsun;margin-left:10px;overflow:hidden;display:inline-block;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px;color:#fff}a.icon-gw{color:#fff;background:#2196ff;text-decoration:none;cursor:pointer}a.icon-gw:hover{background:#1e87ef}a.icon-gw:active{height:15px;_height:13px;line-height:15px;_line-height:13px;padding-left:5px;background:#1c80d9;border-left:1px solid #145997;border-top:1px solid #145997}.icon-unsafe-icon{background:#e54d4b}#con-at{margin-bottom:11px;padding-left:121px;border-bottom:1px #ebebeb solid}#con-at .result-op{font-size:13px;line-height:1.52em}.wrapper_l #con-at .result-op{width:1058px}.wrapper_s #con-at .result-op{width:869px}#con-ar{margin-bottom:40px}#con-ar .result-op{margin-bottom:28px;font-size:13px;line-height:1.52em}.result_hidden{position:absolute;top:-10000px;left:-10000px}#content_left .result-op,#content_left .result{margin-bottom:14px;border-collapse:collapse}#content_left .c-border .result-op,#content_left .c-border .result{margin-bottom:25px}#content_left .c-border .result-op:last-child,#content_left .c-border .result:last-child{margin-bottom:12px}#content_left .result .f,#content_left .result-op .f{padding:0}.subLink_factory{border-collapse:collapse}.subLink_factory td{padding:0}.subLink_factory td.middle,.subLink_factory td.last{color:#666}.subLink_factory td a{text-decoration:underline}.subLink_factory td.rightTd{text-align:right}.subLink_factory_right{width:100%}.subLink_factory_left td{padding-right:26px}.subLink_factory_left td.last{padding:0}.subLink_factory_left td.first{padding-right:75px}.subLink_factory_right td{width:90px}.subLink_factory_right td.first{width:auto}.general_image_pic a{background:#fff no-repeat center center;text-decoration:none;display:block;overflow:hidden;text-align:left}.res_top_banner{height:36px;text-align:left;border-bottom:1px solid #e3e3e3;background:#f7f7f7;font-size:13px;padding-left:8px;color:#333;position:relative;z-index:302}.res_top_banner span{_zoom:1}.res_top_banner .res_top_banner_icon{background-position:0 -216px;width:18px;height:18px;margin:9px 10px 0 0}.res_top_banner .res_top_banner_icon_baiduapp{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/baiduappLogo_7db5fd3c.png) no-repeat 0 0;width:24px;height:24px;margin:3px 10px 0 0;position:relative;top:3px}.res_top_banner .res_top_banner_download{display:inline-block;width:65px;line-height:21px;_padding-top:1px;margin:0 0 0 10px;color:#333;background:#fbfbfb;border:1px solid #b4b6b8;text-align:center;text-decoration:none}.res_top_banner .res_top_banner_download:hover{border:1px solid #38f}.res_top_banner .res_top_banner_download:active{background:#f0f0f0;border:1px solid #b4b6b8}.res_top_banner .res_top_banner_close{background-position:-672px -144px;cursor:pointer;position:absolute;right:10px;top:10px}.res-gap-right16{margin-right:16px}.res-border-top{border-top:1px solid #f3f3f3}.res-border-bottom{border-bottom:1px solid #f3f3f3}.res-queryext-pos{position:relative;top:1px;_top:0}.c-trust-ecard{height:86px;_height:97px;overflow:hidden}@-moz-document url-prefix(){.result,.f{width:538px}}body{min-width:1000px}#ftCon{display:none}#pad-version{display:none}#index_guide{display:none}#index_logo{display:none}#u1{display:none}.s_ipt_wr{height:32px}body{padding:0}.s_form:after,.s_tab:after{content:\".\";display:block;height:0;clear:both;visibility:hidden}.s_form{zoom:1;height:55px;padding:0 0 0 10px}#result_logo{float:left;margin:7px 0 0}#result_logo img{width:101px}#head{padding:0;margin:0;width:100%;position:absolute;z-index:301;min-width:1000px;background:#fff;border-bottom:1px solid #ebebeb;position:fixed;_position:absolute;-webkit-transform:translateZ(0)}#head .head_wrapper{_width:1000px}#head.s_down{box-shadow:0 0 5px #888}.fm{clear:none;float:left;margin:11px 0 0 10px}#s_tab{background:#f8f8f8;line-height:36px;height:38px;padding:55px 0 0 121px;float:none;zoom:1}#s_tab a,#s_tab b{width:54px;display:inline-block;text-decoration:none;text-align:center;color:#666;font-size:14px}#s_tab b{border-bottom:2px solid #38f;font-weight:bold;color:#323232}#s_tab a:hover{color:#323232}#content_left{width:540px;padding-left:121px;padding-top:5px}#content_right{margin-top:45px}#page{padding:0 0 0 121px;margin:30px 0 40px 0}.to_tieba,.to_zhidao_bottom{margin:10px 0 0 121px}.nums{margin:0 0 0 121px;height:42px;line-height:42px}#rs{padding:0;margin:6px 0 0 121px;width:600px}#rs th{width:175px;line-height:22px}#rs .tt{padding:0;line-height:30px}#rs td{width:5px}#rs table{width:540px}#help{background:#f5f6f5;zoom:1;padding:0 0 0 50px;float:right}#help a{color:#777;padding:0 15px;text-decoration:none}#help a:hover{color:#333}#foot{background:#f5f6f5;border-top:1px solid #ebebeb;text-align:left;height:42px;line-height:42px;margin-top:40px;*margin-top:0}#foot .foot_c{float:left;padding:0 0 0 121px}.content_none{padding:45px 0 25px 121px}.nors p{font-size:18px;font-family:microsoft yahei;color:#000}.nors p em{color:#c00}.nors .tip_head{color:#666;font-size:13px;line-height:28px}.nors li{color:#333;line-height:28px;font-size:13px;font-family:'\u5b8b\u4f53';padding-left:30px;list-style-position:inside;list-style-type:disc}#mCon{top:5px}.s_ipt_wr.bg,.s_btn_wr.bg,#su.bg{background-image:none}.s_ipt_wr.bg{background:0}.s_btn_wr{width:auto;height:auto;border-bottom:1px solid transparent;*border-bottom:0}.s_btn{width:100px;height:34px;color:white;letter-spacing:1px;background:#3385ff;border-bottom:1px solid #2d78f4;outline:medium;*border-bottom:0;-webkit-appearance:none;-webkit-border-radius:0}.s_btn.btnhover{background:#317ef3;border-bottom:1px solid #2868c8;*border-bottom:0;box-shadow:1px 1px 1px #ccc}.s_btn_h{background:#3075dc;box-shadow:inset 1px 1px 3px #2964bb;-webkit-box-shadow:inset 1px 1px 3px #2964bb;-moz-box-shadow:inset 1px 1px 3px #2964bb;-o-box-shadow:inset 1px 1px 3px #2964bb}#wrapper_wrapper .container_l .EC_ppim_top,#wrapper_wrapper .container_xl .EC_ppim_top{width:640px}#wrapper_wrapper .container_s .EC_ppim_top{width:570px}#head .c-icon-bear-round{display:none}.container_l #content_right{width:384px}.container_l{width:1212px}.container_xl #content_right{width:384px}.container_xl{width:1257px}.index_tab_top{display:none}.index_tab_bottom{display:none}#lg{display:none}#m{display:none}#ftCon{display:none}#ent_sug{position:absolute;margin:141px 0 0 130px;font-size:13px;color:#666}.foot_fixed_bottom{position:fixed;bottom:0;width:100%;_position:absolute;_bottom:auto}#head .headBlock{margin:-5px 0 6px 121px}#content_left .leftBlock{margin-bottom:14px;padding-bottom:5px;border-bottom:1px solid #f3f3f3}.hint_toprq_tips{position:relative;width:537px;height:19px;line-height:19px;overflow:hidden;display:none}.hint_toprq_tips span{color:#666}.hint_toprq_icon{margin:0 4px 0 0}.hint_toprq_tips_items{width:444px;_width:440px;max-height:38px;position:absolute;left:95px;top:1px}.hint_toprq_tips_items div{display:inline-block;float:left;height:19px;margin-right:18px;white-space:nowrap;word-break:keep-all}.nums{width:538px}.search_tool{_padding-top:15px}.head_nums_cont_outer{height:40px;overflow:hidden;position:relative}.head_nums_cont_inner{position:relative}.search_tool_conter .c-gap-left{margin-left:23px}.search_tool_conter .c-icon-triangle-down{opacity:.6}.search_tool_conter .c-icon-triangle-down:hover{opacity:1}.search_tool,.search_tool_close{float:right}.search_tool,.search_tool_conter span{cursor:pointer;color:#666}.search_tool:hover,.search_tool_conter span:hover{color:#333}.search_tool_conter{font-size:12px;color:#666;margin:0 0 0 121px;height:42px;width:538px;line-height:42px;*height:auto;*line-height:normal;*padding:14px 0}.search_tool_conter span strong{color:#666}.c-tip-con .c-tip-langfilter ul{width:80px;text-align:left;color:#666}.c-tip-con .c-tip-langfilter li a{text-indent:15px;color:#666}.c-tip-con .c-tip-langfilter li span{text-indent:15px;padding:3px 0;color:#999;display:block}.c-tip-con .c-tip-timerfilter ul{width:115px;text-align:left;color:#666}.c-tip-con .c-tip-timerfilter-ft ul{width:180px}.c-tip-con .c-tip-timerfilter-si ul{width:206px;padding:7px 10px 10px}.c-tip-con .c-tip-timerfilter li a{text-indent:15px;color:#666}.c-tip-con .c-tip-timerfilter li span{text-indent:15px;padding:3px 0;color:#999;display:block}.c-tip-con .c-tip-timerfilter-ft li a,.c-tip-con .c-tip-timerfilter-ft li span{text-indent:20px}.c-tip-custom{padding:0 15px 10px 15px;position:relative;zoom:1}.c-tip-custom hr{border:0;height:0;border-top:1px solid #ebebeb}.c-tip-custom p{color:#b6b6b6;height:25px;line-height:25px;margin:2px 0}.c-tip-custom .c-tip-custom-et{margin-bottom:7px}.c-tip-custom-input,.c-tip-si-input{display:inline-block;font-size:11px;color:#333;margin-left:4px;padding:0 2px;width:74%;height:16px;line-height:16px\\9;border:1px solid #ebebeb;outline:0;box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;overflow:hidden;position:relative}.c-tip-custom-input-init{color:#d4d4d4}.c-tip-custom-input-focus,.c-tip-si-input-focus{border:1px solid #3385ff}.c-tip-timerfilter-si .c-tip-si-input{width:138px;height:22px;line-height:22px;vertical-align:0;*vertical-align:-6px;_vertical-align:-5px;padding:0 5px;margin-left:0}.c-tip-con .c-tip-timerfilter li .c-tip-custom-submit,.c-tip-con .c-tip-timerfilter li .c-tip-timerfilter-si-submit{display:inline;padding:4px 10px;margin:0;color:#333;border:1px solid #d8d8d8;font-family:inherit;font-weight:normal;text-align:center;vertical-align:0;background-color:#f9f9f9;outline:0}.c-tip-con .c-tip-timerfilter li .c-tip-custom-submit:hover,.c-tip-con .c-tip-timerfilter li .c-tip-timerfilter-si-submit:hover{display:inline;border-color:#388bff}.c-tip-timerfilter-si-error,.c-tip-timerfilter-custom-error{display:none;color:#3385ff;padding-left:4px}.c-tip-timerfilter-custom-error{padding:0;margin:-5px -13px 7px 0}#c-tip-custom-calenderCont{position:absolute;background:#fff;white-space:nowrap;padding:5px 10px;color:#000;border:1px solid #e4e4e4;-webkit-box-shadow:0 2px 4px rgba(0,0,0,0.2);box-shadow:0 2px 4px rgba(0,0,0,0.2)}#c-tip-custom-calenderCont p{text-align:center;padding:2px 0 4px;*padding:4px 0}#c-tip-custom-calenderCont p i{color:#8e9977;cursor:pointer;text-decoration:underline;font-size:13px}#c-tip-custom-calenderCont .op_cal{background:#fff}.op_cal table{background:#eeefea;margin:0;border-collapse:separate}.op_btn_pre_month,.op_btn_next_month{cursor:pointer;display:block;margin-top:6px}.op_btn_pre_month{float:left;background-position:0 -46px}.op_btn_next_month{float:right;background-position:-18px -46px}.op_cal .op_mon_pre1{padding:0}.op_mon th{text-align:center;font-size:12px;background:#FFF;font-weight:bold;border:1px solid #FFF;padding:0}.op_mon td{text-align:center;cursor:pointer}.op_mon h5{margin:0;padding:0 4px;text-align:center;font-size:14px;background:#FFF;height:28px;line-height:28px;border-bottom:1px solid #f5f5f5;margin-bottom:5px}.op_mon strong{font-weight:bold}.op_mon td{padding:0 5px;border:1px solid #fff;font-size:12px;background:#fff;height:100%}.op_mon td.op_mon_pre_month{color:#a4a4a4}.op_mon td.op_mon_cur_month{color:#00c}.op_mon td.op_mon_next_month{color:#a4a4a4}.op_mon td.op_mon_day_hover{color:#000;border:1px solid #278df2}.op_mon td.op_mon_day_selected{color:#FFF;border:1px solid #278df2;background:#278df2}.op_mon td.op_mon_day_disabled{cursor:not-allowed;color:#ddd}.zhannei-si-none,.zhannei-si,.hit_quet,.zhannei-search{display:none}#c-tip-custom-calenderCont .op_mon td.op_mon_cur_month{color:#000}#c-tip-custom-calenderCont .op_mon td.op_mon_day_selected{color:#fff}.c-frame{margin-bottom:18px}.c-offset{padding-left:10px}.c-gray{color:#666}.c-gap-top-small{margin-top:5px}.c-gap-top{margin-top:10px}.c-gap-bottom-small{margin-bottom:5px}.c-gap-bottom{margin-bottom:10px}.c-gap-left{margin-left:12px}.c-gap-left-small{margin-left:6px}.c-gap-right{margin-right:12px}.c-gap-right-small{margin-right:6px}.c-gap-right-large{margin-right:16px}.c-gap-left-large{margin-left:16px}.c-gap-icon-right-small{margin-right:5px}.c-gap-icon-right{margin-right:10px}.c-gap-icon-left-small{margin-left:5px}.c-gap-icon-left{margin-left:10px}.c-container{width:538px;font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all}.c-container .c-container{width:auto}.c-container table{border-collapse:collapse;border-spacing:0}.c-container td{font-size:13px;line-height:1.54}.c-default{font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all}.c-container .t,.c-default .t{line-height:1.54}.c-default .t{margin-bottom:0}.cr-content{width:259px;font-size:13px;line-height:1.54;color:#333;word-wrap:break-word;word-break:normal}.cr-content table{border-collapse:collapse;border-spacing:0}.cr-content td{font-size:13px;line-height:1.54;vertical-align:top}.cr-offset{padding-left:17px}.cr-title{font-size:14px;line-height:1.29;font-weight:bold}.cr-title-sub{float:right;font-size:13px;font-weight:normal}.c-row{*zoom:1}.c-row:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-span2{width:29px}.c-span3{width:52px}.c-span4{width:75px}.c-span5{width:98px}.c-span6{width:121px}.c-span7{width:144px}.c-span8{width:167px}.c-span9{width:190px}.c-span10{width:213px}.c-span11{width:236px}.c-span12{width:259px}.c-span13{width:282px}.c-span14{width:305px}.c-span15{width:328px}.c-span16{width:351px}.c-span17{width:374px}.c-span18{width:397px}.c-span19{width:420px}.c-span20{width:443px}.c-span21{width:466px}.c-span22{width:489px}.c-span23{width:512px}.c-span24{width:535px}.c-span2,.c-span3,.c-span4,.c-span5,.c-span6,.c-span7,.c-span8,.c-span9,.c-span10,.c-span11,.c-span12,.c-span13,.c-span14,.c-span15,.c-span16,.c-span17,.c-span18,.c-span19,.c-span20,.c-span21,.c-span22,.c-span23,.c-span24{float:left;_display:inline;margin-right:17px;list-style:none}.c-span-last{margin-right:0}.c-span-last-s{margin-right:0}.container_l .cr-content{width:351px}.container_l .cr-content .c-span-last-s{margin-right:17px}.container_l .cr-content-narrow{width:259px}.container_l .cr-content-narrow .c-span-last-s{margin-right:0}.c-border{width:518px;padding:9px;border:1px solid #e3e3e3;border-bottom-color:#e0e0e0;border-right-color:#ececec;box-shadow:1px 2px 1px rgba(0,0,0,0.072);-webkit-box-shadow:1px 2px 1px rgba(0,0,0,0.072);-moz-box-shadow:1px 2px 1px rgba(0,0,0,0.072);-o-box-shadow:1px 2px 1px rgba(0,0,0,0.072)}.c-border .c-gap-left{margin-left:10px}.c-border .c-gap-left-small{margin-left:5px}.c-border .c-gap-right{margin-right:10px}.c-border .c-gap-right-small{margin-right:5px}.c-border .c-border{width:auto;padding:0;border:0;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;-o-box-shadow:none}.c-border .c-span2{width:34px}.c-border .c-span3{width:56px}.c-border .c-span4{width:78px}.c-border .c-span5{width:100px}.c-border .c-span6{width:122px}.c-border .c-span7{width:144px}.c-border .c-span8{width:166px}.c-border .c-span9{width:188px}.c-border .c-span10{width:210px}.c-border .c-span11{width:232px}.c-border .c-span12{width:254px}.c-border .c-span13{width:276px}.c-border .c-span14{width:298px}.c-border .c-span15{width:320px}.c-border .c-span16{width:342px}.c-border .c-span17{width:364px}.c-border .c-span18{width:386px}.c-border .c-span19{width:408px}.c-border .c-span20{width:430px}.c-border .c-span21{width:452px}.c-border .c-span22{width:474px}.c-border .c-span23{width:496px}.c-border .c-span24{width:518px}.c-border .c-span2,.c-border .c-span3,.c-border .c-span4,.c-border .c-span5,.c-border .c-span6,.c-border .c-span7,.c-border .c-span8,.c-border .c-span9,.c-border .c-span10,.c-border .c-span11,.c-border .c-span12,.c-border .c-span13,.c-border .c-span14,.c-border .c-span15,.c-border .c-span16,.c-border .c-span17,.c-border .c-span18,.c-border .c-span19,.c-border .c-span20,.c-border .c-span21,.c-border .c-span22,.c-border .c-span23,.c-border .c-span24{margin-right:10px}.c-border .c-span-last{margin-right:0}.c-loading{display:block;width:50px;height:50px;background:url(\"\/\/www.baidu.com\/aladdin\/img\/tools\/loading.gif\") no-repeat 0 0}.c-vline{display:inline-block;margin:0 3px;border-left:1px solid #ddd;width:0;height:12px;_vertical-align:middle;_overflow:hidden}.c-icon{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_4e7241a3.png) no-repeat 0 0;_background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_d160197c.gif)}.c-icon{display:inline-block;width:14px;height:14px;vertical-align:text-bottom;font-style:normal;overflow:hidden}.c-icon-unfold,.c-icon-fold,.c-icon-chevron-unfold,.c-icon-chevron-fold{width:12px;height:12px}.c-icon-star,.c-icon-star-gray{width:60px}.c-icon-qa-empty,.c-icon-safeguard,.c-icon-register-empty,.c-icon-zan,.c-icon-music,.c-icon-music-gray,.c-icon-location,.c-icon-warning,.c-icon-doc,.c-icon-xls,.c-icon-ppt,.c-icon-pdf,.c-icon-txt,.c-icon-play-black,.c-icon-gift,.c-icon-baidu-share,.c-icon-bear,.c-icon-bear-border,.c-icon-location-blue,.c-icon-hotAirBall,.c-icon-moon,.c-icon-streetMap,.c-icon-mv,.c-icon-zhidao-s,.c-icon-shopping{width:16px;height:16px}.c-icon-bear-circle,.c-icon-warning-circle,.c-icon-warning-triangle,.c-icon-warning-circle-gray{width:18px;height:18px}.c-icon-tieba,.c-icon-zhidao,.c-icon-bear-p,.c-icon-bear-pn{width:24px;height:24px}.c-icon-ball-blue,.c-icon-ball-red{width:38px;height:38px}.c-icon-unfold:hover,.c-icon-fold:hover,.c-icon-chevron-unfold:hover,.c-icon-chevron-fold:hover,.c-icon-download:hover,.c-icon-lyric:hover,.c-icon-v:hover,.c-icon-hui:hover,.c-icon-bao:hover,.c-icon-person:hover,.c-icon-high-v:hover,.c-icon-phone:hover,.c-icon-nuo:hover,.c-icon-med:hover,.c-icon-air:hover,.c-icon-share2:hover,.c-icon-v1:hover,.c-icon-v2:hover,.c-icon-v3:hover,.c-icon-write:hover{border-color:#388bff}.c-icon-unfold:active,.c-icon-fold:active,.c-icon-chevron-unfold:active,.c-icon-chevron-fold:active,.c-icon-download:active,.c-icon-lyric:active,.c-icon-v:active,.c-icon-hui:active,.c-icon-bao:active,.c-icon-person:active,.c-icon-high-v:active,.c-icon-phone:active,.c-icon-nuo:active,.c-icon-med:active,.c-icon-air:active,.c-icon-share2:active,.c-icon-v1:active,.c-icon-v2:active,.c-icon-v3:active,.c-icon-write:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}.c-icon-unfold,.c-icon-fold,.c-icon-chevron-unfold,.c-icon-chevron-fold,.c-icon-download,.c-icon-lyric{border:1px solid #d8d8d8;cursor:pointer}.c-icon-v,.c-icon-hui,.c-icon-bao,.c-icon-person,.c-icon-high-v,.c-icon-phone,.c-icon-nuo,.c-icon-med,.c-icon-air,.c-icon-share2,.c-icon-v1,.c-icon-v2,.c-icon-v3,.c-icon-write{border:1px solid #d8d8d8;cursor:pointer;border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347)}.c-icon-v1,.c-icon-v2,.c-icon-v3,.c-icon-v1-noborder,.c-icon-v2-noborder,.c-icon-v3-noborder,.c-icon-v1-noborder-disable,.c-icon-v2-noborder-disable,.c-icon-v3-noborder-disable{width:19px}.c-icon-download,.c-icon-lyric{width:16px;height:16px}.c-icon-play-circle,.c-icon-stop-circle{width:18px;height:18px}.c-icon-play-circle-middle,.c-icon-stop-circle-middle{width:24px;height:24px}.c-icon-play-black-large,.c-icon-stop-black-large{width:36px;height:36px}.c-icon-play-black-larger,.c-icon-stop-black-larger{width:52px;height:52px}.c-icon-flag{background-position:0 -144px}.c-icon-bus{background-position:-24px -144px}.c-icon-calendar{background-position:-48px -144px}.c-icon-street{background-position:-72px -144px}.c-icon-map{background-position:-96px -144px}.c-icon-bag{background-position:-120px -144px}.c-icon-money{background-position:-144px -144px}.c-icon-game{background-position:-168px -144px}.c-icon-user{background-position:-192px -144px}.c-icon-globe{background-position:-216px -144px}.c-icon-lock{background-position:-240px -144px}.c-icon-plane{background-position:-264px -144px}.c-icon-list{background-position:-288px -144px}.c-icon-star-gray{background-position:-312px -144px}.c-icon-circle-gray{background-position:-384px -144px}.c-icon-triangle-down{background-position:-408px -144px}.c-icon-triangle-up{background-position:-432px -144px}.c-icon-triangle-up-empty{background-position:-456px -144px}.c-icon-sort-gray{background-position:-480px -144px}.c-icon-sort-up{background-position:-504px -144px}.c-icon-sort-down{background-position:-528px -144px}.c-icon-down-gray{background-position:-552px -144px}.c-icon-up-gray{background-position:-576px -144px}.c-icon-download-noborder{background-position:-600px -144px}.c-icon-lyric-noborder{background-position:-624px -144px}.c-icon-download-white{background-position:-648px -144px}.c-icon-close{background-position:-672px -144px}.c-icon-fail{background-position:-696px -144px}.c-icon-success{background-position:-720px -144px}.c-icon-triangle-down-g{background-position:-744px -144px}.c-icon-refresh{background-position:-768px -144px}.c-icon-chevron-left-gray{background-position:-816px -144px}.c-icon-chevron-right-gray{background-position:-840px -144px}.c-icon-setting{background-position:-864px -144px}.c-icon-close2{background-position:-888px -144px}.c-icon-chevron-top-gray-s{background-position:-912px -144px}.c-icon-fullscreen{background-position:0 -168px}.c-icon-safe{background-position:-24px -168px}.c-icon-exchange{background-position:-48px -168px}.c-icon-chevron-bottom{background-position:-72px -168px}.c-icon-chevron-top{background-position:-96px -168px}.c-icon-unfold{background-position:-120px -168px}.c-icon-fold{background-position:-144px -168px}.c-icon-chevron-unfold{background-position:-168px -168px}.c-icon-qa{background-position:-192px -168px}.c-icon-register{background-position:-216px -168px}.c-icon-star{background-position:-240px -168px}.c-icon-star-gray{position:relative}.c-icon-star-gray .c-icon-star{position:absolute;top:0;left:0}.c-icon-play-blue{background-position:-312px -168px}.c-icon-pic{width:16px;background-position:-336px -168px}.c-icon-chevron-fold{background-position:-360px -168px}.c-icon-video{width:18px;background-position:-384px -168px}.c-icon-circle-blue{background-position:-408px -168px}.c-icon-circle-yellow{background-position:-432px -168px}.c-icon-play-white{background-position:-456px -168px}.c-icon-triangle-down-blue{background-position:-480px -168px}.c-icon-chevron-unfold2{background-position:-504px -168px}.c-icon-right{background-position:-528px -168px}.c-icon-right-empty{background-position:-552px -168px}.c-icon-new-corner{width:15px;background-position:-576px -168px}.c-icon-horn{background-position:-600px -168px}.c-icon-right-large{width:18px;background-position:-624px -168px}.c-icon-wrong-large{background-position:-648px -168px}.c-icon-circle-blue-s{background-position:-672px -168px}.c-icon-play-gray{background-position:-696px -168px}.c-icon-up{background-position:-720px -168px}.c-icon-down{background-position:-744px -168px}.c-icon-stable{background-position:-768px -168px}.c-icon-calendar-blue{background-position:-792px -168px}.c-icon-triangle-down-blue2{background-position:-816px -168px}.c-icon-triangle-up-blue2{background-position:-840px -168px}.c-icon-down-blue{background-position:-864px -168px}.c-icon-up-blue{background-position:-888px -168px}.c-icon-ting{background-position:-912px -168px}.c-icon-piao{background-position:-936px -168px}.c-icon-wrong-empty{background-position:-960px -168px}.c-icon-warning-circle-s{background-position:-984px -168px}.c-icon-chevron-left{background-position:-1008px -168px}.c-icon-chevron-right{background-position:-1032px -168px}.c-icon-circle-gray-s{background-position:-1056px -168px}.c-icon-v,.c-icon-v-noborder{background-position:0 -192px}.c-icon-hui{background-position:-24px -192px}.c-icon-bao{background-position:-48px -192px}.c-icon-phone{background-position:-72px -192px}.c-icon-qa-empty{background-position:-96px -192px}.c-icon-safeguard{background-position:-120px -192px}.c-icon-register-empty{background-position:-144px -192px}.c-icon-zan{background-position:-168px -192px}.c-icon-music{background-position:-192px -192px}.c-icon-music-gray{background-position:-216px -192px}.c-icon-location{background-position:-240px -192px}.c-icon-warning{background-position:-264px -192px}.c-icon-doc{background-position:-288px -192px}.c-icon-xls{background-position:-312px -192px}.c-icon-ppt{background-position:-336px -192px}.c-icon-pdf{background-position:-360px -192px}.c-icon-txt{background-position:-384px -192px}.c-icon-play-black{background-position:-408px -192px}.c-icon-play-black:hover{background-position:-432px -192px}.c-icon-gift{background-position:-456px -192px}.c-icon-baidu-share{background-position:-480px -192px}.c-icon-bear{background-position:-504px -192px}.c-icon-bear-border{background-position:-576px -192px}.c-icon-person,.c-icon-person-noborder{background-position:-600px -192px}.c-icon-location-blue{background-position:-624px -192px}.c-icon-hotAirBall{background-position:-648px -192px}.c-icon-moon{background-position:-672px -192px}.c-icon-streetMap{background-position:-696px -192px}.c-icon-high-v,.c-icon-high-v-noborder{background-position:-720px -192px}.c-icon-nuo{background-position:-744px -192px}.c-icon-mv{background-position:-768px -192px}.c-icon-med{background-position:-816px -192px}.c-icon-air{background-position:-840px -192px}.c-icon-share2{background-position:-864px -192px}.c-icon-v1,.c-icon-v1-noborder{background-position:-888px -192px}.c-icon-v2,.c-icon-v2-noborder{background-position:-912px -192px}.c-icon-v3,.c-icon-v3-noborder{background-position:-936px -192px}.c-icon-v1-noborder-disable{background-position:-960px -192px}.c-icon-v2-noborder-disable{background-position:-984px -192px}.c-icon-v3-noborder-disable{background-position:-1008px -192px}.c-icon-write{background-position:-1032px -192px}.c-icon-zhidao-s{background-position:-1056px -192px}.c-icon-shopping{background-position:-1080px -192px}.c-icon-bear-circle{background-position:0 -216px}.c-icon-warning-circle{background-position:-24px -216px}.c-icon-warning-triangle{width:24px;background-position:-48px -216px}.c-icon-warning-circle-gray{background-position:-72px -216px}.c-icon-ball-red{background-position:0 -240px}.c-icon-ball-blue{background-position:-48px -240px}.c-icon-tieba{background-position:0 -288px}.c-icon-zhidao{background-position:-48px -288px}.c-icon-bear-p{background-position:-96px -288px}.c-icon-bear-pn{background-position:-144px -288px}.c-icon-download{background-position:0 -336px}.c-icon-lyric{background-position:-24px -336px}.c-icon-play-circle{background-position:-48px -336px}.c-icon-play-circle:hover{background-position:-72px -336px}.c-icon-stop-circle{background-position:-96px -336px}.c-icon-stop-circle:hover{background-position:-120px -336px}.c-icon-play-circle-middle{background-position:0 -360px}.c-icon-play-circle-middle:hover{background-position:-48px -360px}.c-icon-stop-circle-middle{background-position:-96px -360px}.c-icon-stop-circle-middle:hover{background-position:-144px -360px}.c-icon-play-black-large{background-position:0 -408px}.c-icon-play-black-large:hover{background-position:-48px -408px}.c-icon-stop-black-large{background-position:-96px -408px}.c-icon-stop-black-large:hover{background-position:-144px -408px}.c-icon-play-black-larger{background-position:0 -456px}.c-icon-play-black-larger:hover{background-position:-72px -456px}.c-icon-stop-black-larger{background-position:-144px -456px}.c-icon-stop-black-larger:hover{background-position:-216px -456px}.c-recommend{font-size:0;padding:5px 0;border:1px solid #f3f3f3;border-left:none;border-right:0}.c-recommend .c-icon{margin-bottom:-4px}.c-recommend .c-gray,.c-recommend a{font-size:13px}.c-recommend-notopline{padding-top:0;border-top:0}.c-recommend-vline{display:inline-block;margin:0 10px -2px;border-left:1px solid #d8d8d8;width:0;height:12px;_vertical-align:middle;_overflow:hidden}.c-text{display:inline-block;padding:2px;text-align:center;vertical-align:text-bottom;font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;overflow:hidden}a.c-text{text-decoration:none}.c-text-new{background-color:#f13f40}.c-text-info{padding-left:0;padding-right:0;font-weight:bold;color:#2b99ff;*vertical-align:baseline;_position:relative;_top:2px}.c-text-info b{_position:relative;_top:-1px}.c-text-info span{padding:0 2px;font-weight:normal}.c-text-important{background-color:#1cb7fd}.c-text-public{background-color:#2b99ff}.c-text-warning{background-color:#ff830f}.c-text-prompt{background-color:#f5c537}.c-text-danger{background-color:#f13f40}.c-text-safe{background-color:#52c277}.c-text-empty{padding-top:1px;padding-bottom:1px;border:1px solid #d8d8d8;cursor:pointer;color:#23b9fd;background-color:#fff}.c-text-empty:hover{border-color:#388bff}.c-text-empty:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}.c-text-mult{padding-left:5px;padding-right:5px}.c-text-gray{background-color:#666}.c-btn,.c-btn:visited{color:#333!important}.c-btn{display:inline-block;padding:0 14px;margin:0;height:24px;line-height:25px;font-size:13px;filter:chroma(color=#000000);*zoom:1;border:1px solid #d8d8d8;cursor:pointer;font-family:inherit;font-weight:normal;text-align:center;vertical-align:middle;background-color:#f9f9f9;overflow:hidden;outline:0}.c-btn:hover{border-color:#388bff}.c-btn:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}a.c-btn{text-decoration:none}button.c-btn{height:26px;_line-height:18px;*overflow:visible}button.c-btn::-moz-focus-inner{padding:0;border:0}.c-btn .c-icon{margin-top:5px}.c-btn-disable{color:#999!important}.c-btn-disable:visited{color:#999!important}.c-btn-disable:hover{border:1px solid #d8d8d8;cursor:default}.c-btn-disable:active{border-color:#d8d8d8;background-color:#f9f9f9;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;-o-box-shadow:none}.c-btn-mini{padding-left:5px;padding-right:5px;height:18px;line-height:18px;font-size:12px}button.c-btn-mini{height:20px;_height:18px;_line-height:14px}.c-btn-mini .c-icon{margin-top:2px}.c-btn-large{height:28px;line-height:28px;font-size:14px;font-family:\"\u5fae\u8f6f\u96c5\u9ed1\",\"\u9ed1\u4f53\"}button.c-btn-large{height:30px;_line-height:24px}.c-btn-large .c-icon{margin-top:7px;_margin-top:6px}.c-btn-primary,.c-btn-primary:visited{color:#fff!important}.c-btn-primary{background-color:#388bff;border-color:#3c8dff #408ffe #3680e6}.c-btn-primary:hover{border-color:#2678ec #2575e7 #1c6fe2 #2677e7;background-color:#388bff;background-image:url(data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAMAAACuX0YVAAAABlBMVEVnpv85i\/9PO5r4AAAAD0lEQVR42gEEAPv\/AAAAAQAFAAIros7PAAAAAElFTkSuQmCC);*background-image:none;background-repeat:repeat-x;box-shadow:1px 1px 1px rgba(0,0,0,0.4);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.4);-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.4);-o-box-shadow:1px 1px 1px rgba(0,0,0,0.4)}.c-btn-primary:active{border-color:#178ee3 #1784d0 #177bbf #1780ca;background-color:#388bff;background-image:none;box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-o-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15)}.c-btn .c-icon{float:left}.c-dropdown2{position:relative;display:inline-block;width:100%;height:26px;line-height:26px;font-size:13px;vertical-align:middle;outline:0;_font-family:SimSun;background-color:#fff;word-wrap:normal;word-break:normal}.c-dropdown2 .c-dropdown2-btn-group{position:relative;height:24px;border:1px solid #999;border-bottom-color:#d8d8d8;border-right-color:#d8d8d8;-moz-user-select:none;-webkit-user-select:none;user-select:none}.c-dropdown2:hover .c-dropdown2-btn-group,.c-dropdown2-hover .c-dropdown2-btn-group{box-shadow:inset 1px 1px 0 0 #d8d8d8;-webkit-box-shadow:inset 1px 1px 0 0 #d8d8d8;-moz-box-shadow:inset 1px 1px 0 0 #d8d8d8;-o-box-shadow:inset 1px 1px 0 0 #d8d8d8}.c-dropdown2:hover .c-dropdown2-btn-icon,.c-dropdown2-hover .c-dropdown2-btn-icon{box-shadow:inset 0 1px 0 0 #d8d8d8;-webkit-box-shadow:inset 0 1px 0 0 #d8d8d8;-moz-box-shadow:inset 0 1px 0 0 #d8d8d8;-o-box-shadow:inset 0 1px 0 0 #d8d8d8}.c-dropdown2:hover .c-dropdown2-btn-icon-border,.c-dropdown2-hover .c-dropdown2-btn-icon-border{background-color:#f2f2f2}.c-dropdown2 .c-dropdown2-btn{height:24px;padding-left:10px;padding-right:10px;cursor:default;overflow:hidden;white-space:nowrap}.c-dropdown2 .c-dropdown2-btn-icon{position:absolute;top:0;right:0;width:23px;height:24px;line-height:24px;background-color:#fff;padding:0 1px 0 10px}.c-dropdown2 .c-dropdown2-btn-icon-border{height:24px;width:23px;border-left:1px solid #d9d9d9;text-align:center;zoom:1}.c-dropdown2 .c-icon-triangle-down{*margin-top:5px;_margin-left:2px}.c-dropdown2 .c-dropdown2-menu{position:absolute;left:0;top:100%;_margin-top:0;width:100%;overflow:hidden;border:1px solid #bbb;background:#fff;visibility:hidden}.c-dropdown2 .c-dropdown2-menu-inner{overflow:hidden}.c-dropdown2 .c-dropdown2-option{background-color:#fff;cursor:pointer}.c-dropdown2 .c-dropdown2-selected{background-color:#f5f5f5}.c-dropdown2-common ul,.c-dropdown2-common li{margin:0;padding:0;list-style:none}.c-dropdown2-common .c-dropdown2-option{height:26px;line-height:26px;font-size:12px;color:#333;white-space:nowrap;cursor:pointer;padding-left:10px}.c-dropdown2-common .c-dropdown2-selected{background-color:#f5f5f5}.c-dropdown2-common .c-dropdown2-menu-group .c-dropdown2-group{padding-left:10px;font-weight:bold;cursor:default}.c-dropdown2-common .c-dropdown2-menu-group .c-dropdown2-option{padding-left:20px}.c-img{display:block;min-height:1px;border:none 0}.c-img3{width:52px}.c-img4{width:75px}.c-img6{width:121px}.c-img7{width:144px}.c-img12{width:259px}.c-img15{width:328px}.c-img18{width:397px}.c-border .c-img3{width:56px}.c-border .c-img4{width:78px}.c-border .c-img7{width:144px}.c-border .c-img12{width:254px}.c-border .c-img15{width:320px}.c-border .c-img18{width:386px}.c-index{display:inline-block;padding:1px 0;color:#fff;width:14px;line-height:100%;font-size:12px;text-align:center;background-color:#8eb9f5}.c-index-hot,.c-index-hot1{background-color:#f54545}.c-index-hot2{background-color:#ff8547}.c-index-hot3{background-color:#ffac38}.c-input{display:inline-block;padding:0 4px;height:24px;line-height:24px\\9;font-size:13px;border:1px solid #999;border-bottom-color:#d8d8d8;border-right-color:#d8d8d8;outline:0;box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;vertical-align:top;overflow:hidden}.c-input:hover{box-shadow:inset 1px 1px 1px 0 #d8d8d8;-webkit-box-shadow:inset 1px 1px 1px 0 #d8d8d8;-moz-box-shadow:inset 1px 1px 1px 0 #d8d8d8;-o-box-shadow:inset 1px 1px 1px 0 #d8d8d8}.c-input .c-icon{float:right;margin-top:6px}.c-input .c-icon-left{float:left;margin-right:4px}.c-input input{float:left;height:22px;*padding-top:4px;margin-top:2px;font-size:13px;border:0;outline:0}.c-input{width:180px}.c-input input{width:162px}.c-input-xmini{width:65px}.c-input-xmini input{width:47px}.c-input-mini{width:88px}.c-input-mini input{width:70px}.c-input-small{width:157px}.c-input-small input{width:139px}.c-input-large{width:203px}.c-input-large input{width:185px}.c-input-xlarge{width:341px}.c-input-xlarge input{width:323px}.c-input12{width:249px}.c-input12 input{width:231px}.c-input20{width:433px}.c-input20 input{width:415px}.c-border .c-input{width:178px}.c-border .c-input input{width:160px}.c-border .c-input-xmini{width:68px}.c-border .c-input-xmini input{width:50px}.c-border .c-input-mini{width:90px}.c-border .c-input-mini input{width:72px}.c-border .c-input-small{width:156px}.c-border .c-input-small input{width:138px}.c-border .c-input-large{width:200px}.c-border .c-input-large input{width:182px}.c-border .c-input-xlarge{width:332px}.c-border .c-input-xlarge input{width:314px}.c-border .c-input12{width:244px}.c-border .c-input12 input{width:226px}.c-border .c-input20{width:420px}.c-border .c-input20 input{width:402px}.c-numberset{*zoom:1}.c-numberset:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-numberset li{float:left;margin-right:17px;list-style:none}.c-numberset .c-numberset-last{margin-right:0}.c-numberset a{display:block;width:50px;text-decoration:none;text-align:center;border:1px solid #d8d8d8;cursor:pointer}.c-numberset a:hover{border-color:#388bff}.c-border .c-numberset li{margin-right:10px}.c-border .c-numberset .c-numberset-last{margin-right:0}.c-border .c-numberset a{width:54px}.c-table{width:100%;border-collapse:collapse;border-spacing:0}.c-table th,.c-table td{padding-left:10px;line-height:1.54;font-size:13px;border-bottom:1px solid #f3f3f3;text-align:left}.cr-content .c-table th:first-child,.cr-content .c-table td:first-child{padding-left:0}.c-table th{padding-top:4px;padding-bottom:4px;font-weight:normal;color:#666;border-color:#f0f0f0;white-space:nowrap;background-color:#fafafa}.c-table td{padding-top:6.5px;padding-bottom:6.5px}.c-table-hasimg td{padding-top:10px;padding-bottom:10px}.c-table a,.c-table em{text-decoration:none}.c-table a:hover,.c-table a:hover em{text-decoration:underline}.c-table a.c-icon:hover{text-decoration:none}.c-table .c-btn:hover,.c-table .c-btn:hover em{text-decoration:none}.c-table-nohihead th{background-color:transparent}.c-table-noborder td{border-bottom:0}.c-tabs-nav-movetop{margin:-10px -9px 0 -10px;position:relative}.c-tabs-nav{border-bottom:1px solid #d9d9d9;background-color:#fafafa;line-height:1.54;font-size:0;*zoom:1;_overflow-x:hidden;_position:relative}.c-tabs-nav:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-tabs-nav .c-tabs-nav-btn{float:right;_position:absolute;_top:0;_right:0;_z-index:1;background:#fafafa}.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-prev,.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-next{float:left;padding:6px 2px;cursor:pointer}.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-disable{cursor:default}.c-tabs-nav .c-tabs-nav-view{_position:relative;overflow:hidden;*zoom:1;margin-bottom:-1px}.c-tabs-nav .c-tabs-nav-view .c-tabs-nav-li{margin-bottom:0}.c-tabs-nav .c-tabs-nav-more{float:left;white-space:nowrap}.c-tabs-nav li,.c-tabs-nav a{color:#666;font-size:13px;*zoom:1}.c-tabs-nav li{display:inline-block;margin-bottom:-1px;*display:inline;padding:3px 15px;vertical-align:bottom;border-style:solid;border-width:2px 1px 0 1px;border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347);list-style:none;cursor:pointer;white-space:nowrap;overflow:hidden}.c-tabs-nav a{text-decoration:none}.c-tabs-nav .c-tabs-nav-sep{height:16px;width:0;padding:0;margin-bottom:4px;border-style:solid;border-width:0 1px 0;border-color:transparent #fff transparent #dedede}.c-tabs-nav .c-tabs-nav-selected{_position:relative;border-color:#2c99ff #e4e4e4 #fff #dedede;background-color:#fff;color:#000;cursor:default}.c-tabs-nav-one .c-tabs-nav-selected{border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347);background-color:transparent;color:#666}.c-tabs .c-tabs .c-tabs-nav{padding:10px 0 5px;border:none 0;background-color:#fff}.c-tabs .c-tabs .c-tabs-nav li,.c-tabs .c-tabs .c-tabs-nav a{color:#00c}.c-tabs .c-tabs .c-tabs-nav li{padding:0 5px;position:static;margin:0 10px;border:none 0;cursor:pointer;white-space:nowrap}.c-tabs .c-tabs .c-tabs-nav .c-tabs-nav-sep{height:11px;width:0;padding:0;margin:0 0 4px 0;border:none 0;border-left:1px solid #d8d8d8}.c-tabs .c-tabs .c-tabs-nav .c-tabs-nav-selected{background-color:#2c99ff;color:#fff;cursor:default}.c-tag{padding-top:3px;margin-bottom:3px;height:1.7em;font-size:13px;line-height:1.4em;transition:height .3s ease-in;-webkit-transition:height .3s ease-in;-moz-transition:height .3s ease-in;-ms-transition:height .3s ease-in;-o-transition:height .3s ease-in;*zoom:1;overflow:hidden}.c-tag:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-tag-cont{overflow:hidden;*zoom:1}.c-tag-type,.c-tag-li,.c-tag-more,.c-tag-cont span{margin:2px 0}.c-tag-type,.c-tag-li,.c-tag-cont span{float:left}.c-tag-type,.c-tag-more{color:#666}.c-tag-li,.c-tag-cont span{padding:0 4px;display:inline-block;margin-right:12px;white-space:nowrap;cursor:pointer;color:#00c}.c-tag .c-tag-selected{background:#388bff;color:#fff}.c-tag-more{float:right;background:#fff;cursor:pointer;*height:18px}.c-tool{display:inline-block;width:56px;height:56px;background:url(\"\/\/www.baidu.com\/aladdin\/img\/tools\/tools-5.png\") no-repeat}.c-tool-region{background-position:0 0}.c-tool-calendar{background-position:-72px 0}.c-tool-city{background-position:-144px 0}.c-tool-phone-pos{background-position:-216px 0}.c-tool-other{background-position:-288px 0}.c-tool-midnight{background-position:-360px 0}.c-tool-kefu{width:121px;background-position:-432px 0}.c-tool-phone{background-position:-576px 0}.c-tool-car{background-position:-648px 0}.c-tool-station{background-position:0 -72px}.c-tool-cheat{background-position:-72px -72px}.c-tool-counter{background-position:-144px -72px}.c-tool-time{background-position:-216px -72px}.c-tool-zip{background-position:-288px -72px}.c-tool-warning{background-position:-360px -72px}.c-tool-ip{background-position:0 -144px}.c-tool-unit{background-position:-72px -144px}.c-tool-rate{background-position:-144px -144px}.c-tool-conversion{background-position:-288px -144px}.c-tool-ads{background-position:-360px -144px}<\/style>";result_common_css=$(result_common_css);result_common_css.attr("data-for","result");var index_css= $('head [index]');var wrapper=$("#wrapper");window.index_on=function(){index_css.insertAfter("meta:eq(0)");result_common_css.remove();wrapper.show();if(bds.su&&bds.su.U&&bds.su.U.homeInit){bds.su.U.homeInit();}};window.index_off=function(){result_common_css.insertAfter("meta:eq(0)");wrapper.show();index_css.remove();};})();</script> -<script type="text/javascript">var Cookie={set:function(c,e,d,f,a,b){document.cookie=c+"="+(b?e:escape(e))+((a)?"; expires="+a.toGMTString():"")+((f)?"; path="+f:"; path=/")+((d)?"; domain="+d:"")},get:function(c,b){var a=document.cookie.match(new RegExp("(^| )"+c+"=([^;]*)(;|$)"));if(a!=null){return unescape(a[2])}return b},clear:function(a,c,b){if(this.get(a)){document.cookie=a+"="+((c)?"; path="+c:"; path=/")+((b)?"; domain="+b:"")+";expires=Fri, 02-Jan-1970 00:00:00 GMT"}}};(function(){var defaultOptions={sugSet:1,sugStoreSet:1,isSwitch:1,isJumpHttps:1,imeSwitch:0,resultNum:10,skinOpen:1,resultLang:0},options={},tmpName;var expire30y=new Date();expire30y.setTime(expire30y.getTime()+30*365*86400000);try{if(bds&&bds.comm&&bds.comm.personalData){if(typeof bds.comm.personalData=="string"){bds.comm.personalData=eval("("+bds.comm.personalData+")")}if(!bds.comm.personalData){return}for(tmpName in bds.comm.personalData){if(defaultOptions.hasOwnProperty(tmpName)&&bds.comm.personalData.hasOwnProperty(tmpName)){if(bds.comm.personalData[tmpName].ErrMsg=="SUCCESS"){options[tmpName]=bds.comm.personalData[tmpName].value -}}}}try{if(!parseInt(options.resultNum)){delete (options.resultNum)}if(!parseInt(options.resultLang)&&options.resultLang!="0"){delete (options.resultLang)}}catch(e){}writeCookie();if(!("sugSet" in options)){options.sugSet=(Cookie.get("sug",3)!=3?0:1)}if(!("sugStoreSet" in options)){options.sugStoreSet=Cookie.get("sugstore",0)}var BAIDUID=Cookie.get("BAIDUID");if(!("resultNum" in options)){if(/NR=(\d+)/.test(BAIDUID)){options.resultNum=RegExp.$1?parseInt(RegExp.$1):10}else{options.resultNum=10}}if(!("resultLang" in options)){if(/SL=(\d+)/.test(BAIDUID)){options.resultLang=RegExp.$1?parseInt(RegExp.$1):0}else{options.resultLang=0}}if(!("isSwitch" in options)){options.isSwitch=(Cookie.get("ORIGIN",0)==2?0:(Cookie.get("ORIGIN",0)==1?2:1))}if(!("imeSwitch" in options)){options.imeSwitch=Cookie.get("bdime",0)}}catch(e){}function save(callback){var optionsStr=[];for(tmpName in options){if(options.hasOwnProperty(tmpName)){optionsStr.push('"'+tmpName+'":"'+options[tmpName]+'"')}}var str="{"+optionsStr.join(",")+"}"; -if(bds.comm.personalData){$.ajax({url:"//www.baidu.com/ups/submit/addtips/?product=ps&tips="+encodeURIComponent(str)+"&_r="+new Date().getTime(),success:function(){writeCookie();if(typeof callback=="function"){callback()}}})}else{writeCookie();if(typeof callback=="function"){setTimeout(callback,0)}}}function set(optionName,value){options[optionName]=value}function get(optionName){return options[optionName]}function writeCookie(){if(options.hasOwnProperty("sugSet")){var value=options.sugSet=="0"?"0":"3";clearCookie("sug");Cookie.set("sug",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("sugStoreSet")){var value=options.sugStoreSet==0?"0":"1";clearCookie("sugstore");Cookie.set("sugstore",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("isSwitch")){var ORINGIN_MAP={0:"2",1:"0",2:"1"};var value=ORINGIN_MAP[options.isSwitch];clearCookie("ORIGIN");Cookie.set("ORIGIN",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("imeSwitch")){var value=options.imeSwitch; -clearCookie("bdime");Cookie.set("bdime",value,document.domain,"/",expire30y)}}function writeBAIDUID(){var BAIDUID=Cookie.get("BAIDUID"),NR,FG,SL;if(/FG=(\d+)/.test(BAIDUID)){FG=RegExp.$1}if(/SL=(\d+)/.test(BAIDUID)){SL=RegExp.$1}if(/NR=(\d+)/.test(BAIDUID)){NR=RegExp.$1}if(options.hasOwnProperty("resultNum")){NR=options.resultNum}if(options.hasOwnProperty("resultLang")){SL=options.resultLang}Cookie.set("BAIDUID",BAIDUID.replace(/:.*$/,"")+(typeof SL!="undefined"?":SL="+SL:"")+(typeof NR!="undefined"?":NR="+NR:"")+(typeof FG!="undefined"?":FG="+FG:""),".baidu.com","/",expire30y,true)}function clearCookie(name){Cookie.clear(name,"/");Cookie.clear(name,"/",document.domain);Cookie.clear(name,"/","."+document.domain);Cookie.clear(name,"/",".baidu.com")}function reset(callback){options=defaultOptions;save(callback)}window.UPS={writeBAIDUID:writeBAIDUID,reset:reset,get:get,set:set,save:save}})();(function(){var c=(navigator&&navigator.userAgent)?navigator.userAgent:"";var b=(document&&document.cookie)?document.cookie:""; -var a=!!(c.match(/(msie [2-8])/i)||(c.match(/windows.*safari/i)&&!c.match(/chrome/i))||c.match(/(linux.*firefox)/i)||c.match(/Chrome\/29/i)||c.match(/mac os x.*firefox/i)||b.match(/\bISSW=1/)||UPS.get("isSwitch")==0);if(bds&&bds.comm){bds.comm.supportis=!a;bds.comm.isui=true;bds.comm.did=(function(){var d="";for(var e=0;e<32;e++){d+=Math.floor(Math.random()*16).toString(16)}return d})()}window.__restart_confirm_timeout=true;window.__confirm_timeout=8000;window.__disable_is_guide=true;window.__disable_swap_to_empty=true;window.__switch_add_mask=true;if(window._async_merge){if(a||window.__disable_predict||window.__disable_preload){document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_async_popstate1_99fb5a68.js'><\/script>")}else{document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_instant_search1_39b2f307.js'><\/script>")}}else{document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_async_search_2132d328.js'><\/script>") -}if(bds.comm.newindex){$(window).on("index_off",function(){$('<div class="c-tips-container" id="c-tips-container"></div>').insertAfter("#wrapper");if(window.__sample_dynamic_tab){$("#s_tab").remove()}})}if(!c.match(/(msie 6)/i)){$(function(){setTimeout(function(){$.ajax({url:"http://s1.bdstatic.com/r/www/cache/static/baiduia/baiduia_b45d552b.js",cache:true,dataType:"script"})},0)})}$(function(){setTimeout(function(){$.ajax({url:"http://s1.bdstatic.com/r/www/cache/static/plugins/every_cookie_9643229f.js",cache:true,dataType:"script"})},0)});if(bds.comm&&bds.comm.ishome&&Cookie.get("H_PS_PSSID")){bds.comm.indexSid=Cookie.get("H_PS_PSSID")}})();</script><script>if(bds.comm.supportis){window.__restart_confirm_timeout=true;window.__confirm_timeout=8000;window.__disable_is_guide=true;window.__disable_swap_to_empty=true;}initPreload({'isui':true,'index_form':"#form",'index_kw':"#kw",'result_form':"#form",'result_kw':"#kw"});</script><script>if(navigator.cookieEnabled){document.cookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT";}</script></body></html><script>(function(){var C=G("lm").getElementsByTagName("A");for(var B=0,A=C.length;B<A;B++){var D=C[B];addEV(D,"mousedown",(function(E,F){return function(){ns_c({fm:"behs",tab:"bdlnk",p1:F+1,title:E.innerHTML,url:E.href})}})(D,B))}})();</script> -‰PNG - -��� IHDR�������µÊ -��7&IDATxÚíœåýÿåúq½Al•¨¨Ñ¨üþjˆ5Á؃ - ±ÄFb‰å‚% -Š&ji‚’(&P‘"îhW¹ÎÝÞííîm¿Ûß÷Ùß3üÇeËÌì´ÝûÌëõ~qÜíÎÎÌ>ó|ßó}ÚQ@à(�����-ÁE�����„������������� ����€p�����@8�����á�����€p�����Â���������„��������@8����� ����€p�����@8�����á�����„�����Â�������� ���������@8����� ����€p�����Â�����á�����„������������� ���������@8�����á�����€p�����Â���������„������������� ����€p�����@8�����á�����„�����Â���������„��������@8����� ����€p�����Â�����áEÚQGE…���€Yâ„Â@Báv»Oîëë«èïï_Mÿo#¼D7±•~ÿ–Ï组~NÁµ�Âá€p� Ç3Š$c)ý܈±Ñëv‘xü× �„€Ôr>¨¯¯o*ýì -ÈÜè}³ëëê²p€p@8 �D¤ª²2ƒ¤á½@[ÿ×ÝÝÝ…¸ž�@8 �Ž`ÍêÕi$ ÿ¨°Ñ~¾jkkËÑùòˆã8ùøN„Âá�À„Í(>Ÿï•€Š›ßï‡íWÃãΠϸ‰äf1ýÜæZØßè57ÐÏiøž„Âá�À`Ùðx<74Ø\.×ÍjKÇ–Í›Óûúú›eJ‰ÇÍÓ**0š@8 �ŒšêêòþþþCZÛïÞ={JÔ’£ShŸ[ã8ž‡c(¾{�á€p@8�зL§Ð“ÿë 7ŸÏ÷"ûœxňŽsýÜ£Â!5tŒÆ÷ �:e7N`NÐv³oÙ¼¹Ti–ƒËÆ„ÀÿM8¦ÖÖAÒq†Æ}L�€p@8 �°¬ƒ×ë}# ÃæñxQ’å`Bàv»/e»Ð ¹§Éb±Œ€t�„€†Ù%‹çRÐíÑC8úúúªè3SåwöZ«ÕÊ20­Ž‹ÎÿËÙ³f¥£L�„€FÙ ‡Ãqs@Ç­¹¹ù,9Â1­¢‚Í òµÖÇåóù¦"Ë �Ú”åT¯×ûžÂár¹eŸ+5»AÇwŸN‡f¯¯¯é�„�•›SFŸzj†VCa£d–Ñg§Å -ììïû÷í+¥ã³èul$7‰w$ �„€æ”û÷ -輑@´Ñg§KŽÇ3MçcëY³zu!²�Âá€p� bsJOOÏ/lë¿ùfx´L ø æÏÏ"èÐûØÇ$d9�„Âá�@¥æÖ¬ÑÛÛû„ÂÑÜÜüÿ¢õã`ßf³]kıù|¾¥rGÒ��á€p@8�ˆ,é.—k–A½««kB áH¥À¿Äˆcëïïïd}[ �Âá€p� Žpd¸ÝîÅFu«ÕúëHGÙï~ðÁlÖº0hÛ¹cÇñhV„�:Œ2áðx<ÿ1" ÷ôôÜ©ã(;¶––– n­­­?–:t�„Â@táÈ$áøĈ€ÞÝÝý@áHµZ­¿5R8:;;¯ƒp�„€JÂaT“JGGǯà ‡Ð™ÕétþÙHáhoo¿^Ê\!�@8 �$Gooïß j²¸1Šp°Î¬sŽšêêŸ@8�„Âá�@¥>]]]4" WUV^E8 ëÌ*l¼ÿþ€p@8 �¨$ÍÍÍ7ÐçÏû½p]Ô™u™Q²Ñ×××DÇ0 �*Íñ|Ù²“ 葺¨3ër£„ÃétþƒŽ!F„Âá�@á`?‡ €Î}i¤€.êÌú±QÂÑÚÚz/C„@8 �Ô)ÇL8;Ž…zôŽŽŽ©‘º $% ò ÿÜٳ٤_™˜ø @8 �Ô)Çl½¬ºÚÚñzFôU+WŽŽÐá°ÙlÓ° ·Û½‚>?WÊj¶�@8 �dt½`̘⾾>]Veõz½[¢tá˜ÚÚÚî4B8H¾nãÍ=è0 - ð°ÌÀ÷ý~ÿ5ÄÄ•ÈϦße(é8Êúqtww¿¤G@oiiy ÚaXìömÛþGoÙðù|ûFw\!šS�„Âá�™A$ãúûû? -D^ÔÌC_I¯û5öÁršU^ÿë_GÒ{Néšüë_áý7R¢IДɓKéx\z -G}}=›ý4Í)�Âá€p€‰Çã9‚ïz™ñóø{–,^œ*¥Y…ȳX,šö›èèèx:VÿÑè™Án·{¥^²áõz÷žpÌ1E CWý~?ëÐiWHITÖ:ÎØÃc³ïž2e8}^&C?h¿wLœ8T-ƒÀÿžÝÜÜ|^ÂQ¹{÷ è, - ²AOÝ·2gP!ž6÷ööþ0JVáp–cû¶mW2?P9ž÷ïÞµë:Ð3bõFª<ñøãÃúúú,ZˆÝnŸ>¯@Èn@8�„Âá�F6Ün÷å*þ.‡ÃqF”Žš©<ûPÐÚÚú”šÝb±Ìä=[J@ufÍíìì|N㦔ê{ï¾{ún�„Âœlttt|¯¿¿¿MíàJû¬ooo%«ÎoQWW×,5>“$ç““O<±LN@ k†ñûýµZÈ]ž?úè\úœ|ŒL„ ¸¹1(À¾¯Õ=ÙU³gÍJÑ´’[”—WBâ33ž&»ÝþñØ /Æšj„€.5ƒ >–oÖ­»˜ŽÛ­òu°»iÓU¢Ì æÝ�„ œì†Íf»@¥~7ŸÏ÷pŒ¦•L. %{ªªîìëëë”ÛRÑÞÞþIK)ÏÈî!:öÞ‚ýûöÝJ’àQãüÙù¬ûúëŸÑ~ ùœ hJ„ ¸ìÆg: Ê°Õ×ד(ÅÏ=ǫ́®®®·%ÌÓÑßÛÛ»bù²ec™¬ˆdCQö@Ô—ƒIAѦ¯%Yˆ«©ÉãñlY¸`ÁYl¢f4¥�„ÂNvƒ‚úè€N›×ë}5Æä[‚täðL@é½wß}bMuõï¬Vë,pÓ>jéß݇cyKKËsï.\x½®ŒóÜxd#LÓJ°oÉ´ŠŠ“º»»ç³S›Õ8xðàß+/ÂÏ'G1#áø2è\Ï$¼‰öób*ý|ñ úý¹ô÷l”a�á€p@8@Âd7(x½Ðo³ýÕWE1&àJå€lží(ä™ &å"ØÿK¹häóŒD†CLùqˆ¥#(?/Ϙ1šIŽÛíÞe4Ïårmhhhxä– ŽãÇ^ jF‰(yL*úûûWHö÷µ$"÷‘4 <„ÂL›Ý¸ÿ¾û2)¸ÒQ8½½½wEkNû4ð³yæ"Ÿn|þûÁ<+’&§ƒ¨ éËO—œò+.½ô˜U+W^ºcûö_íݳç®;vܾvÍšŸ]5nܱ\†J¸¨ˆ³.aoÍêÕi$ÒÏ -/k7½¿¢±±Y�á€p@8€ù²V«õ²€Î›ÏçûXƼ)¢ŒG 1éj‹†Dù)àòQÌÅB ˜ÿ¾€¿.;VÖÅf³±õ[¾Téòîå ê¡Œ„ÂLSžRÝn÷L½…ƒ‚k«œ<è ?”AzŒôt.;Ù<»’#b0ÿ½ C©ÑdÈb±Œ ë±Wí$’ßï¿#`�„Âá�¦hNaÁ“Ó¦€Û’Å‹Ëq”Fˆü¤rIeZÒÄ’-èWUVæ’llÔè{軽 -Ò 0¼9åS§æ°Àd„pÔÕÖž› «£Šdœl _ ï¯ZwÐ¥íTH€p@8 ÀPáhll<7`Ðf±Xn¨Ë±3èíí=‡~îÓ¡ùjײO?ÍD™„Ö£»»û6£„£§§çÁ:­7Ÿhm™^×Úãñ<Ž,€p@8 À°þô”]a”pØíöçâÔÞì|-ËO#²Y÷ïÛW -é�„!é.—ëm£„Ãáp¼2@…#ÅãñÌÐûzÓg>‰©Ô„Âá�FG ÇB£„ƒ>{6ŸŸbÐ�»îl‚¯]z_ïþþþúKÆŽÅÊ´�Âá€p�}Ÿ²¹pÌ6p¤ ¤ë¾sÇŽ£unN9¼uttüY�á€p@8€îÂa³Ùf%¼IESáp:#ü~ÿ¤¾¾¾7øÚ${ˆb?±‘~÷oú÷y6_ý;XëÞÓÓcXG]·Ûýâ@ 0P8,ËF?’´¶ˆ Æýô³Ü Íœô¾|>ßµlN! ú‹QלÎmí@ 0°GMuõÏŒ -~$;ª)mmm9$ OÐÏ=*ôwøŠ‚ó-:êÒ~—uÍù”ò�á€p@8€®£T^š>}h òëšn¼VàÇgìœ@?·¨ŸYSÌ¡C‡rÕÌ*Ñ>+Æm¾ ÆŒÉF?�á€p@8€®£%Øbc^¯w›‘oý7ßœï°XÞ|¢éH¶°šÇã9U%áȤýY ŽÀû‹ A?�á€p@8€že‰-0–mµZ_0 µß5¬¬,7žþ6›ídÚÏ~Ùêóù.GŽ¸pd•Q‚p�„ÂŒì8š¹qÆóõz.—ë¿|÷4%Ù™ÞÞÞ³éç›­¾zRé`Aþ±G)¼-Y¼x(„#±ñx<£©,Þ(¯×{>„Âá�†w%ò¨Óu‰úÖÖÖ{ÙÓ¾ÜÀÇŽÙf³D?2(^{|>ßJ¤ƒ+Ë.-߬[7‘Ø÷m__Ÿ¬¬$½~‘…!�bõã\_W7IÇæçóÏ>;œeWäv^looBï¯68f÷²•^åVà,È_wõÕyF šTþžM¥„ér¾s¿ßÿ>oBá€p@8€‘Í*Y'sL‘×ëÝ£GÀ³Ùll†Ñ\¹F'ŒŸJ²ñyÀGÓ¡C‡†Ê9~¡ÏŒÑÇ>ëÍ7Ë!‰ýàt:_’•–óx>ÔcÝ"G’ ‡Ïç»Ì¤\HÇËzö磢P•‘rÚnè}¥Q*0VåîÚ¹óµãÝ… G±À+牋½Ž„螀‰6&?L‚ä -½Ïnàaû„k{).†U·öôôü”b‰œ/Ýív/ÖcGò -Ç ^Y'ÂÖMléëë›Gü– -ÿɨ°·ÝÞ­°“æEá‚»¢åý) -l6›¦CLÛÚÚž`}FäT~ì[[[£Ÿíf+Ø�‘!MAá ïð QÇKŸÝN8ø94° ×é±Hß+Ÿ÷å\¥#7^Ÿ@8’T8Ò¸l ›úÏdê£ ’S©)$k÷*2¾î¼(Ë‘3é¶Û†{½Þ*:>,+ÎÏ/æ/MF N¡ -~©I˱Ëb±œ*å\±£ëû­QKŸ½5T8éìïï?À&ˆäãQî—ø[q•Â -Gj¨t@8’C8‚³&A¥z®9U„çB,b·ÝÚíöß)Ì,\­ C"˲sgÏfCîUÊ.ךÛn¹åhÞwCVvÃétN0yÞ²fõê,)âÄ„ƒÎg±QÇJÂú¯ÐÑAü¸Ò!ß)¯O„“bá>´Ùl·ã*…Ž ^ž I&©|¡dÙØ4Ò§€ZÁˆœ…èéé¹_ÉÅmhh¸4ZVA4b…=ýÌž5ëtµ:‘Ò1¿;ö ‡Ñ~ó…`'1#0¨©©éh6I˜Ù / Ú±ÎIºîî:N«Õú|èè á¸èþk ` nT=®“¥pŸX,–I¸Ja…C¸¿!I(ÙIXf[|>ßÅX\*¼pP°z@ á'·L˜0‚>õéèW˜¾¯Ù½k×­´¯‘lHnJ™VQ‘F|e¢\§ÓycŒëÌJîß·Ï°óêëë¯ #Á‡Çw$ùépëü÷á¡C‡îÀU -+ÙG¢mlFÇ[ ú -‡8½.HQºjåÊË[áÔ+åaŸï—Tï>mÔ(–Õ(æD³döÛDâùd‚•[+¢ïÇÈ"¥_}å•Eýýý=z}¦ç‰ÇHá ë]Àá€p@8˜p—Çã¹Ò¡¯pˆ¤CÈt0Y("Êž6íÔÚššûéÞaâr¹Ö1¹°ÙlKÛÛÛgVUVNšúÐC'±×ò¬–þD-k¬Ûí¾2`ðš# -ƒzÄþâóŒèÇAß×güûH Ž„ÂáÈÂÁ66£ãY}…#ðÝá²™|Í“|.L$J¹Tˆ)å+⢑˳éreƒdæ –-HXSöûߎ’åÞ·{ªªÆé}\œaH,„Âá€p xá>1Ξ5+¡¯pˆ>SÈvdòÊ$—g=ò¹XðŸóøÓs6mºhˆœdÙèêê:†Íâ™èå–«ˆ<(ßãñ¬×Q‚^0fLq¸éä!Ú G___Ç·›6ݘììܱã†ýûö]‹N£Ž„ßÜn÷=Ëa„p„T.<p dpÉH‘#tŒ¬oîdqåpM‚âfª¨/an¢Svc -Âp#/  ‰^SH0Y)Oèá€p$r–£fÊäÉéY:ŒŽcä#”Añ컪²2—¾çÕÉÖ$èt:Ç„ ZBSU®´>—˵º´°°0Òê¼BÖ¥³³ó]]]¥_£ãz]¼^¯Ü…øü‡ã-¡ïì㶶¶ Q†ÅÊÉp4Òë yf0'‰ÌËt&þ‚p|g£›ü�Uð“÷îÙs—–Ô×Õ=F•Ý×jTšT \§õ:�c Ê=‡dCñðWdz›ØÁ‚=QÖ‹h  -ßÊ`#4 ’ŽCV«õøNš‡Wée3¯Úíö%Z}8]ƒ–·þö·“£-–' ×å¯)âOãZS6òØc‡ÑwsH¦<­¡÷²‘6åaú©A)„Á* -GŽ('3©¢‡„ãp½A‡4ŸP±”/ýøã éÉaY<'“yÁ)¡¢û×?ÿyìÆ ~†ª®øüóËcÁ^Ç^ÿòŒåfŽxeƒm¿ýÍo¾/ -B¡°ßa#k ÌÐínoo)È=thYggçëÈF=Ý{çÅšpM$@Y<8æé@ÁžªªkåžS}}ý=|¨µÐwH "Ž¬R(Ù!Á8,ôÚ¹ô–šhˆ³‰j"q¦ ŸÅÛ a…£ßø¹’Ç+VA”Õ×ÕÝO•¯[a¥Ý¨ÇòÊ&a¨ª0b¤XE¢y0RÍtýººº -è{]o`ýÃÔ©Çóó, CpdMOOÏ|ƒ›·°>*ð£€Ø÷S²mëÖ_’XשҖÓÛ»lZEÅIüþË–0ˬÐ98]Ô'GK²].×;2¯¡sêCàBÒH-2¢¬R(YÑ–„ëOç÷ßXûÓâfŸ-e%f6õ}¬Ï‡p@8Âe Ö‹,>]C2DOM¬â+9°ÿ”€Â™+kª«O¨Í*¢ Î¯é`‰d‹Ò¹¦¹vTaeAXà:ãÅæ皆à\"‡c® ú"}Ãúª¯Ôˤ£ø²‹/^}àÀ=ôP°YÉGP_ÏÄ…g DM)øúè¨I*I"ËlYd6«þKÔ11UãcŒ:y›‘æóù–IŽt5ïc¡ JY£‰ GÔχp@8" G–”4_œˆG6®TéiSÑèW¡Yåð5•Û¶šb–ì†ÕjI•×~µùìY³†…ŒIl* 'þ9&é�½ª±±1;B¦ã°˜³Œ ×ÙDkoR°]ÉVñeÍ$ĺY¿ú­ÛíÞL÷Ó‡ ¾»páy¼©´˜gÁ²ÕPj=Qwww_-÷Úѵ¸YÜ<adÓ¦ÊÂl^#É\.A825Ik4ñsÉ„p@8”G¦^QhúxÞœ9§)9n -T¿ad  -G„§Ñ˜˜é˜)pžG?·ªÄß_´hH¤ -]¨ÌÍ"\:þ]}à@f”ìU.ЉÖÄýRÄýTÊDCóC:)¦˜°ì¦Rô®ÌkÖuíUW•êYoé,™…#[͇.9Ñ%ž „Âa¬p„I° qä·Íf{Ô¬#-€¤µQ.§ŸjðD@?#ƒDAa†Wq_¨‚0}T„Γ¹¢¡‰éfë¯#>Ï7ßx#WîZ2tï/ˆ6ÒÆì±iãÆ’@òo á:ŽB8 ëxRnVöFÁGvJÝn·?#¥Â¡'…Ñ~¿ÿFb}ÎeQ¸ˆ®Å9Qø!íï„”E!h–…aÇD•Ø£rq:#Œ¬¤Ù÷Áú+kQË%¢ppéøTܼ¦EZ˜‰ÖBû¨ˆ;:¦©ÑtFßÕ$*3¿Ñ*¿Sˆ™r¯•Ãá˜×ÓÓs/{¿VÇÆ ÊÕ@8²—,^\œì¶!îT -á€p.ÑZì÷*ŽŠXÂÁ‡x½`ð½ç"¶ÐqÌ£Êûfz:+Q+pKéMö€\®‹Œx2³f ±%ªpðJz׉35L§É¸›Ï„Ï -$ð:6ñnÝÝÝÇŪ_ÇಠÅáN¥‡™„#‹µÉ*èÃñX¸é†C›m<Ït“Ý‹~:ßå$×ÐÏ©qƒT§ÓyŸÂŠt¬ÞßwUeeU¸Õúâ&²pðŠzmGGGžš;x©+ 'Äè©t⯜d¿vâN¥‡i„cÓÆÇ+9îÖÖÖI„#‚òK&¾/+I<®“û4*œ›”áká6zŠ¾XÏv}úŽ¦@ºA šèÂÁ¥c£Íf+5¸n ^+¹ý+’i#I>QÂVGäsÅâms ‡ÃáxXÉq×TW_­I…W´ÿ— ýø1ÉC™Lá0ýÔælÿ.—k,ýÜ®×µLáàeb/›ÝÀºEÈ>Xá ‡¡“´º®6„¡cÊ–õÖV¸üxß´ŠŠò‘’(ÂÁ·F:Ö3’E8xçлXSáÚø„uP¢Ae©{îìÙI!\:IDO3¨¿Í€Žu_}r´¡÷q -GR_W„ÃTÂQ}à@>¤uŠ¢ÏWÅ;_¥%‘p°­'ÜŠ¢‰&¼³î3q[=áÀfÊœ0~üñÂ:(QfÓÌJáà›Åår] ·t@8´ºÏQ9\i•ZªÛc쫧¥¥åY-²Ö›Z>Ò±óóšËïEôá€p'|†‹YÊXqTîéy%Ö¤7 *l;Dçw¢”ÞñfŽi)T¾Ç“‘µ½½}:_„M˜ÄJX&¼2ψT–£ ]óbUÄX^“y.íR+yöÚ(»r±¡ÄzJ„C3á,Z©$Ì -µÁ ܨŒ®ˆ¶/*M¢‰ÞT]¹—ê‡Gb ÿüH+õóùbÐiÂqd¶€n˜qn·ûòóTÄÐŸÓ ÷U`[ã­vîØq‰`ÏI(ÁŽ–}úif¢ —7•ž7[dìÙiÓNå_QÈ$VÙÖG ƒ"5VÖ+œpìÚ¹ó–•wÙ¼9sÎ’)óU‚B0È°×Æ*t=¦—t@84a=£l”CW§ .pér¹>—°/áQuåÞÖÖÖ©…£˜O8z¹âE!Ž„ÝxsJ^´'ÙD~žÇZ4ÊLÂÏœ'Ô<õuuòà+¬h+ž)3-dM”p¤Äšè*špìß·o¯ì#VÄï/Z4ZpÄ - -ÁÕ~%‡hæŠg%5‹pÐ}ö•Çw¶þŒÁÂ!”éŒ0+Ô§³§ÀÏ$ì+—¿^­U{ƒ3Úvtt<$ñ\òDºÊnšhN„#17 -–“yê<MJpéééy‚-r¥'TIÛÕèÏQS]]mYl³G<“±¶ào7mºž§—ó¹hd¨5S¦Tá k2žWž‘*㬕+VŒ’)•<(dƨäsÙke\³¯)À1“pPp¾:BzÝl”K•;„C¼Pf¸•iƒ JqA­63,ËC2ä)-Ò -»˜Ú‘Ð[¦û„cŽ)ŠµhP dêtžú+ YäJ+†Œ:é¤áDob¨qŒÒ ó}:\ÇLÂÁ‡¾^¤ä<)˜y·mÝú Q›o–¢!E8ZZZn²f*âô5«WŸ¢@8b…4>Ûn¥ÌËWÏF°˜E8¶lÞ|e„ôº™(“MÒR8q.Þ&e_JîåEÿ{í{·Jç‚ÅÛ ‰¹QÅ×»ìÓOÏ—ºh“¨2Ï-xU¨E<€;„½òòËgØl¶)<çºKÆŽ=B Ì"ìýmmmåtœ-JŽƒ‚üùõ²�©Õ%цY§±�¤@8¤ô5ÊR l;ĆRk$g²„cïž=WˆšÁ2LJ–œl’™…ƒ¾—ή®®[èu7ñµ¢â†Dl"ë?¦â¹@8  ¹ù÷TUÝ*ö(Q8RBÚJ³t"›Ñ|!»ÒÔÔô«'äžxccãèЀe"áH¡ŠêC%Çàr¹Våå•ð딡Ç̧I(,ðÔ···1Z8êjk/eˆÌŠ¬l’™…Ãè ÂáHVáðÖÖÔLáOƒåÊ0 ^¥êˆ°¬x¥’ÎÎÎ7äž¼ÝnŸzS›A8Ø{Nçu -ƒ¤ûã>:[4t.¦l¸Ý{‚x;ôºW•vMTáà×sõìY³Ò½f¯UA8³ *TÊ^ïZ„#¹Ò~Ó†õë¯â²‘kdŠÉ¾q†%جóÆk¯"÷Pp|2´"7Z8ØûÌŸÏ‚Qµ’Ï·Z­oIÍV9Ž¡TQ/`ñ[Ê®£õÿHVáàŸ5Uå¶GÄ­££cª„² á€p$Æær¹ÖÞ1qâq¢6þ ­:ê ©üæ,»†‚Ýn*4šA8Ün÷ï”ÆÆw.< dÔµp¨ \± ŽRfŸMFá`E…ÎáGA8 ‘Σí‘ßÿ~h¬ #!ŽÄjKñz×WUV^ W¿ÆÒ‘®d ³ {ϔɓÓé<jŠä -Þ·%3ÊŒ ƒH -ΡŸ2›zbì7™…ƒeg«•„p@8"Ücª“!¥ó>„‘ˆÕ¾–,^œ‘àßUð;’+===Osá2‹p¤Ý ôˤϾ+V_œ ãǧÒuÚ© 2ìQº–J2mžºÚÚcUî á€p„>�VoÜ°aœÔæP„#a7ªøÖPð-NpáÈJáH¥ -û¥ßã†õëÏ‹•Ý s>WaèÂÁænyQ,„ÃXᨯ¯¿¾©©é!úwªÑT8pϪ•+/+ÌÍ-çCÿó{%Eb|‚p@8R:v¨=žÖËü~ÿTÌ£ý/Ѫèþ9A–™„ƒ½þïï½—OçâPúþù¹ç†„žOh…ër¹þáP|4L?>C…!ϲ„ƒDçbÝG/šºÆÓÝn÷KtN&aÂÂB>ŸO©”pŠBfN‘05„Âqd½ÈVèÔÖ̬B…º±ª²27Þkçõzϧ}}ˆc&P=6“ G -}æÕq|w®hÓÒ “µQ`ø¡|kkk;?Þ,o3L8„Næ™<¸çš€Ѥn’g†p@8ŽØèir#½w(_jXSýÃNÞ»gÏ]‡cY<ݸï)}‚³Ùl%T‰.(˜„ ÂqT*ëiqG7Ÿ-5Je›Aßo„CùF÷ôÓñNy á0F8B¤#—I3 {É„#\*tO™ó´™–ó4]ùÎ;~é÷ûÛ”VN§óF™…_Xó£!‘*=³‡} òòQÂa‰!Áök&&åík™ -»A84úž.¡ë»2¡s½‹·A8ŽØØÐSÑràZO÷-¤ƒ3o¾ùÆg’tÔ* . ŸöYŽÄÔÞ úœ›˜_%Z¥g2á`Ù‡q‡C‚dÑg´C8âÊ�6Fë'á0^8Ø{IÞ•¬×ŽêÛ·°<=„#’pdóÊVëé¾…a¢9o¿}&݈ŠžhÝn÷ýzJ³ûÚ€ -ýG¸p³ô]5Ås>¯ÎœYE‚AŽ•IG|õýÄ[o͉§„CsáHµÙl·'ëµ£{x–h•d„ã;‘©Ç”ᢵMRy öÄ®©®ž¬0Àì6œýÞn·ÿ€~¶'êk6á k×µ¬ª¬<+V†ÃjµÎ€pÄ·mþöÛâéÇáÐ\8Òèþ˜¬×ÎårÍî'„Ãá¹Îˆ0ü«ÈãñlUrümmm§E -lA+ª07'òk"áPo<çÓÕÕõ«X}8¾úòK6‡ìN½Žÿ¿íÚ¹ót‡i…#˜éµX,“’\8„᳇qÂ�X’ŽŽE£œNçïÃU¬¬2 s»+Ño\³ [G!žóq»Ý¯Ç,$ÿ„p(ߪø!„ÃÜÂ!õ}‰¸±{ Âá0›pÍ+ÙT”^ôx<†[MuÉâÅlñ‡ºÂAq<çC•îÞH] Ã:¿:sæ‰ôÚC&ŽÔi¥rß3R8bK‡ñÂÑÞÞ~[2^7Š)ߊÖÀ‚p@8Ì!â P[Ss¥Â�¶5Ìâfl¶ÊIqÜ0H€žds†¨ Ý„“©w&²p¸Ýî¸×x à~NŒÖXyÌ[µrå…~¿¿Õ,ÂÁ¶¶û¤6÷) æϪ§pPY\@×ðÙD€ÊÔAƒ…#؇cXYY.[[ˆŽGnGl¿Íf[üŸÿû’wæÍ;±pÁ‚sãEØÕÅP({ô »®öïŸR”—W"^ Âá0“poÚºÚÚË -‡00Eœ5¡Â¿NÁîú;;;ßyì±Ãhe!SûÆ ÛWY¢®¥"F»ÝþŠ -O@oŘü+œ*xøÁO¤óœ#¥ïH<ÂÑÚÚ:>†p"T°ùÛo¯q:l®®H³ê²¹Dè<7$îáC†äèÙ¤BÁùjÑ=cfÊÙd‡&ŽT¡Œ_Í5#Hdÿ,wÉ�ÚŸ¥½½ýé ãÇçsÅC =÷x<ëÔÁ=ÍÍÍŒ#Gžxø/„Âa:áhjjR”á]’œío÷®]#Ø} w_t OòJIX7@ÍéÙMX˜à‘IOˆjô‹q<xpdŒàžÎçm ÎÙ2ñÖ[߶uë/#-0Eû{˜¤án¥ÂAOŒÇŽA!k\ƒW„Yu˹dæǺ·4šøk_´ Ö´ŽíÛ¶ «ˆæ™ö}²ÉM âNó캕¾:sæét¿/’[w±¦cª ¼câDaa5É01eÙ=*3›Ô½^úÜÙÓ**Náå½×uYá†ÄB8 fŽ´®®®)qG–H8R覕=¡{b‰l~MÔœ˜í/7Á…#c劣Ԋ~¿Eˆ½ˆU¶ k“X„¦Šøë2b4ׄªp7H¡“ó`Ñ1…›Q·P´ÐUºÞÂAey©”)´ÕŽ½{ö\Á¿« ÃîÁ©ó¼h=ñW˜2ÎÊNéê/¾¸‚¤H‰�Ô¹\®;î¿ï>aÍ“ˆ°þ¨œŒ§÷lSRÆǧï½óEhy!ó9 ÂÔæÓf8èFyKi†^\¹²éf˜*w'[6o¾’‰,ñº*l&H`ážðs•Î&È¿íøw ÌÙ’c1«ñ“•\á`›Õj½,†A"MtL‘„5EÂ9ª*‹åéXM9j kŸ¯I‘5±œÖS›‹ÊSªHdYTÌ–‚ß·wïoôï`[½ïÆi)a:Ó³ææ[è{UTÞ˜mX¿^h>‹F†(s3(€µT fŽ—gÌÈ¡@ÑpKq»½Øívû³r÷óü³ÏŽà7N\kP¨U›T8‚#Hè˜^W1ýÿ|Œ€,®”c-f•-ÀÇ6‘\Uee±„e·…cJ‰2«nŠÄ%¼UŽ=UU—Æ{OË-¯JÔ¹® 6 šE8"ˆl¦¨™¥äÚ«®:FIÿ^ž·’\üœíŸ¨Òég6p¯ÂŒd &B<Ó˜kY„ÃŒÂÁF”<£´r¥›¸6D8ÒÇËr÷óççž-¥>Ð…C|Û¶n½DÅŽì;\ÔÒÒ2X¢ôDEJ³P$áàëÖ¬^¥sTM8¨|YÏ>óÌÂxË2„CÿÕbCšY„å -ãéßÁËÄzÖÜ¢ðÞ v½dìØ£yÓe¢˜KÕC8 ¦–ò£ŠöO8–Šw»ÝkB„#C‰pГí™ZV˜I"Á€]^\œï|a*Å*ϱ:œ¨ÂÁå *CCQ8œNçÒ ‰%#ç'ÊíßñÙòå—Ò}². ñÆ;„ÎÐ!4=Ú’‡é„ƒ*Ø1T¨7Ä{cØíöׄöjA8X–»«Õ:%žy ˆpÍ*9TÉ>¢E=G•òûçF -ß:èX&³Tt" GmMÍ ñŽPp+±úw°þl¾ …ý;bnR:„ÊŒOÇá6ôMŸþ÷¿C›ššJè¿EZB7útÓÝM•Øªx²âíàÁƒ¿„I‹Å";ÓqU}²ti2ÒÎã¡F׬S»¬þµ´ÿûH>N1H8„­‘Žã%*»g›]8Ø´ógž~z‘c…Cëþá6º×¶lÚ¸ñ:Q‡P¡ŸFF¬þQGÒot£¹§UT M¡’kvŒú˜žhC8bV€ìxrÛÛÛŸÔé«n ë¶…þÝllfZú·Cáq°ï®KmØ$a¬øÅ{‘¨<¼&žáÂ^8ØèD)ý;^ž1c4ÉÂŽ8êÑ^¹B!Ž'ô¤ú¯)tƒÀ¬7ß®´g«ËÒ~ሽþÍuW_=Dí¾Ø”·¹ÿóÿ85Þù7’]8êjkÙJľDŽHý;Þ™7ï›Í6?ÞŒ±ËåZ¾dñâHí -á€p 8áر}ûâöjq¶€Pœø.5žªCŸ®åŠÙ„#ðÝU~s·oÛv¥OçØâÛ(è¼kâ3-…ƒÖzÊ~œÊø£f…äøI9 :šQ8„ϵÛí£ü~ÿlöÜ¥¢´ÚNçT¶ð¥âá€p$ÍFÜᦎ®ESSÓo“á<M*‡'QbíÉTá>oÜÆÖtyiúô‘< ž¦R°Àj±&Žúºº,6¡}'Ë -†ÇÊúœ;«È„p@8¼p°¾Ë—-ûQ¸áB;íÏö³2ºij Ú¤¿Åk‹ççÓ×R„~c¶ºÚÚ;yvCµÑfm…ÃëõžÏäA"7Ñ{Ùd{/…>÷oôù×Ññž#zïÙGRlÍÍÍDZK<÷þ}û&@8´Ž@ÈRòc/¼pXooïgÿún]]]³xçAUgÉ…ph*il²;=Ï…$à�Õ ôüL,ÞáH†&†wø­°éãÐt¿Íf[áÐL8Ä×:ŸI‡Ýnÿ [ÙXtÌ÷¾WÊG,d¨9—„#xïÝw‡i ÁuGü~ÿû:–“÷o½ùæØJÆ5ÕÕ¿£ïÔ£“p`yzGBW°ž|â‰e±*XqºÒm· gãË!ê Gà»u³xÖ©„öÿj%Ðlëïìì|½(/¯TÔ”’ªæ‘.lèt¬ ÔâŽLª“4s6ONUeåD>W1P+Y÷õ×ãØœ-:‡0]„‘P›·¹¹ùOR+XÑ“w0ÝÿÔOŒôz½»!ê Gé`ßOñ» žÓÛÛË:·õyýX¥ët:ײiš[ZZ¦íÛ»wÊ·›6Ý´âóÏ/§'ØÿygÞ¼ó ,Ã~÷ͺu×P%=‰®Ñ£‹å-‡Ãñ9•j -@>3”:ŸDJøµÎR[6 Á)â?ÑH8Xf6Ûív/ÖòøéÞ[>ý…NÍ«‘Ã?;8M:ûã ‡P6!ŽÄØèI`ë«V].·‚ ‚$ߧ›p„C›9D×;“g ‚k?°ïÎf³-¡ÀåÒúZ±©žÙwÜÞÞþòÎ;nûË+¯°õqØ¢|å|öÄR^ŽŠÃ ü­”¿‡Q~ÖèÑG¯þâ‹qMMMO’„,SkvGOÜlm‹9|챓øqj&Ž@ ¾®î¦X#JÌ(t42aæåWXÿ$“g|ų•ææ–уÜSZ5±Âá€p$‚hìØ¿oß]|ö»"Ñ#g.!²‚_Àn°ÖÖÖiz¿&#'%¯ýP:aüøã©"¼Ãb±Ìq¹\_19 ïÁ&ãɾ‡ÞSOåb;Ë:Ð~æ²U,÷îÙsת•+z×wžF,„4r?–<^ŽrDO|¡äð×äò÷ðŠ»H,"?¹è¢[·l¹‰‚Íë¼ÉΧQ�iéìì|•Ë“Dr´hFpüßF2ðUYQQA¬~1fV§‘hÏdӇ̚!êK!ž­4[hýü³Ï.¦2\á€p (áðz½ûºººÞ¦�r)âå3”T°¢uß`óæÌ9‹=-êý”šìˆ¼öC~hÀær0dÔI' ŸúÐC'1ÌŸÿ£… œ+@Oó§°ßää e*ÊE™‡P±(äå%O$Yü828“^4Ò9ü½Y¼üäð}„œOù·ß>rÓÆã[ZZž±ÙlK©¯d÷4™ØœNçJÚÏó_®];nXYÙÐxÑ‚pHßH†¿yiúôïKYq×$Âá£òöÑbkâ¬Æ³…†ÜŸBhÑcÆ gªa„C’p°5¨P[MN¢E7ö&ºQ>¢›õö”ÊÖàÁDèàT²rJœU¥‰Ö ¦ûÇ_ý±ì³Ùp1ªä¿4t}ÖR¥´†®ÏÄе1„ŠŽ*ˆ_ѵÜβARa¯§s£õ4ÔaÄ#4` Yƒ¢MbŠB„"4c1˜ï_,‚X‹N¥ˆžòr¼¡¤ˆVìLåûˈp>G%V®Ù’â;¶oÿUmMÍýõõõS›››Ÿ&¡x–õ¡ÿ?ÌRà,K3­¢â!Yšb~Îy¢§Õ¸§œ–#TÿËÊ¢Ùî•YEuÀÂÊÝ»o?zèÐ2q?1 e<½±±q»W£]'þ·%j ÝÇûYækþܹç(ÒläááXYeYÄxëy‹ É-Y¼Ð”ò§A³Rò¤*~JW®Yj>É…I÷çñÏ }ê6 B%’A8Òøy OÙ÷©úœ Å#5LÖ@È„6oˆÿ–%Šp‹TñŠ–foÄç#Hh$_$Táú†ˆ íOš¥ÉÒS4Gα’ÏÏl÷‡Z”…žÐ7&MF?±ÁÂBjQ>£„_Ë,Qf¡DÈô)¬GKãYÕ5LK^H}¢´Ž/åeF“T8RBLµÈÄŠ*Õü0éï Q�¤AÇÆQ  &"?R¿•Q8¹¢ŒA,òÅÍS”WqÖ@œ9gÄ„þ=%„AZÉ…‚ó Í€d…ˆ”¸oH(9²4iJ–WQ8ÒEr^Ää‹t2¥ÊxÈ}˜£²¢º'?Žz´ Ì1+]ÕU|ƒC„Yé±å`Xlò -‡øé]üôhf2£¤¿ôÔm6?±Dé›"ç;ÏÔ£ý £)FÜ7$ºdiÜ#f¾?Ô¾×ÒäÞ¢º7]ÆþůÍòI!TJã®3Ã<ŒÅ[·g`â¯äŽ£"TtfŬO©fdÄà÷>æ"•¨dFñw ãE뤤U½Ü¨xl)˜Ú<¹…c@-”�� ±â„Â���@8 ���„���€p dá����Ì„Â���@8 ���„���€p@8����„������������� ����€p�����@8�����á�����„��������@8����� ����€p�����Â�����á�����„����\����@8�����á�����€p�����Â���������„������������� ����€p�����@8�����á�����„�����Â���������„��������@8����� ����€p�����Â�����á�����„�����Â�������� ���������@8�����á�����€p�����Â�����á�����„������������� ����€p�����¨Æÿ멳àÛ'b3����IEND®B`‚ \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/logo_white_ee663702.png0-7000 b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/logo_white_ee663702.png0-7000 deleted file mode 100644 index 6a7db25..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/logo_white_ee663702.png0-7000 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/logo_white_ee663702.png7001-14175 b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/logo_white_ee663702.png7001-14175 deleted file mode 100644 index f6fd201..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/logo_white_ee663702.png7001-14175 and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/res.png b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/res.png deleted file mode 100644 index fc4efba..0000000 Binary files a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/res.png and /dev/null differ diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/sina.htm b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/sina.htm deleted file mode 100644 index 5138c35..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/sina.htm +++ /dev/null @@ -1,7468 +0,0 @@ -<!DOCTYPE html> -<!--[30,131,1] published at 2015-06-18 13:31:26 from #130 by system--> -<html> -<head> -<link rel="icon" sizes="any" mask href="http://www.sina.com.cn/favicon.svg"> -<meta name="theme-color" content="red"> -<link rel="icon" type="image/x-icon" href="http://www.sina.com.cn/favicon.ico"> - <meta http-equiv="Content-type" content="text/html; charset=gb2312" /> - <title>ÐÂÀËÊ×Ò³</title> - - <meta name="keywords" content="ÐÂÀË,ÐÂÀËÍø,SINA,sina,sina.com.cn,ÐÂÀËÊ×Ò³,ÃÅ»§,×ÊѶ" /> - <meta name="description" content="ÐÂÀËÍøΪȫÇòÓû§24СʱÌṩȫÃ漰ʱµÄÖÐÎÄ×ÊѶ£¬ÄÚÈݸ²¸Ç¹úÄÚÍâÍ»·¢ÐÂÎÅʼþ¡¢Ìå̳ÈüÊ¡¢ÓéÀÖʱÉС¢²úÒµ×ÊѶ¡¢ÊµÓÃÐÅÏ¢µÈ£¬ÉèÓÐÐÂÎÅ¡¢ÌåÓý¡¢ÓéÀÖ¡¢²Æ¾­¡¢¿Æ¼¼¡¢·¿²ú¡¢Æû³µµÈ30¶à¸öÄÚÈÝƵµÀ£¬Í¬Ê±¿ªÉ販¿Í¡¢ÊÓƵ¡¢ÂÛ̳µÈ×ÔÓÉ»¥¶¯½»Á÷¿Õ¼ä¡£" /> - <meta name="stencil" content="PGLS000022" /> - <meta name="publishid" content="30,131,1" /> - <meta name="verify-v1" content="6HtwmypggdgP1NLw7NOuQBI2TW8+CfkYCoyeB8IDbn8=" /> - <meta name="360-site-verification" content="63349a2167ca11f4b9bd9a8d48354541" /> - <meta name="application-name" content="ÐÂÀËÊ×Ò³"/> - <meta name ="msapplication-TileImage" content="http://i1.sinaimg.cn/dy/deco/2013/0312/logo.png"/> - <meta name="msapplication-TileColor" content="#ffbf27"/> - <meta name="sogou_site_verification" content="BVIdHxKGrl"/> -<link rel="apple-touch-icon" href="http://i3.sinaimg.cn/home/2013/0331/U586P30DT20130331093840.png" /> - - <script type="text/javascript"> - //jsÒì²½¼ÓÔعÜÀí - (function(){var w=this,d=document,version='1.0.7',data={},length=0,cbkLen=0;if(w.jsLoader){if(w.jsLoader.version>=version){return};data=w.jsLoader.getData();length=data.length};var addEvent=function(obj,eventType,func){if(obj.attachEvent){obj.attachEvent("on"+eventType,func)}else{obj.addEventListener(eventType,func,false)}};var domReady=false,ondomReady=function(){domReady=true};if(d.addEventListener){var webkit=navigator.userAgent.match(/AppleWebKit\/(\d+)/);if(webkit&&webkit[1]<525){doReadyStateCheck()}else{d.addEventListener("DOMContentLoaded",function(){d.removeEventListener("DOMContentLoaded",arguments.callee,false);ondomReady()},false)}};function doScrollCheck(){if(domReady){return};try{d.documentElement.doScroll("left")}catch(e){return};ondomReady()};function doReadyStateCheck(){if(domReady){return};if(d.readyState=='loaded'||d.readyState=='complete'){ondomReady();return}else{setTimeout(doReadyStateCheck,1);return}};function createPosNode(){if(jsLoader.caller){return};cbkLen++;if(!domReady&&d.attachEvent){doScrollCheck()};if(!domReady){try{d.write('<div style="display:none" id="_jl_pos_'+cbkLen+'"></div>');s=d.getElementById('_jl_pos_'+cbkLen)}catch(e){var s=d.createElement('div');s.id='_jl_pos_'+cbkLen;s.style.display='none';d.body.insertBefore(s,d.body.firstChild)}}else{var s=d.createElement('div');s.id='_jl_pos_'+cbkLen;s.style.display='none';d.body.appendChild(s)};return s};function getScript(url,dispose,charset){var scriptNode=d.createElement("script");scriptNode.type="text/javascript";if(charset){scriptNode.charset=charset};scriptNode.onreadystatechange=scriptNode.onload=function(){if(!this.readyState||this.readyState=="loaded"||this.readyState=="complete"){if(dispose){dispose()};scriptNode.onreadystatechange=scriptNode.onload=null;scriptNode.parentNode.removeChild(scriptNode)}};scriptNode.src=url;var h=d.getElementsByTagName("head")[0];h.insertBefore(scriptNode,h.firstChild)};var write=d.write,posNode;function cWrite(str){if(posNode.childNodes.length>0){return};if(posNode.innerHTML!=''){while(posNode.childNodes.length){posNode.parentNode.insertBefore(posNode.childNodes[0],posNode)}};posNode.innerHTML=str;while(posNode.childNodes.length){posNode.parentNode.insertBefore(posNode.childNodes[0],posNode)}};var JsObj=function(name,url){this.name=name;this.url=url;this.callback=[]};JsObj.prototype={status:'init',onload:function(){this.status='ok';var errors=[];for(var i=0;i<this.callback.length;i++){if(typeof this.callback[i]=='function'){try{if(this.callback[i].posNode){posNode=this.callback[i].posNode;d.write=cWrite};this.callback[i]();if(this.callback[i].posNode){d.write=write;this.callback[i].posNode.parentNode.removeChild(this.callback[i].posNode)}}catch(e){errors.push(e)}}};this.callback=[];if(errors.length!=0){throw errors[0]}}};w.jsLoader=function(cfg){var url=cfg.url||"";var name=cfg.name||"";var callback=cfg.callback||"";var charset=cfg.charset||"";if(name){if(!data[name]){if(!url){data[name]=new JsObj(name);data[name].status='waiting'}else{data[name]=new JsObj(name,url)};length++}else if(data[name].status=='waiting'&&url){data[name].status='init'};if(cfg.status){data[name].status=cfg.status};if(data[name].status=='loading'||data[name].status=='waiting'){if(typeof callback=='function'){callback.posNode=createPosNode();data[name].callback.push(callback)};return}else if(data[name].status=='ok'){if(typeof callback=='function'){callback()};return}}else{if(!url){return};for(var item in data){if(data[item].url==url){name=item;break}};if(!name){name='noname'+length;data[name]=new JsObj(name,url);length++};if(data[name].status=='loading'){if(typeof callback=='function'){callback.posNode=createPosNode();data[name].callback.push(callback)};return}else if(data[name].status=='ok'){if(typeof callback=='function'){callback()};return}};if(typeof callback=='function'){callback.posNode=createPosNode();data[name].callback.push(callback)};getScript(url,function(){data[name].onload()},charset);data[name].status='loading'};w.jsLoader.version=version;w.jsLoader.getData=function(){return data}})(); - -/* - jsLoader({ - name : 'iplookup', - url : 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js' - }); -*/ - - </script> - -<script type="text/javascript" src="http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js"></script> - -<script type="text/javascript"> - jsLoader({ - name : 'iplookup', - status : 'ok' - }); -</script> - -<!-- ͬ²½jsºÏ²¢saletop.js¡¢leju.js --> -<script type="text/javascript" src="http://d1.sina.com.cn/js/index/14/sync.js"></script> - -<!-- -<script type="text/javascript" src="http://d4.sina.com.cn/d1images/common/saletop.js"></script> ---> - -<script type="text/javascript"> - jsLoader({ - name : 'saletop', - status : 'ok' - }); -</script> - -<!-- ÀÖ¾Ó¹ã¸æ½Å±¾ begin--> -<!-- -<script charset="UTF-8" src="http://d5.sina.com.cn/litong/zhitou/leju/leju.js"></script> ---> - -<script> - //ÕýʽÊý¾Ý·¾¶£¬°ÑÕâ¸ö·¾¶¸Ä³É404µØÖ·¿ÉÒÔÇëÇóĬÈÏÊý¾Ý£¬²âÊÔÈÝ´í - leju.conf.url = 'http://adm.leju.sina.com.cn/get_ad_list/PG_514AC419D66F33'; - //ÈÝ´íÊý¾Ý·¾¶ - leju.conf.defaultUrl = 'http://staticadm.leju.sina.com.cn/get_ad_list/PG_514AC419D66F33.js'; - //»ñÈ¡Êý¾Ý - var lejuMedia = leju.getData(); -</script> -<!-- ÀÖ¾Ó¹ã¸æ½Å±¾ end--> - -<script> - //ÉèÖñ¾Ò³ÃæµÄ¸»Ã½ÌåÀàÐ͵Ä˳Ðò - - //var _SINAADS_CONF_PAGE_MEDIA_ORDER = ["PDPS000000000001", "PDPS000000002520", "PDPS000000006450", "PDPS000000051826", "PDPS000000052408"]; - - var _SINAADS_CONF_PAGE_MEDIA_ORDER = ["PDPS000000000001", "PDPS000000002520", "PDPS000000006450", "PDPS000000051826", "PDPS000000052408", "feibiao_xibao"]; - - //var sinaadsPageMediaOrder = ['fullscreen', 'stream', 'couplet', 'bp', 'videoWindow']; -</script> - - <style> - /* ³õʼ»¯CSS */ - html, body, ul, li, ol, dl, dd, dt, p, h1, h2, h3, h4, h5, h6, form, fieldset, legend, img { margin:0; padding:0; } - fieldset, img { border:none; } - img{display: block;} - address, caption, cite, code, dfn, th, var { font-style:normal; font-weight:normal; } - ul, ol { list-style:none; } - input { padding-top:0; padding-bottom:0; font-family: "SimSun","ËÎÌå";} - input::-moz-focus-inner { border:none; padding:0; } - select, input { vertical-align:middle; } - select, input, textarea { font-size:12px; margin:0; } - input[type="text"], input[type="password"], textarea { outline-style:none; -webkit-appearance:none; } - textarea { resize:none; } - table { border-collapse:collapse; } - body { color:#333; padding:5px 0; font:12px/20px "SimSun","ËÎÌå","Arial Narrow",HELVETICA; background:#fff;/* overflow-y:scroll;*/ } - .clearfix:after { content:"."; display:block; height:0; visibility:hidden; clear:both; } - .clearfix { zoom:1; } - .clearit { clear:both; height:0; font-size:0; overflow:hidden; } - a { color:#666; text-decoration:none; } - a:visited { color:#666; } - a:hover, a:active, a:focus { color:#ff8400; text-decoration:underline; } - - .hidden{visibility:hidden;} - /**** Á´½ÓÑÕÉ« link,visited,hover*/ - /*#333 #8D0000 #333*/ - .fe661{color: #e66100 !important;} - .fe661:visited{color: #e66100 !important;} - .fe661:hover, .fe661:visited, .fe661:focus{color: #ff8400 !important;} - span.fe661 a:link, span.fe661 a:visited{color: #e66100 !important;} - span.fe661 a:hover, span.fe661 a:focus, span.fe661 a:active{color: #ff8400 !important;} - - .f9157{color: #e66100 !important;} - span.f9157 a:link, span.f9157 a:visited{color: #915724 !important;} - span.f9157 a:hover, span.f9157 a:focus, span.f9157 a:active{color: #ff8400 !important;} - - /*main*/ - .main{width: 1000px;margin: 0 auto;clear: both;background-color: #fff;overflow: hidden; } - - /**** ±à¼­Ï°¹ß */ - a.linkRed:link,a.linkRed:visited{color:#e66100!important;} - a.linkRed:hover,a.active:hover{color:#e66100!important;} - a.liveNewsLeft{background:url(http://i1.sinaimg.cn/dy/deco/2013/0316/liveNewsLeft.gif) no-repeat 0px 50%; padding-left:25px;} - a.audioNewsLeft{background:url(http://i3.sinaimg.cn/dy/deco/2009/0617/LeftAudio.gif) no-repeat ;padding-left:20px} - a.videoNewsLeft{background: url(http://i1.sinaimg.cn/dy/deco/2013/0313/videoNewsLeft.gif) 0 50% no-repeat;padding-left: 23px;} - li.videoNewsLeft{background: url(http://i1.sinaimg.cn/dy/deco/2013/0313/videoNewsLeft.gif) 0 50% no-repeat !important;padding-left: 23px !important;} - a.photoNewsLeft {background: url(http://i1.sinaimg.cn/dy/main/icon/photoNewsLeft2.gif) no-repeat 0 center;padding-left: 23px;} - - /*** ±êÌâ*/ - .tit01{height: 47px;} - .tit01-l{float: left;display: inline;border: 1px solid #d9dce0;border-right:0px;height: 25px;_width:114px;} - .tit01-sw{margin-left: -1px;} - .tit01-l span{height: 25px;line-height:25px;width: 37px;text-align:center;border-right:1px solid #d9dce0; float: left;display: inline;color: #4f4f4f;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -1px repeat-x;cursor: pointer;} - .tit01-l span.selected{background: #fff;border-top: 2px solid #ff8400;margin-top: -1px;position: relative;_margin-bottom: -1px;} - .tit01-r{float: right;border: 1px solid #d9dce0;height: 25px;} - .tit01-r .tit-ipt, .tit01-r .tit-sub{float: left;display: inline;} - .tit01-r .tit-ipt{border: 0px;height: 25px;line-height: 25px;color: #999;background: #f7f7f7;width: 78px;padding-left: 5px;} - .tit01-r .tit-sub{width: 33px;text-align: center;background: #ffefc1;color: #4f4f4f;line-height: 25px;height: 25px;} - .tit01-r .tit-sub:visited{color: #4f4f4f} - .tit01-r .tit-sub:hover, .tit01-r .tit-sub:focus, .tit01-r .tit-sub:active{color: #ff8400;text-decoration: none;} - - .tit02{height: 35px;line-height: 35px;border-bottom: 1px solid #e3e6ed;} - .tit02 h3{font-weight: normal;color: #000;font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimHei","ºÚÌå";font-size: 16px;float: left;display: inline;margin-left: 12px;} - .tit02 h3 a:link, .tit02 h3 a:visited{color: #000;} - .tit02 h3 a:hover, .tit02 h3 a:focus, .tit02 h3 a:active{color: #ff8400;text-decoration: none;} - .tit02 .go-personal{float: right;display: inline;height: 35px;margin-right: 12px;} - - .tit03{height: 37px;border: 1px solid #e3e6ed;border-left: 0px;border-right: 0px;} - .tit03 span{float: left;display: inline;width: 58px;text-align:center;border-left: 1px solid #e3e6ed;border-right:1px solid #f9f9f9;height: 37px;line-height: 37px;background-color: #f9f9f9;font-size: 14px;} - .tit03 span.selected{border-top: 3px solid #ff8400;background-color: #fff;margin-top: -1px;font-weight: bold;line-height: 33px;height: 36px;_position:relative;_margin-bottom:-1px;} - .tit03 span.selected a:link, .tit03 span.selected a:visited{color: #000;} - .tit03 span.selected a:hover, .tit03 span.selected a:focus, .tit03 span.selected:active{text-decoration: none;color: #ff8400;} - .tit03 .last-index{border-right: 1px solid #e3e6ed;} - - .tit04{height: 34px;line-height: 34px;} - .tit04 .bz-order, .tit04 .more{float: right;display: inline;height: 34px;line-height: 34px;width: 54px;text-align: center;border-left: 1px solid #e3e6ed;border-right: 1px solid #e3e6ed;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -32px repeat-x;} - .tit05{height: 28px;line-height: 30px;padding-left: 10px;} - - .tit05 a{font-size: 16px;font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimHei","ºÚÌå";background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 75px -722px no-repeat;padding-right: 20px;display: block;width: 65px;} - - .tit05 a, .tit05 a:visited{color: #000;} - .tit05 a:hover, .tit05 a:focus, .tit05 a:active{color: #ff8400;text-decoration: none;} - - /**** Áбí*/ - .list-a li{padding-left:10px;line-height:26px;height:26px;overflow:hidden;font-size: 14px;background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px;_zoom:1;} - .list-a a:link{color:#122E67;text-decoration:none;} - .list-a a:visited{color:#52687e;text-decoration:none;} - .list-a a:hover,.list-a a:active{color:#ff8400;text-decoration:underline;} - - .list-b li{padding-left:10px;line-height:24px;height:24px;overflow:hidden;font-size: 12px;background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px;} - .list-b a:link{color:#666;text-decoration:none;} - .list-b a:visited{color:#666;text-decoration:none;} - .list-b a:hover,.list-b a:active{color:#ff8400;text-decoration:underline;} - - .list-c li{line-height: 26px;} - - /*pic-txt*/ - .pic-txt{} - .pic-txt .pic{width: 65px;height: 65px;float: left;display: inline;} - .pic-txt .txt{width: 130px;float: left;display: inline;margin-left: 14px;margin-top: -3px;_position: relative;} - - .pic-txt h3{font-weight: normal;padding-bottom: 5px;font-size: 14px;} - .pic-txt h3 a, .pic-txt h3 a:visited{color: #e66100;} - .pic-txt h3 a:hover, .pic-txt h3 a:focus, .pic-txt h3 a:active{color: #ff8400} - .pic-txt p{line-height: 26px;color: #666;} - .pic-txt h3{padding-bottom: 4px;} - .pic-txt02 p{line-height: 24px;} - - /**** footer*/ - .footer{width:1000px; overflow:hidden; text-align:center; color:#939393;font-size: 12px;} - .footer p{line-height:20px;} - .footer p a:link,.footer p a:visited{color:#939393; text-decoration:none;} - .footer p a:hover,.footer p a:active{color:#ff8400; text-decoration:underline;} - .footer .ft-info{background: #F7F7F7;padding:7px 0;margin-bottom: 10px;} - .footer .ft-info a:link,.footer .ft-info a:visited{color:#75839D;} - .footer .ft-info a:hover,.footer .ft-info a:active{color:#ff8400; text-decoration:underline;} - .footer .ft-list{margin:10px 0 8px 0;width:100%;height:50px;} - .footer .ft-list li{float:left;display: inline;margin:0 1px 0 0;} - -/*ÎÞÕÏ°­µ¼Ã¤×©*/ -.JumpTo{position: absolute; top:-1px; left:-1px;} - - /*** others*/ - .blank-d{height: 25px;clear: both;overflow: hidden;display: block;} - .blank-cont{height: 25px;clear: both;overflow: hidden;display: block;} - - .loading{width:350px;height:182px;line-height: 184px;background: url(http://i3.sinaimg.cn/dy/stencil/sysimages/sysimg/loading_01.gif) center center no-repeat;} - - /*---------------------------------- top.css*/ - * html,* html body{background-image:url(about:blank);background-attachment:fixed} - .top-nav-wrap{width:100%;min-width:1000px;z-index:9999;position:absolute;top:0;left:0;} - .top-nav-wrap-fix{position: fixed; top:0; _position:absolute;_top:expression(eval(document.documentElement.scrollTop)); left:0; } - .top-nav{ height:41px; border-top: 3px solid #ff8500;border-bottom:1px solid #EDEEF0; background-color: #FCFCFC; } - .top-nav .tn-bg{ height:41px; /*overflow: hidden; */} - .top-nav .tn-header{ width:1000px; margin:0 auto; position: relative;font-family:"Microsoft YaHei", "΢ÈíÑźÚ", "SimSun", "ËÎÌå"; } - .top-nav .tn-nav{ float:left; _display:inline; /*margin:0 0 0 151px; */} - .top-nav .tn-title{ float:left; font-size:12px; position:relative; } - .top-nav .tn-title .tn-tab{ border: 1px solid #FCFCFC; border-width: 0 1px; color:#4C4C4C; display: inline-block; line-height: 16px; cursor: pointer; position: relative; z-index:9999; padding:0 2px 0 0; } - - .top-nav .tn-title .tn-tab i,.top-nav .tn-title .tn-user i{ display: inline-block; height:17px; padding:12px 9px 12px 16px; vertical-align:bottom; _overflow: hidden; } - - .top-nav .tn-title .tn-user{display: inline-block; line-height: 16px; position: relative; z-index:9999; padding:0 2px 0 0;} - .top-nav .tn-title .tn-user i{padding-left: 0;padding-right:10px;color: #FF8400;} - .top-nav .tn-user a:link,.top-nav .tn-user a:visited{color:#FF8400;text-decoration:none;} - .top-nav .tn-user a:hover,.top-nav .tn-user a:active{color:#FF8400;text-decoration:underline;} - .top-nav .tn-logout{margin-left:5px;} - .top-nav .tn-onmouse .tn-tab{ color:#eee; } - .top-nav .tn-title .tn-tab:hover,.top-nav .tn-setting .tn-name:hover,.top-nav .tn-setting .tn-tab:hover,.top-nav .tn-onmouse .tn-tab,.top-nav .tn-onmouse .tn-tab{ border-color:#EDEEF0; background-color: #EDEEF0; text-decoration:none; color:#ff8400; } - - .top-nav .tn-onmouse .tn-tab i,.top-nav .tn-onmouse .tn-tab i{ color: #4C4C4C; } - .top-nav .tn-onmouse .tn-tab:hover i,.top-nav .tn-onmouse .tn-tab:hover i{color:#ff8400;} - .top-nav .tn-title-login .tn-tab a,.top-nav .tn-title-login .tn-tab a:hover{ color:#000; } - /*.top-nav .tn-title-login a.tn-tab:link,.top-nav .tn-title-login a.tn-tab:visited{ color:#000; background-color: #ff8500; } - .top-nav .tn-title-login a.tn-tab:hover{color:#333; background-color: #ff8500;} - .top-nav .tn-title-login a.tn-user,.top-nav .tn-title-login a.tn-user:hover{ color:#FF8400; background-color: #2D2D2D; }*/ - - /*.top-nav .tn-title-login .LoginIcon{display: none;}*/ - .top-nav .tn-person{ float: right;} - - .top-nav .tn-new{ position: absolute; margin:-10px 0 0 0; display:none; } - .tn-topmenulist{ position:absolute; border:1px solid #333; background:#fff; z-index:9998; font-size:12px; } - .tn-topmenulist { color:#333; } - .tn-topmenulist a{ color:#0a8cd2; } - .tn-topmenulist .tn-text-list { border-bottom:1px solid #FECC5B; margin-bottom: -2px; } - .tn-topmenulist .tn-text-list li{ /*height:31px; »áÒýÆð3ÏñËØbug*/ - line-height:31px; border-bottom: 1px solid #FECC5B; } - .tn-topmenulist .tn-text-list li a{ _zoom:1; display: block; color:#333; padding:0 15px; } - .tn-topmenulist .tn-text-list li a:hover{ color: #E67902; background:#FFF5DA; text-decoration:none; } - .tn-topmenulist .tn-text-list li em{ color:#DE1F26; float: right; } - .tn-topmenulist-a{ border: 1px solid #EBBE7A; border-top:0; overflow: hidden; -moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); top:41px; left:0;} - - .tn-topmenulist-b{border:0;top:42px;left:-110px;} - .tn-topmenulist-a-client{width:112px} - - .tn-topmenulist-a-nav{ width:110px;} - .tn-topmenulist-a-menu{ width:110px;} - .tn-topmenulist-a-weibo,.tn-topmenulist-a-other{ width:78px;} - .tn-topmenulist-a-mail,.tn-topmenulist-a-blog{ width:110px; } - .tn-topmenulist .tn-loading{ padding:10px 0; text-align:center; } - body,.top-nav,.top-nav dl,.top-nav dt,.top-nav dd,.top-nav ul,.top-nav ol,.top-nav li,.top-nav p,.top-nav form,.top-nav input,.top-nav textarea{ margin:0; padding:0; } - .top-nav li { list-style:none; } - .top-nav img { border:0; } - .top-nav a:focus{ outline-style:none; } - .top-nav em,.top-nav i{ font-style:normal; font-weight:normal; } - .top-nav a{ color:#FF8400; text-decoration:none; } - .top-nav a:hover { text-decoration:underline; } - .top-nav .tn-new { background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -1017px; width:14px; height:11px; } - .top-nav .tn-arrow { display:inline-block; width:8px; height:5px; margin:0 0 0 5px; overflow:hidden; vertical-align:middle; font-size:12px; line-height:13px; -webkit-transform:none; -moz-transform:none; -o-transform:none; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -977px no-repeat; } - .top-nav .tn-onmouse .tn-arrow{ /*-webkit-transform: rotate(180deg); -moz-transform: rotate(180deg); -o-transform: rotate(180deg); transform: rotate(180deg); -webkit-transition: all .25s ease 0s; -moz-transition: all .25s ease 0s; -o-transition: all .25s ease 0s; transition: all .25s ease 0s; */ - /*background-position: 0 -997px;*/ } - .clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } - .clearfix { display: inline-block; }* html .clearfix { height: 1%; } - .clearfix { display: block; } - .clear { clear:both; height:0; font:0/0 Arial; visibility:hidden; } - - /*---------------------------------- top-search.css*/ - /*Í·²¿ËÑË÷Ä£¿é*/ - .top-search-wrap{height: 58px;padding-top: 60px;width: 100%;min-width: 1000px;} - .top-search-wrap .top-search-frame{width: 1000px;margin: 0 auto;} - .top-search-wrap .sina-logo, .top-search-wrap .top-search, .top-search-wrap .now-wea-wrap{float: left;display: inline;} - .top-search-wrap .sina-logo{width:111px;height:47px;margin-left:19px;background-image:url(http://i1.sinaimg.cn/dy/deco/2013/0329/logo/LOGO_1x.png); - background-image:-webkit-image-set(url(http://i1.sinaimg.cn/dy/deco/2013/0329/logo/LOGO_1x.png) 1x,url(http://i2.sinaimg.cn/dy/deco/2013/0329/logo/LOGO_2x.png) 2x);background-repeat:no-repeat;} - .top-search-wrap .top-search{margin: 6px 0 0 23px;color: #666;} - .top-search .sim-select{float: left;display:inline;position: relative;width: 75px;height: 33px;border: 1px solid #c1c1c1;border-right:0px; border-radius: 3px 0 0 3px;margin-top:3px;background:#fff url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 74px -218px no-repeat;} - .top-search .sim-select h3{line-height: 33px;font-weight: normal;font-size: 14px;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 57px -340px no-repeat;padding-left: 15px;cursor: pointer;float: left;display: inline;width: 59px;} - /*.top-search .sim-select .v-line{height: 31px;width: 0px;border-left: 1px solid #c1c1c1;overflow: hidden;float: left;display: inline;margin: 1px 0;}*/ - .top-search .sim-select .sim-ul-flt{margin-top:-1px;position: absolute;left: -1px;top: 34px;z-index: 1000;} - .sim-select .sim-ul-bg{} - .sim-select ul{cursor: pointer;position: absolute;left: 0px;top: 0px;z-index: 1000; -moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); box-shadow: 3px 3px 3px rgba(0, 0, 0, .1);} - .sim-select ul li{height: 29px;width:58px;border: 1px solid #d0d0d0;border-top: 0px;background-color: #fff;line-height: 29px;padding-left: 16px;} - .sim-select ul li.over{color: #e77802;background-color: #fff6dd;} - .top-search .inp-txt{width: 244px; color: #666; margin:0;height: 32px;line-height: 32px; padding: 0px 0 0px 14px;border:0px;font-size:14px;_height:30px;_line-height:30px;font-family: "Arial","SimSun","ËÎÌå";} - @media screen and (-webkit-min-device-pixel-ratio:0) {body:nth-of-type(1) .top-search .inp-txt{height:15px;line-height: 15px;padding: 9px 0 9px 14px;}} - .inp-txt-wrap{border: 1px solid #c1c1c1;float: left;display: inline;margin-top: 3px;border-radius: 0;font-family: "Arial","SimSun","ËÎÌå";height: 33px;width: 258px;border-left: 0px;font-size: 14px;} - .inp-txt-click{-moz-animation:bg .5s ease-in-out;-webkit-animation:bg .5s ease-in-out;-o-animation:bg .5s ease-in-out;} - @-moz-keyframes bg{ - 0%{background:rgba(255,170,170,0.18);} - 25%{background:rgba(255,170,170,0.5);} - 50%{background:rgba(255,170,170,0.1);} - 75%{background:rgba(255,170,170,0.5);} - 100%{background:rgba(255,170,170,0.18);} - } - @-webkit-keyframes bg{ - 0%{background:rgba(255,170,170,0.18);} - 25%{background:rgba(255,170,170,0.5);} - 50%{background:rgba(255,170,170,0.1);} - 75%{background:rgba(255,170,170,0.5);} - 100%{background:rgba(255,170,170,0.18);} - } - @-o-keyframes bg{ - 0%{background:rgba(255,170,170,0.18);} - 25%{background:rgba(255,170,170,0.5);} - 50%{background:rgba(255,170,170,0.1);} - 75%{background:rgba(255,170,170,0.5);} - 100%{background:rgba(255,170,170,0.18);} - } - .top-search .submit-second-btn{border:0px;float:left;display:inline;width: 66px;height: 35px;margin-top:3px;margin-right:6px;background:#ff8400 url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 0px 0px no-repeat;cursor: pointer;border-radius: 0px;} - .top-search .submit-second-btn-hover{background-position: -1px -64px;width: 72px;height: 42px;margin: 0px;background-color: transparent;} - .now-wea-wrap{color: #7a7874;margin: 19px 0 0 15px;} - .now-wea-wrap{width:180px;} - .now-wea-wrap a{_zoom:1;_float: left;} - .now-wea-wrap a:hover, .now-wea-wrap a:focus, .now-wea-wrap a:active{text-decoration: none;} - .now-wea-wrap a span, .now-wea-wrap a:visited span{color: #7a7874;cursor: pointer;} - .now-wea-wrap a:hover span, .now-wea-wrap a:active span, .now-wea-wrap a:focus span{color: #ff8400;text-decoration: none;} - .now-wea-wrap span{float: left;display: inline;height: 30px;line-height: 15px;} - /*.now-wea-wrap .now-wea-city{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 10px -478px no-repeat;}*/ - .now-wea-wrap .now-wea-i{padding: 0 5px;} - .now-wea-wrap .now-wea-i img{margin-top: -1px;} - .now-wea-wrap .now-wea-st{padding-right: 5px;}/*Í·²¿title*/ - - .now-wea-wrap {margin: 13px 0 0 15px;} - .now-wea-wrap span{ line-height: 32px; font-size: 14px;} - - .uni-blk{width: 360px;position: relative;} - .uni-blk .uni-blk-t{height: 34px;border: 1px solid #dbdee1;line-height: 34px;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -33px repeat-x;} - .uni-blk-t .order-menu{float: left;margin-left: -2px;} - .uni-blk-t .t-guide{float: right;display: inline;margin-right: 10px;} - .uni-blk .order-trigger, .uni-blk .order-reset{display: block;position: absolute;z-index: 1000;top: -16px;right: -4px;} - .uni-blk .order-trigger{width: 63px;height:25px;line-height:22px;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 0px -358px no-repeat;color: #fff;text-align: center;} - .uni-blk .order-trigger:visited{color: #fff;} - .uni-blk .order-trigger:hover,.uni-blk-t .order-trigger:active,.uni-blk-t .order-trigger:focus{color: #fff;text-decoration: none;background-position: 0px -333px;} - .uni-blk .order-reset{width: 149px;height: 25px;line-height: 300px;overflow: hidden;} - .uni-blk .order-menu span{float: left;height: 35px;line-height:35px;font-size: 16px;font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimHei","ºÚÌå";padding: 0 13px;margin-top: -1px;} - .uni-blk .order-menu a, .uni-blk .order-menu a:visited{color: #000;} - .uni-blk .order-menu a:hover, .uni-blk .order-menu a:active, .uni-blk .order-menu a:focus{color: #ff8400;text-decoration: none;} - .uni-blk .order-menu span.selected{height: 33px;line-height:29px;border-top: 3px solid #ff8400;border-left: 1px solid #dbdee1;border-right: 1px solid #dbdee1;background-color: #fff;_position: relative;_margin-bottom: -1px;padding:0 12px;} - .order-menu span.selected a, .order-menu span.selected em{} - .order-menu span.selected em{color: #000;font-style: normal;margin: 0 12px;} - .order-menu .vline{color: #000;font-style: normal;margin: 0 12px;} - .uni-blk .order-edit, .uni-blk .order-rest{color: #fff;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat;float: left;display: inline;text-align: center;width: 74px;} - .uni-blk .order-edit{background-position: 0px -403px;height: 22px;margin-right: 1px;} - .uni-blk .order-rest{background-position: -75px -403px;height: 25px;} - .uni-blk .order-edit:visited, .uni-blk .order-rest:visited{color: #fff;} - .uni-blk-t .order-edit:hover, .uni-blk-t .order-edit:focus, .uni-blk-t .order-edit:active, .uni-blk-t .order-rest:hover, .uni-blk-t .order-rest:focus, .uni-blk-t .order-rest:active{color: #fff;text-decoration: none;} - .uni-blk .order-edit:hover{background-position: 0px -435px;} - .uni-blk .order-rest:hover{background-position: -75px -435px;} - .uni-blk-t .order-changeit{width: 45px;padding-left: 10px;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 40px -144px no-repeat;float: left;display: inline;border-left:1px solid #dbdee1;border-right: 1px solid #dbdee1} - .uni-blk-t .order-changeit, .uni-blk-t .order-changeit:visited{color: #7b8695;} - .uni-blk-t .order-changeit:hover,.uni-blk-t .order-changeit:focus,.uni-blk-t .order-changeit:active{color: #ff8400;background-color:#fff;text-decoration: none;background-position: 40px -1379px;} - .uni-blk-orderlist{padding-top: 3px !important} - - .uni-blk-picwrap {} - .uni-blk-picwrap .uni-blk-bpic{width: 170px;height:119px;border: 1px solid #fff;} - .uni-blk-picwrap .uni-blk-bpic:hover, .uni-blk-picwrap .uni-blk-bpic:active, .uni-blk-picwrap .uni-blk-bpic:focus {border-color: #ff8400;text-decoration: none;} - .uni-blk-picwrap .uni-blk-bpic:hover span, .uni-blk-picwrap .uni-blk-bpic:active span, .uni-blk-picwrap .uni-blk-bpic:focus span {color: #ff8400;} - .uni-blk-picwrap .uni-blk-bpic span{width: 170px;} - - .weibo-login{display: block;position: absolute;z-index: 1000;top: 3px;right: 2px;height: 34px;line-height: 15px;width: 54px;text-align:center;color: #7a7a7a;} - .weibo-login:visited{color: #7a7a7a;} - .weibo-login:hover, .weibo-login:focus, .weibo-login:active{color: #ff8400;text-decoration: none;} - - /*ËÑË÷°å¿é*/ - .order-search{ float: right; display: inline; width: 73px; margin-right:-1px; position: relative; border-left: 1px solid #dbdee1; border-right: 1px solid #dbdee1; z-index: 10;} - .order-search a.order-seat{ display: block; text-align: center; padding: 0px; padding-left: 20px; color: #7a7a7a; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 17px -523px no-repeat; } - .order-search a.order-seat:visited{ color: #7a7a7a} - .order-search a.order-seat:hover, .order-search a.order-seat:focus, .order-search a.order-seat:active{ color: #ff8400; text-decoration: none; background-color: #fff; background-position: 17px -1096px;} - .sea-out-win{ position: absolute; z-index: 5000; top: 30px; border: 1px solid #ff8400; background: #fff; padding: 15px 14px 12px; } - .order-search-fin .sea-out-win{width: 262px;left: -218px;} - .order-search-blog .sea-out-win{width: 190px;left: -146px;} - .sea-out-win .sow-arr{ width: 15px; height: 6px; display: block; position: absolute; z-index: 10000; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -929px no-repeat;top: -6px; } - .order-search-fin .sow-arr{left: 252px;} - .order-search-blog .sow-arr{left: 176px;} - .sow-form form{position: relative;z-index: 300; _zoom:1;} - .sow-form .sim-select{float: left;display: inline;width: 58px; margin-right:12px;} - .sow-form .sim-select h3{font-weight: normal;color: #888;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 44px -840px no-repeat;height: 23px;line-height: 23px;border: 1px solid #cdcdcd;width: 48px;padding-left: 8px;font-size: 12px;cursor: pointer;} - .sow-form .sim-select ul{top: 25px;left: 0px;} - .sow-form .sim-select li{width: 48px;height: 23px;line-height: 23px;padding-left: 8px;color: #888;} - .sow-form .sow-ipt-w, .sow-form .sow-sub-wrap, .sow-form .sow-sub{ float: left; display: inline; } - .sow-form .sow-ipt-w{ width: 108px; height: 23px; border: 1px solid #cdcdcd; padding-left: 20px; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 5px -573px no-repeat; border-right: 0px; line-height: 21px;} - .sow-form .sow-ipt-w div{left: 79px !important;} - .sow-form .sow-ipt{ border: 0px; height: 22px; line-height: 22px; _height:21px;_line-height:21px;width: 104px; color: #888; } - .sow-form .sow-sub-wrap{border: 1px solid #cdcdcd;} - .sow-form .sow-sub{border:0px; height: 23px; line-height: 23px; width: 58px; text-align: center; cursor: pointer; background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0px -109px repeat-x;} - .sow-form .sow-sub-wrap:hover{border: 1px solid #eec57c;text-decoration: none;} - .sow-form .sow-sub-wrap:hover .sow-sub{background-position: 0px -136px;} - .sow-list{ line-height: 24px; padding-top: 8px; } - .sow-list li{ float: left; display: inline; width: 60px; } - - /*²Æ¾­ÄÚÈÝËÑË÷*/ - .uni-blk-form{margin-top: 15px;margin-bottom: 9px;} - .uni-blk-form .sow-form .sow-ipt-w{width: 208px;} - .uni-blk-form .sow-form .sow-ipt{width: 204px;} - .uni-blk-form .sow-form .sim-select{position: relative;z-index: 20;} - .uni-blk-form .sim-select ul{left: 0px;top: 25px;} - - /*µ×²¿ÐÅÏ¢²ã*/ - .uni-blk-b{padding-top: 10px;} - .uni-blk-b .uni-blk-bt{padding: 10px 0px 1px 0px;} - .uni-blk-b .uni-blk-list01{float: left;padding-left: 15px;position: relative;margin-top: -5px;width: 220px;overflow: hidden;} - .part-a .uni-blk-b .uni-blk-list01{padding-left:14px;} - .uni-blk-b .uni-blk-list01 li{line-height: 26px !important;} - .uni-blk-b .uni-blk-list02{padding: 0px 0px 0px 0px;} - /*¶¨ÖƸ¡²ã*/ - .uni-blk-f-w{position: absolute;z-index: 999;left: 0px;top: 0px;background: #fff;color: #596a7b;width: 360px;} - .uni-blk-f-w .order-menu{padding-left: 10px;} - .uni-blk-f-w .order-menu a{padding: 0 10px 0 10px;color: #000;float: left;} - .uni-blk-f-w .order-menu a:visited{color: #000;} - .uni-blk-f-w .order-menu a:hover{opacity: 0.7;filter:alpha(opacity=70);text-decoration: none;} - .uni-blk-f-w .order-menu span, .uni-blk-f-w .order-menu i{float: left;display: inline;} - .uni-blk-f-w .order-menu span{padding: 0px 5px 0 0;} - .uni-blk-f-w .order-menu i{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0px -32px no-repeat;width: 10px;height: 10px;margin-top: 13px;} - .uni-blk-f{overflow-x: hidden;overflow-y:hidden;border-left: 1px solid #dbdee1;border-right:1px solid #dbdee1;width: 358px;padding: 0 0 15px 0;} - .parent-menu{overflow-y: auto;padding-bottom: 15px;} - .parent-menu li{float: left;width: 70px;text-align: center;height:33px;line-height: 33px;font-size: 14px;display: inline;margin-top: 10px;margin-left: 14px;} - .parent-menu li a{display: block;overflow: hidden;background: #fff;color: #596a7b;} - .parent-menu li a:visited{color: #596a7b;} - .parent-menu li a:hover{color: #ff8400;text-decoration: none;} - .parent-menu li .son-menu{display: none;} - .parent-menu li.selected a.p-item{background-color: #ff8400;color: #fff;font-weight: bold;} - .parent-menu li.selected a.p-item:visited, .parent-menu li.selected a.p-item:hover, .parent-menu li.selected a.p-item:active, .parent-menu li.selected a.p-item:focus{color: #fff;text-decoration: none;} - .son-menu-wrap{background-color: #fbfbfd;padding-left: 10px;} - .son-menu-tip{line-height: 26px;} - .son-menu{margin-left: -10px;padding-bottom: 9px;} - .son-menu li{line-height: 31px;height: 31px;font-size: 12px;width: auto;float:left;padding-right: 3px;margin-left: 20px;display: inline;_overflow: hidden;} - .son-menu li a{white-space: nowrap;cursor: pointer;float: left;} - .son-menu li a, .son-menu li a:visited{color: #596a7b;} - .son-menu li a:hover, .son-menu li a:active, .son-menu li a:focus{color: #ff8400;} - .son-menu li span, .son-menu li i{display: inline-block;} - .son-menu li span{*vertical-align: -3px;_vertical-align: 0px;} - .son-menu li i{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -111px no-repeat;width: 11px;height: 10px;margin:10px 0 0 5px;} - .son-menu li a:hover i{opacity: 0.7;filter:alpha(opacity=70);} - .son-menu li.has-checked a,.son-menu li.has-checked a:visited{color: #ff8400;} - .son-menu li.has-checked a:hover,.son-menu li.has-checked a:focus,.son-menu li.has-checked a:active{color: #ff8400;} - .son-menu li.has-checked i{background-position: 0px -77px;width: 7px;height: 7px;margin-left: 7px;margin-right:2px;_vertical-align:-2px;} - - .btn-area{clear: both;border: 1px solid #dbdee1;height: 55px;overflow: hidden;_padding-bottom:13px;} - .btn-area a{background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat;float: left;display: inline;width: 78px;height: 32px;margin-top: 10px;display: inline;} - .btn-area a:hover{opacity: 0.8;filter:alpha(opacity=80);} - .btn-area .do-submit{background-position: -32px -190px;margin-left: 100px;} - .btn-area .do-cancel{background-position: -113px -190px;margin-left: 5px;} - - /*ͼÎÄ*/ - .uni-blk-pic{float: left;display: block;width: 105px;height: 90px;overflow: hidden;border:1px solid #fff;} - .uni-blk-pic span{width: 105px;text-align: center;color: #fff;height: 20px;line-height: 20px;display: block;background: #000;} - .uni-blk-b .uni-blk-pic span, .uni-blk-b .uni-blk-pic:visited span, .uni-blk-b .uni-blk-pic:hover span, .uni-blk-b .uni-blk-pic:active span, .uni-blk-b .uni-blk-pic:focus span{color: #fff;} - .uni-blk-b .uni-blk-pic:hover{border-color: #e66100;text-decoration: none;} - .uni-blk-b .uni-blk-pic:hover span, .uni-blk-b .uni-blk-pic:active span, .uni-blk-b .uni-blk-pic:focus span{text-decoration: none;color: #ff8400} - .uni-blk-b .uni-blk-pic .play-icon {position:absolute; width:40px; height:40px; top:55px; left:5px; cursor:pointer; background:url(http://i2.sinaimg.cn/dy/deco/2013/0316/play_icon_normal.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i2.sinaimg.cn/dy/deco/2013/0316/play_icon_normal.png');_background:none;} - .uni-blk-b .uni-blk-pic:hover .play-icon {background:url(http://i1.sinaimg.cn/dy/deco/2013/0316/play_icon_hover.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i1.sinaimg.cn/dy/deco/2013/0316/play_icon_hover.png');_background:none;} - - .uni-blk-bpic{width: 125px;height: 120px;position: relative;border:0px;} - .uni-blk-bpic span{position: absolute;z-index: 500;left: 0px;top: 70px;} - - .uni-blk-bpic span{width: 125px;height: 24px;line-height: 24px;top: 95px;background:none\9;filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 0,startColorstr = '#9A000000', endColorstr = '#9A000000' )\9;background-color:rgba( 0, 0, 0, .6 );*background-color:transparent\9;} - - .uni-blk-pic-c{float:none;height: 80px;margin:6px auto;position:relative;} - .videonewsList{width:230px;float:left;} - .videoLeftC{float:left;margin-right:16px;zoom:1;width:107px;} - .vid-play-icon{position: absolute;width: 22px;height: 22px;top: 33px;left: 3px;cursor: pointer;background: url(http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png) no-repeat;_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png');_background: none;} - .uni-blk-pic-c:hover .vid-play-icon{background: url(http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png) no-repeat;_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png');_background: none;} - - /*blk-line*/ - .blk-line{height: 2px;overflow: hidden;clear: both;background-color: #fff;} - .dot-line{height: 1px;overflow: hidden;clear: both;background: url(http://i1.sinaimg.cn/dy/deco/2013/0306/dot_line.png) 0 0 repeat-x;margin: 3px 0 3px 0} - .blk-line02{background: url(http://i2.sinaimg.cn/dy/deco/2013/0318/spe.png) 0 -1px no-repeat;height: 11px;overflow: hidden;clear: both;} - - /*others*/ - .no-bl{border-left: 0px !important;padding-left: 13px !important} - .main-nav{ overflow:hidden; width: 1000px; margin: 0 5px; overflow: hidden; font-family:"Microsoft YaHei", "΢ÈíÑźÚ", "SimSun", "ËÎÌå";} - .nav-mod-1,.nav-mod-2{ overflow:hidden; _display:inline-block; float:left; padding: 2px 5px 18px 0} - .nav-mod-1{ width:132px; background:url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat 136px -183px; margin-left:2px; display:inline; } - .nav-mod-2{ width:95px; } - .nav-w{ width:136px; background-position:140px -183px; } - .nav-w-2{width: 145px;background: none;} - .main-nav ul{ height:26px; clear:both; overflow: hidden;} - .main-nav li{ float:left; width:27px; margin-left:13px; line-height:26px; text-align: center; white-space: nowrap;display: inline;} - .main-nav .nav_1 li{ padding:0 6px 0 7px; } - .main-nav a,.main-nav a:visited{ color:#000; text-decoration:none; } - .main-nav a:hover,.main-nav a:active{ color:#e66100; text-decoration: underline; } - - .top-ads{ background-color: #f6f8f9; } - .top-ads a:link, .top-ads a:visited{ color: #666; } - .top-ads a:hover, .top-ads a:active, .top-ads a:focus{ color: #e66100; } - .top-ads-list{ height: 35px; } - .top-ads-list li{ line-height: 35px; height: 35px; float: left; display: inline; width: 125px; overflow: hidden; text-align:center; } - - .part-a{ clear: both; } - .part-a-l, .part-a-m, .part-a-r{ float: left; display: inline; } - .part-a-l{ width: 240px; margin-right: 20px; } - .part-a-m{ width: 360px; margin-right: 20px; } - .part-a-r{ width: 360px; } - - /*mod01*/ - .palm01-ad{ padding-top: 13px; } - - /*mod02*/ - .mod-02{ border: 1px solid #d9e0ee; border-top: 3px solid #ff8400; } - .mod-02 a{ color: #666; } - .mod-02 a:visited{ color: #666; } - .mod-02 a:hover, .mod-02 a:focus, .mod-02 a:active{ color: #ff8400; } - .mod02-cont{ padding: 7px 5px 0px 5px; } - .mod02-cont-t{ background: url(http://i1.sinaimg.cn/dy/deco/2013/0306/dot_line.png) 0 bottom repeat-x; width: 228px;} - .pro{ float: left; display: inline; width: 60px; text-align: center; margin: 0 8px; } - .pro span{ line-height: 26px; padding: 4px 0 2px 0;display: block; position: relative;} - .pro img{ clear: both; } - .mod02-cont-b{ padding: 4px 0 0; width: 228px;} - .mod02-cont-b li{ float: left; display: inline; width: 76px; text-align: center; padding-bottom: 4px; } - - /*mod03*/ - .mod03{ } - .mod03-cont{ border: 1px solid #e3e6ed; border-top: 0px; padding: 3px 8px 3px 15px; } - .mod03-list{} - .mod03-list li{float: left;display: inline;width: 105px;overflow: hidden;font-size: 12px;line-height: 24px;height:24px;padding-right: 1px;} - - /*mod04*/ - .mod-04 .uni-blk-b{ padding-top: 10px; } - .mod-04 .uni-blk-bt{padding-top: 0px;margin-top: 15px;padding-bottom: 0px;} - - /*mod05*/ - .mod-05 .order-menu em, .mod-05 .order-menu i{float: left;display: inline;} - .mod-05 .order-menu em{ margin: 0 12px; color: #000;font-style: normal;} - .mod-05 .order-menu span em{color: #000;font-style: normal;margin: 0;} - .mod-05 .order-menu span{padding:0 7px;} - .mod-05 .order-menu span.selected{padding:0 6px;} - .mod-05 .order-menu span.selected .mod-guess-control{margin-top:6px !important;} - .mod-05 .order-menu i{ width: 41px; height: 21px; line-height:21px;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -126px 0 no-repeat; margin: 8px 0 0 5px; cursor: pointer; font-size: 12px;color: #7a7a7a;padding-left: 24px;font-style: normal;font-family: "SimSun","ËÎÌå";} - .order-menu span.selected i{ margin-top: 5px; } - .mod-05 .order-menu i.over{ background-position: -126px -154px; color: #555556;} - .mod-05 .order-trigger{ width: 72px; padding: 0px; text-align: center; background: none; } - .mod-05 .mod05-cont{ padding: 10px 0 0px 0} - .mod-05 .list-a{ /*padding-bottom: 17px;*/ } - .mod-05 .mod05-ads a{float: left;display: inline;} - - /*mod06*/ - .mod-06 .vline{ color: #bfb3a8 !important; line-height: 25px !important; } - - .part-b{ } - .part-b-l, .part-b-m, .part-b-r{ float: left; display: inline; } - .part-b-l{ width: 240px; margin-right: 20px; } - .part-b-m{ width: 360px; margin-right: 20px; } - .part-b-r{ width: 360px; } - - /*mod07*/ - .mod-07 h3 a{height:35px;overflow:hidden; background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 68px -276px no-repeat; display: block;width: 110px;} - .mod-07 .s-btn{float: right; height: 24px; margin-top: 11px;_margin:11px 0 -1px 0;*position: relative;*z-index: 100} - .s-btn span{ height: 23px; line-height: 23px; float: left; display: inline; width: 40px; text-align: center; border: 1px solid #ddd;border-right:0px;border-bottom: 0px;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -77px repeat-x; } - .s-btn span.selected{ background: #fff; } - /*.mod07-cont{ padding: 0 7px 0 7px; }*/ - .mod07-cont-t{ border-bottom: 1px solid #ddd; height: 79px; /*overflow-x: hidden;*/ padding: 5px 7px 0 7px; } - .mod07-cont-t .t-icon, .mod07-cont-t .s-score{ float: left; display: inline; width:110px;overflow: hidden;text-align: center;} - .mod07-cont-t .t-icon{ width: 57px; text-align: center; _margin:5px 0;} - .t-icon img{ clear: both; } - .t-icon:link span, .t-icon:visited span{ color: #505050; } - .t-icon:hover span, .t-icon:focus span, .t-icon:active span{ color: #ff8400} - .s-score{ margin-top: 10px; } - .s-score-t a{ display: block; text-align: center; line-height: 30px; } - .s-score-t a:link,.s-score-t a:visited{font-size: 22px; font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimSun","ËÎÌå"; color: #343434; } - .s-score-t a:hover, .s-score-t a:active, .s-score-t a:focus{ color: #ff8400; text-decoration: none; } - .s-score-b a{padding: 0 2px 0 1px;} - .s-score-b a:link,.s-score-b a:visited{ color: #4f4f4f; } - .s-score-b a:hover, .s-score-b a:active, .s-score-b a:focus{ color: #ff8400; text-decoration: none; } - .mod07-cont-wrap{width: 238px;height: 172px;text-align: right;border-top: 1px solid #e3e6ed;margin-top: -1px;_overflow:hidden;} - .mod07-cont-wrap .loading{width:238px;height: 172px;} - .mod07-cb-item .team,.mod07-cb-item .label{float: left;display: inline;} - .mod07-cont-b{ padding: 12px 0 15px 0; } - .mod07-cb-item{ width: 106px; overflow: hidden; padding: 0 6px 0 5px; border-right: 1px solid #d9dce0; float: left; display: inline; } - .mod07-cb-item span{ color: #a4a4a4; } - .mod07-cont-wrap .last{border-right: 0;padding: 0 5px 0 6px;} - .s-list{} - .s-list li{ /*float: left; display: inline;*/ line-height: 20px; /*width: 50px; */} - /*mod12*/ - .mod-12{ border-bottom: 1px solid #e9e9e9; padding: 10px 0 6px 0; } - .mod12-item{ float: left; display: inline; padding-left: 18px; width: 120px; border-right: 1px solid #e9e9e9; } - .mod12-item a{ line-height: 24px; height:24px;overflow:hidden;display: block; color: #596a7b; } - .mod12-item a:visited{ color: #596a7b; } - .mod12-item a:hover, .mod12-item a:active, .mod12-item a:focus{ color: #e66100; } - .part-d-l, .part-d-m, .part-d-r{ float: left; display: inline; } - .part-d-l{ width: 240px; margin-right: 20px; } - .part-d-m{ width: 360px; margin-right: 20px; } - .part-d-r{ width: 360px; } - /*mod13*/ - .mod13-cont{ padding: 12px 5px 15px 9px; } - - .part-e{ width: 1000px; /*z-index: 1 !important*/} - /*scroll*/ - .scroll-pic-frame{ position: relative; overflow: hidden; z-index: 100; } - .scroll-pic-wrap{ position: relative; overflow: hidden; } - .scroll-item{ float: left; display: inline; width: 200px; height: 164px; overflow: hidden; } - .scroll-item a{ display: block; width: 198px; height: 162px; border: 1px solid #fff; position: relative; overflow: hidden; z-index: 50; } - .scroll-item a:hover{ border-color: #ff8400; } - .scroll-item .scroll-txt{ width: 198px; height: 30px; line-height: 30px; position: absolute; z-index: 1000; left: 0px; background: #262626; top: 132px; display: block; text-align: center; } - .scroll-item a:link .scroll-txt, .scroll-item a:visited .scroll-txt{ color: #fff; } - .scroll-item a:hover .scroll-txt, .scroll-item a:active .scroll-txt, .scroll-item a:focus .scroll-txt{ color: #ff8400; text-decoration: none; } - - .scroll-arr-l, .scroll-arr-r{ position: absolute; z-index: 20000; width: 29px; height: 43px; top: 48px; background: url(http://i1.sinaimg.cn/dy/deco/2013/0316/arr.png) no-repeat; } - .scroll-arr-l{ left: 1px; background-position:0 0; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i0.sinaimg.cn/dy/deco/2013/0316/arr_l.png'); } - .scroll-arr-r{ right: 1px; background-position: -29px 0px; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i2.sinaimg.cn/dy/deco/2013/0316/arr_r.png'); } - .scroll-arr-l:hover{ background-position:0 -43px; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i3.sinaimg.cn/dy/deco/2013/0316/arr_l_hover.png'); } - .scroll-arr-r:hover{ background-position: -29px -43px; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i1.sinaimg.cn/dy/deco/2013/0316/arr_r_hover.png'); } - .scroll-dot-lists{ clear: both; text-align: center; height: 30px; padding-top: 7px; } - .scroll-dot-lists span{ display: inline-block; width: 15px; height: 15px; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 2px -485px no-repeat; cursor: pointer; margin: 0 3px; } - .scroll-dot-lists span.cur{ background-position: 0 -440px; } - .part-f{ padding: 5px 0; border-top: 1px solid #e9e9e9; border-bottom: 1px solid #e9e9e9; height: 49px;overflow: hidden;} - .pf-list{ width: 189px; padding-left: 10px; border-right: 1px solid #e9e9e9; float: left; } - .pf-list li{ line-height: 24px; clear: both; height: 24px;overflow: hidden;} - .pf-list a, .pf-list a:visited{ color: #596a7b; } - .pf-list a:hover, .pf-list a:focus, .pf-list a:active{ color: #e66100; } - - .part-g-l, .part-g-m, .part-g-r, .part-g-mr{ float: left; display: inline; } - .part-g-l{ width: 240px; margin-right: 20px; } - .part-g-mr{ width: 740px; } - .part-g-m{ width: 360px; margin-right: 20px; } - .part-g-r{ width: 360px; } - - /*mod17*/ - .mod-17{ border:1px solid #e3e6ed; border-top: 3px solid #ff8400; } - .mod17-cont{ padding: 12px 5px 12px 9px; } - .mod-17 .bz-order i{ display:block; width: 23px; height: 23px; background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -128px -100px no-repeat; margin: 5px 0 0 18px;*margin-left: 5px; cursor: pointer;} - .mod-17 .bz-order:hover i{ opacity: 0.7; filter:alpha(opacity=70); } - - /*mod19*/ - .mod-19 .uni-blk-b{ padding-top: 7px; } - .mod-19 .uni-blk-b .uni-blk-bt{ } - - /*mod20*/ - .book-cust{ } - .book-tit{ height: 20px; line-height: 20px; background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -163px repeat-x; padding: 5px 0 7px 0} - .book-tit h3{ width: 102px; background:#fff url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -88px -49px no-repeat; font-weight: normal; } - .book-tit h3 a, .book-tit h3 a:visited{ color: #e66100; font-size: 14px; } - .book-tit h3 a:hover, .book-tit h3 a:active, .book-tit h3 a:focus{ color: #ff8400; } - - .book-list{ } - .book-list li{ width: 180px; float: left; display: inline; line-height: 24px; } - .book-list em{ font-weight: bold; color: #ff8400; font-family: "Arial"; padding-right: 12px; } - - .part-h-l, .part-h-m, .part-h-r{ float: left; display: inline; } - .part-h-l{ width: 240px; margin-right: 20px; } - .part-h-m{ width: 360px; margin-right: 20px; } - .part-h-r{ width: 360px; } - - /*mod21*/ - .ed-pic-lists{ float: right; height: 35px; margin-right: 10px; display: inline; } - .ed-pic-lists span{ float: left; display: inline; width: 13px; height: 13px; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 1px -680px no-repeat; margin: 10px 2px 0; cursor: pointer; } - .ed-pic-lists span.cur{ background-position: 0 -632px; } - .mod21-cont{ padding: 7px 8px 0 8px; } - .ed-pic-wrap{ width: 218px; overflow: hidden; } - .ed-pic-item{ float: left; display: inline; overflow: hidden; width: 218px; } - .ed-pic-item .list-b{ height: 24px; padding: 3px 0; } - - /*mod22*/ - .mod-22{ border: 1px solid #d9e0ee; border-top: 0px; } - .mod22-cont{ padding-left: 10px; } - - /*mod24*/ - .mod24-t{_overflow:hidden;} - .mod24-menu{float: left;_zoom:1;} - .mod24-menu span{text-align:center; border-right: 1px solid #dbdee1;float: left;display:inline;height: 35px;line-height: 35px;} - .mod24-menu span a, .mod24-menu span a:visited{ color: #596a7b; font-size: 14px ; font-family:"SimSun","ËÎÌå"; padding: 0px; } - .mod24-menu span a:hover, .mod24-menu span a:active, .mod24-menu span a:focus{ color: #ff8400 !important; text-decoration: none; } - .mod24-menu span.selected{ border-top: 1px solid #dbdee1; height: 35px;background-color: #fff;line-height: 33px;margin-top: -1px;_margin-bottom: -1px;position: relative;} - .mod24-menu span.selected a{ line-height: 35px; } - - /*mod25*/ - .mod25-menu span.selected{ border-top: 3px solid #ff8400; height: 33px;background-color: #fff;px;margin-top: -1px;_margin-bottom: -1px;position: relative;} - .mod25-menu span.selected a{ line-height: 31px; } - - .part-j-l, .part-j-m, .part-j-r{ float: left; display: inline; } - .part-j-l{ width: 240px; margin-right: 20px; } - .part-j-m{ width: 360px; margin-right: 20px; } - .part-j-r{ width: 360px; } - - /*mod27*/ - .mod27-cont{ padding: 20px 10px 6px 10px} - - .part-k-l, .part-k-m, .part-k-r{ float: left; display: inline; } - .part-k-l{ width: 240px; margin-right: 20px; } - .part-k-m{ width: 360px; margin-right: 20px; } - .part-k-r{ width: 360px; } - .part-l-l, .part-l-m, .part-l-r{ float: left; display: inline; } - .part-l-l{ width: 240px; margin-right: 20px; } - .part-l-m{ width: 360px; margin-right: 20px; } - .part-l-r{ width: 360px; } - .part-n-l, .part-n-m, .part-n-r{ float: left; display: inline; } - .part-n-l{ width: 240px; margin-right: 20px; } - .part-n-m{ width: 360px; margin-right: 20px; } - .part-n-r{ width: 360px; } - - /*mod38*/ - .mod38-cont{ padding-top: 15px; } - - /*mod39*/ - .mod39-cont{ padding: 12px 10px 0; } - - .part-o-l, .part-o-m, .part-o-r{ float: left; display: inline; } - .part-o-l{ width: 240px; margin-right: 20px; } - .part-o-m{ width: 360px; margin-right: 20px; } - .part-o-r{ width: 360px; } - - /*mod42*/ - .mod42-cont{ padding: 18px 0 20px 12px; } - .mod42-cont-b{padding-top: 14px;} - - /*mod44*/ - .mod44-list{ float: right; display: inline; margin-right: 5px;} - .mod44-list li{ height: 34px; line-height: 34px; float: left; display: inline; margin-right: 5px; } - .mod44-list li a, .mod44-list li a:visited{ color: #7a7a7a} - .mod44-list li a:hover, .mod44-list li a:active, .mod44-list li a:focus{ color: #ff8400; } - - .part-q-l, .part-q-m, .part-q-r{ float: left; display: inline; } - .part-q-l{ width: 240px; margin-right: 20px; } - .part-q-m{ width: 360px; margin-right: 20px; } - .part-q-r{ width: 360px; } - - .part-r-l, .part-r-m, .part-r-r{ float: left; display: inline; } - .part-r-l{ width: 240px; margin-right: 20px; } - .part-r-m{ width: 360px; margin-right: 20px; } - .part-r-r{ width: 360px; } - - .part-s-l, .part-s-m, .part-s-r{ float: left; display: inline; } - .part-s-l{ width: 240px; margin-right: 20px; } - .part-s-m{ width: 360px; margin-right: 20px; } - .part-s-r{ width: 360px; } - /*mod52*/ - .mod52-fix-cont{ padding-top: 0px !important; } - .part-s-m .order-menu span.selected{ overflow: hidden; }.f596{color: #59687b;} - .f596:visited{color: #666;} - .f596:hover, .f596:active, .f596:focus{color: #ff8400;} - - .nmod01{border-top: 1px solid #e9e9e9;font-size: 14px;padding: 3px 0;clear: both;margin-top: 4px;} - .nmod01 a{line-height: 26px;} - - /*Æû³µÆµµÀ*/ - .car-nmod{float: left;width: 235px;display: inline;overflow: hidden;padding-left: 14px;margin-top: -3px;position: relative;padding-bottom: 4px;height: 98px;} - .car-nmod h3{font-size: 14px;font-weight: bold;line-height: 20px;padding-bottom: 6px;} - .car-nmod a, .car-nmod a:visited{color: #122e67;} - .car-nmod a:hover, .car-nmod a:active, .car-nmod a:focus{color: #ff8400} - - .car-nmod p{line-height: 24px;} - .wb-share, .wb-comment, .wb-like{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat;float: left;display: inline;height: 24px;margin-right: 5px;} - .wb-share, .wb-share:visited, .wb-share:active, .wb-share:focus, .wb-share:hover, .wb-comment, .wb-comment:visited, .wb-comment:hover, .wb-comment:active, .wb-comment:focus, .wb-like, .wb-like:visited, .wb-like:hover, .wb-like:active, .wb-like:focus{line-height: 24px;color: #7b7b7b;} - .wb-share{background-position: 0px -1185px;padding-left: 20px;} - .wb-comment{background-position: 0px -1243px;padding-left: 15px;} - .wb-like{background-position: 0px -1306px;padding-left: 15px;} - - /*×ۺϿÎÌÃ*/ - .vid-txt{} - .vid-txt .vid{float: left;width: 87px;height: 59px;overflow: hidden;display: block;position: relative;} - .vid-txt .txt{float: left;display: inline;margin-left: 12px;width: 120px;} - .vid-txt .txt h3{font-size: 12px;font-weight: normal;line-height: 18px;} - .vid-txt .free-listen{width: 69px;height: 23px;text-align: center;line-height: 23px;display: block;background-color: #ff8400;color: #fff;clear: both;margin-top: 18px;} - .vid-txt .free-listen:visited, .vid-txt .free-listen:hover, .vid-txt .free-listen:active, .vid-txt .free-listen:focus{color: #fff;text-decoration: none;} - .vid-txt .free-listen:hover, .vid-txt .free-listen:active, .vid-txt .free-listen:focus{opacity: 0.7;filter:alpha(opacity=70);} - .vid-txt .vid-play-icon {position:absolute; width:22px; height:22px; top:33px; left:3px; cursor:pointer; background:url(http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png');_background:none;} - .vid-txt:hover .vid-play-icon {background:url(http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png');_background:none;} - - /*΢²©×ª·¢°´Å¥*/ - .weibo_btn {position:fixed; left:50%; bottom:100px; margin:0 0 0 505px; text-align:center; color:#4c4c4c; width:26px; _position:absolute;} - - .weibo_btn .wt_link, .weibo_btn .wt_link:visited {background:#fff url(http://i0.sinaimg.cn/dy/2011/0905/U6893P1DT20110905170320.gif) no-repeat 4px 5px; width:21px;outline:none; overflow:hidden; display:block; cursor:pointer; color:#4c4c4c; border:solid 1px #ccc;padding:29px 2px 7px; line-height:14px;} - .weibo_btn .wt_link:hover { background-color:#eee;color:#4c4c4c; text-decoration:none;} - .weibo_btn .wt_link, .weibo_btn .wt_link:visited{text-decoration:none} - - /*ת·¢µ½Î¢²©°´Å¥*/ - .weibo_btn { color: #4C4C4C; } - .weibo_btn .wt_link, .weibo_btn .wt_link:visited {background:url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 0 -490px no-repeat;height: 50px; width: 50px;_background:url(http://i0.sinaimg.cn/dy/deco/2012/1227/news_zxh_content_btn_bg.png) no-repeat; border:none;line-height:400px; padding: 0; filter:Alpha(Opacity=35); opacity:0.35;} - .weibo_btn .wt_link:hover { filter:Alpha(Opacity=50); opacity:0.5;} - - .side-btns-wrap{width:50px;left: 50%; margin:0 0 0 505px;position: fixed; _position:absolute;bottom: 60px;z-index:100; } - - div.nmod01{padding:0px 0 1px 0;margin-top:-1px; line-height:18px;padding-left:10px;*zoom:1;} - /*ÊÓƵֱ²¥*/ - textarea.hidden{position: absolute;top:-100px;left:-9999px;} - .mod07-cont .list-b{padding: 12px 0 0 9px;} - .mod07-cont .list-b li{text-align: left;} - .mod07-cont-b{padding-top: 8px;} - .mod07-cont-b .list-b{height:70px;overflow: hidden; padding-top:0;} - - /*¹º³µ*/ - .mod-a .hd{padding:3px 0 0 0px;height: 26px;line-height: 26px;border-top:1px solid #eee;margin-left:10px;_margin-left:5px;} - .mod-a .tab-nav-a{font-size:14px;float: left;} - .hd a, .hd a:visited{color: #58677a;} - .hd a:hover, .hd a:active, .hd a:focus{color: #ff8400} - .mod-a .extra{float:right;font-size:12px;} - .mod-a .selected:hover, .mod-a .selected:active, .mod-a .selected:focus{color: #58677a;text-decoration: none;} - .mod-a .tab-nav-a a{line-height: 23px;height:23px;padding:0;border-left: 0px;float: left;} - .mod-a .tab-nav-a span{line-height: 23px;height:23px;padding: 0 2px;border-left: 0px;float: left;} - .mod-a .tab-nav-a a.selected{color:#e66100!important;} - /*²Æ¾­ËÑË÷µ÷Õû*/ - .order-search-fin a.order-seat{background-position: 10px -523px;padding-left: 18px;} - .order-search-fin a.order-seat:hover, .order-search-fin a.order-seat:active, .order-search-fin a.order-seat:focus{background-position: 10px -1096px;} - .sow-ipt-w table{table-layout:fixed; } - .sow-ipt-w tbody td{width:68px;} - .sow-ipt-w td a {height:20px;overflow:hidden;} - - /*²Æ¾­Ä£¿éµ÷Õû*/ - .finance-pt{border:1px solid #fff;display: block;float: left;height: 90px;overflow: hidden;width: 105px;} - .finance-form{border: 1px solid #d6dadd;width: 100%} - .finance-form th, .finance-form td{height: 21px;line-height: 21px;overflow: hidden;border: 1px solid #d6dadd} - .finance-form th{background-color: #f7f7f7;color: #113066;text-align: center;font-size: 14px;} - .finance-form td{color: #58677a;text-align: center;} - .finance-form a, .finance-form a:visited{color: #58677a} - .finance-form a:hover, .finance-form a:active, .finance-form a:focus{color: #ff8400} - .finance-form .num{text-align: right;padding-right: 10px;display: block;width: 54px;height: 21px;overflow: hidden;} - .finance-form .down, .finance-form .up{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat;} - .finance-form .down{background-position: 58px -1435px;} - .finance-form .up{background-position: 58px -1485px;} - - /*ÌåÓýÄ£¿éµ×²¿¹ã¸æ*/ - .nmod01 a:link,.nmod01 a:visited{color:#596a7b;} - .nmod01 a:hover,.nmod01 a:active{color:#e66100;} - /*¶¥²¿¹Ø±Õ*/ - .tn-close{float:right;height:21px;margin:8px 0 0 3px;line-height:21px;_line-height:22px;width:54px;height:21px;overflow:hidden;border:1px solid #E2E2E2;font-size:12px;} - .tn-close a{display:block;height:21px;} - .tn-close a:link,.tn-close a:visited{color:#A7A5A0;text-decoration:none;} - .tn-close a:hover,.tn-close a:active{color:#938F8F;text-decoration:none;} - .tn-close i{float:left;display:inline;width:17px;height:17px;margin:2px 5px 0 2px;_margin-right:3px; overflow:hidden;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 3px -994px no-repeat #BEBCBC;_zoom:1;} - .tn-close a:hover i{background-color:#938F8F;} - - /*new icon*/ - .top-nav .tn-new2{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -1539px no-repeat;width: 17px;height: 13px;} - .pro-new{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -1539px no-repeat;width: 17px;height: 13px;position: absolute;left: 54px;top: 9px;*top:3px;_left:51px;_zoom:1;} - - /*³ÇÊÐÁªÃË*/ - .city-union{width:998px;border:1px solid #e9e9e9;line-height:21px;background:#fffcf1;color:#e66100;} - .city-union .clearit{overflow:hidden;} - .city-union .name{width:120px;float:left;text-align:center;padding:16px 0 0;position:relative;font-family: "Microsoft YaHei", "΢ÈíÑźÚ", "SimHei", "ºÚÌå";font-size: 16px;} - .city-union .name a{color:#e66100} - .city-union .name a:hover{color:#ff8400} - .city-union .clist{background:#fff;float:left;padding:6px 0 6px 35px;width:842px;} - .city-union .clist a,.city-union .clist span{margin:0 6px 0 0;color: #596976} - .city-union .clist a:hover{color: #596976} - .city-union .clist a:hover, .city-union .clist a:active, .city-union .clist a:focus{color: #ff8400} - .city-union .c-hot .clist{background:#fff;border-top:1px solid #e9e9e9} - .city-union .c-hot .name{border-top:1px solid #e9e9e9;padding:6px 0} - - /* ͨÀ¸¹ã¸æ×Ô¶¯¸ß¶È */ - .ad-banner{ width:1000px; } - .mb25{ margin-bottom:25px} - - /*network supervision*/ - .hxjzg{width: 103px;height: 50px;background: url(http://i0.sinaimg.cn/home/2014/1030/hxjzg103.jpg) 0 0 no-repeat;margin: 0px 0 0 0;padding-right:5px;float:right;} - .nwsu_Wrap{width: 133px;height: 50px;float: right;margin: 0px 0 0 0;overflow:hidden;} - .nwsu-item{width: 133px;height: 50px;} - .nwsu{width: 133px;height: 50px;background: url(http://i2.sinaimg.cn/home/2014/1030/jb5.jpg) 0 0 no-repeat;margin: 0px 0 0 0;display:block;} - - .nwsu2{width: 133px;height: 50px;background: url(http://i3.sinaimg.cn/home/main/index2013/0509/bkjb.png) 0 0 no-repeat;margin: 0px 0 0 0;display:block;} - - .nwsu3{width: 133px;height: 50px;background: url(http://i3.sinaimg.cn/home/main/index2013/0509/jbicon.png) 0 0 no-repeat;margin: 0px 0 0 0;display:block;} - - /*suggest*/ - .inp-txt-wrap{position: relative;z-index: 1} - .top-suggest-wrap{position: absolute;border: 1px solid #c1c1c1;background: #fff;width: 258px;z-index: 3000;left: -1px;top:33px;-moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, .2); -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, .2); box-shadow: 3px 3px 3px rgba(0, 0, 0, .2);font-family: "Arial","SimSun","ËÎÌå";overflow: hidden;} - .top-suggest-wrap .top-suggest-item,.top-suggest-wrap .top-suggest-tip,.top-suggest-wrap .top-suggest-more{height: 26px;line-height: 26px;padding-left: 14px;overflow: hidden;} - .top-suggest-wrap .top-suggest-item{cursor: pointer;} - .top-suggest-wrap .top-suggest-mover{background-color: #ddd;color: #000;} - .top-suggest-wrap .top-suggest-tip{color: #000;line-height: 30px;height: 30px;border-bottom: 1px dashed #eee;} - .top-suggest-wrap .top-suggest-more{font-size: 12px;border-top: 1px dashed #eee;height: 30px;line-height: 30px;} - .top-suggest-more a{display: inline;} - /*.top-suggest-more a:link, .top-suggest-more a:visited{color: #000;} - .top-suggest-more a:hover, .top-suggest-more a:active, .top-suggest-more a:focus{color: #ff8400}*/ - .top-suggest-more .top-suggest-hotAll{float: left;margin-left: 0px;} - .top-suggest-more .top-suggest-toHomePage{float:right;margin-right: 10px;} - .weibo-suggest .top-suggest-more{display: block;} - .news-suggest .top-suggest-more{display: none;} - - /*guess modify*/ - .mod-guess-cont,.mod-weiboGuess-cont{width:360px;overflow: hidden;height:208px;} - .mod-guess-cont ul{width:360px;float: left;overflow: hidden;} - .mod-weiboGuess-cont ul{width:180px;float: left;overflow: hidden;} - .mod-guess-control{height:19px !important;overflow:hidden;float: right;padding: 0px !important;margin-top: 9px !important;} - .mod-guess-control a{width:19px;height: 19px;display: inline;float: left;background: #000;margin:0 5px;text-indent: -9999em;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat;} - - .mod-licaishiGuess-cont{width:360px;overflow: hidden;height:208px;} - .mod-licaishiGuess-cont ul{width:360px;float: left;overflow: hidden;} - .mod-licaishiGuess-cont {position: relative} - .mod-licaishiGuess-cont .lcs_b_logo {width:105px;height:63px;position:absolute;display:inline-block;z-index:99;right:0;top:0;} - - .selected .mod-guess-control a.mod-guess-prev{background-position: -146px -553px;} - .selected .mod-guess-control a.mod-guess-prev:hover{background-position: -148px -519px;} - .selected .mod-guess-control a.mod-guess-next{background-position: -172px -553px;} - .selected .mod-guess-control a.mod-guess-next:hover{background-position: -123px -519px;} - - .mod-guess-control a.mod-guess-prev{background-position: -146px -607px;} - .mod-guess-control a.mod-guess-prev:hover{background-position: -148px -581px;} - .mod-guess-control a.mod-guess-next{background-position: -172px -607px;} - .mod-guess-control a.mod-guess-next:hover{background-position: -123px -581px;} - - .mod-guess-control .mod-guess-dots{padding: 0px !important;height: 6px !important;overflow: hidden;margin-top: 7px !important;} - .mod-guess-dots span{width:6px !important;height:7px !important;display: inline;float: left;overflow:hidden;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -175px -525px no-repeat;margin: 0 3px;padding: 0px !important} - .mod-guess-control .mod-guess-dots span.current{background-position: -185px -525px;} - .mod-guess-dots{float: left;display: inline;} - - /*background-color #FAFAFC*/ - /* dz»Òµ×É« */ - /* - .uni-blk, .uni-blk .order-menu span.selected, .blk-line, .mod24-menu span.selected, .mod-a .tab-nav-a a.selected,.uni-blk-b .uni-blk-list02{background-color: #fafafc;} - .uni-blk-pic{border-color:#fafafc;} - - */ - /*ÎÒ°®¿´Í¼*/ - /* HACK ScrollPic ¶Ôdisplay:none³õʼ»¯Ê±£¬²»ÄÜÕýÈ·Éú³Édots*/ - .part-e .part-econt{width:1000px;height:201px;overflow: hidden;position:relative} - .scroll-pic-frame{height:164px;overflow: hidden;} - .scroll-pic-frame .scroll-item{position: relative;} - .scroll-pic-guess-wrap .scroll-item a{text-align: center;background: #F6F6F6;} - .scroll-pic-guess-wrap .scroll-img{display: inline-block; *display:table-cell;width:198px;height:132px;background: #F6F6F6;text-align: center;cursor: pointer;overflow:hidden;position: relative;} - .scroll-pic-guess-wrap .scroll-img img{display: inline-block;*margin-top:-30px;border: none;vertical-align: middle;max-height: 100%;max-width: 100%;} - .scroll-pic-guess-wrap i{display: inline-block;height: 100%;line-height: 132px; vertical-align: middle;font-size: 0;} - .scroll-loading{width:1000px;height:132px;overflow: hidden;} - -/* ʱÉÐÈȵã */ - .xb-mod22-cont-pa{position:relative;zoom:1;width:220px;height:160px;} - .xb-mod22-cont-pa a{display:block;position:relative;zoom:1;width:220px;height:160px;} - .xb-mod22-cont-pa a:link,.xb-mod22-cont-pa a:visited{color:#fff;text-decoration:none;} - .xb-mod22-cont-pa a:hover{color:#fff;text-decoration:underline;} - .xb-mod22-cont-pa img{display:block;width:220px;height:160px;} - .xb-mod22-cont-pa span{cursor:pointer;zoom:1;position:absolute;left:0;bottom:0;display:block;width:220px;height:30px;font:500 14px/30px 'Microsoft Yahei','΢ÈíÑźÚ','Simsun','ËÎÌå';text-align:center;background:rgba(0,0,0,0.5);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#88000000',endColorstr='#88000000')\9;} - :root .xb-mod22-cont-pa span{filter:none\9;} - .xb-mod22-cont-pa a:hover span{text-decoration:underline;} - - /* 0904 side-btns-closer begin */ - .side-btns-wrap .side-btns-closer {height: 18px;overflow: hidden;clear: both;} - .side-btns-wrap .side-btns-closer a {display: block;width: 100%;height: 18px;overflow: hidden;line-height: 300px;background: url(http://i3.sinaimg.cn/dy/deco/2013/0913/close2.png) 0 0 no-repeat;} - .side-btns-wrap .side-btns-closer a:link, .side-btns-wrap .side-btns-closer a:visited {} - .side-btns-wrap .side-btns-closer a:hover, .side-btns-wrap .side-btns-closer a:active, .side-btns-wrap .side-btns-closer a:focus {opacity: 0.8;filter:alpha(opacity=80);} - /* 0904 side-btns-closer end */ - - /* 0909 history pictures begin */ - .history-pics-wrap {} - .history-pics-wrap .history-pics-arrleft-wrap, .history-pics-wrap .history-pics-arrright-wrap, .history-pics-wrap .history-pics-frame {float: left;display: inline;} - .history-pics-wrap .history-pics-arrleft-wrap, .history-pics-wrap .history-pics-arrright-wrap {width: 19px;} - .history-pics-wrap .history-pics-arrleft, .history-pics-wrap .history-pics-arrright{width: 19px;height: 26px;overflow: hidden;background: url(http://i3.sinaimg.cn/home/main/index2013/0904/history_arr.png) 0 0 no-repeat;display: block;margin-top: 35px;} - .history-pics-wrap .history-pics-arrleft{background-position: 0 0;} - .history-pics-wrap .history-pics-arrleft:hover{background-position: 0 -41px;} - .history-pics-wrap .history-pics-arrright{background-position: -12px 0;} - .history-pics-wrap .history-pics-arrright:hover{background-position: -12px -41px;} - .history-pics-wrap .history-pics-frame{width: 180px;overflow: hidden;} - .history-pics-wrap .history-pics-frame .history-pics-box{} - .history-pics-wrap .history-pics-frame .history-pics-item{float: left;display: inline;width: 180px;} - .history-pics-wrap .history-pics-item a {display: block;} - .history-pics-wrap .history-pics-item span {height: 21px;line-height: 21px;background-color: #000;text-align:center;display: block;} - .history-pics-wrap .history-pics-item a:link, .history-pics-wrap .history-pics-item a:visited{color: #fff;} - .history-pics-wrap .history-pics-item a:hover, .history-pics-wrap .history-pics-item a:focus, .history-pics-wrap .history-pics-item a:active{ color: #ff8400;text-decoration: none;} - .history-pics-wrap .history-pics-item a:link span, .history-pics-wrap .history-pics-item a:visited span{color: #fff;} - .history-pics-wrap .history-pics-item a:hover span, .history-pics-wrap .history-pics-item a:focus span, .history-pics-wrap .history-pics-item a:active span{ color: #ff8400;text-decoration: none;} - /* 0909 history pictures end */ - - .uni-blk-t .t-guidechange a{ - display: block; - width: 37px; - height: 34px; - padding-left: 25px; - background: url("http://i1.sinaimg.cn/dy/main/icon/changeicon_red4.png") 7px -26px no-repeat; - border-left: 1px solid #dbdee1; - color: #ff0000; - } - .uni-blk-t .t-guidechange a:visited{color: #ff0000;} - .uni-blk-t .t-guidechange a:hover{background: url("http://i1.sinaimg.cn/dy/main/icon/changeicon_red4.png") 7px -26px no-repeat;color: #ff0000;} - - /*addÆû³µÆµµÀ*/ - .selectCar{margin:8px 0;} - .selectLeft,.selectRight{float:left;} - .selectLeft{width:180px;} - .selectLeft form{float:left;width:140px;} - .selectLeft .sim-select{float: left;display: inline;width: 140px;margin-bottom:8px;background:#fff;position:relative;} - .selectLeft .sim-select h3{font-weight: normal;color: #333;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 120px -840px no-repeat;height: 30px;line-height: 30px;border: 1px solid #cdcdcd;width: 132px;padding-left: 8px;font-size: 12px;cursor: pointer;} - .selectLeft .sim-select .sim-ul-flt{} - .selectLeft .sim-select ul{top: 32px;left: 0px;background:#fff;} - .selectLeft .sim-select li{width: 132px;height: 30px;line-height: 30px;padding-left: 8px;color: #333;} - .selectLeft .selectBtn{width:140px;height:30px;line-height:30px;text-align:center;background:#ff8400;float:left;overflow:hidden;} - .selectLeft .selectBtn input{display:block;width:140px;height:30px;background:none;border:none;color:#fff;font-size:14px;} - .selectLeft .selectBtn input:hover{cursor:pointer;} - .selectLeft .carIndex{float:left;width:24px;margin:4px 10px 0 0;position:relative;} - .selectLeft span{width:24px;text-align:center;overflow:hidden;display:block;} - .selectLeft .carGap{background:#ebebeb;width:2px;height:16px;margin:0 auto;} - .selectLeft .carDot{width:24px;height:24px;line-height:24px;color:#cdcdcd;font-size:14px;background:url(http://i0.sinaimg.cn/home/main/index2013/0127/carIndex.jpg) 0px -113px no-repeat;} - .selectLeft .able{background-position:0px 0px;color:#fff;} - .selectRight{width:168px;padding-left:12px;} - .selectRight .cbox li{width:54px;overflow:hidden;float:left;text-align:center;} - .selectRight .cbox li a{line-height:26px;display: block;} - .selectRight .cbox .cborder{border-left:1px solid #eee;border-right:1px solid #eee;} - .selectRight .cbox2 a,.selectRight .cbox2 span{float:left;} - .selectRight .cbox2 span{padding:0 6px;} - .selectRight .cbox2 p{line-height:24px;} - .selectRight .cbox2 .clearfix{padding-left:8px;} - - .selectRight a:link{color:#122E67;text-decoration:none;} - .selectRight a:visited{color:#52687e;text-decoration:none;} - .selectRight a:hover,.list-a a:active{color:#ff8400;text-decoration:underline;} - - .carPics {padding-top:10px;position:absolute;background:#fff;} - .carPics .carPicL,.carPics .carPicR{float:left;height:360px;overflow:hidden;} - .carPics .carPicL .uni-blk-pic,.carPics .carPicL .uni-blk-pic span{width:160px;} - .carPics .carPicL{width:162px;margin-right:6px;} - .carPics .uni-blk-pic{margin-bottom:10px;} - .carPics .carPicR{width:192px;} - .carPics .carPicR .uni-blk-pic,.carPics .carPicR .uni-blk-pic span{width:190px;} - .carPics .carh1{height:108px;} - .carPics .carh2{height:238px;} - .carPics .carh3,.carPics .carh4{width:180px;display:block;text-align:left;margin-bottom:10px;float:left; padding-left:10px;} - .carPics .carh3{height:32px;font-size:16px;background:#ff8400;line-height:32px;} - .carPics .carh4{height:46px;background:#2375e2;} - .carPics .carh4 p{line-height:22px;} - .carPics .carh4 span{line-height:22px;display:block} - .carPics .carh3 a,.carPics .carh4 a{color:#fff;} - .carPics .carh5{height:124px;} - - span#SI_IP_Auto_City_Title{color:#58677a;} - - /* 0204 ÐÞ¸Ä ¿Æ¼¼ ʶȤ°å¿é */ - .shiqu-ml{ margin-left: 19px; margin-bottom: 7px; _margin-bottom: 0px; } - .shiqu-mt{ _margin-top: -3px; } - - /* 0316 ÐÞ¸Ä Í¼Æ¬ B °æ */ - #fc_B_pic{ position: relative; z-index: 98; } - #fc_B_pic_attachment{ position: absolute; margin: 13px 0 0 -1px; width: 361px; height: 250px; z-index: 99; overflow: hidden; background-color: white; } - .fc-B-pic-a-header{ border-left: solid 1px #dbdee1; border-top: solid 1px #dbdee1; border-bottom: solid 1px #dbdee1; height: 34px; background-color: #fafafa; } - .fc-B-pic-a-header a{ height: 34px; line-height: 34px; border-right: solid 1px #dbdee1; font-size: 14px; text-align: center; color: #333; } - .fc-B-pic-a-header a:hover{ color: #ff8400; text-decoration: none; } - .fc-B-pic-ah-hover{ border-bottom: solid 1px #fff; color: #ff8400!important; background-color: #fff; text-decoration: none!important; } - .fc-bpah-items{ float: left; width: 63px; } - .fc-bpah-fr{ float: right; width: 102px; text-indent: 15px; background: url(http://i0.sinaimg.cn/home/2015/0401/bg.png) no-repeat 10px 10px; color: #333; text-decoration: none; } - .fc-bpah-fr:hover{ color: #ff8400; text-decoration: none; background-position: 10px -25px; } - .fc-bpah-fr-hover{ color: #ff8400!important; background-position: 10px -25px; background-color: #fff!important; text-decoration: none!important; border-bottom: solid 1px #fff!important; } - - .fc-B-pic-a-cont{ width: 400px; margin-top: 18px; } - .fc-B-pic-a-cont a{ float: left; width: 105px; height: 70px; position: relative; overflow: hidden; border: solid 1px #fff; margin: 0 19px 28px 0; color: #fff; } - .fc-B-pic-a-cont a:visited{ color: #fff; } - .fc-B-pic-a-cont a:hover{ border-color: #e66100; color: #ff8400; } - .fc-B-pic-a-cont a:hover span{text-decoration: none; font-style: none; outline: none; } - .fc-B-pic-a-cont a img{ width: 100%; height: 100%; } - .fc-B-pic-a-cont a span{ position: absolute; width: 100%; height: 20px; bottom: 0px; left: 0; text-align: center; font-size: 12px; line-height: 20px; text-decoration: none!important; } - .fc-B-pic-a-cont a span.fc-bpac-bg{ background-color: #000; opacity: 0.7; _filter: alpha(opacity=70); } - .uni-blk-t .t-guide{outline: none!important;} - -/* - .fc-B-pic-a-intr{ position: absolute; width: 370px; top: 54px; left: 0; background-color: #fff; } - .fc-B-pic-a-intr a{ font-size: 14px; color: #333; line-height: 14px; float: left; height: 14px; width: 90px; text-align: center; margin-bottom: 20px; } - .fc-B-pic-a-intr a:hover{ color: #ff8400; text-decoration: none; } - .fc-B-pic-a-submit{ border-top: solid 1px #dbdee1; margin-top: -5px; padding-top: 15px; width: 360px; float: left; } - .fc-B-pic-a-submit span{ font-size: 14px; color: #666; line-height: 28px; } - a#fc_bpac_submit{ float: right; font-size: 14px; color: #fff; width: 70px; height: 28px; background-color: #ff8400; text-align: center; line-height: 28px; } - a#fc_bpac_submit:hover{ background-color: #ff9900; } - a.fc-B-pic-ai-hover{ color: #ff8400; background: url(http://i0.sinaimg.cn/home/2015/0401/bg.png) no-repeat 8px -73px; } -*/ - - </style> - -<script language="javascript" type="text/javascript"> -//<![CDATA[ -document.domain = "sina.com.cn"; -//]]> -</script> - -<script> - (function (d, s, id) { - var s, n = d.getElementsByTagName(s)[0]; - if (d.getElementById(id)) return; - s = d.createElement(s); - s.id = id; - s.setAttribute('charset', 'utf-8'); - s.src = '//d' + Math.floor(0 + Math.random() * (9 - 0 + 1)) + '.sina.com.cn/litong/zhitou/sinaads/release/sinaads.js'; - n.parentNode.insertBefore(s, n); - })(document, 'script', 'sinaads-script'); -</script> - -</head> -<body><!-- body code begin --> - -<!-- SUDA_CODE_START --> -<script type="text/javascript"> -//<!-- -(function(){var an="V=2.1.15";var ah=window,F=document,s=navigator,W=s.userAgent,ao=ah.screen,j=ah.location.href;var aD="https:"==ah.location.protocol?"https://s":"http://",ay="beacon.sina.com.cn";var N=aD+ay+"/a.gif?",z=aD+ay+"/g.gif?",R=aD+ay+"/f.gif?",ag=aD+ay+"/e.gif?",aB=aD+"beacon.sinauda.com/i.gif?";var aA=F.referrer.toLowerCase();var aa="SINAGLOBAL",Y="FSINAGLOBAL",H="Apache",P="ULV",l="SUP",aE="UOR",E="_s_acc",X="_s_tentry",n=false,az=false,B=(document.domain=="sina.com.cn")?true:false;var o=0;var aG=false,A=false;var al="";var m=16777215,Z=0,C,K=0;var r="",b="",a="";var M=[],S=[],I=[];var u=0;var v=0;var p="";var am=false;var w=false;function O(){var e=document.createElement("iframe");e.src=aD+ay+"/data.html?"+new Date().getTime();e.id="sudaDataFrame";e.style.height="0px";e.style.width="1px";e.style.overflow="hidden";e.frameborder="0";e.scrolling="no";document.getElementsByTagName("head")[0].appendChild(e)}function k(){var e=document.createElement("iframe");e.src=aD+ay+"/ckctl.html";e.id="ckctlFrame";e.style.height="0px";e.style.width="1px";e.style.overflow="hidden";e.frameborder="0";e.scrolling="no";document.getElementsByTagName("head")[0].appendChild(e)}function q(){var e=document.createElement("script");e.src=aD+ay+"/h.js";document.getElementsByTagName("head")[0].appendChild(e)}function h(aH,i){var D=F.getElementsByName(aH);var e=(i>0)?i:0;return(D.length>e)?D[e].content:""}function aF(){var aJ=F.getElementsByName("sudameta");var aR=[];for(var aO=0;aO<aJ.length;aO++){var aK=aJ[aO].content;if(aK){if(aK.indexOf(";")!=-1){var D=aK.split(";");for(var aH=0;aH<D.length;aH++){var aP=aw(D[aH]);if(!aP){continue}aR.push(aP)}}else{aR.push(aK)}}}var aM=F.getElementsByTagName("meta");for(var aO=0,aI=aM.length;aO<aI;aO++){var aN=aM[aO];if(aN.name=="tags"){aR.push("content_tags:"+encodeURI(aN.content))}}var aL=t("vjuids");aR.push("vjuids:"+aL);var e="";var aQ=j.indexOf("#");if(aQ!=-1){e=escape(j.substr(aQ+1))}aR.push("hashtag:"+e);return aR}function V(aK,D,aI,aH){if(aK==""){return""}aH=(aH=="")?"=":aH;D+=aH;var aJ=aK.indexOf(D);if(aJ<0){return""}aJ+=D.length;var i=aK.indexOf(aI,aJ);if(i<aJ){i=aK.length}return aK.substring(aJ,i)}function t(e){if(undefined==e||""==e){return""}return V(F.cookie,e,";","")}function at(aI,e,i,aH){if(e!=null){if((undefined==aH)||(null==aH)){aH="sina.com.cn"}if((undefined==i)||(null==i)||(""==i)){F.cookie=aI+"="+e+";domain="+aH+";path=/"}else{var D=new Date();var aJ=D.getTime();aJ=aJ+86400000*i;D.setTime(aJ);aJ=D.getTime();F.cookie=aI+"="+e+";domain="+aH+";expires="+D.toUTCString()+";path=/"}}}function f(D){try{var i=document.getElementById("sudaDataFrame").contentWindow.storage;return i.get(D)}catch(aH){return false}}function ar(D,aH){try{var i=document.getElementById("sudaDataFrame").contentWindow.storage;i.set(D,aH);return true}catch(aI){return false}}function L(){var aJ=15;var D=window.SUDA.etag;if(!B){return"-"}if(u==0){O();q()}if(D&&D!=undefined){w=true}ls_gid=f(aa);if(ls_gid===false||w==false){return false}else{am=true}if(ls_gid&&ls_gid.length>aJ){at(aa,ls_gid,3650);n=true;return ls_gid}else{if(D&&D.length>aJ){at(aa,D,3650);az=true}var i=0,aI=500;var aH=setInterval((function(){var e=t(aa);if(w){e=D}i+=1;if(i>3){clearInterval(aH)}if(e.length>aJ){clearInterval(aH);ar(aa,e)}}),aI);return w?D:t(aa)}}function U(e,aH,D){var i=e;if(i==null){return false}aH=aH||"click";if((typeof D).toLowerCase()!="function"){return}if(i.attachEvent){i.attachEvent("on"+aH,D)}else{if(i.addEventListener){i.addEventListener(aH,D,false)}else{i["on"+aH]=D}}return true}function af(){if(window.event!=null){return window.event}else{if(window.event){return window.event}var D=arguments.callee.caller;var i;var aH=0;while(D!=null&&aH<40){i=D.arguments[0];if(i&&(i.constructor==Event||i.constructor==MouseEvent||i.constructor==KeyboardEvent)){return i}aH++;D=D.caller}return i}}function g(i){i=i||af();if(!i.target){i.target=i.srcElement;i.pageX=i.x;i.pageY=i.y}if(typeof i.layerX=="undefined"){i.layerX=i.offsetX}if(typeof i.layerY=="undefined"){i.layerY=i.offsetY}return i}function aw(aH){if(typeof aH!=="string"){throw"trim need a string as parameter"}var e=aH.length;var D=0;var i=/(\u3000|\s|\t|\u00A0)/;while(D<e){if(!i.test(aH.charAt(D))){break}D+=1}while(e>D){if(!i.test(aH.charAt(e-1))){break}e-=1}return aH.slice(D,e)}function c(e){return Object.prototype.toString.call(e)==="[object Array]"}function J(aH,aL){var aN=aw(aH).split("&");var aM={};var D=function(i){if(aL){try{return decodeURIComponent(i)}catch(aP){return i}}else{return i}};for(var aJ=0,aK=aN.length;aJ<aK;aJ++){if(aN[aJ]){var aI=aN[aJ].split("=");var e=aI[0];var aO=aI[1];if(aI.length<2){aO=e;e="$nullName"}if(!aM[e]){aM[e]=D(aO)}else{if(c(aM[e])!=true){aM[e]=[aM[e]]}aM[e].push(D(aO))}}}return aM}function ac(D,aI){for(var aH=0,e=D.length;aH<e;aH++){aI(D[aH],aH)}}function ak(i){var e=new RegExp("^http(?:s)?://([^/]+)","im");if(i.match(e)){return i.match(e)[1].toString()}else{return""}}function aj(aO){try{var aL="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var D="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";var aQ=function(e){var aR="",aS=0;for(;aS<e.length;aS++){aR+="%"+aH(e[aS])}return decodeURIComponent(aR)};var aH=function(e){var i="0"+e.toString(16);return i.length<=2?i:i.substr(1)};var aP=function(aY,aV,aR){if(typeof(aY)=="string"){aY=aY.split("")}var aX=function(a7,a9){for(var a8=0;a8<a7.length;a8++){if(a7[a8]==a9){return a8}}return -1};var aS=[];var a6,a4,a1="";var a5,a3,a0,aZ="";if(aY.length%4!=0){}var e=/[^A-Za-z0-9\+\/\=]/g;var a2=aL.split("");if(aV=="urlsafe"){e=/[^A-Za-z0-9\-_\=]/g;a2=D.split("")}var aU=0;if(aV=="binnary"){a2=[];for(aU=0;aU<=64;aU++){a2[aU]=aU+128}}if(aV!="binnary"&&e.exec(aY.join(""))){return aR=="array"?[]:""}aU=0;do{a5=aX(a2,aY[aU++]);a3=aX(a2,aY[aU++]);a0=aX(a2,aY[aU++]);aZ=aX(a2,aY[aU++]);a6=(a5<<2)|(a3>>4);a4=((a3&15)<<4)|(a0>>2);a1=((a0&3)<<6)|aZ;aS.push(a6);if(a0!=64&&a0!=-1){aS.push(a4)}if(aZ!=64&&aZ!=-1){aS.push(a1)}a6=a4=a1="";a5=a3=a0=aZ=""}while(aU<aY.length);if(aR=="array"){return aS}var aW="",aT=0;for(;aT<aS.lenth;aT++){aW+=String.fromCharCode(aS[aT])}return aW};var aI=[];var aN=aO.substr(0,3);var aK=aO.substr(3);switch(aN){case"v01":for(var aJ=0;aJ<aK.length;aJ+=2){aI.push(parseInt(aK.substr(aJ,2),16))}return decodeURIComponent(aQ(aP(aI,"binnary","array")));break;case"v02":aI=aP(aK,"urlsafe","array");return aQ(aP(aI,"binnary","array"));break;default:return decodeURIComponent(aO)}}catch(aM){return""}}var ap={screenSize:function(){return(m&8388608==8388608)?ao.width+"x"+ao.height:""},colorDepth:function(){return(m&4194304==4194304)?ao.colorDepth:""},appCode:function(){return(m&2097152==2097152)?s.appCodeName:""},appName:function(){return(m&1048576==1048576)?((s.appName.indexOf("Microsoft Internet Explorer")>-1)?"MSIE":s.appName):""},cpu:function(){return(m&524288==524288)?(s.cpuClass||s.oscpu):""},platform:function(){return(m&262144==262144)?(s.platform):""},jsVer:function(){if(m&131072!=131072){return""}var aI,e,aK,D=1,aH=0,i=(s.appName.indexOf("Microsoft Internet Explorer")>-1)?"MSIE":s.appName,aJ=s.appVersion;if("MSIE"==i){e="MSIE";aI=aJ.indexOf(e);if(aI>=0){aK=window.parseInt(aJ.substring(aI+5));if(3<=aK){D=1.1;if(4<=aK){D=1.3}}}}else{if(("Netscape"==i)||("Opera"==i)||("Mozilla"==i)){D=1.3;e="Netscape6";aI=aJ.indexOf(e);if(aI>=0){D=1.5}}}return D},network:function(){if(m&65536!=65536){return""}var i="";i=(s.connection&&s.connection.type)?s.connection.type:i;try{F.body.addBehavior("#default#clientCaps");i=F.body.connectionType}catch(D){i="unkown"}return i},language:function(){return(m&32768==32768)?(s.systemLanguage||s.language):""},timezone:function(){return(m&16384==16384)?(new Date().getTimezoneOffset()/60):""},flashVer:function(){if(m&8192!=8192){return""}var aK=s.plugins,aH,aL,aN;if(aK&&aK.length){for(var aJ in aK){aL=aK[aJ];if(aL.description==null){continue}if(aH!=null){break}aN=aL.description.toLowerCase();if(aN.indexOf("flash")!=-1){aH=aL.version?parseInt(aL.version):aN.match(/\d+/);continue}}}else{if(window.ActiveXObject){for(var aI=10;aI>=2;aI--){try{var D=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+aI);if(D){aH=aI;break}}catch(aM){}}}else{if(W.indexOf("webtv/2.5")!=-1){aH=3}else{if(W.indexOf("webtv")!=-1){aH=2}}}}return aH},javaEnabled:function(){if(m&4096!=4096){return""}var D=s.plugins,i=s.javaEnabled(),aH,aI;if(i==true){return 1}if(D&&D.length){for(var e in D){aH=D[e];if(aH.description==null){continue}if(i!=null){break}aI=aH.description.toLowerCase();if(aI.indexOf("java plug-in")!=-1){i=parseInt(aH.version);continue}}}else{if(window.ActiveXObject){i=(new ActiveXObject("JavaWebStart.IsInstalled")!=null)}}return i?1:0}};var ad={pageId:function(i){var D=i||r,aK="-9999-0-0-1";if((undefined==D)||(""==D)){try{var aH=h("publishid");if(""!=aH){var aJ=aH.split(",");if(aJ.length>0){if(aJ.length>=3){aK="-9999-0-"+aJ[1]+"-"+aJ[2]}D=aJ[0]}}else{D="0"}}catch(aI){D="0"}D=D+aK}return D},sessionCount:function(){var e=t("_s_upa");if(e==""){e=0}return e},excuteCount:function(){return SUDA.sudaCount},referrer:function(){if(m&2048!=2048){return""}var e=/^[^\?&#]*.swf([\?#])?/;if((aA=="")||(aA.match(e))){var i=V(j,"ref","&","");if(i!=""){return escape(i)}}return escape(aA)},isHomepage:function(){if(m&1024!=1024){return""}var D="";try{F.body.addBehavior("#default#homePage");D=F.body.isHomePage(j)?"Y":"N"}catch(i){D="unkown"}return D},PGLS:function(){return(m&512==512)?h("stencil"):""},ZT:function(){if(m&256!=256){return""}var e=h("subjectid");e.replace(",",".");e.replace(";",",");return escape(e)},mediaType:function(){return(m&128==128)?h("mediaid"):""},domCount:function(){return(m&64==64)?F.getElementsByTagName("*").length:""},iframeCount:function(){return(m&32==32)?F.getElementsByTagName("iframe").length:""}};var av={visitorId:function(){var i=15;var e=t(aa);if(e.length>i&&u==0){return e}else{return}},fvisitorId:function(e){if(!e){var e=t(Y);return e}else{at(Y,e,3650)}},sessionId:function(){var e=t(H);if(""==e){var i=new Date();e=Math.random()*10000000000000+"."+i.getTime()}return e},flashCookie:function(e){if(e){}else{return p}},lastVisit:function(){var D=t(H);var aI=t(P);var aH=aI.split(":");var aJ="",i;if(aH.length>=6){if(D!=aH[4]){i=new Date();var e=new Date(window.parseInt(aH[0]));aH[1]=window.parseInt(aH[1])+1;if(i.getMonth()!=e.getMonth()){aH[2]=1}else{aH[2]=window.parseInt(aH[2])+1}if(((i.getTime()-e.getTime())/86400000)>=7){aH[3]=1}else{if(i.getDay()<e.getDay()){aH[3]=1}else{aH[3]=window.parseInt(aH[3])+1}}aJ=aH[0]+":"+aH[1]+":"+aH[2]+":"+aH[3];aH[5]=aH[0];aH[0]=i.getTime();at(P,aH[0]+":"+aH[1]+":"+aH[2]+":"+aH[3]+":"+D+":"+aH[5],360)}else{aJ=aH[5]+":"+aH[1]+":"+aH[2]+":"+aH[3]}}else{i=new Date();aJ=":1:1:1";at(P,i.getTime()+aJ+":"+D+":",360)}return aJ},userNick:function(){if(al!=""){return al}var D=unescape(t(l));if(D!=""){var i=V(D,"ag","&","");var e=V(D,"user","&","");var aH=V(D,"uid","&","");var aJ=V(D,"sex","&","");var aI=V(D,"dob","&","");al=i+":"+e+":"+aH+":"+aJ+":"+aI;return al}else{return""}},userOrigin:function(){if(m&4!=4){return""}var e=t(aE);var i=e.split(":");if(i.length>=2){return i[0]}else{return""}},advCount:function(){return(m&2==2)?t(E):""},setUOR:function(){var aL=t(aE),aP="",i="",aO="",aI="",aM=j.toLowerCase(),D=F.referrer.toLowerCase();var aQ=/[&|?]c=spr(_[A-Za-z0-9]{1,}){3,}/;var aK=new Date();if(aM.match(aQ)){aO=aM.match(aQ)[0]}else{if(D.match(aQ)){aO=D.match(aQ)[0]}}if(aO!=""){aO=aO.substr(3)+":"+aK.getTime()}if(aL==""){if(t(P)==""){aP=ak(D);i=ak(aM)}at(aE,aP+","+i+","+aO,365)}else{var aJ=0,aN=aL.split(",");if(aN.length>=1){aP=aN[0]}if(aN.length>=2){i=aN[1]}if(aN.length>=3){aI=aN[2]}if(aO!=""){aJ=1}else{var aH=aI.split(":");if(aH.length>=2){var e=new Date(window.parseInt(aH[1]));if(e.getTime()<(aK.getTime()-86400000*30)){aJ=1}}}if(aJ){at(aE,aP+","+i+","+aO,365)}}},setAEC:function(e){if(""==e){return}var i=t(E);if(i.indexOf(e+",")<0){i=i+e+","}at(E,i,7)},ssoInfo:function(){var D=unescape(aj(t("sso_info")));if(D!=""){if(D.indexOf("uid=")!=-1){var i=V(D,"uid","&","");return escape("uid:"+i)}else{var e=V(D,"u","&","");return escape("u:"+unescape(e))}}else{return""}},subp:function(){return t("SUBP")}};var ai={CI:function(){var e=["sz:"+ap.screenSize(),"dp:"+ap.colorDepth(),"ac:"+ap.appCode(),"an:"+ap.appName(),"cpu:"+ap.cpu(),"pf:"+ap.platform(),"jv:"+ap.jsVer(),"ct:"+ap.network(),"lg:"+ap.language(),"tz:"+ap.timezone(),"fv:"+ap.flashVer(),"ja:"+ap.javaEnabled()];return"CI="+e.join("|")},PI:function(e){var i=["pid:"+ad.pageId(e),"st:"+ad.sessionCount(),"et:"+ad.excuteCount(),"ref:"+ad.referrer(),"hp:"+ad.isHomepage(),"PGLS:"+ad.PGLS(),"ZT:"+ad.ZT(),"MT:"+ad.mediaType(),"keys:","dom:"+ad.domCount(),"ifr:"+ad.iframeCount()];return"PI="+i.join("|")},UI:function(){var e=["vid:"+av.visitorId(),"sid:"+av.sessionId(),"lv:"+av.lastVisit(),"un:"+av.userNick(),"uo:"+av.userOrigin(),"ae:"+av.advCount(),"lu:"+av.fvisitorId(),"si:"+av.ssoInfo(),"rs:"+(n?1:0),"dm:"+(B?1:0),"su:"+av.subp()];return"UI="+e.join("|")},EX:function(i,e){if(m&1!=1){return""}i=(null!=i)?i||"":b;e=(null!=e)?e||"":a;return"EX=ex1:"+i+"|ex2:"+e},MT:function(){return"MT="+aF().join("|")},V:function(){return an},R:function(){return"gUid_"+new Date().getTime()}};function ax(){var aK="-",aH=F.referrer.toLowerCase(),D=j.toLowerCase();if(""==t(X)){if(""!=aH){aK=ak(aH)}at(X,aK,"","weibo.com")}var aI=/weibo.com\/reg.php/;if(D.match(aI)){var aJ=V(unescape(D),"sharehost","&","");var i=V(unescape(D),"appkey","&","");if(""!=aJ){at(X,aJ,"","weibo.com")}at("appkey",i,"","weibo.com")}}function d(e,i){G(e,i)}function G(i,D){D=D||{};var e=new Image(),aH;if(D&&D.callback&&typeof D.callback=="function"){e.onload=function(){clearTimeout(aH);aH=null;D.callback(true)}}SUDA.img=e;e.src=i;aH=setTimeout(function(){if(D&&D.callback&&typeof D.callback=="function"){D.callback(false);e.onload=null}},D.timeout||2000)}function x(e,aH,D){SUDA.sudaCount++;if(!av.visitorId()&&!L()){if(u<3){u++;setTimeout(x,500);return}}var i=N+[ai.V(),ai.CI(),ai.PI(e),ai.UI(),ai.MT(),ai.EX(aH,D),ai.R()].join("&");G(i);if(window.location.host.search("auto.sina.com.cn")>=0){wrating_url="http://m.wrating.com/m.gif?a=&c=860010-2370010112&mcookie="+av.visitorId()+"&"+ai.R()+"=";G(wrating_url)}}function y(e,D,i){if(aG||A){return}if(SUDA.sudaCount!=0){return}x(e,D,i)}function ab(e,aH){if((""==e)||(undefined==e)){return}av.setAEC(e);if(0==aH){return}var D="AcTrack||"+t(aa)+"||"+t(H)+"||"+av.userNick()+"||"+e+"||";var i=ag+D+"&gUid_"+new Date().getTime();d(i)}function aq(aI,e,i,aJ){aJ=aJ||{};if(!i){i=""}else{i=escape(i)}var aH="UATrack||"+t(aa)+"||"+t(H)+"||"+av.userNick()+"||"+aI+"||"+e+"||"+ad.referrer()+"||"+i+"||"+(aJ.realUrl||"")+"||"+(aJ.ext||"");var D=ag+aH+"&gUid_"+new Date().getTime();d(D,aJ)}function aC(aK){var i=g(aK);var aI=i.target;var aH="",aL="",D="";var aJ;if(aI!=null&&aI.getAttribute&&(!aI.getAttribute("suda-uatrack")&&!aI.getAttribute("suda-actrack")&&!aI.getAttribute("suda-data"))){while(aI!=null&&aI.getAttribute&&(!!aI.getAttribute("suda-uatrack")||!!aI.getAttribute("suda-actrack")||!!aI.getAttribute("suda-data"))==false){if(aI==F.body){return}aI=aI.parentNode}}if(aI==null||aI.getAttribute==null){return}aH=aI.getAttribute("suda-actrack")||"";aL=aI.getAttribute("suda-uatrack")||aI.getAttribute("suda-data")||"";sudaUrls=aI.getAttribute("suda-urls")||"";if(aL){aJ=J(aL);if(aI.tagName.toLowerCase()=="a"){D=aI.href}opts={};opts.ext=(aJ.ext||"");aJ.key&&SUDA.uaTrack&&SUDA.uaTrack(aJ.key,aJ.value||aJ.key,D,opts)}if(aH){aJ=J(aH);aJ.key&&SUDA.acTrack&&SUDA.acTrack(aJ.key,aJ.value||aJ.key)}}if(window.SUDA&&Object.prototype.toString.call(window.SUDA)==="[object Array]"){for(var Q=0,ae=SUDA.length;Q<ae;Q++){switch(SUDA[Q][0]){case"setGatherType":m=SUDA[Q][1];break;case"setGatherInfo":r=SUDA[Q][1]||r;b=SUDA[Q][2]||b;a=SUDA[Q][3]||a;break;case"setPerformance":Z=SUDA[Q][1];break;case"setPerformanceFilter":C=SUDA[Q][1];break;case"setPerformanceInterval":K=SUDA[Q][1]*1||0;K=isNaN(K)?0:K;break;case"setGatherMore":M.push(SUDA[Q].slice(1));break;case"acTrack":S.push(SUDA[Q].slice(1));break;case"uaTrack":I.push(SUDA[Q].slice(1));break}}}aG=(function(D,i){if(ah.top==ah){return false}else{try{if(F.body.clientHeight==0){return false}return((F.body.clientHeight>=D)&&(F.body.clientWidth>=i))?false:true}catch(aH){return true}}})(320,240);A=(function(){return false})();av.setUOR();var au=av.sessionId();window.SUDA=window.SUDA||[];SUDA.sudaCount=SUDA.sudaCount||0;SUDA.log=function(){x.apply(null,arguments)};SUDA.acTrack=function(){ab.apply(null,arguments)};SUDA.uaTrack=function(){aq.apply(null,arguments)};U(F.body,"click",aC);window.GB_SUDA=SUDA;GB_SUDA._S_pSt=function(){};GB_SUDA._S_acTrack=function(){ab.apply(null,arguments)};GB_SUDA._S_uaTrack=function(){aq.apply(null,arguments)};window._S_pSt=function(){};window._S_acTrack=function(){ab.apply(null,arguments)};window._S_uaTrack=function(){aq.apply(null,arguments)};window._S_PID_="";y();try{k()}catch(T){}})(); -//--> -</script> -<noScript> -<div style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden'><img width=0 height=0 src='http://beacon.sina.com.cn/a.gif?noScript' border='0' alt='' /></div> -</noScript> -<!-- SUDA_CODE_END --> - -<!-- SSO_GETCOOKIE_START --> -<script type="text/javascript">var sinaSSOManager=sinaSSOManager||{};sinaSSOManager.getSinaCookie=function(){function dc(u){if(u==undefined){return""}var decoded=decodeURIComponent(u);return decoded=="null"?"":decoded}function ps(str){var arr=str.split("&");var arrtmp;var arrResult={};for(var i=0;i<arr.length;i++){arrtmp=arr[i].split("=");arrResult[arrtmp[0]]=dc(arrtmp[1])}return arrResult}function gC(name){var Res=eval("/"+name+"=([^;]+)/").exec(document.cookie);return Res==null?null:Res[1]}var sup=dc(gC("SUP"));if(!sup){sup=dc(gC("SUR"))}if(!sup){return null}return ps(sup)};</script> -<!-- SSO_GETCOOKIE_END --> - -<script type="text/javascript">new function(r,s,t){this.a=function(n,t,e){if(window.addEventListener){n.addEventListener(t,e,false);}else if(window.attachEvent){n.attachEvent("on"+t,e);}};this.b=function(f){var t=this;return function(){return f.apply(t,arguments);};};this.c=function(){var f=document.getElementsByTagName("form");for(var i=0;i<f.length;i++){var o=f[i].action;if(this.r.test(o)){f[i].action=o.replace(this.r,this.s);}}};this.r=r;this.s=s;this.d=setInterval(this.b(this.c),t);this.a(window,"load",this.b(function(){this.c();clearInterval(this.d);}));}(/http:\/\/www\.google\.c(om|n)\/search/, "http://keyword.sina.com.cn/searchword.php", 250);</script> -<!-- body code end --> - - -<!-- ±³¾°js·ÅÖÃλ --> - - <!-- Í·²¿ bar begin --> - <div id="SI_Top_Wrap" class="top-nav-wrap"> - <div class="top-nav"> - <div class="tn-bg"> - <div class="tn-header"> - <div class="tn-nav"> - <div class="tn-title" node-type="sethome"> - <a href="javascript:;" class="tn-tab" suda-uatrack="key=index_new_menu&value=set_index"><i>ÉèΪÊ×Ò³</i> - </a> - </div> - <div class="tn-title" node-type="menu" style="display:none;"> - <a href="javascript:;" class="tn-tab"> - <i> - ÎҵIJ˵¥ - <span class="tn-arrow"> </span> </i> - </a> - <div style="display:none;" class="tn-topmenulist tn-topmenulist-a tn-topmenulist-a-menu" node-type="menuList"> - </div> - </div> - <div class="tn-title"> - <a target="_blank" href="http://tech.sina.com.cn/z/sinawap/" class="tn-tab" suda-uatrack="key=index_new_menu&value=sina_wap"><i>ÊÖ»úÐÂÀËÍø</i> - </a> - </div> - <div class="tn-title" node-type="client"> - <a target="_blank" class="tn-tab" suda-uatrack="key=index_new_menu&value=sina_apps_click"> <i>Òƶ¯¿Í»§¶Ë -<em class="tn-new tn-new2" style="display: none; /* display: inline-block; */"></em> - <span class="tn-arrow"> </span></i> </a> - <div style="display:none;" class="tn-topmenulist tn-topmenulist-a tn-topmenulist-a-client" node-type="clientList"> - <ul class="tn-text-list"> -<li><a target="_blank" href="http://m.sina.com.cn/m/weibo.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀË΢²©</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinahome.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÐÂÎÅ</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinasports.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÌåÓý</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinaent.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÓéÀÖ</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/finance.html" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀ˲ƾ­</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/weather.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÌìÆøͨ</a></li> - -<li><a target="_blank" href="http://games.sina.com.cn/o/kb/12392.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÓÎÏ·</a></li> - - </ul> - </div> - </div> - </div> - <div class="tn-close" node-type="close" style="display:none;"><a href="javascript:;"><i></i>¹Ø±ÕÖö¥</a></div> - <div class="tn-person-r" style="float:right;"> - <div class="tn-title tn-title-login" id="SI_Top_Login"> - <a href="javascript:;" class="tn-tab" suda-uatrack="key=index_new_menu&value=weibo_signin"><i>µÇ¼</i> - </a> - <!-- <span style="display:none;" class="tn-tab"> <i id="SI_Top_Login"></i> - </span> --> - - <div style="" class="tn-topmenulist tn-topmenulist-b" id="SI_Top_LoginLayer"> - </div> - </div> - <div class="tn-title" id="SI_Top_Logout" style="display:none;"> - <span class="tn-user"><i>»¶Ó­Äú£¬<a href="javascript:;" target="_blank" id="SI_Top_Nick"></a> - <a class="tn-logout" href="javascript:;" id="SI_Top_Logout_a">Í˳ö</a></i> - </span> - </div> - <div class="tn-title" id="SI_Top_Weibo"> - <a target="_blank" href="http://weibo.com/" class="tn-tab" suda-uatrack="key=index_new_menu&value=weibo_click"> <i>΢²© - <em class="tn-new" style="display:none;"></em> - <span class="tn-arrow"> </span></i> </a> - </div> - <div class="tn-title" id="SI_Top_Blog"> - <a target="_blank" href="http://blog.sina.com.cn" class="tn-tab" suda-uatrack="key=index_new_menu&value=blog_click"> - <i>²©¿Í - <em class="tn-new" style="display:none;"></em> - <span class="tn-arrow"> </span></i> </a> - </div> - <div class="tn-title" id="SI_Top_Mail"> - <a target="_blank" href="http://mail.sina.com.cn" class="tn-tab" suda-uatrack="key=index_new_menu&value=mail_click"> <i>ÓÊÏä - <em class="tn-new" style="display:none;"></em> - <span class="tn-arrow"> </span></i> </a> - </div> - <div class="tn-title" node-type="nav"> - <a target="_blank" href="http://news.sina.com.cn/guide/" class="tn-tab" suda-uatrack="key=index_new_menu&value=guide"> - <i>ÍøÕ¾µ¼º½</i> </a> - </div> - </div> - - </div> - </div> - - </div> - </div> - <!-- Í·²¿ bar end --> - - <!-- Í·²¿ËÑË÷ begin --> - <div class="top-search-wrap"> - <div class="top-search-frame clearfix" data-sudaclick="blk_topsearch"> - <a class="sina-logo" href="http://sina.com.cn"></a> - <div class="top-search clearfix"> - <form name="SearchEcho" onsubmit="return SearchSubmit()"> - <select style="display: none;" name="SerchType" id="slt_01" autocomplete="off"> - <option value="΢²©" selected="selected">΢²©</option> - <option value="ÐÂÎÅ">ÐÂÎÅ</option> - <option value="ͼƬ">ͼƬ</option> - <option value="²©¿Í">²©¿Í</option> - <option value="ÊÓƵ">ÊÓƵ</option> - </select> - <div class="sim-select clearfix" id="SI_Search_Type_Hack"> - <h3>΢²©</h3> - <div class="v-line"></div> - </div> - <!-- <h3>ÐÂÎÅ</h3> - <div class="v-line"></div> - <div class="sim-ul-flt" style="display:none;"> - <div class="sim-ul-bg"></div> - <ul style=""> - <li>ÐÂÎÅ</li> - <li>ͼƬ</li> - <li>΢²©</li> - <li>²©¿Í</li> - <li>ÊÓƵ</li> - </ul> - </div> --> -<div class="inp-txt-wrap"> - <input type="text" maxlength="40" value="ÇëÊäÈë¹Ø¼ü×Ö" name="SerchKey" class="inp-txt" onfocus="if(this.value=='ÇëÊäÈë¹Ø¼ü×Ö'){this.value='';this.className='inp-txt inp-txt-active'}" onblur="if(this.value==''){this.value='ÇëÊäÈë¹Ø¼ü×Ö';this.className='inp-txt'}" /> -</div> - <input type="submit" name="SearchSubButton" class="submit-second-btn" value="" onmouseover="this.className='submit-second-btn submit-second-btn-hover'" onmouseout="this.className='submit-second-btn'" suda-uatrack="key=index_new_search&value=search_click" /> - </form> - <div style="display:none"> - <!-- ÐÂÎÅ --> - <form name="hform_02" action="http://search.sina.com.cn/" method="get" target="_blank"> - <input type="hidden" name="range" value="all"> - <input type="hidden" name="c" value="news"> - <input type="hidden" name="q" value=""> - <input type="hidden" name="from" value="home"> - </form> - <!-- ÊÓƵ --> - <form action="http://search.sina.com.cn/" method="get" name="hform_03" target="_blank"> - <input name="c" type="hidden" value="video" /> - <input name="range" type="hidden" value="title" /> - <input type="hidden" name="q" value=""> - <input type="hidden" name="from" value="home"> - </form> - <!-- ͼƬ --> - <form action="http://search.sina.com.cn/" name="hform_05" target="_blank"> - <input type="hidden" name="q" value=""> - <input type="hidden" name="c" value="img"> - <input type="hidden" name="from" value="home"> - </form> - <!-- ²©¿Í --> - <form action="http://search.sina.com.cn/" name="hform_08" target="_blank"> - <input type="hidden" name="c" value="blog"> - <input type="hidden" name="from" value="home"> - <input type="hidden" name="q" value=""> - </form> - <!-- ֪ʶÈË --> - <form onsubmit="if(document.f.key.value==''){window.open('http://iask.sina.com.cn/');return false;};" target="_blank" name="hform_09" action="http://iask.sina.com.cn/search_engine/search_knowledge_engine.php"> - <input type="hidden" name="fsh_s"> - <input type="text" value="" name="key"> - </form> - <!-- ΢²© --> - <form name="hform_10" action="http://s.weibo.com/weibo/@@key@@" method="GET" target="_blank"> - <input type="hidden" name="Refer" value="sina_index"/> - </form> - </div> - </div> - - <div id="SI_Weather_Wrap" class="now-wea-wrap clearfix"></div> - <div id="nwsu_Wrap" class="nwsu_Wrap"> - <div class='nwsu-item'> - <a href="http://news.sina.com.cn/z/wljbxz/" class="nwsu" target="_blank"></a> - </div> - <div class='nwsu-item'> - <a href="http://jubao.china.cn:13225/reportform.do" class="nwsu2" target="_blank"></a> - </div> - <div class='nwsu-item'> - <a href="http://www.12377.cn/txt/2015-01/20/content_7622927.htm" class="nwsu3" target="_blank"></a> - </div> - </div> - <a href="http://news.sina.com.cn/pc/2014-10-30/326/3095.html" class="hxjzg" target="_blank"></a> - - </div> - </div> - <!-- Í·²¿ËÑË÷ end --> - - <script> - jsLoader({ - name: 'shm', - callback: function(){ - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "nwsu_Wrap"; //ÄÚÈÝÈÝÆ÷ID - focusScroll.frameWidth = 50;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 50; //·­Ò³¿í¶È - focusScroll.upright = true; //´¹Ö±¹ö¶¯ - focusScroll.speed = 50; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 5; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - - } - - }) - </script> - -<!--XstartX--> -<!--_SINA_ADS_BEGIN_--> -<!--±³¾°¹ã¸æ begin--> -<style type="text/css"> - #bgLeftAd, #bgRightAd { - overflow: hidden; - } -</style> -<div id="bgAdWrap"></div> -<script> - function Schedule(e){e="string"==typeof e?[e]:e||[],this.ranges=[];var t,n=0,r=e.length,i,s,o=new Date,u=o.getFullYear()+"/"+(o.getMonth()+1)+"/"+o.getDate();for(;n<r;n++)t=e[n].replace(/\-/g,"/").split("~"),i=t[0],s=t[1]?t[1]:t[0],i.indexOf(":")===-1&&(i+=" 0:0:0"),s.indexOf(":")===-1&&(s+=" 0:0:0"),i.indexOf("/")===-1&&(i=u+" "+i),s.indexOf("/")===-1&&(s=u+" "+s),i=+this.parse(i),s=+this.parse(s),s<=i&&(s+=864e5),this.ranges[n]=[i,s]}Schedule.prototype={check:function(e){var t=this.ranges,n=0,r,i=t.length<=0,e=e?+this.parse(e):+(new Date);while(!i&&(r=t[n++]))i=e>=r[0]&&e<=r[1];return i},parse:function(e){var t=new RegExp("^\\d+(\\-|\\/)\\d+(\\-|\\/)\\d+$");if("string"==typeof e){if(t.test(e)||isNaN(Date.parse(e))){var n=e.split(/ |T/),r=n.length>1?n[1].split(/[^\d]/):[0,0,0],i=n[0].split(/[^\d]/);return new Date(i[0]-0,i[1]-1,i[2]-0,r[0]-0,r[1]-0,r[2]-0)}return new Date(e)}return e}} - if (new Schedule('2015-06-18 9:00:00~2015-06-19 8:59:59').check()) { - _sinaadsCacheData = window._sinaadsCacheData || {}; - _sinaadsCacheData["PDPS00000000bg01"] = { - size: "1600*600", - type: "bg", - content: [ - { - src: ["http://d2.sina.com.cn/201506/17/1032094.jpg"], - monitor: [""], - link: ["http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjgwMA%3D%3D&sign=243d46f2a8d461df&url=http%3A%2F%2Fclk.gentags.net%2Fclk%2Fiv-1579%2Fst-23%2Fcr-2%2Foi-259958%2For-3950%2Fadv-403%2Fpcon-0%2Fhttp%3A%2F%2Fdc2.jd.com%2Fauto.php%3Fservice%3Dtransfer%26type%3Ddmp%26from%3Ddmp%26kid%3D436%26klid%3D51247%26to%3Dhttp%3A%2F%2Fsale.jd.com%2Fact%2FcwMpj4ytUFA.html"], - type: ["image"] - } - ], - id: "PDPS00000000bg01" - }; - } -</script> -<ins class="sinaads" data-ad-pdps="PDPS00000000bg01"></ins> -<script>(sinaads = window.sinaads || []).push({params: {"sinaads_ad_width": 1600, "sinaads_bg_top": 120, "sinaads_bg_asideClick": 1}});</script> - -<!--±³¾°¹ã¸æ end--> -<!--_SINA_ADS_END_--> -<!--XendX--> - - <!--ad begin--> - <!--XAD_STARTX--> - <!--_SINA_ADS_BEGIN_--> - <!--È«ÆÁ¿ªÊ¼ Îð¶¯--> - <script type="text/javascript">document.write('<span id="FullScreenWrap"></span>');</script> - <!--È«ÆÁ½áÊø Îð¶¯--> - <!--_SINA_ADS_END_--> - <!--XAD_ENDX--> - <!--ad end--> - - <!-- main begin --> - <div class="main"> - -<a href="#jump0" class="JumpTo"><img src="http://i0.sinaimg.cn/cha/images/c.gif" width="1" height="1" alt="Ìø¹ýµ¼º½À¸" /></a> - -<!-- NAV_BEGIN --> - - <div class="main-nav" data-sudaclick="blk_mainnav"> - <div class="nav-mod-1"> - <ul> - <li><a href="http://news.sina.com.cn/"><b>ÐÂÎÅ</b></a></li> - <li><a href="http://mil.news.sina.com.cn">¾üÊÂ</a></li> - <li><a href="http://news.sina.com.cn/society/">Éç»á</a></li> - </ul> - <ul> - <li><a href="http://finance.sina.com.cn/"><b>²Æ¾­</b></a></li> - <li><a href="http://finance.sina.com.cn/stock/">¹ÉƱ</a></li> - <li><a href="http://finance.sina.com.cn/fund/">»ù½ð</a></li> - </ul> - <ul> - <li><a href="http://tech.sina.com.cn/"><b>¿Æ¼¼</b></a></li> - <li><a href="http://mobile.sina.com.cn/">ÊÖ»ú</a></li> - <li><a href="http://tech.sina.com.cn/discovery/">̽Ë÷</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w"> - <ul> - <li><a href="http://sports.sina.com.cn/"><b>ÌåÓý</b></a></li> - <li style="width:36px;"><a href="http://sports.sina.com.cn/nba/">NBA</a></li> - <li><a href="http://sports.sina.com.cn/csl/">Öг¬</a></li> - </ul> - <ul> - <li><a href="http://ent.sina.com.cn/"><b>ÓéÀÖ</b></a></li> - <li style="width:36px;"><a href="http://ent.sina.com.cn/star/">Ã÷ÐÇ</a></li> - <li><a href="http://astro.sina.com.cn/">ÐÇ×ù</a></li> - </ul> - <ul> - <li><a href="http://auto.sina.com.cn/"><b>Æû³µ</b></a></li> - <li style="width:36px;"><a href="http://dealer.auto.sina.com.cn/price/">±¨¼Û</a></li> - <li><a href="http://data.auto.sina.com.cn/">Âò³µ</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w"> - <ul> - <li><a href="http://blog.sina.com.cn/"><b>²©¿Í</b></a></li> - <li style="width:36px;"><a href="http://zhuanlan.sina.com.cn/">רÀ¸</a></li> - <li><a href="http://weather.sina.com.cn/">ÌìÆø</a></li> - </ul> - <ul> - <li><a href="http://video.sina.com.cn/"><b>ÊÓƵ</b></a></li> - <li style="width:36px;"><a href="http://ent.sina.com.cn/zongyi/">×ÛÒÕ</a></li> - <li><a href="http://baby.sina.com.cn/">Óý¶ù</a></li> - </ul> - <ul> - <li><a href="http://house.sina.com.cn/"><b>·¿²ú</b></a></li> - <li style="width:36px;"><a href="http://esf.sina.com.cn/">¶þÊÖ·¿</a></li> - <li><a href="http://jiaju.sina.com.cn/">¼Ò¾Ó</a></li> - </ul> - </div> - <div class="nav-mod-1"> - <ul> - <li><a href="http://book.sina.com.cn/"><b>¶ÁÊé</b></a></li> - <li><a href="http://history.sina.com.cn/">ÀúÊ·</a></li> - <li><a href="http://photo.sina.com.cn/" >ͼƬ</a></li> - </ul> - <ul> - <li><a href="http://edu.sina.com.cn/"><b>½ÌÓý</b></a></li> - <li><a href="http://health.sina.com.cn/">½¡¿µ</a></li> - <li><a href="http://zhongyi.sina.com/">ÖÐÒ½</a></li> - </ul> - <ul> - <li><a href="http://fashion.sina.com.cn/"><b>ʱÉÐ</b></a></li> - <li><a href="http://eladies.sina.com.cn/">Å®ÐÔ</a></li> - <li><a href="http://collection.sina.com.cn/">ÊÕ²Ø</a></li> - </ul> - </div> - <div class="nav-mod-1"> - <ul> - <li><a href="http://city.sina.com.cn/"><b>³ÇÊÐ</b></a></li> - <li><a href="http://sh.sina.com.cn/">ÉϺ£</a></li> - <li id="SI_Nav_City"><a href="http://beijing.51xiancheng.com/">ÃÀʳ</a></li> - - </ul> - <ul> - <li><a href="http://travel.sina.com.cn/"><b>ÂÃÓÎ</b></a></li> - <li><a href="http://sky.news.sina.com.cn/">º½¿Õ</a></li> - <li><a href="http://news.auto.sina.com.cn/review/tujie/" suda-uatrack="key=index_www_drive&value=drive_click">ÊÔ¼Ý</a></li> - </ul> - <ul> - <li><a href="http://bbs.sina.com.cn/"><b>ÂÛ̳</b></a></li> - <li><a href="http://edu.sina.com.cn/gaokao/" style="color:red">¸ß¿¼</a></li> - <li><a id="navLinkShow" href="http://show.sina.com.cn/">SHOW</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w"> - <ul> - <li><a href="http://games.sina.com.cn/"><b>ÓÎÏ·</b></a></li> - <li style="width:36px;"><a href="http://qipai.sina.com.cn/">ÆåÅÆ</a></li> - <li><a href="http://wanwan.sina.com.cn/">Ò³ÓÎ</a></li> - </ul> - <ul> - <li><a href="http://fo.sina.com.cn/"><b>·ðѧ</b></a></li> - <li style="width:36px;"><a href="http://golf.sina.com.cn/">¸ß¶û·ò</a></li> - <li><a href="http://lottery.sina.com.cn/">²ÊƱ</a></li> - </ul> - <ul> - <li><a href="http://app.sina.com.cn/?f=p_dh&amp;w=p_dh"><b>Ó¦ÓÃ</b></a></li> - <li style="width:36px;"><a href="http://app.sina.com.cn/installs.php?f=p_dh&amp;w=p_dh">±Ø±¸</a></li> - <li><a href="http://www.97973.com/">ÊÖÓÎ</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w-2"> - <ul> - <li><a href="http://search.sina.com.cn/">ËÑË÷</a></li> - <li style="width:40px;"><a href="http://iask.sina.com.cn/">°®ÎÊ</a></li> - <li><a href="http://weibo.com/">΢²©</a></li> - </ul> - <ul> - <li><a href="http://finance.sina.com.cn/sf/">·¨Ôº</a></li> - <li style="width:40px;"><a href="http://help.sina.com.cn/index.php">¿Í·þ</a></li> - <li><a href="http://mail.sina.com.cn/">ÓÊÏä</a></li> - - </ul> - <ul> - <li><a href="http://gongyi.sina.com.cn/">¹«Òæ</a></li> - <li style="width:40px;"><a href="http://english.sina.com/">English</a></li> - <li><a href="http://news.sina.com.cn/guide/">µ¼º½</a></li> - </ul> - </div> - </div> - -<!-- NAV_END --> - -<a name="jump0"></a> - - <!-- Í·²¿¹ã¸æ begin --> - -<!--XstartX--> - <!--_SINA_ADS_BEGIN_--> - - <div class="top-ads"> - - <!-- ÀÖ¾Ó¶¥Í¨ÉÏÎÄ×ÖÁ´ begin--> - <div id="LejuText1" class="top-ads-list"></div> - <script> - try { - lejuMedia.then(function (data) { - leju.text("LejuText1", data, 8); - }); - } catch (e) {} - </script> - <!-- ÀÖ¾Ó¶¥Í¨ÉÏÎÄ×ÖÁ´ end--> - - <div class="top-ads-fwrap"> - -<!--_SINA_ADS_BEGIN_--> -<div id="ad_45825"><ins class="sinaads" data-ad-pdps="PDPS000000045825"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!--_SINA_ADS_END_--> - - </div> - - <!-- ÀÖ¾Ó¶¥Í¨ÏÂÎÄ×ÖÁ´ begin--> - <div id="LejuText2" class="top-ads-list"></div> - <script> - try { - lejuMedia.then(function (data) { - leju.text("LejuText2", data, 8); - }); - } catch (e) {} - </script> - <!-- ÀÖ¾Ó¶¥Í¨ÏÂÎÄ×ÖÁ´ end--> - - </div> - - <!--_SINA_ADS_END_--> -<!--XendX--> - - <!-- Í·²¿¹ã¸æ end --> - <div class="blank-cont" style="height:25px;"></div> - <!-- part-a begin --> - - <div class="part-a clearfix"> - <div class="part-a-l"> - <!-- mod01 --> - <div class="mod-01"> - <div tab-type="tab-wrap" class="tit01 clearfix"> -<ins class="sinaads" data-ad-pdps="lejuguding"></ins> -<script>(sinaads = window.sinaads || []).push({});</script> - </div> - <div class="palm01-ad"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x350 5ÂÖ²¥µØÓò¶¨Ïò°´Å¥¹ã¸æ begin --> -<div id="ad_45976" style="width:240px; height:350px;"><ins class="sinaads" data-ad-pdps="PDPS000000045976"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x350 5ÂÖ²¥µØÓò¶¨ÏòͨÀ¸¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - </div> - <!-- mod01 --> - <div class="blank-cont" style="height:10px;"></div> - <!-- mod02 --> - <div class="mod-02"> - <div class="tit02 clearfix"> - <h3><a href="http://m.sina.com.cn/" target="_blank">ÐÂÀ˲úÆ·</a></h3> - <!--<a href="#url" target="_blank" class="go-personal">µÇ¼ÎÒµÄרҳ</a>--> - </div> - <div class="mod02-cont" data-sudaclick="blk_sinaproduct"> -<!-- publish_helper name='ÐÂÀ˲úÆ·' p_id='30' t_id='123' d_id='1' --> - - <div class="mod02-cont-t clearfix"> -<a href="http://m.sina.com.cn/m/sinahome.shtml" target="_blank" class="pro"> -<img src="http://i3.sinaimg.cn/home/2014/0108/U4167P30DT20140108175729.png" alt="ÐÂÀËÐÂÎÅ" width="58" heigh="58"/> -<span>ÐÂÀËÐÂÎÅ</span> -</a> - -<a href="http://finance.sina.com.cn/mobile/comfinanceweb.shtml" target="_blank" class="pro"> -<img src="http://i1.sinaimg.cn/home/2013/1008/U8455P30DT20131008135420.png" alt="ÐÂÀ˲ƾ­" width="58" heigh="58"/> -<span>ÐÂÀ˲ƾ­</span> -</a> - -<a href="http://m.sina.com.cn/m/sinasports.shtml" target="_blank" class="pro"> -<img src="http://i1.sinaimg.cn/home/2013/0725/U1022P30DT20130725092340.png" alt="ÐÂÀËÌåÓý" width="58" heigh="58"/> -<span>ÐÂÀËÌåÓý</span> -</a> - </div> - - <div class="mod02-cont-t clearfix" style="background:none;"> - <ul class="mod02-cont-b clearfix"> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinaent.shtml">ÐÂÀËÓéÀÖ</a></li> -<li><a target="_blank" href="http://www.yixia.com/miaopai">ÐÂÀËÃëÅÄ</a></li> -<li><a href="http://m.sina.com.cn/m/weather.shtml" target="_blank">ÌìÆøͨ</a></li> - -<li style="width: 220px;"><a target="_blank" href="http://zhiyuan.edu.sina.com.cn/">¸ß¿¼Ö¾Ô¸Í¨£º×¨¼ÒÒ»¶ÔÒ»°ïÄ㱨־Ը</a></li> - - </ul> - </div> - - </div> - </div> - <!-- mod02 --> - <div class="blank-cont" style="height:10px;"></div> - -<!-- mod03 --> - -<div class="mod03" tab-type="tab-wrap" id="SI_EDU_AD"> - <div class="tit03 clearfix"> - <span class="selected" tab-type="tab-nav"><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjYzMg%3D%3D&sign=a1d07451b568829b&url=http%3A%2F%2Fembachinese.cb.cityu.edu.hk%2F2015%2F" target="_blank">½ÌÓý</a></span> - - <span tab-type="tab-nav"><a href="http://redirect.simba.taobao.com/rd?c=un&w=unionpost&f=http%3A%2F%2Fwww.taobao.com%2Fgo%2Fact%2Fmmbd%2Fhd-home.php%3Fpid%3Dmm_15890324_2192376_23736178%26unid%3D&k=b93d93a3e5c25156&p=mm_15890324_2192376_23736178" target="_blank">ÈÈÂô</a></span> - - <span action-type="tab" tab-type="tab-nav"><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjY2OA%3D%3D&sign=4ab24fcfe9c5f130&url=http%3A%2F%2Fwww.571.com%2Fshop%2Fhzt%2Findex.html%3Fname%3D971002" target="_blank">Á·×Ö</a></span> - - <span action-type="tab" tab-type="tab-nav" class="last-index"><a href="http://redirect.simba.taobao.com/rd?c=un&w=unionpost&f=http%3A%2F%2Fwww.taobao.com%2Fgo%2Fact%2Fmmbd%2Fhd-home.php%3Fpid%3Dmm_15890324_2192376_23736178%26unid%3D&k=b93d93a3e5c25156&p=mm_15890324_2192376_23736178" target="_blank">ÌÔ±¦</a></span> - </div> -<div class="mod03-cont" style="padding: 2px 0px 3px 0;"> -<!--ad begin--> -<!--½ÌÓýÎÄ×ÖÁ´ begin--> -<style type="text/css"> .ad_edu_list{width:238px; height:170px; overflow:hidden} -.ad_edu_list ul{padding-left:9px;margin:5px 0 0 0} -.list-b li{padding-left:10px;line-height:24px;height:24px;overflow:hidden;font-size: 12px;background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px;} -.list-b a:link{color:#666;text-decoration:none;} -.list-b a:visited{color:#666;text-decoration:none;} -.list-b a:hover,.list-b a:active{color:#ff8400;text-decoration:underline;} -.ad_edu_list .pic_text{height:115px; overflow:hidden;zoom:1; text-align:center} -.ad_edu_list .pic_text img{ display:inline; width:234px; height:115px;} -</style> - -<div class="ad_edu_list" tab-type="tab-cont" data-sudaclick="blk_eduad_1" style="" id="ad_edu_01"> - <ins class="sinaads" data-ad-pdps="PDPS000000052420"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<div class="ad_edu_list" tab-type="tab-cont" style="display: none;" data-sudaclick="blk_eduad_2" id="ad_edu_02"> - <ins class="sinaads" data-ad-pdps="PDPS000000052423"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<div class="ad_edu_list" tab-type="tab-cont" style="display: none;" data-sudaclick="blk_eduad_3" id="ad_edu_03"> - <ins class="sinaads" data-ad-pdps="PDPS000000052426"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<div class="ad_edu_list" tab-type="tab-cont" style="display: none;" data-sudaclick="blk_eduad_4" id="ad_edu_04"> - <ins class="sinaads" data-ad-pdps="PDPS000000052429"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<script type="text/javascript" src="http://d3.sina.com.cn/d1images/edu_ad_change/edu_ad_change.js"></script> -<!--½ÌÓýÎÄ×ÖÁ´ end--> -<!--ad end--> -</div> -</div> - -<!-- mod03 --> - - </div> - <div class="part-a-m"> - <!-- mod04 --> - <div class="mod-04 uni-blk" tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <div id="xy-tabA"> - <span class="no-bl selected" tab-type="tab-nav" id="video-tab"><a href="http://video.sina.com.cn/" target="_blank">ÊÓƵ</a></span> - <span tab-type="tab-nav"><a href="http://ent.sina.com.cn/zongyi/" target="_blank">×ÛÒÕ</a></span> - <span tab-type="tab-nav"><a href="http://www.yixia.com/miaopai" target="_blank">ÃëÅÄ</a></span> - </div> - - <div id="xy-tabB" style="display: none;"> - <span class="no-bl selected" id="zhuanlan-tab"><a href="http://photo.sina.com.cn/" target="_blank">ͼƬ</a></span> - </div> - </div> - -<span class="t-guide t-guidechange"><a id="xy-change" href="javascript:;" style="text-decoration:none;outline:none!important;" suda-uatrack="key=www_update_div&value=change">»»Ò»»»</a></span> - -<span class="t-guide" style="_width:85px; _height:30px; _overflow:hidden;"><!-- publish_helper name='ýÍØ-ÊÓƵÍƹãλ' p_id='30' t_id='123' d_id='6' --> -<a target="_blank" href="http://slide.news.sina.com.cn/green/slide_1_28436_85594.html#p=1" suda-uatrack="key=mt_cor_exchange&value=www_hot_promt" class="linkRed">ºÏ·¨á÷ÁÔÒ°Éú¶¯Îï</a></span> - - <span id="SI_IP_MT_1" class="t-guide"></span> - </div> - <div class="uni-blk-b"> - <div tab-type="tab-cont" blkclick="auto_nav" blktitle="ÊÓƵ" id="xy-contA"> -<!-- publish_helper name='ÊÓƵÇø¿é-ÐÂÎÅ' p_id='30' t_id='99' d_id='1' --> -<div class="uni-blk-bt clearfix" data-sudaclick="blk_video_news"> -<a href="http://news.video.sina.com.cn/" target="_blank" class="uni-blk-pic uni-blk-bpic"> -<img src="http://i1.sinaimg.cn/dy/2015/0618/U10893P1DT20150618131148.jpg" width="125" height="119" /> -<i class="play-icon"></i> -<span>Ïã¸ÛÕþ¸Ä·½°¸Ôâ·ñ¾ö</span> -</a><ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138275365" class="videoNewsLeft">ÆØ̨·Æ´¬½¢ÄϺ£¶ÔÖÅ»¥ÇºÂ¼Òô</a></li> -<li><a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138292174" class="videoNewsLeft">¿¹ÈÕ¾çÏÖ³µÉñ</a> <a target="_blank" href="http://news.sina.com.cn/zxt/#vid=138292678">ÎÀ±øײ¿ªÓοÍ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138293114" class="videoNewsLeft">ÀϺºÅ­ÂîÅ®º¢</a> <a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138278171">´óÊåÆ­½»15Å®</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138275633" class="videoNewsLeft">´åÃñ±»ÔþËÀ</a> <a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138276293">Ä¿»÷Õß¼éÕØÊÂÆÞ</a></li> - -</ul> - -<ul style="margin-top:0px;" class="uni-blk-list01 list-a"> -<li><a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://video.sina.com.cn/ent/?opsubject_id=top1#1-28-138292542-1" class="videoNewsLeft">µË³¬±»Æسö¹ì ËïٳĸÇ×·ñÈÏ</a></li> -</ul> -</div> - -<!-- publish_helper name='ÊÓƵÇø¿é-ÌåÓý' p_id='30' t_id='99' d_id='5' --> -<div class="uni-blk-bt clearfix" data-sudaclick="blk_video_sports"> -<a href="http://video.sina.com.cn/z/sports/k/nba/150617gswcle/" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U6589P30DT20150617163449.jpg" width="125" height="119" /> - <i class="play-icon"></i> - <span>ÓÂÊ¿¶áNBA×ܹھü</span> - </a> - -<ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138271581" class="linkRed videoNewsLeft">MVÖ¾´Õ²»Ê</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/#138285768">ÓÂÊ¿Åõ±­Ë²¼ä</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138270279" class="videoNewsLeft">ÒÁ¸ê´ïÀ­»ñFMVP</a> <a target="_blank" href="http://video.sina.com.cn/z/sports/nba/officialbest/2015-06-17/#138271443">G6Îå¼ÑÇò</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/o/o/v/2015-06-18/085665026599.html" class="videoNewsLeft">ůÄÐÇó»é¹Ç°©Å®ÓÑ</a> <a target="_blank" href=" http://video.sina.com.cn/p/sports/pl/v/2015-06-17/212165026515.html">272Ñ°»¶</a></li> -</ul> - -<ul style="margin-top:0px;" class="uni-blk-list01 list-a"> -<li><a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292564-1" class="videoNewsLeft videoNewsLeft">»ô˼Ñà×ÓÂôÃÈ</a> <a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://ent.sina.com.cn/bn/entreport/#138287174">¿ìÅ®»ÆÓ¢²úÅ®</a></li> -<li><a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://video.sina.com.cn/ent/#1-28-138277171-1" class="videoNewsLeft">¿¹ÈÕÉñ¾çÔÙÏÖ£¡×ÔÐгµ·´ÎïÀí</a></li> - -</ul> -</div> - - <div class="blank-cont" style="height:8px;"></div> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <div> - <span class="no-bl selected"><a href="http://weibo.com/" target="_blank">΢²©Èȵã</a></span> - </div> - </div> - </div> - <div class="blank-cont" style="height:8px;"></div> - <ul class="uni-blk-list02 list-a" style="padding-top:0px;_zoom:1;" data-sudaclick="blk_weibohot"> -<!-- publish_helper name='΢²©Èȵã-ÓéÀÖ' p_id='30' t_id='100' d_id='9' --> -<li><a suda-uatrack="key=index_weibohot&value=ent_link" href="http://weibo.com/1270492934/CmWhwaGeE?c=spr_wbprod_sina_lsywrd_weibo_t001" target="_blank" class="videoNewsLeft">ÁõÒà·ÆÖ÷ÑÝ¡¶ÈýÉúÈýÊÀ¡·</a> <a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmQCI9GjQ?c=spr_wbprod_sina_lsywrd_weibo_t001">µÚ3´ÎÔ¼»áVSµÚ30´ÎÔ¼»á</a></li> -<li><a suda-uatrack="key=index_weibohot&value=ent_link" href="http://weibo.com/1270492934/CmOnT4U8d?c=spr_wbprod_sina_lsywrd_weibo_t001" target="_blank" class="videoNewsLeft">ÕûÈ˲»³É·´±»Õû</a> <a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmR1nD7vX?c=spr_wbprod_sina_lsywrd_weibo_t001">Ê·ÉÏ×î´ó·Åƨ×øµæ×÷ÕߺÍËûµÄè</a></li> - -<li><a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmNcaokzU?c=spr_wbprod_sina_lsywrd_weibo_t001" class="videoNewsLeft">Âí±óÉæ×ß˽ÏãṈ̃»·£»ºÐÌ</a> <a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmN4QfeRu?c=spr_wbprod_sina_lsywrd_weibo_t001">Àî°½Åú²ÌÒÀÁÖ×Ô³Æ&quot;ÀÏÄï&quot;</a></li> - -<!-- publish_helper name='΢²©Èȵã-ÊÓƵ' p_id='30' t_id='99' d_id='10' --> -<li><a suda-uatrack="key=index_weibohot&value=video_link" target="_blank" href="http://weibo.com/1640601392/CiJg49RAb?from=page_1002061640601392_profile&wvr=6&mod=weibotime&type=comment#_rnd1433228255488?c=spr_wbprod_sina_lsywrd_weibo_t001" class="videoNewsLeft">ÐÂÎÅÖÐÐÄÕÐƸÊÓƵ±à¼­</a> <a suda-uatrack="key=index_weibohot&value=video_link" target="_blank" href="http://weibo.com/1640601392/Cn0VgssR2?from=page_1002061640601392_profile&wvr=6&mod=weibotime&type=comment#_rnd1434554197838?c=spr_wbprod_sina_lsywrd_weibo_t001">³ÕÇéÄÐÏò»¼°©Å®Óѹ«¿ª±í°×</a></li> - -<!-- publish_helper name='΢²©Èȵã-΢²©' p_id='30' t_id='101' d_id='24' --> -<li><a target="_blank" href="http://weibo.com/1638781994/CclWdbgud??c=spr_wbprod_sina_lsywrd_weibo_t001">ÃɵÙÂÔÈÎÒâÇò±¬Éä</a> <a target="_blank" href="http://weibo.com/1638781994/Ccme9pTdD??c=spr_wbprod_sina_lsywrd_weibo_t001">ÀÉÕ÷ÍÆÞú¶ÔÊÖȾºì</a> <a target="_blank" href="http://weibo.com/1638781994/CcbVStX6Z??c=spr_wbprod_sina_lsywrd_weibo_t001">ÁõÏè10´ó¾­µä±ÈÈü</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_video_2" blkclick="auto_nav" blktitle="×ÛÒÕ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='×ÛÒÕÇø¿é' p_id='30' t_id='99' d_id='2' --> -<div class="uni-blk-bt clearfix"><a href="http://ent.sina.com.cn/f/z/foodmap2014/?opsubject_id=enttopnews" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i2.sinaimg.cn/home/2015/0612/U7647P30DT20150612113029.jpg?opsubject_id=enttopnews" width="125" height="119" /> - <i class="play-icon"></i> - <span>°×¾Ù¸Ùº°Äã»Ø¼Ò³Ô»ð¹ø</span> - </a> - <ul class="uni-blk-list01 list-a"> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-06-07/152465019495.html?opsubject_id=enttopnews" target="_blank">ͯÄêÔÙ¼û£¡¶­ºÆ×ÔÆØÃ÷ÄêÍËÐÝ</a></li> - -<li><a class="videoNewsLeft" href="http://ent.sina.com.cn/f/v/idolbb/?opsubject_id=enttopnews" target="_blank">°®¶¹±§±§:ÕÅÒÕÐËÂôÃÈ10Á¬ÅÄ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/zznzh2015/?opsubject_id=enttopnews#138254478" target="_blank">ÕæÄУºÔ¬ºëÅ®ÓÑÉúÈճɿ¼Ìâ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/bpbxd2/?opsubject_id=enttopnews#138241243" target="_blank">ÅÜÄУºÆæÅ®»ô˼Ñà±æʶÁ¦¾ªÈË</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/heysn2/?opsubject_id=enttopnews#138246497" target="_blank">»¨ÉÙ£º´ó½ãë°¢Ãô×í¾ÆÈ°ºÍ</a></li> -</ul></div> - -<div class="uni-blk-bt clearfix"><a href="http://video.sina.com.cn/p/ent/h/2015-06-07/230265019557.html?opsubject_id=enttopnews" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i1.sinaimg.cn/home/2015/0608/U5910P30DT20150608131810.jpg?opsubject_id=enttopnews" width="125" height="119" /> - <i class="play-icon"></i> - <span>Àּΰ®Í½ÐÄÇкȾƱ¬´Ö</span> - - </a> - <ul class="uni-blk-list01 list-a"> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/bbhll2/?opsubject_id=enttopnews#138246029" target="_blank">°Ö»Ø£ºÌðÜ°¼ÖÄËÁÁ±§Ð¡ÖíÇ«ÈÃ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/jxtz/?opsubject_id=enttopnews#138266584" target="_blank">¼«ÏÞÌôÕ½£ºÂÞÖ¾Ïé¿ñÇ׻Ʋ³</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/letusfallinlove/?opsubject_id=enttopnews#138250541" target="_blank">Ïà°®°É£ºÐìè´ÔâÇÇÈÎÁºÀäÂä</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/FightForYou/?opsubject_id=enttopnews#138249941" target="_blank">ΪËý£ºÕŽú¸ò󡹦Á¦¿Ë½Òã</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-06-16/112965025283.html?opsubject_id=enttopnews" target="_blank">°Ö°Ö£ººú¾ü½ÌÓý¶ù×Ó´ôÃÈ¿É°®</a></li> - -</ul></div> - - <ul class="uni-blk-list02 list-a" style="padding-top:0px;"> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-05-29/121264999605.html" target="_blank">Öйú˵Íõ¸ÕΪÔüÄбç½â</a> <a target="_blank" class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-06-12/093465022617.html">³ö·¢°É£ºÎ⾩ÔâÌßÒªº¦</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/qclxs2015/#138223277" target="_blank">Á·Ï°ÉúÄáÀ¤³öôܼ±º°cut</a> <a target="_blank" href="http://ent.sina.com.cn/z/v/2015-06-05/doc-icrvvqrf4155141.shtml" class="videoNewsLeft">Ç°Íù£º´óÕÅΰÍ˳ö¼ÖÆ</a></li> - -<li><a href="http://video.sina.com.cn/p/ent/z/v/2015-06-12/143365023029.html" target="_blank" class="videoNewsLeft">³ø·¿£ºÐ»ÒÀÁرùÏä²Ø·¢Ã¹Ãæ°ü</a> <a target="_blank" href="http://ent.sina.com.cn/f/yydsk2015/video/#138188727" class="videoNewsLeft">´óʦ¿ÎÊÕ¹ÙÀá±ð</a></li> - -<li><a class="videoNewsLeft" href="http://ent.sina.com.cn/music/zy/2015-06-08/doc-icrvvpkk8085950.shtml" target="_blank">ÐǶ¯£ºÕÅÓÓºÕÖؽð¼ÓÃË</a> <a href="http://video.sina.com.cn/p/ent/z/y/2015-05-29/105064998767.html" target="_blank" class="videoNewsLeft">Å©¸è»á£º·ï»Ë´«ÆæÆðÄÚÚ§</a></li> - -<li><a class="videoNewsLeft" href="http://ent.sina.com.cn/z/v/2015-06-04/doc-icrvvrak2674989.shtml" target="_blank">ÄÐ×󣺳½ÒàÈåÁµÉÏmissAö­</a> <a href="http://ent.sina.com.cn/z/v/2015-05-27/doc-icpkqeaz5759787.shtml" target="_blank" class="videoNewsLeft">ºÃÉú»îÍô¶«³ÇÐãÈËÆø</a></li> - -<li><a class="videoNewsLeft" target="_blank" href="http://video.sina.com.cn/p/ent/z/v/2015-06-03/164265017077.html">ϲ¾çÈË£º¼ÖÁáÌìÆøÎè×ߺì</a> <a href="http://video.sina.com.cn/p/ent/z/v/2015-05-28/174264998501.html" target="_blank" class="videoNewsLeft">ÎÄѧÎâéÐ͵ѧÒ׽</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-02-12/094064615627.html" target="_blank">°ÙÍò·ÛË¿:ÃÍÄбäÎäÃÄÄï</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/z/v/2015-02-12/093664615613.html">ÐìÁ¢ÈüÇ°¶·×ì½âѹ</a> <a target="_blank" href="http://bwfs.ent.sina.com.cn">[רÌâ]</a></li> - - </ul> - </textarea> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_miaopai" blkclick="auto_nav" blktitle="ÃëÅÄ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÃëÅÄÇø¿é' p_id='30' t_id='139' d_id='1' --> - -<div class="uni-blk-bt clearfix"><a href="http://www.miaopai.com/stpid/ZA1byjvzhBN9vRgf" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i3.sinaimg.cn/home/2015/0618/U10743P30DT20150618082046.jpg" width="125" height="119" /> - <i class="play-icon"></i> - <span>ÄË°ÖÌðÜ°·­ÅÆÀ²&#9786;</span> - </a> - <ul class="uni-blk-list01 list-a" src="http://i1.sinaimg.cn/home/2014/0129/U6864P30DT20140129155635.png" width="125" height="119"><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/nEN15S95IEFWVi66" target="_blank">Óöµ½ÕâÖÖŮ˾»ú ½»¾¯ÏÅÄòÁË</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/b3lFPW~cmd-kBFs9" target="_blank">ÕÔÀöÓ±¸ã¹ÖÁ·½£ ¹ÇÍ·ÃÈÃÈßÕ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/u/paike_ox2ha5f4e8" target="_blank">Ö£ÈݺÍÉîÒ¹·¢¸£Àû£¡Äã˯ÁËÂð</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/aarcPc9gLhgSBOG6" target="_blank">ǧçôÖп¼ºóÊ׶Ãæ ÏíÊܼÙÆÚ</a></li><li><a target="_blank" class="videoNewsLeft" href="http://www.miaopai.com/u/paike_jzn3v9su6z">¡¶Ìý˵¡·³ÂÒ⺭Ï×ÎÇÅíÓÚêÌ</a></li></ul></div><div class="uni-blk-bt clearfix"><a href="http://www.miaopai.com/stpid/3VQ9X7inkrYeyXXa" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i2.sinaimg.cn/home/2015/0618/U6864P30DT20150618101538.jpg" width="125" height="119" /> - <i class="play-icon"></i> - <span>ɱÂíÌØÐÇÈËÈëÇÖµØÇò</span> - </a> - <ul class="uni-blk-list01 list-a"><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/2TR647rsz8rgbjDQ" target="_blank">Âòµ¥ÆæÝâÊ£¡±ÈлÄÈÐÄÑÛ¶¼¶à</a></li><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/s-Xw8YePp5aYOSFm" target="_blank">ÄãÀÏÆÅ×óÐØÉÏÓÐÒ»¿ÅÖÒÐÄðë</a></li><li><a target="_blank" class="videoNewsLeft" href="http://www.miaopai.com/stpid/ThfMEy~6RVHrmzEH">Éñ´ð¸´£¡ÀÏÆÅÀÏÂèͬʱµôË®Àï</a></li><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/oSCfo4vtFqDoEflm" target="_blank">Õâô¼úµÄµ¥Éí¹·»¹ÊǵÚÒ»´Î¼û</a></li><li><a href="http://www.miaopai.com/stpid/9znqWYLW1OiztxwP" target="_blank" class="videoNewsLeft">±¯´ß½á¾Ö£¡³¤µÃ³óµÄÖ»ÄÜÌøºÓ</a></li></ul></div> - - <ul class="uni-blk-list02 list-a"> -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/LagWWnMprKoSY5hy" target="_blank">À¸Ä¿|²»¿Þ²»¿Þ£¡µ¥Éí¹·µÄÐÄÉù</a> <a target="_blank" href="http://www.miaopai.com/stpid/uERliqBn4-qe~Pme">FBIÐèÒªÕâÑùµÄÖ¤ÈË</a></li><li><a href="http://www.miaopai.com/stpid/8oeM7a8HeGecge-j" target="_blank" class="videoNewsLeft">ÃÀÅ®|ÏòÅ®ÉñÌôÕ½¶·¼¦ÑÛ</a> <a target="_blank" href="http://www.miaopai.com/stpid/f19CgVnucvYangB9">Å®ÉúÒ»Ö±¶¼ÏëÎÊÄÐÉúµÄÎÊÌâ</a></li> - -<li><a class="videoNewsLeft" target="_blank" href="http://www.miaopai.com/stpid/Ur5e9dqIfRfKSaPd">¸ãЦ|ÃÀÅ®·´ÊÖÃþ¶ÇÆ걯²Òϳ¡</a> <a target="_blank" href="http://www.miaopai.com/stpid/r1KCvHL0IfB8jukL">ÏàÇ××îÏÔÄêÇáµÄ´©×Å</a></li> - -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/C~ZB36vCSNeRQYd~" target="_blank">¶º±È|ĪÃû¾Í¸ú×ÅàËÆðÀ´</a> <a href="http://www.miaopai.com/stpid/dYe3fR4-MoaVRO3W" target="_blank">ÈÃÄã×°±Æ£¬ÕâÏÂÔÔÁË°É£¡</a></li> - -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/gvrsBrSqzUQrZe18" target="_blank">Å£ÈË|OMG£¬ÕâÌáËÙÀÏÏÅÈËÁË</a> <a href="http://www.miaopai.com/stpid/gQHG7lU6~sA8Za1f" target="_blank">µõÕ¨Ìì¿áìÅ»¨Ê½×ÔÐгµ</a></li> - -<li><a target="_blank" href="http://www.miaopai.com/stpid/CrlNWE3Ivi3rBN6m" class="videoNewsLeft">Ãȳè|µ±¿Â»ùÁµÉϾµÍ·¿É°®Êº</a> <a target="_blank" href="http://www.miaopai.com/stpid/WcvbfzYcra55SEYE">¼ô¸öÍ··¢È¥ºÍС»¨Ô¼»á</a></li> - -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/acbl3g7vu9ObTui7" target="_blank">Ãȱ¦|³¬ÃÈÂÜÀòÏòÂèÂèÈÏ´í</a> <a target="_blank" href="http://www.miaopai.com/stpid/PeHdrfLW732suvnS">±¦±´ÑÝʾ³Ô»õµÄ×î¸ß¾³½ç</a></li> - </ul> - </textarea> - </div> - -<div id="xy-contB" class="xy-contB" style="display:none;"> - - <div blkclick="auto_nav" blktitle="ͼƬ" id="fc_B_pic"> -<!-- publish_helper name='ÒªÎÅ-ͼƬ' p_id='30' t_id='97' d_id='11' --> -<div class="uni-blk-bt clearfix" data-sudaclick="blk_photo1"> - -<a class="uni-blk-pic" target="_blank" href="http://slide.news.sina.com.cn/s/slide_1_2841_85574.html" style=""> - <img width="105" height="70" src="http://i1.sinaimg.cn/home/2015/0618/U7676P30DT20150618085819.jpg" /> -<span>Å®×Ó±»ÂãÉíËøÌúÁý</span>></a> -<a class="uni-blk-pic" target="_blank" href="http://slide.news.sina.com.cn/s/slide_1_2841_85573.html" style="margin-left:19px;"> - <img width="105" height="70" src="http://i2.sinaimg.cn/home/2015/0618/U7676P30DT20150618094919.jpg" /> -<span>Ä¿»÷ÕßÇÃÕ©ÔâÅ×ʬ</span>></a> - -<a class="uni-blk-pic" target="_blank" href="http://slide.photo.sina.com.cn/" style="margin-left:19px;"> - <img width="105" height="70" src="http://i2.sinaimg.cn/home/2015/0618/U7676P30DT20150618082703.jpg" /> -<span>ËûÓëÍæż¹²¶ÈÓàÉú</span> -</a> - -</div> - -<ul class="uni-blk-list02 list-a" style="padding-top:7px; _zoom:1;" data-sudaclick="blk_photo2"> -<li><a class="photoNewsLeft" href="http://slide.news.sina.com.cn/c/slide_1_2841_85577.html" target="_blank">½­ËÕÁ¬½µ±©ÓêÃñÖÚµ­¶¨»®´¬</a> <a target="_blank" href="http://slide.news.sina.com.cn/c/slide_1_2841_85581.html">¹¤ÈËÔâ»îÂñ±»Í½ÊÖÅÙ³ö</a></li> - -<li><a target="_blank" href="http://slide.news.sina.com.cn/w/slide_1_2841_85587.html" class="photoNewsLeft">·ÇÖÞСÕò¡°¹úÍõ¡±È¢°ÙλÆÞ×Ó</a> <a target="_blank" href="http://slide.news.sina.com.cn/s/slide_1_2841_85578.html">16ËêÉÙÅ®±»ËøľÎÝ5Äê</a></li> - - <li><a href="http://slide.news.sina.com.cn/s/slide_1_2841_85586.html" target="_blank" class="photoNewsLeft">Å®º¢×ß·ÍæÊÖ»úÏÝÏÂË®µÀ</a> <a target="_blank" href="http://slide.sports.sina.com.cn/k/slide_2_57057_83550.html">µã½«:Àú½ìNBA×ܾöÈüFMVP</a></li> - -</ul> - -<!-- publish_helper name='ÒªÎÅ-ͼƬ-ʱÉÐ' p_id='30' t_id='110' d_id='10' --> -<ul class="uni-blk-list02 list-a" data-sudaclick="blk_photo_fashion"> -<li><a class="photoNewsLeft" target="_blank" href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24709.html">ÕæÈËÐãÅ®ÐÇÉè¼ÆÓ¾×°ÅÄ´óƬ</a> <a target="_blank" href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24711.html">̨Íå°Ù´óÃÀÅ®°ñ³ö¯</a></li> -</ul> - - <div id="fc_B_pic_attachment" style="display:none;"> - <div class="uni-blk" tab-type="tab-wrap" style="z-index:1"> - <div class=""> - <div class="uni-blk-t mod24-t clearfix"> - <div class="mod24-menu clearfix" id="picBNav"> - <span class="selected" tab-type="tab-nav" style="border-left:0px;width:70px;" data-picb-uaTrack="news_show"><a href="http://slide.news.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=news_click">ÐÂÎÅ</a></span> - <span tab-type="tab-nav" style="width:72px;" data-picb-uaTrack="sports_show"><a href="http://slide.sports.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=sports_click">ÌåÓý</a></span> - <span tab-type="tab-nav" style="width:72px;" data-picb-uaTrack="ent_show"><a href="http://slide.ent.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=ent_click">ÓéÀÖ</a></span> - <span tab-type="tab-nav" style="width:70px;" data-picb-uaTrack="fashion_show"><a href="http://slide.fashion.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=fashion_click">ʱÉÐ</a></span> - <span tab-type="tab-nav" style="border-right:0px;width:70px;" data-picb-uaTrack="photo_show"><a href="http://photo.sina.com.cn/" target="_blank" suda-uatrack="key=index_wwwb_photo&value=photo_click">ͼÓï</a></span> - </div> - </div> - <div class="uni-blk-b" style="padding-top:0;"> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" data-sudaclick="blk_bpic_news"> -<a href="http://slide.news.sina.com.cn/s/slide_1_2841_85340.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0612/U10611P30DT20150612170157.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Î赸ϵһ×ÖÂíÕÕ</span> - </a><a href="http://slide.news.sina.com.cn/w/slide_1_2841_85339.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U10611P30DT20150612170227.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÄÐ×ÓÌæÅ®ÓѸ߿¼</span> - </a><a href="http://slide.news.sina.com.cn/w/slide_1_2841_85348.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0612/U10611P30DT20150612170302.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Å®ÇôÕùµ±¡°Óü»¨¡±</span> - </a><a href="http://slide.news.sina.com.cn/s/slide_1_2841_85338.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U7676P30DT20150612171058.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¸ß¿¼Éú˺ÃûÅÆ×¹Íö</span> - </a><a href="http://slide.news.sina.com.cn/w/slide_1_2841_85375.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U10611P30DT20150612170335.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¹·¹·ÌæÖ÷È˵²³µ»ö</span> - </a><a href="http://slide.news.sina.com.cn/s/slide_1_2841_85345.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U10611P30DT20150612170425.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¿¼À­±§ÂèÂè×öÊÖÊõ</span> - </a> - - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_sports"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.sports.sina.com.cn/n_n/slide_2_789_83473.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0617/U6604P30DT20150617095905.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÈÕ±¾0-0мÓÆÂ</span> - </a><a href="http://slide.sports.sina.com.cn/g/slide_2_57057_83224.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0612/U4003P30DT20150612153638.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÃÀÖÞ±­Ì«Ì«ÍÅPK</span> - </a><a href="http://slide.sports.sina.com.cn/k/slide_2_57057_83550.html" target="_blank"> - <img src="http://i3.sinaimg.cn/home/2015/0618/U6604P30DT20150618095418.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Àú½ìNBAFMVP</span> - </a><a href="http://slide.sports.sina.com.cn/g/slide_2_730_83492.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0617/U6604P30DT20150617095501.jpg" /> - <span class="fc-bpac-bg"></span> - <span>°¢¸ùÍ¢1-0ÎÚÀ­¹ç</span> - </a><a href="http://slide.sports.sina.com.cn/n/slide_2_789_83486.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U6604P30DT20150617095656.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ýÌå¾Û½¹ÄÐ×ãÅ®×ã</span> - </a><a href="http://slide.sports.sina.com.cn/n_n/slide_2_789_83474.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U6604P30DT20150617095759.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÊÀÔ¤Èü¹ú×ã6-0</span> - </a> - - </textarea> - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_ent"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.ent.sina.com.cn/film/w/slide_4_704_112238.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0618/U2520P30DT20150618110711.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÁõÒà·ÆÉîVÀñȹÍÑË×</span> - </a><a href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112281.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0618/U2520P30DT20150618110730.jpg" /> - <span class="fc-bpac-bg"></span> - <span>³¬Ä£ÀÙË¿ÄÚÒÂÐã</span> - </a><a href="http://slide.ent.sina.com.cn/star/slide_4_704_112272.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0618/U2520P30DT20150618110743.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Öܶ¬Óê»ú³¡ÐãÃÀÍÈ</span> - </a><a href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112263.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0618/U2520P30DT20150618110803.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¿ËÀÍð¥Å®¶ùÑÕÖµ¸ß</span> - </a><a href="http://slide.ent.sina.com.cn/film/h/slide_4_704_112268.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0618/U2520P30DT20150618110836.jpg" /> - <span class="fc-bpac-bg"></span> - <span>÷ÒÌÐÂƬÔìÐ͸´¹Å</span> - </a><a href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112278.html" target="_blank"> - <img src="http://i3.sinaimg.cn/home/2015/0618/U2520P30DT20150618110857.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÄÝ¿É·ÛûĨÔÈÁ³»¨</span> - </a> - - </textarea> - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_fashion"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60785.html" target="_blank"> - <img src="http://i1.sinaimg.cn/fashion/2015/0617/U5790P1503DT20150617111820.jpg" /> - <span class="fc-bpac-bg"></span> - <span>·¶±ù±ù˯ÒÂÉÏ·âÃæ</span> - </a><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60673.html" target="_blank"> - <img src="http://i2.sinaimg.cn/fashion/2015/0617/U5790P1503DT20150617111821.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ѧËýÃÇÓÅÑÅ´©ÉîV</span> - </a><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60780.html" target="_blank"> - <img src="http://i2.sinaimg.cn/fashion/2015/0617/U5790P1503DT20150617111821_1.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÖÜѸ»éºóÔìÐÍ·´¹¥</span> - </a><a href="http://slide.eladies.sina.com.cn/news/slide_3_65868_24172.html" target="_blank"> - <img src="http://i0.sinaimg.cn/lx/old2013/photo/idx/2015/0304/U6929P8T440D1F14806DT20150304145841.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÖìÀò¾ÉÕÕÌðËÆÃÛ</span> - </a><a href="http://slide.eladies.sina.com.cn/news/slide_3_65868_24181.html" target="_blank"> - <img src="http://i3.sinaimg.cn/lx/old2013/photo/idx/2015/0305/U6929P8T440D1F14806DT20150305145059.jpg" /> - <span class="fc-bpac-bg"></span> - <span>±´Â³ÆæÃÀÕÕÅ̵ã</span> - </a><a href="http://slide.eladies.sina.com.cn/news/slide_3_65868_24189.html" target="_blank"> - <img src="http://i2.sinaimg.cn/lx/old2013/photo/idx/2015/0306/U6929P8T440D1F14806DT20150306142910.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Ó¾×°ÃÀÅ®ÐԸбÈÆ´</span> - </a> - - </textarea> - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_photo"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60818.html#p=1" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0617/U12708P30DT20150617113306.png" /> - <span class="fc-bpac-bg"></span> - <span>¸¸Ç×½ÚΪ°Ö°Ö×ö²Ë</span> - </a><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60816.html#p=1" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0617/U12708P30DT20150617113812.png" /> - <span class="fc-bpac-bg"></span> - <span>³¬¼¶¸ßÌú</span> - </a><a href="http://photo.auto.sina.com.cn/tuji/18245#53204155" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0617/U12708P30DT20150617142050.png" /> - <span class="fc-bpac-bg"></span> - <span>M135i ¶¯Á¦ÅìÅÈ</span> - </a><a href="http://photo.auto.sina.com.cn/tuji/18258#53273179" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0617/U12708P30DT20150617142302.png" /> - <span class="fc-bpac-bg"></span> - <span>°ÂµÏS7 È«ÃæÉý¼¶</span> - </a><a href="http://slide.news.sina.com.cn/green/slide_1_28436_85564.html#p=1" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U12708P30DT20150617140521.png" /> - <span class="fc-bpac-bg"></span> - <span>ÐÜÂèÂè½ÌСÐܲ¶ÁÔ</span> - </a><a href="http://slide.baby.sina.com.cn/other/slide_10_846_28238.html#p=1" target="_blank"> - <img src="http://i3.sinaimg.cn/home/2015/0617/U12708P30DT20150617141854.png" /> - <span class="fc-bpac-bg"></span> - <span>ÒòΪÉÙÅ®ËùÒÔͯÄê</span> - </a> - - </textarea> - </div> - - </div> - </div> - </div> - </div> - - </div> - -<!-- - <div tab-type="tab-cont" style="display:none"> -{miaopai_ÃëÅÄÇø¿éB°æ} - </div> ---> - - <div class="blank-cont" style="height:13px;"></div> - - <div tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <span tab-type="tab-nav" class="no-bl selected"><a href="http://video.sina.com.cn/news/" target="_blank" suda-uatrack="key=www_yaowen&value=video">ÊÓƵ</a></span> - <span tab-type="tab-nav"><a href="http://www.yixia.com/miaopai" target="_blank">ÃëÅÄ</a></span> - </div> - </div> - <div class="blank-cont" style="height:13px;"></div> -<div tab-type="tab-cont"> - <div class="videoLeftC" data-sudaclick="blk_videopic"> -<!-- publish_helper name='ÓéÀÖÊÓƵͼ' p_id='30' t_id='100' d_id='13' --> -<a class="uni-blk-pic uni-blk-pic-c" target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292542-1"> - <img width="105" height="60" src="http://i1.sinaimg.cn/home/2015/0618/U7647P30DT20150618100655.jpg" /> - <i class="vid-play-icon"></i> -<span>µË³¬±»Æسö¹ì</span> -</a> - -<!-- publish_helper name='ÌåÓýÊÓƵͼ' p_id='30' t_id='101' d_id='22' --> -<a class="uni-blk-pic uni-blk-pic-c" target="_blank" href=" http://video.sina.com.cn/p/sports/g/v/2015-06-18/103965026697.html"> - <img width="105" height="60" src="http://i2.sinaimg.cn/home/2015/0618/U8059P30DT20150618104559.jpg" /> - <i class="vid-play-icon"></i> -<span>ÄÚÂí¶ûÌßÈËȾºì</span> -</a> - </div> - <ul class="list-a videonewsList" data-sudaclick="blk_videonews"> -<!-- publish_helper name='ÒªÎÅ-ÊÓƵ' p_id='30' t_id='99' d_id='13' --> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138275365" target="_blank">̨Íå·ÆÂɱöÄϺ£¶ÔÖżÒôÆعâ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138291450" target="_blank">ÏÖ³¡-Ïã¸ÛÁ¢·¨»áÉóÒéÕþ¸Ä·½°¸</a></li> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138276407" target="_blank">ÃÀ¸»ºÀ²ÎÑ¡×ÜͳÑݽ²23´ÎÌáÖйú</a></li> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138275397" target="_blank">̨Íå×î´óº£Ñ²½¢ÃØÃÜѲº½ÄϺ£</a></li> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138292174" target="_blank">¾ª´ô£¡¿¹ÈÕÉñ¾ç×ÔÐгµ¾ø¼¼À×ÈË</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138291700" target="_blank">ÈýÅ®±í°×˧¸ç±»¾ÜÇ¿ÐÐקÆäÉϳµ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138291580" target="_blank">ÎÞÒµÄÐÍøÁÄÓÕ15´óѧÉúÆ­²ÆÆ­É«</a></li> - - </ul> -</div> - - <div tab-type="tab-cont" style="display:none;"> -<!-- publish_helper name='ÃëÅÄÇø¿éB°æ' p_id='30' t_id='139' d_id='3' --> -<div class="videoLeftC" data-sudaclick="blk_miaopaipic"><a class="uni-blk-pic uni-blk-pic-c" target="_blank" href="http://www.miaopai.com/stpid/n1qzlQ72ZEcXZiRK"> - <img width="105" height="60" src="http://i0.sinaimg.cn/home/2015/0617/U10743P30DT20150617120246.jpg" /> - <i class="vid-play-icon"></i> - <span>Âòµ¥Óöµ½µÄÞÏÞÎÊÂ</span> - </a> - <a class="uni-blk-pic uni-blk-pic-c" target="_blank" href="http://www.miaopai.com/stpid/-p7W09VBG4SbXt60"> - <img width="105" height="60" src="http://i0.sinaimg.cn/home/2015/0618/U10743P30DT20150618112557.jpg" /> - <i class="vid-play-icon"></i> - <span>´øÌðÜ°È¥º£±ßÍæË£</span> - </a></div><ul class="list-a videonewsList" data-sudaclick="blk_miaopainews"><li><a class="videoNewsLeft" href="http://www.miaopai.com/show/nQJye~rg7zaegsCVPW981w__.htm" target="_blank">³ÉÁú²»ÐÅ·¶±ù±ùÓÐÄÐÓѲ»ÖªÀ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/kRqHb1NbxONo0lBm3ah3dQ__.htm" target="_blank">ÑîÑó²ÝµØÂôÃÈ×ö¸öÓÇÓô˧ÆøÐÍÄÐ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/rf0TXZRw9d-P6a3K1TqbDg__.htm" target="_blank">¸çÃDZð˵ÄãÊǼûÒåÓÂΪű»´òËÀ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/TnLH-hEeMPMXOuSw4Az4xw__.htm" target="_blank">ÄÐÅóÓѵİ®³Æ°µ²ØÐþ»úСÐı»Æ­</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/IA4PhaElSwYI7TOhUw9aYw__.htm" target="_blank">ЦÅç!¹âÍ·Ç¿ºÍ¶þ¹·×ÓµÄÑóÎñÔ˶¯</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/~0CNpooVCgC2yBAEpBDfDQ__.htm" target="_blank">ÀÏÆÅÓÎÏ·Ö»ÄܶþÑ¡Ò»Äã»áÔõô×ö</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/mDMTFA0eF5f6kx-EsPcNFw__.htm" target="_blank">µ±ÐֵܵıðÇî×·²»Éá¸ø¸ǫ̈½×ÏÂ</a></li></ul> - </div> - </div> - - </div> - - </div> - </div> - <!-- mod04 --> - <div class="blank-cont" style="height:19px;"></div> - <!-- mod05 --> - <div class="mod-05 uni-blk mod-guess" id="SI_Order_Guess" tab-type="tab-wrap" tab-data="touch=0"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span tab-type="tab-nav" id="SI_Guess_span" class="no-bl selected clearfix"> - <em>²ÂÄãϲ»¶</em> - <span class="mod-guess-control" id="SI_Guess_Control" style="display:none;"><a class="mod-guess-prev" href="javascript:;" title="ÉÏÒ»Ö¡" id="SI_Guess_Prev" hidefocus="true">ÉÏÒ»Ö¡</a><span class="mod-guess-dots" id="SI_Guess_Dots"></span><a class="mod-guess-next" href="javascript:;" title="ÏÂÒ»Ö¡" id="SI_Guess_Next" hidefocus="true">ÏÂÒ»Ö¡</a></span> - </span> - -<!-- -<span tab-type="tab-nav" id="SI_channel_show_span" class=" " style=""><em><a href="http://edu.sina.com.cn/gaokao/" target="_blank">2015¸ß¿¼</a></em></span> ---> - -<!-- -<span tab-type="tab-nav" id="SI_channel_show_span2" class=" " style=""><em><a href="http://huodong.weibo.com/qiche/" target="_blank">»¶ÀÖ¹º³µ¼¾</a></em></span> ---> - - <span tab-type="tab-nav" id="SI_WEIBORecommend_span" class=" " style=""><em>ÈÈÃÅ»°Ìâ</em></span> - - </div> - <a id="SI_Guess_Login_Btn" class="weibo-login" title="ÇëÓÃ΢²©Õ˺ŵǼ£¬²ÂÄãϲ»¶ÍƼöЧ¹û¸üºÃ£¡" href="javascript:;">µÇ¼΢²©Ð§¹û¸ü¼Ñ</a> - </div> - <div class="mod05-cont SC_Order_Fix_Cont" > - <div tab-type="tab-cont"> - <div id="SI_Guess_Wrap" data-sudaclick="blk_guess" class="mod-guess-cont" page-length="5" list-length="8" item-length="24"> - <p class="loading"></p> - </div> - </div> - -<!-- - <div tab-type="tab-cont" style='display:none'> -edu_2015¸ß¿¼ - </div> ---> -<!-- - <div tab-type="tab-cont" style='display:none'> -{auto_ÉϺ£³µÕ¹} - </div> ---> - <div tab-type="tab-cont" style='display:none'> - <div id="SI_WEIBORecommend_Wrap" data-sudaclick="blk_weibohottopic" class="mod-weiboGuess-cont" page-length="16" list-length="8" item-length="24"> - <p class="loading"></p> - </div> - </div> - - <div style="border-bottom:1px solid #e9e9e9;"> - <style type="text/css"> - /*.list-a-ad li{background: none;} - Ô­µãÑùʽ - .list-a-ad a:link,.nmod01 a:visited{color:#596a7b;} - Á´½ÓÑÕÉ« - */ - </style> - - <ul class="list-a list-a-ad" data-sudaclick="blk_mt_tg"> -<!-- publish_helper name='ýÍØ-²ÂÄãϲ»¶°å¿éÍƹã' p_id='30' t_id='123' d_id='7' --> -<li> - -<a target="_blank" href="http://auto.sina.com.cn/2015-06-16/detail-ifxczqap4176884.shtml">4¿î¸ßÆ·ÖʺÀ»ª³µÍƼö</a> <a target="_blank" href="http://photo.auto.sina.com.cn/tuji/18268">ÇÀÏÈʵÅÄÎÖ¶ûÎÖXC90 80ÍòÆðÊÛ</a></li> - </ul> - </div> - -<!--Ͷ×ʺ£µí begin--> - <div class="nmod01" data-sudaclick="blk_ad_tzhd" style="border-top:0px;"> - <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjE2MA%3D%3D&sign=74df9fa89934325d&url=http%3A%2F%2Finvest.bjhd.gov.cn%2F" target="_blank">Ͷ×ʺ£µí</a> | <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjE5NA%3D%3D&sign=423b0ef0acbb446d&url=http%3A%2F%2Fwww.zhsp.gov.cn%2F" target="_blank">Öйشå¹ú¼Òʾ·¶Çø</a> <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjE2MQ%3D%3D&sign=8835c2fd4467a441&url=http%3A%2F%2Finvest.bjhd.gov.cn%2Fzctx%2F" target="_blank">º£µíÇø1+4+1Õþ²ßÌåϵ</a> - </div> -<!--Ͷ×ʺ£µí begin--> - </div> - -<script> -/* ÈÈÃÅ»°Ì⡢ƵµÀ°å¿éËæ»úÏÔʾ */ - -/* -var fortab_random = parseInt(2*Math.random()); - if (fortab_random == "1"){ - document.getElementById("SI_WEIBORecommend_span").style.display = ""; - document.getElementById("SI_channel_show_span").style.display = "none"; - //document.getElementById("SI_channel_show_span2").style.display = "none"; - } - if (fortab_random == "0"){ - document.getElementById("SI_WEIBORecommend_span").style.display = "none"; - document.getElementById("SI_channel_show_span").style.display = ""; - //document.getElementById("SI_channel_show_span2").style.display = ""; - } -*/ -</script> - - </div> - <!-- mod05 --> - - </div> - <div class="part-a-r"> - <!-- mod06 --> - <div tab-type="tab-wrap" class="mod-06 uni-blk" id="wwwidx_imp_con"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - - <span tab-type="tab-nav" class="no-bl selected"><a href="http://news.sina.com.cn/" target="_blank" suda-uatrack="key=www_yaowen&value=news">ÐÂÎÅ</a></span> - <span tab-type="tab-nav" id="SI_IP_Tab_Nav_1" style="display:none;"></span> - -<span id="xy-imptabtp-A" style="padding:0; margin-top:0px;"> -<span class="order-menu-lnk" ><a target="_blank" href="http://photo.sina.com.cn/" suda-uatrack="key=www_yaowen&value=photo">ͼƬ</a></span> -<span class="order-menu-lnk" ><a target="_blank" href="http://zhuanlan.sina.com.cn/" suda-uatrack="key=www_yaowen&value=zhuanlan">רÀ¸</a></span> -</span> - -<div id="xy-imptabtp-B" style="display:none;"> -</div> - - </div> - -<span class="t-guide">2015.6.18</span> - - </div> - <div tab-type="tab-cont" class="mod06-cont" data-sudaclick="blk_news_all" blkclick="auto_nav" blktitle="ÒªÎÅ"> - <div class="blank-cont" style="height:20px"></div> - -<div id="xy-impcon-A"> -<!-- publish_helper name='ÒªÎÅ-ÐÂÎÅ' p_id='1' t_id='850' d_id='1' --> -<ul class="list-a" id="syncad_0" data-sudaclick="blk_news_0"> -<!--Ö±´ïÍ·ÌõλÖñê¼Ç--> -<!--ÿÐв»³¬¹ý25¸ö×Ö--> - -<li><a target="_blank" href="http://news.sina.com.cn/c/p/2015-06-17/231431962078.shtml">Ï°½üƽ¸ßËÙ·ÅÔ¿´³¬ÊРѯÎÊʳƷ±£ÖÊÆÚ</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/221831962034.shtml">ÏçÇ×Çé</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/162731961377.shtml">×ùÓÒÃú</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/191631961826.shtml">Àî¿ËÇ¿£º»¹ÓÐ1ÒÚ¶àÈËÉú»îÔÚÅﻧÇø ²»½â¾öºÎ̸¹«Æ½</a></li> - -<li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/175831961619.shtml">ÇÇʯÒÅÌåÖÜÎå»ð»¯Ìì°²ÃÅÏ°ëÆì</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/185531961733.shtml" >ÄÄЩÁìµ¼ÈËÊÅÊÀ½µÁËÆì</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/222731962040.shtml">ÐÂÀËÃñµ÷£º¹ÕÂô¶ùͯӦ¸ÃÒ»ÂÉÅÐËÀÐÌÂð£¿</a></li> - -<li><a href="http://news.sina.com.cn/c/2015-06-18/111031964858.shtml" target="_blank">Ò»¼üֱͨÖмÍί£¡»¶Ó­ÓÃÊÖ»úÅÄÉã¾Ù±¨¹«¿î³ÔºÈ</a></li> - -</ul> - -<div class="blank-d" style="height:10px"></div> -<ul class="list-a" id="syncad_1" data-sudaclick="blk_news_1"> - -<li><span class="fe661"><a target="_blank" href="http://news.sina.com.cn/china/">¹úÄÚ</a> | </span><a href="http://news.sina.com.cn/c/2015-06-18/100531964553.shtml" target="_blank">¹úÎñÔº£º7ÔÂÆð ̨°ûÀ´Íù´ó½ÃâÇ©</a> <a href="http://news.sina.com.cn/c/2015-06-18/124531965111.shtml" target="_blank">ÈçºÎ°ìÀí</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/120231965030.shtml">Èý²¿ÃÅ£ºÈ«ÃæÇåÀí¡°ÄãÂèÊÇÄãÂ衱µÈÆæÝâÖ¤Ã÷</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/125631965129.shtml">Ïã¸ÛÕþ¸Ä·½°¸ÔâÁ¢·¨»á·ñ¾ö</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/094031964472.shtml">102ËêÃñ¹ú²ÅÅ®ÕųäºÍÈ¥ÊÀ ºÏ·ÊËĽãÃóɾøÏì(ͼ)</a></li> - -<li><a href="http://news.sina.com.cn/c/2015-06-18/115131965018.shtml" target="_blank">Çì°²¼Í¼ì¸É²¿µÃ×ï·¿²úÉ̱»Î§Å¹ÖÂËÀ ÒÑ×¥»ñ9ÈË</a></li> - -<li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/110231964841.shtml">¹ã¶«ÎªÇÀ¾Èº«¹úMERS»¼Õß15Ì컨µôÓâ800Íò</a></li> - -<li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/121231965051.shtml">¶­Ã÷Ö飺¹¤Ð½½×²ãÄêÊÕÈë10ÍòÔªÒÔϲ»Òª½»Ë°</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/023931962493.shtml">´óÊåÓë15ÃûÅ®´óѧÉúÁµ°®Æ­35Íò 3ÈËÔøΪÆä¶éÌ¥</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/z/dzzgr/">[ÖйúζÈ]</a><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/023331962458.shtml">ĸÇ×¼á³Ö258Ì콫ֲÎïÈËÅ®¶ù»½ÐÑ(ͼ)</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/zxt/#vid=138292678" class="videoNewsLeft">ÐÂÀË×ÊѶ̨£ºÏÖ³¡-ÓοÍÎóÈëÓ¢»Ê¼ÒÎÀ±ø¶ÓÁб»×²¿ª</a></li> - -<li><span class="fe661"><a href="http://zhuanlan.sina.com.cn/" target="_blank" suda-uatrack="key=index_column_click&value=click">רÀ¸</a></span> | <a target="_blank" href="http://zhuanlan.sina.com.cn/" suda-uatrack="key=index_column_click&value=click">ÈË··×ÓÒ»ÂÉËÀÐ̺ݻ°¹ý·ÖÂð</a> <a target="_blank" href="http://news.sina.com.cn/zl/zatan/2015-06-18/12353905.shtml" suda-uatrack="key=index_column_click&value=click">Íâ¹ú·¨ÂÉÈçºÎ³ÍÈË··</a></li> - -</ul> -<ul class="list-a" id="syncad_2" data-sudaclick="blk_news_2"> - -<li><span class="fe661"><a target="_blank" href="http://news.sina.com.cn/world/">¹ú¼Ê</a> | </span><a href="http://news.sina.com.cn/w/p/2015-06-18/050031962821.shtml" target="_blank" >·¨¹úר³µË¾»úÓë³ö×⳵˾»ú³åÍ»ÔâÈÓʯ¿é(ͼ)</a></li> - -</ul> -</div> - -<div id="xy-impcon-B" class="xy-impcon-B" style="display:none;"> - <ul class="list-a" id="syncad_0_B" data-sudaclick="blk_news_0_B"> - <li><a target="_blank" href="http://news.sina.com.cn/c/p/2015-06-17/231431962078.shtml">Ï°½üƽ¸ßËÙ·ÅÔ¿´³¬ÊРѯÎÊʳƷ±£ÖÊÆÚ</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/221831962034.shtml">ÏçÇ×Çé</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/162731961377.shtml">×ùÓÒÃú</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/191631961826.shtml">Àî¿ËÇ¿£º»¹ÓÐ1ÒÚ¶àÈËÉú»îÔÚÅﻧÇø ²»½â¾öºÎ̸¹«Æ½</a></li><li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/175831961619.shtml">ÇÇʯÒÅÌåÖÜÎå»ð»¯Ìì°²ÃÅÏ°ëÆì</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/185531961733.shtml" >ÄÄЩÁìµ¼ÈËÊÅÊÀ½µÁËÆì</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/222731962040.shtml">ÐÂÀËÃñµ÷£º¹ÕÂô¶ùͯӦ¸ÃÒ»ÂÉÅÐËÀÐÌÂð£¿</a></li><li><a href="http://news.sina.com.cn/c/2015-06-18/111031964858.shtml" target="_blank">Ò»¼üֱͨÖмÍί£¡»¶Ó­ÓÃÊÖ»úÅÄÉã¾Ù±¨¹«¿î³ÔºÈ</a></li><li><span class="fe661"><a target="_blank" href="http://news.sina.com.cn/china/">¹úÄÚ</a> | </span><a href="http://news.sina.com.cn/c/2015-06-18/100531964553.shtml" target="_blank">¹úÎñÔº£º7ÔÂÆð ̨°ûÀ´Íù´ó½ÃâÇ©</a> <a href="http://news.sina.com.cn/c/2015-06-18/124531965111.shtml" target="_blank">ÈçºÎ°ìÀí</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/120231965030.shtml">Èý²¿ÃÅ£ºÈ«ÃæÇåÀí¡°ÄãÂèÊÇÄãÂ衱µÈÆæÝâÖ¤Ã÷</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/125631965129.shtml">Ïã¸ÛÕþ¸Ä·½°¸ÔâÁ¢·¨»á·ñ¾ö</a></li> - </ul> - - <div class="blank-cont" style="height:13px;"></div> - - <div tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://zhuanlan.sina.com.cn/" target="_blank">רÀ¸</a></span> -<!-- - <span tab-type="tab-nav" ><a href="http://weibo.com/" target="_blank">΢²©</a></span> ---> - </div> - </div> - - <div class="blank-cont" style="height:13px;"></div> - - <ul class="list-a" id="syncad_1_B" tab-type="tab-cont" data-sudaclick="blk_zhuanlan"> - <li><a target="_blank" href="http://finance.sina.com.cn/zl/china/20150618/080022463638.shtml">»¥ÁªÍø+ÒªÎüÈ¡ÃÀ¹úµÄ½Ìѵ</a> <a target="_blank" href="http://finance.sina.com.cn/focus/ggwd_zxy">Ò»´øһ·²»Äܱ§Õü¾ÈËûÈËÐÄ̬</a> </li> -<li><a target="_blank" href="http://cul.history.sina.com.cn/zl/shiye/2015-06-15/15021153.shtml">²Â¶¡¿Ç£ºÓÎÏ·ÌåÏֵġ°¹«Æ½¡±</a> <a target="_blank" href="http://cul.history.sina.com.cn/zl/redian/2015-06-15/17491154.shtml">´Ó¸ß¿¼×÷ÎÄÈ«¹ú¾í˵¿ªÈ¥</a></li> -<li><a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/i/2015-06-18/pid_8481226.htm">360˽Óл¯ÊÇΪ»ØA¹ÉȦǮÂð</a> <a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/it/2015-06-18/pid_8481223.htm">Oculus£ºÐÂÒ»´úÔ¼ÅÚÉñÆ÷£¿</a></li> -<li><a href="http://ent.sina.com.cn/zl/" target="_blank">ÂÞÖ¾ÏéÍøºìл¶ÕûÈݾÉÕÕÁ³´ó</a><a href="http://ent.sina.com.cn/zl/bagua/blog/2015-06-16/15383552/1243021947/4a17027b0102vkcq.shtml" target="_blank"> 47ËêÅ®ÉñÕÅÃô¶Ì·¢Ã²ÃÀ</a></li> -<li><a href="http://sports.sina.com.cn/zl/basketball/2015-06-17/zldoc-ifxczqap4207893.shtml" target="_blank">ÑîÒã:ÓÂʿʱ´ú¿âÀïÔڵȴý</a> <a href="http://sports.sina.com.cn/zl/football/2015-06-17/zldoc-ifxczyze9659633.shtml" target="_blank">ÃÏ·±´ï:ÄÐ×ã×î´óѹÁ¦ÊÇÅ®×ã</a></li> -<li><a href="http://fashion.sina.com.cn/zl/fashion/2015-06-17/14423786.shtml" target="_blank">ûÊÂÒµÂí¼×Ïßզѡ±È»ùÄá</a> <a href="http://fashion.sina.com.cn/zl/fashion/2015-06-17/17063791.shtml" target="_blank">Ì©ÀÕ˹Íþ·òÌؽÖÅÄм¼ÄÜget</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/zl/edu/2015-06-17/10492798.shtml">Ê®´ó¸ßнÐÐÒµ</a> <a target="_blank" href="http://edu.sina.com.cn/zl/edu/blog/2015-06-17/10272797/1594826071/5f0f1d570102vp0j.shtml">»ªÅ©Ð£»¨Å®Íõ·¶(ͼ)</a> <a target="_blank" href="http://edu.sina.com.cn/zl/oversea/blog/2015-06-16/11102796/2771745342/a5357a3e0102vv45.shtml">ÄãÔÚÃÀ¹úÄÜÕõ¶àÉÙÇ®</a></li> - </ul> - -<!-- - <ul tab-type="tab-cont" class="uni-blk-list02 list-a" style="padding-top:0px;_zoom:1;display: none;" data-sudaclick="blk_weibo_1"> -{weibo_΢²©} - </ul> ---> - - </div> - -</div> - - <div class="blank-cont" style="height:13px"></div> - <ul class="list-a" id="syncad_3" data-sudaclick="blk_topfinance_1"> -<!-- publish_helper name='ÒªÎÅ-²Æ¾­' p_id='30' t_id='98' d_id='1' --> -<li><span class="fe661"><a href="http://finance.sina.com.cn/" target="_blank">²Æ¾­</a> | </span> <a target="_blank" href="http://finance.sina.com.cn/china/20150618/093122464500.shtml ">5ÔÂ20³Çз¿¼Û¸ñ»·±ÈÉÏÕÇ ÉîÛÚÕÇ·ù×î¸ß(¸½±í)</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/gsnews/20150618/010922459366.shtml">ÑëÆó²©ÞÄ£º¡°Âò·½Â¢¶ÏÖÐÌú×Ü¡±µ£ÐÄÖгµ·´×ª»°ÓïȨ</a></li> - -<li><a target="_blank" href=" http://finance.sina.com.cn/chanjing/gsnews/20150618/023922461223.shtml ">ÖÐͶ֤ȯԭ¶­Ê³¤¹«¿î³ÔºÈ40Íò »¨Ç®Âò¹Ù¹«¿î³öÊé(ͼ)</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/stock/level2/orderIntro.html" class="linkRed">ÐÂÀ˲ƾ­Ê×ÍƸ߶˰æA¹ÉÐÐÇé Äê·Ñ998Ôª</a> <a target="_blank" href="http://finance.sina.com.cn/focus/i300/" class="linkRed">i300Ö¸»ùÇÀ¹ºÖÐ</a></li> - - </ul> - <ul class="list-a" data-sudaclick="blk_tophouse_1"> -<!-- 13:16:46 --> -<li><a href="http://news.leju.com/" target="_blank">Íò¿Æ¸ß¹ÜÔٶȵ÷Õû</a> <a href="http://bj.house.sina.com.cn/news/2015-06-18/13006017163671862817221.shtml" target="_blank">ÊÀ½çO2O´ó»áºØÒúÓî̸Òƶ¯»¥Áª</a></li> - - </ul> - <ul class="list-a" id="syncad_4" data-sudaclick="blk_toptech_1"> -<!-- publish_helper name='ÒªÎÅ-¿Æ¼¼' p_id='30' t_id='103' d_id='1' --> -<li><span class="fe661"><a href="http://tech.sina.com.cn/" target="_blank">¿Æ¼¼</a> | </span><a href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxefurt9344968.shtml" target="_blank">Ê¢´óÓÎϷ˽Óл¯²ÆÍÅÔÙÉú±ä£ºÖÐÒøÈÞÒµÒâÍâ³ö¾Ö</a></li> - -<li><a href="http://tech.sina.com.cn/it/2015-06-17/doc-ifxefurq6045451.shtml" target="_blank">΢ÈíÖØ×é¹ÜÀí²ã£ºÅµ»ùÑÇÇ°CEO°£ÂåÆÕ½«ÀëÖ°</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-18/doc-ifxefurt9354794.shtml">ÎÒÃǵĴóÄÔ¿Õ¼ä»á±»ÓÃÍêÂð?</a> <a href="http://slide.tech.sina.com.cn/d/slide_5_453_60863.html" target="_blank">ÏÖʵ°æ±äÐνð¸Õ¼¸Ãë±äÆû³µ</a></li> - </ul> - <ul class="list-a" data-sudaclick="blk_topd_1"> -<!-- publish_helper name='ÒªÎÅ-ÔËÓª' p_id='30' t_id='123' d_id='2' --> -<li><span class="fe661"><a href="http://fashion.sina.com.cn/" target="_blank">ʱÉÐ</a> | </span> -<a href="http://fashion.sina.com.cn/" target="_blank">Áõ¼ÎÁáºÍÅ®ÍõÈ¥¿´ÂíÁË</a> -<a href="http://slide.fashion.sina.com.cn/m/slide_24_66132_60867.html" target="_blank">ÑîÃݸßÔ²Ô²°×T³¬´óÅÆ</a></li> - </ul> - - <ul class="list-a" data-sudaclick="blk_topd_2"> -<li> -<span class="fe661">Èȵã | </span> -<ins class="sinaads" data-ad-pdps="PDPS000000046154"></ins><script>(sinaads = window.sinaads || []).push({});</script> - <!--µØÓò¶¨ÏòÎÄ×ÖÁ´ begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000045978"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<!--µØÓò¶¨ÏòÎÄ×ÖÁ´ end--> -</li> - -<li> -<span class="fe661">¹Ø×¢ | </span> -<ins class="sinaads" data-ad-pdps="PDPS000000045979"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<ins class="sinaads" data-ad-pdps="PDPS000000045980"></ins><script>(sinaads = window.sinaads || []).push({});</script> -</li> - -<li> -<span class="fe661"><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDgzMg%3D%3D&sign=c1466af9aee00db5&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fguanzhu1%2F%3Ftel%3D1%26src%3D0001" target="_blank">±Ø¿´</a> | </span> -<a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDgzMg%3D%3D&sign=c1466af9aee00db5&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fguanzhu1%2F%3Ftel%3D1%26src%3D0001" target="_blank">2ÕÐ,ÈÃʧÃßÈË˯¸öºÃ¾õ</a> -<a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwMjk1NQ%3D%3D&sign=4f57cb0d7cc05f97&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fguanzhu-2a%2F" target="_blank">½ÒÃØ:ÌÇÄò²¡-ÕæÕý¸ùÔ´</a> -</li> - - </ul> - - </div> - <div tab-type="tab-cont" id="SI_IP_Tab_Cont_1" class="mod06-cont" style="display:none;" data-sudaclick="blk_topcity_1" blkclick="auto_nav" blktitle="µØ·½Õ¾"> - </div> - - </div> - <!-- mod06 --> - </div> - </div> - <!-- part-a end --> - -<!-- ÒªÎÅÇø¶¨Ïò¹ã¸æ´úÂë --> -<!-- nosmb begin --> -<script language="javascript" type="text/javascript"> -(function() { - function addEvent(obj, eventType, func) { - if(obj.attachEvent) { - obj.attachEvent("on" + eventType, func); - } else { - obj.addEventListener(eventType, func, false); - } - }; - - function attachURL2Window(id,url) { - var links; - try { - links = document.getElementById(id).getElementsByTagName("a"); - }catch(e) { - links = []; - } - for (var i = 0, len = links.length; i < len; i++) { - addEvent(links[i], "mousedown", function(e) { - var writeCookie = function(O, o, l, I, p) { - var i = "", - c = "", - path = ""; - if (l != null) { - if(l == "NaN"){ - i = ";"; - }else{ - i = new Date((new Date).getTime() + l * 3600000); - i = "; expires=" + i.toGMTString(); - } - }; - if (I != null) { - c = ";domain=" + I - }; - if(p != null){ - path = ";path=" + p; - }; - document.cookie = O + "=" + escape(o) + i + c + path; - }; - writeCookie("directAd","true",1,".sina.com.cn","/"); - //µã»÷¼à²â - var _clickStat = new Image(); - _clickStat.src = url + "&_=" + new Date().getTime() + "&url="; - }); - } - }; - - attachURL2Window("syncad_1","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,533936,539210&cid=0,0,0&sid=540113&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_2","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,534288,539558&cid=0,0,0&sid=540487&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_3","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,534289,539559&cid=0,0,0&sid=540488&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_4","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,539990,545264&cid=0,0,0&sid=546428&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_0","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,547080,552353&cid=0,0,0&sid=553716&advid=358&camid=69129&show=ignore"); - - attachURL2Window("syncad_0_B","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,547080,552353&cid=0,0,0&sid=553716&advid=358&camid=69129&show=ignore"); - -})() -</script> -<!-- nosmb end --> -<!-- ÒªÎÅÇø¶¨Ïò¹ã¸æ´úÂë --> - - <div class="blank-cont" style="height:20px;"></div> - - <!-- pageload firstpage --> - -<script src="http://i.sso.sina.com.cn/js/ssologin.js"></script> - -<!-- ABban --> -<script> - jsLoader({ - name: 'shm', - url: 'http://www.sina.com.cn/js/index/96/0801/shm.js' - }); - - // ÐÞ¸Ä 5 begin -jsLoader({ - name: 'shm', - callback: function () { - var sguid = SHM.util.cookie.getCookie('SINAGLOBAL'); - if (typeof sguid == 'string') { - lastNum = sguid.charAt(sguid.length - 1, 1); - if (lastNum == '6') { - var timer1 = null; - var pic_utils = { - $: function (id) { - return document.getElementById(id); - }, - fixEvent: function (e) { - var e = e || win.event; - e.target = e.target ? e.target : e.srcElement; - return e; - }, - delegateByTag: function(ele,tag,etype,fn){ - var that = this; - that.addEvent(ele,etype,function(ev){ - var e = that.fixEvent(ev); - var t = e.target; - tag = tag.toLowerCase(); - do { - if(t.nodeName && t.nodeName.toLowerCase() === tag){ - fn(e, t); - } - t = t.parentNode; - } while (t && t !== ele) - }); - }, - addEvent: document.addEventListener ? - function (elem, type, fn) { - elem.addEventListener(type, fn, false); - } : function (elem, type, fn) { - elem.attachEvent('on' + type, fn); - }, - removeEvent: document.removeEventListener ? - function (elem, type, fn) { - elem.removeEventListener(type, fn, false); - } : function (elem, type, fn) { - elem.detachEvent('on' + type, fn); - } - }; - var bPicArea = pic_utils.$('fc_B_pic'), - bPicAttachment = pic_utils.$('fc_B_pic_attachment'), - bPicShow = 0; - pic_utils.addEvent(bPicArea, 'mouseover', function (e) { - clearTimeout(timer1); - bPicAttachment.style.display = ''; - try { - ! bPicShow && _S_uaTrack('index_wwwb_photo', 'pic_show'); - bPicShow = 1; - } catch (e) {}; - }); - pic_utils.addEvent(bPicArea, 'mouseout', function () { - clearTimeout(timer1); - timer1 = setTimeout(function () { - bPicAttachment.style.display = 'none'; - bPicShow = 0; - }, 300); - }); - var picbd = document.getElementById('picBNav'), currentTag = ''; - pic_utils.delegateByTag(picbd, 'span', 'mouseover', function (e, t) { - // console.log(t); - if (t.getAttribute('data-picb-uaTrack') == currentTag) { - return; - } - currentTag = t.getAttribute('data-picb-uaTrack'); - try { - _S_uaTrack('index_wwwb_photo', currentTag); - } catch (e) {} - }); - } - } - } -}); - // ÐÞ¸Ä 5 end - - jsLoader({ - name: 'shm', - callback: function(){ - jsLoader({ - name: 'StateMgr', - url: 'http://www.sina.com.cn/js/96/2014/0317/StateMgr.js', - callback:function(){ - var guessCtr=document.getElementById('SI_Guess_Wrap'); - var mgr = new SHM.xy.stateMgr({ - timeSlice: 0, //min - state1Ids:['xy-tabA', 'xy-contA', 'xy-imptabtp-A', 'xy-impcon-A'], - state2Ids:['xy-tabB', 'xy-contB', 'xy-imptabtp-B', 'xy-impcon-B'], - s1Callback:function(){ - //guessCtr.style.height='186px';//8 Ìõ - SHM.app.tab.switchByEle(SHM.E('video-tab')); -try{_S_uaTrack("www_update_div", "a");}catch(e){} - }, - s2Callback:function(){ - //guessCtr.style.height='186px';//8 Ìõ - SHM.app.tab.switchByEle(SHM.E('zhuanlan-tab')); -try{_S_uaTrack("www_update_div", "b");}catch(e){} - } - }); - SHM.evt.addEvent(SHM.E('xy-change'), 'click', function(evt){ - mgr.toggleState(); - SHM.evt.preventDefault(evt); - }, false); - } - }); - } - }); -</script> - - <!-- µÇ¼¸¡²ã js plugin start --> - <script type="text/javascript" src="http://i.sso.sina.com.cn/js/outlogin_layer.js" charset="UTF-8"></script> - <!-- µÇ¼¸¡²ã js plugin end --> -<script type="text/javascript" src="http://i.sso.sina.com.cn/js/user_panel_homepage.js" charset="UTF-8"></script> - <script> - - // 20140403 MOD lqf {update the default hot} -jsLoader({name: "shm",callback: function() { - SHM.register("io.jsonp2", function($) { - return function(url, params, callback, fix) { - var head_dom, old_script, script_dom, byId = $.dom.byId, idStr = url + "&" + params, fun = ""; - byId(url) && document.body.removeChild(byId(url)), fix = fix || !1, fix ? "string" == typeof callback && (fun = callback) : (url = url + (-1 == url.indexOf("?") ? "?" : "&") + "_t=" + Math.random(), "function" == typeof callback && (fun = "fun_" + (new Date).getUTCMilliseconds() + ("" + Math.random()).substring(3), eval(fun + "=function(res){callback(res)}"))), url = url + "&_cb=" + fun, url = url + "&" + params, head_dom = document.getElementsByTagName("head")[0], old_script = byId(idStr), old_script && head_dom.removeChild(old_script), script_dom = $.C("script"), script_dom.src = url, script_dom.id = idStr, script_dom.type = "text/javascript", script_dom.language = "javascript", head_dom.appendChild(script_dom) - } - }), SHM.register("home.suggest", function(a) { - var b = {requestURL: "http://s.weibo.com/ajax/jsonp/suggestion?ver=1&Refer=sina_sug",searchURL: "http://s.weibo.com/weibo/@@key@@",interTime: 6e5}, c = "top-suggest-", d = c + "wrap", e = c + "item", f = c + "evt", g = window, h = g.document, j = ($globalInfo.ua.isIOS, a.str.trim), k = a.dom.addClass, m = a.dom.removeClass, n = a.dom.byAttr, o = a.io.jsonp2, p = a.evt.addEvent, q = a.evt.delegatedEvent, r = function(a) { - this.input = a.input, this.maxLen = a.maxLen || 10, this.onoff = a.onoff || "on", this.index = -1, this.cache = new Object, this.controlFunction = a.controlFunction || function() { - }, this.init.apply(this, arguments) - }; - return r.prototype = {init: function() { - var d, a = this, b = a.input; - return "off" === a.onoff ? !1 : (a.wrap = b.parentNode, b.setAttribute("autocomplete", "off"), d = q(a.wrap), a.setDefault(), a.getRandomKey(), d.add(f, "mouseover", function(b) { - var c = b.el; - a.select(c) - }), d.add(f, "mouseout", function(b) { - var d = b.el, e = c + "mover"; - d.className.indexOf(e) && m(d, e), !!a.cache.curitem && m(a.cache.curitem, e) - }), d.add(f, "mousedown", function(b) { - a.evtclick(b.el) - }), p(b, "focus", function() { - !a.cache.listStatus && a.getTimeOut(a.show, "show") - }), b.onpropertychange ? b.onpropertychange = function() { - a.sendRequest() - } : p(b, "input", function() { - a.sendRequest() - }), p(b, "blur", function() { - a.getTimeOut(a.hidden, "hidden") - }), p(b, "keydown", function(b) { - a.keydownEvt(b) - }), p(b, "keyup", function(b) { - var b = b || g.event; - return 38 == b.keyCode || 40 == b.keyCode || 27 == b.keyCode ? !1 : (a.sendRequest(), void 0) - }), void 0) - },getTimeOut: function(a, b) { - var c = this, d = c.cache["timeLayer_" + b]; - !!d && clearTimeout(d), c.cache["timeLayer_" + b] = setTimeout(function() { - a.apply(c, arguments) - }, 200) - },sendRequest: function() { - var a = this, c = a.getInputVal(); - a.setDefault(), "" !== c ? (a.getSugData(b.requestURL, "key=" + encodeURIComponent(c)), a.cache.listType = "sug") : (a.cache.hotList ? (a.sugWrap.innerHTML = a.cache.hotList, a.cache.curVal = "", a.curMaxLen = a.sugWrap.getElementsByTagName("DIV").length - 2, a.innerShowORHidden(!0)) : a.getHotData(b.requestURL, "", !0), a.cache.listStatus = !1, a.cache.listType = "hot") - },setDefault: function() { - var a = this; - a.cache.curitem = null, a.cache.curindex = -1 - },show: function() { - var a = this; - a.sugWrap ? a.innerShowORHidden(!0) : a.sugWrap = a.createSugList() - },hidden: function() { - this.innerShowORHidden(!1); - var a = this.getInputVal(); - "" !== a && "ÇëÊäÈë¹Ø¼ü×Ö" !== a && (this.cache.listStatus = !0) - },innerShowORHidden: function(a) { - var b = this; - b.sugWrap.className = "΢²©" === h.SearchEcho.SerchType.value ? "top-suggest-wrap weibo-suggest" : "top-suggest-wrap news-suggest", this.controlFunction() ? a ? (b.sugWrap.style.display = "block", b.cache.keyDownOff = !1) : (b.sugWrap.style.display = "none", b.cache.keyDownOff = !0) : (b.sugWrap.style.display = "none", b.cache.keyDownOff = !0) - },getInputVal: function() { - return j(this.input.value) - },evtclick: function(a) { - var c = a.innerHTML, d = encodeURIComponent(encodeURIComponent(c)); - this.input.value = c, "΢²©" === h.SearchEcho.SerchType.value ? (h.hform_10.Refer.value = void 0 != this.cache.curVal && c != j(this.cache.curVal) ? "sug" === this.cache.listType ? "sina_sug" : "sina_hot_sug" : "sina_index", h.hform_10.setAttribute("action", b.searchURL.replace("@@key@@", d)), h.hform_10.submit()) : "ÐÂÎÅ" === h.SearchEcho.SerchType.value && (h.hform_02.q.value = c, h.hform_02.submit()) - },keydownEvt: function() { - var c, d, a = this, b = arguments[0] || g.event; - if (a.cache.keyDownOff) - return !1; - switch (b.keyCode) { - case 38: - d = a.curMaxLen || a.maxLen, c = -1 === a.cache.curindex ? d - 1 : a.cache.curindex - 1, a.select(c, !0); - break; - case 40: - d = a.curMaxLen || a.maxLen, c = -1 === a.cache.curindex ? 0 : a.cache.curindex === d - 1 ? -1 : a.cache.curindex + 1, a.select(c, !0); - break; - case 13: - } - },select: function(a, b) { - var e, f, d = this, g = c + "mover", h = d.cache.curitem; - "object" == typeof a ? function() { - e = a, f = +e.getAttribute("index") - }() : function() { - -1 === a ? (e = null, f = -1) : (e = n(d.sugWrap, "index", a + "")[0], f = +a) - }(), !!h && m(h, g), e ? (k(e, g), d.cache.curitem = e, d.cache.curindex = f, b && (d.input.value = e.innerHTML)) : (d.input.value = d.cache.curVal, d.cache.curitem = null, d.cache.curindex = -1), setTimeout(function() { - d.setCursorPos(d.input.value.length) - }, -1) - },setCursorPos: function(a) { - var c, b = this.input; - b.setSelectionRange ? (b.setSelectionRange(a, a), b.focus()) : (c = b.createTextRange(), c.collapse(!0), c.moveEnd("character", a), c.moveStart("character", a), c.select()) - },createSugList: function() { - var c = this, e = c.input; - if (a.util.getUniqueKey(), !e) - throw "input is undefined!"; - - return c.sugWrap = h.createElement("DIV"), c.sugWrap.className = d, c.innerShowORHidden(!1), e.value = "", c.cache.hotList ? (c.sugWrap.innerHTML = c.cache.hotList, c.innerShowORHidden(!0)) : c.getHotData(b.requestURL, "", !0), c.wrap.appendChild(c.sugWrap), setInterval(function() { - c.getHotData(b.requestURL, "", !1) - }, b.interTime), c.sugWrap - },getHotData: function(a, b, c) { - var d = this, e = function(a) { - if (1e5 == a.code && a.data.list.length) { - var b = a.data.list; - c ? (d.cache.hotList = d.sugWrap.innerHTML = d.itemConsturctor(b, 0), d.innerShowORHidden(!0)) : d.cache.hotList = d.itemConsturctor(b, 0, !0) - } else - d.innerShowORHidden(!1) - }; - o(a, b, e) - },getSugData: function(a, b) { - var c = this, d = function(a) { - if (1e5 == a.code && a.data.length) { - if ("" !== c.getInputVal()) { - var b = a.data; - c.sugWrap.innerHTML = c.itemConsturctor(b, 1), c.innerShowORHidden(!0), c.cache.listStatus = !1 - } - } else - c.innerShowORHidden(!1) - }; - o(a, b, d) - },getRandomKey: function() { - var a = this, c = a.input, d = function(a, b) { - return Math.floor(a + Math.random() * (b - a)) - }, e = function(b) { - if (1e5 == b.code && b.data.list.length) { - var e = b.data.list, f = b.data.show, h = d(0, f); - - a.cache.hotList = a.itemConsturctor(e, 0); - // MOD lqf 20140414 {default search error} - a.cache.curVal = e[h]; - - g.___homeSugVal___ = c.value = "´ó¼ÒÕýÔÚËÑ£º" + e[h], a.cache.keyDownOff = !0 - } else - c.value = "ÇëÊäÈë¹Ø¼ü×Ö\r\n" - }; - o(b.requestURL, "", e) - },itemConsturctor: function(a, b, c) { - var g, h, i, j, k, d = this; - for (a = a, g = [], h = "word", i = "", j = "", l = a.length > d.maxLen ? d.maxLen : a.length, c || (d.curMaxLen = l, d.cache.curVal = d.input.value), 0 == b ? (h = "word", i = '<div class="top-suggest-tip">´ó¼ÒÕýÔÚËÑ£º\r\n</div>', j = '<div class="top-suggest-more clearfix"><a href="http://s.weibo.com/top/summary?Refer=sina_sug" target="_blank" class="top-suggest-hotAll">ÍêÕûÈÈËÑ°ñ&gt;&gt;</a><a href="http://s.weibo.com/?Refer=sina_sug" target="_blank" class="top-suggest-toHomePage">½øÈëËÑË÷Ê×Ò³&gt;&gt;</a></div>') : (h = "suggestion", i = "", j = ""), g.push(i), k = 0; l > k; k++) - g.push('<div class="'), g.push(e), g.push('" index="'), g.push(k), g.push('" action-type="'), g.push(f), g.push('">'), g.push(a[k]), g.push("</div>"); - return g.push(j), g.join("") - }}, r - }), window.search_suggest = new SHM.home.suggest({input: document.SearchEcho.SerchKey,maxLen: 10,onoff: "on",controlFunction: function() { - return "΢²©" === document.SearchEcho.SerchType.value || "ÐÂÎÅ" === document.SearchEcho.SerchType.value ? !0 : !1 - }}) - }}); -// 20140403 MOD lqf {update the default hot} end - - function tSearchUatrack(val) { - try{ - _S_uaTrack('index_new_search', val); - }catch(e){} - } - function formSubmit(form,isWb,key){ - var isFF = /firefox/.test(navigator.userAgent.toLowerCase()); - if(isFF){ - if(!isWb) { - setTimeout(function(){ - form.submit(); - },0); - } else { - setTimeout(function(){ - !!key ? form.setAttribute('action', 'http://s.weibo.com/weibo/@@key@@'.replace('@@key@@',key)) : - form.setAttribute('action', 'http://s.weibo.com/weibo/'); - form.submit(); - },0); - } - } else { - if(!isWb) { - form.submit(); - } else { - !!key ? form.setAttribute('action', 'http://s.weibo.com/weibo/@@key@@'.replace('@@key@@',key)) : - form.setAttribute('action', 'http://s.weibo.com/weibo/'); - form.submit(); - } - } - } - function SearchSubmit(){ - var key = document.SearchEcho.SerchKey.value.replace(/(^[\s\u3000]*)|([\s\u3000]*$)/g, ""); - var ipt = document.SearchEcho.SerchKey; - if(key == "ÇëÊä¹Ø¼ü´Ê" || key == "ÇëÊäÈë¹Ø¼ü×Ö" || key === "") - { - ipt.value = ""; - ipt.className = 'inp-txt inp-txt-click'; - setTimeout(function(){ipt.className='inp-txt'},500); - ipt.focus(); - return false; - } else if(key === window.___homeSugVal___) { - key = key.replace("\u5927\u5BB6\u6B63\u5728\u641C\uFF1A",""); - document.hform_10.Refer.value = 'sina_direct_index'; - } - switch(document.SearchEcho.SerchType.value){ - case "ÐÂÎÅ" : - document.hform_02.q.value = key; - tSearchUatrack('search_click_news'); - formSubmit(document.hform_02); - break; - case "ÊÓƵ" : - document.hform_03.q.value = key; - tSearchUatrack('search_click_video'); - formSubmit(document.hform_03); - break; - case "ͼƬ" : - document.hform_05.q.value = key; - tSearchUatrack('search_click_pic'); - formSubmit(document.hform_05); - break; - case "²©¿Í" : - document.hform_08.q.value = key; - tSearchUatrack('search_click_blog'); - formSubmit(document.hform_08); - break; - case "΢²©" : - var ReferEle = document.hform_10.Refer; - if(search_suggest.cache.curVal!=undefined && key != search_suggest.cache.curVal.replace(/(^[\s\u3000]*)|([\s\u3000]*$)/g, "") && search_suggest.sugWrap.style.display === 'block') { - if(search_suggest.cache.listType==='sug') { - ReferEle.value = 'sina_sug'; - } else { - ReferEle.value = 'sina_hot_sug'; - } - } else if(ReferEle.value != 'sina_direct_index') { - ReferEle.value = 'sina_index'; - } - key = encodeURIComponent(encodeURIComponent(key)); - tSearchUatrack('search_click_weibo'); - formSubmit(document.hform_10,true,key); - break; - case "֪ʶÈË" : - document.hform_09.key.value = key; - tSearchUatrack('search_click_knowledge'); - formSubmit(document.hform_09); - break; - default : //ÍøÒ³ - break; - } - return false; - } - - jsLoader({ - name: 'shm', - callback: function() { - SHM.register('home.custEvent.firstpage.fire', function($) { - $.evt.custEvent.fire($, 'firstPageEnd'); - }); - - //²âÊÔ²ÂÄãϲ»¶µÄµÇ¼ - } - }); - </script> - - <!-- / pageload firstpage --> - - <!-- part-b begin --> - - <div class="part-b clearfix"> - <div class="part-b-l"> - <!-- mod07 --> - -<!-- - <div tab-type="tab-wrap" class="mod-07 mod-02"> - <div class="tit02" style="border-bottom:0px;"> - <h3><a href="http://video.sina.com.cn/sports/" target="_blank">ÊÓƵֱ²¥</a></h3> - <div class="s-btn"> - <span tab-type="tab-nav" class="selected">½ñÈÕ</span> - <span tab-type="tab-nav">Ã÷ÈÕ</span> - </div> - </div> - <div id="SI_Live_Wrap" class="mod07-cont-wrap"> - <p class="loading"></p> - </div> -{sports_ÌåÓý_6_ÊÓƵֱ²¥²¹³ä} - </div> ---> - -<!-- ÐÂÀËÌåÓý̨ begin --> - <!-- mod-xltyt start --> - <style type="text/css"> - .mod-x{width:240px;height:210px;overflow: hidden;font:12px/20px "Microsoft Yahei","΢ÈíÑźÚ","SimSun","ËÎÌå","Arial Narrow",serif;float: left;display: inline;} - .mod-x .mod-hd{width:280px;height:35px;border-bottom: 1px solid #000;background: #292928;} - .mod-x .mod-hd a{width:119px; height:35px;overflow:hidden;line-height: 35px;float: left;display: inline;text-align: center;font-size: 17px;line-height: 35px;border:1px solid #000;border-width: 0 1px;padding:0;} - .mod-x .mod-hd a:link,.mod-x .mod-hd a:visited{color:#a0a0a0;text-decoration: none;} - .mod-x .mod-hd a:hover,.mod-x .mod-hd a:active{color:#a0a0a0;text-decoration: none;} - .mod-x .mod-hd a.left{border-right-color:#000;border-left-color:#292928;} - .mod-x .mod-hd a.right{border-right-color:#292928;border-left-color:#3A3939;} - .mod-x .mod-hd a.selected{color:#fff !important;background: #0056A3;} - .mod-x .mod-hd a.left.selected{border-left-color:#0056A3;} - .mod-x .mod-hd a.right.selected{border-right-color:#0056A3;border-left-color:#0068AE;} - - .mod-xltyt{background: url(http://i3.sinaimg.cn/ty/2011hqj/10151730/images/bg.png?v=44) 0 -64px no-repeat;} - .mod-xltyt .mod-bd{height:174px; overflow: hidden;position: relative;} - - .mod-xltyt .mod-hd a.left.selected{background: url(http://i1.sinaimg.cn/ty/2011hqj/10151730/images/bg.png) 0 0 no-repeat;border-left: 0;} - .mod-xltyt .mod-hd a.right.selected{background: url(http://i1.sinaimg.cn/ty/2011hqj/10151730/images/bg.png) 0 -50px no-repeat;border-right:0;border-left-color: #AC0000;} - - .mod-xltyt .item{display: block; border-top:1px solid #224553;border-bottom: 1px solid #000000;line-height: 25px;height: 25px;overflow: hidden;color:#fff;position: relative;} - .mod-xltyt .item:link,.mod-xltyt .item:visited{color:#fff;text-decoration: none;} - .mod-xltyt .item:hover,.mod-xltyt .item:active{color:#fff;text-decoration: none;cursor: pointer;} - .mod-xltyt .item .txt{position: relative;z-index: 10;_zoom:1;} - .mod-xltyt .item .bg{filter:alpha(opacity=10); opacity: 0.1;background: #fff;line-height: 25px;height: 25px;width: 100%;position: absolute;top:-999px;left: 0;} - .mod-xltyt .hover .bg,.mod-xltyt .item:hover .bg{top:0;} - .mod-xltyt .time{float: left;display: inline;width: 70px;text-align: right;} - .mod-xltyt .item2 .time{width: 40px;} - .mod-xltyt .date{float: left;display: inline;width: 60px;text-align: right;} - .mod-xltyt .team{padding-left: 10px;width: 175px;} - .mod-xltyt .blive{height:55px;border-top-color: #5A2020;line-height: 20px;} - .mod-xltyt .blive .txt{padding: 0 0 0 70px;} - .mod-xltyt .blive .bg,.mod-xltyt .blive:hover .bg{height: 55px;background: #4F1212;filter:alpha(opacity=50); opacity: 0.5;top:0;} - .mod-xltyt .blive .tip{color:#e82323;display: block;padding:8px 0 0 10px;} - .mod-xltyt .hot{height:42px;line-height: 20px;} - .mod-xltyt .hot .txt{padding: 0 0 0 70px;} - .mod-xltyt .hot:hover .bg{height: 42px;} - .mod-xltyt .hot .tip{display: block;padding:2px 0 0 10px;} - .mod-xltyt .item i{display: block;position: absolute;overflow: hidden;} - .mod-xltyt .blive i{width:53px;height:26px;background: url(http://i3.sinaimg.cn/ty/2011hqj/10151730/images/blive.gif);left:14px;top:14px;} - .mod-xltyt .slive i{width:28px;height:12px;background: url(http://i0.sinaimg.cn/ty/2011hqj/10151730/images/slive.gif);left:4px;top:7px;} - .mod-xltyt .hot i{width:25px;height:11px;background: url(http://i3.sinaimg.cn/ty/2011hqj/10151730/images/hot.png);_background: url(http://i2.sinaimg.cn/ty/2011hqj/10151730/images/hot_.png);left:30px;top:17px;} - </style> - <div class="mod-xltyt mod-x" tab-type="tab-wrap"> - <div class="mod-hd"> - <a href="http://sports.sina.com.cn/tv" target="_blank" class="left selected" tab-type="tab-nav"><span>ÐÂÀËÌåÓý̨</span></a> - <a href="http://video.sina.com.cn/sports/?show=live" target="_blank" class="right" tab-type="tab-nav"><span>Ò»Öܽ¹µãÖ±²¥</span></a> - </div> - <div class="mod-bd" tab-type="tab-cont" id="SI_XLTYT_Con0" data-sudaclick="sports_tyt1"> - </div> - <div class="mod-bd" tab-type="tab-cont" id="SI_XLTYT_Con1" style="display:none;" data-sudaclick="sports_tyt2"> - </div> - </div> - <script type="text/javascript" src="http://www.sina.com.cn/js/index/96/live.js"></script> - <!-- mod-xltyt end --> -<!-- ÐÂÀËÌåÓý̨ end --> - - <!-- mod07 --> - <div class="blank-cont" style="height:6px;"></div> - <!-- mod08 --> - <div class="mod-08"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x200 3ÂÖ²¥°´Å¥01¹ã¸æ begin --> -<div id="ad_16827" style="width:240px; height:200px;"> -<ins class="sinaads" data-ad-pdps="PDPS000000016827"></ins><script>(sinaads = window.sinaads || []).push({});</script> -</div> -<!-- 240x200 3ÂÖ²¥°´Å¥01¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod08 --> - </div> - <div class="part-b-m"> - <!-- mod09 --> - <div class="uni-blk" id="SI_Order_A" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://sports.sina.com.cn/" target="_blank">ÌåÓý</a></span> - <span tab-type="tab-nav"><a href="http://sports.sina.com.cn/nba/" target="_blank">NBA</a></span> - <span tab-type="tab-nav"><a href="http://video.sina.com.cn/sports/" target="_blank">ÌåÓýÊÓƵ</a></span> - </div> - -<ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://sports.sina.com.cn/csl/" target="_blank">Öг¬</a></li> -<li><a href="http://sports.sina.com.cn/g/championsleague/" target="_blank">Å·¹Ú</a></li> -<li><a href="http://sports.sina.com.cn/z/bjzjk/" target="_blank">¶¬°Â</a></li> -<li><a href="http://sports.sina.com.cn/tennis/frenchopen15/" target="_blank">·¨Íø</a></li> -</ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_sports_1" blkclick="auto_nav" blktitle="ÌåÓý"> -<!-- publish_helper name='ÌåÓýÇø¿é' p_id='30' t_id='101' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://sports.sina.com.cn/hdphoto/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U6599P30DT20150618101827.jpg" height="70" width="105" /> - - <span>Àú½ìNBA×ܾöÈüMVP</span> - - </a> - -<ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/">ΤµÂ:Õâ´Î×ܾöʧÀû¶ÔLBJ´ò»÷×î´ó</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09547637072.shtml">¿Æ±È×£ºØÓÂÊ¿</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/01237636921.shtml">JR×ÔÆØ»òÌø³öºÏͬ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/03107636932.shtml">ÆØÓÂÊ¿Óû½»Ò׶á¹Ú¹¦³¼ »ð¼ý½ÓÅÌ?</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09177637032.shtml">×ܾöÊÕÊÓ½ö´Î98ÄêÇǵ¤µÚ6¹Ú</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/">ÊÓƵ</a></li> - -</ul> - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://sports.sina.com.cn/csl/">Ëï¿É»ò7000Íòת»áÌ©´ï</a> <a target="_blank" href="http://sports.sina.com.cn/china/j/2015-06-18/doc-ifxefurq6405356.shtml">¿â¿¨¿Ö±»¶¨ÐÔŹ´ò²ÃÅнûÈüÊýÔÂ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/g/2015copaamerica/">ÃÀÖÞ±­-ÄÚÂí¶û±¨¸´ÌßÈËȾºì°ÍÎ÷¸º</a> <a target="_blank" href="http://sports.sina.com.cn/g/2015-06-18/08597637012.shtml">Éñͬ²½!ÕâÑù·À÷Î÷</a></li> - -<li><a href="http://sports.sina.com.cn/g/laliga/2015-06-18/08247636975.shtml" target="_blank">×îÁÁÓîÖæÐÇϵÒÔCÂÞÃüÃû</a> <a target="_blank" href="http://sports.sina.com.cn/g/laliga/2015-06-18/09237637037.shtml">¾ÞÐÇÒªÇóCÂÞÈóö»ÊÂíÈÎÒâÇòȨ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/g/laliga/2015-06-18/08447636987.shtml">ÆØ°²Ë§¶áÅ·¹ÚÕÕÑùÏ¿Î</a> <a target="_blank" href="http://sports.sina.com.cn/g/pl/2015-06-18/10057637095.shtml">ÂüÁª»ÊÂí̸ÅÐÏëÂòÄÂ˧¿àÇóÃû½«</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/z/others/2015snookerwc/">ÊÀ½ç±­¶¡¿¡êÍÂʶӺáɨÉýµÚ1</a> <a target="_blank" href="http://sports.sina.com.cn/cba/2015-06-18/doc-ifxefurt9362584.shtml">Âí²¼Àï·´ÊÖÃþ¶ÇÆêʧ°Ü(ͼ)</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/t/2015-06-18/10407637154.shtml">ÌÀΨÓÐÐËȤÖ÷ÑÝÀîÄÈ×Ô´«µçÓ°</a> <a target="_blank" href="http://sports.sina.com.cn/o/o/2015-06-17/22347636890.shtml">Éñ¾çÔÙÏÖ!×ÔÐгµ½ØÍ£»ð³µ</a></li> - -<li><a href="http://blog.sina.com.cn/lm/sports/" target="_blank">²©¿Í</a>-<a href="http://blog.sina.com.cn/s/blog_5c4bb2910102wde6.html?tj=1" target="_blank">ÍõÃÍ:±ÈÊäÓ®¸üÖØÒªµÄ</a> <a href="http://sports.sina.com.cn/zl/" target="_blank">רÀ¸</a>-<a href="http://sports.sina.com.cn/zl/basketball/2015-06-18/zldoc-ifxefurs2578675.shtml" target="_blank">ÖìÑå˶:×ܾöÈüûÊä¼Ò</a></li> - -<li><a class="videoNewsLeft" target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/101865026655.html">¡¶ÉùÉ«NBA¡·</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/095165026635.html">Õ²»Ê´ßÀáMV</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/g/v/2015-06-18/101665026653.html">8±¬ÈéÃÀŮȫÂã³ö¾µÃÀÖÞ±­</a></li> -<li><a href="http://lottery.sina.com.cn/" target="_blank">ÉñÈ˲ÂÖÐ1.8ÒÚ¾Þ½±¾¹Ò»·ÖδµÃ</a> <a href="http://sports.sina.com.cn/lotto/" target="_blank">´óÀÖ͸¿ª7עǧÍò¼¶Í·½±</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_sports_2" blkclick="auto_nav" blktitle="NBA"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='NBAÇø¿é' p_id='30' t_id='101' d_id='2' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://sports.sina.com.cn/nba/" target="_blank" class="uni-blk-pic"> - - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U7835P30DT20150617100106.jpg" width="105" height="70" /> - <span>ÓÂÊ¿»÷°ÜÆïÊ¿¶á¹Ú</span> - - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/02347636929.shtml">¶á¹ÚÒ¹°Â¿ËÀ¼ÇòÃÔÄð³åÍ»</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/00167636912.shtml">2015ÀÖ͸ÐãѲÀñÖ®ÐݳÇÀ¶Ä§¹í</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-17/13367636594.shtml">ÐÂÀËÖ±»÷ÓÂÊ¿¸üÒÂÊÒÇì×£</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09547637072.shtml">¿Æ±È·¢ÍƺØÓÂÊ¿¶á¹Ú</a></li> - -</ul> - - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://sports.sina.com.cn/nba/">ÆØÓÂÊ¿Óû½»Ò׶á¹Ú¹¦³¼</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/01237636921.shtml">JR×ÔÆØ»ò½«Ìø³öºÏͬ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/nbamitan/" class="linkRed videoNewsLeft">¡¶NBAÃÜ̽¡·</a> <a target="_blank" href="http://video.sina.com.cn/z/sports/k/nba/150601sinanba/" class="linkRed">¡¶ÀË˵NBA¡·ÂÖ²¥</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/095165026635.html">Õ²»Ê´ßÀáMV</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/105865026729.html" class="videoNewsLeft">G6΢µçÓ°</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/102465026663.html">ÓÂÊ¿¿­Ðý»Ø¼Ò</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-17/172765026449.html">·çÁÖ»ðɽսÊõ¼¯½õ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09177637032.shtml">×ܾöÈüÊÕÊÓÈËÊý´´Ð¸ß</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09117637023.shtml">×î¼ÑµÚÁùÈËδÀ´È¥ÏòÎåÑ¡Ò»</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09257637040.shtml">ÐÝÈüÆÚÓÂÊ¿»áÓж¯×÷Âð£¿</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/10377637149.shtml">¸ñÁÖ£ºÔøÓÐÈË˵ÎÒÎÞ·¨Á¢×ã</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09307637051.shtml">ΤµÂ£ºÕâ´ÎʧÀû¶ÔÕ²´ò»÷×î´ó</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/10507637178.shtml">ŵÌìÍõ̹³ÐáÛ·åÒѹý</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/11167637230.shtml">ÅÁ½ð˹:Õ²»ÊÅäµÃÉÏÊÀ½ç×î¼Ñ</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/11137637224.shtml">¼ÖÃ×É­»ØÒä¿Æ±È:ºÜºÃÏà´¦</a></li> - -<li><a target="_blank" href="http://slide.sports.sina.com.cn/k/slide_2_786_83545.html" class="linkRed">¸ßÇå-ÓÂÊ¿ÖÚ½«¿­Ðý</a> <a target="_blank" href="http://slide.sports.sina.com.cn/k/slide_2_786_83544.html" class="linkRed">¿âÀïÒ»¸ç±§×Ž±±­Ë¯×Å</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-17/17217636778.shtml">½ñÈÕÉñͲÛ:Ò»¸çº¦¿âÀï¿ÞÔÎ Õ²»ÊŪ¶ªÇó»é½äÖ¸</a></li> - </ul> - </textarea> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_sports_3" blkclick="auto_nav" blktitle="ÌåÓýÊÓƵ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÌåÓýÊÓƵÇø¿é' p_id='30' t_id='101' d_id='3' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://video.sina.com.cn/z/sports/k/nba/150617gswcle/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U6589P30DT20150617163842.jpg" width="105" height="70" /> - <span>ÓÂÊ¿¶á15NBA×ܹھü</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138271581" class="linkRed videoNewsLeft">MVÖ¾´Õ²»Ê</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/#138285768">ÓÂÊ¿Åõ±­Ë²¼ä</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138270279" class="videoNewsLeft">ÒÁ¸ê´ïÀ­»ñFMVP</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/#138285972">LBJ¿âÀïÏàÓµ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138286970" class="videoNewsLeft">¿âÀïÈüºóÓµ±§×ܾöÈü½±±­</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/matches/" class="videoNewsLeft liveNewsLeft">×ܾöÈüG6»ã×Ü</a> <a target="_blank" href="http://video.sina.com.cn/z/sports/nba/officialbest/2015-06-17/#138271443">NBA¹Ù·½5¼ÑÇò</a></li> -</ul> - - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/n/v/2015-06-16/222865025571.html" class="videoNewsLeft">¹ú×ã6-0²»µ¤È¡¿ªÃźì ÑîÐñ´÷ñ+2´«ÓÚ´ó±¦2Çò</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0613/ITA/" class="videoNewsLeft">Å·Ô¤Èü-²¼·ëÆ˵ãÒâ´óÀû1-1</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0613/NED/">ºÉÀ¼2-0</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/g/v/2015-06-13/033465023405.html">±´¶ûÕ¶±ÈÀûʱ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0615/ENG/" class="videoNewsLeft">Ó¢¸ñÀ¼3-2</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0614/POR/">CÂÞ´÷ñÆÏÌÑÑÀ3-2</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0614/GER/">µÂ¹ú7-0</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0615/ESP/">Î÷°àÑÀ1-0</a></li> - -<li><a href="http://video.sina.com.cn/p/sports/pl/v/2015-06-16/112965025289.html" target="_blank" class="videoNewsLeft">Ó¢¸ñÀ¼¶ÓÊ·10¼ÑÇò</a> <a target="_blank" href=" http://video.sina.com.cn/p/sports/g/v/2015-06-16/095865025177.html">´ÈÉÆÈü¿ËÂåÔóµõÉäϷˣΫ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/pl/v/2015-06-16/143565025367.html" class="videoNewsLeft">ǹÊÖÐÂÇòÒÂÕ𺳷¢²¼</a> <a target="_blank" href=" http://video.sina.com.cn/p/sports/seriea/v/2015-06-16/215065025567.html">MV¡¶ÄǾÍÕâÑù°É¡·ËͱðƤ²¨</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138199129" class="videoNewsLeft">Å·¹Ú|°ÍÈø3-1ÓÈÎÄ</a> <a href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138199143" target="_blank">¶á¹Ú°ä½±Â¼²¥</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/clear/victoryfootball/1514/#138199153">Å·¹ÚÈü¼¾10¼ÑÇò</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138215864" class="videoNewsLeft">MVÖ¾´¹Ú¾ü°ÍÈø</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/clear/victoryfootball/1514/#138231309">Å·¹ÚÈü¼¾È«¾°»Ø¹Ë</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138199609">÷Î÷Å·¹ÚÈ«½øÇò</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/footballtactics/" class="videoNewsLeft">¡¶×ãÇòµÀÖеÀ¡·</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/clear/victoryfootball/">¡¶Ê¤Àû×ãÇò¡·</a> <a target="_blank" href="http://sports.sina.com.cn/video/cba20years/">¡¶CBA¶þÊ®Äê¡·</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/pl/" class="videoNewsLeft">Ó¢³¬ |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/">Î÷¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/seriea/">Òâ¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/bundesliga/">µÂ¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/ligue1/">·¨¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/c/j/csl/">Öг¬ |</a> <a target="_blank" href="http://sports.sina.com.cn/video/c/j/afccl/">ÑǹÚ</a></li> - </ul> - </textarea> - </div> -<!-- 0316 nmod01 --> - <div class="nmod01" data-sudaclick="blk_sports_textad"> -<a target="_blank" href="http://sports.sina.com.cn/hdphoto/">¸ßÇåÃÀͼ</a>&nbsp;<ins class="sinaads" data-ad-pdps="PDPS000000045982"></ins><script>(sinaads = window.sinaads || []).push({});</script>&nbsp;<ins class="sinaads" data-ad-pdps="PDPS000000045983"></ins><script>(sinaads = window.sinaads || []).push({});</script> - - </div> - <!-- 0316 nmod01 --> - </div> - </div> - </div> - <!-- mod09 --> - </div> - <div class="part-b-r"> - <!-- mod10 --> - <div class="mod-10"> - <div class="uni-blk" id="SI_Order_B" tab-type="tab-wrap" struc="2-3"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://auto.sina.com.cn/" target="_blank">Æû³µ</a></span> - <span tab-type="tab-nav"><a href="http://auto.sina.com.cn/guide/" target="_blank">¹º³µ</a></span> - <span tab-type="tab-nav"><a href="http://photo.auto.sina.com.cn/" target="_blank">ͼÉÍ</a></span> - </div> - - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Car"> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_auto_search&value=auto_search">ËѳµÐÍ</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" method="GET" action="http://so.auto.sina.com.cn/search/" onsubmit="return carsearch(this,'car')"> - <select id="SI_Slt_05" name="by"> - <option value="cars" selected="selected">³µÐÍ</option> - <option value="kinds">Æ·ÅÆ</option> - </select> - <input type="hidden" name="c" value="car"> - <input type="hidden" name="range" value="article"> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" onblur="if(this.value==''){this.value='ÇëÊäÈë²éѯ´Ê'}" onfocus="if(this.value=='ÇëÊäÈë²éѯ´Ê'){this.value=''}" value="ÇëÊäÈë²éѯ´Ê" name="q"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_auto_search&value=auto_search_click"/> - </a> - </form> - </div> - </div> - </div> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden" style="display:none;"> - <li><a href="http://finance.sina.com.cn/sf/list/?cate_id=50025972&cat_name=%E6%9C%BA%E5%8A%A8%E8%BD%A6" target="_blank" suda-uatrack="key=index_sfpm&value=autosf">Æû³µÅÄÂô</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - - <!--adÆû³µ°å¿éÎÄ×ÖÁ´ begin--> - <div style="position:relative;" data-sudaclick="blk_auto_adtext"> - <ul class="uni-blk-list02 list-a" style=" position:absolute; top:320px; left:0px; width:360px;"> -<li><ins class="sinaads" data-ad-pdps="PDPS000000045984"></ins><script>(sinaads = window.sinaads || []).push({});</script>&nbsp;<ins class="sinaads" data-ad-pdps="PDPS000000045985"></ins><script>(sinaads = window.sinaads || []).push({});</script></li> - -<li><!--µØÓò¶¨ÏòÎÄ×ÖÁ´ begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000045986"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<ins class="sinaads" data-ad-pdps="PDPS000000045987"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<!--µØÓò¶¨ÏòÎÄ×ÖÁ´ end--></li> - </ul> - </div> - <!--adÆû³µ°å¿éÎÄ×ÖÁ´ end--> - - <div tab-type="tab-cont" blkclick="auto_nav" blktitle="Æû³µ" data-sudaclick="blk_auto_1"> -<!-- publish_helper name='Æû³µÇø¿é' p_id='30' t_id='102' d_id='1' --> - -<div class="uni-blk-bt clearfix"><a href="http://photo.auto.sina.com.cn/tuji/18269" target="_blank" suda-uatrack="key=sina_auto_xjdt&value=sina_auto_xjdt1" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U4982P30DT20150618085458.jpg" width="105" height="70" /> - <span>±¼³Û·¢²¼GLCÌæGLK</span> - </a> - - <ul class="uni-blk-list01 list-a" data-sudaclick="blk_auto_1wz1"><li><a target="_blank" href="http://auto.sina.com.cn/">±¼³Û±¦ÂíÇëÈò½£¡ÊÔ¼ÝȫаµÏTT</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/review/sinasupic/2015-06-18/detail-ifxczyze9690905.shtml">ÊÔ¼Ý6ÍòÔªSUV»ÃËÙS3 ȫϵ±êÅä7×ù </a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/car/2015-06-05/09421444537.shtml">³¤ÂíÐÂCX-5½ñÈÕÉÏÊÐ Ô¤ÊÛ17ÍòÆð</a></li><li><a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxefurt9355520.shtml">¼ªÀûÎÖ¶ûÎÖÔì³µ ½ô´ÕSUVÆ¥µÐ¼«¹â</a></li> -</ul></div><div class="blk-line"></div><div class="uni-blk-bt clearfix" style="padding-top:5px"> - -<a href="http://photo.auto.sina.com.cn/tuji/18167/" target="_blank" suda-uatrack="key=sina_auto_xjdt&value=sina_auto_xjdt2" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U4982P30DT20150618085502.jpg" width="105" height="70" /> - <span>2015¿îCX-5½ñÉÏÊÐ</span> - - </a> - - <ul class="uni-blk-list01 list-a" data-sudaclick="blk_auto_1wz2"><li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxefurt9337492.shtml">°ÂµÏQ3¸Ä¿î ×Ô¶¯¼ÝʻʱËÙ130km/h</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczyze9679612.shtml">½Ý±ªÂ·»¢¿ÉÍÆÒ£¿ØŲ³µºÍ×Ô¶¯µ÷Í·</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczqan1518406.shtml">пÂíX5²åµçʽ»ì¶¯Ô¼47.7ÍòÔª</a></li><li><a class="photoNewsLeft" target="_blank" href="http://photo.auto.sina.com.cn/tuji/18267/">×î½ÚÓ͸߶û·ò</a> <a target="_blank" href="http://photo.auto.sina.com.cn/tuji/18262/">¸£ÌïÊ׿îSUV</a></li></ul></div> - - <ul class="uni-blk-list02 list-a" style="padding-top:0px;margin-top:0px;"> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxefurs2562286.shtml">±±¾©»ò½«Õ÷Óµ¶Â·ÑÈ¡ÏûÏÞÅÆÏÞÐÐ</a> <a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxczyze9695968.shtml">±êÖÂ308 GTI 25ÈÕÊ×·¢</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxefurt9346113.shtml">Á¦·«820ÈçºÎÑ¡¼ö1.8LÊÖ¶¯ºÀ»ª</a> <a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxczyze9701151.shtml">ÐÂÓ¢ÖÂMPVÅäÌØ˹À­´óÆÁ </a></li> - -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczqan1435616.shtml">MINI¼Ó³¤°æµýÕÕÆعâ»ò9ÔÂÊ×·¢</a> <a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczqar0994580.shtml">Âí×Ô´ï6X °¢ÌØ×È¿ç½ç°æ </a></li> - -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczqan1469420.shtml">duang!³¤³ÇÐû²¼½µ¼Û¹þ¸¥H6½µ6ǧ</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-18/07001447332.shtml">±öÀûÍÆȫг¨Åñ½ÎÅÜ</a></li> - - </ul> - </div> - <div tab-type="tab-cont" style="display:none" blkclick="auto_nav" blktitle="¹º³µ" data-sudaclick="blk_auto_2"> - <div class="selectCar clearfix"> - <div class="selectLeft" id="selectCar" data-sudaclick="blk_auto_2xc"> - <div class="carIndex clearfix"> - <span class="carDot able">1</span> - <span class="carGap"></span> - <span class="carDot" id="CSI_Slt_8">2</span> - <span class="carGap"></span> - <span class="carDot" id="CSI_Slt_7">3</span> - <span class="carGap"></span> - <span class="carDot" id="CSI_Slt_6">4</span> - </div> - <form action="http://data.auto.sina.com.cn/xuanche/index.php#ul_list" method="post" target="_blank" id="selectIndex"> - <select id="SI_Slt_9" name="price"> - <option value="0" selected="selected">Ñ¡Ôñ¼Û¸ñ</option> - <option value="0-5">0-5Íò</option> - <option value="5-8">5-8Íò</option> - <option value="8-11">8-11Íò</option> - <option value="11-15">11-15Íò</option> - <option value="15-20">15-20Íò</option> - <option value="20-25">20-25Íò</option> - <option value="25-35">25-35Íò</option> - <option value="35-50">35-50Íò</option> - <option value="50-70">50-70Íò</option> - <option value="70-100">70-100Íò</option> - <option value="100-999999">100ÍòÒÔÉÏ</option> - </select> - <select id="SI_Slt_8" name="type"> - <option value="0" selected="selected">Ñ¡Ôñ³µÐÍ</option> - <option value="1">½Î³µ</option> - <option value="2">Åܳµ</option> - <option value="3">SUV</option> - <option value="4">MPV</option> - <option value="5">Ãæ°ü³µ</option> - <option value="6">Ƥ¿¨</option> - </select> - <select id="SI_Slt_7" name="country"> - <option value="0" selected="selected">Ñ¡Ôñ¹ú±ð</option> - <option value="china">Ö§³Ö¹ú»õ</option> - <option value="germany">ÎÒÖ»ÒªµÂ¹ú³µ</option> - <option value="ou">Å·ÖÞ³µ¶¼ÐÐ</option> - <option value="america">ÎÒϲ»¶ÃÀ¹ú·¶</option> - <option value="nojp">²»ÂòÈÕ±¾³µ</option> - <option value="japan">Ö»ÂòÈÕ±¾³µ</option> - <option value="korea">º«¹ú³µË¼ÃÜ´ï</option> - </select> - <select id="SI_Slt_6" name="feature1"> - <option value="0" selected="selected">Ñ¡ÔñÌØÐÔ</option> - <option value="1">°²È«µÚÒ»</option> - <option value="3">¸Ü¸ÜµÄ¶¯Á¦ºÍ²Ù¿Ø</option> - <option value="2">´ó¿Õ¼äÓдó¶ÇÁ¿</option> - <option value="4">ºÃÑø»îµÄС»ï°é</option> - <option value="5">¿ª×Å×ø×Ŷ¼Êæ·þ</option> - <option value="6">ÅÀɽÉæË®µÄÔ½Ò°¸ßÊÖ</option> - </select> - <div class="selectBtn"><input type="submit" value="¿ªÊ¼Ñ¡³µ" /></div> - </form> - </div> - <div class="selectRight"> - <div class="cbox" data-sudaclick="blk_auto_2jgzc"> - <p>°´¼Û¸ñÕÒ³µ£º</p> - <ul class="clearfix"> - <li><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=0-5&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">5ÍòÒÔÏÂ</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=5-8&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">5-8Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=8-11&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">8-11Íò</a></li> - -<li class="cborder"><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=11-15&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">11-15Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=15-20&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">15-20Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=20-25&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">20-25Íò</a></li> - -<li><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=25-35&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">25-30Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=35-50&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">35-50Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=100-9999999&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">100ÍòÒÔÉÏ</a></li> - </ul> - </div> - <div class="cbox2" data-sudaclick="blk_auto_2_rmcx"> - <p>ÈÈÃųµÐÍ£º</p> -<!-- publish_helper name='ÈÈÃųµÐÍ' p_id='30' t_id='102' d_id='10' --> -<p class="clearfix"><a href="http://data.auto.sina.com.cn/632" target="_blank">ººÀ¼´ï</a><span>|</span><a href="http://data.auto.sina.com.cn/168" target="_blank">±¦Âí5ϵ</a><span>|</span><a href="http://data.auto.sina.com.cn/994" target="_blank">°º¿ÆÍþ</a></p> -<p class="clearfix"><a href="http://data.auto.sina.com.cn/2091/" target="_blank">Èñ½ç</a><span>|</span><a href="http://data.auto.sina.com.cn/410/" target="_blank">ËÙÌÚ</a><span>|</span><a href="http://data.auto.sina.com.cn/2119/" target="_blank">ÎåÊ®Áåmu-X</a></p> -<p class="clearfix"><a href="http://data.auto.sina.com.cn/776/" target="_blank">¹þ¸¥H6</a><span>|</span><a href="http://data.auto.sina.com.cn/535/" target="_blank">½Ý±ªXF</a><span>|</span><a href="http://data.auto.sina.com.cn/88" target="_blank">зɶÈ</a></p> - - </div> - </div> - </div> - <div class="blk-line" style="margin-top:5px;"></div> - <div class="mod-a" tab-type="tab-wrap"> - <div class="hd clearfix"> -<span class="extra" id="SI_IP_Auto_City_Title" style="" data-sudaclick="blk_auto_2city">ÆäËü³ÇÊУº<a href="http://tj.auto.sina.com.cn/" target="_blank">Ìì½ò</a>|<a href="http://sh.auto.sina.com.cn/" target="_blank">ÉϺ£</a>|<a href="http://cq.auto.sina.com.cn/" target="_blank">ÖØÇì</a>|<a href="http://gz.auto.sina.com.cn/" target="_blank">¹ãÖÝ</a>|<a href="http://cc.auto.sina.com.cn/" target="_blank">³¤´º</a></span> -<span class="tab-nav-a clearfix"><a tab-type="tab-nav" href="http://bj.auto.sina.com.cn/" style="" target="_blank" class="selected" id="SI_IP_Auto_Tab_Nav_1">±±¾©±¨¼Û</a><span>|</span><a tab-type="tab-nav" href="http://dealer.auto.sina.com.cn/" target="_blank" class=" " >È«¹ú±¨¼Û</a></span> - </div> - <div class="bd tab-cont-a" style="height:80px; overflow: hidden;"> - -<div id="SI_IP_Auto_Tab_Cont_1" style="zoom: 1; overflow: hidden;" data-sudaclick="blk_auto_gc2city"> - <ul tab-type="tab-cont" class="list-a" style=""> -<li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/17321445940.shtml">±¼³ÛE¼¶7.6ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09231446114.shtml">ÀÊÒÝÃë³µ¼Û9.29Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09291446115.shtml">¿Æ³×È8.2ÕÛÏúÊÛ</a></li> - - <li><a target="_blank" href="http://auto.sina.com.cn/car/2015-06-15/10521446451.shtml">¸£ÌØÒí²«×î¸ßÖ±½µ1.4Íò</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-15/11301446458.shtml">;¹Û8.7ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/10161445593.shtml">¸£¿Ë˹7.9ÕÛ</a></li> - - <li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/18361445945.shtml">Ó¢·ÆÄáµÏQ50 8.7ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09331446116.shtml">V60½µ7.69Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/18431445946.shtml">ÂõÈñ±¦17.19ÍòÆð</a></li> - - </ul> -</div> - - <ul tab-type="tab-cont" class="list-a" data-sudaclick="blk_auto_gc2" style="display:none;"> -<li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/16091446182.shtml ">±ð¿ËÓ¢ÀÊ7.7ÕÛÏúÊÛ</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/16041446181.shtml">ËÙÌÚ×î¸ßÓÅ»Ý2.5ÍòÔª</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/15551446179.shtml">;¹Û9.4ÕÛÆð</a></li><li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/14541446172.shtml">2015¿î°ÂµÏA4L 8ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/17321445940.shtml">±¼³ÛE¼¶7.6ÕÛÆð </a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09291446115.shtml">¿Æ³×ȵøÆÆ8Íò</a></li><li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/18251445943.shtml">Ö¸ÄÏÕß×î¸ß½µ4.1Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09431446117.shtml">Âí×Ô´ïCX-5 9ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/11101445605.shtml">¸£¿Ë˹½µ2.5Íò</a></li><li><a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/18341445681.shtml">°ÂµÏQ5ÓŻݳ¬9Íò</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/19261445684.shtml">ÐùÒÝ×îµÍ²»×ã9Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/16331446185.shtml">°º¿ÆÀ­È«³¡8.9ÕÛÆð</a></li> - - </ul> - - </div> - </div> - - </div> - <div tab-type="tab-cont" style="display:none" blkclick="auto_nav" blktitle="Æû³µÍ¼ÉÍ" data-sudaclick="blk_auto_3"> - <div class="carPics clearfix"> -<!-- publish_helper name='ͼÉÍ' p_id='30' t_id='102' d_id='11' --> -<div class="carPicL"> -<a href="http://photo.auto.sina.com.cn/tuji/18232/" target="_blank" class="uni-blk-pic carh1" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts1"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0616/U4982P30DT20150616150517.jpg" width="160" height="88" /> - <span>µÚËÄ´ú·»¢·¢ÏÖ82ÍòÆð</span> -</a> -<a href="http://photo.auto.sina.com.cn/tuji/18267/" target="_blank" class="uni-blk-pic carh2" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts2"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U4982P30DT20150618103700.jpg" width="160" height="218" /> - <span>Ê·ÉÏ×î½ÚÓ͸߶û·ò</span> - </a></div><div class="carPicR"><span class="carh3" data-sudaclick="blk_auto_31"><a href="http://photo.auto.sina.com.cn/tuji/18231/" target="_blank">°ÂµÏ³¬°ÙÍò¸ßÐÔÄܽÎÅÜ</a></span> - <span class="carh4" data-sudaclick="blk_auto_32"><span><a href="http://photo.auto.sina.com.cn/tuji/18197/" target="_blank">½Ö³µ±äÁ³ÁË£¡Ð¿îÔö¯ÊµÅÄ</a></span> - <span><a href="http://photo.auto.sina.com.cn/tuji/18213/" target="_blank">Ò°ÐÔÊ®×ã µÀÆæƤ¿¨Ô¼27ÍòÆð</a></span></span> - <a href="http://photo.auto.sina.com.cn/tuji/18244" target="_blank" class="uni-blk-pic carh5" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts3"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U4982P30DT20150617113030.jpg" width="190" height="104" /> - <span>ԭζÔ˶¯ ʵÅı¼³ÛC¼¶±ê×¼Öá¾à°æ</span> - </a> - <a href="http://photo.auto.sina.com.cn/tuji/18268/" target="_blank" class="uni-blk-pic carh5" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts4"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U4982P30DT20150618105040.jpg" width="190" height="104" /> - <span>ʵÅÄÎÖ¶ûÎÖ×î¸ß¶ËSUV XC90</span> - </a></div> - </div> - </div> - </div> - </div> - </div> - </div> - <!-- mod10 --> - </div> - </div> - <!-- part-b end --> - <div class="blank-cont" style="height:23px;"></div> - <!-- part-c begin --> - - <span id="SI_IP_Part_1" style="display:none"></span> - - <div class="part-c"> - <!-- mod11 --> - <div class="mod-11"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸01¹ã¸æ begin --> -<div id="ad_25256" class="ad-banner"><ins class="sinaads" data-ad-pdps="PDPS000000025256"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸01¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod11 --> - <!-- mod12 --> - <!-- ÀÖ¾ÓµÚ¶þÆÁͨÀ¸ÏÂÎÄ×ÖÁ´(14Ìõ) begin--> - <div id="LejuText3" class="mod-12 clearfix"></div> - <script> - lejuMedia.then(function (data) { - leju.text2('LejuText3', data, 14); - }); - </script> - <!-- ÀÖ¾ÓµÚ¶þÆÁͨÀ¸ÏÂÎÄ×ÖÁ´(14Ìõ) end --> - <!-- mod12 --> - </div> - <!-- part-c end --> - <div class="blank-cont" style="height:25px;"></div> - <!-- part-d begin --> - - <div class="part-d clearfix"> - <div class="part-d-l"> - <!-- mod13 --> - <div class="mod-13 mod-02"> - <div class="tit02 clearfix"> - <h3><a href="http://music.sina.com.cn/" target="_blank">ÀÖ¿â</a></h3> - </div> - <div class="mod13-cont"> - <ul class="list-b" data-sudaclick="blk_music_1" blkclick="auto_nav" blktitle="ÀÖ¿â"> -<!-- publish_helper name='ÀÖ¿âÇø¿é' p_id='30' t_id='104' d_id='2' --> -<li><a href="http://music.sina.com.cn/yueku/a/244718.html" target="_blank">»ª³¿ÓÎÒ¹ÜÄã¡·</a> <a href="http://music.sina.com.cn/yueku/a/244703.html" target="_blank">Å·ºÀ¡¶So What!¡·</a> </li> -<li><a href="http://music.sina.com.cn/yueku/a/244736.html" target="_blank">ÀîÒ׷塶ÄêÉÙÓÐÄã¡·</a> <a href="http://music.sina.com.cn/yueku/a/244720.html" target="_blank">̷άά¡¶°®µ½µ×¡·</a></li> -<li><a href="http://music.sina.com.cn/yueku/a/244719.html" target="_blank">¡¶»¨Ç§¹Ç¡·²åÇú</a> <a href="http://music.sina.com.cn/yueku/a/244721.html" target="_blank">Ö£¾û¡¶·çÂí¡·Âý°æ</a></li> - -<li><a href="http://weibo.com/sinamusic" target="_blank">ÐÂÀËÀÖ¿â</a>|<a href="http://music.sina.com.cn/" target="_blank">ÒôÀÖÈË</a>|<a href="http://music.weibo.com/snake/snk_apply.php" target="_blank"><b>Èëפ</b></a> <a href="http://music.weibo.com/t/s/2740928150.html" target="_blank">°×¾Ù¸Ù</a> <a href="http://music.weibo.com/t/s/1844477730.html" target="_blank">Å·ºÀ</a></li> - </ul> - </div> - </div> - <!-- mod13 --> - <div class="blank-cont" style="height:20px;"></div> - <!-- mod14 --> - <div class="mod-14"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x200 2ÂÖ²¥°´Å¥02¹ã¸æ begin --> -<div id="ad_46010" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046010"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x200 2ÂÖ²¥°´Å¥02¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod14 --> - </div> - <div class="part-d-m"> - <!-- mod15 --> - <div class="uni-blk" id="SI_Order_C" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://ent.sina.com.cn/" target="_blank">ÓéÀÖ</a></span> - <span tab-type="tab-nav"><a href="http://ent.sina.com.cn/star/" target="_blank">°ËØÔ</a></span> - <span tab-type="tab-nav"><a href="http://video.sina.com.cn/ent/" target="_blank">ÓéÀÖÊÓƵ</a></span> - </div> - -<ul class="mod44-list clearfix SC_Order_Hidden" style="float:right; padding-right:5px;"> -<!-- -<li><a href="http://ent.sina.com.cn/f/z/2015cw/" target="_blank">ÑòÄê´ºÍí</a></li> ---> -</ul> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_2"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_ent_1" blkclick="auto_nav" blktitle="ÓéÀÖ"> -<!-- publish_helper name='ÓéÀÖÇø¿é' p_id='30' t_id='100' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112240.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U8551P30DT20150618085611.jpg" width="105" height="70" /> -<span>46ËêÐíÇç°×ÒÂÉÙÅ®</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxefurt9354264.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ËïÙ³ÂèÂè·ñÈϵ˳¬³ö¹ì£ºÐ¡ÈËÔìÒ¥</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxczyze9703841.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">Óá°×ü±ÙÒ¥×ÔÆØÄÛÄ£ ËïÙ³ËÍ×£¸£</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurs2568670.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">¹ù¾¸Ñ¾ÛÊ×£¡ºÃÓÑΪÃçÇÈΰÇìÉú</a></li> - -<li><a target="_blank" href="http://live.sina.com.cn/zt/l/v/ent/filmdirector/" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ºîТÏÍ£ºËÀºóÿ°ÙÄê¿´´Îµ±ÌìµçÓ°</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxefurt9363347.shtml">ÀîÑÇÅô¼ÛÖµ35ÒÚСÕò2ÒÚ˦Âô</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112277.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">±ß²ß×·µ¿»á½¯Ð¡º­Ê§¿Ø.ͼ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurt9355689.shtml">´óS:ÍôС·Æ³ö¹ìÁ¢¿Ì·ÖÊÖ</a> <a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurs2577907.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">¸ÛÐÇÅóÓѶù×ÓÓë·ÆÓ¶ÉÏ´²È¾hiv</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/v/m/2015-06-17/doc-ifxczqap4217798.shtml " class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">14ʱÑîÑ󰮶¹±§±§Ìرð³¡</a> <a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxefurs2586000.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÍÀºé¸ÕÈý»éÉñÃؽ¿ÆÞÆøÖʳöÖÚ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/j/2015-06-18/doc-ifxefurs2574042.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÈÕÅ®ÐÇÎÞ¾åÀϹ«ÍµÇé:ÄÐÈ˶¼³ö¹ì</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112274.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÕÅ°ØÖ¥ºÏÓ°·ÛË¿ÐãÃÀÍÈ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurt9361417.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÓéÀÖȦ·ÖÊÖÇéÂĄ̂ͬÈÈÓµorİ·</a> <a target="_blank" href="http://slide.ent.sina.com.cn/tv/h/slide_4_704_112226.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">¡¶È¨Á¦ÓÎÏ·¡·ÃâËÀÃûµ¥</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurt9360889.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÂÞÖ¾ÏéÁµÉÏÍøºì·ÛË¿È°·ÖÊÖ</a> <a target="_blank" href="http://ent.sina.com.cn/f/m/siff18/" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">·¶±ù±ù»ñÀÏ°å³Ðŵ½ÇÉ«ÈÎÌô</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/photo/">ͼ</a>:<a target="_blank" href="http://slide.ent.sina.com.cn/film/w/slide_4_704_112238.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÁõÒà·ÆÉîVÇåÐÂ</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/k/slide_4_704_112260.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">º«À²À²¶Ó¿ªÍÈÈÈÎè</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/slide_4_704_112246.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">¶Å½­Îª»ô˼Ñ࿪ÃÅ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138275167-1" class="videoNewsLeft">±»ÍµÅÄÂÞÖ¾Ïé³ÐÈÏÁµÇé</a> <a target="_blank" href="http://ent.sina.com.cn/bn/entreport/#138293078" class="videoNewsLeft">СS±§·¶·¶¶ù×Ó¶ÊÂÒµÏß</a></li> - -<li><a href="http://blog.sina.com.cn/lm/ent/" target="_blank">²©¿Í</a>|<a href="http://blog.sina.com.cn/lm/ent/" target="_blank">Ã÷ÐÇÔÙ»é¸ü·ç¹â</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_14b06494b0102voyh.html?tj=1">±¨¸´Ç°ÈÎ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_141f22bbf0102w8vq.html?tj=1">10´óĸŮ»¨</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_1423123bf0102vzre.html?tj=1">»¼ÄÑÈ´·ÖÊÖ</a></li> - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_ent_2" blkclick="auto_nav" blktitle="°ËØÔ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='°ËØÔÇø¿é' p_id='30' t_id='100' d_id='5' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.ent.sina.com.cn/film/w/slide_4_704_112238.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U8551P30DT20150618111738.jpg" width="105" height="70" /> -<span>µÍÐØ£¡ÁõÒà·ÆÃÀ·­</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurs2577907.shtml">¸ÛÅ®ÐÇÅóÓѶù×ÓÓë·ÆÓ¶ÉÏ´²È¾°¬×Ì</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/v/m/2015-06-17/doc-ifxefurt9342611.shtml">Ç°ÑëÊÓÖ÷²¥Âí±ó£ººó»Ú×ß˽ÏãÑÌ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-17/doc-ifxczyze9684814.shtml">СS±§·¶·¶¶ù×Ó¶ÊÂÒµÏß°×ðªÃÀÍÈ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurt9355689.shtml">´óS£º·¢ÏÖÍôС·Æ³ö¹ìÁ¢¿Ì·ÖÊÖ</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://e.weibo.com/entpaparazzi">΢²©</a>|<a target="_blank" href="http://ent.sina.com.cn/y/ygangtai/2015-06-16/doc-ifxczqap4181484.shtml">ÐÅ14ËêÅ®¶ù¿áËÆ°Ö°Ö(ͼ)</a> <a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-16/doc-ifxczqar0967926.shtml">ÕÅÜ°Óè°µÖ¸×Ô¼ºÕæʵ²»×°</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/korea/">º«Óé</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/y/k/slide_4_704_112161.html">º«¹úÅ®¸èÊÖÈÈÁ¦³ªÌø(ͼ)</a> <a target="_blank" href="http://slide.ent.sina.com.cn/tv/k/slide_4_704_112185.html">ºÓÖÇÔ·´©Ð£·þ±ä»Ø¸ßÖÐÉú</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/">ÈÕÓé</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/y/jp/slide_4_704_112167.html">¼¤ÃÈ£¡ÈÕ±¾16ËêÃÀÉÙÅ®×ߺì</a> <a target="_blank" href="http://ent.sina.com.cn/y/yrihan/2015-06-15/doc-ifxczqan0016921.shtml">Çå´¿Å®Ðǻ᳡¸îÍó×Ô²Ð</a></li> - -<li><a href="http://slide.ent.sina.com.cn/?cate=304" target="_blank">ÐÇÎÅ</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112158.html">ÈøÀ­¹«Ö÷ËÆ»³Ôи¹²¿Í¹Æð</a> <a target="_blank" href="http://slide.ent.sina.com.cn/y/k/slide_4_704_112157.html">EXO±ß²®ÏÍΪ°ôÇòÈü¿ªÇò</a></li> - -<li><a target="_blank" href="http://slide.ent.sina.com.cn/?cate=303">»¨±ß</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/y/h/slide_4_704_112194.html">ÂóÀò²»¹ÎҸë´©Àñ·þ³¬°­ÑÛ</a> <a target="_blank" href="http://ent.sina.com.cn/y/ygangtai/2015-06-17/doc-ifxczyze9646779.shtml">¹ùѩܽ³Æ°Ǫ̂°Ù´óÃÀÅ®</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/">ÃÀͼ</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112191.html">°î³½ÐãÄæÌìÃÀÍÈ</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112177.html">Ó¢³¬Å®Éñ½¿µÎµÎ</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112166.html">°²Äݹ«Ö÷´©¾Éȹ</a></li> - -<li><a target="_blank" href="http://blog.sina.com.cn/lm/ent/">ͲÛ</a>|<a href="http://blog.sina.com.cn/s/blog_7964e4ec0102vqpn.html?tj=1" target="_blank">Å̵㴩ɽկÀñ·þÔâ´òÁ³µÄÅ®ÐÇ</a><a target="_blank" href="http://blog.sina.com.cn/s/blog_4baa667b0102vo3t.html?tj=1"> ³Â³åÁ½¸öÅ®¶ù½ÔòÃÀ</a></li> -<li><a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-18/101365026649.html" class="videoNewsLeft">¹ù¾¸ÑÈýÊ®ÄêÔÙ¾ÛÊ×</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-18/102865026673.html" class="videoNewsLeft liveNewsLeft">´óS³Æ·¢ÏÖ³ö¹ìÁ¢¿Ì·ÅÊÖ</a></li> - -<li><a href="http://video.sina.com.cn/p/ent/2015-06-18/104165026707.html" target="_blank" class="videoNewsLeft">СS±§·¶·¶¶ù×Ó¶ÊÂÒµÏß</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/v/m/2015-06-18/093665026625.html" class="videoNewsLeft">¿¹ÈÕÉñ¾ç·´ÎïÀíÖƵÐ</a></li> - </ul> - </textarea> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_movie_1" blkclick="auto_nav" blktitle="´óƬ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='´óƬÇø¿é' p_id='30' t_id='99' d_id='4' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://video.sina.com.cn/ent/#1-28-138292542-1" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U7647P30DT20150618105718.jpg" width="105" height="70" /> - - <span>µË³¬±»Æسö¹ì</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://video.sina.com.cn/ent/#1-28-138277171-1" target="_blank" class="videoNewsLeft">¿¹ÈÕÉñ¾çÏÖ×ÔÐгµ·´ÎïÀíÖƵÐ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292564-1" class="videoNewsLeft">»ô˼Ñà¶ù×Ó×ê»õ¼Üµ÷Ƥ³¬ÃÈ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138275167-1" class="videoNewsLeft">±»ÍµÅĺóÂÞÖ¾Ïé´óµ¨³ÐÈÏÁµÇé</a></li><li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292308-1" class="videoNewsLeft">ÀîÒ×·åÇ£ÊÖÅ®º¢Óо­Ñé¿¿ºÎêÁ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://ent.sina.com.cn/bn/entreport/ttbl/" class="videoNewsLeft">¿ì±¨Í·Ìõ</a>| <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/110265025261.html">·¶±ù±ùËͳµ»öСº¢¾ÍÒ½</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/112765025279.html">±£½£·æ±¨Ï²µ±µù</a></li><li><a href="http://ent.sina.com.cn/bn/entreport/bghb/" target="_blank" class="videoNewsLeft">¿ì±¨°ËØÔ</a>| <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-15/163765024877.html">Íô·å¶àÊ׸èײÃûÖ£¾û</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/111265025269.html">Íõʯ³ÆÌïÆÓ¬Bϱ¸¾</a></li> - -<li><a href="http://ent.sina.com.cn/bn/entreport/yqwx/" target="_blank" class="videoNewsLeft">¿ì±¨ÓéÇé</a>| <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/114065025291.html">л骶ù×Ó·¢¸ßÉÕ</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-15/155265024853.html">Íõ±¦Ç¿ÇìÉú½¿ÆÞÏ×ÎÇ</a></li> - -<li><a href="http://video.sina.com.cn/ent/" target="_blank" class="videoNewsLeft">¶À¼Ò¶Ô»°</a>|<a href="http://video.sina.com.cn/p/ent/v/j/2015-05-18/165964960247.html" target="_blank">×Á÷³Ø²ýÐñ</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/v/m/2015-06-10/092665021023.html">ÐÂÇàÄêÑîÑó</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/v/m/2015-06-11/094165021937.html">µçÊÓÈËÎâÀÚ</a></li> - -<li><a href="http://video.sina.com.cn/vlist/ent/idolbb/" target="_blank" class="videoNewsLeft">×ÔÖƽÚÄ¿</a>|<a href="http://ent.sina.com.cn/f/v/idolbb/" target="_blank">ÕÅÒÕÐËÏÖ³¡ÊªÉí</a> <a target="_blank" href="http://video.sina.com.cn/vlist/ent/cannes2015/#138106669">ºîТÏÍ»ñê©ÄÉ×î¼Ñµ¼ÑÝ</a></li> - -<li><a href="http://video.sina.com.cn/movie/category/teleplay/area/1.html" target="_blank" class="videoNewsLeft">¹ú²ú</a>|<a href="http://video.sina.com.cn/m/201505220332631_64988569.html" target="_blank">´ý¼ÞÀÏ°Ö</a> <a target="_blank" href="http://video.sina.com.cn/m/201505251126675_64992315.html">¶þÉô</a> <a target="_blank" href="http://video.sina.com.cn/m/201505190927653_64974419.html"> »éÒöʱ²î</a> <a target="_blank" href="http://video.sina.com.cn/m/201505050246701_64915825.html"> ÁÄիбà</a> <a target="_blank" href="http://video.sina.com.cn/m/201506050241698_65021591.html">¾ç³¡</a></li> - -<li><a href="http://video.sina.com.cn/movie/movie/" target="_blank" class="videoNewsLeft">µçÓ°</a>|<a href="http://video.sina.com.cn/m/yznaw_64759031.html" target="_blank">ÓÐÖÖÄã°®ÎÒ</a> <a href="http://video.sina.com.cn/m/bssn_63372523.html" target="_blank">°ëÊìÉÙÅ®</a> <a target="_blank" href="http://video.sina.com.cn/m/xjxs_61983055.html">Ð×¼äѩɽ</a> <a target="_blank" href="http://video.sina.com.cn/m/ysh_61625873.html">Ò¹ÉϺ£</a></li> - -<li><a href="http://video.sina.com.cn/movie/category/original/" target="_blank" class="videoNewsLeft">Ô­´´</a>|<a target="_blank" href="http://video.sina.com.cn/m/jf1_64489349.html">½Ó·¢</a> <a href="http://video.sina.com.cn/m/xkrj_64030295.html" target="_blank">ÐÇ¿ÕÈÕ¼Ç</a> <a href="http://video.sina.com.cn/m/qcxjbhw_64408185.html" target="_blank">Çà´ºÏà¼ú²»ºÞÍí</a><a target="_blank" href="http://video.sina.com.cn/m/aqh_64077739.html"> °®ÇÙº£</a></li> - -<li><a href="http://video.sina.com.cn/movie/category/cartoon/area/1.html" target="_blank" class="videoNewsLeft">¶¯»­</a>|<a href="http://video.sina.com.cn/m/xdcr_64045215.html" target="_blank">Ï̵°³¬ÈË</a> <a href="http://video.sina.com.cn/m/xdjh_63840289.html" target="_blank">Цµô½­ºþ</a> <a href="http://video.sina.com.cn/m/asatm_63821101.html" target="_blank">°¬Ë¹¡¤°ÂÌØÂü</a> <a target="_blank" href="http://video.sina.com.cn/m/dongbeiyijiaren_63825081.html">¶«±±Ò»¼ÒÈË</a></li> - - </ul> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod15 --> - </div> - <div class="part-d-r"> - <!-- mod16 --> - <div class="uni-blk" id="SI_Order_D" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://finance.sina.com.cn/" target="_blank">²Æ¾­</a></span> - <span tab-type="tab-nav"><a href="http://finance.sina.com.cn/stock/" target="_blank">¹ÉƱ</a></span> - <span tab-type="tab-nav"><a href="http://finance.sina.com.cn/money/" target="_blank">Àí²Æ</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden" style="float:left; padding-left:73px;"> - <li><a href="http://finance.sina.com.cn/sf/" target="_blank" suda-uatrack="key=index_sfpm&value=financesf">·¨Ôº</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Fin"> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_finance_search&value=finance_search">ËѹÉƱ</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" class="clearfix" method="GET" action="http://biz.finance.sina.com.cn/suggest/lookup_n.php"> - <select id="SI_Slt_02" name="country" onchange="changeViewInputs(this);"> - <option selected="selected" value="stock">¹ÉƱ</option> - <option value="fund">»ù½ð</option> - <option value="hkstock">¸Û¹É</option> - <option value="usstock">ÃÀ¹É</option> - </select> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" value="´úÂë/Ãû³Æ/Æ´Òô" name="q" id="textSuggest"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_finance_search&value=finance_search_click" /> - </a> - </form> - </div> - </div> - </div> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" id="blk_finance_1" data-sudaclick="blk_finance_1" blkclick="auto_nav" blktitle="²Æ¾­"> -<!-- publish_helper name='²Æ¾­Çø¿é' p_id='30' t_id='98' d_id='2' --> - - <div class="uni-blk-bt clearfix"> -<!-- ÐÐÇéͼ´úÂëbegin --> -<a href="http://finance.sina.com.cn/realstock/company/sh000001/nc.shtml" target="_blank" class="uni-blk-pic" style="border:#fff 1px solid;"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://image.sinajs.cn/newchart/small/t/sh000001.gif" width="103" height="68" /><span id="SI_Text_sh600001">ÉÏÖ¤</span></a> -<!-- ÐÐÇéͼ´úÂëend --> - -<ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/cyxw/20150617/230122458690.shtml " class="linkRed">´«¼à¹Ü²ãÄâ·Å¿ªÍâ×ʹºÂòÖйúÂ¥ÊÐ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/china/20150618/003722458786.shtml ">¶àµØÉç±£½É·Ñ»ùÊýËæƽ¾ù¹¤×ÊÉϵ÷</a></li> -<li><a target="_blank" href="http://finance.sina.com.cn/china/20150617/225922458678.shtml">ÍÁµØÒÀÀµÖ¢£¿µØ·½³Æ²»ÂôµØû¹¤×Ê</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/cyxw/20150618/015522459837.shtml ">±¦ÂíÔÚ»ªÏúÁ¿10ÄêÄÚÊ×½µ</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/gsnews/20150618/023922461275.shtml">ÖÐʯÓÍÅ®ÏúÊÛ¾í¿î5ÒÚÅÜ·׷×Ù£ºÓµ°ÙÍòºÀ³µÈýÌ×·¿</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/consume/puguangtai/20150618/012122459450.shtml ">½¡¿µÔª¡¢Ë¼²ºÆÕͨʳƷÖ÷´ò¼õ·Ê¹¦Ð§ »òÉæÎ¥¹æÐû´« </a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/cyxw/20150617/225722458655.shtml ">Â̳ÇÄâÔڻʹ¬ÒÅÖ·ÉϽ¨ºÀÕ¬ ÔøÒòר¼ÒÇ¿ÁÒ¿¹ÒéÍ£¹¤ËÄÄê</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/cyxw/20150618/005922458806.shtml">·¢¸Äί¼ÓÂëµçÍø³É±¾¼à¹Ü ¹ýÈ¥12ÄêµÍÂò¸ßÂô³Ô²î¼Û</a></li> - -<li><a href="http://finance.sina.com.cn/stock/" target="_blank">¹ÉƱ</a>|<a target="_blank" href="http://finance.sina.com.cn/stock/jsy/20150618/113322465808.shtml"> »¦Ö¸ÅÌÕû΢µø0.18% ½ðÈڹɵÍÃÔ</a> <a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150617/225622458649.shtml">²úÒµ×ʱ¾´óÌÓÍö</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/stock/stocklearnclass/20150618/065222463281.shtml">·è¿ñµÄÅä×ÊÆ­¾Ö£ºÕË»§¸ÄÃÜÌ×È¡±£Ö¤½ð</a> <a target="_blank" href="http://finance.sina.com.cn/stock/stocklearnclass/20150618/010922459340.shtml">¸Ü¸Ë×î¸ß´ï9±¶</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/stock/stocklearnclass/20150618/092422464435.shtml">³¤É³ºîÏÈÉúΪţÊÐÌøÂ¥µÚÒ»ÈË£¿¼ÒÊô¾¯·½·ñÈÏÒò³´¹ÉʧÀû</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/sjyhpc2015_zx/" class="linkRed">ÆÀ²â:ÖÐÐÅÊÖ»úÒøÐвúÆ·ØÑ·¦Ìøת»ºÂý</a> <a target="_blank" href="http://finance.sina.com.cn/money/bank/pingxuan2015.html" class="linkRed">ƱѡÖйúºÃÐг¤£¡</a></li> - -<li><a target="_blank" href="http://blog.sina.com.cn/lm/stock/">²©¿Í</a>| <a target="_blank" href="http://blog.sina.com.cn/lm/stock/">¼Îΰ£º´óÅÌÔÚÓÌÔ¥Öб¬·¢ ÄÄÀà¹ÉÔÚÍ»ÆÆÇ°Ò¹</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" id="blk_finance_2" data-sudaclick="blk_finance_2" blkclick="auto_nav" blktitle="¹ÉƱ"> -<!-- publish_helper name='¹ÉƱÇø¿é' p_id='30' t_id='98' d_id='4' --> - - <div class="uni-blk-bt clearfix"> -<div class="finance-pt"><table cellspacing="0" cellpadding="0" class="finance-form"><thead><tr><th colspan="2">±Ø¶ÁÊý¾Ý</th></tr></thead> - <tbody><tr><td><a href="http://finance.sina.com.cn/data/#visual-gnzz" target="_blank">Êг¡Èȵã</a></td> - <td><a href="http://finance.sina.com.cn/data/#visual-wbyq" target="_blank">΢²©ÓßÇé</a></td></tr> - <tr><td><a href="http://finance.sina.com.cn/data/#visual-agrt" target="_blank">A¹ÉÈÈͼ</a></td> - <td><a href="http://finance.sina.com.cn/data/#visual-mgrt" target="_blank">ÃÀ¹ÉÈÈͼ</a></td></tr> - <tr><td><a href="http://finance.sina.com.cn/data/#visual-hqgszz" target="_blank">»·Çò¹ÉÖ¸</a></td> - <td><a href="http://finance.sina.com.cn/data/#visual-agssdd" target="_blank">ʵʱ´óµ¥</a></td></tr></tbody></table></div><ul class="uni-blk-list01 list-a"><li>[<a href="http://blog.sina.com.cn/lm/stock/" target="_blank">²©¿Í</a>]<a href="http://blog.sina.com.cn/lm/stock/" target="_blank">¹ÉÊÐÕÇÂ¥ÊÐÒ»¶¨»áÕÇÂð</a></li> <li>[<a href="http://blog.sina.com.cn/lm/stock/" target="_blank">¶À¼Ò</a>]<a target="_blank" href="http://blog.sina.com.cn/s/blog_494225410102vhkq.html?tj=fina">Äϱ±³µºÏ²¢Î´´¥¼°¹úÆó¸Ä¸ï</a></li> - -<li>[<a href="http://finance.sina.com.cn/stock/hkstock/" target="_blank">¸Û¹É</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/hkstock/hkstocknews/20150618/071922463351.shtml">ÏÕ×ʳ­µ×²ÆÏո۹ɳÉÖ÷Á¦</a></li> - -<li>[<a href="http://finance.sina.com.cn/stock/usstock/" target="_blank">ÃÀ¹É</a>]<a href="http://finance.sina.com.cn/stock/usstock/c/20150618/021122460062.shtml" target="_blank">ÃÀÁª´¢°µÊ¾ÄêÄÚ¼ÓÏ¢</a></li></ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li>[<a href="http://finance.sina.com.cn/stock/roll/gushilive.html" target="_blank">´óÅÌ</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/130522466232.shtml ">¸ÖÌú¹É±©ÕÇ2¹ÉÕÇÍ£</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/114922465926.shtml ">º½¿Õ°å¿é4¹ÉÕÇÍ£</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/131622466314.shtml ">µØ²ú¹É´óÕÇ</a></li> -<li> [<a href="http://finance.sina.com.cn/focus/jyts/" target="_blank">°å¿é</a>]<a href="http://finance.sina.com.cn/stock/gujiayidong/20150618/131222466286.shtml " target="_blank">¾©½ò¼½¸ÅÄîì­Éý</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/111422465685.shtml">»¥ÁªÍø½ðÈÚ¸ÅÄîÆÕµø</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/110622465606.shtml">ºËµç¹ÉÆÕµø</a></li> -<li> [<a href="http://roll.finance.sina.com.cn/finance/zq1/zldx/index.shtml" target="_blank">¸ö¹É</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/101922464969.shtml ">̩ɽʯÓÍÕÇÍ£</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/132422466353.shtml ">»Æ½ð°å¸ÅÄîì­Éý ¶«·½½ðîÚÕÇÍ£</a></li> -<li> [<a href="http://vip.stock.finance.sina.com.cn/q/go.php/vIR_CustomSearch/index.phtml" target="_blank">Ñо¿</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/084822464040.shtml">Ü÷Óñ¸ù:¸Ü¸ËûÄÇô¿ÉÅÂ</a> <a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/021922460170.shtml">ÐËÒµ:Å£ÊеÚÒ»½×¶ÎβÉù</a></li> -<li>[<a href="http://finance.sina.com.cn/blog/7.html" target="_blank">ÍƼö</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/022422460734.shtml ">¹Ø×¢ÒøÐÐB֤ȯBµÄÀíÓÉ</a> <a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/012722459581.shtml">Öг¤ÆÚ·ç¿Ú:ÖйúÖÆÔì2025</a></li> -<li>[<a href="http://finance.sina.com.cn/blog/8.html" target="_blank">²©¿Í</a>]<a target="_blank" href="http://blog.sina.com.cn/s/blog_eb1cfc160102vyha.html?tj=fina">ÖйúÖгµ°ó¼Ü´óÅÌ</a> <a href="http://blog.sina.com.cn/s/blog_69b012610102vq2l.html?tj=fina" target="_blank">ÈýÏß²¼¾Ö·´µ¯</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_634ca6e10102w45a.html?tj=fina">Ƶ·±¾ÞÕð²ØÒõı</a></li> -<li>[<a href="http://licaishi.sina.com.cn/web/plan?fr=stock_top" target="_blank" class="linkRed">Àí²Æʦ</a>]<a target="_blank" class="linkRed" href="http://licaishi.sina.com.cn/web/askList?is_p=1&fr=stock_top">ÎÊ:</a><a target="_blank" class="linkRed" href="http://licaishi.sina.com.cn/web/topic?tid=291&fr=stock_top">³å5000ÄÜ·ñ³É¹¦</a> <a target="_blank" class="linkRed" href="http://licaishi.sina.com.cn/web/planList?s=2&fr=stock_top">Å£¼Æ»®</a> <a target="_blank" class="linkRed" href="http://finance.sina.com.cn/roll/20150617/134122455407.shtml">³ÏƸÄÚÈÝÔËӪרԱ</a></li> -<li> [<a href="http://guba.sina.com.cn/" target=_blank>¹É°É</a>]<a target="_blank" href="http://guba.sina.com.cn/">Åﻧ¸ÄÔì¹ÉÓ­¹ú¼Ò¼¶ÀûºÃ</a> <a target="_blank"href="http://guba.sina.com.cn/?s=thread&tid=48386&bid=2285&dpc=1"target="_blank" >µØ·½¹úÆó¸Ä¸ï³Éзç¿Ú</a> -</li> -<li>[<a target="_blank" href="http://blog.sina.com.cn/lm/stock">Ãû¼Ò</a>]<a target="_blank" href="http://blog.sina.com.cn/lm/stock/">¼Îΰ£º´óÅÌÔÚÓÌÔ¥Öб¬·¢ ÄÄÀà¹ÉÔÚÍ»ÆÆÇ°Ò¹</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" id="blk_finance_3" data-sudaclick="blk_finance_3" blkclick="auto_nav" blktitle="Àí²Æ"> -<!-- publish_helper name='Àí²ÆÇø¿é' p_id='30' t_id='98' d_id='3' --> - - <div class="uni-blk-bt clearfix"> - - <div class="finance-pt"> - <!-- finance table begin 0426 --> - <table cellspacing="0" cellpadding="0" class="finance-form"> - <thead> - <tr> - <th style="width:43px;">Æ·ÖÖ</th> - <th style="width:60px;">¼Û¸ñ</th> - </tr> - </thead> - <tbody> - <tr> - <td><a href="http://finance.sina.com.cn/money/future/GC/quote.shtml" target="_blank">»Æ½ð</a></td> - <td id="comex"><span class="num down"></span></td> - </tr> - <tr> - <td><a href="http://finance.sina.com.cn/money/future/CL/quote.shtml" target="_blank">Ô­ÓÍ</a></td> - <td id="nymex"><span class="num up"></span></td> - </tr> - <tr> - <td><a href="http://finance.sina.com.cn/money/forex/hq/USDCNY.shtml" target="_blank">ÃÀÔª</a></td> - <td id="usdcny"><span class="num down"></span></td> - </tr> - </tbody> - </table> - <script type="text/javascript"> - jsLoader({ - name : 'financeData', - url : 'http://hq.sinajs.cn/list=hf_GC,hf_CL,USDCNY', - callback : function() { - //»Æ½ð - var comexarr = hq_str_hf_GC.split(','); - //Ô­ÓÍ - var nymexarr = hq_str_hf_CL.split(','); - //ÃÀÔªÈËÃñ±Ò - var usdcnyarr = hq_str_USDCNY.split(','); - var byId = 'getElementById', - byTN = 'getElementsByTagName', - D = document, - T = 'SPAN', - comex = (D[byId]('comex'))[byTN](T)[0], - nymex = (D[byId]('nymex'))[byTN](T)[0], - usdcny = (D[byId]('usdcny'))[byTN](T)[0]; - - var setVal = function(obj,val,flag) { - if(parseFloat(flag) < 0) { - obj.className = 'num down'; - } else if(parseFloat(flag) > 0) { - obj.className = 'num up'; - } else { - obj.className = 'num'; - } - obj.innerHTML = val; - } - - setVal(comex,comexarr[0],comexarr[1]); - setVal(nymex,nymexarr[0],nymexarr[1]); - setVal(usdcny,usdcnyarr[1],parseFloat(usdcnyarr[1]) - parseFloat(usdcnyarr[3])); - } - }); - </script> - <!-- finance table end 0426 --> - </div> - -<ul class="uni-blk-list01 list-a"> -<li>[<a href="http://finance.sina.com.cn/fund/" target="_blank">»ù½ð</a>] <a target="_blank" href="http://finance.sina.com.cn/money/smjj/20150618/005922458908.shtml">5ÔÂ˽ļ¹Ú¾üÊÕÒ泬400%</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/fund/20150618/083122463866.shtml">ÂòÕâ2Ö»·Ö¼¶BË­´øÄã·ÉµÃÓÖÔ¶ÓÖÎÈ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/fund/20150618/012622459579.shtml">7ÔÂÆðͶ×ÊÕß½«¿ÉÔÚ¼ÒÂòÏã¸Û¹«Ä¼</a></li> - -<li><a href="http://finance.sina.com.cn/money/fund/20150618/082622463824.shtml" target="_blank">½ñÄêлù½ðÊ×·¢¹æÄ£ÆÆÍòÒÚÔª</a></li> -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://finance.sina.com.cn/money/">Àí²Æ|</a> -<a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/053922462422.shtml">½ü900ÒÚÔª¾Þ×ʳ­µ×A¹É ÈôÒÑϳµ¾ÍµÈÏÂÌË</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/bank_hydt/20150618/081622463753.shtml" class="linkRed">18ÈÕÔÚÊÛ¸ßÊÕÒæÒøÐÐÀí²Æ²úÆ·</a> <a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/082422463817.shtml" class="linkRed">ÖØÒªÀí²ÆÐÅÏ¢»ã×Ü</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/074622463547.shtml">¹ÉÊÐÎüÒýͶ×ÊÈËÑÛÇò ±¦±¦ÀàÊÕÒæµøÈë2ʱ´ú </a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/083022463885.shtml">׬ǮЧӦ͹ÏÔ Æ«¹É»ù½ðÄêÄڷֺ쳬¹ý420ÒÚÔª</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/bank_hydt/20150618/005922458900.shtml">´ó¶î´æµ¥×ªÈûúÖÆÔÝ佨Á¢ ½ö²¿·ÖÒøÐпɰìÀíÖÊѺ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/bank_hydt/20150618/053922462573.shtml">ÉîÛÚ¶à¼ÒÒøÐÐÉϵ÷Ê×Ì×·¿´ûÀûÂÊ ³ÊÏÖÊÕ½ô̬ÊÆ</a></li> - -<li>[<a target="_blank" href="http://finance.sina.com.cn/forex/">Íâ»ã</a>] <a target="_blank" href="http://finance.sina.com.cn/money/forex/20150618/070022463306.shtml">ÃÀÁª´¢Ö÷ϯµ­»¯Ê״μÓÏ¢</a> <a target="_blank" href="http://finance.sina.com.cn/money/forex/20150618/070722463320.shtml">È«Çò½ðÈÚ×ʲúÔõô×ß</a></li> - -<li>[<a target="_blank" href="http://finance.sina.com.cn/nmetal/">»Æ½ð</a>] <a target="_blank" href="http://finance.sina.com.cn/money/nmetal/20150618/061322462693.shtml">¸ëÅÉÃÀÁª´¢Íƶ¯½ð¼ÛÖØ»Ø1180 ²¬½ðÔÙ´¥6ÄêеÍ</a></li> - -<li><a href="http://sports.sina.com.cn/l/2015-06-18/doc-ifxefurs2575240.shtml" target="_blank">90ºó´ò¹¤×Ð3ÔªÖÐ2400Íò:Ëæ»úÑ¡ºÅÔÙÐÞ¸Ä</a> <a href="http://slide.sports.sina.com.cn/l/slide_2_22616_83540.html" target="_blank">¸ßÇå×éͼ</a></li> - </ul> - </div> - </div> - </div> - </div> - -<!-- ²Æ¾­°å¿é¶¨Ïò begin --> -<script language="javascript" type="text/javascript"> -(function() { - function addEvent(obj, eventType, func) { - if(obj.attachEvent) { - obj.attachEvent("on" + eventType, func); - } else { - obj.addEventListener(eventType, func, false); - } - }; - - function attachURL2Window(id,url) { - var links; - try { - links = document.getElementById(id).getElementsByTagName("a"); - }catch(e) { - links = []; - } - for (var i = 0, len = links.length; i < len; i++) { - addEvent(links[i], "mousedown", function(e) { - var writeCookie = function(O, o, l, I, p) { - var i = "", - c = "", - path = ""; - if (l != null) { - if(l == "NaN"){ - i = ";"; - }else{ - i = new Date((new Date).getTime() + l * 3600000); - i = "; expires=" + i.toGMTString(); - } - }; - if (I != null) { - c = ";domain=" + I - }; - if(p != null){ - path = ";path=" + p; - }; - document.cookie = O + "=" + escape(o) + i + c + path; - }; - writeCookie("directAd_finance","true",1,".sina.com.cn","/"); - //µã»÷¼à²â - var _clickStat = new Image(); - _clickStat.src = url + "&_=" + new Date().getTime() + "&url="; - }); - } - }; - - attachURL2Window("blk_finance_1","http://sina.allyes.com/main/adfclick?db=sina&bid=202406,581303,586578&cid=0,0,0&sid=589122&advid=358&camid=36885&show=ignore"); - attachURL2Window("blk_finance_2","http://sina.allyes.com/main/adfclick?db=sina&bid=202406,581309,586584&cid=0,0,0&sid=589128&advid=358&camid=36885&show=ignore"); - attachURL2Window("blk_finance_3","http://sina.allyes.com/main/adfclick?db=sina&bid=202406,581310,586585&cid=0,0,0&sid=589129&advid=358&camid=36885&show=ignore"); - -})() -</script> -<!-- ²Æ¾­°å¿é¶¨Ïò end --> - -<script type="text/javascript" src="http://d3.sina.com.cn/d1images/sinaads_entry/sinaads_entry_index.js"></script> - - <!-- mod16 --> - </div> - </div> - <!-- part-d end --> - <div class="blank-cont" style="height:18px"></div> - - <!-- part-e begin --> - <div class="part-e uni-blk" tab-type="tab-wrap" tab-data="touch=0"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"><p> - <span tab-type="tab-nav" class="no-bl selected"><a href="http://photo.sina.com.cn/" target="_blank">ÎÒ°®¿´Í¼</a></span> - <span tab-type="tab-nav" id="SI_Scroll_Guess_Trigger" style="">²ÂÄãϲ»¶</span> - <span tab-type="tab-nav" id="SI_Scroll_WB_Trigger" style="display:none;"><a href="http://weibo.com/" target="_blank">΢²©ÈÈͼ</a></span> - </p></div> - <span class="t-guide" id="SI_IP_MT_9"></span> - </div> - <div class="blank-cont" style="height:20px"></div> - <div class="part-econt"> - <div tab-type="tab-cont" data-sudaclick="blk_kantu_all" blkclick="auto_nav" blktitle="ÎÒ°®¿´Í¼"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap"> - - <div class="scroll-item" data-sudaclick="blk_kantu_news"> -<!-- publish_helper name='ÐÂÎÅ£¨ÈÕ³££©' p_id='30' t_id='97' d_id='3' --> -<a href="http://slide.news.sina.com.cn/w/slide_1_2841_85583.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U10611P30DT20150618085209.jpg" width="198" height="132" /> - <span class="scroll-txt">¿ÏÄáÑÇÏÖÄÐÓÃÕê²Ù´ø ÉÏËø·ÀɧÈÅ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_sports"> -<!-- publish_helper name='ÌåÓýͼ£¨ÈÕ³££©' p_id='30' t_id='101' d_id='4' --> -<a href="http://slide.sports.sina.com.cn/k/slide_2_57057_83550.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U6604P30DT20150618094928.jpg" width="198" height="132" /> - <span class="scroll-txt">µã½«£ºÀú½ìNBA×ܾöÈüFMVP</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_ent"> -<!-- publish_helper name='ÓéÀÖͼ£¨°ËØÔ£©' p_id='30' t_id='100' d_id='3' --> -<a href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112277.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U8551P30DT20150618103651.jpg" width="198" height="132" /> - <span class="scroll-txt">±ß²ß×·µ¿»á½¯Ð¡º­ÂäÀáÇéÐ÷ʧ¿Ø</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_mil"> -<!-- publish_helper name='¾üÊÂͼ' p_id='30' t_id='107' d_id='2' --> -<a href="http://slide.mil.news.sina.com.cn/k/slide_8_68162_36309.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0616/U10553P30DT20150616115148.jpg" width="198" height="132" /> - <span class="scroll-txt">èÉÁúÊ×´ÎÁÁÏà°ÍÀ躽չ²¢±íÑÝ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_history"> -<!-- publish_helper name='Àúʷͼ' p_id='30' t_id='121' d_id='9' --> -<a href="http://slide.history.sina.com.cn/y/slide_61_40602_51700.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11647P30DT20150618092220.jpg" width="198" height="132" /> - <span class="scroll-txt">ÆƱùÖ®Âãº1972ÄêÄá¿ËËɷûª</span> - </a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_news2"> -<!-- publish_helper name='ÐÂÎÅ£¨Ô­´´£©' p_id='30' t_id='97' d_id='8' --> -<a href="http://slide.news.sina.com.cn/j/slide_1_45272_85404.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U10611P30DT20150618085120.jpg" width="198" height="132" /> - <span class="scroll-txt">¼ÇÒ䣺Öйú³ö×â³µ¡°·Ý¶ùÇ®¡±±äǨʷ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_sports2"> -<!-- publish_helper name='ÌåÓýͼ£¨Ã÷ÐÇ£©' p_id='30' t_id='101' d_id='13' --> -<a href="http://slide.sports.sina.com.cn/g/slide_2_730_83546.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U6604P30DT20150618095020.jpg" width="198" height="132" /> - <span class="scroll-txt">ÐÔ¸ÐÑ¡ÃÀ¹Ú¾üÁ¦Í¦Ã·Î÷</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_ent2"> -<!-- publish_helper name='ÓéÀÖͼ£¨Ã÷ÐÇ£©' p_id='30' t_id='100' d_id='7' --> -<a href="http://slide.ent.sina.com.cn/tv/h/slide_4_704_112226.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U9988P30DT20150617182208.jpg" width="198" height="132" /> - <span class="scroll-txt">¡¶È¨Á¦µÄÓÎÏ·¡·ÃâËÀÃûµ¥´ó²Â²â£¡</span> - </a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_astro"> -<!-- publish_helper name='ÐÇ×ùͼ' p_id='30' t_id='120' d_id='2' --> -<a href="http://slide.astro.sina.com.cn/slide_52_42283_32893.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0617/U7132P30DT20150617184653.gif" width="198" height="132" /> -<span class="scroll-txt">12ÐÇ×ùºÝÓôÃÆ</span></a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_tech"> -<!-- publish_helper name='¿Æ¼¼Í¼' p_id='30' t_id='103' d_id='8' --> -<a href="http://slide.tech.sina.com.cn/d/slide_5_453_60814.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U2727P30DT20150617090629.jpg" width="198" height="132" /> - <span class="scroll-txt">Ï¡ÓÐÒÁÀçÊóÍÃÒòýÌ屨µÀÃæÁÙÃð¾ø</span> - </a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_auto"> -<!-- publish_helper name='Æû³µÍ¼' p_id='30' t_id='102' d_id='5' --> - - <a href="http://photo.auto.sina.com.cn/tuji/18246/" target="_blank" suda-uatrack="key=woaikantu_auto&value=woaikantu_auto1"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U4982P30DT20150617094645.jpg" width="198" height="132" /> - <span class="scroll-txt">2015¿î×î±ãÒ˰µÏQ7ʵÅÄ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_blog"> -<!-- publish_helper name='²©¿Íͼ' p_id='30' t_id='105' d_id='3' --> -<a href="http://blog.sina.com.cn/lm/pic/" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U8214P30DT20150618095845.jpg" width="198" height="132" /> - <span class="scroll-txt">ÐüÔÚ¾ø±ÚÉϵIJ£Á§Õ»µÀ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_eladies"> -<!-- publish_helper name='Å®ÐÔͼ' p_id='30' t_id='110' d_id='4' --> -<a href="http://fashion.sina.com.cn/2015-06-18/0727/doc-ifxczqap4213453.shtml" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U5924P30DT20150618095551.jpg" width="198" height="132" /> - <span class="scroll-txt">¾Ý˵µÁĹ±Ê¼ÇºÃ¿´µÄÖ»ÓÐÑÕÖµ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_edu"> -<a href="http://slide.edu.sina.com.cn/slide_11_611_28256.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U5539P30DT20150618083421.jpg" alt="Öйú×îÃÀУ»¨ÐãÃÀͯÑÕ" width="198" height="132" /> - <span class="scroll-txt">Öйú×îÃÀУ»¨ÐãÃÀͯÑÕ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_collection"> -<a href="http://slide.collection.sina.com.cn/slide_26_17348_36347.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U5083P30DT20150618092240.jpg" width="198" height="132" /> - <span class="scroll-txt">»Ø¹ËÁξ²ÎÄÉúǰ˲¼ä</span> - </a> - </div> - - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L" suda-uatrack="key=index_new_pic&value=i_love_pic_change"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R" suda-uatrack="key=index_new_pic&value=i_love_pic_change"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists"> - <span class="cur"></span> - <span></span> - </div> - </div> - <div tab-type="tab-cont" style=""> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap scroll-pic-guess-wrap" id="SI_Scroll_Guess_Wrap" list-length ="10" item-length="16"> - <p class="loading scroll-loading"></p> - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Guess_Arr_L" suda-uatrack="key=index_picguess&value=change"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Guess_Arr_R" suda-uatrack="key=index_picguess&value=change"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Guess_Dot_Lists"> - <span class="cur"></span> - <span></span> - </div> - </div> - - <div tab-type="tab-cont" data-sudaclick="blk_weibopic_all" blkclick="auto_nav" blktitle="΢²©ÈÈͼ"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap1"> -<!-- -{weibo_΢²©ÈÈͼ} ---> - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L1" suda-uatrack="key=index_new_pic&value=weibo_pic_change"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R1" suda-uatrack="key=index_new_pic&value=weibo_pic_change"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists1"> - <span class="cur"></span> - <span></span> - </div> - </div> - - </div> - </div> - <script type="text/javascript"> - jsLoader({ - name: 'shm', - callback: function() { - SHM.register('home.custEvent.secondpage.fire', function($) { - $.evt.custEvent.fire($, 'secondPageEnd'); - var eventType = 'mouseover'; - var hasTouch = (typeof(window.ontouchstart) !== 'undefined'); - if (hasTouch) { - eventType = 'touchstart'; - } - var wbTrigger = $.E('SI_Scroll_WB_Trigger'); - var guessCont = $.E('SI_Scroll_Guess_Wrap'); - var wbWrap = $.E('SI_Scroll_Wrap1'); - var guessWrap = guessCont.parentNode.parentNode; - $.evt.addEvent(wbTrigger, eventType, function() { - if (typeof guessWrap !== 'undefined' && guessWrap) { - guessWrap.style.display = 'none'; - } - var imgs = wbWrap.getElementsByTagName('img'); - if(imgs&&imgs.length>0){ - for (var i = imgs.length - 1; i >= 0; i--) { - var img = imgs[i]; - var src = img.getAttribute('data-src'); - if(src){ - img.src=src; - img.removeAttribute('data-src'); - } - }; - } - }); - }); - //²âÊÔ²ÂÄãϲ»¶µÄµÇ¼ - } - }); - - jsLoader({ - name : 'shm', - callback : function() { - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "SI_Scroll_Wrap"; //ÄÚÈÝÈÝÆ÷ID - focusScroll.dotListId = "SI_Scroll_Dot_Lists";//µãÁбíID - focusScroll.dotClassName = "";//µãclassName - focusScroll.dotOnClassName = "cur";//µ±Ç°µãclassName - focusScroll.listType = "";//ÁбíÀàÐÍ(number:Êý×Ö£¬ÆäËüΪ¿Õ) - focusScroll.listEvent = "onmouseover"; //Çл»Ê¼þ - focusScroll.frameWidth = 1000;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 1000; //·­Ò³¿í¶È - focusScroll.upright = false; //´¹Ö±¹ö¶¯ - focusScroll.speed = 10; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - - var focusScroll1 = new ScrollPic(); - focusScroll1.scrollContId = "SI_Scroll_Wrap1"; //ÄÚÈÝÈÝÆ÷ID - focusScroll1.dotListId = "SI_Scroll_Dot_Lists1";//µãÁбíID - focusScroll1.dotClassName = "";//µãclassName - focusScroll1.dotOnClassName = "cur";//µ±Ç°µãclassName - focusScroll1.listType = "";//ÁбíÀàÐÍ(number:Êý×Ö£¬ÆäËüΪ¿Õ) - focusScroll1.listEvent = "onmouseover"; //Çл»Ê¼þ - focusScroll1.frameWidth = 1000;//ÏÔʾ¿ò¿í¶È - focusScroll1.pageWidth = 1000; //·­Ò³¿í¶È - focusScroll1.upright = false; //´¹Ö±¹ö¶¯ - focusScroll1.speed = 10; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll1.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll1.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll1.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll1.circularly = true; - focusScroll1.initialize(); //³õʼ»¯ - - function $(id){ - return document.getElementById(id) || null; - } - - function attachEvent(obj, evt, func, eObj) { - eObj = !eObj ? obj : eObj; - if(obj.addEventListener) { - obj.addEventListener(evt , func, false); - } else if(eObj.attachEvent) { - obj.attachEvent('on' + evt, func); - } - } - - function getRandom(obj) { - var max = obj.pageLength - 1; - var min = 0; - var randomNum = Math.round(Math.random()*(max - min) + min); - obj.pageTo(randomNum); - } - - $('SI_Scroll_Arr_L').onmousedown = function(){ - focusScroll.pre(); - return false; - } - $('SI_Scroll_Arr_R').onmousedown = function(){ - focusScroll.next(); - return false; - } - - $('SI_Scroll_Arr_L1').onmousedown = function(){ - focusScroll1.pre(); - return false; - } - $('SI_Scroll_Arr_R1').onmousedown = function(){ - focusScroll1.next(); - return false; - } - - getRandom(focusScroll); - - attachEvent($('SI_Scroll_Dot_Lists'),'mouseover',function(event){ - var tar = event.target || event.srcElement; - if(tar.tagName == 'SPAN'){ - try{ - _S_uaTrack("index_new_pic", "i_love_pic_change_red_point"); - }catch(e){ - - } - } - }); - } - }); - </script> - <!-- part-e end --> - - <div class="blank-cont" style="height:10px"></div> - <!-- part-g begin --> - - <div class="part-g clearfix"> - <div class="part-g-l"> - <!-- mod17 --> - <div class="mod-17"> - <div class="tit02 tit04"> - <h3><a href="http://blog.sina.com.cn/lm/search/class/" target="_blank">²©Ö÷¶©ÔÄ</a></h3> - <a href="http://blog.sina.com.cn/lm/search/class/" class="more" target="_blank" style="border-right:0px;">¸ü¶à&gt;&gt;</a> -<!-- -<a href="http://zhuanlan.sina.com.cn/" class="bz-order" target="_blank"><i></i></a> ---> - </div> - <div class="mod17-cont"> - <ul class="list-b" data-sudaclick="blk_blog_dy" blkclick="auto_nav" blktitle="²©Ö÷¶©ÔÄ"> -<!-- publish_helper name='²©Ö÷¶©ÔÄ' p_id='30' t_id='105' d_id='2' --> -<li><a href="http://blog.sina.com.cn/s/blog_54648dbe0102wf27.html?tj=1" target="_blank">¸ß·£ºÖ÷³ÖÈËÂí±ó±»·£ºÎ±Ø²»Í´¿ì</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_4949b3d50102vnvm.html?tj=1" target="_blank">²éСÐÀ£ºÖÐÎÄÊÇÏã¸Û¹ú¼ÊѧУµÚ¶þÓïÑÔ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_43e6e0b00102vo41.html?tj=1" target="_blank">¶­¿Ëƽ£ºÀ±²»ÊÇζµÀ¶øÊÇÒ»ÖÖÍ´¾õ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_d7b481510102vmkg.html?tj=1" target="_blank">ÓμíÆÒÕ¯Îâ¸ç¿ßµÄʵÓù¥ÂÔ(ͼ)</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_474edc500102vsue.html?tj=1" target="_blank">³±°×£º¡°ËÄ´¨Ò½¿Æ´óѧ¡±¸ÄÃû·ç²¨</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_520d14230102vp2l.html?tj=1" target="_blank">ÐúÈí°×ÄÛµÄСÈâ°ü×ÓÑø³É¼Ç(×éͼ)</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_4fbe436f0102vxuq.html?tj=1" target="_blank">ÏãËâÃÛÖ­ÅŹǿÚζ¶ÀÌØ˱ָÁôÏã(×éͼ)</a></li> - </ul> - </div> - </div> - <!-- mod17 --> - <div class="blank-cont" style="height:10px"></div> - <!-- mod18 --> - <div class="mod-18"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 2ÂÖ²¥°´Å¥03¹ã¸æ begin --> -<div id="ad_46011" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046011"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 2ÂÖ²¥°´Å¥03¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod18 --> - </div> - <div class="part-g-mr clearfix"> - <div class="part-g-m"> - <!-- mod19 --> - <div class="uni-blk mod-19" id="SI_Order_E" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://blog.sina.com.cn/" target="_blank">²©¿Í</a></span> - <span tab-type="tab-nav" style="display:none;"><a href="http://blog.sina.com.cn/lm/rank/" target="_blank">¾«Ñ¡</a></span> - <span tab-type="tab-nav" style="display:none;"><a href="http://weibo.com/" target="_blank">΢²©</a></span> - </div> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Blog"> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_blog_search&value=blog_search">ËÑË÷</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" method="GET" action="http://search.sina.com.cn/" onsubmit="return blogsearch(this,'blog')"> - <select id="SI_Slt_03" name="by"> - <option value="all" selected="selected">È«ÎÄ</option> - <option value="title">±êÌâ</option> - <option value="nick">×÷Õß</option> - <option value="tag">±êÇ©</option> - </select> - <input type="hidden" name="c" value="blog"> - <input type="hidden" name="range" value="article"> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" onblur="if(this.value==''){this.value='ÇëÊäÈë²éѯ´Ê'}" onfocus="if(this.value=='ÇëÊäÈë²éѯ´Ê'){this.value=''}" value="ÇëÊäÈë²éѯ´Ê" name="q"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_blog_search&value=blog_search_click"/> - </a> - </form> - </div> - </div> - </div> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_3"></li> - </ul> - - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_blog_1" blkclick="auto_nav" blktitle="²©¿Í"> -<!-- publish_helper name='²©¿ÍÇø¿é' p_id='30' t_id='105' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<div class="uni-blk-pic" id="blogPic0"><a href="http://blog.sina.com.cn/s/blog_518cc2930102vo6t.html?tj=1" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0617/U1748P30DT20150617162750.jpg" width="105" height="70" /> - <span>½ÖÅı±¾©ÇåÁ¹ÃÀÅ®</span></a> - -<!-- newitemÌæ»»±ê¼Ç0 --></div><ul class="uni-blk-list01 list-a " id="bloglist0"><li><a href="http://blog.sina.com.cn/" target="_blank">¡°··Âô¶ùͯһÂÉÅÐËÀÐÌ¡±Ôõ²»¿¿Æ×</a></li> - <li><a href="http://blog.sina.com.cn/s/blog_8db3ce3d0102wgpd.html?tj=1" target="_blank">Ò×ÏÜÈÝ£ºµ±Ç°ÖйúA¹ÉÔõ±©ÕDZ©µø</a></li> - <li><a target="_blank" href="http://blog.sina.com.cn/s/blog_477614640102vilt.html?tj=1">ÑîÀ½£ºÖ£¾ûÍõ½Ü×ÔÆز»ÎªÈËÖªÍùÊÂ</a></li> - <li><a href="http://blog.sina.com.cn/s/blog_4fc500400102vid3.html?tj=1" target="_blank">±±´ó˶ʿ×ö×°ÐÞ¹¤ÊÇÈ˲ÅÀË·ÑÂð£¿</a></li> -<!-- newitemÌæ»»±ê¼Ç1 --></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a " id="bloglist1"> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_496489160102vst0.html?tj=1">ÒÔʲô×ËÊÆÓ­½ÓÓñÁÖ¹·Èâ½ÚÖ®Õù</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_61b3435e0102vriq.html?tj=1">ÀÖÊÓºÍСÃ×µ½µ×³³Ê²Ã´</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_6011cb260102vl0z.html?tj=1" target="_blank">°²±¶·òÆÞ¡°·ò³ª¸¾²»Ë桱ÃØÃÜ</a> <a href="http://blog.sina.com.cn/s/blog_6dd414ed0102vr48.html?tj=1" target="_blank">Íâ½»²¿ÐÂÎÅ·¢ÑÔÈËÏàËƵã</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_48631e860102vnyz.html?tj=1">ÖйúÄÄ×ù³ÇÊоÓÃñ×î°®ÔĶÁ</a> <a href="http://blog.sina.com.cn/s/blog_4d77291f0102vhvw.html?tj=1" target="_blank">Ô¬ºêµÀ£ºÍíÃ÷Ê¿ÈË×ÝÀÖÉú»î</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_573c3a4d0102vkoa.html?tj=1" target="_blank">´ÏÃ÷Å®È˲»ÒªÖص¸¾ÓÀï·òÈ˸²ÕÞ</a> <a href="http://blog.sina.com.cn/s/blog_82b859870102wde7.html?tj=1" target="_blank">¼Ò³¤³£·¸µÄÓý¶ùÎóÇø</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/lm/ruiblog/">ÈÕ±¾Å®Ã÷ÐÇΪºÎ²»Ô¸¼ÞÍÁºÀ</a> <a target="_blank" href="http://blog.sina.com.cn/lm/lz/#sh">ΪºÎÄã×ÜÍÏƽ¾ù¹¤×ʵĺóÍÈ</a></li> -<li><a href="http://blog.sina.com.cn/lm/lz/#rw" target="_blank">Ò¶ÓÀÁÒ£ºÎÒÔŲ́Íå²éÔÄ´÷óÒµµ°¸</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_5ef43b490102vnj3.html?tj=1">°ÄÖÞÍÁÖøÉñÃرíÑÝ(ͼ)</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_54a625bf0102vtwz.html?tj=1" target="_blank">ÎÄâù£ºÈÃËÉ»¨µ°²»Õ³µ¶µÄÇÏÃÅ</a> <a href="http://blog.sina.com.cn/s/blog_621571b70102vje5.html?tj=1" target="_blank">×îÊʺϺ£ÊÄɽÃËÖ®µØ(ͼ)</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_4be8c9b30102vpnt.html?tj=1">ÓéÀÖȦǰÈÎÃǵİ®ºÞÇé³ð</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_ea61066a0102vvd1.html?tj=1">â¹ų̂¡¶°Ö°Ö3¡·Ð¦µã²»Óóî</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_61631ef60102vnly.html?tj=1" target="_blank">Òª²»ÒªÀë»éÖ»ÐèºâÁ¿Ò»¸öÎÊÌâ</a> <a href="http://blog.sina.com.cn/s/blog_4cb10b1c0102w3e8.html?tj=1" target="_blank">ÔõÍü¼ÇÍøÂçÓÎÏ·ÀïµÄÄÐÈË</a></li> - -<!-- newitemÌæ»»±ê¼Ç2 --> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_e91b9fb60102vuzp.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¹ÉÊн׶ÎÐÔµ÷ÕûºóÔõô²Ù×÷</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_43e6e0b00102vntq.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ôÕ×Ó×îÔçºÍÇüԭûһëǮ¹Øϵ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_699132e60102voup.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¡¶»¨Ç§¹Ç¡·Ê¥Ä¸ÂêÀöËÕ´«Ææ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_48c2bed00102vpnm.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ºÚ辯²ìÄܸϳ¬»úÆ÷èÂð</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_ea61066a0102vvd1.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¡¶°Ö°Ö3¡·¿¿Ê²Ã´À­¸ßÊÕÊÓÂÊ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_477614640102vilt.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">Ö£¾ûÍõ½Ü²»ÎªÈËÖªµÄ¹ÊÊÂ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_5ef43b490102vnj3.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">À¶É½ÉñÃØÈÈÀ±µÄ°ÄÖÞÍÁÖø±íÑÝ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_621571b70102vje5.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">Òâ´óÀûÀËÂþÎåÓæ´åÈ«¹¥ÂÔ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_43e6e0b00102vo41.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">À±²»ÊÇζµÀ¶øÊÇÒ»ÖÖÍ´¾õ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_72d0cc2e0102vydz.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ÃÀζûÉÌÁ¿µÄСÁãʳը¶àζÓã</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_48dcdda20102vngm.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">³ÔÒâ´óÀû²Ë¿´À­Ë¹Î¬¼Ó˹¡°³¾¾í¡±</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_6ab1f9f80102vl79.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ÃÔʧÔÚ°ÄÖÞÃÀÀöº£µº</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_9ae454b30102w2tb.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ºº×å¶ÔÆäËûÃñ×å³ÆνµÄ±äǨ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_4be1d27f0102vhb7.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ͶôÕ¼ÀÇüÔ­µÄ¹ÊÊ¿ÉÐÅÂð</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_4870bbec0101edru.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">Ç°ÖйúÅ®¼ÇÕßÑÛÖеÄмÓÆÂ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_44b813260102vkvh.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¼Ö±¦ÓñµÄÄÌÂèΪɶÖô¹ÕÕÈ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_536e70930102vk9i.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">×îÈ«µ××±´óɨä</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_5ebb9dc30102vuex.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¼ÌÐø¼òÕþ·ÅȨÉ¹úÆó¸Ä¸ï</a> - - </ul> - - <ul class="uni-blk-list02 list-a "> -<li><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTU2NQ%3D%3D&sign=d4d4b3b820972b68&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fboke1%2F%3Ftel%3D17%26src%3D0017" target="_blank">Ãî:¸ßѪ֬µÄÈË,³ÔÕâ¸öÎȽµ</a> <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTI1Ng%3D%3D&sign=6ece5959ef4f303d&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fboke-2b%2F"target="_blank">ÄÐÈËÇ°ÁÐÏÙ×ÔÎÒÁÆ·¨:ÊÓƵ</a></li> - </ul> - - </div> - -<script> - jsLoader({ - name: 'shm', - callback: function() { - - //var guessUrl = 'http://www.sina.com.cn/js/index/96/home.recommender.min.js'; - - var guessUrl = 'http://www.sina.com.cn/js/index/96/home.recommender.2014.min.js'; - -/* - var sguid = SHM.util.cookie.getCookie('SINAGLOBAL'); - if(typeof sguid == 'string'){ - lastNum = sguid.charAt(sguid.length - 1, 1); - if(lastNum == '8' || lastNum == '1' || lastNum == '4'){ - guessUrl = 'http://www.sina.com.cn/js/index/96/home.recommender.2014.min.js'; - } - } -*/ - - jsLoader({ - url : guessUrl, - callback : function () { - var Store = window.___CrossDomainStorage___; - Store.ready(function(st){ - //renderLinks(30, 'ud.fd.www.blogStorage0', 'bloglist0', 'blogNewItem', false, st); - renderLinks(50, 'ud.fd.www.blogStorage1', 'bloglist1', 'blogNewItem', false, st); - //renderLinks(50, 'ud.fd.www.blogStorage2', 'blogPic0', 'blogNewPic', true, st); - }); - } - }); - } - }); -</script> - -<script src="http://www.sina.com.cn/js/79/2013/0717/fix.js" charset="utf-8"></script> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_blog_2" blkclick="auto_nav" blktitle="¾«Ñ¡"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¾«Ñ¡Çø¿é' p_id='30' t_id='105' d_id='4' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/s/blog_493258a80102vib4.html?tj=1" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0518/U8214P30DT20150518105256.jpg" width="105" height="70" /> -<span>Ô¼¾»¨¿ª</span></a><ul class="uni-blk-list01 list-a"> -<li><a href="http://blog.sina.com.cn/s/blog_5edca6f40102vocb.html?tj=1" target="_blank">Âí¶úɽ¶Å¾é»¨º£ç²Àö¾°É«</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_5fd993e20102vmvx.html?tj=1" target="_blank">ÏÖʵÉú»îÖÐÇÚÀ͵Ļݰ²Å®</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_6b99ba750102w102.html?tj=1" target="_blank">ʵÅÄÄÏ°ëÇòСÕò×íÃÀÇïÌì</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_49aa2c640102vl1o.html?tj=1" target="_blank">ÐÐÉãÂÞȪ¹ÅÕòµÄ²×É£ËêÔÂ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://blog.sina.com.cn/s/blog_e91b9fb60102vuzp.html?tj=1" target="_blank">¹ÉÊн׶ÎÐÔµ÷ÕûºóÔõô²Ù×÷</a> <a href="http://blog.sina.com.cn/s/blog_43e6e0b00102vntq.html?tj=1" target="_blank">ôÕ×Ó×îÔçºÍÇüԭûһëǮ¹Øϵ</a></li><li><a href="http://blog.sina.com.cn/s/blog_699132e60102voup.html?tj=1" target="_blank">¡¶»¨Ç§¹Ç¡·Ê¥Ä¸ÂêÀöËÕ´«Ææ</a> <a href="http://blog.sina.com.cn/s/blog_48c2bed00102vpnm.html?tj=1" target="_blank">ºÚ辯²ìÄܸϳ¬»úÆ÷èÂð</a></li><li><a href="http://blog.sina.com.cn/s/blog_ea61066a0102vvd1.html?tj=1" target="_blank">¡¶°Ö°Ö3¡·¿¿Ê²Ã´À­¸ßÊÕÊÓÂÊ</a> <a href="http://blog.sina.com.cn/s/blog_477614640102vilt.html?tj=1" target="_blank">Ö£¾ûÍõ½Ü²»ÎªÈËÖªµÄ¹ÊÊÂ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_5ef43b490102vnj3.html?tj=1" target="_blank">À¶É½ÉñÃØÈÈÀ±µÄ°ÄÖÞÍÁÖø±íÑÝ</a> <a href="http://blog.sina.com.cn/s/blog_621571b70102vje5.html?tj=1" target="_blank">Òâ´óÀûÀËÂþÎåÓæ´åÈ«¹¥ÂÔ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_43e6e0b00102vo41.html?tj=1" target="_blank">À±²»ÊÇζµÀ¶øÊÇÒ»ÖÖÍ´¾õ</a> <a href="http://blog.sina.com.cn/s/blog_72d0cc2e0102vydz.html?tj=1" target="_blank">ÃÀζûÉÌÁ¿µÄСÁãʳը¶àζÓã</a></li><li><a href="http://blog.sina.com.cn/s/blog_48dcdda20102vngm.html?tj=1" target="_blank">³ÔÒâ´óÀû²Ë¿´À­Ë¹Î¬¼Ó˹¡°³¾¾í¡±</a> <a href="http://blog.sina.com.cn/s/blog_6ab1f9f80102vl79.html?tj=1" target="_blank">ÃÔʧÔÚ°ÄÖÞÃÀÀöº£µº</a></li> - -<li><a href="http://blog.sina.com.cn/s/blog_9ae454b30102w2tb.html?tj=1" target="_blank">ºº×å¶ÔÆäËûÃñ×å³ÆνµÄ±äǨ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_4be1d27f0102vhb7.html?tj=1">ͶôÕ¼ÀÇüÔ­µÄ¹ÊÊ¿ÉÐÅÂð</a></li><li><a href="http://blog.sina.com.cn/s/blog_4870bbec0101edru.html?tj=1" target="_blank">Ç°ÖйúÅ®¼ÇÕßÑÛÖеÄмÓÆÂ</a> <a href="http://blog.sina.com.cn/s/blog_44b813260102vkvh.html?tj=1" target="_blank">¼Ö±¦ÓñµÄÄÌÂèΪɶÖô¹ÕÕÈ</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_536e70930102vk9i.html?tj=1">×îÈ«µ××±´óɨä</a> <a href="http://blog.sina.com.cn/s/blog_5ebb9dc30102vuex.html?tj=1" target="_blank">¼ÌÐø¼òÕþ·ÅȨÉ¹úÆó¸Ä¸ï</a></li> - </ul> - </textarea> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_weibo_2" blkclick="auto_nav" blktitle="΢²©"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- -{weibo_΢²©Çø¿é} ---> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod19 --> - </div> - <div class="part-g-r"> - <!-- mod20 --> - <div class="uni-blk mod-19" id="SI_Order_F" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://book.sina.com.cn/" target="_blank">¶ÁÊé</a></span> - <span tab-type="tab-nav" style="display:none;"><a href="http://vip.book.sina.com.cn/book_lib.php?lib=001&order=fwc&sta=&pub=&dpc=1" target="_blank">С˵</a></span> - </div> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Book" style=""> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_book_search&value=book_search">ËÑÊé</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" method="GET" action="http://vip.book.sina.com.cn/s.php" onsubmit="return booksearch(this)"> - <select id="SI_Slt_04" name="s_type"> - <option value="" selected="selected">Ä£ºý</option> - <option value="1">ÊéÃû</option> - <option value="2">×÷Õß</option> - <option value="3">³ö°æÉç</option> - </select> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" onblur="if(this.value==''){this.value='ÇëÊäÈë²éѯ´Ê'}" onfocus="if(this.value=='ÇëÊäÈë²éѯ´Ê'){this.value=''}" value="ÇëÊäÈë²éѯ´Ê" name="k"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_book_search&value=book_search_click" /> - </a> - </form> - </div> - </div> - </div> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_4"></li> - </ul> - - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_book_1" blkclick="auto_nav" blktitle="¶ÁÊé"> -<!-- publish_helper name='¶ÁÊéÇø¿é' p_id='30' t_id='106' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://book.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U11368P30DT20150618105830.jpg" width="105" height="70" /> - - <span>±»ÒÅÍüµÄÎÄѧ´óʦ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://book.sina.com.cn/top201504/">ÐÂÀËÖйúºÃÊé°ñ2015Äê4Ô°ñ½ÒÏþ</a></li> -<li><a target="_blank" href="http://book.sina.com.cn/news/c/2015-06-18/0853748804.shtml">ÓÚµ¤£ºÖйú¸¸Ç×ʧȥ¾«ÉñÒýÁì¼ÛÖµ</a></li> -<li><a target="_blank" href="http://book.sina.com.cn/news/c/2015-06-18/0914748807.shtml">ÁùСÁäͯ£ºÃûÖø¿É´´Ðµ«Îð¶ñ¸ã</a></li> -<li><a target="_blank" href="http://book.sina.com.cn/news/c/2015-06-18/0916748808.shtml">ÕÅÏÍÁÁÖø×÷¡¶ÁéÓëÈâ¡·½«ÅĵçÊÓ¾ç</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://book.sina.com.cn/255/2014/0121/75.shtml" target="_blank">ÎÄ»¯</a>| -<a href="http://book.sina.com.cn/news/c/2015-06-18/0926748809.shtml" target="_blank">¡¶µÁĹ±Ê¼Ç ¡·²îÆÀÈç³± ÄÏÅÉÈýÊ壺¶¼°ÑÎÒ¿´ÉµÁË</a></li><li><a href="http://book.sina.com.cn/255/2014/0120/73.shtml" target="_blank">ÊéÆÀ</a>| -<a href="http://book.sina.com.cn/news/review/w/2015-06-17/0926748552.shtml" target="_blank">¡¶¿à¼Ë»ØÒ伡·£º²¢·ÇËùÓеİ®¶¼ÊÇ¿íÀ«µÄº£Ñó</a></li> - -<li><a href="http://book.sina.com.cn/zl/" target="_blank">רÀ¸</a>| -<a href="http://book.sina.com.cn/zl/mingjia/2015-05-12/16461017.shtml" target="_blank">ËûÊÊÓ¦Á˶ÁÕßµÄÐèÒª¡ª¡ªÇ³ÒéÍô¹úÕæÓëÊ«¸èÔĶÁ</a></li> - -<li><a href="http://book.sina.com.cn/zl/" target="_blank">רÀ¸</a>| -<a href="http://book.sina.com.cn/zl/jiaodian/2015-05-26/17281018.shtml" target="_blank">ÌÆé¦:Óëʱ¼äÍæζ¡ª¡ª¹ØÓÚÎÄѧʷÉϵÄÈÕ¼ÇÓëÐżþ</a></li> - -<li><a href="http://book.sina.com.cn/excerpt/" target="_blank">ÊéÕª</a>| -<a href="http://book.sina.com.cn/excerpt/sz/rw/2015-05-26/1545743885.shtml" target="_blank"> -°ÂÆÕÀ­£º»¶ÓäÊÇÖÖÓлØÀ¡µÄÄÜÁ¿</a> -<a href="http://book.weibo.com/book/play/5347244-10256715.html" target="_blank">³¬Ô½¿ìÀÖÔ­Ôò</a></li> - -<li><a href="http://book.sina.com.cn/excerpt/" target="_blank">ÊéÕª</a>| -<a href="http://book.sina.com.cn/excerpt/sz/rw/2015-05-15/1705741716.shtml" target="_blank"> -Ì©ÀÕ¸ÐÇéµÄµÚÒ»´Î¼èÄѾñÔñ</a> -<a href="http://book.weibo.com/book/play/5347448-10274656.html" target="_blank">µ±ÉñʧȥËýµÄËù°®</a></li> - -<li><a href="http://book.sina.com.cn/zthz/" target="_blank">²ß»®</a>| -<a href="http://book.sina.com.cn/zt/jiangfeng.html" target="_blank">½¯·å:ÎÒÏàÐÅÎÄѧ»á²»Ðà</a> <a href="http://book.sina.com.cn/focusmedia/2015-05-05/1101739430.shtml" target="_blank">Ê«È˵ÄÁé»êÓÀÔ¶ÊôÓÚÊ«¸è</a></li> - -<li><a href="http://book.sina.com.cn/zthz/" target="_blank">²ß»®</a>| - <a href="http://book.sina.com.cn/zt/kanghe.html" target="_blank">¿µºÕ:¹Ø¼üÔÚ·ÅÆú¿Ö¾å¡ª¡ªËüÖ»Óб仯£¬Ã»ÓÐÖÕ¼«</a></li> - -<li><a href="http://city.sina.com.cn/">³ÇÊÐ</a>| <a href="http://city.sina.com.cn/" target="_blank">ÉϺ£±©ÓêÕþÎñ΢²©¿ìËÙÓ¦¶Ô</a> <a href="http://city.sina.com.cn/focus/t/2015-06-18/103950840.html" target="_blank">¿ØÑÌÁîϽäÑÌÕß±ä¶à</a></li> - </ul> - - <ul class="uni-blk-list02 list-a"> -<li><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTQwNQ%3D%3D&sign=be249e2a53b70f5b&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fdushu-1a%2F" target="_blank">¿ìѶ</a>| <a -href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDU0NA%3D%3D&sign=33ec0754c8336b6d&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fdushu1%2F%3Ftel%3D17%26src%3D0017" target="_blank">Ô´Í·"³Ôµô"¸ßѪѹ£¨Í¼£©</a> <a -href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTgwOQ%3D%3D&sign=7547d7b72cb78fec&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fdushu2%2F%3Ftel%3D17%26src%3D0017" target="_blank">²ÍºóѪÌÇ6.5¾ÍÕâô³Ô</a></li> - </ul> - - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_book_2" blkclick="auto_nav" blktitle="С˵"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- -{book_¶ÁÊé_4_С˵Çø¿é} ---> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod20 --> - </div> - </div> - </div> - <!-- part-g end --> - <div class="blank-cont" style="height:19px;"></div> - <!-- part-ip-2 --> - <span id="SI_IP_Part_2"></span> - <!-- /part-ip-2 --> - - <!-- part-i begin --> - <div class="part-i"> - -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸02¹ã¸æ begin --> -<div id="ad_43762" class="ad-banner mb25"><ins class="sinaads" data-ad-pdps="PDPS000000043762"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸02¹ã¸æ end --> -<!--_SINA_ADS_END_--> - - </div> - <!-- part-i end --> - - <!-- part-h begin --> - <div class="part-h clearfix"> - <div class="part-h-l"> - <!-- mod21 --> - <div class="mod-21 mod-02"> - <div class="tit02"> - <h3><a href="http://tech.sina.com.cn/d/photo/" target="_blank">̽Ë÷Ȥͼ</a></h3> - <div class="ed-pic-lists clearfix" id="SI_Scroll_Sdot_Lists"></div> - </div> - <div class="mod21-cont" data-sudaclick="blk_tech_dispic" blkclick="auto_nav" blktitle="̽Ë÷Ȥͼ"> - <div class="ed-pic-wrap clearfix" id="SI_Scroll_Swrap"> -<!-- publish_helper name='¿Æ¼¼Ã¿ÈÕͼƬ' p_id='30' t_id='103' d_id='6' --> -<div class="ed-pic-item"><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60862.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U2727P30DT20150618082042.jpg" width="218" height="160" /></a> -<ul class="list-b"><li><a target="_blank" href="http://slide.tech.sina.com.cn/d/slide_5_453_60862.html">·ÇÖ޺Ϸ¨á÷ÁÔ£º´óÁ¿Ò°Éú¶¯ÎïÖƳɱ걾</a></li></ul></div> - </div> - </div> - </div> - <!-- mod21 --> - <!-- mod22 --> - <div class="mod-22"> - - <div class="mod22-cont clearfix" style="padding:6px 0 6px 8px;"> - <ul class="list-b" data-sudaclick="blk_tech_dispic_list" blkclick="auto_nav" blktitle="ȤͼÁбí"> -<!-- publish_helper name='¿Æ¼¼Ì½Ë÷Ȥͼ' p_id='30' t_id='103' d_id='7' --> -<li><a target="_blank" href="http://tech.sina.com.cn/d/f/2015-06-17/doc-ifxczqan1463329.shtml">Õ溺×Ó¿´ÊÖÖ¸:ʳָ±ÈÎÞÃûÖ¸¶Ì¸üÓÐÄÐÈËζ</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-17/doc-ifxczyze9666582.shtml">º¬·úÆøÌå¶ÔÎÒÃǵ½µ×ÓÐʲôΣº¦(ͼ)</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-17/doc-ifxczqap4206563.shtml">ÈËÏз´µ¹ÈÝÒ×Éú²¡£¿ÊʶȽôÕÅÌá¸ßÃâÒßÁ¦</a></li> - -<li><a target="_blank" href="http://slide.tech.sina.com.cn/digi/slide_5_30939_60865.html">¹âÓ°Á÷ÌʵÄÇéÐ÷ ²¶×½ÈËÎï×îϸ΢µÄÉñÔÏ</a></li> - </ul> - </div> - - </div> - <!-- mod22 --> - <div class="blank-cont" style="height:10px"></div> - <!-- nmod02 --> - <div class="nmod02"> - -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 3ÂÖ²¥°´Å¥04¹ã¸æ begin --> -<div id="ad_46013" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046013"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 3ÂÖ²¥°´Å¥04¹ã¸æ end --> -<!--_SINA_ADS_END_--> - - </div> - <!-- nmod02 --> - </div> - <div class="part-h-m"> - <!-- mod23 --> - <div class="uni-blk" id="SI_Order_G" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://tech.sina.com.cn/" target="_blank">¿Æ¼¼</a></span> - <span tab-type="tab-nav"><a href="http://tech.sina.com.cn/discovery/" target="_blank">̽Ë÷</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://tech.sina.com.cn/t/4g/" target="_blank">4G</a></li> -<li><a href="http://blog.sina.com.cn/lm/tech/" target="_blank">IT²©¿Í</a></li> -<li><a href="http://tech.sina.com.cn/internet/" target="_blank">»¥ÁªÍø</a></li> -<li><a href="http://tech.sina.com.cn/zl/" target="_blank">´´Ê¼Ç</a></li> -<li><a href="http://tech.sina.com.cn/zl/post/detail/2013-04-24/pid_8274000.htm" target="_blank">Ͷ¸å</a></li> - -<li id="SI_IP_MT_5"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_tech_1" blkclick="auto_nav" blktitle="¿Æ¼¼"> -<!-- publish_helper name='¿Æ¼¼Çø¿é' p_id='30' t_id='103' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://tech.sina.com.cn/d/photo/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U2727P30DT20150618082135.gif" width="105" height="70" /> - - <span>ÏÖʵ°æ±äÐνð¸Õ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://tech.sina.com.cn/it/2015-06-18/doc-ifxefurq6211346.shtml" target="_blank">Öйúµç×ÓÉÙÊýÁìµ¼ÄÚÍâ¹´½áÌ×¹ú×Ê</a></li> - -<li><a href="http://tech.sina.com.cn/it/2015-06-18/doc-ifxefurq6126833.shtml" target="_blank">ÌØ˹À­ÔÚ»ªÏúÁ¿²»¼Ñ£ºÄ£Ê½ÔâÖÊÒÉ</a></li> - -<li><a href="http://tech.sina.com.cn/i/2015-06-17/doc-ifxefurq5977932.shtml" target="_blank">¿ì²¥CEOÌ«Ì«·¢Î¢²©:ÍøÓÑ´òÉÍ</a></li> - -<li><a href="http://tech.sina.com.cn/t/2015-06-18/doc-ifxefurt9352981.shtml" target="_blank">ÐźÅÆÁ±ÎÆ÷ËæÒâÂòÂô ¼à¹Ü´¦Ã¤Çø</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxefurt9352829.shtml">É«ÇéÒµ´îO2O˳·ç³µ£º×éÖ¯·Ö¹¤Ã÷È· ¹Ë¿ÍÒ»¼üϵ¥ </a></li> - -<li><a href="http://tech.sina.com.cn/i/2015-06-17/doc-ifxczyze9680418.shtml" target="_blank">Æ滢Ðû²¼½«´ÓÃÀ¹ÉÍËÊÐ</a> <a target="_blank" href="http://tech.sina.com.cn/i/2015-06-17/doc-ifxefurq5809032.shtml">Öܺèµt£ºÊÐֵδÌåÏÖ¹«Ë¾¼ÛÖµ</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxczyze9691073.shtml">ºê´ïвÄÎ¥¹æ±»µ÷²é ·ÖÖÚ´«Ã½»Ø¹éA¹ÉÉúÐüÄî</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/z/roadshow/">´´ÒµÂ·ÑÝ</a>|<a target="_blank" href="http://tech.sina.com.cn/z/roadshow-ldl/">½¡×ßÅܲ½APP&quot;ÀÖ¶¯Á¦&quot;</a> <a target="_blank" href="http://tech.sina.com.cn/i/2015-06-05/doc-icrvvrak2740010.shtml" class="linkRed">ÉϺ£Â·Ñݱ¨Ãû</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/zl/">´´Ê¼Ç</a>| <a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/it/2015-06-18/pid_8481223.htm">Oculus£ºFacebookµÄÐÂÒ»´ú¡°Ô¼ÅÚ¡±¹¤¾ß£¿</a></li> -<li><a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/i/2015-06-18/pid_8481226.htm">360˽Óл¯ÊÇΪÁË»ØA¹ÉȦǮÂð</a> <a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/i/2015-06-17/pid_8481148.htm">¿Æ¼¼¹«Ë¾ÈçºÎƭɵ×ÓÇ®</a></li> - -<li><a href="http://blog.sina.com.cn/lm/tech/" target="_blank">²©¿Í</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_40345c100102vzol.html?tj=tech">´¸×ÓƾʲôÐÂÈý°åÉÏÊÐ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_54789aa40102vs3m.html?tj=tech">Å̵ã×î¾ßµß¸²Á¦Ê®´óºÚ¿Æ¼¼</a></li> - - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_tech_2" blkclick="auto_nav" blktitle="̽Ë÷"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='̽Ë÷Çø¿é' p_id='30' t_id='103' d_id='3' --> - <div class="uni-blk-bt clearfix"> -<a href="http://tech.sina.com.cn/d/photo/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U2727P30DT20150618110834.jpg" width="105" height="70" /> - - <span>°ÔÆøºÀ»ªÔ½Ò°Ì¹¿Ë</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://tech.sina.com.cn/d/a/2015-06-18/doc-ifxczyze9699185.shtml" target="_blank">ɱÊÖµÄÑÝ»¯£ºÖ©Ö붾Һ´ÓºÎ¶øÀ´£¿</a></li> - -<li><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60813.html" target="_blank">¿Æѧ¼ÒÊ×´ÎÅĵ½±±¼«ÐܳԺ£ëà(ͼ)</a></li> - -<li><a href="http://tech.sina.com.cn/d/v/2015-06-18/doc-ifxefurs2586889.shtml" target="_blank">ÄãÕæµÄÃ÷°×ÐÄÀíѧ³£Ê¶ÔÚ˵ʲôÂð</a></li> - -<li><a href="http://tech.sina.com.cn/d/f/2015-06-18/doc-ifxefurq6678703.shtml" target="_blank">Å®ÐÔ¸ü³¤ÊÙ°ÂÃشƼ¤ËØÓ°Ïì¸Éϸ°û</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-18/doc-ifxefurt9354794.shtml">ÎÒÃǵĴóÄÔ¿Õ¼ä»á±»ÓÃÍêÂð£¿ÒÅÍüÒ²ÊÇÒ»ÖÖѧϰ</a></li> - -<li><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60863.html" target="_blank">ÏÖʵ°æ±äÐνð¸Õ£º»úÆ÷È˱äË«×ùÆû³µ½öÐ輸ÃëÖÓ(GIF)</a></li> - -<li><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60862.html" target="_blank">·ÇÖ޺Ϸ¨á÷ÁÔ²úÒµ£º´óÁ¿Ò°Éú¶¯Îï±»ÖƳɱ걾(×éͼ)</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/a/2015-06-18/doc-ifxefurq6638019.shtml">»³ÔÐĸöèÔâÃÀÓæÃñÆʸ¹ 34ֻСöèÓã²ÒËÀ¸¹ÖÐ(ͼ)</a></li><li><a target="_blank" href="http://tech.sina.com.cn/d/s/2015-06-18/doc-ifxefurs2576226.shtml">ÃÀÓ¾Ö¹ÙÔ±³ÆÈôÕæÓÐÍâÐÇÈËÓ¦ÒÑÖªÏþÈËÀà´æÔÚ(ͼ)</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/solarimpulse/live/abu_dhabi/">ÊÀ½çÌ«ÑôÄÜ·É»úÒòÌìÆøÔ­Òò±¸½µÈÕ±¾Ãû¹ÅÎÝ</a> <a target="_blank" href="http://solarimpulse.sina.com.cn/">¹ÙÍø</a></li> - -<li><a href="http://tech.sina.com.cn/blog/image/" target="_blank">ÃÀͼ</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_69f845650102w8qd.html?tj=tech">µûӼΪ±ÜÌìµÐαװ³É¶¾Éß</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_73f3af200102vohj.html?tj=tech">°ÄÖÞöùÓãͬÀàÏà²Ð</a></li> - - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod23 --> - <div class="blank-cont" style="height:16px"></div> - <!-- mod24 --> - <div class="uni-blk" tab-type="tab-wrap" style="z-index:1"> - <div class=""> - <div class="uni-blk-t mod24-t clearfix"> - <div class="mod24-menu clearfix"> - <span class="selected" tab-type="tab-nav" style="border-left:0px;width:56px;"><a href="http://games.sina.com.cn/" target="_blank">ÓÎÏ·</a></span> - <span tab-type="tab-nav" style="width:75px;"><a href="http://games.sina.com.cn/newgame/" target="_blank">ÐÂÍøÓÎ</a></span> - <span tab-type="tab-nav" style="width:75px;"><a href="http://ka.sina.com.cn/" target="_blank">ÐÂÊÖ¿¨</a></span> - <span tab-type="tab-nav" style="width:82px;"><a href="http://games.sina.com.cn/hd.shtml" target="_blank">Óн±»î¶¯</a></span> - <span tab-type="tab-nav" style="border-right:0px; width:66px;"><a href="http://www.97973.com/" target="_blank">ÊÖÓÎ</a></span> - </div> - </div> - <div class="uni-blk-b"> -<div class="uni-blk-bt clearfix" tab-type="tab-cont" data-sudaclick="blk_youxi_1" blkclick="auto_nav" blktitle="ÓÎÏ·"> -<!-- publish_helper name='ÓÎÏ·' p_id='30' t_id='108' d_id='2' --> -<a href="http://games.sina.com.cn/" target="_blank" class="uni-blk-pic"> <img src="http://i1.sinaimg.cn/home/2015/0618/U2456P30DT20150618114514.jpg" width="105" height="70" /> <span>ÃÀÍÈÅ®ÐÇ´úÑÔÓÎÏ·</span> </a> -<ul class="uni-blk-list01 list-a"> - -<li><a href="http://games.sina.com.cn/" target="_blank">ÔÙսȼÉÕ¾üÍŠħÊÞ6.2ÏÂÖÜËÄÉÏÏß</a></li> -<li><a href="http://games.sina.com.cn/y/n/2015-06-17/fxczqap4201308.shtml" target="_blank">¡¶Ïɽ£ÆæÏÀ´«¡·Ò»´úPC°æÒÆÖ²ÊÖ»ú</a></li> -<li><a href="http://www.97973.com/moxw/2015-06-18/ifxczyze9704479.shtml" target="_blank">¡¶»ð¾æÖ®¹â¡·Òƶ¯°æ½ØͼÊ×´ÎÆعâ</a></li> -<li><a href="http://games.sina.com.cn/g/g/2015-06-18/fxczyze9706967.shtml" target="_blank">Å©Ãñ¹¤³ÁÃÔÓÎÏ·»¨¹â»ýÐîÎÔ¹ì×Ôɱ</a></li> -</ul> - - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_5" blkclick="auto_nav" blktitle="ÐÂÍøÓÎ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÐÂÍøÓÎ' p_id='30' t_id='108' d_id='6' --> - <a href="http://games.sina.com.cn/newgame/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/Y8C--fxczqap4174218.jpg" width="105" height="70" /> -<span>ÉÏÖÜÊ×±¬ÐÂÓλعË</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://games.sina.com.cn/ol/n/2015-06-16/fxczqan0636608.shtml" target="_blank">΢Èí¹«²¼Ä£ÄâÏÖʵÍøÓÎ ¡¶ION¡·</a></li> -<li><a href="http://games.sina.com.cn/ol/n/2015-06-16/1608624682.shtml" target="_blank">ÂÝÐýèÐÔ¸ÐCOSÓ¢ÐÛÁªÃËŮӢÐÛ </a></li> -<li><a href="http://games.sina.com.cn/ng/wgujian/index.shtml" target="_blank">¹Å½£ÆæÌ·ÍøÂç°æÖäÒþÊÓƵÊ×Æعâ</a></li> -<li><a href="http://games.sina.com.cn/ol/n/2015-06-16/fxczqap4172157.shtml" target="_blank">¡¶È«Ö°´óʦ¡·Êײ⾫²ÊÊÓƵ¼¯½õ</a></li></ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_4" blkclick="auto_nav" blktitle="ÐÂÊÖ¿¨"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÐÂÊÖ¿¨' p_id='30' t_id='108' d_id='5' --> -<a href="http://ka.sina.com.cn/16532" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0612/U2457P30DT20150612174219.jpg" width="105" height="70" /> - - <span>¡¶ÌìÚÍ¡·Ê±×°Àñ°ü</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://ka.sina.com.cn/16470" target="_blank">¡¶Ä§Óò¡· ÆæÏëͯÀÖÐÂÊÖÏä</a> <a target="_blank" href="http://games.sina.com.cn/my/index.shtml">רÇø</a></li> - -<li><a href="http://ka.sina.com.cn/15015" target="_blank">¡¶ÎʵÀ¡· ¾öÕ½À¥ÂØÖÁ×ðÀñ°ü</a> <a target="_blank" href="http://games.sina.com.cn/o/z/askdao/">רÇø</a></li> - -<li><a href="http://ka.sina.com.cn/16571" target="_blank">¡¶²»´ò²»Ïàʶ¡·ºÀ»ªÀñ°ü</a> <a target="_blank" href="http://www.17g.com/union?link_id=182">רÇø</a></li> - -<li><a href="http://ka.sina.com.cn/16573" target="_blank">¡¶Ææ¼£MU¡·ÐÂÀ˶À¼ÒÀñ°ü</a> <a target="_blank" href="http://games.sina.com.cn/mu/index.shtml">רÇø</a></li></ul> - </textarea> - </div> - - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_3" blkclick="auto_nav" blktitle="Óн±»î¶¯"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='Óн±»î¶¯' p_id='30' t_id='108' d_id='4' --> -<a href="http://e.games.sina.com.cn/?proj=tianyu" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0616/U2456P30DT20150616122107.jpg" width="105" height="70" /> - - <span>ÍæÌìÚÍӮƻ¹ûÊÖ±í</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://e.games.sina.com.cn/?proj=bdbxs" target="_blank">²»´ò²»Ïàʶºì°ü¼¾ Éý¼¶ÁìÈ¡ºì°ü</a></li> - -<li><a href="http://e.games.sina.com.cn/?proj=moyu2015" target="_blank">¡¶Ä§Óò¡·¹«²â¿ªÆô ÍæÓÎÏ·Ëͺì°ü</a></li> - -<li><a href="http://e.games.sina.com.cn/?proj=qjmu" target="_blank">Í桶Ææ¼£MU¡·S9°æ±¾Ó®·áºñ½±Æ·</a></li> - -<li><a href="http://e.games.sina.com.cn/?proj=fbyx2015 " target="_blank">·ç±©Ó¢ÐÛ¹«²â ·¢Î¢²©Ó®Æ»¹ûÊÖ±í</a></li></ul> - </textarea> - </div> - - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_2" blkclick="auto_nav" blktitle="ÃÀÅ®COS"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='΢̳' p_id='30' t_id='108' d_id='3' --> -<a href="http://www.97973.com/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U2217P30DT20150617163149.jpg" width="105" height="70" /> - - <span>ÊÕ»ñÈÕµÇÒƶ¯Æ½Ì¨</span> - -</a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://www.97973.com/" target="_blank">¡¶Î´ÉÏËøµÄ·¿¼ä¡·ÑÇÖÞ°æÖ§³ÖÖÐÎÄ</a></li> - -<li><a href="http://www.97973.com/sjyj/2015-06-17/ifxczqap4199477.shtml" target="_blank">½Ò¶ÊÖ»úÓÎÏ·Éú̬ȦÄÚ²¿µÄºÚħ·¨</a></li> - -<li><a href="http://www.97973.com/2015-06-17/ifxczqar0987401.shtml" target="_blank">SE¹ÅĹÀöÓ°ÊÖÓΡ¶ÀÍÀ­:GO¡·ÁÁÏà</a></li> - -<li><a href="http://www.97973.com/moxw/2015-06-17/ifxczqap4202816.shtml" target="_blank">¡¶Íõ¹úÖ®ÐÄ:½â·ÅX¡·¹ÙÍøÒѾ­ÉÏÏß</a></li> - -</ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod24 --> - </div> - <div class="part-h-r"> - <!-- mod25 --> - <div class="uni-blk" id="SI_Order_H" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav" id="tech_mobi_tab"><a href="http://mobile.sina.com.cn/" target="_blank">ÊÖ»ú</a></span> - <span tab-type="tab-nav" id="tech_digi_tab"><a href="http://digi.sina.com.cn/" target="_blank">ÊýÂë</a></span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk" style="padding-right:6px;"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_5"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://shiqu.sina.com.cn/" target="_blank">ʶȤ</a></li> -<li><a href="http://tech.sina.com.cn/notebook/" target="_blank">±¾±¾</a></li> -<li><a href="http://tech.sina.com.cn/smart/" target="_blank">ÖÇÄܼҾÓ</a></li> -<li><a href="http://tech.sina.com.cn/down/" target="_blank">ÏÂÔØ</a></li> -<li><a href="http://tech.sina.com.cn/apple/" target="_blank">Æ»¹û»ã</a></li> - -<li id="SI_IP_MT_6"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_digi_1" blkclick="auto_nav" blktitle="ÊýÂë"> -<!-- publish_helper name='ÊýÂëÇø¿é' p_id='30' t_id='103' d_id='5' --> - <div class="uni-blk-bt clearfix"> -<a href="http://tech.sina.com.cn/zhongce/002.html" target="_blank" class="uni-blk-pic" border="0"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0616/U10175P30DT20150616105405.jpg" width="105" height="70" /><span>ÖÚ²â:ÊÖ»úÃâ·ÑÄÃ</span></a> -<ul class="uni-blk-list01 list-a"> - -<li><a href="http://tech.sina.com.cn/mobile/special/bestchoice20150615/" target="_blank">×îÍƼö:OPPO Find 7Çá×°°æ1999Ôª</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurs2575779.shtml" target="_blank">ѧÉú±Ø±¸»úÐÍ</a> - <a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxczyze9696633.shtml" target="_blank">Ö¸ÎÆʶ±ðÊÖ»úÍƼö</a> -</li> - -<li><a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurs2575562.shtml" target="_blank">´óÆÁÓéÀÖÊÖ»ú</a> - <a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurq6483408.shtml" target="_blank">³¬³¤Ðøº½ÊÖ»úÅ̵ã</a> -</li> - -<li><a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurt9352684.shtml" target="_blank">Ë«Ãæ²£Á§ÊÖ»ú</a> - <a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxczyze9695317.shtml" target="_blank">¸ßÏñËØÅÄÕÕÊÖ»ú»ã</a> -</li> - -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://tech.sina.com.cn/apple/" target="_blank">[Æ»¹û]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354574.shtml" target="_blank">iPhone±ØÐëÂô¸ß¼Û£¿</a> <a target="_blank" href="http://tech.sina.com.cn/it/2015-06-18/doc-ifxefurt9355899.shtml">Æ»¹ûϵͳÏÖÑÏÖØйÃÜ©¶´</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/tag/%E6%96%B0%E6%9C%BA%E6%9B%9D%E5%85%89" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9695986.shtml" target="_blank">Ò»¼ÓÊÖ»ú2¹Ù·½±¬ÁÏ</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurq6481350.shtml">ÈÙÒ«7±»Æؽ«ÓÃȫд¦ÀíÆ÷</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/tag/%E8%AF%84%E6%B5%8B%E8%A7%A3%E6%9E%90" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354298.shtml" target="_blank">ÈýÐÇNote 5»òÌáÇ°·¢²¼</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9696852.shtml">Win10ÊÖ»ú°æÔöµ¥ÊÖģʽ</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/tag/%E6%96%B0%E6%9C%BA%E6%9B%9D%E5%85%89" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354532.shtml" target="_blank">Ï´úiPhone»òÓÐõ¹å½ðÅäÉ«</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9697330.shtml">ŵ»ùÑÇÇ°CEO½«ÀëÖ°</a> -</li> - -<li><a href="http://slide.tech.sina.com.cn/mobile/" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurq6506081.shtml" target="_blank">Lumia940»òÅäÈý¿ÅÉÁ¹âµÆ</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354994.shtml">÷ÈÀ¶2»ñ¹¤ÐŲ¿ÈëÍø</a> -</li> - -<li><a href="http://tech.sina.com.cn/mobile/cesasia2015/" target="_blank">[ÍƼö]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9698349.shtml" target="_blank">ŵ»ùÑÇÊÖ»ú²»ÔÙ µ«Åµ»ùÑÇרÀûÎÞ´¦²»ÔÚ</a></li> - -<li><a href="http://slide.tech.sina.com.cn/mobile/" target="_blank">[ÐÂÎÅ]</a> - <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurs2577517.shtml">ÄäÃûÔ±¹¤±¬ÁÏ£º»ªÎªµÄÈ·ÔÚÔìNexusÊÖ»ú</a></li> - - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_shiqu_1" blkclick="auto_nav" blktitle="ʶȤ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ʶȤÇø¿é' p_id='30' t_id='103' d_id='13' --> - <div class="uni-blk-bt clearfix"> -<a href="http://shiqu.sina.com.cn/" target="_blank" class="uni-blk-pic "><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U4373P30DT20150618084716.jpg" width="105" height="70" /><span>¼üÅ̳µÉñÐÂ×°±¸</span></a> - -<a href="http://tech.sina.com.cn/q/life/2015-06-18/doc-ifxefurt9355014.shtml" target="_blank" class="uni-blk-pic shiqu-ml"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U4373P30DT20150618084734.jpg" width="105" height="70" /><span>Àָ߽á»éµ°¸â</span></a> - -<a href="http://tech.sina.com.cn/q/life/2015-06-18/doc-ifxefurq6513360.shtml" target="_blank" class="uni-blk-pic shiqu-ml"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U4373P30DT20150618084812.jpg" width="105" height="70" /><span>ÒøÐÓÌ«ÑôÄܳäµçÆ÷</span></a> - - </div> - <div class="blk-line shiqu-mt"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://shiqu.sina.com.cn/toy/">[ʶȤÍæÎï]</a> <a href="http://tech.sina.com.cn/q/toy/2015-06-18/doc-ifxczyze9698024.shtml" target="_blank">ÕâÊǸöÉñÆæµÄÉ豸£ºAumeoÒôÀÖ½ÃÕýÆ÷</a></li> - -<li><a target="_blank" href="http://shiqu.sina.com.cn/life/">[ʶȤÉú»î]</a> <a href="http://tech.sina.com.cn/q/life/2015-06-18/doc-ifxefurs2576980.shtml" target="_blank">´¿ÊÖ¹¤´òÔìÒþÐÎ×ÔÐгµ£ºÈËÈ⶯Á¦Õ½¶·»ú</a></li> - -<li> -<a href="http://tech.sina.com.cn/notebook/" target="_blank">[±¾±¾]</a> -<a href="http://tech.sina.com.cn/n/g/2015-06-18/doc-ifxefurs2577987.shtml" target="_blank">ÈÈÏú¼ÒÍ¥ÓéÀֱʼDZ¾ÍƼö</a> -<a href="http://tech.sina.com.cn/notebook/pad/2015-06-18/doc-ifxefurs2576601.shtml" target="_blank">Surface Pro 3½µ¼Û</a> - -</li> - -<li><a href="http://tech.sina.com.cn/pad/" target="_blank">[ƽ°å]</a> -<a href="http://tech.sina.com.cn/n/t/2015-06-18/doc-ifxefurq6524613.shtml" target="_blank">Èý´óÒƶ¯²Ù×÷ϵͳÖÕ¼«PK</a> -<a href="http://tech.sina.com.cn/n/k/2015-06-18/doc-ifxefurs2576967.shtml" target="_blank">MacBook±¾¸Ãû½Ó¿Ú</a> -</li> -<li><a href="http://tech.sina.com.cn/digital/" target="_blank">[Ïà»ú]</a> <a target="_blank" href="http://tech.sina.com.cn/digi/dc/s/2015-06-18/doc-ifxczyze9697999.shtml">618½µ¼Ûµ¥·´/΢µ¥Å̵ã</a> <a target="_blank" href="http://tech.sina.com.cn/digi/dc/q/2015-06-18/doc-ifxefurs2577629.shtml">²ËÄñÉý¼¶×¨ÒµÉãӰʦÐĵÃ</a></li> - -<li><a href="http://club.tech.sina.com.cn/" target="_blank">[ÉçÇø]</a> -<a href="http://club.tech.sina.com.cn/mobile/thread-11474874-1-1.html" target="_blank">´Á´©Áù´óÓ²¼þα֪ʶ</a> -<a href="http://club.tech.sina.com.cn/mobile/thread-11474884-1-1.html" target="_blank">iPhone 6sÉÏÊÐʱ¼ä»òÆعâ</a> -</li> - -<li> -<a href="http://tech.sina.com.cn/elec/" target="_blank">[¼Òµç]</a> -<a href="http://tech.sina.com.cn/e/x/2015-06-18/doc-ifxczyze9695938.shtml">PPTV¿¿ËÕÄþÔìµçÊÓÉú̬</a> <a target="_blank" href="http://tech.sina.com.cn/e/x/2015-06-18/doc-ifxefurt9355053.shtml">ר¼ÒÆÀ¼ÖԾͤÀ´Ç®Ì«ÈÝÒ× </a> -</li> - - </ul> - </textarea> - </div> - </div> - </div> - </div> - -<script> -/* ÊÖ»ú¡¢ÊýÂë°å¿éËæ»úĬÈϳÊÏÖ */ -jsLoader({ - name: 'shm', - callback: function() { - var selected = Math.random()>0.5?'tech_digi_tab':'tech_mobi_tab'; - SHM.app.tab.switchByEle(SHM.dom.byId(selected)); - } -}); -</script> - <!-- mod25 --> - <div class="blank-cont" style="height:16px"></div> - <!-- mod26 --> - <div class="uni-blk" tab-type="tab-wrap" style="z-index:1"> - <div class=""> - <div class="uni-blk-t mod24-t clearfix"> - <div class="mod24-menu clearfix"> - <span class="selected" tab-type="tab-nav" style="border-left:0px;width:70px;"><a href="http://app.sina.com.cn/?f=p_binfen&w=p_binfen" target="_blank">Ó¦ÓÃÖÐÐÄ</a></span> - <span tab-type="tab-nav" style="width:72px;"><a href="http://app.sina.com.cn/app_index.php?f=p_binfen&w=p_binfen" target="_blank">°²×¿Ó¦ÓÃ</a></span> - <span tab-type="tab-nav" style="width:72px;"><a href="http://app.sina.com.cn/game_index.php?f=p_binfen&w=p_binfen" target="_blank">°²×¿ÓÎÏ·</a></span> - <span tab-type="tab-nav" style="width:70px;"><a href="http://app.sina.com.cn/installs.php?f=p_binfen&w=p_binfen" target="_blank">×°»ú±Ø±¸</a></span> - <span style="border-right:0px;width:70px;" tab-type="tab-nav"><a href="http://app.sina.com.cn/?f=p_binfen&w=p_binfen" target="_blank">ÐÂÆ·ÉϼÜ</a></span> - - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> -<!-- publish_helper name='Ó¦ÓÃÖÐÐÄ' p_id='30' t_id='122' d_id='1' --> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" data-sudaclick="blk_apps_1" blkclick="auto_nav" blktitle="Ó¦ÓÃÖÐÐÄ"> - <a href="http://app.sina.com.cn/appdetail.php?appID=2349268&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/sms/images/sms_image/appstore/diandianxs.png" width="105" height="70" /> - - <span>²Ý´ÔÓ¢ÐÛÆëµÇ³¡</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349109&f=p_binfen&w=p_binfen" target="_blank">·ÉԽδÀ´´ó¶¼Ìì¼Ê£º·ÉÌ컬°å¸ßÊÖ</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349154&f=p_binfen&w=p_binfen" target="_blank">30¿éÁìÍÁµÈÄãÕ÷·þ£ºÅÑÂÒÎäÊ¿Ö®Õ½</a></li> - - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2350985&f=p_binfen&w=p_binfen" target="_blank">ÆæÃîµÄħ»ÃÖ®ÂãºÐ¡Ð¡Ä§ÊÞ´óÕ½Õù</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2351044&f=p_binfen&w=p_binfen" target="_blank">µãȼս¶·Áé»ê£º³¬ºÏÌåħÊõ»úÆ÷ÈË</a></li> - </ul> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_2" blkclick="auto_nav" blktitle="°²×¿Ó¦ÓÃ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='°²×¿Ó¦ÓÃ' p_id='30' t_id='122' d_id='2' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=623838&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/sms/images/sms_image/appstore/meiyou.png" width="105" height="70" /> - - <span>ÃÀèÖ´óÒÌÂèÉñÆ÷</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=110&f=p_binfen&w=p_binfen" target="_blank">[ѧϰ°ì¹«]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=84472&f=p_binfen&w=p_binfen" target="_blank">Á¼Ê¦ÒæÓÑ£ºº£´Ê´Êµä</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=101&f=p_binfen&w=p_binfen" target="_blank">[ϵͳ¹¤¾ß]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=117176&f=p_binfen&w=p_binfen" target="_blank">±£»¤ÄãÒþ˽£ºÓ¦ÓÃËø</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=112&f=p_binfen&w=p_binfen" target="_blank">[½ðÈÚÀí²Æ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=84623&f=p_binfen&w=p_binfen" target="_blank">Ͷ×ÊÕß³´¹É£ºÍ¬»¨Ë³</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=103&f=p_binfen&w=p_binfen" target="_blank">[ÈÕ³£Éú»î]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=1237478&f=p_binfen&w=p_binfen" target="_blank">ʵʱȥ¶¨Î»£º¸úƨ³æ</a></li> - </ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_3" blkclick="auto_nav" blktitle="°²×¿ÓÎÏ·"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='°²×¿ÓÎÏ·' p_id='30' t_id='122' d_id='3' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=2348486&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/sms/images/sms_image/appstore/daocaor.png" width="105" height="70" /> - - <span>ÂóÌïÊØÍûÕß</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=201&f=p_binfen&w=p_binfen" target="_blank">[ÒæÖÇÐÝÏÐ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2347482&f=p_binfen&w=p_binfen" target="_blank">]»¥¶¯Ñݱ䣺¹ÖÎï½ø»¯</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=204&f=p_binfen&w=p_binfen" target="_blank">[½ÇÉ«°çÑÝ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2349163&f=p_binfen&w=p_binfen" target="_blank">Ê·Ê«¾ÞÏ×£º³Ç±¤·ç±©</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=203&f=p_binfen&w=p_binfen" target="_blank">[ÌåÓý¾ºËÙ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2351045&f=p_binfen&w=p_binfen" target="_blank">ÉúËÀÖ®¼ä£º·è¿ñƯÒÆ</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=205&f=p_binfen&w=p_binfen" target="_blank">[·ÉÐÐÉä»÷]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2350509&f=p_binfen&w=p_binfen" target="_blank">ûÓÐÍË·£º³Ç¼ÊºäÕ¨</a></li> - </ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_4" blkclick="auto_nav" blktitle="×°»ú±Ø±¸"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='×°»ú±Ø±¸' p_id='30' t_id='122' d_id='4' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=1118624&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/sms/images/sms_image/appstore/baogongzi.png" width="105" height="70" /> - - <span>Öª¼ºÖª±Ë×÷Õ½Ö°³¡</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=113&f=p_binfen&w=p_binfen" target="_blank">[µØͼµ¼º½]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=84453&f=p_binfen&w=p_binfen" target="_blank">³öÐÐͨ£º¿­Á¢µÂµ¼º½</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=102&f=p_binfen&w=p_binfen" target="_blank">[Ö÷Ìâ±ÚÖ½]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=101351&f=p_binfen&w=p_binfen" target="_blank">Ʒζ¸Ð¶¯£ºÆæ˼±ÚÖ½</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=107&f=p_binfen&w=p_binfen" target="_blank">[ÅÄÉãÃÀ»¯]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=118425&f=p_binfen&w=p_binfen" target="_blank">¿°±ÈÓ°Â¥£ºÌØЧÏà»ú</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=108&f=p_binfen&w=p_binfen" target="_blank">[ÐÂÎÅ×ÊѶ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=127035&f=p_binfen&w=p_binfen" target="_blank">ȨÍþ·¢²¼£ºÈËÃñÈÕ±¨</a></li> - </ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_5" blkclick="auto_nav" blktitle="ÐÂÆ·ÉϼÜ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÐÂÆ·ÉϼÜ' p_id='30' t_id='122' d_id='5' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=2350440&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/sms/images/sms_image/appstore/quantingzdy.png" width="105" height="70" /> - - <span>º£µ×ÊÀ½ç´óðÏÕ</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2348348&f=p_binfen&w=p_binfen" target="_blank">½¨Ôì˽È˺À»ª´óÓÎͧ£º¿ìÀ´Ôì´¬°É</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2350477&f=p_binfen&w=p_binfen" target="_blank">¶À×ÔÒ»¸öÈ˽øÐÐá÷ÁÔ£º¾Ñ»÷ÊÖÁÔ¹</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349239&f=p_binfen&w=p_binfen" target="_blank">ÏòµÐÈË·¢³ö³¬¼¶Õ½¶·£ºÃȾü·ÉÐжÓ</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349139&f=p_binfen&w=p_binfen" target="_blank">ÏÖ´ú±øÆ÷µÄ¿Ö²À¶Ô¾ö£ºCS·´¿Ö¾«Ó¢</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod26 --> - </div> - </div> - <!-- part-h end --> - - <div class="blank-cont" style="height:12px"></div> - <!-- part-j begin --> - - <div class="part-j clearfix"> - <div class="part-j-l"> - <!-- mod27 --> - <div class="mod-27 mod-02"> - <div class="tit02"> - <h3><a href="http://history.sina.com.cn/photo/" target="_blank">Àúʷͼ¿â</a></h3> - </div> - <div class="mod27-cont" data-sudaclick="blk_history_tk" blkclick="auto_nav" blktitle="Àúʷͼ¿â" style="padding:10px;"> - <div class="history-pics-wrap clearfix"> - <div class="history-pics-arrleft-wrap"> - <a href="javascript:;" class="history-pics-arrleft" id="SI_Scroll_History_Arr_L"></a> - </div> - <div class="history-pics-frame clearfix" id="SI_Scroll_History_Wrap" style="height:108px; overflow:hidden;"> -<!-- publish_helper name='Àúʷͼ¿â' p_id='30' t_id='121' d_id='8' --> -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/y/slide_61_40602_44368.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U3093P30DT20150617105708.jpg" width="180" height="87" /> -<span>ÀÏÕÕƬÖеIJпáºÍ±¯Çé˲¼ä</span> -</a></div> - -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/w/slide_61_40602_53152.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U3093P30DT20150618091721.jpg" width="180" height="87" /> -<span>1955ÄêµÄÏã¸Û°Ù̬</span> -</a></div> - -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/y/slide_61_40602_44454.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U3093P30DT20150617105803.jpg" width="180" height="87" /> -<span>Äãû¼û¹ýµÄÓ¡¶ÈÀÏÕÕƬ</span> -</a></div> - -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/y/slide_61_40602_44443.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U3093P30DT20150617105635.jpg" width="180" height="87" /> -<span>Ç峯»Ê×åµÄÕæʵ³¤Ïà</span> -</a></div> - - </div> - <div class="history-pics-arrright-wrap"> - <a href="javascript:;" class="history-pics-arrright" id="SI_Scroll_History_Arr_R"></a> - </div> - </div> - </div> - </div> - <script type="text/javascript"> - jsLoader({ - name : 'shm', - callback : function() { - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "SI_Scroll_History_Wrap"; //ÄÚÈÝÈÝÆ÷ID - focusScroll.frameWidth = 180;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 180; //·­Ò³¿í¶È - focusScroll.upright = false; //´¹Ö±¹ö¶¯ - focusScroll.speed = 15; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 30; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - - SHM.dom.byId('SI_Scroll_History_Arr_L').onmousedown = function(){ - focusScroll.pre(); - return false; - } - SHM.dom.byId('SI_Scroll_History_Arr_R').onmousedown = function(){ - focusScroll.next(); - return false; - } - } - }); - </script> - <!-- mod27 --> - - <div class="blank-cont" style="height:20px;"></div> - <!-- mod28 --> - <div class="mod-28"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 1ÂÖ²¥°´Å¥05¹ã¸æ begin --> -<div id="ad_46012" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046012"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 1ÂÖ²¥°´Å¥05¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod28 --> - </div> - <div class="part-j-m"> - <!-- mod29 --> - <div class="uni-blk" id="SI_Order_I" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://history.sina.com.cn/" target="_blank">ÀúÊ·</a></span> - <span tab-type="tab-nav"><a href="http://cul.sina.com.cn/" target="_blank">ÎÄ»¯</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden" data-sudaclick="blk_history_menu"> -<li id="SI_IP_MT_8"></li> -<li><a href="http://history.sina.com.cn/digest/" target="_blank">Ê·º£¹³³Á</a></li> -<li><a href="http://history.sina.com.cn/photo/" target="_blank">ÀúʷͼƬ</a></li> -<li><a href="http://history.sina.com.cn/zt/" target="_blank">²ß»®</a></li> -<li><a href="http://history.sina.com.cn/zl/" target="_blank">רÀ¸</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_history_1" blkclick="auto_nav" blktitle="ÀúÊ·"> -<!-- publish_helper name='ÀúÊ·Çø¿é' p_id='30' t_id='121' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://history.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11647P30DT20150618091526.jpg" width="105" height="70" /> - - <span>³¯ÏʽðÈÕ³Éʱ´ú</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://history.sina.com.cn/" target="_blank">¿¹Õ½³õÆÚÖÐÈÕË«·½±øÁ¦¶Ô±È</a></li> - -<li><a href="http://blog.sina.com.cn/lm/history/" target="_blank">½¨¹úÖ®³õԪ˧Ҷ½£Ó¢ÎªºÎƵƵÓö´Ì</a></li> - -<li><a href="http://slide.history.sina.com.cn/y/slide_61_40602_46683.html" target="_blank">½â·ÅÇ°µÄÉϺ££º¶¯µ´Óë¾­¼Ã±ÀÀ£</a></li> - -<li><a href="http://history.sina.com.cn/zl/" target="_blank">Ï£ÂÞ¶àµÂΪºÎÕ¾ÔÚ²¨Ë¹µÄÁ¢³¡ÉÏ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://history.sina.com.cn/digest/">Î人¿¹Õ½£º¹ú¹²µÚ¶þ´ÎºÏ×÷»Æ½ðÄê´ú</a> <a target="_blank" href="http://history.sina.com.cn/bk/jgcqs/2015-06-18/0946121564.shtml">´÷¸ßÀÖ¼Ò×åÖйúÔµ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_3f5e61240102w8j0.html?tj=1">Ê׸öÍâ¹úÌ«¼àÖÂÔª³¯ÃðÍö</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_4ac5b19f0102vp7e.html?tj=1">Ë­×îÔç·¢ÏÖëÔó¶«ÓÐÐÛ²ÅΰÂÔ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_4b8bd1450102vljx.html?tj=1">Öй²µÚÒ»¼ÒÍ¥µÄ´ÈÉÆÓ빫Òæ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_a1929b370102vw32.html?tj=1">½¯½éʯÃØÃÜѵÁ·Ò»ÅúµÂеʦ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_e39346e40102vqbv.html?tj=1">ÖìԪ谺ÍÃ÷½ÌÊÇʲô¹Øϵ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_7e84ef460102vyih.html?tj=1">²ÜκÃû½«ÕÅàAÊDz»ÊÇËÀÓÚ·ÇÃü </a></li><li><a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-18/1016121572.shtml">ÀäÕ½Î÷µÂÏòÃÀӢתÒÆǧ¶Ö»Æ½ð</a> <a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-18/0952121566.shtml">¹Å°Íµ¼µ¯Î£»úÖеĴ«ÉùͲ</a></li><li><a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-17/1705121533.shtml">ƽÐ͹ذË·¾ü°ÑµÐ¾ü·Ö¸îÊý¶Î</a> <a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-17/1655121531.shtml">Ǭ¡ÉÝ»ª¶ËÎç°ÚǧÓàôÕ×Ó</a></li><li><a href="http://history.sina.com.cn/bk/jds/2015-06-17/1140121518.shtml" target="_blank">Ó¢¹úÁ½´ÎÈëÇÖÎ÷²Ø¶Ô²Ø¾ü´óÍÀɱ</a> <a target="_blank" href="http://history.sina.com.cn/bk/kzs/2015-06-17/1137121514.shtml">¹úÄÑ֮Ͻ¯½éʯµÄ»ú»á</a></li><li><a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-17/1117121512.shtml"> Ó¢°¢ÂíµºÖ®Õ½£º±¾¿É±ÜÃâµÄÕ½Õù</a> <a target="_blank" href="http://history.sina.com.cn/bk/gds/2015-06-18/1119121576.shtml">¹Å´úÓéÀÖȦµÄ»Æ½ðʱ´ú</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_cul_1" blkclick="auto_nav" blktitle="ÎÄ»¯"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÎÄ»¯Çø¿é' p_id='30' t_id='121' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/lm/history/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0611/U10606P30DT20150611094610.jpg" width="105" height="70" /> - - <span>¾ÉÅ·ÖÞÊøÑüÃÀÈË</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://cul.history.sina.com.cn/zl/" target="_blank">Âþ»°Â³Ñ¸£ºÏÖ´úÖйú×îÍ´¿àµÄÁé»ê</a></li> - -<li><a href="http://cul.history.sina.com.cn/zl/redian/2015-03-31/17321148.shtml" target="_blank">ÕŹúÈÙ£¬ÈËÉúûÓÐÄãÕæµÄ»á²»Í¬</a></li> - -<li><a href="http://cul.history.sina.com.cn/zl/redian/2015-03-11/16201138.shtml" target="_blank">ÀîÒøºÓ£ºÅ®ÈË£¬²»ÊÇÒ»ÖÖÐÔ±ð</a></li> - -<li><a href="http://cul.history.sina.com.cn/zl/redian/2015-03-25/09371146.shtml" target="_blank">ÎÒÃÇ»¹ÄÜ×øÁ®¼Ûº½¿Õ¹«Ë¾Âð£¿</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://history.sina.com.cn/bk/mqs/2015-06-11/1016121189.shtml">´óº½º£Ê±´ú£ºµÛ¹úÐËË¥ËõÓ°</a> <a target="_blank" href="http://history.sina.com.cn/bk/jds/2015-06-11/1046121192.shtml">´ÈìûÊÕÀñÇå³õ¹æ¾Ø´Ó´ËʧЧ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_c5026db80102vhi2.html?tj=1">¹²ºÍ¹úΨһһ´Î³¬¹æ¸ñÔáÀñ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_3f5e61240102w4g1.html?tj=1">µ±ÄêÃɹÅÈËΪºÎûÕ÷·þÈÕ±¾</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_7807f9150102vp55.html?tj=1">Ç峯ÐÂÄï³ö¼ÞÌØд(×éͼ) </a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_c4f2b62a0102vdvr.html?tj=1">ÀúÊ·ÉÏ×îÄÜ¡°×°¡±µÄËÄ´óÌì²Å</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_50d4ea0e0102ebyp.html?tj=1">ÐÂËľüÅ®Ìع¤ÊæÈü</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_4496894d0102vo8v.html?tj=1">¹Å´úÎ书ÅÅÐÐ×îÇ¿ÊÇ¡¶¿û»¨±¦µä¡·</a></li><li><a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-10/1547121138.shtml">¹ÅÈËÑϽû·ÉÏÂÒµ¹À¬»øÎ¥ÕßÑϳÍ</a> <a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-11/0940121186.shtml">ÄÃÆÆÂØÍ··¢ÓëËÀÒòÖ®ÃÕ</a></li><li><a target="_blank" href="http://history.sina.com.cn/bk/jds/2015-06-12/0910121237.shtml">»ðÉÕÔ²Ã÷Ô°£ºÒ»¸öÍõ³¯µÄÌ®Ëú</a> <a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-11/1521121203.shtml">¶­´æÈðÄêÓ×ʱ»úÁ鵨´ó</a></li><li><a href="http://history.sina.com.cn/bk/gds/2015-06-12/0928121239.shtml" target="_blank">ÃÉÔª£ºÒ»¸öÊÀ½çÐÔµÄÂí°°µÛ¹ú</a> <a target="_blank" href="http://history.sina.com.cn/bk/gds/2015-05-05/0927119644.shtml">Áõ°îƽÃñ¼ÒÊÀÓë³öÉúÉñ»°</a></li><li><a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-11/1540121204.shtml">ÓîÎÄÌ©´´ÐÂÖÆÒÖÖÆÌ°¸¯</a> <a target="_blank" href="http://history.sina.com.cn/bk/jds/2015-04-30/0931119506.shtml">°ÙÈÕµøå´£ºÎìÐç±ä·¨µÄÇ°Òòºó¹û</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod29 --> - </div> - <div class="part-j-r"> - <!-- mod30 --> - <div class="uni-blk" id="SI_Order_J" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://mil.news.sina.com.cn/" target="_blank">¾üÊÂ</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://slide.mil.news.sina.com.cn/" target="_blank">¾üͼ</a></li> -<li><a href="http://mil.news.sina.com.cn/jssd/" target="_blank">Éî¶È</a></li> -<li><a href="http://mil.news.sina.com.cn/dgby/" target="_blank">´ó¹ú²©ÞÄ</a></li> -<li><a href="http://mil.news.sina.com.cn/jshm/" target="_blank">¾üÊ·</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_mil_1" blkclick="auto_nav" blktitle="¾üÊÂ"> -<!-- publish_helper name='¾üÊÂÇø¿é' p_id='30' t_id='107' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://slide.mil.news.sina.com.cn/k/slide_8_442_36356.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U10553P30DT20150618105342.jpg" width="105" height="70" /> - - <span>ÎÚ¿ËÀ¼°æÔË20£¿</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://mil.news.sina.com.cn/" target="_blank">ÈÕý³ÆÖйúºä6K¿É´ÓÈÕ±¾ÄÏ·½¹¥»÷</a></li> - -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0852833403.html" target="_blank">Öйúº£¾üҪץÅܵ½¼ÒÃÅ¿ÚµÄÃÀDZͧ</a></li> -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0715833379.html" target="_blank">Èո߹ٳÆÖйú½¨ÉèÄϺ£µº½¸Ã»Ö÷Ȩ</a></li> -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0844833393.html" target="_blank">·ÆÂɱöäÖȾ±»Á½°¶ÖйúÈËÒ»ÆðÆÛ¸º</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0828833390.html" target="_blank">ÈÕ³ÆÖйúµ¼µ¯¿É¶Ô¸¶Èնᵺ²¿¶Ó</a> <a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0815833386.html">¼ÙÏëµöÓ㵺¹¥·ÀÕ½</a></li><li><a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0849833409.html">°ÍÌú·ÉÐÐÔ±³ÆèÉÁúÕ½»ú°ô¼«ÁË</a> <a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0923833411.html">Ãåµé»ò¹ºÂòèÉÁú</a></li><li><a href="http://mil.news.sina.com.cn/2015-06-18/0841833392.html" target="_blank">ÃÀ¹ú¾Ü¾øÖйúÌ«¿ÕºÏ×÷Ì«¹ÌÖ´ ÖÐÃÀˮƽ²î50¶àÄê</a></li><li><a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0804833384.html">¶íý³ÆÖйú²»×¼±¸ÔÚÄϺ£Èò½ ÃÀ»ò¸üƵ·±Õì²ì</a></li><li><a target="_blank" href="http://mil.news.sina.com.cn/jssd/" class="linkRed">Èȵã½âÎö</a>|<a target="_blank" href="http://mil.news.sina.com.cn/jssd/">Ô½ÄϺ£¿Õ¾ü¶ÔÄϺ£ÓкÎÍþв ËÕ27½Ø»÷Î÷ɳ</a></li><li><a href="http://roll.mil.news.sina.com.cn/photo_hz/photo_hdphoto/index.shtml" target="_blank">×éͼ</a>£º<a target="_blank" href="http://slide.mil.news.sina.com.cn/k/slide_8_442_36356.html">ÎÚ¿ËÀ¼°²70ÔËÊä»ú»»×°ÎÐÉȶ¯Á¦±äÉíÕ½ÂÔÔËÊä»ú</a></li><li><a href="http://roll.mil.news.sina.com.cn/photo_hz/photo_hdphoto/index.shtml.shtml" target="_blank">×éͼ</a>£º<a href="http://slide.mil.news.sina.com.cn/l/slide_8_38692_36357.html" target="_blank">Öйú¾ü¹¤ÍƳöпîÍâóÐÍ97ʽ²½Ç¹ ÒÑÈ¡ÏûÌá°Ñ</a></li><li><a href="http://roll.mil.news.sina.com.cn/blog/js-jsrd/index.shtml" target="_blank">×éͼ</a>£º<a href="http://slide.mil.news.sina.com.cn/l/slide_8_646_36358.html" target="_blank">ÃÀ¹ú¹«Ë¾ÍƳöºÀ»ª°æÔ½Ò°Õ½³µ ÇëÀ´ÃÀÅ®°ïÊÛÂô</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod30 --> - </div> - </div> - <!-- part-j end --> - <div class="blank-cont" style="height:20px"></div> - <!-- npart-a begin --> - <div class="npart-a"> - -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸03¹ã¸æ begin --> -<div id="ad_05494" class="mb25"><ins class="sinaads" data-ad-pdps="PDPS000000005494"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸03¹ã¸æ end --> -<!--_SINA_ADS_END_--> - - </div> - <!-- npart-a end --> - - <!-- part-k begin --> - - <div class="part-k clearfix"> - -<script> - if ("°²»Õ" === remote_ip_info.province) { - document.write([ - '<div class="part-k-l">', - '<div class="mod-13 mod-02">', - '<div class="tit02 clearfix">', - '<h3>', - '<ins class="sinaads" data-ad-pdps="PDPS000000025252"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</', 'script>', - '</h3>', - '</div>', - '</div>', - '<ins class="sinaads" data-ad-pdps="3C1ABA5504C1"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</', 'script>', - '</div>' - ].join('')); - } else { - document.write([ - '<div class="part-k-l">', - '<div class="mod-13 mod-02">', - '<div class="tit02 clearfix">', - '<h3>', - '<ins class="sinaads" data-ad-pdps="PDPS000000025252"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</','script>', - '</h3>', - '</div>', - '<div class="mod13-cont" style="padding-top:5px; padding-bottom:5px;">', - '<ul class="list-b" id="gina_res_show1347">', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046014"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046015"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046016"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046017"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046018"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '</ul>', - '</div>', - '</div>', - '<div class="blank-cont" style="height:15px"></div>', - '<div class="mod-32" id="gina_res_show1348">', - '<ins class="sinaads" data-ad-pdps="PDPS000000046019"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</' , 'script>', - '</div>', - '</div>' - ].join('')); - } -</script> - - <div class="part-k-m"> - <!-- mod33 --> - <div class="uni-blk" id="SI_Order_K" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://news.sina.com.cn/society/" target="_blank">Éç»á</a></span> - <span tab-type="tab-nav"><a href="http://gongyi.sina.com.cn/" target="_blank">¹«Òæ</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_7"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_society_1" blkclick="auto_nav" blktitle="Éç»á"> -<!-- publish_helper name='Éç»áÇø¿é' p_id='30' t_id='97' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://news.sina.com.cn/society/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150618/WpYj-fxefurs2578053.jpg" width="105" height="70" /> - - <span>Å®×ÓѧԺ±ÏÒµÕÕ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://news.sina.com.cn/society/" target="_blank">¸»½ãй¾À²øÕßÐÐ×Ù Æä×·ÇóÕßɱÈË</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/081731964210.shtml">º«¹ú¶ùͯ²»³ÔÅݲËÔâÀÏʦ¶¾´ò</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/023031962383.shtml">Ãñ¾¯ÓëÖƶ¾Ê¦ºÏ×÷Éú²ú°Ù¹«½ï±ù¶¾</a></li> - -<li><a href="http://news.sina.com.cn/s/2015-06-18/022431962374.shtml" target="_blank">ÄÐ×ÓÓë14ÃûÅ®´óѧÉúÍøÁµÆ­²ÆÆ­É«</a></li> - -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://news.sina.com.cn/s/p/2015-06-18/030031962605.shtml">ºóÂèÏÓŮͯ³Ô·¹ÂýÈÃÆäײǽ(ͼ)</a> <a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/081131964167.shtml">Å®×Óδ»éÏÈÔÐɱٶù</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/p/2015-06-18/032231962674.shtml">ÄÐ×Ó±»½¦Ò»ÉíÄà ±ÆÍ£½Î³µÒªÇó˾»úµÀǸ(ͼ)</a></li> - -<li><a href="http://news.sina.com.cn/s/2015-06-18/050031962820.shtml" target="_blank">³µÖ÷Ç¿Ðпª×ßÔâ½»¾¯²é¿Û³µÁ¾ ±»ÅÐÇÀ½Ù»ñ»ºÐÌ</a></li> - -<li><a href="http://news.sina.com.cn/s/2015-06-18/050731962857.shtml" target="_blank">Õã½­º£µº»Ä´åÍðÈçͯ»°ÊÀ½ç</a> <a href="http://news.sina.com.cn/s/2015-06-18/080931964162.shtml" target="_blank">ÂÉʦ΢²©ÎêÈè·¨¹Ù±»·£3Íò</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/053931963195.shtml">Àϸ¾Õù³è´òÉËÈýÊ®¶àËêСÇéÈËÏàºÃ</a> <a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/005931962235.shtml">Å®×ӳƴóÄÔ±»ÈË¿ØÖÆ</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-17/233031962105.shtml">ÄÐ×Ӿƺó¸øÁ÷ÀËÀÏÈËÂòʳÎï Ôâ¾Ü¾øÉȶԷ½¶ú¹â</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/p/2015-06-18/044531962817.shtml">·ŭ˾»ú¶à´Î³¬³µÎ´¹û ±ÆÍ£¶Ô·½ºó½Åõß³µÃÅ(ͼ)</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/015831962308.shtml">ÕÉ·ò¸°Ì©¹úÂÃÓÎÄçÍö ÆÞ×ÓÆðËßÂÃÐÐÉçË÷Åâ°ÙÍò</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_gongyi_1" blkclick="auto_nav" blktitle="¹«Òæ"> -<textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¹«ÒæÇø¿é' p_id='30' t_id='126' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://gongyi.sina.com.cn" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0616/U7063P30DT20150616103412.jpg" width="105" height="70" /> - - <span>¹Ø°®µáÎ÷¿¹Õ½Àϱø</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://gongyi.sina.com.cn/" target="_blank">¹«°ìÑøÀÏÔº²»ÔÙ½ÓÊշDZ£Õ϶ÔÏó</a></li> - -<li><a href="http://gongyi.sina.com.cn/gyzx/2015-06-17/101352937.html" target="_blank">12ËêŮͯͶ¶¾°¸ÏÆ¿ªÉç»áÀ£Ññ</a></li> - -<li><a href="http://gongyi.sina.com.cn/gyzx/2015-06-17/101352938.html" target="_blank">Ê×½ì·Ç¹«Ä¼ÂÛ̳̽ÌÖ¹«Òæг£Ì¬</a></li> - -<li><a href="http://gongyi.sina.com.cn/weibo.com/p/1008083ff5b51b3d66a706c0e3e4072b473f2d" target="_blank">Ò»ÆðÄý¾Û#ÕýÄÜÁ¿# ´«µÝ#ÕýÄÜÁ¿#</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-16/091252926.html">¹Ø×¢Éú´æ»·¾³£º¾©½ò¼½´óÆøÖÎÎÛÖг¤Æڹ滮Æô¶¯±àÖÆ</a></li><li><a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-16/092852929.html">ÎÒ¹ú½«°Ñ·ûºÏÌõ¼þµÄÉç»á°ìÒ½ÁÆ»ú¹¹ÄÉÈëÒ½±£¶¨µã·¶Î§</a></li><li><a href="http://gongyi.sina.com.cn/gyzx/ngo.html" target="_blank">µ÷²é</a>| <a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-12/110052911.html">Òæµ÷²é£º2014ÄêÉç»á¾èÔù604.4ÒÚÓÐÄãµÄÒ»·ÝÂð£¿</a></li><li><a href="http://gongyi.sina.com.cn/zhuantilist.html" target="_blank">´ÈÉÆ</a>| <a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-02/103352788.html">2015º£Ï¿Á½°¶ô߸۰ĴÈÉÆÂÛ̳ÔŲ́±±³É¹¦¾Ù°ì</a></li><li><a href="http://weibo.com/gongyi" target="_blank">΢²©</a>| -<a target="_blank" href="http://weibo.com/p/10080885f06b8fa1f4455d23b8069efe0d46d0">Ò»Æð°ïÖúº¢×ÓÃÇ#ͯԸ³ÉÕæ# »ñµÃ¹Ø°®µÄȨÀû</a></li><li><a href="http://gongyi.sina.com.cn/zhuantilist.html" target="_blank">רÌâ</a>| <a target="_blank" href="http://gongyi.sina.com.cn/z/2015shijiexueyoubingri/index.shtml">¡°ÊÀ½çѪÓѲ¡ÈÕ¡±»½Æð¹«ÖÚ¶ÔѪÓѲ¡µÄÕýÈ·ÈÏÖª</a></li><li><a href="http://yangfanbook.sina.com.cn/" target="_blank">Ñï·«</a>| -<a target="_blank" href="http://yangfanbook.sina.com.cn/news/1231">ºþ±±Àû´¨´åС»Ø·Ã¼Ç</a> <a target="_blank" href="http://weibo.com/1274469185/CmG7f3Juu">ÔĶÁ¸øͬѧ´øÀ´µÄ±ä»¯</a></li> -<li><a href="http://green.sina.com.cn/" target="_blank">»·±£</a>| <a target="_blank" href="http://slide.news.sina.com.cn/green/slide_1_28436_85557.html#p=1">ÓñÁÖ¹···×ÓÖµ簮¹·Õß ×¼±¸¹·µÈÄãÀ´Âò£¨Í¼£©</a></li> - </ul> -</textarea> - </div> - - </div> - </div> - </div> - <!-- mod33 --> - </div> - <div class="part-k-r"> - <!-- mod34 --> - <div class="uni-blk" id="SI_Order_L" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://games.sina.com.cn/" target="_blank">ÓÎÏ·</a></span> - <span tab-type="tab-nav"><a href="http://kan.sina.com.cn/" target="_blank">¿´ÓÎÏ·</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://games.sina.com.cn/vg/" target="_blank">µçÍæ</a></li> -<li><a href="http://ka.sina.com.cn/" target="_blank">ÐÂÊÖ¿¨</a></li> -<li><a href="http://kan.sina.com.cn/" target="_blank">¿´ÓÎÏ·</a></li> -<li><a href="http://gameapi.g.sina.com.cn/statiApi.php?action=doRedirect&label=sinaMainGameModem" target="_blank">App</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_games_1" blkclick="auto_nav" blktitle="ÓÎÏ·"> -<!-- publish_helper name='ÓÎÏ·Çø¿é' p_id='30' t_id='108' d_id='9' --> - <div class="uni-blk-bt clearfix"> -<a href="http://games.sina.com.cn/" target="_blank" class="uni-blk-pic"> <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U2456P30DT20150617153135.jpg" width="105" height="70" /> <span>ÓÎÏ·ÄÛÄ£ÖúÕóÊÖÓÎ</span> </a> -<ul class="uni-blk-list01 list-a"> - -<li><a href="http://games.sina.com.cn/" target="_blank">ÓÎÏ·µÄÊ¢Ñç E3³öÕ¹¾«²Ê´ó×÷Å̵ã</a></li> -<li><a href="http://games.sina.com.cn/ol/n/2015-06-17/fxczqap4207784.shtml" target="_blank">·ÅËÁÒ»ÏÄ£¡2015ÊîÆÚ±ØÍæÍøÓÎÍƼö</a></li> -<li><a href="http://games.sina.com.cn/y/n/2015-06-17/fxczqar0988039.shtml" target="_blank">ÈÕ±¾ÓÎÏ·´ÓÒµÕßÏÖ×´£º¸ßн¿¿¼Ó°à</a></li> -<li><a href="http://games.sina.com.cn/o/z/wow/2015-06-17/fxczqar0984639.shtml" target="_blank">ħÊÞ6.2µØÓü»ð±¤ÀÝʱ¼ä±íÒѹ«²¼</a></li> -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://games.sina.com.cn/o/z/hos/2015-06-17/1252624799.shtml" target="_blank">·ç±©Ó¢ÐÛÓÀºãÖ®Õ½E3Ðû´«Æ¬</a> <a target="_blank" href="http://games.sina.com.cn/j/n/2015-06-17/fxczqap4208661.shtml">Å̵ãÊ®´óÓÉС˵¸Ä±àµÄÓÎÏ·</a></li> - -<li><a target="_blank" href="http://games.sina.com.cn/ol/n/2015-06-17/fxczyze9668079.shtml">ÈýÌåµçÓ°°æµÚÒ»²¿ÅÄÉãÍê±Ï</a> <a target="_blank" href="http://www.97973.com/sjyj/2015-06-17/ifxczqar0986087.shtml">¡¶º£ÔôÍõ¡·³ÉÈ«ÇòµÚÒ»Âþ»­</a></li> - -<li><a href="http://games.sina.com.cn/g/p/2015-06-17/fxczqap4211214.shtml" target="_blank">ÿÈÕ‡åͼ£ºÈËÉú³äÂúÁ˾ªÏ²</a> <a href="http://games.sina.com.cn/o/z/wow/2015-06-17/fxczqan1598533.shtml" target="_blank">ħÊÞµÂÀ­ÅµÈ«Èü¼¾½±Àø×øÆï</a></li> - -<li><a href="http://ka.sina.com.cn/" target="_blank">·¢¿¨</a>| -<a href="http://ka.sina.com.cn/15015" target="_blank">ÎʵÀÖÁ×ð´óÀñ°ü</a> -<a href="http://ka.sina.com.cn/16532" target="_blank">ÌìÚÍʱװÀñ°ü</a> <a href="http://ka.sina.com.cn/16573" target="_blank">Ææ¼£MU¶À¼ÒÀñ°ü</a></li> - -<li><a href="http://games.sina.com.cn/newgame/" target="_blank">ÐÂÓÎ</a>| <a href="http://games.sina.com.cn/ol/n/2015-06-17/fxczyze9663433.shtml" target="_blank">ʹÃüÕÙ»½OLа汾ÉÏÏß</a> <a href="http://games.sina.com.cn/ol/n/dlwyxw/2015-06-17/fxczqap4199059.shtml" target="_blank">ÂåÆæÓ¢ÐÛ´«BOSS÷¶ûµÇ³¡</a></li> - -<li><a href="http://www.97973.com/" target="_blank">ÊÖÓÎ</a>| <a href="http://www.97973.com/moxw/2015-06-17/ifxczqap4202816.shtml" target="_blank">Íõ¹úÖ®ÐÄÊÖÓιÙÍøÉÏÏß</a> <a href="http://www.97973.com/moxw/2015-06-17/ifxczqap4210819.shtml" target="_blank">δÉÏËøµÄ·¿¼ä·¢²¼ÖÐÎÄ°æ</a></li> - -<li><a href="http://games.sina.com.cn/gamer" target="_blank">ȤÎÅ</a>| <a target="_blank" href="http://games.sina.com.cn/g/g/2015-06-17/fxczqap4209819.shtml">Íù½ìE3µÄÃÀÅ®SG´óÅ̵ã</a> <a href="http://games.sina.com.cn/y/n/2015-06-17/fxczqar0988039.shtml" target="_blank">ÈÕ±¾ÓÎÏ·´ÓÒµÕßÊÕÈëÏÖ×´</a></li> - -<li><a href="http://zq.games.sina.com.cn/" target="_blank">רÇø</a>| <a href="http://games.sina.com.cn/o/z/dota2/2015-06-17/1042624754.shtml" target="_blank">DOTA2×Ô¶¨ÒåµØͼ¼´½«ÉÏÏß</a> <a target="_blank" href="http://games.sina.com.cn/o/z/dota2/2015-06-17/1015624737.shtml">µç¾º¾ãÀÖ²¿¹æ·¶¹«²¼</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_games_2" blkclick="auto_nav" blktitle="¿´ÓÎÏ·"> -<textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¿´ÓÎÏ·Çø¿é' p_id='30' t_id='108' d_id='7' --> - <div class="uni-blk-bt clearfix"> -<a href="http://kan.sina.com.cn/akbk" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U2456P30DT20150617143510.jpg" width="105" height="70" /> - - <span>Å®º¢ÃÇϲ»¶µÄÓÎÏ·</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://kan.sina.com.cn/u/5104400319/3476750" target="_blank">¡¶·½ÖÛ:Éú´æ½ø»¯¡·µÄ¿ÖÁúËÇÑøÔ±</a></li> - -<li><a href="http://kan.sina.com.cn/u/2931323820/3476659" target="_blank">ºüÀ꿪Æô¡¶GTA5¡·»¶ÀÖËÀÍö¾º¼¼</a></li> - -<li><a href="http://kan.sina.com.cn/u/1743000753/3475955" target="_blank">°µÒ¹¡¶Â¯Ê¯´«Ëµ¡·¾º¼¼³¡¶Ä²©Ä£Ê½</a></li> - -<li><a href="http://kan.sina.com.cn/u/12dora/3476726" target="_blank">´óµ±¼Ò¡¶300Ó¢ÐÛ¡·¿ªºÚ»¶ÀÖÖ±²¥</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://kan.sina.com.cn/zq/wd" target="_blank">¡¶ÎʵÀ¡·Ã¿Íí¾¢±¬Ö±²¥</a> <a href="http://kan.sina.com.cn/zq/thyj" target="_blank">¡¶ÌÒ»¨Ô´¼Ç¡·7.3ÈÕÊ״ι«²â</a></li><li><a href="http://kan.sina.com.cn/zq/sqcs" target="_blank">¡¶ÉñÆ÷´«Ëµ¡·È«Ãñ¹«²â</a> <a href="http://kan.sina.com.cn/zq/qjmu" target="_blank">¡¶Ææ¼£MU¡·S9аæÕýʽÉÏÏß</a></li><li><a href="http://kan.sina.com.cn/zq/qbzz" target="_blank">¡¶³à±ÚÖ®Õ½¡·ÔÙÏÆÈÈѪ·ç³±</a> <a href="http://kan.sina.com.cn/zq/dtcq" target="_blank">¡¶µ¶Ëþ´«Ææ¡·ÐÂ×ÊÁÏƬÀ´Ï®</a></li><li><a href="http://kan.sina.com.cn/anchor/" target="_blank">Ã÷ÐÇÖ÷²¥</a>| -<a href="http://kan.sina.com.cn/u/1780682544" target="_blank">·½ÖÛ ÍÀÁúÓÂÊ¿K×Ü</a> -<a href="http://kan.sina.com.cn/u/yangxiaomu/3475091" target="_blank">¡¶ÓÀºãÖ®Ëþ¡·»³¾ÉÖ±²¥</a></li> -<li><a href="http://kan.sina.com.cn/activity/" target="_blank">»î¶¯ÈüÊÂ</a>| -<a href="http://kan.sina.com.cn/u/1875984205" target="_blank">WCAְҵԤѡÈü</a> <a target="_blank" href="http://kan.sina.com.cn/u/2609950594">2015̹¿ËÊÀ½ç³¬¼¶ÁªÈü¼¾ºóÈü</a></li> -<li><a href="http://kan.sina.com.cn/hotgirls/" target="_blank">ÃÀŮֱ²¥</a>| <a href="http://kan.sina.com.cn/u/2413262821/3476622" target="_blank">Ôºߺߺϳè¼Ç</a> <a href="http://kan.sina.com.cn/u/5611043726/3476536" target="_blank">ÃλÃÎ÷ÓÎÃÀòµÄµÚÒ»·òÈË</a></li> -<li><a href="http://kan.sina.com.cn/dj/" target="_blank">µç¾ºÊÀ½ç</a>| -<a href="http://kan.sina.com.cn/u/3976780317" target="_blank">ÂÞÂíÖ®¼Ò±ÈÈüÖ±²¥</a> <a target="_blank" href="http://kan.sina.com.cn/act/xlgxs">ÐÂÀ˳¬ÐÂÐǸßУÈü</a></li> -<li><a href="http://kan.sina.com.cn/zq/gaoqing1" target="_blank">¸ßÇåƵµÀ</a>| -<a href="http://kan.sina.com.cn/u/2890524092/" target="_blank">DGµç¾º¾ãÀÖ²¿Ö±²¥</a> <a target="_blank" href="http://kan.sina.com.cn/u/2497298463">µçÍæƵµÀE3ÓÎÏ··¢²¼»á</a></li> - </ul> -</textarea> - </div> - - </div> - </div> - </div> - <!-- mod34 --> - </div> - </div> - <!-- part-k end --> - <div class="blank-cont" style="height:25px;"></div> - <!-- part-l begin --> - - <div class="part-l clearfix"> - <div class="part-l-l"> - <!-- mod35 --> - <div class="mod-13 mod-02" data-sudaclick="blk_zycg"> - <div class="tit02 clearfix"> - <h3><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDIxNA%3D%3D&sign=02562632d22fe03f&url=http%3A%2F%2Fzhongyi.sina.com%2Fcustomer_index.shtml" target="_blank">ÖÐÒ½³É¹û</a></h3> - </div> - <div class="mod13-cont" style="width:240px;_width:238px;padding:0;margin-left:-1px; _margin-left:0px;"> -<a target="_blank" href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjc3MQ%3D%3D&sign=82b4c6ecb1dbf379&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fredian-1a%2F"><img src="http://d5.sina.com.cn/201506/16/1029597.jpg" style="width:240px;_width:238px;"/></a> - -<a target="_blank" href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjY0MQ%3D%3D&sign=0ae3d42ac8ee03d9&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fredian-2a%2F"><img src="http://d4.sina.com.cn/201506/16/1029596.jpg" style="width:240px;_width:238px;margin-top:5px;"/></a> - - </div> - </div> - <!-- mod35 --> - </div> - <div class="part-l-m"> - <!-- mod36 --> - <div class="uni-blk" id="SI_Order_M" tab-type="tab-wrap" struc="1-5"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://redirect.simba.taobao.com/rd?c=un&w=channel&f=http%3A%2F%2Fwww.taobao.com%2Fgo%2Fact%2Fmmbd%2Fpdnew.php%3Fpid%3Dmm_15890324_2192376_13096223%26unid%3D&k=30375390a8b21737&p=mm_15890324_2192376_13096223" target="_blank">ÉÌѶ</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - - <div class="uni-blk-b SC_Order_Fix_Cont"> - -<iframe src="http://d3.sina.com.cn/litong/zhitou/union/tanx.html?pid=mm_15890324_2192376_13096223&type=html" width="360" height="242" frameborder="0" scrolling="no"></iframe> - -<!-- -<iframe src="http://www.taobao.com/go/act/sale/xlsyzt.php" width="360" height="247" style="margin-left:-10px; margin-top:-10px;" frameborder="0" scrolling="no"></iframe> ---> - - </div> - - </div> - </div> - <!-- mod36 --> - </div> - <div class="part-l-r"> - <!-- mod37 --> - <div class="uni-blk" id="SI_Order_N" tab-type="tab-wrap" struc="1-5"> - - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://sea.sina.com.cn/" target="_blank">×ÊѶ</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li style="margin-right:20px;"><ins class="sinaads" data-ad-pdps="PDPS000000055132"></ins><script type="text/javascript">(sinaads = window.sinaads || []).push({})</script></li> -<li><a href="http://iask.sina.com.cn/" target="_blank">°®ÎÊ</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont"> - - <div class="uni-blk-bt clearfix"> - -<div id="gina_res_show1356" style="float:left;width:107px;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052113"></ins> - <script>(sinaads = window.sinaads || []).push({params: { - sinaads_ad_width: 105, - sinaads_ad_height: 90, - sinaads_ad_tpl: [ - '<a href="#{link0}" onclick="try{#{monitor}}catch(e){}" target="_blank" class="uni-blk-pic"><img src="#{src0}" width="105" height="70" />', - '<span>', - '#{src1}', - '</span>', - '</a>' - ].join('') - }});</script> - - <!-- ×ÊѶ105*90ͼÎĹã¸æ02 Start --> - <ins class="sinaads" data-ad-pdps="PDPS000000056020" style="padding-top:18px;"></ins> - <script>(sinaads = window.sinaads || []).push({params : { - sinaads_ad_width : 105, - sinaads_ad_height : 90, - sinaads_ad_tpl: [ - '<a href="#{link0}" onclick="try{#{monitor}}catch(e){}" target="_blank" class="uni-blk-pic"><img src="#{src0}" width="105" height="70" />', - '<span>', - '#{src1}', - '</span>', - '</a>' - ].join('') - }});</script> - <!-- ×ÊѶ105*90ͼÎĹã¸æ02 End --> -</div> - -<style> -.list-news20150310 li{ - padding-left: 10px; - line-height: 25px !important; - height: 25px; - overflow: hidden; - font-size: 14px; - background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px; - _zoom: 1; -} -</style> - -<ul class="uni-blk-list01 list-a list-news20150310" id="gina_res_show1355"> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052114"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052115"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052116"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052117"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="margin-top:9px;line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052119"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052121"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052123"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052125"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> -</ul> - - </div> - <div class="blk-line"></div> - -<ul class="uni-blk-list02 list-a" id="gina_res_show1332"> -<li> - <ins class="sinaads" data-ad-pdps="PDPS000000052126"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</li> -</ul> - - </div> - - </div> - </div> - </div> - <!-- mod37 --> - </div> - </div> - <!-- part-l end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-m begin --> - <div class="part-m"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸04¹ã¸æ begin --> -<div id="ad_46020" class="ad-banner mb25"> -<ins class="sinaads" data-ad-pdps="PDPS000000046020"></ins> -<script>(sinaads = window.sinaads || []).push({});</script> -</div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸04¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- part-m end --> - - <!-- part-n begin --> - - <div class="part-n clearfix"> - <div class="part-n-l"> - <!-- mod38 --> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x355 1ÂÖ²¥°´Å¥07¹ã¸æ begin --> -<div id="ad_46021" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046021"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x355 1ÂÖ²¥°´Å¥07¹ã¸æ end --> -<!--_SINA_ADS_END_--> - <!-- mod38 --> - </div> - <div class="part-n-m"> - <!-- mod41 --> - <div class="uni-blk" id="SI_Order_P" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://eladies.sina.com.cn/" target="_blank">Å®ÐÔ</a></span> - <span tab-type="tab-nav"><a href="http://eladies.sina.com.cn/feel/" target="_blank">Çé¸Ð</a></span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_3"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_eladies_1" blkclick="auto_nav" blktitle="Å®ÐÔ"> -<!-- publish_helper name='Å®ÐÔÇø¿é' p_id='30' t_id='110' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://eladies.sina.com.cn/photo/" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/lx/old2013/photo/idx/2015/0617/U6929P8T440D1F14806DT20150617152735.jpg" width="105" height="70" /> - - <span>̨Íå×îÃÀÕ¬ÄÐÅ®Éñ</span> - - </a><ul class="uni-blk-list01 list-a"><li><a href="http://eladies.sina.com.cn/" target="_blank" class="linkRed01">Í·Ìõ|²»ÅÂɽկ ÌÆæÌÓÐN¿îÏÞÁ¿°ü</a></li> - - <li><a href="http://eladies.sina.com.cn/feel/" target="_blank">Çé¸Ð</a>| <a target="_blank" href="http://eladies.sina.com.cn/feel/xinli/2015-06-18/0802/doc-ifxczyze9670917.shtml" class="linkRed01">Áµ°®8Àà¶ñÅ®</a> <a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0803/doc-ifxczyze9632377.shtml" class="linkRed01">ÎҰܸøСÈý</a></li> - - <li><a href="http://eladies.sina.com.cn/news/" target="_blank">»¨±ß</a>| <a href="http://eladies.sina.com.cn/news/star/2015-06-18/0759/doc-ifxczqan1507381.shtml" target="_blank" class="linkRed01">ÁÖ־ӱ쟹</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-18/0740/doc-ifxczqar0984241.shtml" class="linkRed01">³ÉÁú²»Ê¶À</a></li> - -<li><a href="http://fashion.sina.com.cn/luxury/" target="_blank" class="linkRed01">Éú»î</a>| <a target="_blank" href="http://fashion.sina.com.cn/luxury/watch/" class="linkRed01">ʱ÷Ö±ãÒËÍó±í</a> <a target="_blank" href="http://fashion.sina.com.cn/d/he/2015-06-18/0751/doc-ifxczqap3911739.shtml" class="linkRed01">6ÖÖ³¤ÊÙʳÎï</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://fashion.sina.com.cn/style/" target="_blank">·þÊÎ</a>| - -<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60851.html#p=1" class="linkRed01">×îÇ¿¼¡ÈâÄÐÐǽÖÅÄ</a> -<a target="_blank" href="http://fashion.sina.com.cn/s/ce/2015-06-18/0744/doc-ifxczyze9463092.shtml" class="linkRed01">±´Ð¡ÆßÍÁºÀ×°±¸</a> -<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60827.html#p=1" class="linkRed01">¾®°ØÈ»ÂôÃÈ</a> - -</li> - -<li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>| - <a target="_blank" href="http://fashion.sina.com.cn/b/mk/2015-06-18/0739/doc-ifxczyze9675538.shtml" class="linkRed01">Ñî×ÏײÁ³6Å®ÐÇ</a> -<a target="_blank" href="http://fashion.sina.com.cn/b/sk/2015-06-18/0748/doc-ifxczqar0956008.shtml" class="linkRed01">Å®ÐÇËØÑÕpkÕ½</a> -<a target="_blank" href="http://fashion.sina.com.cn/b/ha/2015-06-18/0748/doc-ifxczyze9594720.shtml" class="linkRed01">Í··¢±âËúÔõôÆÆ</a></li> - -<li><a href="http://fashion.sina.com.cn/wedding/" target="_blank" class="linkRed01">»é¼Þ</a>| <a href="http://fashion.sina.com.cn/w/re/2015-06-18/0755/doc-ifxczqap4212630.shtml" target="_blank" class="linkRed01">È«Ö°Ì«Ì«µÄ10¸ö±×¶Ë</a> - -<a href="http://fashion.sina.com.cn/match/" target="_blank">ÃÀ´î</a>| -<a href="http://slide.fashion.sina.com.cn/m/slide_24_66132_60808.html" target="_blank" class="linkRed01">¸ßÔ²Ô²BabyÐÔ¸ÐïοÕ</a></li> - -<li><a href="http://eladies.sina.com.cn/photo/" target="_blank">ÃÀͼ</a>| -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24707.html" target="_blank" class="linkRed01">ÁøÑÒË«·å°ÁÈË</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24714.html" target="_blank" class="linkRed01">˽·¿Ð´Õæ</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24712.html" target="_blank" class="linkRed01">ÏÄÈÕÅ®Éñ</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24715.html" target="_blank" class="linkRed01">´¿É«ÄÚÒÂÅ®ÀÉ</a></li> - -<li><a href="http://eladies.sina.com.cn/news/" target="_blank" class="linkRed01">°ËØÔ</a>| - <a href="http://eladies.sina.com.cn/news/star/2015-06-18/0759/doc-ifxczqar0983993.shtml" target="_blank" class="linkRed01">ÑëÊÓÇ°Ö÷²¥×ß˽</a> -<a href="http://eladies.sina.com.cn/news/star/2015-06-18/0800/doc-ifxczqan1500694.shtml" target="_blank" class="linkRed01">·¶±ù±ù¾ÈÄÐͯ</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-18/0800/doc-ifxczqap4197873.shtml" class="linkRed01">Íô·å¡°½è¼ø¡±Ö£¾û</a></li> - -<li><a href="http://eladies.sina.com.cn/qg/koushu/" target="_blank" class="linkRed01">¿ÚÊö</a>| -<a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0803/doc-ifxczqap4168902.shtml" class="linkRed01">ÒÔ»³ÔÐÍìÁôËû</a> <a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0805/doc-ifxczqar0954571.shtml" class="linkRed01">ÀϹ«°®¿´ÍøÉÏÃÀÅ®</a> <a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0804/doc-iawzuney6592149.shtml" class="linkRed01">ÕÉ·òƵ·±³ö¹ì</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/column/">רÀ¸</a>| -<a target="_blank" href="http://blog.sina.com.cn/lm/eladies/ " class="linkRed01">ÄÐÅ®ºÃÉ«Çø±ð</a> -<a target="_blank" href="http://blog.sina.com.cn/s/blog_8e59d2630102vl07.html?tj=1" class="linkRed01">°®ÉÏ×ø̨Ůº¢</a> - -<a target="_blank" href="http://blog.sina.com.cn/s/blog_6f3ba5d90102vsqn.html?tj=1" class="linkRed01">ÄÐÓѽ»8¸öÇéÈË</a> -</li> - -<li><a target="_blank" href="http://eladies.sina.com.cn/bbs/">ÂÛ̳</a>| <a target="_blank" href="http://club.eladies.sina.com.cn/slide.php?tid=6461257" class="linkRed01">Å®Ö÷²¥ÉîÒ¹ÆØÂã±³(ͼ)</a> <a target="_blank" href="http://fashion.sina.com.cn/try/product/1055" class="linkRed01">ÇÀÖ²´åÐãÐÂÆ·Ë«É«ÕÚ覱Ê</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_eladies_3" blkclick="auto_nav" blktitle="Çé¸Ð"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='Çé¸ÐÇø¿é' p_id='30' t_id='110' d_id='3' --> - <div class="uni-blk-bt clearfix"> -<a href="http://eladies.sina.com.cn/feel/xinli/2015-06-18/0739/doc-ifxczyze9669913.shtml" target="_blank" class="uni-blk-pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150618/P5KK-fxefurs2581152.jpg" width="105" height="70" /> - - <span>½ÌÄãÈçºÎʶ±ðÔüÄÐ</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://eladies.sina.com.cn/feel/xinli/2015-06-17/0729/doc-ifxczyze9630586.shtml" target="_blank">½ÒÃØΪʲôÄÐŮϲ»¶¸ãêÓÃÁ</a></li> - -<li><a href="http://eladies.sina.com.cn/feel/xinli/2015-06-17/0729/doc-ifxczqar0954236.shtml" target="_blank">´óÊåµ±µÀ Å®ÈËΪºÎ»áϲ»¶ÀÏÄÐÈË</a></li> - -<li><a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqan0628752.shtml" target="_blank">ÕÅÌúÁÖÆØÓÐ˽Éú×Ó</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqan0631899.shtml">½´¨»éÀñ</a></li> - -<li><a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczyze9619106.shtml" target="_blank">·¶±ù±ù¾ÈÄк¢</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqan0633143.shtml">´óSÔøΪСSÆíµ»</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1659/doc-ifxczqar1000167.shtml" target="_blank">ÀϹ«ÅÂÇéÈËÀ´¼Ò´óÄÖ¶øʧ×Ù</a> -<a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1722/doc-ifxczqar1001074.shtml" target="_blank">ÄÐÓѳԷ¹²»ÌÍÇ®ÎÒ»éÇ°ÑøËû</a></li><li><a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1725/doc-ifxczqap4215670.shtml" target="_blank">¹ëÃÜÇÀÁËÎÒÄÐÓÑÎÒ¾¹²»ÖªµÀ</a> -<a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1729/doc-ifxczqap4215925.shtml" target="_blank">Ç°·òÕÒÉÏÃÅÎÒ²ÅÖªËýÀë¹ý»é</a></li><li><a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczyze9619722.shtml" target="_blank">Àî°½Åú²ÌÒÀÁÖ×Գơ°ÀÏÄ</a> -<a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqar0941188.shtml" target="_blank">47ËêÏ¢Ó°Å®ÐÇÕÅÃô½üÕÕÆعâ</a></li><li><a href="http://blog.sina.com.cn/s/blog_49f747bc0102voxt.html?tj=1" target="_blank">ÄãÕæÐÄÏëÒª×ö¡°¶¡¿Ë¡±Âð</a> -<a href="http://blog.sina.com.cn/s/blog_49b486130102vvuu.html?tj=1" target="_blank">ÖйúÄÐÈËÊܹ»ÁËÖйúÅ®ÈË£¿</a></li><li><a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24694.html" target="_blank">άÃØÌìʹÏÄÈÕÇåÐÂÓ¾×°´óƬ</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24656.html" target="_blank">Ð콿½üÕÕÄæÉú³¤ËÆÂÜÀò</a></li><li><a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24678.html" target="_blank">Á½´ó³¬Ä£º£±ßϷˮ˫·å°ÁÈË</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24677.html" target="_blank">AKB48×îÐÔ¸ÐÅ®ÉñСëÑô²Ë</a></li> - -<li><a href="http://blog.sina.com.cn/s/blog_6f3ba5d90102vst3.html?tj=lady" target="_blank">ÎÒûÅö¹ýÅ®ÓÑËýÈ´»³ÔÐ</a> -<a href="http://blog.sina.com.cn/s/blog_51177cc40102vmh5.html?tj=lady" target="_blank">СÈýÉÏÃÅÀϹ«±§×ÅÎÒÈÃËý´ò</a></li> - -<li> - -<a href="http://fashion.sina.com.cn/zl/love/2015-05-05/14113459.shtml" target="_blank">ÖйúÄÐÈËΪʲôϲ»¶ÐíÇ磿</a> -<a href="http://fashion.sina.com.cn/zl/fashion/2015-06-16/16363778.shtml" target="_blank">¼Þ¸ø×êʯÄеÄÆ«Æ«ÊÇËýÃÇ</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod41 --> - - </div> - <div class="part-n-r"> - - <!-- mod40 --> - <div class="uni-blk" id="SI_Order_O" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://house.sina.com.cn/" target="_blank">·¿²ú</a></span> - <span tab-type="tab-nav"><a href="http://esf.sina.com.cn/" target="_blank">¶þÊÖ·¿</a></span> - <span tab-type="tab-nav"><a href="http://jiaju.sina.com.cn/" target="_blank">¼Ò¾Ó</a></span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_2"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> - <li><a href="http://finance.sina.com.cn/sf/list/?cate_id=50025969&cat_name=%E6%88%BF%E4%BA%A7" target="_blank" suda-uatrack="key=index_sfpm&value=housesf">·¿²úÅÄÂô</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_house_1" blkclick="auto_nav" blktitle="·¿²ú"> -<!-- publish_helper name='house_·¿²ú_Çø¿é' p_id='30' t_id='109' d_id='6' --> -<div class="uni-blk-bt clearfix" id="SI_IP_House_0"> -<!-- 09:43:41 --> -<a href="http://bj.house.sina.com.cn/zhuanti/zxsh/index.shtml" target="_blank" class="uni-blk-pic"><img src="http://src.house.sina.com.cn/imp/imp/deal/e8/c9/2/405057288770cda8e38fc45502c_p24_mk24.jpg" width="105" height="70"/><span>¶ËÎçôÕÏíÊ¢»Ý</span> -</a><ul class="uni-blk-list01 list-a"> -<li><a href="http://search.house.sina.com.cn/bj/news/" target="_blank" class="col_8">ÐÂÎÅ</a><i>|</i><a href="http://bj.house.sina.com.cn/" target="_blank">5Ô¾©ÉÌס¼Û¸ñ»·±ÈÕÇ1.4%</a></li> - -<li><a href="http://bj.house.sina.com.cn/exhibit/" target="_blank" class="col_8">רÌâ</a><i>|</i><a href="http://bj.house.sina.com.cn/exhibit/forlovepapa/index.shtml" target="_blank" class="col_8">Ϊ°®±¼ÅÜÀÖ¾Ó¸¸Ç×½ÚîÒ»Ý</a></li> - -<li><a href="http://bj.house.sina.com.cn/exhibit/" target="_blank" class="col_8">Êг¡</a><i>|</i><a href="http://bj.house.sina.com.cn/scan/2015-06-12/18406015075033695957695.shtml"target="_blank" class="col_8">ÂòºÃ·¿ÐÄÇéºÃ¹ý±±¾©À¶Ìì</a></li> - -<li><a href="http://data.house.sina.com.cn/bj/new/" target="_blank" class="col_8">¿´·¿</a><i>|</i><a href="http://bj.house.sina.com.cn/zhuanti/6.27dxkft/index.shtml" target="_blank" class="col_8">6.27ÏÄÈÕ¹º·¿¼¾¿´·¿ÍÅ - -</a></li> -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<!-- 10:20:10 --> -<li id="SI_IP_House_1"><a href="http://search.house.sina.com.cn/bj/news/scdt/" target="_blank" class="linkRed03">ÐÂÎÅ</a>| <a href="http://bj.house.sina.com.cn/news/2015-06-18/07096017075518384681085.shtml" target="_blank">±±¾©¹«»ý½ðÔ½ɴæÉÏÏÞÔö484Ôª</a> <a href="http://bj.house.sina.com.cn/news/2015-06-18/07226017078769838502906.shtml" target="_blank">ÀöÔóµØÏ»·ÀÈ¿ª½¨</a></li> - -<li id="SI_IP_House_2"><a href="http://data.house.sina.com.cn/bj/dianping/" target="_blank">Â¥ÆÀ</a>| <a target="_blank" href="http://bj.house.sina.com.cn/scan/2015-06-02/11236011341189431997262.shtml">ÌìÆøÈȲ»¼°Â¥ÊÐÈÈ</a> <a target="_blank" href="http://bj.house.sina.com.cn/scan/2015-06-04/11236012065931063505297.shtml?qq-pf-to=pcqq.discussion">×ß·¸ß¿¼²»ÏÞºÅ</a></li> - -<li id="SI_IP_House_3"><a href="http://bj.house.sina.com.cn/bbs/" target="_blank">»¥¶¯</a>| <a href="http://blog.sina.com.cn/s/blog_48f319170102vmvk.html?tj=1" target="_blank">¿ªÕ÷·¿²úË°¶ÔÂ¥ÊÐÁù´óºÃ´¦</a> <a href="http://bj.bbs.house.sina.com.cn/thread-6014597615063158347.html"target="_blank">6ºÅÏßÎ÷ÑÓ6Õ¾Á¬ÉÏÆ»¹ûÔ°</a> </li> - -<li id="SI_IP_House_4"><a href="http://house.sina.com.cn/" target="_blank">Èȵã</a>| </i><a href="http://bj.house.sina.com.cn/news/2015-06-18/06556017072009572561844.shtml" target="_blank">±±¾©²ð³ýȺ×â·¿573»§</a> <a href="http://bj.house.sina.com.cn/news/2015-06-18/06596017072981782868816.shtml" target="_blank">±¾ÔÂÖÁ9Ô½«¼¯ÖÐÖÎÀí</a></li> - -<li><a href="http://house.sina.com.cn/" target="_blank">ÒªÎÅ</a>| <a href="http://tj.house.sina.com.cn/news/2015-06-18/08116017090895957243317.shtml" target="_blank">Íâ×ʹºÂòÖйúÂ¥Êлò·Å¿ª</a> <a href="http://tj.house.sina.com.cn/news/2015-06-18/08096017090551437112820.shtml" target="_blank">ÍÁµØ²ÆÕþÒÀÀµÖ¢ÈÔδ½â</a></li> - -<li><a href="http://news.leju.com/" target="_blank">Éî¶È</a>| <a href="http://news.leju.com" target="_blank">Íò¿Æ¸ß¹ÜÔٶȵ÷Õû</a> <a href="http://news.leju.com/view/6017120441414930210.html" target="_blank">Â¥ÊÐÅÝÄ­µÄÒÕÊõ»¯ÓëÉú´æ</a></li> - -<li id="SI_IP_House_5"><a href="http://esf.sina.com.cn/" target="_blank">¶þÊÖ·¿</a>| <a href="http://bj.esf.sina.com.cn/act/house" target="_blank">ÈÏÖ¤·¿³ÏÐÅ·¿Ô´´óÁªÕ¹</a> <a href="http://j.eju.com/login" target="_blank">ÖйúÍøÂç¾­¼ÍÈËÁªÃË</a></li><li><a href="http://jiaju.sina.com.cn/" target="_blank" class="linkRed03">¼Ò¾Ó</a>| <a href="http://jiaju.sina.com.cn/news/j/20150618/6017110069639184416.shtml?utm_source=snls&utm_medium=nrw&utm_campaign=n_9999" target="_blank">½ÌÄã×°ÐÞͼֽµÄС֪ʶ</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/?utm_source=snls&utm_medium=nrw&utm_campaign=n_9998">148ƽÈËÎľӾ«ÖÂÉÏÑÝ</a></li> - </ul> - - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_house_2" blkclick="auto_nav" blktitle="¶þÊÖ·¿"> -<!-- publish_helper name='¶þÊÖ·¿Çø¿é' p_id='30' t_id='129' d_id='4' --> - - <div class="uni-blk-bt clearfix" id="SI_IP_House_10"> -<!-- 10:25:06 --> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_wx/weixin20150612xm/" target="_blank" - -class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.esfimg.com/imp/537d3c60d0c582b11a30d299d1cf5ee9_os433ec8.jpg" - -width="105" height="70" border="0" /><span>ÖÃÒµÕß×ø²»×¡ÁË</span> -</a> - -<ul class="uni-blk-list01 list-a"> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150611lzq/" - -target="_blank">µØÌú´ø»ðÑོ 8Ì×·¿ÇÀÏÈ¿´</a></li> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150611zwy/" - -target="_blank">¸ÄÉƵ±µÀ²ýƽ´ó»§¾ù¼Û2ÍòÆð</a></li> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150608gxz/" - -target="_blank">É˲»Æð£¡ÂòÍê2СÇø¾ÍÕǼÛ</a></li> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_wx/weixin20150613gxz/" target="_blank"> - -ÂòѧÇø·¿Ç§Íò±ðÓÌÔ¥</a></li> -</ul> - - </div> - <div class="blk-line"></div> - -<!-- 10:21:04 --> -<ul class="uni-blk-list02 list-a" id="SI_IP_House_11"> - -<li> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50832" class="linkRed03">ÔçѶ</a>| -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50888" target="_blank">¾©Ð·¿¹©Ó¦Ôö¼Ó </a> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50881" target="_blank">ÉÏ°ëÔ¶þÊÖ·¿³É½»Á¿ÕÇ250%</a> -</li> - -<li> -<a href="http://esf.sina.com.cn/" >¿´µã</a>| -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50887" target="_blank">ͨÖݶþÊÖ·¿±©Õǽü15Íò</a> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50875" target="_blank">ºÀÕ¬³É½»Ê®Ç¿¾©Î÷Õ¼6</a> -</li> - -<li> -<a href="http://esf.sina.com.cn/" >½â¶Á</a>| -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50886" target="_blank">Âò·¿Ê²Ã´Ê±»ú×îºÏÊÊ</a> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50879" target="_blank">Ë­ÔÚΪ·è¿ñµÄºÀÕ¬Âòµ¥</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >רÌâ</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150608gxz/" target="_blank">Õâ2СÇøÂòÍê¾ÍÕǼÛ</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150604xm/" target="_blank">°Ù×ÓÍå´ø»ðºóÏÖ´ú³Ç</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >ÍƼö</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150605xjl/" target="_blank">¼ÒµÄºó»¨Ô°¾ÍÊÇÔ²Ã÷Ô°</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150605xjl/" target="_blank">¹«»ý½ðÂòµÃÆð·¿É½´ó·¿</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >¶À¼Ò</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150604lzq/" target="_blank">ÃûУÔú¶Ñ Íû¾©9·¿¼±ÊÛ</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150602gxz/" target="_blank">³´¹É²»ÈçÂò·¿Õæʵ</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >µ¼¹º</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150529xjl/" target="_blank">Âò·¿£¡¼ÒÃÅ¿ÚÓÐË«µØÌú</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150529gxz/" target="_blank">¸Õ½úÉýѧÇøÈëÊÖÒ»Ì×£¡</a> -</li> - -<li> -<a href="http://esf.sina.com.cn/" >µ¼¹º</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/index/" target="_blank">רÌâÍÆ·¿</a> -<a href="http://bj.esf.sina.com.cn/house/c1/" target="_blank">150ÍòÄÚ</a> -<a href="http://bj.esf.sina.com.cn/house/e1/" target="_blank">±±Æ¯</a> -<a href="http://bj.esf.sina.com.cn/house/c0,300-e3/" target="_blank">СÈý·¿</a> -<a href="http://bj.esf.sina.com.cn/house/b7-a16/" target="_blank">ºÀÕ¬</a> -<a href="http://bj.esf.sina.com.cn/house/oÐÂÕþ/?" target="_blank">ÐÂÕþ</a> -</li> - -</ul> - - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_house_3" blkclick="auto_nav" blktitle="¼Ò¾Ó"> -<!-- publish_helper name='¼Ò¾ÓÇø¿é' p_id='30' t_id='129' d_id='5' --> -<div class="uni-blk-bt clearfix"> <a href="http://zx.jiaju.sina.com.cn/anli/?utm_source=snls&utm_medium=nrw&utm_campaign=n_9993" target="_blank" class="uni-blk-pic" title="ÓÅÑÅÊæÊʼ«ÁË"> <img src="http://src.house.sina.com.cn/imp/imp/deal/ca/c3/2/c09258da42a8bbf06e08d25aaf4_p24_mk24.jpg" width="105" height="70" /><span>ÓÅÑÅÊæÊʼ«ÁË</span></a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://jiaju.sina.com.cn/news/j/20150618/6017110069639184416.shtml?utm_source=snls&utm_medium=nrw&utm_campaign=n_9997" target="_blank">½ÌÄãÈçºÎ¿´×°ÐÞͼֽµÄС֪ʶ</a></li> - <li><a href="http://jiaju.sina.com.cn/haoguanjia/119.html?utm_source=snls&utm_medium=nrw&utm_campaign=n_9996" target="_blank">ÈçºÎ¹¹ÖþȫеÄÉú»î·½Ê½Ìåϵ</a></li> - <li><a href="http://zx.jiaju.sina.com.cn/anli/105781.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9995" target="_blank">СÇåÐÂ133ƽìŲÊʱÉÐÏÖ´ú3¾Ó</a></li> - <li><a href="http://zx.jiaju.sina.com.cn/anli/105713.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9994" target="_blank">âñÈ»ÐĶ¯³©Ïí180ƽÃÀʽÎÂÜ°</a></li> - </ul> -</div> -<div class="blk-line"></div> -<ul class="uni-blk-list02 list-a"> - <li><a href="http://jiaju.sina.com.cn/news/20150618/6016885348175774650.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9992" target="_blank">¼Ò¾Ó·çË®²»Àû»áÈÃÄ㩲Æ</a> <a href="http://jiaju.sina.com.cn/news/fengshui/20150618/6017109213304914880.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9984" target="_blank">¸ÃÈçºÎÍØÕ¹ÄãµÄ¼Ò¾Ó²ÆÔË</a></li> - <li><a target="_blank" href="http://zx.jiaju.sina.com.cn/?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9976">¸ßÇå</a>| <a href="http://zx.jiaju.sina.com.cn/anli/106034.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9991" target="_blank">ÍñתµÄ¾ªÑÞ89ƽºÚ°×¾Ó</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/105871.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9983">ÑÅȤÈý¿ÚÖ®¼ÒÃ÷Ãĸñµ÷</a></li> - <li><a target="_blank" href="http://www.qianggongzhang.com/anli/">×°ÐÞ</a>| <a href="http://jiaju.sina.com.cn/news/20150617/6016758925029081130.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9990" target="_blank">¾«Ñ¡20Ìõ´ÉשװÐÞ¾÷ÇÏ</a> <a target="_blank" href="http://wh.jiaju.sina.com.cn/news/j/20150618/6017111381005110285.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9982">±ÜÃâ×°ÐÞÖÐÒ×·¸µÄ´íÎó</a></li> - <li><a target="_blank" href="http://jiaju.sina.com.cn/decoration/">¹¥ÂÔ</a>| <a href="http://tj.jiaju.sina.com.cn/news/j/20150618/6017106628254696245.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9985" target="_blank">Ïļ¾ÎÀÔ¡Æ·±£ÑøµÄÃØ·½</a> <a target="_blank" href="http://jiaju.sina.com.cn/news/j/20150618/6017111632969531740.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9977">ÈýÖÖÓÍÑÌ»úÓÅȱµã½âÎö</a></li> - <li><a target="_blank" href="http://jiaju.sina.com.cn/decoration/">רÌâ</a>| <a href="http://zx.jiaju.sina.com.cn/anli/105889.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9989" target="_blank">ÈáÇé119ƽÐÂÖÐʽ¼ò½à·ç</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/105820.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9981">¾øÃÀ·çÉÐ98ƽÐÄÁé¾»ÍÁ</a></li> - <li><a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9975">ÃÀͼ</a>| <a href="http://supports.jiaju.sina.com.cn/dzjz/index.php?_a=detail&id=1246?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9988" target="_blank">¸ÐÊÜÉú»îÇéȤµÄС¹«Ô¢</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/105623.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9980">125ƽ³Á¾²Ö®ÃÀйŵä</a></li> - <li><a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/c1/?utm_source=snls&utm_medium=nrw&utm_campaign=n_9972">Éè¼Æ</a>| <a href="http://zx.jiaju.sina.com.cn/anli/105788.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9973" target="_blank">150ƽÐÒ¸£ÒݼÒдÒâ¿Õ¼ä</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/106017.html -?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9974">9Íò¸ÄÔìÔ¡»ðÖØÉú¾ÉÎÝ</a></li> - <li id="SI_IP_House_13"><a target="_blank" href="http://jiaju.sina.com.cn/decoration/">´îÅä</a>| <a target="_blank" href="http://sh.jiaju.sina.com.cn/news/j/20150617/6016888288424823016.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9986">½ÌÄãËÄÕÐÌù³öÍêÃÀµØÃæ</a> <a target="_blank" href="http://sz.jiaju.sina.com.cn/news/j/20150618/6017115031790225571.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9978">ÃÈÍÞÄÖ·­ÌìµØ°åÇÀ¾È·¨</a></li> -</ul> - - </div> - </div> - </div> - </div> - <!-- mod40 --> - - </div> - </div> - <!-- part-n end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-o begin --> - - <div class="part-o"> - <div class="part-o-l"> - <!-- mod42 --> - <div class="mod-42 mod-13 mod-02"> - <div class="tit02 clearfix"> - <h3><a href="http://open.sina.com.cn/" target="_blank">ÐÂÀ˹«¿ª¿Î</a></h3> - </div> - <div class="mod42-cont" data-sudaclick="blk_edu_wkt" blkclick="auto_nav" blktitle="΢¿ÎÌÃ"> -<!-- publish_helper name='ÐÂÀË΢¿ÎÌÃ' p_id='30' t_id='111' d_id='3' --> -<div class="vid-txt clearfix"><a href="http://open.sina.com.cn/course/id_1192" target="_blank" class="vid"> - <img src="http://i1.sinaimg.cn/home/2015/0611/U684P30DT20150611113718.jpg" /> - <i class="vid-play-icon"></i> - </a> - <div class="txt"><h3><a href="http://open.sina.com.cn/course/id_1192" target="_blank" class="videoNewsLeft">ÈÕ±¾´«Í³ÎÄ»¯Ê·</a></h3> - <a href="http://open.sina.com.cn/" target="_blank" class="free-listen">¸ü¶à¿Î³Ì</a></div></div><div class="mod42-cont-b"><a target="_blank" href="http://open.sina.com.cn/course/id_946" class="videoNewsLeft">ƽÃæÉè¼ÆÈëÃÅ</a> <a target="_blank" href="http://open.sina.com.cn/school/id_146/" class="linkRed">ר¼Ò½ÌÄã¸ß¿¼Ö¾Ô¸Ì</a></div> - </div> - </div> - <!-- mod42 --> - <div class="blank-cont" style="height:20px"></div> - <!-- mod43 --> - <div class="mod-43"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 2ÂÖ²¥°´Å¥08¹ã¸æ begin --> -<div id="ad_45990" style="width:240px; height:170px;"><ins class="sinaads" data-ad-pdps="PDPS000000045990"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 2ÂÖ²¥°´Å¥08¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod43 --> - </div> - <div class="part-o-m"> - <!-- mod44 --> - <div class="uni-blk" id="SI_Order_Q" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://edu.sina.com.cn/" target="_blank">½ÌÓý</a></span> - <span tab-type="tab-nav"><a href="http://edu.sina.com.cn/a/" target="_blank">³ö¹ú</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> - -<li><a href="http://edu.sina.com.cn/college/" target="_blank">¹À·ÖÑ¡´óѧ</a> <a href="http://zhiyuan.edu.sina.com.cn/query/view/" target="_blank">ÍùÄê·ÖÊýÏß</a> <a href="http://zhiyuan.edu.sina.com.cn/default/lesson/" target="_blank">Ö¾Ô¸²Ò°Ü°¸Àý</a></li> - -<!-- -<li><a href="http://open.sina.com.cn/" target="_blank">¹«¿ª¿Î</a></li> -<li><a href="http://edu.sina.com.cn/gaokao/" target="_blank">¸ß¿¼</a></li> -<li><a href="http://edu.sina.com.cn/zxx/" target="_blank">ÖÐСѧ</a></li> -<li><a href="http://edu.sina.com.cn/bschool/" target="_blank">ÉÌѧԺ</a></li> ---> - </ul> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_edu_1" blkclick="auto_nav" blktitle="½ÌÓý"> -<!-- publish_helper name='½ÌÓýÇø¿é-ͼÎÄ' p_id='30' t_id='111' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://edu.sina.com.cn/photo/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U5539P30DT20150618081358.jpg" width="105" height="70" /> - <span>жÈÄïÅÄѧʿ·þÕÕ</span> -</a><ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://edu.sina.com.cn/">ΪÆø³¡Ä¸Ç×»¨10ÍòΪٶù°ìÒôÀÖ»á</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/gaokao/">ÀúÄê¸÷Ê¡¸ß¿¼·ÖÊýÏß</a> <a target="_blank" href="http://edu.sina.com.cn/gaokao/chafen/">Ô¤¹À2015</a></li><li><a target="_blank" href="http://edu.sina.com.cn/college/">¹À·ÖѡУ</a> <a target="_blank" href="http://edu.sina.com.cn/gaokao/2015-06-17/0736473598.shtml">±±¾©Âú·Ö×÷ÎĽ«³¬50ƪ</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/gaokao/bzy/" class="linkRed">¿¼Éú³¬Ò»±¾Ïß71·ÖÂä°ñ</a> <a target="_blank" href="http://zhiyuan.edu.sina.com.cn" class="linkRed">²é·ÖÊýÏß</a></li> -</ul> - </div> - <div class="blk-line"></div> - -<!-- publish_helper name='½ÌÓýÇø¿é-Áбí' p_id='30' t_id='111' d_id='5' --> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://edu.sina.com.cn/kaoyan/">¿ç¿¼Éú²ÒÓö±¯¾ç</a> <a target="_blank" href="http://edu.sina.com.cn/official/2015-06-18/0806473762.shtml">±¨¿¼¹«ÎñÔ±Éí·Ý±»Ã°ÓÃ</a> <a target="_blank" href="http://edu.sina.com.cn/official/">¼ªÁÖÊ¡¿¼ÃæÊÔ</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/a/">ÁôѧÉúÃÀ¹úÂôÈâ¼ÐâÉ</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/0817260908.shtml">ѧ·Ñ×îÖµÃÀ´óѧ</a> <a target="_blank" href="http://edu.sina.com.cn/yimin/">Ï£À°Âò·¿Èý´úÒÆÃñ</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/foreign/">˯¾õÒ²ÄܸßЧ¼Çµ¥´Ê</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/073590292.shtml">¾Ü¾øÀÏÌ×ÃæÊÔ</a> <a target="_blank" href="http://edu.sina.com.cn/yyks/2015-06-18/0738473756.shtml">½âÍи£ÔĶÁ³¤ÄѾä</a></li><li><a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1003473786.shtml">Âí»¯ÌÚÓëÀÏÆÅQQ½áÔµ</a> <a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1106473825.shtml">ÁõÇ¿¶«600ÒÚÄÄÀ´</a> <a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1039473803.shtml">Angelababy×ܲÃ</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/zxx/">10ÐÐΪ×îÉËÍÞ×Ô×ð</a> <a target="_blank" href="http://edu.sina.com.cn/zxx/2015-06-18/0955473782.shtml">±ð±Æº¢×Ó˵¼Ù»°</a> <a target="_blank" href="http://edu.sina.com.cn/zxx/2015-06-18/0836473766.shtml">Äк¢ÄçÍöͬ°é²ØÒÂ</a></li> -<li><a href="http://edu.sina.com.cn/ischool/" target="_blank">ÇîÑøº¢×ÓÓ°ÏìÖÇÁ¦</a> <a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1109473828.shtml">µÏ°ÝÇîÈ˺ÀÕ¬</a> <a target="_blank" href="http://edu.sina.com.cn/zl/">±¾¿ÆÊ®´ó¸ßнְҵ</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_aad920be0102vs5l.html?tj=1">17ËêÅ®Éú±»ÔÞ4000ÄêÄÑÓö(ͼ)</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_afe7c7fe0102vpjr.html?tj=1">²»¿°ÈëÄ¿ÈÕ±¾Å®º¢¹ë·¿</a></li><li><a target="_blank" href="http://open.sina.com.cn/course/id_818/" class="videoNewsLeft">½ÌÄãÍæתÊýѧħÊõ</a> <a target="_blank" href="http://open.sina.com.cn/course/id_1208">º«¹úÁÏÀíÅëâ¿ÈëÃÅ</a> <a href="http://open.sina.com.cn/course/id_1188" target="_blank">·¢ÏÖÐÄÀíѧ</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_edu_2" blkclick="auto_nav" blktitle="³ö¹ú"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='³ö¹úÇø¿é' p_id='30' t_id='111' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://open.sina.com.cn/course/id_304" target="_blank" class="uni-blk-pic"> - -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0611/U9906P30DT20150611114512.jpg" alt="ÐÂÀ˹«¿ª¿Î" width="105" height="70" /> - -<span>ÊÀ½çÃûУ±ÏÒµÑݽ²</span></a> - -<ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://edu.sina.com.cn/a/2015-06-03/1112260472.shtml">ÄãÖªµÀÈçºÎÑ¡ÔñÒÆÃñÖнé»ú¹¹Âð£¿</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1038260920.shtml" target="_blank">ÔÚ°Ä´óÀûÑÇÁôѧÒÔ·¿Ñøѧ¿¿²»¿¿Æ×</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/1055260922.shtml">ÃÀ¹ú12Ëê¾øÖ¢ÉÙÅ®´´·þ×°Æ·ÅÆ(ͼ)</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/104990300.shtml">ͼ½â2100ÄêµÄµØÇò½«ÓжàÈÈ(Ë«Óï)</a></li> -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://edu.sina.com.cn/highschool/">ÃÀ¹úº£ÉÏ¿´Ï¦Ñô±»·ç´µ×ß</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-17/1552260901.shtml">ÂèÂèÇ×Êö£ºÎÒÅã¶ù×Ó¶ÁÃÀ¸ß</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1014260915.shtml" target="_blank">¼ÓÖݹ«Ô¢Â¥Ëú6Ãû°®¶ûÀ¼Ñ§ÉúÉíÍö</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/0823260909.shtml">È«Çò³ÇÊÐÉú»î³É±¾ÅÅÃû</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1046260921.shtml" target="_blank">ÃÀ´óѧУÄÚÐÄÀí¸¨µ¼ÔâÖÊÒÉ</a> <a href="http://edu.sina.com.cn/a/2015-06-18/1011260914.shtml" target="_blank">Ϊº¢×ÓÁôѧº«¹úÏÖ´óÑã¼ÒÍ¥</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/100790294.shtml">ÓÐЧÀûÓÃͼÊé¹Ý</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/100190293.shtml">ÃÀ¹úÈËÊܲ»Á˼ÓÄôó</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/103790298.shtml">Å®×ãÊÀ½ç±­ÈËÆø</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/101490295.shtml">»¥ÁªÍøʱ´ú¹ý¶È×ÔÐÅ</a> <a target="_blank" href="http://m.sina.com.cn/m/sinaopencourse.shtml">¹«¿ª¿Î¿Í»§¶Ë</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/101890296.shtml">10¸öÔñÒµ´íÎóÏë·¨</a></li><li><a target="_blank" href=" http://edu.sina.com.cn/en/2015-06-18/104490299.shtml">¸øÁ¦ÍŶÓÒµ¼¨²»¼ÑÕÕÑùÄý±½ð</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/103390297.shtml">·¬Çѵ½µ×ÊÇË®¹û»¹ÊÇÊß²Ë</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/yyks/2015-06-18/1055473813.shtml">ÑÅ˼ÌýÁ¦¿¼ÊÔÈý´ó²½Öè</a> <a target="_blank" href="http://edu.sina.com.cn/yyks/2015-06-18/1058473818.shtml">GRE×÷ÎÄÖÐArgument¾­µäÄ£°å¾ä</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1004260913.shtml" target="_blank">¶¥¼â¿¼¹Åרҵº£ÍâԺУ</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/1125260926.shtml">ÖйúÂ踰ÃÀ²ú×ÓÓö¡°Ìì¼ÛÕ˵¥¡±</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod44 --> - </div> - <div class="part-o-r"> - <!-- mod45 --> - <div class="uni-blk" id="SI_Order_R" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://baby.sina.com.cn/" target="_blank" suda-uatrack="key=index_www_baby&value=baby_click">Óý¶ù</a></span> - <span tab-type="tab-nav"><a href="http://baby.sina.com.cn/" target="_blank" suda-uatrack="key=index_www_baby&value=childbirth_click">Ôвú</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://baby.sina.com.cn/guide/zhunbei.html" target="_blank">È«³ÌÓý¶ùÖ¸µ¼</a> <a href="http://kid.baby.sina.com.cn/" target="_blank">ÐÂÀ˶ùͯ</a></li> - </ul> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_baby_1" blkclick="auto_nav" blktitle="Óý¶ù"> -<!-- publish_helper name='Óý¶ùÇø¿é' p_id='30' t_id='112' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://baby.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11426P30DT20150618082154.jpg" width="105" height="70" /> - - <span>¼ÒÓжþÌ¥Ã÷ÐÇ</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://baby.sina.com.cn" target="_blank">ÓëÀÏÈËͬס»áÔö¼Ó²úºóÒÖÓô·çÏÕ£¿</a></li> - -<li><a href="http://baby.sina.com.cn/photo/" target="_blank">ͼƬ</a>|<a href=" http://slide.baby.sina.com.cn/bbshai/slide_10_846_28126.html" target="_blank">ÌðÜ°³±×°³ö¾µ</a> <a href="http://slide.baby.sina.com.cn/bbshai/slide_10_846_28213.html" target="_blank">½ÒãÎåºÃ·òÆÞ</a></li> - -<li><a href=" http://slide.baby.sina.com.cn/bbshai/slide_10_846_28214.html" target="_blank">°ÂÀò°ÚÅÄ´ïÈË</a> <a target="_blank" href=" http://slide.baby.sina.com.cn/other/slide_10_846_28180.html">¶íÂÞ˹ѧУÍÞÍÞ±ø</a></li> - -<!--<li><a href="http://talk.baby.sina.com.cn/baby/zrjy/" target="_blank" class="linkRed liveNewsLeft">΢·Ã̸£ºÁÖâù̸½ÌÓýÓ¦ºÜ×ÔÈ»</a></li>--> - -<!--<li><a target="_blank" href="http://talk.baby.sina.com.cn/baby/zhzsz/" class="linkRed liveNewsLeft">ÕÅ˼À³Ì¸Ó¤Ó׿ÆѧιÑøÐÂÖ÷ÕÅ</a></li>--> - -<li><a href="http://baby.sina.com.cn/news/2015-06-18/0816/200868915.shtml" target="_blank">Ó¤¶ù³µÇ¿´î·öÌÝ Á½ÃûÓ¤¶ùÏÕÊÜÉË</a></li></ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://baby.sina.com.cn/z/yebd/" target="_blank">‡N°É</a>| <a href="http://baby.sina.com.cn/news/2015-06-17/1205/120568904.shtml" target="_blank">À­ÅóÓѸøÍÞͶƱÄãÍ·ÌÛÂð</a> <a href="http://baby.sina.com.cn/edu/15/1706/2015-06-17/1226/1226298111.shtml" target="_blank">º¢Í¶¶¾É±È˺öÂÔÁËʲô</a></li> - -<li><a href="http://baby.sina.com.cn/baobao/" target="_blank">ÑøÓý</a>| <a href="http://baby.sina.com.cn/edu/15/0106/2015-06-18/0818/0925297198.shtml" target="_blank">¸ô±²½ÌÓýÔõô×ö</a> <a href="http://baby.sina.com.cn/edu/15/1206/2015-06-18/0818/1051297898.shtml" target="_blank">Óý¶ùÊ®´óÎóÇø</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/2705/2015-06-18/0818/0730296955.shtml">3ËêºóÐèÌ«Ñô¾µÂð</a></li> - -<li> -<a href="http://blog.baby.sina.com.cn/lm/baby/" target="_blank">²©¿Í</a>| -<a href="http://blog.baby.sina.com.cn/s/blog_3e9837d10102vkts.html " target="_blank">Ó׶ùÔ°ÍÞÒª½á»é</a> <a href="http://blog.baby.sina.com.cn/s/blog_44420d270102vnat.html " target="_blank">º¢×Ó³ÔÀ±ÌõÉíÍö</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_615329790102vo67.html ">ÍÁºÀ¼Ò±£Ä·É¶Ñù</a></li> - -<li><a href="http://baby.sina.com.cn/z/nyszd/" target="_blank">רÀ¸</a>| - <a href="http://baby.sina.com.cn/edu/15/1606/2015-06-16/1156/1156298024.shtml" target="_blank">¹ÃÂè±»µ±ÈË··Ôâ´ò</a> <a target="_blank" href="http://baby.sina.com.cn/z/dyqxmbnyddhz/">è°Ö´÷ÓñÇ¿ÓýÅ®</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_ed2ae0770102vokg.html">±¦¸ÃºÈ¶àÉÙË®</a></li> - -<li><a href="http://baby.sina.com.cn/tv/" target="_blank" class="linkRed">GIF </a>| -<a target="_blank" href="http://slide.baby.sina.com.cn/slide_10_846_27082.html#p=1" suda-uatrack="key=baby_ad&value=baby_adclick">ÓÐÄ̲»³ÔÄã·ÇàÜ</a> <a target="_blank" href="http://slide.baby.sina.com.cn/other/slide_10_846_27325.html#p=1 ">½æÄ©ÁñÁ«ÇåÁ¹ÓÍ</a> <a target="_blank" href="http://slide.baby.sina.com.cn/other/slide_10_846_27695.html#p=1 ">ÂèÂèÍü¼Ç³ÔÒ©ÁË</a></li> - -<li><a href="http://club.baby.sina.com.cn/" class="linkRed03" target="_blank">ÂÛ̳</a>| <a href="http://club.baby.sina.com.cn/thread-7336471-1-1.html " target="_blank">¿ÙÃÅÆÅÆÅÕûÌìÂîÎÒ</a> <a href="http://club.baby.sina.com.cn/thread-7336093-1-1.html " target="_blank">ÓöÒ»¼Ò¼«Æ·Õ¦°ì</a> <a target="_blank" href="http://club.baby.sina.com.cn/thread-7335788-1-1.html ">ºÍÉ©×ÓÇÀÆÅÆÅ</a></li> - -<li><a href="http://baby.sina.com.cn/zt/" target="_blank">רÌâ</a>| <a target="_blank" href="http://baby.sina.com.cn/z/muru/ ">Ö°³¡Âè±³ÄÌÈ«¹¥ÂÔ</a> <a target="_blank" href="http://baby.sina.com.cn/z/quwendazhan/">ÏÄÈÕ·ÀÎþøÕÐ</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1606/2015-06-16/1729/1729298041.shtml">±£½£·æ±¨Ï²µ±°Ö</a></li> - -<li><a href="http://baby.sina.com.cn/news/list.html" target="_blank">Èȵã</a>| <a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/200368914.shtml">9ËêÄÐͯÁ³±äÐÎ </a> <a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/183468910.shtml">½ûÖ¹Ó¤¶ù´©¶ú¶´</a> <a target="_blank" href="http://baby.sina.com.cn/ask/15/1706/2015-06-17/1009/1009298088.shtml">»³ÔиÃÖªµÀµÄÊÂ</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_baby_2" blkclick="auto_nav" blktitle="Ôвú"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÔвúÇø¿é' p_id='30' t_id='112' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://slide.baby.sina.com.cn/yjq/slide_10_846_28172.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11426P30DT20150618083814.jpg" width="105" height="70" /> - - <span>»ô˼ÑàÇ××ÓÕÕ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://baby.sina.com.cn/health/15/0206/2015-06-18/0815/0924297277.shtml" target="_blank">˭͵×ßÁËÅ®Ã÷ÐǵÄÉúÓýÄÜÁ¦£¿</a></li> - -<li><a href=" http://slide.baby.sina.com.cn/bbshai/slide_10_846_28092.html" target="_blank">¿á˧µÏ°ÝÃÈÍÞ</a> <a target="_blank" href="http://slide.baby.sina.com.cn/other/slide_10_846_28199.html">ÉúÄк¢²»¼ªÀû²¿Âä</a></li> - -<li><a href=" http://slide.baby.sina.com.cn/other/slide_10_846_28208.html" target="_blank">¶À±Û³åÀËÂè²ú×Ó</a> <a href=" http://slide.baby.sina.com.cn/mxx/slide_10_846_28215.html" target="_blank">¿¨´÷ɺΪº¢ÇìÉú</a></li> - -<!--<li><a target="_blank" href="http://talk.baby.sina.com.cn/baby/yyewy/" class="linkRed liveNewsLeft">ÓªÑøר¼Ò̸ӤÓ׶ùιÑøÖ¸µ¼</a></li>--> - -<li><a href="http://baby.sina.com.cn/news/2015-06-12/1203/120368858.shtml" target="_blank">СÂÜÀòËÍÄÌÄ̼Ҽ¸¸öÔºó´ò±äÉí£¡</a></li></ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://baby.sina.com.cn/health/15/1006/2015-06-18/0841/0807297715.shtml" target="_blank">Öκø¾¿Æ²¡ÔÙ±¸ÔÐ</a> <a href="http://baby.sina.com.cn/health/15/1006/2015-06-18/0841/0910297725.shtml" target="_blank">±¸ÔаְֵıØɱ¼¼</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1006/2015-06-17/0820/0821297717.shtml">¹¬ÍâÔÐÄܲ»ÄÜÔ¤·À</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1606/2015-06-18/0843/1045298017.shtml" target="_blank">Á÷²úºóÒªÁ¢¼´±ÜÔÐ</a> <a href="http://baby.sina.com.cn/health/15/1606/2015-06-18/0843/1424298025.shtml" target="_blank">Æʹ¬²ú²¢·Ç½Ý¾¶</a> <a href="http://baby.sina.com.cn/health/15/1606/2015-06-18/0843/1430298027.shtml" target="_blank">·ÖÃäÇ°Ò׺öÊӵŤ×÷</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1706/2015-06-18/0844/1118298106.shtml" target="_blank">²úºóµÚÒ»²Í³Ôʲô</a> <a href="http://baby.sina.com.cn/health/15/1706/2015-06-18/0844/1119298107.shtml" target="_blank">²úºó×¢ÒâÒâÍ⻳ÔÐ</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1706/2015-06-18/0844/1121298108.shtml">ʲôµ¼Ö²úºóÒÖÓô</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1206/2015-06-18/0845/0742297860.shtml" target="_blank">С¶ùѪÓѲ¡Ôç·¢ÏÖ</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1206/2015-06-18/0845/0745297861.shtml">±¦±¦ÒâÍâÌÌÉËĪ»Å</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1206/2015-06-18/0845/0750297862.shtml">ÈçºÎ»¤Àí¿ÚË®±¦±¦</a></li> - -<li><a href="http://blog.baby.sina.com.cn/s/blog_5cb098ae0102vn08.html " target="_blank">»³ÔÐ4ÔÂÐÄÇéµøå´</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_7285b5180102vnnb.html ">¶à´ÎÌ¥¼à²âÊÔÏÅ»µÎÒ</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_768113ef0102voxf.html ">ĸÈéιÑøÓÐÈý¼É</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1206/2015-06-12/1153/1153297908.shtml" target="_blank">Å®ÓѱÆ×ÅÔìÈËÔõ°ì</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1606/2015-06-16/1729/1729298041.shtml">±£½£·æ±¨Ï²µ±°Ö°Ö</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_82b859870102wcmm.html?tj=1">±»±Æ³öÀ´µÄ»¢Âè</a></li> - -<li><a target="_blank" class="videoNewsLeft" href="http://video.baby.sina.com.cn/p/baby/v/2015-06-18/001365026543.html">B³¬¼ì²éÓ°ÏìÌ¥¶ù½¡¿µ?</a> <a target="_blank" href="http://video.baby.sina.com.cn/p/baby/v/2015-06-18/001365026545.html">º¢×Ó·¢ÉÕÄܾ­³£Ê¹ÓÃÍ·æßÂð</a></li> - -<li><a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/195468913.shtml">·¶Ò¯»ØÓ¦¾ÈÄÐͯ·ç²¨</a> <a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/193968912.shtml">ÀîСÅôÀíÐÔ½Ì×Ó</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1506/2015-06-15/1352/1352297970.shtml">´óS²úºóÔõÊÝÉí</a></li> - - </ul> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod45 --> - </div> - </div> - <!-- part-o end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-p begin --> - <div class="part-p"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸05¹ã¸æ begin --> -<div id="ad_46022" class="mb25"><ins class="sinaads" data-ad-pdps="PDPS000000056034"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸05¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- part-p end --> - <!-- part-q begin --> - - <div class="part-q clearfix"> - <div class="part-q-l"> - <!-- mod46 --> - <div class="mod-02"> - <div class="tit02"><h3><a target="_blank" href="http://fashion.sina.com.cn/">ʱÉÐÈȵã</a></h3></div> - <div style="height:8px;" class="blank-cont"></div> - <div class="mod22-cont clearfix" data-sudaclick="blk_fashion_ssrd" blkclick="auto_nav" blktitle="ʱÉÐÈȵã"> -<!-- publish_helper name='ʱÉÐÈȵã' p_id='30' t_id='110' d_id='6' --> -<div class="xb-mod22-cont-pa"><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60851.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U5790P30DT20150618102211.jpg" width="220px" height="160px" /><span>ÉÏ°ëÄê×îÇ¿¼¡ÈâÄÐÐǽÖÅÄ</span></a></div><div style="height:5px" class="blank-d"></div><ul class="list-b list-c" style="padding-bottom:7px;"> - -<li><a target="_blank" href="http://fashion.sina.com.cn/s/in/2015-06-18/0733/doc-ifxczqap4215744.shtml">¼¯Æë10¸öÆ·ÅÆ ¿ÉÔÚÃ×À¼ÄÐ×°ÖÜÕÙ»½ÏÊÈâ</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/b/mk/2015-06-17/0649/doc-ifxczqar0953508.shtml">ÁøÑÒÆØËØÑÕ£¿ ÈÃÖ±ÄÐÉϵ±Â̲è×±³¤ÕâÑù</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/d/ft/2015-06-18/0734/doc-ifxczqan1552426.shtml">¸úùùһÆðÒ²OK ÅÖÃÃÈüÁÕÄȾ¹ÊÝ»ØÀ´ÁË</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/l/ts/2015-06-18/0756/doc-ifxczyze9588267.shtml">Éà¼âÉϵÄÓÕ»ó</a> <a target="_blank" href="http://fashion.sina.com.cn/l/ts/2015-06-18/0757/doc-ifxczqap4209837.shtml">ÆßÖÖÄã²»ÖªµÀµÄºÃ³ÔÌðÆ·</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/w/ho/2015-06-18/0753/doc-ifxczqap4211261.shtml">³ö·¢£¡2016Ê®´óÀËÂþÃÛÔÂÊ¥µØÅ̵ã</a></li></ul> - </div> - </div> - <!-- mod46 --> - </div> - <div class="part-q-m"> - <!-- mod47 --> - <div class="uni-blk" id="SI_Order_S" tab-type="tab-wrap" struc="1-4"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://fashion.sina.com.cn/" target="_blank">ʱÉÐ</a></span> - <span tab-type="tab-nav"><a href="http://fashion.sina.com.cn/photo/" target="_blank">ÊÓ¾õ</a></span> - - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_fashion_1" blkclick="auto_nav" blktitle="ʱÉÐ"> -<!-- publish_helper name='ÉÐÆ·Çø¿é' p_id='30' t_id='113' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://fashion.sina.com.cn/" target="_blank" class="uni-blk-pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U8586P30DT20150618101815.jpg" width="105" height="70" /> - - <span>±´°ÖСÆßÓа®Ë²¼ä</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://fashion.sina.com.cn/" target="_blank" class="linkRed01">̺ÐÇÍËÏ Áõ¼ÎÁáºÍÅ®ÍõÈ¥¿´ÂíÁË</a></li> - -<li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>|<a target="_blank" href="http://fashion.sina.com.cn/2015-06-18/0727/doc-ifxczqap4213453.shtml" class="linkRed01">¾Ý˵µÁĹ±Ê¼ÇºÃ¿´µÄÖ»ÓÐÑÕ</a></li> - -<li><a href="http://fashion.sina.com.cn/style/" target="_blank">ʱÉÐ</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60856.html" class="linkRed01">³ôÁ³Íõ×ÓСÇÇÖÎÏÓÆú±íÇé°ü</a></li> - -<li><a href="http://fashion.sina.com.cn/try/" target="_blank">ÊÔÓÃ</a>|<a target="_blank" href="http://fashion.sina.com.cn/try/product/1053" class="linkRed01">Òü¶÷»Ý×ŷÀ³ÑÅ»¤·¢Ì××°</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://fashion.sina.com.cn/style/" target="_blank" class="linkRed01">ʱװ</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60860.html#p=1" class="linkRed01">17ËêÏÊÈâ¿´Ðã</a> - -<a target="_blank" href="http://fashion.sina.com.cn/s/ce/2015-06-18/0740/doc-ifxczyze9671552.shtml" class="linkRed01">ÌÆæÌ´óÅÆÏÞÁ¿°ü</a> <a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60819.html#p=1" target="_blank" class="linkRed01">Å£×пã¸ã¶¨¿Ë³Äá</a></li> - -<li><a href="http://fashion.sina.com.cn/beauty/" target="_blank" class="linkRed01">ÃÀÈÝ</a>|<a target="_blank" href="http://fashion.sina.com.cn/b/mk/2015-06-18/0734/doc-icrvvqrf4562993.shtml" class="linkRed01">ÕâЩŮÉñ¾ÓÈ»ÊÇͬ°àͬѧ</a> <a target="_blank" href="http://fashion.sina.com.cn/b/ha/2015-06-18/0737/doc-ifxczqar0989595.shtml" class="linkRed01">¿ÕÆøÁõº£outÐÄÐÎÁõº£ÉÏ</a></li> - -<li><a href="http://fashion.sina.com.cn/body/" target="_blank">ÃÀÌå</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/d/slide_24_66332_60858.html#p=1" class="linkRed01">³£±»Îó½âµÄ7ÖÖ½¡¿µÊ³Æ·</a> -<a target="_blank" href="http://fashion.sina.com.cn/d/he/2015-06-18/0751/doc-ifxczyze9671160.shtml" class="linkRed01">6ÖÖʳÎï°ïÄã˦µô±ãÃØ</a></li> - -<li><a href="http://fashion.sina.com.cn/luxury/" target="_blank">ÉÐÆ·</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60818.html#p=1" class="linkRed01">¸¸Ç×½ÚΪ°Ö°Ö×öµÀϾƲË</a> -<a target="_blank" href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60830.html" class="linkRed01">ÒÉËÆÄ̲èÃÃÃúÀÕ¬Æعâ</a></li> - -<li><a href="http://fashion.sina.com.cn/wedding/" target="_blank">»é¼Þ</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/w/slide_24_66152_60841.html#p=1" class="linkRed01">Èðµä»ÊÊÒ»éÀñÉϵľøÃÀÀñ·þ</a> -<a href="http://slide.fashion.sina.com.cn/w/slide_24_66152_60743.html#p=1" target="_blank" class="linkRed01">É¢·¢×ÅÅ®ÈËÏãµÄ»éÉ´</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/column/">רÀ¸</a>|<a href="http://fashion.sina.com.cn/zl/fashion/2015-06-17/14103784.shtml" target="_blank" class="linkRed01">20¸öÇÏÃÅÈÃÄãʱÉиüʱÉÐ</a> -<a href="http://fashion.sina.com.cn/zl/beauty/2015-06-17/15053787.shtml" target="_blank" class="linkRed01">¿´±´É©½ÖÅÄѧְ³¡·¢ÐÍ</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/photo/">ͼ¿â</a>|<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60787.html#p=1" target="_blank" class="linkRed01">Ö£ÖݻƽðÄÚÒÂÄÚ¿ãÐã</a> -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60783.html#p=1" target="_blank" class="linkRed01">Âê¸êÂޱȾüÂ̱³´øÈÈ¿ã</a></li> - </ul> - </div> - - <div tab-type="tab-cont" style="display:none;" data-sudaclick="blk_fashion_2" blkclick="auto_nav" blktitle="ÊÓ¾õ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÊÓ¾õÇø¿é' p_id='30' t_id='110' d_id='5' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60752.html" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0616/U5790P30DT20150616093757.jpg" width="105" height="70" /> - - <span>·ÆÀûÆÕÍõ×Ó½á»éÕÕ</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| <a href="http://slide.fashion.sina.com.cn/slide_24_60018_60755.html" target="_blank" class="linkRed01">·¶ÎÄ·¼Êܳè16ÄêÉÙÅ®ÐÄδ±ä</a></li> - - <li><a href="http://eladies.sina.com.cn/news/" target="_blank">»¨±ß</a>| <a href="http://eladies.sina.com.cn/news/star/2015-05-15/0758/doc-iawzuney5569497.shtml" target="_blank">СSɹ×ÔÅÄÒÉÏÖ¡°Ñ¹Á¦Íº¡±</a></li> - - <li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| <a href="http://slide.fashion.sina.com.cn/slide_24_60018_60754.html" target="_blank" class="linkRed01">±±¾©¸ßУģÌرÈÆ´ÐÔ¸ÐÓ¾×°</a></li> - <li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>| <a href="http://fashion.sina.com.cn/beauty/" target="_blank" class="linkRed01">ÕÔÀöÓ±±äÐÂÒ»´úÄÐÉñÊÕ¸î»ú</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60750.html" target="_blank" class="linkRed01">ÍþÁ®¹þÀï½á°é´òÂíÇò</a> -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60753.html" target="_blank" class="linkRed01">´óѧÉúº£±ßÅÄÉã¸öÐÔ±ÏÒµÕÕ</a></li><li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| - - <a target="_blank" href="http://slide.fashion.sina.com.cn/slide_24_60018_60751.html" class="linkRed01">ÃÀÖÞ±­ÔÙÏÖÈéÉñ</a> <a target="_blank" href="http://slide.fashion.sina.com.cn/slide_24_60018_60749.html" class="linkRed01">±ÈÀûʱʾÍþÕß¡°ÌÉʬ¡±½ÖÍ·</a></li><li><a href="http://fashion.sina.com.cn/style/" target="_blank">ʱÉÐ</a>| -<a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60851.html#p=1" target="_blank" class="linkRed01">ÉÏ°ëÄê×îÇ¿¼¡ÈâÄÐÐǽÖÅÄ</a> -<a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60827.html#p=1" target="_blank" class="linkRed01">¾®±¦Í·´÷ÍÞÍÞñÂôÃÈ</a></li><li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>| -<a href="http://fashion.sina.com.cn/b/mk/2015-06-17/1501/doc-ifxczqap4209704.shtml" target="_blank" class="linkRed01">·¨¹úÅ®È˵ÄÓÅÑÅÃؼ®</a> -<a href="http://fashion.sina.com.cn/b/ha/2015-06-17/0703/doc-ifxczqar0757654.shtml" target="_blank" class="linkRed01">GAGA½ã¸ßÄÜÐü¸¡±èÁÁÁË</a></li><li><a href="http://fashion.sina.com.cn/body/" target="_blank">ÃÀÌå</a>| - <a href="http://fashion.sina.com.cn/d/ta/2015-06-18/0737/doc-ifxczqap4209515.shtml" target="_blank" class="linkRed01">Ï붴ó°×ÍÈ£ºÏ¥¸Ç¹»°×Âð</a> - <a href="http://fashion.sina.com.cn/d/he/2015-06-18/0752/doc-ifxczqap3911284.shtml" target="_blank" class="linkRed01">´©Ì«¶ÌСÐÄÁ½ÖÖ²¡</a></li><li><a href="http://fashion.sina.com.cn/luxury/" target="_blank">ÉÐÆ·</a>| -<a href="http://fashion.sina.com.cn/l/ds/2015-06-18/0758/doc-ifxczqan1557752.shtml" target="_blank" class="linkRed013">ÉñÃØŲÍþ ²»Ö»¼«¹â</a> -<a href="http://fashion.sina.com.cn/wedding/" target="_blank">»é¼Þ|</a> -<a href="http://slide.fashion.sina.com.cn/w/slide_24_66152_60149.html#p=1" target="_blank" class="linkRed01">˽È˶©ÖÆÄãµÄ»éÀñ</a></li><li><a target="_blank" href="http://fashion.sina.com.cn/zl/">רÀ¸</a>| -<a target="_blank" href="http://fashion.sina.com.cn/zl/fashion/blog/2015-06-12/15263753/1188369822/46d5159e0102vqni.shtml" class="linkRed01">´òÔ취ʽ·çÇéµÄʱÉÐÒªËØ</a> - -<a target="_blank" href="http://fashion.sina.com.cn/zl/style/2015-06-15/14403761.shtml" class="linkRed01">²ÌÀ½:¶ËÎç³ÔʲôôÕ×ÓºÃ</a></li> - </ul> - </textarea> - </div> - -<!--whs--> - - </div> - </div> - </div> - <!-- mod47 --> - </div> - <div class="part-q-r"> - <!-- mod48 --> - <div class="uni-blk" id="SI_Order_T" tab-type="tab-wrap" struc="1-4"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://travel.sina.com.cn/" target="_blank">ÂÃÓÎ</a></span> - <span tab-type="tab-nav"><a href="http://photo.weibo.com/welcome/hot?from=sina" target="_blank">Ïà²á</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_travel_1" blkclick="auto_nav" blktitle="ÂÃÓÎ"> -<!-- publish_helper name='ÂÃÓÎÇø¿é' p_id='30' t_id='116' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://weibo.com/p/1001603854451369721970" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U10184P30DT20150618100710.jpg" width="105" height="70" /> - - <span>Îâ¸ç¿ß Õæ°®ÓÀºã</span> - </a><ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://weibo.com/p/1001603853199063809686">×îÃÀº£±õͽ²½µÀ ÓÌÈçÌìÌÃÖÐÂþ²½</a></li> - -<li><a href="http://weibo.com/p/1001603853939245237145" target="_blank">ËÕ¸ñÀ¼µÄÀä¿áÏɾ³ ±¥ÀÀ¾«»ªËùÔÚ</a></li> - -<li><a href="http://weibo.com/p/1001603854028139289130" target="_blank">´øן¢×ÓÂÃÐÐ ³¤³ÇÉϵıðÑùͯÄê</a></li> - -<li><a href="http://travel.sina.com.cn/china/2015-06-10/1703308514.shtml" target="_blank">¿áÊîÏ®À´ ÔÚ¸£ÖÝÍæË®µÄNÖÖ×ËÊÆ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://travel.sina.com.cn/lvyou/">¹úÄÚ|</a> <a target="_blank" href="http://travel.sina.com.cn/china/2015-05-22/1510307277.shtml">ʯ÷Íå·Ç³ÏÎðÈŵÄÃÀ¾°</a> <a target="_blank" href="http://travel.sina.com.cn/china/2015-06-02/1205307997.shtml">Õâ¸ö¸¸Ç×½Ú°Ö°ÖÈ¥ÄĶù</a></li><li><a target="_blank" href="http://travel.sina.com.cn/lvyou/">³ö¾³|</a> <a target="_blank" href="http://weibo.com/p/1001603853969347754469">°Â¿ËÀ¼ºÚɳ̲¡°Ìì¿ÕÖ®¾µ</a> <a href="http://weibo.com/p/1001603853762841175626 " target="_blank">ÈÕ±¾Á­²Ö÷Óê¼¾ÉÍ»¨</a></li><li><a target="_blank" href="http://data.travel.sina.com.cn/quanbu-remen/">¿ìѶ|</a> <a target="_blank" href="http://travel.sina.com.cn/world/2015-06-17/1650308995.shtml ">ÊîÆÚÐÞѧÓÎÉýÎÂ</a> <a target="_blank" href="http://travel.sina.com.cn/world/2015-06-17/1652308996.shtml ">Ç©Ö¤ÀûºÃÊîÆÚ³ö¾³ÓÎÔ¤¶©»ð±¬</a></li> -<li><a target="_blank" href="http://vi.travel.sina.com.cn/">ÀÖÏí|</a> <a target="_blank" href="http://slide.travel.sina.com.cn/slide_68_57328_26874.html">Å·ÖÞ&quot;¾ÅÕ¯¹µ&quot;</a> <a target="_blank" href="http://slide.travel.sina.com.cn/slide_68_57328_26829.html">¿¦À­¾þ²ÝÔ­</a> <a target="_blank" href="http://slide.travel.sina.com.cn/slide_68_57328_26535.html">åüÃÄÑÌÓêÑ°½­ÄÏ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/lm/travel/">ÓμÇ|</a> <a href="http://blog.sina.com.cn/s/blog_6960d5f00102w3qs.html?tj=1" target="_blank">ϤÄáºì·ãÁÖ</a> <a href="http://blog.sina.com.cn/s/blog_7533c52c0102vxs2.html?tj=1" target="_blank">×íÃÀÎ÷ɳȺµº</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_7170ab0e0102vpe6.html?tj=1">ÐÁÌØÀ­Í¯»°Ãξ³</a></li><li><a target="_blank" href="http://weibo.com/tourer">»°Ìâ|</a> <a href="http://weibo.com/p/100808a09c808bb9b07843dbc9cab00a1991b7" target="_blank">#±ÏÒµÒ»Æð×ß#</a> <a target="_blank" href="http://weibo.com/p/10080861d7f53499e7dbe8c2422506dbceaa2c">#ÎÒÃÇ°®ÂÃÐÐ# </a> <a href="http://weibo.com/p/1008081598a5d7a224485db4e04b77899db798?k=%E5%86%8D%E4%B8%8D%E7%8E%A9%E5%B0%B1%E8%80%81%E4%BA%86&from=501&_from_=huati_topic" target="_blank">#ÔÙ²»Íæ¾ÍÀÏÁË#</a></li><li><a target="_blank" href="http://travel.sina.com.cn/">ÕÐļ|</a> <a href="http://weibo.com/1502844527/BAsrla37a?type=comment#_rnd1419168392865" target="_blank">Ãû²©ÁìÖ÷ËÙËÙ±¨Ãû</a> <a target="_blank" href="http://travel.sina.com.cn/z/dayulieren/">ÎÒÒªµ±ÁÔÈË</a> <a target="_blank" href="http://travel.weibo.com/">Íæ±éÌ©¹ú³ÔסÐÐ</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none;" data-sudaclick="blk_photo_1" blkclick="auto_nav" blktitle="Ïà²á"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='Ïà²áÇø¿é' p_id='30' t_id='115' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://photo.weibo.com/welcome/hot?from=sina" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0402/U8580P30DT20150402153323.png" width="105" height="70" /> - - <span>΢ЦÊÇÇ×ÇеÄÓïÑÔ</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://weibo.com/p/1038030002_874?from=sina&x=10" target="_blank">ÎÒΪÊÓƵ¿ñ ·Ö·ÖÖÓÈÃÄãàË·­Ìì</a></li> - -<li><a href="http://photo.weibo.com/events/pictag?from=sina&x=1" target="_blank">΢²©ÏÖÔÚ¿ÉÒÔ¸øÕÕƬÉÏ´ò±êÇ©à¶</a></li> - -<li><a href="http://weibo.com/p/1008083fd4566a4b5554651ac1b1156ac4e7d7?from=sina&x=2" target="_blank" class="linkRed">ÅÄÉí±ß#´ºÉ«# Õùµ±È«ÃñÉãӰʦ</a></li> - -<li><a href="http://weibo.com/1962310741/C9t5n5SjZ?from=sina&x=2" target="_blank">ÐÒ¸£²»ÊÇŬÁ¦È¥°® ¶øÊÇ°²ÐÄÉú»î</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://weibo.com/1962310741/CbjyxomhR?from=sina&x=3" target="_blank">¹ý×Ô¼ºµÄÈËÉú ÐÄÀï×°ÂúÁË°®</a> <a href="http://weibo.com/1962310741/Cbi1a0hV0?from=sina&x=3" target="_blank">Ëæ×Å·ç×ÔÓÉÔÚ·çÖпñÎè</a></li> - -<li><a href="http://weibo.com/1962310741/Cb4Sr6ZGT?from=sina&x=4" target="_blank">Ã÷ÐÇÑÛÖеĴºÉ«ÊÇÔõÑùµÄ</a> <a href="http://weibo.com/1962310741/Cb0HyiroA?from=sina&x=4" target="_blank">¶ùʱµÄ»¶ÀÖÊÇ×îµ¥´¿ÐÒ¸£</a></li> - -<li><a href="http://weibo.com/1962310741/CaZaajHiL?from=sina&x=5" target="_blank">̧ÆðÍ·ÑöÍûÀ¶ÌìÉîºôÎü</a> <a href="http://weibo.com/1962310741/CaXv6z3fU?from=sina&x=5" target="_blank">´ºÌìÎÒÁ÷À˹ýµÄµØ·½ËêÔ¼«ÃÀ</a></li> - -<li><a target="_blank" href="http://weibo.com/1962310741/CbpgGwBmo?from=sina&x=6">´ò¿ªÐÄÃÅ¿´¼ûÕû¸öÊÀ½ç</a> <a target="_blank" href="http://weibo.com/1962310741/CaQQ68oa3?from=sina&x=6">²»Öª²»¾õÂúÔ°´ºÉ«ÕÀ·ÅÃÀÈç»­</a></li> - -<li><a href="http://weibo.com/1962310741/CaBN61tls?from=sina&x=7" target="_blank">Ö»Ïë½øÐÐÒ»³¡ÂþÎÞÄ¿µÄµÄÂÃÐÐ</a> <a href="http://weibo.com/1962310741/Ca056BkYk?from=sina&x=7" target="_blank">ÏëÄîÄÏ·½µÄ´ºÉ«»¨º£</a></li> - -<li><a href="http://weibo.com/1962310741/CaclibPqq?from=sina&x=8" target="_blank">ÄÇÀﶼÊÇÎÒ¸ÃÈ¥µÄµØ·½</a> <a href="http://weibo.com/1962310741/Ca2Oqh3zQ?from=sina&x=8" target="_blank">Óε´ÊÀ½ç¸÷µØÊÕ¼¯ÆßÉ«º£Ì²</a></li> - -<li><a href="http://weibo.com/1962310741/CasmBrThq?from=sina&x=9" target="_blank">Ò»±­Çå²èÁ½ÏàÍû Çã³ÇÑÕ Ò÷ÝóÝç</a> <a href="http://weibo.com/1962310741/C9LWmtzng?from=sina&x=9" target="_blank">ϦÑôÓà»ÔϵÄËÕ×È´ï¶û</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod48 --> - </div> - </div> - <!-- part-q end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-r begin --> - - <div class="part-r clearfix"> - <div class="part-r-l"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x330 1ÂÖ²¥°´Å¥09¹ã¸æ begin --> -<div id="ad_46023" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046023"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x330 1ÂÖ²¥°´Å¥09¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <div class="part-r-m"> - <!-- mod49 --> - <div class="uni-blk" id="SI_Order_U" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://collection.sina.com.cn/" target="_blank">ÊÕ²Ø</a></span> - <span tab-type="tab-nav"><a href="http://golf.sina.com.cn/" target="_blank">¸ß¶û·ò</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_collection_1" blkclick="auto_nav" blktitle="ÊÕ²Ø"> -<!-- publish_helper name='ÊÕ²ØÇø¿é' p_id='30' t_id='117' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://collection.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U5083P30DT20150618091151.jpg" width="105" height="70" /> - - <span>èó¸ßÓÍ»­Êä¸øʱ¼ä</span> - - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://collection.sina.com.cn/yshq/20150618/0812189291.shtml" target="_blank" class="linkRed">×ÏÉ°ºøµÚÒ»¹ÉÁ¬ÐøÕÇÍ£ÈÇÕùÒé</a></li> - -<li><a href="http://collection.sina.com.cn/cjrw/20150618/0731189282.shtml" target="_blank">Áξ²ÎÄ£ºÒ»ÉúÊغòÐ챯ºè</a></li> - -<li><a href="http://collection.sina.com.cn/yjjj/20150618/0818189293.shtml" target="_blank">¹Ê¹¬¿ÍÁ÷¶¯Ì¬Ô¤¾¯2016ÄêÆôÓÃ</a></li> - -<li><a href="http://collection.sina.com.cn/cqty/20150618/0725189281.shtml" target="_blank">õ·Áê´É¼Û¸ñÉÏÕÇ ÒÕÊõ´ÉÓпռä</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/cqyw/index.shtml">¾Û½¹|</a> <a target="_blank" href="http://collection.sina.com.cn/yjjj/20150618/0705189277.shtml" class="linkRed">̨±±¹Ê¹¬ÄÏÔº½«¿ª¹ÝÊÔÓªÔË ºÄ×ʽü80ÒÚÐĄ̂±Ò</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/plfx/index.shtml">ÆÀÂÛ|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0741189284.shtml">Ǯѡ¼û¹ý¡¶Ïª°¶Í¼¡·Âð</a> <a target="_blank" href="http://collection.sina.com.cn/jczs/20150617/1641189267.shtml">°×½¶ÍíÄêÊé·¨ÊÖ¸åÓиÐ</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/jczs2/index.shtml">¼ø²Ø|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0746189286.shtml">ÄÏä±Ò»ÃÅÈý´úËÄ²Ø¼Ò </a> <a target="_blank" href="http://collection.sina.com.cn/cjrw/20150618/0736189283.shtml">Ê黭ֵǮÁËÎÒÈ´¸ü¹Â¶À</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/jczs2/index.shtml">Òµ½ç|</a> <a target="_blank" href="http://collection.sina.com.cn/zgsh/20150618/0815189292.shtml">Êé·¨¾¿¾¹ÊôÒÕ»¹ÊÇÊôѧ</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150617/1649189268.shtml">µ±ÒÕÊõ´´×÷±ä³ÉÒÕÊõÉú²ú</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/yjjj/index.shtml">Òµ½ç|</a> <a target="_blank" href="http://collection.sina.com.cn/zgsh/20150618/0708189278.shtml">Åþ¬Ë±ڻ­±£»¤¿Ì²»ÈÝ»º</a> <a target="_blank" href="http://collection.sina.com.cn/cqyw/20150618/0823189294.shtml">ÁÖ»ÕÒòÓë¾°Ì©À¶µÄÇéÔµ</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/cqyw/index.shtml">¹Ø×¢|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0754189288.shtml">°üºÀ˹²ØÆ·½»Ò×ʼĩ </a> <a target="_blank" href="http://collection.sina.com.cn/auction/pcdt/20150618/0702189276.shtml">³ÂÄËǬ´æÁôÐÅÔýÁÁÏàÅij¡</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/hwdt/index.shtml">Õ¹ÀÀ|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0745189285.shtml">²ßÕ¹È˳ÂÂÄÉú£ºÇ¶ÈëʽչÀÀ·½Ê½ÊÇÀϲ©Îï¹ÝÉú»ú</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none;" data-sudaclick="blk_golf_1" blkclick="auto_nav" blktitle="¸ß¶û·ò"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¸ß¶û·òÇø¿é' p_id='30' t_id='101' d_id='11' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.sports.sina.com.cn/golf/slide_2_754_82711.html/d/8#p=1" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0602/U12660P30DT20150602125929.jpg" height="70" width="105" /> - - <span>СÂóÓëÐÂÅ®ÓÑÐã¶÷°®</span> - - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://sports.sina.com.cn/golf/2015usopengolf/" target="_blank">ÃÀ¹ú¸ß¶û·ò¹«¿ªÈü22ʱ¿ª´ò</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/02077636924.shtml" target="_blank">ÃÀÁª£ºÇ°ÇòÍõÎé×È´¿Êô×ÔÆÛÆÛÈË</a></li> - -<li><a href="http://sports.sina.com.cn/golf/pgatour/2015-06-18/doc-ifxehfqi8029184.shtml" target="_blank">Îé×ȱ»ÆØÓûÓëÇ°ÆÞÖØÐ޾ɺÃ</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/09307637052.shtml" target="_blank">ÃÀ¹ú¹«¿ªÈü½±½ðÉýÖÁǧÍòÃÀÔª</a></li> - -</ul> - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/08557637009.shtml" target="_blank" >ËûÊÇÃÀ¹ú¹«¿ªÈüÖ÷Ô× Ë­ÄÜÌÓÍÑ£¿</a> <a href="http://sports.sina.com.cn/golf/2015-06-18/09207637036.shtml" taret="_blank">¼ÓÄôóÇòÔ±ÌôÐÆ´÷ά˹</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/10317637143.shtml" target="_blank">ÃÀ¹ú¹«¿ªÈüµ½Î÷ÑÅͼ¶à»ð£¿</a> <a href="http://sports.sina.com.cn/golf/2015-06-18/10237637114.shtml" target="_blank" >Ç®²®Ë¹Íå´òÇòʱ¼ä»ò´ï6Сʱ</a></li> - -<li><a href="http://slide.sports.sina.com.cn/golf/slide_2_754_83548.html?img=1526208#p=3" target="_blank" class="ideoNewsLeft linkRed01">¸ßÇå-Îé×ÈÃæ¶ÔС°×Çò¶àÑù±íÇé</a> <a href="http://sports.sina.com.cn/golf/2015-06-18/10287637122.shtml" target="_blank">ÅÁ¶ûĬ£ºËûÓÐÄÜÁ¦ÔÙ»ØÀ´</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/03487636934.shtml" target="_blank">ÃÀ¹ú¹«¿ªÈüÓн±¾º²Â</a> <a href="http://slide.sports.sina.com.cn/golf/slide_2_754_83388.html" target="_blank" >18¶´ÇòµÀͼ</a> <a href="http://sports.sina.com.cn/golf/2015-06-16/doc-ifxczqar0962995.shtml" target="_blank" class="ideoNewsLeft linkRed01">¶á¹ÚÅâÂÊ</a> <a href="http://sports.sina.com.cn/golf/2015-06-14/21087634516.shtml" target="_blank">19µÀ¿¼Ìâ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/golf/2015-06-17/14437636684.shtml">Óà¸Ö£ºÃÀ¹ú¹«¿ªÈüÒòºÎΪǮ²®Ë¹Íå¡°»µ¡±¹æ¾Ø </a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/golf/2015-06-18/07587636971.shtml">ÃÀ¹ú¹«¿ªÈüµÄÁ½ÕÅ»ªÈËÃæ¿×£ºÁºÎijåÓëÅËÕþçý¼ûÃæ</a></li> - -<li><a href="http://sports.sina.com.cn/golf/blog/" target="_blank">²©¿Í</a>-<a href="http://blog.sina.com.cn/s/blog_4bcff9240102vqtp.html?tj=1" target="_blank">ÔÙ»áÁË Ê®ÈýÁêÇò³¡</a> <a href="http://blog.sina.com.cn/s/blog_66f24f360102vpbe.html?tj=tiyu" target="_blank">±£Àû36¶´£¬À϶ÎÅã´ò¡£</a></li> - - </ul> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod49 --> - </div> - <div class="part-r-r"> - <!-- mod50 --> - <div class="uni-blk" id="SI_Order_V" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://health.sina.com.cn/" target="_blank">½¡¿µ</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_health_1" blkclick="auto_nav" blktitle="½¡¿µ"> -<!-- publish_helper name='½¡¿µÇø¿é' p_id='30' t_id='118' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/s/blog_b8b22a140102w1ag.html?tj=1" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U5307P30DT20150618113217.bmp" width="105" height="70" /> - -<span>È«Çò×ÃÀÉí²Ä</span> - - </a><ul class="uni-blk-list01 list-a"><li><a href="http://health.sina.com.cn/" target="_blank" class="linkRed">3ÏîÖ¸±ê²âÊÙÃü</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_a554c60c0102vl28.html?tj=1">»ëÉíÊÇÒ©µÄ´óÖÚ²Ë</a></li> - -<li><a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173024.shtml">ÄÐÈ˱ر¸3ÖÖ»¤¸Î²è</a> <a target="_blank" href="http://health.sina.com.cn/hc/m/2015-06-18/0734173025.shtml">ºÃÉ«Å®ÈËÌØÕ÷</a></li> - -<li><a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173021.shtml">ÓÐÕâÖÖðëÊǸβ¡</a> <a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173017.shtml">ºÈ¶àÉپƻáÖ°©</a></li> - -<li><a href="http://blog.sina.com.cn/lm/health/" target="_blank">ÁùÖÖÅ®ÈËÒ׳ö¹ì</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_13c4a419c0102vtpw.html?tj=1">˯ǰ×öɶ»á¶ÌÃü</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><span style="color: #0c0000;"><a href="http://health.sina.com.cn/tiaoshi/" target="_blank">Ìôʳ</a></span>|<a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173029.shtml">3Öֲ˷À°©ÆæºÃ</a> <a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173027.shtml">ɽҩÊÇ×îºÃµÄ²¹Æ·</a> <a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173030.shtml">ºìÔæ×îÑø¸Î³Ô·¨</a></li> - -<li><span style="color:#0c0000;"><a href="http://health.sina.com.cn/hc/sh/" target="_blank">Éú»î</a>|<a target="_blank" href="http://health.sina.com.cn/hc/ct/2015-06-18/0734173014.shtml">40ËêÊǽ¡¿µ·ÖË®Áë</a> <a target="_blank" href="http://health.sina.com.cn/hc/ct/2015-06-18/0734173022.shtml">ס¼¸Â¥ÊÙÃü³¤</a> <a target="_blank" href="http://health.sina.com.cn/hc/mr/2015-06-18/0735173013.shtml">Å®ÈËÀϲ»ÀÏ¿´Õâ</a></span></li> - -<li><span style="color:#c00;"><a href="http://health.sina.com.cn/rdxw/" target="_blank">»î¶¯</a></span>|<a target="_blank" href="http://health.sina.com.cn/tiaoshi/">Ìôʳ£ºÔõô³ÔèÛè½ÄÜÖΰ׷¢</a> <a target="_blank" href="http://health.sina.com.cn/z/zhaojiling/">ר¼ÒÆÀ²âÍÅÑûÄã¼ÓÈë</a></li> - -<li><span style="color: #0c0000;"><a href="http://health.sina.com.cn/disease/" target="_blank">¼²²¡</a></span>|<a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173020.shtml">ÉíÌåȱɶ³¤°×·¢</a> <a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173012.shtml">ÕâÖÖÄÐÈË×ÊÙ</a> <a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173016.shtml">ÕâÖÖ°×·¢ÄܱäºÚ</a></li> - -<li><span style="color:#0c0000;"><a href="http://health.sina.com.cn/" target="_blank">Èȵã</a>|<a target="_blank" href="http://slide.health.sina.com.cn/hc/slide_31_28380_85477.html#p=1">ÃÀÅ®´©¶Ç¶µ³«Òé½â·ÅÈé·¿</a> <a target="_blank" href="http://slide.health.sina.com.cn/d/slide_31_28379_85559.html#p=1">Å®×ÓÖ»³ÔÅ£Èâ³É¹¦¼õ·Ê</a></span></li> - -<li><span style="color:#c00;"><a href="http://blog.sina.com.cn/lm/health/" target="_blank" class="linkRed03">²©¿Í</a></span>|<a href="http://blog.sina.com.cn/s/blog_ea18fbe40102vyk8.html?tj=1" target="_blank">¼ÒÀï·ÅɶÒ×Ö°©</a> <a href="http://blog.sina.com.cn/s/blog_c23914bb0102vo0a.html?tj=1" target="_blank">ÕâÑù³ÔÓã¶ÌÊÙ</a> <a href="http://blog.sina.com.cn/s/blog_132cb5ac10102vo6y.html?tj=1" target="_blank">ºú×Ó³¤µÃ¿ìԤʾɶ</a></li> - -<li><span style="color:#c00;"><a href="http://health.sina.com.cn/" target="_blank">ÄпÆ</a></span>|<a href="http://health.sina.com.cn/d/s/2015-06-18/0733172982.shtml" target="_blank">´Ó³¿²ª¿´ÄÐÈ˽¡¿µ</a> <a href="http://health.sina.com.cn/hc/s/2015-06-18/0732172983.shtml" target="_blank">ÐÔ°®ÖÐÄÐÈËÅÂʲô</a> <a target="_blank" href="http://health.sina.com.cn/hc/s/2015-06-18/0732172986.shtml">´ßÇéʳÆ×</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod50 --> - </div> - </div> - <!-- part-r end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-s begin --> - - <div class="part-s clearfix"> - <div class="part-s-l"> - <!-- mod51 --> - <div class="mod-13 mod-02" tab-type="tab-wrap"> - <div class="tit02 clearfix"> - <h3 tab-type="tab-nav"><a href="http://fo.sina.com.cn/" target="_blank">·ðѧ</a></h3> - </div> - - <div class="mod27-cont" tab-type="tab-cont" style="padding-top:15px; padding-right:2px;" data-sudaclick="blk_fo_1" blkclick="auto_nav" blktitle="·ðѧ"> - -<!-- publish_helper name='·ðѧÇø¿é' p_id='30' t_id='119' d_id='1' --> - - <div class="pic-txt clearfix"> -<a href="http://fo.sina.com.cn/" target="_blank" class="pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/119/2013/0314/U2333P30T119D1F3626DT20150617143852.jpg" width="65" height="65" /></a><div class="txt"><h3><a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_67296_28236.html">·ð½Ì¹©·î¶ÔÏóÓÐÄÄЩ</a></h3> - -<p><a href="http://slide.fo.sina.com.cn/slide_65_68449_28230.html" target="_blank">ŨÇé¶ËÎ磺×ÔÖÆËØôÕ×Ó</a></p> - -<p><a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_68374_28146.html">´ó×ãǧÊÖ¹ÛÒô½ð¹âÖØÏÖ</a></p></div> - </div> - - <div class="blank-d" style="height:2px"></div> - - <ul class="list-b"> -<li><a target="_blank" href="http://fo.sina.com.cn/intro/lecture/2015-06-16/doc-ifxczyze9621110.shtml">ÕÒ»Ø×Ô¼º±¾ÐÄ</a> <a target="_blank" href="http://fo.sina.com.cn/intro/lecture/2015-06-16/doc-ifxczqan0741850.shtml">Ò»ÐÐìøʦ£ºÍ´¿à²»ÊÇÈ«²¿</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/intro/basic/2015-06-17/doc-ifxczyze9662570.shtml">½ðÓ¹ÎäÏÀÌìÁú°Ë²¿Óë·ð½Ì</a> <a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_68422_28207.html">°Ë´óÆÐÈøÌÆ¿¨</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/intro/basic/index.shtml">³£Ê¶</a>|<a target="_blank" href="http://fo.sina.com.cn/intro/basic/2015-06-17/doc-ifxczqan1546103.shtml">ÈÌÈèÊÇÈÌÆøÍÌÉùÂð</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_769fb5f30102voga.html?tj=1">ΪºÎ²»Òª×ÜËãÃü</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/intro/lecture/index.shtml">¿ªÊ¾</a>|<a target="_blank" href="http://fo.sina.com.cn/intro/lecture/2015-06-17/doc-ifxczqap4207346.shtml">Éí·ÝÒÔÍâµÄÄã</a> <a target="_blank" href="http://fo.sina.com.cn/intro/2015-06-17/doc-ifxczyze9663136.shtml">»»½Ç¶È¿´ÎÊÌâ¿àÊÇÀÖ</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/xuefo/">ѧ·ð</a>|<a target="_blank" href="http://fo.sina.com.cn/xuefo/2015-06-16/doc-ifxczqar0950965.shtml">ÓàÇïÓê̸·ð·¨ÈËÉú</a> <a target="_blank" href="http://fo.sina.com.cn/xuefo/2015-06-17/doc-ifxczqap4199508.shtml">ºîСǿѧ·ð֮·</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/blog/">²©¿Í</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_a64f18960102vre2.html?tj=1" class="linkRed">°ËÖ¤¾ÝÈÃÄãÏàÐÅÂÖ»Ø</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_773f4e890102w5pp.html?tj=1">ÐÞÐÐÈËÆ߸£±¨</a></li><li><a target="_blank" href="http://slide.fo.sina.com.cn/">ͼ¼¯</a>|<a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_67296_28173.html">·ð½ÌµÄ¼ªÏé°Ë±¦</a> <a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_68460_28235.html">ÈÕ±¾ËÂÔº½¨ÖþÖ®ÃÀ</a></li><li><a href="http://fo.sina.com.cn/veg/" target="_blank">ËØʳ</a>|<a target="_blank" href="http://fo.sina.com.cn/veg/cp/2015-06-17/doc-ifxczqap4169384.shtml">¶¹¸¯É³À­</a> <a target="_blank" href="http://fo.sina.com.cn/veg/cp/2015-06-16/doc-ifxczyze9629147.shtml">¶¹½¬ÀäÃæ</a> <a target="_blank" href="http://fo.sina.com.cn/veg/cp/2015-06-17/doc-ifxczqan1546531.shtml">²Ë½·ÖñËñ(ͼ)</a></li> - </ul> - - </div> - </div> - <!-- mod51 --> - </div> - <div class="part-s-m"> - <!-- mod52 --> - <div class="uni-blk" id="SI_Order_W" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"> -<!-- - <a href="http://pet.sina.com.cn/" target="_blank">³èÎï</a> ---> - <a href="http://eat.sina.com.cn/" target="_blank">ÃÀʳ</a> - </span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_4"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b mod52-fix-cont SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_life_1" blkclick="auto_nav" blktitle="³èÎïÃÀʳ"> -<!-- publish_helper name='³èÎïÃÀʳÇø¿é' p_id='30' t_id='124' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/s/blog_13bf8b5300102vu4e.html?tj=1" target="_blank" class="uni-blk-pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U2062P30DT20150617153211.jpg" width="105" height="70" /> - <span>¸¸Ç×½Ú±ý¸ÉËÍÀÏ°Ö</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://blog.sina.com.cn/s/blog_5edbc5430102vmi9.html?tj=1" target="_blank">ÓÕÈ˵ļ«Æ·ÓÍÆÃÀ±×Ó</a> <a href="http://blog.sina.com.cn/s/blog_44ca89150102vh1c.html?tj=1" target="_blank">ÂéÀ±Ð¡ÁúϺ</a></li> - -<li><a href="http://blog.sina.com.cn/s/blog_98a3573d0102vmmh.html?tj=1" target="_blank">×îÏ·¹ÏãÀ±öÏÓã¾í</a> <a href="http://blog.sina.com.cn/s/blog_6acaee7c0102vp3b.html?tj=1" target="_blank">ÓÀÔ¶µÄºìÉÕÈâ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_844d7ba90102vlfr.html?tj=1" target="_blank">Ïļ¾±Ø±¸¿ìÊÖÁ¹°è²Ë</a> <a href="http://blog.sina.com.cn/s/blog_75282e070102vn3v.html?tj=1" target="_blank">ÇÑÖ­¼å¶¹¸¯</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_520d14230102vp2l.html?tj=1" target="_blank">¾íÐIJËСÏÊÈâ°ü</a> <a href="http://blog.sina.com.cn/s/blog_87df1b000102vt2y.html?tj=1" target="_blank">ɽÎ÷Ãû²Ë¹ýÓÍÈâ</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://beijing.51xiancheng.com/pc/index/list?cate=1" target="_blank">ÃÀʳ</a>| <a href="http://beijing.51xiancheng.com/article/11615 -" target="_blank">²ØÔÚ¾ÓÃñÇøµÄ½ðÅÆËâÄàÁúϺ</a> <a href="http://beijing.51xiancheng.com/article/12192" target="_blank">Õý×Ú½­ÄÏÊ®ÈýÏãÂéС</a> </li> -<li><a href="http://beijing.51xiancheng.com/pc/index/list?cate=6" target="_blank">±¬¿î</a>| <a href="http://weibo.com/p/1001603854685999088573 -" target="_blank">²ØÔÚºúͬÀïµÄ±Æ¸ñ¿§·È¹Ý</a> <a href="http://weibo.com/p/1001603838743596431247" target="_blank">²»¿É´í¹ýµÄÄÞºç¹úÃÀʳ</a> </li> -<li><a href="http://beijing.51xiancheng.com/pc/index/list?cate=1" target="_blank">¹¥ÂÔ</a>| <a href="http://beijing.51xiancheng.com/article/11637" target="_blank">ÄêÇáÈËÔú¶ÑµÄÂéÀ±Ð¡ÁúϺ</a> <a href="http://beijing.51xiancheng.com/article/12239" target="_blank">Èë¿Ú³¬Ë¬µÄÃØÖÆСÁúϺ</a> </li> -<li><a href="http://beijing.51xiancheng.com/" target="_blank">±±¾©</a>| <a href="http://beijing.51xiancheng.com/article/12351" target="_blank">µÛ¶¼×î½²¾¿µÄ¾©Î¶²Ë</a> <a href="http://beijing.51xiancheng.com/article/12366" target="_blank">³ÔÍê¾Í¿ªÊ¼ÏëÄîµÄ±±¾©Ð¡³Ô</a></li> -<li><a href="http://edu.sina.com.cn/photo/" target="_blank">×éͼ</a>| <a target="_blank" href="http://slide.edu.sina.com.cn/slide_11_611_28251.html">»Æ²Ó²Ó½ø¾üÓéÀÖȦ</a> <a target="_blank" href="http://slide.edu.sina.com.cn/slide_11_611_28255.html">жÈÄïѧʿÕÕ</a> <a target="_blank" href="http://slide.edu.sina.com.cn/slide_11_611_28257.html">ÒÕУ¸Ö¹ÜÎèУ»¨</a></li> -<li><a href="http://blog.sina.com.cn/lm/edu/" target="_blank">²©¿Í</a>| <a target="_blank" href="http://blog.sina.com.cn/s/blog_539c5bd20102vjdk.html?tj=1">ÈçºÎ±¨Ö¾Ô¸Èø߿¼·ÖÊý²»ÀË·Ñ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_a5357a3e0102vv45.html?tj=1">ÄãÔÚÃÀ¹úÕõ¶àÉÙÇ®</a></li> -<li><a href="http://edu.sina.com.cn/zl/" target="_blank">ÍƼö</a>| <a target="_blank" href="http://blog.sina.com.cn/s/blog_abb623400102vr31.html?tj=1">½ÒÃظßУÈËÌåÄ£ÌØ(ͼ)</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_903b54120102vre7.html?tj=1">ÈÈÇé±¼·Å×îÃÀУ»¨(ͼ)</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod52 --> - </div> - <div class="part-s-r"> - <!-- mod53 --> - <div class="uni-blk" id="SI_Order_X" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://astro.sina.com.cn/" target="_blank">ÐÇ×ù</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b mod52-fix-cont SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_astro_1" blkclick="auto_nav" blktitle="ÐÇ×ù"> -<!-- publish_helper name='ÐÇ×ùÇø¿é' p_id='30' t_id='120' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://slide.astro.sina.com.cn/slide_52_42283_36327.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0617/U7132P30DT20150617184803.gif" width="105" height="70" /> - - <span>12ÐÇ×ùÎü¾¦´ó·¨</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://astro.sina.com.cn/" target="_blank">Å®ÈË͵͵²â:ÄãͯÕ껹ʣ¶àÉÙ</a></li> - -<li><a target="_blank" href="http://astro.sina.com.cn/v/ss/2015-06-17/doc-ifxczqar0990404.shtml">ΪǮ·­Á³µÄÐÇ×ù</a> <a target="_blank" href="http://astro.sina.com.cn/e/2015-06-17/doc-ifxczqap4211765.shtml">½ñÄê¶ËÎçË­µ¹Ã¹</a></li> - -<li><a target="_blank" href="http://astro.sina.com.cn/v/ss/2015-06-17/doc-ifxczqar0992909.shtml">ËÍ12ÐÇ×ù°Ö°ÖɶÀñÎï</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_61682aca0102vpjt.html?tj=1">3ÖÖÃβ»ÄÜ˵</a></li> - -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_5bd1ddf60102w059.html?tj=1">ÄãÊdz´¹É±ØÅâÃüÂð</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_50939dbf0102vwhd.html?tj=1">12ÐÇ×ùÌôÌÞÍõ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://astro.sina.com.cn/t/" target="_blank">²âÊÔ</a>|<a target="_blank" href="http://astro.sina.com.cn/t/aq/2015-06-17/doc-ifxczqar0990738.shtml">ÎÞÍ´·ÖÊÖÄãÐÐÂð</a> <a target="_blank" href="http://astro.sina.com.cn/t/aq/2015-06-17/doc-ifxczqap4205473.shtml">ÇéµÐºÚÄãÕ¦½â¾ö</a> <a target="_blank" href="http://astro.sina.com.cn/t/2015-06-17/doc-ifxczqar0995624.shtml">ÄãÂèÕ¦¿´ÄãµÄ</a></li><li><a href="http://astro.sina.com.cn/b/ysjj/" target="_blank">ÔËÊÆ</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_61bd67650102vl7r.html?tj=1">ÈýÂèÖÜÔË</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_6431df490102vk3h.html?tj=1">AlexÖÜÔË</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_3e8e948a0102vl9o.html?tj=1">Î×Å®ÖÜÔË</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_4758ccc20102vq7d.html?tj=1">12ÐÇ×ù¿ªÔËÖ¸ÄÏ</a></li><li><a href="http://astro.sina.com.cn/l/" target="_blank">½Ì³Ì</a>|<a target="_blank" href="http://astro.sina.com.cn/e/2015-06-17/doc-ifxczqan1629906.shtml">¶ËÎç±Ùа´ó½ÒÃØ</a> <a target="_blank" href="http://astro.sina.com.cn/e/2015-06-17/doc-ifxczqap4210882.shtml">ɶÃüÒ»¶¨·¢ºá²Æ</a> <a target="_blank" href="http://astro.sina.com.cn/e/2015-06-16/doc-ifxczyze9636062.shtml">10ÖÖ·¿×Ó²»ÄÜÒª</a></li><li><a href="http://astro.sina.com.cn/xl/" target="_blank">ÐÄÀí</a>|<a target="_blank" href="http://astro.sina.com.cn/xl/hl/2015-06-17/doc-ifxczqar0988325.shtml">Å®ÈËÐØÐÍ¿´»éÒö</a> <a target="_blank" href="http://astro.sina.com.cn/xl/hl/2015-06-17/doc-ifxczqar0989128.shtml">10Ô¼»áÄÐÈË×îºÞ</a> <a target="_blank" href="http://astro.sina.com.cn/t/2015-06-17/doc-ifxczqan1584952.shtml">ÄãÊÇÇéÉ«¸ßÊÖÂð</a></li><li><a href="http://club.astro.sina.com.cn/" target="_blank">ÂÛ̳</a>|<a target="_blank" href="http://club.astro.sina.com.cn/thread-3771532-1-1.html">ͬÄêͬÔÂͬÈÕµÄÁ©Ìì³Ó</a> <a target="_blank" href="http://club.astro.sina.com.cn/thread-3727606-1-1.html">Ë«ÓãÅ®ÏñÇ×ÂèÒ»Ñù¿ÞÄÖ</a></li> -<li><a href="http://astro.sina.com.cn/bbs/" target="_blank">ÂÛ̳</a>|<a target="_blank" href="http://club.astro.sina.com.cn/thread-3751839-1-1.html">ħ¶¼Ê¨×ÓÇéÏÝÉÏÁ÷Éç»á</a> <a target="_blank" href="http://club.astro.sina.com.cn/thread-3774248-1-1.html">ÌìЫ׷²»µ½´¦Å®¿Þ³É¹·</a></li> -<li><a target="_blank" href="http://slide.astro.sina.com.cn/">GIF</a>|<a target="_blank" href="http://slide.astro.sina.com.cn/slide_52_42283_35835.html">12ÐÇ×ù±¿±¿ßÕ</a> <a target="_blank" href="http://slide.astro.sina.com.cn/slide_52_42283_35855.html">12ÐÇ×ùµÄÌØÒ칦ÄÜ</a> <a target="_blank" href="http://slide.astro.sina.com.cn/slide_52_42283_35879.html">12ÐÇ×ù×÷ËÀÉñ¼¼</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod53 --> - </div> - </div> - <!-- part-s end --> - -<div class="blank-cont" style="height:18px"></div> -<style> -.part-t{width:1000px;} -.part-t .part-tcont{width:1000px;height:201px;overflow:hidden;position:relative;} -.part-t .uni-blk-t .order-menu span{padding:0 29px;} -.part-t .uni-blk-t .order-menu span.no-bl{padding:0 29px 0 28px !important;} -.part-t .uni-blk-t .order-menu span.selected{padding:0 28px;} -</style> -<div class="part-t uni-blk" tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"><p> - <span tab-type="tab-nav" class="mod54-tab no-bl" id="testU"><a href="http://fashion.sina.com.cn/photo/" target="_blank" suda-uatrack="key=index_www_pic&value=pic_click">ÃÀͼ</a></span> - <span tab-type="tab-nav" class="mod54-tab"><a href="http://slide.astro.sina.com.cn/" target="_blank" suda-uatrack="key=index_www_pic&value=gif_click">GIF</a></span> - </p></div> - </div> - <div class="blank-cont" style="height:20px"></div> - <div class="part-tcont"> - <div tab-type="tab-cont" class="mod54-cont"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap_t00" data-sudaclick="blk_pic_fashion"> -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/s/slide_24_68372_60732.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/BsUl-fxczqar0946754.jpg" width="198" height="132" /> <span class="scroll-txt">º«¸ýÁη²³Ø²ýÐñ ÄÐÉñÆë¾ÛÐ㳡</span></a></div> - -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60756.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/A-ze-fxczqar0946802.jpg" width="198" height="132" /> <span class="scroll-txt">TaylorÁìÏÎÏÄÈÕÀÙË¿Ê¢Ñç </span></a></div> - -<div class="scroll-item"><a href="http://slide.edu.sina.com.cn/slide_11_611_28194.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/edu/2015/0616/U12690P42DT20150616112913.jpg" width="198" height="132" /> <span class="scroll-txt">»ªÅ©Ð£»¨É¹ÐÂÕÕ Å®Íõ·¶Ê®×ã</span></a></div> - -<div class="scroll-item"><a href="http://slide.baby.sina.com.cn/syj/slide_10_846_28178.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/dy/2015/0616/U12222P1DT20150616112733.jpg" width="198" height="132" /> <span class="scroll-txt">ÈÕ±¾Õ¬Å®·¿¼ä£ºÕâÊÇÈËסµÄÂð£¿</span></a></div> - -<div class="scroll-item"><a href="http://slide.health.sina.com.cn/hc/slide_31_28380_85515.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/health/2015/0616/U11489P434DT20150616112526.jpg" width="198" height="132" /> <span class="scroll-txt">¹ãÎ÷У»¨Ð£²Ý´óÈü Ñ¡ÊÖÓ¾×°Ðã</span></a></div> - -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60684.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150616/BAkz-fxczyze9624350.jpg" width="198" height="132" /> <span class="scroll-txt">ÈÃÄãÐÒ¸£¸Ð±¬ÅïµÄ20¿îÌðÌðȦ</span></a></div> - -<div class="scroll-item"><a href="http://slide.baby.sina.com.cn/yjq/slide_10_846_28124.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/dy/2015/0616/U12222P1DT20150616112740.jpg" width="198" height="132" /> <span class="scroll-txt">ÐìÎõæÂÓëÅ®¶ùºÏÓ°ÕÕÆعâ</span></a></div> - -<div class="scroll-item"><a href="http://slide.health.sina.com.cn/hc/slide_31_28380_85376.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/health/2015/0616/U11489P434DT20150616112830.jpg" width="198" height="132" /> <span class="scroll-txt">ÍÁ¶úÆä85ËêÀÏÈËÔÙµ±µù </span></a></div> - -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60764.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/VfHT-fxczqan0672023.jpg" width="198" height="132" /> <span class="scroll-txt">ÂíÇòÈü ÇÇÖÎСÍõ×ÓÃÈ·­ÖÚÈË</span></a></div> - -<div class="scroll-item"><a href="http://slide.edu.sina.com.cn/slide_11_611_28091.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/edu/2015/0616/U12690P42DT20150616112913_1.jpg" width="198" height="132" /> <span class="scroll-txt">20Ë궫ʦÃÀÅ®ÉñËÆСÌÀΨ×ߺì</span></a></div> - - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L_t00"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R_t00"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists_t00"></div> - </div> - <div tab-type="tab-cont" class="mod54-cont"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap_t01" data-sudaclick="blk_pic_astro"> -<textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32866.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/b7K4-fxefurt9337403.gif" width="198" height="132" /> <span class="scroll-txt">12ÐÇ×ù±»Ë¦ÁË</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32949.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/ch7S-fxefurt9337413.gif" width="198" height="132" /> <span class="scroll-txt">12ÐÇ×ùµÄÃÈÄãÒ²ÊDz»¶®</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32969.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/8_Kt-fxefurs2560083.gif" width="198" height="132" /> <span class="scroll-txt">12ÐÇ×ùûÁ³¼ûÈË</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32890.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/yLbI-fxefurt9337448.gif" width="198" height="132" /> <span class="scroll-txt">ÐÐΪ¹Å¹ÖµÄ12ÐÇ×ù</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32861.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/4Xr6-fxefurt9337462.gif" width="198" height="132" /> <span class="scroll-txt">ÔãÁË£¡12ÐÇ×ù̯ÉÏ´óÊÂÁË£¡</span></a></div> - -</textarea> - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L_t01" style="display:none;"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R_t01" style="display:none;"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists_t01" style="display:none;"></div> - </div> - - </div> - <script> - jsLoader({ - name : 'shm', - callback : function() { - for(var i = 0, l = 2; i < l; i++){ - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "SI_Scroll_Wrap_t0" + i; //ÄÚÈÝÈÝÆ÷ID - focusScroll.dotListId = "SI_Scroll_Dot_Lists_t0" + i;//µãÁбíID - focusScroll.arrLeftId = "SI_Scroll_Arr_L_t0" + i; - focusScroll.arrRightId = "SI_Scroll_Arr_R_t0" + i; - focusScroll.dotClassName = "";//µãclassName - focusScroll.dotOnClassName = "cur";//µ±Ç°µãclassName - focusScroll.listType = "";//ÁбíÀàÐÍ(number:Êý×Ö£¬ÆäËüΪ¿Õ) - focusScroll.listEvent = "onmouseover"; //Çл»Ê¼þ - focusScroll.frameWidth = 1000;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 1000; //·­Ò³¿í¶È - focusScroll.upright = false; //´¹Ö±¹ö¶¯ - focusScroll.speed = 10; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = false; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - } - var tabArr = SHM.dom.byClass("mod54-tab"), - contArr = SHM.dom.byClass("mod54-cont"); - - var defaultSelectedNavIndex = (Math.random()*10|0) < 5 ? 0 : 1; - - SHM.app.tab.switchByEle(tabArr[defaultSelectedNavIndex]); - contArr[defaultSelectedNavIndex?0:1].style.display = "none"; - } - }); - </script> -</div> -<div class="blank-cont" style="height:10px"></div> - -<!-- -<div class="blank-cont" style="height:25px"></div> ---> - -<!-- publish_helper name='³ÇÊÐÁªÃË' p_id='30' t_id='125' d_id='2' --> -<!-- city-union begin --> -<div class="city-union" data-sudaclick="blk_city_union"> - <div class="clearfix"> - <p class="name"><a target="_blank" href="http://city.sina.com.cn/">ÐÂÀ˳ÇÊÐ</a></p> - <div class="clist"> - <p><a target="_blank" href="http://sh.sina.com.cn/">ÉϺ£</a> <a href="http://tj.sina.com.cn/" target="_blank">Ìì½ò</a> <a target="_blank" href="http://cq.sina.com.cn/">ÖØÇì</a> <a target="_blank" href="http://gd.sina.com.cn/">¹ã¶«</a> <a target="_blank" href="http://henan.sina.com.cn/">ºÓÄÏ</a> <a target="_blank" href="http://sc.sina.com.cn/">ËÄ´¨</a> <a target="_blank" href="http://fj.sina.com.cn/">¸£½¨</a> <a target="_blank" href="http://mn.sina.com.cn/">ÃöÄÏ</a> <a target="_blank" href="http://zj.sina.com.cn/">Õã½­</a> <a target="_blank" href="http://jiangsu.sina.com.cn">½­ËÕ</a> <a target="_blank" href="http://hebei.sina.com.cn/">ºÓ±±</a> <a target="_blank" href="http://hb.sina.com.cn/">ºþ±±</a> <a target="_blank" href="http://hunan.sina.com.cn/">ºþÄÏ</a> <a target="_blank" href="http://sx.sina.com.cn/">ÉÂÎ÷</a> <a target="_blank" href="http://ln.sina.com.cn/">ÁÉÄþ</a> <a target="_blank" href="http://hlj.sina.com.cn">ºÚÁú½­</a> <a target="_blank" href="http://ah.sina.com.cn">°²»Õ</a> <a target="_blank" href="http://jx.sina.com.cn/">½­Î÷</a> <a target="_blank" href="http://jl.sina.com.cn/">¼ªÁÖ</a> <a target="_blank" href="http://shanxi.sina.com.cn/">ɽÎ÷</a> <a target="_blank" href="http://hainan.sina.com.cn/">º£ÄÏ</a> <a href="http://sd.sina.com.cn/" target="_blank">ɽ¶«</a> <a href="http://gx.sina.com.cn/" target="_blank">¹ãÎ÷</a></p> - <p><a href="http://nb.sina.com.cn/" target="_blank">Äþ²¨</a> <a target="_blank" href="http://dl.sina.com.cn/">´óÁ¬</a> <a href="http://wx.sina.com.cn/" target="_blank">ÎÞÎý</a> <a target="_blank" href="http://hlj.sina.com.cn/lyj/index.html ">±ù³Ç</a> <a href="http://jl.sina.com.cn/changchun/index.html" target="_blank">³¤´º</a> <a target="_blank" href="http://www.xian-tourism.com/">Î÷°²</a> <a target="_blank" href="http://city.sina.com.cn/city/f/sjzwx.html">ʯ¼Òׯ</a> <a target="_blank" href="http://www.jsjjw.cn">¾¸½­</a> <a target="_blank" href="http://sina.haian.gov.cn/">º£°²</a> <a target="_blank" href="http://www.haimen.gov.cn/">º£ÃÅ</a> <a target="_blank" href="http://www.sinasy.com.cn/">ÉÏÓÝ</a> <a target="_blank" href="http://www.yw.gov.cn/">ÒåÎÚ</a> <a target="_blank" href="http://hlj.sina.com.cn/shangzhi/">ÉÐÖ¾</a> <a href="http://sina.hd.cn/" target="_blank">ºªµ¦</a> <a href="http://ah.sina.com.cn/zt/travel/ahwenhuazhilv/index.shtml" target="_blank">ÃÀºÃ°²»Õ</a> <a href="http://weibo.com/hcxfjq" target="_blank">»Ê³ÇÏฮ</a> <a href="http://jl.sina.com.cn/yanbian/" target="_blank">ÑÓ±ß</a> <a href="http://yn.sina.com.cn/travel/zt/tiyandianyuetieluchuanyuemiguishiguang/index.shtml" target="_blank">ºìºÓ</a> <a href="http://www.qingdaochina.org/" target="_blank">Çൺ</a></p> - </div> - </div> - <div class="clearfix c-hot"> - <p class="name"><a target="_blank" href="http://city.sina.com.cn/">Éú»îÈÈÇø</a></p> - <p class="clist"><a target="_blank" href="http://hmgxq.haimen.gov.cn/">º£ÃŸÛÐÂÇø</a> <a target="_blank" href="http://sx.sina.com.cn/zt/city/xachanba/index.shtml">›ºå±Éú̬Çø</a> <a href="http://hlj.sina.com.cn/mdr/index.html" target="_blank">±ùÑ©´óÊÀ½ç</a> <a href="http://hlj.sina.com.cn/hanan/index.html" target="_blank">ÎåÉ«¹þÄÏ</a> <a href="http://jl.sina.com.cn/jlsgjt/index.html" target="_blank">¼ªÁÖÉ­¹¤</a> <a target="_blank" href="http://city.sina.com.cn/city/Declaration.html">[¹«¸æÉùÃ÷]</a></p> - </div> -</div> -<!-- city-union end --> - -<div class="blank-cont" style="height:25px"></div> - - <!-- part-t begin --> - <div class="part-t"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 3ÂÖ²¥µ×²¿Í¨À¸¹ã¸æ begin --> -<div id="ad_16990" class="mb25"><ins class="sinaads" data-ad-pdps="PDPS000000016990"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 3ÂÖ²¥µ×²¿Í¨À¸¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- part-t end --> - - <!-- footer begin --> - <div id="footer" class="footer" data-sudaclick="blk_footer"> - <div class="ft-info"><a href="http://corp.sina.com.cn/chn/">ÐÂÀ˼ò½é</a> ©® <a href="http://corp.sina.com.cn/eng/">About Sina</a> ©® <a href="http://emarketing.sina.com.cn/">¹ã¸æ·þÎñ</a> ©® <a href="http://www.sina.com.cn/contactus.html">ÁªÏµÎÒÃÇ</a> ©® <a href="http://career.sina.com.cn/">³ÏƸӢ²Å</a> ©® <a href="http://www.sina.com.cn/intro/lawfirm.shtml">ÍøÕ¾ÂÉʦ</a> ©® <a href="http://english.sina.com">SINA English</a> ©® <a href="https://login.sina.com.cn/signup/signup.php">×¢²á</a> ©® <a href="http://help.sina.com.cn/">²úÆ·´ðÒÉ</a></div> - <p class="ft-copy">Copyright &copy;1996-2015 SINA Corporation, All Rights Reserved</p> - <div class="ft-list"> - <ul> - <li style="margin-left:0px;"> - <a href="http://www.itrust.org.cn" target="_blank"> - <img width="110" height="50" alt="Öйú»¥ÁªÍøЭ»á" src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo01.gif"></a> - </li> - <li> - <a href="http://www.hd315.gov.cn/beian/view.asp?bianhao=0102000102300001" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i2.sinaimg.cn/home/main/index2013/footerlogo/footer_logo02.gif" width="109" height="50" alt="¾­ÓªÐÔÍøÕ¾±¸°¸ÐÅÏ¢"></a> - </li> - <li> - <a href="http://www.12377.cn/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i3.sinaimg.cn/home/main/index2013/footerlogo/footer_logo03.gif" width="109" height="50" alt="²»Á¼ÐÅÏ¢¾Ù±¨ÖÐÐÄ"></a> - </li> - <li> - <a href="http://www.bnia.cn/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i0.sinaimg.cn/home/main/index2013/footerlogo/footer_logo04.gif" width="109" height="50" alt="±±¾©ÍøÂçÐÐҵЭ»á"></a> - </li> - - <li> - <a href="http://www.bj.cyberpolice.cn/index.htm" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo05.gif" width="105" height="50" alt="ÍøÂç110±¨¾¯·þÎñ"></a> - </li> - - <li> - <a href="https://ss.knet.cn/verifyseal.dll?sn=2010091500100002145&ct=df&a=1&pa=0.14296675658609825" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo10_1.gif" width="123" height="50" alt="¿ÉÐÅÍøÕ¾"></a> - </li> - - <li> - <a href="http://www.bjwhzf.gov.cn/accuse.do" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i3.sinaimg.cn/home/main/index2013/footerlogo/footer_logo07.gif" width="111" height="50" alt="±±¾©ÎÄ»¯Êг¡¾Ù±¨ÈÈÏß"></a> - </li> - <li> - <a href="http://www.allyes.com/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i0.sinaimg.cn/home/main/index2013/footerlogo/footer_logo08.gif" width="107" height="50" alt="ºÃÒ®¹ã¸æÍøÂç"></a> - </li> - <li> - <a href="http://www.bjjubao.org/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo09.gif" width="107" height="50" alt="±±¾©»¥ÁªÍø¾Ù±¨ÖÐÐÄ"></a> - </li> - </ul> - - </div> - <p><a href="http://corp.sina.com.cn/chn/sina_priv.html" target="_blank">Òþ˽±£»¤</a>¡¡ÐÂÀ˹«Ë¾¡¡<a href="http://www.sina.com.cn/intro/copyright.shtml">°æȨËùÓÐ</a>¡¡<a href="http://www.miibeian.gov.cn" target="_blank">¾©ICPÖ¤000007</a></p> - <p>¿Í»§·þÎñÈÈÏߣº4006900000¡¡Î¥·¨ºÍ²»Á¼ÐÅÏ¢¾Ù±¨µç»°£º010-62646869¡¡¾Ù±¨ÓÊÏ䣺<a href="mailto:jubao@vip.sina.com">jubao@vip.sina.com</a></p> - <p>&nbsp;</p> - <p><a href="http://www.sina.com.cn/licence/www0003.html" target="_blank">¾©ÍøÎÄ[2014]2045-295ºÅ</a>¡¡<a href="http://www.sina.com.cn/licence/news.html" target="_blank">»¥ÁªÍøÐÂÎÅÐÅÏ¢·þÎñÐí¿É</a></p> - <p><a href="http://www.sina.com.cn/licence/yjj0031.html" target="_blank">¹ú¼ÒÒ©¼à¾Ö£¨¾©£©-¾­ÓªÐÔ-2014-0004</a>¡¡<a href="http://www.sina.com.cn/licence/4.html" target="_blank">¾©½ÌÑÐ[2002]7ºÅ</a>¡¡<a href="http://www.sina.com.cn/licence/3.html" target="_blank">µçÐÅÒµÎñÉóÅú[2001]×ÖµÚ379ºÅ</a></p> - <p><a href="http://www.sina.com.cn/license/telecom09.html" target="_blank">ÔöÖµµçÐÅÒµÎñ¾­ÓªÐí¿ÉÖ¤B2-20090108</a>¡¡<a href="http://www.sina.com.cn/licence/dx000007.html" target="_blank">µçÐÅÓëÐÅÏ¢·þÎñÒµÎñ¾­ÓªÐí¿ÉÖ¤000007ºÅ</a>¡¡<a href="http://www.sina.com.cn/licence/wsxx.html" target="blank">¾©ÎÀÍøÉó[2014]µÚ0148ºÅ</a></p> - <p><a href="http://www.sina.com.cn/license/rtppl2009.html" target="_blank">¹ã²¥µçÊÓ½ÚÄ¿ÖÆ×÷¾­ÓªÐí¿ÉÖ¤£¨¾©£©×ÖµÚ828ºÅ</a> <a href="http://www.sina.com.cn/license/map2011.html" target="_blank">¼×²â×Ê×Ö1100078</a> ¾©¹«Íø°²±¸110000000016ºÅ</p> - </div> - <!-- footer end --> - </div> - <!-- main end --> - - <script type="text/javascript"> -// var ORDER_MAP = {'10100' : 'SI_Order_A', '10200' : 'SI_Order_B', '10300' : 'SI_Order_C', '10400' : 'SI_Order_D', '10500' : 'SI_Order_E', '10600' : 'SI_Order_F', '10700' : 'SI_Order_G', '10800' : 'SI_Order_H', '10900' : 'SI_Order_I', '11000' : 'SI_Order_J', '11100' : 'SI_Order_K', '11200' : 'SI_Order_L', '11500' : 'SI_Order_O', '11600' : 'SI_Order_P', '11700' : 'SI_Order_Q', '11800' : 'SI_Order_R', '11900' : 'SI_Order_S', '12000' : 'SI_Order_T', '12100' : 'SI_Order_U', '12200' : 'SI_Order_V', '12300' : 'SI_Order_W', '12400' : 'SI_Order_X'}; - jsLoader({ - name : 'middleJs', - url : 'http://finance.sina.com.cn/basejs/suggestServer.js', - callback: function() { - var suggestServer = new SuggestServer(); - suggestServer.bind({ - "input": "textSuggest", - "type": "stock", - "value": "@2@", - "width": 160, - "head": {"Ñ¡Ïî":'Ñ¡Ïî',"ÖÐÎÄÃû³Æ":'ÖÐÎÄÃû³Æ'}, - "body": {'0':'-1', '1':'4'}, - "link": "http://biz.finance.sina.com.cn/suggest/lookup_n.php?country=@type@&q=@2@" - }); - window.changeViewInputs = function changeViewInputs(__elementSelect) { - __elementSelect.form["q"].value = "´úÂë/Ãû³Æ/Æ´Òô"; - suggestServer.changeType(__elementSelect.value); - } - } - }); - /*jsLoader({ - name: 'shm', - callback: function() { - jsLoader({ - name: 'placeholderinit', - url: '../../js/placeholderinit.js' - }); - } - });*/ - -/* - jsLoader({ - name: 'shm', - callback: function() { - var byId = SHM.dom.byId, - addEvent = SHM.evt.addEvent, - unTrack = SHM.app.uaTrack, - getXY = SHM.dom.getXY, - W = window, - D = document; - DIV = D.createElement('DIV'), - tml = '<div class="top_btn" id="SI_Totop_Btn" style="visibility:hidden"><a class="toplink" href="javascript:;" title="·µ»Ø¶¥²¿" style="">TOP</a></div>'; - DIV.className = 'side-btns-wrap'; - DIV.setAttribute('id','SI_Sidebtns_Wrap'); - DIV.innerHTML = tml; - D.getElementsByTagName('BODY')[0].appendChild(DIV); - - var wrap = byId('SI_Sidebtns_Wrap'); - var btn = byId('SI_Totop_Btn'); - var isIE6 = $globalInfo.ua.isIE6; - var resetBtnLeft = function() { - var mLeft = parseInt(SHM.dom.getWinSize().width); - - mLeft < 1100 ? (wrap.style.marginLeft = (mLeft/2 - wrap.offsetWidth - 15) + 'px') : (wrap.style.marginLeft = '505px'); - }; - addEvent(W,'resize',function(){ - resetBtnLeft(); - }); - addEvent(W,'scroll',function(){ - var top = W.pageYOffset || D.documentElement.scrollTop || D.body.scrollTop; - top > 0 ? btn.style.visibility = 'visible' : btn.style.visibility = 'hidden'; - if(isIE6) { - var wh = W.innerHeight || D.documentElement.clientHeight || D.body.clientHeight; - wrap.style.top = (top + wh - 120) + 'px'; - } - }); - addEvent(btn,'click',function(){ - D.documentElement.scrollTop = 0; - D.body.scrollTop = 0; - unTrack('to_top','to_top'); - }); - } - }); -*/ - -/* - jsLoader({ - name: 'shm', - callback: function() { - jsLoader({ - name: 'shm_order', - url: 'http://ent.sina.com.cn/js/470/2013/0311/order.js' - }); - } - }); -*/ - jsLoader({ - name: 'shm', - callback: function() { - jsLoader({ - name: 'b_search', - url: 'http://www.sina.com.cn/js/index/96/temp/b_search.js', - callback : function() { - window.blogsearch = function(fn,strName) { - if(fn.q.value==""||fn.q.value=="ÇëÊäÈë²éѯ´Ê") { - fn.q.value="ÇëÊäÈë²éѯ´Ê"; - fn.q.focus(); - return false - } - if(strName!="blog") { - return false - } - fn.submit(); - return false - }; - window.booksearch = function(fn) { - if(fn.k.value==""||fn.k.value=="ÇëÊäÈë²éѯ´Ê") { - fn.k.value="ÇëÊäÈë²éѯ´Ê"; - fn.k.focus(); - return false; - } - fn.submit(); - return false; - }; - window.carsearch = function(fn,strName) { - if(fn.q.value==""||fn.q.value=="ÇëÊäÈë²éѯ´Ê") { - fn.q.value="ÇëÊäÈë²éѯ´Ê"; - fn.q.focus(); - return false - } - if(strName!="car") { - return false - } - if(fn.by.value == "cars"){ - window.open('http://so.auto.sina.com.cn/car/' + fn.q.value+'/'); - return false; - } - else if(fn.by.value == "kinds"){ - window.open('http://so.auto.sina.com.cn/search/' + fn.q.value+'/'); - return false; - } - }; - } - }); - } - }); - -var isIE6 = navigator.appVersion.indexOf("MSIE 6") != -1 ? true: false; -//ͼƬ¹ö¶¯¼ÓÔØ -~function() {var d = document, w = this, b = document.body, h = document.documentElement, p = [], eventFunc = function() {scrollLoader.scroll() }, bH = -1, timer, bT, bVH, iTotal = d.images.length; var sina = {$: function(objName) {if (d.getElementById) {return d.getElementById(objName) } else {return d.all[objName] } }, addEvent: function(obj, eventType, func) {if (obj.attachEvent) {obj.attachEvent("on" + eventType, func) } else {obj.addEventListener(eventType, func, false) } }, delEvent: function(obj, eventType, func) {if (obj.detachEvent) {obj.detachEvent("on" + eventType, func) } else {obj.removeEventListener(eventType, func, false) } }, absPosition: function(obj, parentObj) {var left = obj.offsetLeft; var top = obj.offsetTop; var tempObj = obj.offsetParent; try {while (tempObj != b && tempObj != d.documentElement && tempObj != parentObj && tempObj != null) {left += tempObj.offsetLeft; top += tempObj.offsetTop; tempObj = tempObj.offsetParent } } catch (e) {}; return {left: left, top: top } } }; var scrollLoader = {version: '1.1.0', status: "complete", mult: 2, init: function(ele) {var that = this, imgs, num = 0; if (ele && ele.getElementsByTagName) {imgs = ele.getElementsByTagName('img') } else {imgs = d.images }; for (var i = 0; i < imgs.length; i++) {if (imgs[i].getAttribute("data-src") && !imgs[i].__isSL) {if (imgs[i].offsetWidth == 0 && imgs[i].offsetHeight == 0) {imgs[i].__pObj = imgs[i].parentNode; while (imgs[i].__pObj.offsetWidth == 0 && imgs[i].__pObj.offsetHeight == 0) {imgs[i].__pObj = imgs[i].__pObj.parentNode } }; imgs[i].__isSL = true; p.push(imgs[i]); num++ } }; if (num > 0) {if (this.status != 'scrolling') {sina.addEvent(w, "scroll", eventFunc); this.status = "scrolling"; timer = setInterval(function() {that.timer() }, 200) }; this.scroll() } }, timer: function() {if (iTotal !== d.images.length) {iTotal = d.images.length; this.init() }; var vh = Math.min(h.clientHeight, b.clientHeight); var vt = (w.pageYOffset || b.scrollTop || h.scrollTop) - Math.round(vh * (this.mult - 1) / 2); var vb = vt + Math.round(vh * ((this.mult - 1) / 2 + 1)); if (bT !== vt || vb !== bVH) {this.scroll() } }, showImg: function(img) {if (img.getAttribute("data-src")) { img.removeAttribute("data-top"); img.__pObj = null; img.__isSL = null;img.src = img.getAttribute("data-src"); if(isIE6){return false;} } }, scroll: function() {if (this.status != "scrolling") {return }; var cache = 0; if (bH == d.body.scrollHeight) {cache = 1 } else {bH = d.body.scrollHeight }; var vh = Math.min(h.clientHeight, b.clientHeight); var vt = (w.pageYOffset || b.scrollTop || h.scrollTop) - Math.round(vh * (this.mult - 1) / 2); var vb = vt + Math.round(vh * ((this.mult - 1) / 2 + 1)); bT = vt; bVH = vb; var s = 0, posTop, obj; for (var i = 0; i < p.length; i++) {if (!p[i].getAttribute("data-src")) {continue }; s++; if (!cache) {if (p[i].offsetWidth == 0 && p[i].offsetHeight == 0) {p[i].__pObj = p[i].parentNode; if (!p[i].__pObj) {this.showImg(p[i]); continue }; while ( !! p[i].__pObj && p[i].__pObj.offsetWidth == 0 && p[i].__pObj.offsetHeight == 0) {p[i].__pObj = p[i].__pObj.parentNode } }; obj = p[i].__pObj || p[i]; posTop = sina.absPosition(obj, b).top; p[i].setAttribute("data-top", posTop) } else {posTop = p[i].getAttribute("data-top") } if (posTop >= vt && posTop <= vb) {this.showImg(p[i]) } }; if (s == 0) {this.status = "complete"; sina.delEvent(w, "scroll", eventFunc); clearInterval(timer) } } }; this.scrollLoader = scrollLoader }(); scrollLoader.init(); - - </script> - - <!-- ¼ì²éµØÓò begin --> - <script type="text/javascript"> - ;(function() { - //var shmIPlookup = null; - var handle = function(info, city) { - // infoΪremote_ip_info,cityΪÓëcookieÖеÄcity±È½ÏºóµÄ³ÇÊУ¬cookieÓÅÏÈ - var province = info.province; - city = info.city; - //var province = shmIPlookup.getPNameByCName(city); - //city = city; - - var desc = info.desc; - if (info.ret != 1) { - return; - } - - var autoJS = ''; - var areaJS = ''; - var mtJS = ''; - switch (province) { - case 'ÉϺ£': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sh.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/14_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shanghai.js'; - break; - - case 'ËÄ´¨': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sc.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/12_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/sichuan.js'; - break; - - case 'ºÓÄÏ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/henan.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/1_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/henan.js'; - break; - - case '¹ã¶«': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/gd.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/1031/26.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/guangdong.js'; - if (city == 'Ö麣' || desc == 'Zhuhai') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/zhuhai.js'; } - if (city == 'ÉîÛÚ' || desc == 'Shenzhen') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/shenzhen.js'; } - break; - - case '¸£½¨': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/fj.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/7_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/fujian.js'; - if (city == 'ÏÃÃÅ' || desc == 'Xiamen' || city == 'ÕÄÖÝ' || desc == 'Zhangzhou' || city == 'ȪÖÝ' || desc == 'Quanzhou') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/fj_mn.js'; } - break; - - case 'Õã½­': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/zj.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/4_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/zhejiang.js'; - if (city == 'Äþ²¨' || desc == 'Ningbo') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/zj_nb.js'; } - break; - - case 'ÖØÇì': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/cq.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/11_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/chongqing.js'; - break; - - case 'ºþÄÏ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hunan.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/10_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hunan.js'; - break; - - case 'ºþ±±': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hb.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/9_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hubei.js'; - break; - - case 'ÉÂÎ÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sx.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/13_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shannxi.js'; - break; - - case 'ÁÉÄþ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/ln.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/3_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/liaoning.js'; - if (city == '´óÁ¬' || desc == 'Dalian') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/ln_dl.js'; } - break; - - case 'ºÚÁú½­': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hlj.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/5_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/heilongjiang.js'; - break; - - case '°²»Õ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/ah.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/8_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/anhui.js'; - break; - - case 'ºÓ±±': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hebei.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/6_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hebei.js'; - break; - - case '½­ËÕ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jiangsu.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/2_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/jiangsu.js'; - if (city == 'ÎÞÎý') { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jiangsu_wx.js'; } - if (city == 'ËÕÖÝ') { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sz.js'; } - break; - - case 'Ìì½ò': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/tj.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/15_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/tianjin.js'; - break; - - case 'ɽÎ÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/shanxi.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/16_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shanxi.js'; - break; - - case '¼ªÁÖ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jl.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/19_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/jilin.js'; - break; - - case '½­Î÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jx.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/17_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/jiangxi.js'; - break; - - case 'º£ÄÏ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hainan.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/18_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hainan.js'; - break; - - case 'ɽ¶«': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sd.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/20_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shandong.js'; - if (city == 'Çൺ') { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/qd.js'; } - break; - - case '¹ãÎ÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/gx.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0528/22.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/guangxi.js'; - break; - - case 'ÔÆÄÏ': - autoJS = 'http://auto.sina.com.cn/867/2013/0528/23.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/yunnan.js'; - break; - - case '¹óÖÝ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/gz.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0528/24.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/guizhou.js'; - break; - - case '¸ÊËà': - autoJS = 'http://auto.sina.com.cn/867/2013/0528/25.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/gansu.js'; - break; - - case 'н®': - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/xinjiang.js'; - break; - - case 'ÄÚÃɹÅ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/nmg.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/1126/27.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/neimenggu.js'; - break; - - default: - //autoJS = ''; - //areaJS = ''; - break; - } - // Æû³µip¶¨Ïò - if(autoJS){ - jsLoader({ - url : autoJS - }); - } - //µØ·½Õ¾ip¶¨Ïò - if(areaJS){ - jsLoader({ - url : areaJS - }); - } - //ýÍØip¶¨Ïò - if(mtJS){ - jsLoader({ - url : mtJS - }); - } - }; - - jsLoader({ - name: 'shm', - callback: function() { - SHM.home.iplookup.load(function(info, city) { - handle(info, city); - }); - } - }); - - //MT ip¶¨Ïò -/* - jsLoader({ - name: 'ipMT', - url:'http://www.sina.com.cn/js/67/index2013/ipMT.js' - }); -*/ - - })(); - -//·¿²úip¶¨Ïò -;(function(){ - var API = 'http://ip.house.sina.com.cn/sina_sanshou_2010.php'; - var render = function() { - for (var i = 0, len = SI_IP_House_.length; i < len; i++) { - var item = SI_IP_House_[i]; - var node = document.getElementById('SI_IP_House_'+i); - if (item&&node) { - node.innerHTML = item; - } - } - }; - jsLoader({ - name: 'ipHouse', - url:API, - callback: function() { - render(); - } - }); -})(); - - </script> - <!-- ¼ì²éµØÓò end --> - - <!-- ²Æ¾­°å¿éµ÷ÓÃjs begin --> - <script type="text/javascript"> - ;(function(){ - var render = function(id,html){ - var wrap = document.getElementById(id); - if(wrap){ - wrap.innerHTML = html; - } - }; - jsLoader({ - name : 'financeHQ', - url : 'http://hq.sinajs.cn/list=s_sh000001,s_sh000011', - callback : function(){ - var amtHQ = parseFloat( hq_str_s_sh000001.split(",")[1] ), - rateHQ = parseFloat( hq_str_s_sh000001.split(",")[3] ); - - render('SI_Text_sh600001', - "»¦ " + amtHQ.toFixed(1) + "(" + ( rateHQ > 0 ? "+" : ( rateHQ == 0 ? "" : "" ) ) + rateHQ.toFixed(1) + "%)" - ); - render('SI_Text_sh600011', - "ÉÏ»ù " + hq_str_s_sh000011.split(",")[1] - ); - } - }); - })(); - - </script> - <!-- ²Æ¾­°å¿éµ÷ÓÃjs end --> - -<!--_SINA_ADS_BEGIN_--> -<!-- ¿ØÖƽű¾¶¥ ÇëÎðÐ޸ĻòÒƶ¯ --> -<script language="javascript" type="text/javascript">function ADFunc(sFuncName){this.sFuncName = sFuncName;};function ADFuncSeq(){this.aryFunc = new Array();this.push = function(sFuncName){try{this.aryFunc.push(new ADFunc(sFuncName));}catch(e){}};this.shift = function(){try{return this.aryFunc.shift();}catch(e){}};};var arryADSeq = new ADFuncSeq();function nextAD(){var oFunAD = arryADSeq.shift();if (oFunAD != null){try{eval(oFunAD.sFuncName);}catch(e){}}};</script> -<!-- ¿ØÖƽű¾¶¥ ÇëÎðÐ޸ĻòÒƶ¯--> - -<!--¼ÓÔØÈ«ÆÁ begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000000001" data-ad-type="fullscreen"></ins><script>var FullScreenData=new Array();(sinaads = window.sinaads || []).push({});</script> -<!--¼ÓÔØÈ«ÆÁ end--> - -<!--¼ÓÔØÁ÷ýÌå begin--> -<span id="SteamMediaWrap"></span> -<ins class="sinaads" data-ad-pdps="PDPS000000002520" data-ad-type="stream"></ins><script>var SteamMediaData=new Array();(sinaads = window.sinaads || []).push({});</script> -<!--¼ÓÔØÁ÷ýÌå end--> - -<!--ϲ±¨ begin--> -<script> - function Schedule(e){e="string"==typeof e?[e]:e||[],this.ranges=[];var t,n=0,r=e.length,i,s,o=new Date,u=o.getFullYear()+"/"+(o.getMonth()+1)+"/"+o.getDate();for(;n<r;n++)t=e[n].replace(/\-/g,"/").split("~"),i=t[0],s=t[1]?t[1]:t[0],i.indexOf(":")===-1&&(i+=" 0:0:0"),s.indexOf(":")===-1&&(s+=" 0:0:0"),i.indexOf("/")===-1&&(i=u+" "+i),s.indexOf("/")===-1&&(s=u+" "+s),i=+this.parse(i),s=+this.parse(s),s<=i&&(s+=864e5),this.ranges[n]=[i,s]}Schedule.prototype={check:function(e){var t=this.ranges,n=0,r,i=t.length<=0,e=e?+this.parse(e):+(new Date);while(!i&&(r=t[n++]))i=e>=r[0]&&e<=r[1];return i},parse:function(e){var t=new RegExp("^\\d+(\\-|\\/)\\d+(\\-|\\/)\\d+$");if("string"==typeof e){if(t.test(e)||isNaN(Date.parse(e))){var n=e.split(/ |T/),r=n.length>1?n[1].split(/[^\d]/):[0,0,0],i=n[0].split(/[^\d]/);return new Date(i[0]-0,i[1]-1,i[2]-0,r[0]-0,r[1]-0,r[2]-0)}return new Date(e)}return e}} - - //618ºÅ9:00-12 ¿ØÖÆͶ·Åʱ¼ä - //if (new Schedule('2015-06-18 9:00:00~2015-06-18 12:59:59').check()) { - _sinaadsCacheData = window._sinaadsCacheData || {}; - _sinaadsCacheData['feibiao_xibao'] = { - "type" : "stream", - "content" : [ - { - "monitor":[""], - "link":[""], - "type":["js"], - "pv":[], - "src":[ - "http://rm.sina.com.cn/bj_chuanyang/tb20150618/index.js" - ] - } - ], - "size":"950*450", - "id":"feibiao_xibao" - }; - //} -</script> -<ins class="sinaads" data-ad-pdps="feibiao_xibao"></ins> -<script>(sinaads = window.sinaads || []).push({});</script> -<!--ϲ±¨ end--> - -<!--¼ÓÔØ¿çÀ¸ begin--> -<span id="CoupletMediaWrap"></span> -<ins class="sinaads" data-ad-pdps="PDPS000000006450" data-ad-type="couplet"></ins><script>var CoupletMediaData=new Array();(sinaads = window.sinaads || []).push({params:{sinaads_couple_top : 45}});</script> -<!--¼ÓÔØ¿çÀ¸ end--> - -<!--ÐÂÀËÊ×Ò³120x270ËæÆÁ¶ÔÁª begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000054315" data-ad-type="float"></ins> -<script>(sinaads = window.sinaads || []).push({ - params : { - sinaads_float_show_pos: 800, //ËæÆÁ¶ÔÁª - sinaads_float_top : 46 - } -});</script> -<!--ÐÂÀËÊ×Ò³120x270ËæÆÁ¶ÔÁª end--> - -<!--ÐÂÀËÊ×Ò³¶þÂÖ²¥±³Í¶¹ã¸æ¿ªÊ¼--> -<ins class="sinaads" data-ad-pdps="PDPS000000051826" data-ad-type="bp"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<!--ÐÂÀËÊ×Ò³¶þÂÖ²¥±³Í¶¹ã¸æ½áÊø--> - -<!-- CPMÊÓ´°¹ã¸æ ¿ªÊ¼ --> -<span id="videoWindowWrap"></span> -<ins class="sinaads" data-ad-pdps="PDPS000000052408" data-ad-type="videoWindow"></ins> -<script> -(sinaads = window.sinaads || []).push({ - params : { - sinaads_frequence : 60 * 10 - } -}); -</script> -<!-- CPMÊÓ´°¹ã¸æ ½áÊø --> - -<!-- ¿ØÖƽű¾Î² ÇëÎðÐ޸ĻòÒƶ¯ --> -<script type="text/javascript"> -jsLoader({ - name : 'salebottom', - url : 'http://d4.sina.com.cn/d1images/common/salebottom.js' -}); -</script> -<script type="text/javascript"> -jsLoader({ - name : 'salebottom', - callback : function(){ - try{nextAD();}catch(e){} - } -}); -</script> -<!-- ¿ØÖƽű¾Î² ÇëÎðÐ޸ĻòÒƶ¯--> -<!--_SINA_ADS_END_--> - -<!--ͨÀ¸¹ã¸æÒþ²Ø»úÖÆ--> -<script type="text/javascript"> -jsLoader({ - name: 'adNone', - url:'http://d1.sina.com.cn/d1images/common/adNone.js' -}); -</script> - -<script type="text/javascript" src="http://i1.sinaimg.cn/unipro/pub/suda_m_v629.js"></script> -<script type="text/javascript">suds_init(41,1.0000,1015,2);</script> - -<!-- body code begin --> -<script type="text/javascript"> -(function(){ - if(window.top !== window.self || window._thereIsNoRealTimeMessage){return}; - var script = document.createElement('script'); - script.setAttribute('charset', 'gb2312'); - script.src = 'http://news.sina.com.cn/js/694/2012/0830/realtime.js?ver=1.5.1'; - document.getElementsByTagName('head')[0].appendChild(script); -})(); -</script> - -<!-- SSO_UPDATECOOKIE_START --> -<script type="text/javascript">var sinaSSOManager=sinaSSOManager||{};sinaSSOManager.q=function(b){if(typeof b!="object"){return""}var a=new Array();for(key in b){a.push(key+"="+encodeURIComponent(b[key]))}return a.join("&")};sinaSSOManager.es=function(f,d,e){var c=document.getElementsByTagName("head")[0];var a=document.getElementById(f);if(a){c.removeChild(a)}var b=document.createElement("script");if(e){b.charset=e}else{b.charset="gb2312"}b.id=f;b.type="text/javascript";d+=(/\?/.test(d)?"&":"?")+"_="+(new Date()).getTime();b.src=d;c.appendChild(b)};sinaSSOManager.doCrossDomainCallBack=function(a){sinaSSOManager.crossDomainCounter++;document.getElementsByTagName("head")[0].removeChild(document.getElementById(a.scriptId))};sinaSSOManager.crossDomainCallBack=function(a){if(!a||a.retcode!=0){return false}var d=a.arrURL;var b,f;var e={callback:"sinaSSOManager.doCrossDomainCallBack"};sinaSSOManager.crossDomainCounter=0;if(d.length==0){return true}for(var c=0;c<d.length;c++){b=d[c];f="ssoscript"+c;e.scriptId=f;b=b+(/\?/.test(b)?"&":"?")+sinaSSOManager.q(e);sinaSSOManager.es(f,b)}};sinaSSOManager.updateCookieCallBack=function(c){var d="ssoCrossDomainScriptId";var a="http://login.sina.com.cn/sso/crossdomain.php";if(c.retcode==0){var e={scriptId:d,callback:"sinaSSOManager.crossDomainCallBack",action:"login",domain:"sina.com.cn"};var b=a+"?"+sinaSSOManager.q(e);sinaSSOManager.es(d,b)}else{}};sinaSSOManager.updateCookie=function(){var g=1800;var p=7200;var b="ssoLoginScript";var h=3600*24;var i="sina.com.cn";var m=1800;var l="http://login.sina.com.cn/sso/updatetgt.php";var n=null;var f=function(e){var r=null;var q=null;switch(e){case"sina.com.cn":q=sinaSSOManager.getSinaCookie();if(q){r=q.et}break;case"sina.cn":q=sinaSSOManager.getSinaCookie();if(q){r=q.et}break;case"51uc.com":q=sinaSSOManager.getSinaCookie();if(q){r=q.et}break}return r};var j=function(){try{return f(i)}catch(e){return null}};try{if(g>5){if(n!=null){clearTimeout(n)}n=setTimeout("sinaSSOManager.updateCookie()",g*1000)}var d=j();var c=(new Date()).getTime()/1000;var o={};if(d==null){o={retcode:6102}}else{if(d<c){o={retcode:6203}}else{if(d-h+m>c){o={retcode:6110}}else{if(d-c>p){o={retcode:6111}}}}}if(o.retcode!==undefined){return false}var a=l+"?callback=sinaSSOManager.updateCookieCallBack";sinaSSOManager.es(b,a)}catch(k){}return true};sinaSSOManager.updateCookie();</script> -<!-- SSO_UPDATECOOKIE_END --> - -<!-- Start Wrating --> -<script language="javascript"> -var wrUrl="//sina.wrating.com/";var wrDomain="sina.com.cn";var wratingDefaultAcc="860010-0323010000";var wratingAccArray={"history.sina.com.cn":"860010-0334010000","health.sina.com.cn":"860010-0330010000","fashion.sina.com.cn":"860010-0311010000","collection.sina.com.cn":"860010-0331010000","2014.sina.com.cn":"860010-0308160000","2012.sina.com.cn":"860010-0308150000","torch.2008.sina.com.cn":"860010-0308070000","video.sina.com.cn":"860010-0309010000","ent.sina.com.cn":"860010-0312010000","tech.sina.com.cn":"860010-0313010000","mobile.sina.com.cn":"860010-0313020000","house.sina.com.cn":"860010-0315010000","bj.house.sina.com.cn":"860010-0315020000","auto.sina.com.cn":"860010-0316010000","eladies.sina.com.cn":"860010-0317010000","woman.sina.com.cn":"860010-0317010000","games.sina.com.cn":"860010-0318010000","edu.sina.com.cn":"860010-0307010000","baby.sina.com.cn":"860010-0320010000","astro.sina.com.cn":"860010-0321020000","news.sina.com.cn":"860010-0310010000","weather.news.sina.com.cn":"860010-0310020000","mil.news.sina.com.cn":"860010-0310030000","www.sina.com.cn":"860010-0322010000","home.sina.com.cn":"860010-0322010000","sports.sina.com.cn":"860010-0308010000","shidefc.sina.com.cn":"860010-0308020000","weiqi.sina.com.cn":"860010-0308030000","f1.sina.com.cn":"860010-0308040000","golf.sina.com.cn":"860010-0308050000","2002.sina.com.cn":"860010-0308060000","2004.sina.com.cn":"860010-0308060000","2006.sina.com.cn":"860010-0308060000","2008.sina.com.cn":"860010-0308070000","yayun2002.sina.com.cn":"860010-0308060000","yayun2006.sina.com.cn":"860010-0308060000","book.sina.com.cn":"860010-0319010000","cul.book.sina.com.cn":"860010-0319020000","comic.book.sina.com.cn":"860010-0319030000","finance.sina.com.cn":"860010-0314010000","money.sina.com.cn":"860010-0314020000","yue.sina.com.cn":"860010-0324010000","www.sina.com":"860010-0322010000"};function vjTrack(){var U=1800;var T=false;var S=false;var R="";var Q="0";var P="";var N;var L;var K;var J;var I;var H="expires=Fri, 1 Jan 2038 00:00:00 GMT;";var G=0;if(document.location.protocol=="file:"){return }T=navigator.cookieEnabled?"1":"0";S=navigator.javaEnabled()?"1":"0";var F="0";var E;var C=-1;var D=document.cookie;if(T=="1"){C=D.indexOf("vjuids=");if(C<0){E=vjVisitorID();document.cookie="vjuids="+escape(E)+";"+H+";domain="+wrDomain+";path=/;";if(document.cookie.indexOf("vjuids=")<0){T="0"}else{Q="1"}}else{E=vjGetCookie("vjuids")}}L=document.referrer;if(!L||L==""){L=""}R=vjFlash();if(self.screen){N=screen.width+"x"+screen.height+"x"+screen.colorDepth}else{if(self.java){var M=java.awt.Toolkit.getDefaultToolkit();var O=M.getScreenSize();N=O.width+"x"+O.height+"x0"}}if(navigator.language){K=navigator.language.toLowerCase()}else{if(navigator.browserLanguage){K=navigator.browserLanguage.toLowerCase()}else{K="-"}}I="";var B;var X;X=new Date();J=X.getTimezoneOffset()/-60;J=X.getTimezoneOffset()/-60;B="&s="+N+"&l="+K+"&z="+J+"&j="+S+"&f="+R;if(T=="1"){C=document.cookie.indexOf("vjlast=");if(C<0){G=0}else{G=parseInt(vjGetCookie("vjlast"))}}if((X.getTime()/1000)-G>U){F="1";document.cookie="vjlast="+Math.round(X.getTime()/1000)+";"+H+";domain="+wrDomain+";path=/;"}if(L!=""){B=B+"&r="+escape(L)}if(F!="0"){B=B+"&n="+G}if(Q!="0"){B=B+"&u="+Q}var V;var A=vjGetAcc();var W=vjGetDomain();V=wrUrl+"a.gif?a="+X.getTime().toString(16)+"&t="+escape(I)+"&i="+escape(E)+"&b="+escape(document.location)+"&c="+A+B+"&ck="+W;document.write('<img src="'+V+'" width="1" height="1" style="visibility:hidden;position:absolute;left:0px;top:0px;z-index:-1" />')}function vjGetAcc(){var B=document.location.toString().toLowerCase();var C=(B.split("/"))[2];var A=wratingAccArray[C];if(typeof (A)=="undefined"){A=wratingDefaultAcc}return A}function vjFlash(){var _wr_f="-",_wr_n=navigator;if(_wr_n.plugins&&_wr_n.plugins.length){for(var ii=0;ii<_wr_n.plugins.length;ii++){if(_wr_n.plugins[ii].name.indexOf("Shockwave Flash")!=-1){_wr_f=_wr_n.plugins[ii].description.split("Shockwave Flash ")[1];break}}}else{if(window.ActiveXObject){for(var ii=10;ii>=2;ii--){try{var fl=eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+ii+"');");if(fl){_wr_f=ii+".0";break}}catch(e){}}}}return _wr_f}function vjHash(B){if(!B||B==""){return 0}var D=0;for(var C=B.length-1;C>=0;C--){var A=parseInt(B.charCodeAt(C));D=(D<<5)+D+A}return D}function vjVisitorID(){var B=vjHash(document.location+document.cookie+document.referrer).toString(16);var A;A=new Date();return B+"."+A.getTime().toString(16)+"."+Math.random().toString(16)}function vjGetCookieVal(B){var A=document.cookie.indexOf(";",B);if(A==-1){A=document.cookie.length}return unescape(document.cookie.substring(B,A))}function vjGetCookie(C){var B=C+"=";var F=B.length;var A=document.cookie.length;var E=0;while(E<A){var D=E+F;if(document.cookie.substring(E,D)==B){return vjGetCookieVal(D)}E=document.cookie.indexOf(" ",E)+1;if(E==0){break}}return null}function vjGetDomain(){var A=0;try{if(window.self.parent!=self){var D=/sina.com/i;var C=document.location.toString().toLowerCase();var B=parent.location.toString().toLowerCase();if(D.test(C)&&D.test(B)){A=1}}}catch(e){A=1}return A}vjTrack(); -</script> -<!-- End Wrating--> -<!-- body code end --> -</body> -</html> \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/www.sina.com.cn b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/www.sina.com.cn deleted file mode 100644 index d3a6003..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cache/www.sina.com.cn +++ /dev/null @@ -1,7468 +0,0 @@ -<!DOCTYPE html> -<!--[30,131,1] published at 2015-06-18 14:48:24 from #130 by system--> -<html> -<head> -<link rel="icon" sizes="any" mask href="http://www.sina.com.cn/favicon.svg"> -<meta name="theme-color" content="red"> -<link rel="icon" type="image/x-icon" href="http://www.sina.com.cn/favicon.ico"> - <meta http-equiv="Content-type" content="text/html; charset=gb2312" /> - <title>ÐÂÀËÊ×Ò³</title> - - <meta name="keywords" content="ÐÂÀË,ÐÂÀËÍø,SINA,sina,sina.com.cn,ÐÂÀËÊ×Ò³,ÃÅ»§,×ÊѶ" /> - <meta name="description" content="ÐÂÀËÍøΪȫÇòÓû§24СʱÌṩȫÃ漰ʱµÄÖÐÎÄ×ÊѶ£¬ÄÚÈݸ²¸Ç¹úÄÚÍâÍ»·¢ÐÂÎÅʼþ¡¢Ìå̳ÈüÊ¡¢ÓéÀÖʱÉС¢²úÒµ×ÊѶ¡¢ÊµÓÃÐÅÏ¢µÈ£¬ÉèÓÐÐÂÎÅ¡¢ÌåÓý¡¢ÓéÀÖ¡¢²Æ¾­¡¢¿Æ¼¼¡¢·¿²ú¡¢Æû³µµÈ30¶à¸öÄÚÈÝƵµÀ£¬Í¬Ê±¿ªÉ販¿Í¡¢ÊÓƵ¡¢ÂÛ̳µÈ×ÔÓÉ»¥¶¯½»Á÷¿Õ¼ä¡£" /> - <meta name="stencil" content="PGLS000022" /> - <meta name="publishid" content="30,131,1" /> - <meta name="verify-v1" content="6HtwmypggdgP1NLw7NOuQBI2TW8+CfkYCoyeB8IDbn8=" /> - <meta name="360-site-verification" content="63349a2167ca11f4b9bd9a8d48354541" /> - <meta name="application-name" content="ÐÂÀËÊ×Ò³"/> - <meta name ="msapplication-TileImage" content="http://i1.sinaimg.cn/dy/deco/2013/0312/logo.png"/> - <meta name="msapplication-TileColor" content="#ffbf27"/> - <meta name="sogou_site_verification" content="BVIdHxKGrl"/> -<link rel="apple-touch-icon" href="http://i3.sinaimg.cn/home/2013/0331/U586P30DT20130331093840.png" /> - - <script type="text/javascript"> - //jsÒì²½¼ÓÔعÜÀí - (function(){var w=this,d=document,version='1.0.7',data={},length=0,cbkLen=0;if(w.jsLoader){if(w.jsLoader.version>=version){return};data=w.jsLoader.getData();length=data.length};var addEvent=function(obj,eventType,func){if(obj.attachEvent){obj.attachEvent("on"+eventType,func)}else{obj.addEventListener(eventType,func,false)}};var domReady=false,ondomReady=function(){domReady=true};if(d.addEventListener){var webkit=navigator.userAgent.match(/AppleWebKit\/(\d+)/);if(webkit&&webkit[1]<525){doReadyStateCheck()}else{d.addEventListener("DOMContentLoaded",function(){d.removeEventListener("DOMContentLoaded",arguments.callee,false);ondomReady()},false)}};function doScrollCheck(){if(domReady){return};try{d.documentElement.doScroll("left")}catch(e){return};ondomReady()};function doReadyStateCheck(){if(domReady){return};if(d.readyState=='loaded'||d.readyState=='complete'){ondomReady();return}else{setTimeout(doReadyStateCheck,1);return}};function createPosNode(){if(jsLoader.caller){return};cbkLen++;if(!domReady&&d.attachEvent){doScrollCheck()};if(!domReady){try{d.write('<div style="display:none" id="_jl_pos_'+cbkLen+'"></div>');s=d.getElementById('_jl_pos_'+cbkLen)}catch(e){var s=d.createElement('div');s.id='_jl_pos_'+cbkLen;s.style.display='none';d.body.insertBefore(s,d.body.firstChild)}}else{var s=d.createElement('div');s.id='_jl_pos_'+cbkLen;s.style.display='none';d.body.appendChild(s)};return s};function getScript(url,dispose,charset){var scriptNode=d.createElement("script");scriptNode.type="text/javascript";if(charset){scriptNode.charset=charset};scriptNode.onreadystatechange=scriptNode.onload=function(){if(!this.readyState||this.readyState=="loaded"||this.readyState=="complete"){if(dispose){dispose()};scriptNode.onreadystatechange=scriptNode.onload=null;scriptNode.parentNode.removeChild(scriptNode)}};scriptNode.src=url;var h=d.getElementsByTagName("head")[0];h.insertBefore(scriptNode,h.firstChild)};var write=d.write,posNode;function cWrite(str){if(posNode.childNodes.length>0){return};if(posNode.innerHTML!=''){while(posNode.childNodes.length){posNode.parentNode.insertBefore(posNode.childNodes[0],posNode)}};posNode.innerHTML=str;while(posNode.childNodes.length){posNode.parentNode.insertBefore(posNode.childNodes[0],posNode)}};var JsObj=function(name,url){this.name=name;this.url=url;this.callback=[]};JsObj.prototype={status:'init',onload:function(){this.status='ok';var errors=[];for(var i=0;i<this.callback.length;i++){if(typeof this.callback[i]=='function'){try{if(this.callback[i].posNode){posNode=this.callback[i].posNode;d.write=cWrite};this.callback[i]();if(this.callback[i].posNode){d.write=write;this.callback[i].posNode.parentNode.removeChild(this.callback[i].posNode)}}catch(e){errors.push(e)}}};this.callback=[];if(errors.length!=0){throw errors[0]}}};w.jsLoader=function(cfg){var url=cfg.url||"";var name=cfg.name||"";var callback=cfg.callback||"";var charset=cfg.charset||"";if(name){if(!data[name]){if(!url){data[name]=new JsObj(name);data[name].status='waiting'}else{data[name]=new JsObj(name,url)};length++}else if(data[name].status=='waiting'&&url){data[name].status='init'};if(cfg.status){data[name].status=cfg.status};if(data[name].status=='loading'||data[name].status=='waiting'){if(typeof callback=='function'){callback.posNode=createPosNode();data[name].callback.push(callback)};return}else if(data[name].status=='ok'){if(typeof callback=='function'){callback()};return}}else{if(!url){return};for(var item in data){if(data[item].url==url){name=item;break}};if(!name){name='noname'+length;data[name]=new JsObj(name,url);length++};if(data[name].status=='loading'){if(typeof callback=='function'){callback.posNode=createPosNode();data[name].callback.push(callback)};return}else if(data[name].status=='ok'){if(typeof callback=='function'){callback()};return}};if(typeof callback=='function'){callback.posNode=createPosNode();data[name].callback.push(callback)};getScript(url,function(){data[name].onload()},charset);data[name].status='loading'};w.jsLoader.version=version;w.jsLoader.getData=function(){return data}})(); - -/* - jsLoader({ - name : 'iplookup', - url : 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js' - }); -*/ - - </script> - -<script type="text/javascript" src="http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js"></script> - -<script type="text/javascript"> - jsLoader({ - name : 'iplookup', - status : 'ok' - }); -</script> - -<!-- ͬ²½jsºÏ²¢saletop.js¡¢leju.js --> -<script type="text/javascript" src="http://d1.sina.com.cn/js/index/14/sync.js"></script> - -<!-- -<script type="text/javascript" src="http://d4.sina.com.cn/d1images/common/saletop.js"></script> ---> - -<script type="text/javascript"> - jsLoader({ - name : 'saletop', - status : 'ok' - }); -</script> - -<!-- ÀÖ¾Ó¹ã¸æ½Å±¾ begin--> -<!-- -<script charset="UTF-8" src="http://d5.sina.com.cn/litong/zhitou/leju/leju.js"></script> ---> - -<script> - //ÕýʽÊý¾Ý·¾¶£¬°ÑÕâ¸ö·¾¶¸Ä³É404µØÖ·¿ÉÒÔÇëÇóĬÈÏÊý¾Ý£¬²âÊÔÈÝ´í - leju.conf.url = 'http://adm.leju.sina.com.cn/get_ad_list/PG_514AC419D66F33'; - //ÈÝ´íÊý¾Ý·¾¶ - leju.conf.defaultUrl = 'http://staticadm.leju.sina.com.cn/get_ad_list/PG_514AC419D66F33.js'; - //»ñÈ¡Êý¾Ý - var lejuMedia = leju.getData(); -</script> -<!-- ÀÖ¾Ó¹ã¸æ½Å±¾ end--> - -<script> - //ÉèÖñ¾Ò³ÃæµÄ¸»Ã½ÌåÀàÐ͵Ä˳Ðò - - //var _SINAADS_CONF_PAGE_MEDIA_ORDER = ["PDPS000000000001", "PDPS000000002520", "PDPS000000006450", "PDPS000000051826", "PDPS000000052408"]; - - var _SINAADS_CONF_PAGE_MEDIA_ORDER = ["PDPS000000000001", "PDPS000000002520", "PDPS000000006450", "PDPS000000051826", "PDPS000000052408", "feibiao_xibao"]; - - //var sinaadsPageMediaOrder = ['fullscreen', 'stream', 'couplet', 'bp', 'videoWindow']; -</script> - - <style> - /* ³õʼ»¯CSS */ - html, body, ul, li, ol, dl, dd, dt, p, h1, h2, h3, h4, h5, h6, form, fieldset, legend, img { margin:0; padding:0; } - fieldset, img { border:none; } - img{display: block;} - address, caption, cite, code, dfn, th, var { font-style:normal; font-weight:normal; } - ul, ol { list-style:none; } - input { padding-top:0; padding-bottom:0; font-family: "SimSun","ËÎÌå";} - input::-moz-focus-inner { border:none; padding:0; } - select, input { vertical-align:middle; } - select, input, textarea { font-size:12px; margin:0; } - input[type="text"], input[type="password"], textarea { outline-style:none; -webkit-appearance:none; } - textarea { resize:none; } - table { border-collapse:collapse; } - body { color:#333; padding:5px 0; font:12px/20px "SimSun","ËÎÌå","Arial Narrow",HELVETICA; background:#fff;/* overflow-y:scroll;*/ } - .clearfix:after { content:"."; display:block; height:0; visibility:hidden; clear:both; } - .clearfix { zoom:1; } - .clearit { clear:both; height:0; font-size:0; overflow:hidden; } - a { color:#666; text-decoration:none; } - a:visited { color:#666; } - a:hover, a:active, a:focus { color:#ff8400; text-decoration:underline; } - - .hidden{visibility:hidden;} - /**** Á´½ÓÑÕÉ« link,visited,hover*/ - /*#333 #8D0000 #333*/ - .fe661{color: #e66100 !important;} - .fe661:visited{color: #e66100 !important;} - .fe661:hover, .fe661:visited, .fe661:focus{color: #ff8400 !important;} - span.fe661 a:link, span.fe661 a:visited{color: #e66100 !important;} - span.fe661 a:hover, span.fe661 a:focus, span.fe661 a:active{color: #ff8400 !important;} - - .f9157{color: #e66100 !important;} - span.f9157 a:link, span.f9157 a:visited{color: #915724 !important;} - span.f9157 a:hover, span.f9157 a:focus, span.f9157 a:active{color: #ff8400 !important;} - - /*main*/ - .main{width: 1000px;margin: 0 auto;clear: both;background-color: #fff;overflow: hidden; } - - /**** ±à¼­Ï°¹ß */ - a.linkRed:link,a.linkRed:visited{color:#e66100!important;} - a.linkRed:hover,a.active:hover{color:#e66100!important;} - a.liveNewsLeft{background:url(http://i1.sinaimg.cn/dy/deco/2013/0316/liveNewsLeft.gif) no-repeat 0px 50%; padding-left:25px;} - a.audioNewsLeft{background:url(http://i3.sinaimg.cn/dy/deco/2009/0617/LeftAudio.gif) no-repeat ;padding-left:20px} - a.videoNewsLeft{background: url(http://i1.sinaimg.cn/dy/deco/2013/0313/videoNewsLeft.gif) 0 50% no-repeat;padding-left: 23px;} - li.videoNewsLeft{background: url(http://i1.sinaimg.cn/dy/deco/2013/0313/videoNewsLeft.gif) 0 50% no-repeat !important;padding-left: 23px !important;} - a.photoNewsLeft {background: url(http://i1.sinaimg.cn/dy/main/icon/photoNewsLeft2.gif) no-repeat 0 center;padding-left: 23px;} - - /*** ±êÌâ*/ - .tit01{height: 47px;} - .tit01-l{float: left;display: inline;border: 1px solid #d9dce0;border-right:0px;height: 25px;_width:114px;} - .tit01-sw{margin-left: -1px;} - .tit01-l span{height: 25px;line-height:25px;width: 37px;text-align:center;border-right:1px solid #d9dce0; float: left;display: inline;color: #4f4f4f;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -1px repeat-x;cursor: pointer;} - .tit01-l span.selected{background: #fff;border-top: 2px solid #ff8400;margin-top: -1px;position: relative;_margin-bottom: -1px;} - .tit01-r{float: right;border: 1px solid #d9dce0;height: 25px;} - .tit01-r .tit-ipt, .tit01-r .tit-sub{float: left;display: inline;} - .tit01-r .tit-ipt{border: 0px;height: 25px;line-height: 25px;color: #999;background: #f7f7f7;width: 78px;padding-left: 5px;} - .tit01-r .tit-sub{width: 33px;text-align: center;background: #ffefc1;color: #4f4f4f;line-height: 25px;height: 25px;} - .tit01-r .tit-sub:visited{color: #4f4f4f} - .tit01-r .tit-sub:hover, .tit01-r .tit-sub:focus, .tit01-r .tit-sub:active{color: #ff8400;text-decoration: none;} - - .tit02{height: 35px;line-height: 35px;border-bottom: 1px solid #e3e6ed;} - .tit02 h3{font-weight: normal;color: #000;font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimHei","ºÚÌå";font-size: 16px;float: left;display: inline;margin-left: 12px;} - .tit02 h3 a:link, .tit02 h3 a:visited{color: #000;} - .tit02 h3 a:hover, .tit02 h3 a:focus, .tit02 h3 a:active{color: #ff8400;text-decoration: none;} - .tit02 .go-personal{float: right;display: inline;height: 35px;margin-right: 12px;} - - .tit03{height: 37px;border: 1px solid #e3e6ed;border-left: 0px;border-right: 0px;} - .tit03 span{float: left;display: inline;width: 58px;text-align:center;border-left: 1px solid #e3e6ed;border-right:1px solid #f9f9f9;height: 37px;line-height: 37px;background-color: #f9f9f9;font-size: 14px;} - .tit03 span.selected{border-top: 3px solid #ff8400;background-color: #fff;margin-top: -1px;font-weight: bold;line-height: 33px;height: 36px;_position:relative;_margin-bottom:-1px;} - .tit03 span.selected a:link, .tit03 span.selected a:visited{color: #000;} - .tit03 span.selected a:hover, .tit03 span.selected a:focus, .tit03 span.selected:active{text-decoration: none;color: #ff8400;} - .tit03 .last-index{border-right: 1px solid #e3e6ed;} - - .tit04{height: 34px;line-height: 34px;} - .tit04 .bz-order, .tit04 .more{float: right;display: inline;height: 34px;line-height: 34px;width: 54px;text-align: center;border-left: 1px solid #e3e6ed;border-right: 1px solid #e3e6ed;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -32px repeat-x;} - .tit05{height: 28px;line-height: 30px;padding-left: 10px;} - - .tit05 a{font-size: 16px;font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimHei","ºÚÌå";background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 75px -722px no-repeat;padding-right: 20px;display: block;width: 65px;} - - .tit05 a, .tit05 a:visited{color: #000;} - .tit05 a:hover, .tit05 a:focus, .tit05 a:active{color: #ff8400;text-decoration: none;} - - /**** Áбí*/ - .list-a li{padding-left:10px;line-height:26px;height:26px;overflow:hidden;font-size: 14px;background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px;_zoom:1;} - .list-a a:link{color:#122E67;text-decoration:none;} - .list-a a:visited{color:#52687e;text-decoration:none;} - .list-a a:hover,.list-a a:active{color:#ff8400;text-decoration:underline;} - - .list-b li{padding-left:10px;line-height:24px;height:24px;overflow:hidden;font-size: 12px;background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px;} - .list-b a:link{color:#666;text-decoration:none;} - .list-b a:visited{color:#666;text-decoration:none;} - .list-b a:hover,.list-b a:active{color:#ff8400;text-decoration:underline;} - - .list-c li{line-height: 26px;} - - /*pic-txt*/ - .pic-txt{} - .pic-txt .pic{width: 65px;height: 65px;float: left;display: inline;} - .pic-txt .txt{width: 130px;float: left;display: inline;margin-left: 14px;margin-top: -3px;_position: relative;} - - .pic-txt h3{font-weight: normal;padding-bottom: 5px;font-size: 14px;} - .pic-txt h3 a, .pic-txt h3 a:visited{color: #e66100;} - .pic-txt h3 a:hover, .pic-txt h3 a:focus, .pic-txt h3 a:active{color: #ff8400} - .pic-txt p{line-height: 26px;color: #666;} - .pic-txt h3{padding-bottom: 4px;} - .pic-txt02 p{line-height: 24px;} - - /**** footer*/ - .footer{width:1000px; overflow:hidden; text-align:center; color:#939393;font-size: 12px;} - .footer p{line-height:20px;} - .footer p a:link,.footer p a:visited{color:#939393; text-decoration:none;} - .footer p a:hover,.footer p a:active{color:#ff8400; text-decoration:underline;} - .footer .ft-info{background: #F7F7F7;padding:7px 0;margin-bottom: 10px;} - .footer .ft-info a:link,.footer .ft-info a:visited{color:#75839D;} - .footer .ft-info a:hover,.footer .ft-info a:active{color:#ff8400; text-decoration:underline;} - .footer .ft-list{margin:10px 0 8px 0;width:100%;height:50px;} - .footer .ft-list li{float:left;display: inline;margin:0 1px 0 0;} - -/*ÎÞÕÏ°­µ¼Ã¤×©*/ -.JumpTo{position: absolute; top:-1px; left:-1px;} - - /*** others*/ - .blank-d{height: 25px;clear: both;overflow: hidden;display: block;} - .blank-cont{height: 25px;clear: both;overflow: hidden;display: block;} - - .loading{width:350px;height:182px;line-height: 184px;background: url(http://i3.sinaimg.cn/dy/stencil/sysimages/sysimg/loading_01.gif) center center no-repeat;} - - /*---------------------------------- top.css*/ - * html,* html body{background-image:url(about:blank);background-attachment:fixed} - .top-nav-wrap{width:100%;min-width:1000px;z-index:9999;position:absolute;top:0;left:0;} - .top-nav-wrap-fix{position: fixed; top:0; _position:absolute;_top:expression(eval(document.documentElement.scrollTop)); left:0; } - .top-nav{ height:41px; border-top: 3px solid #ff8500;border-bottom:1px solid #EDEEF0; background-color: #FCFCFC; } - .top-nav .tn-bg{ height:41px; /*overflow: hidden; */} - .top-nav .tn-header{ width:1000px; margin:0 auto; position: relative;font-family:"Microsoft YaHei", "΢ÈíÑźÚ", "SimSun", "ËÎÌå"; } - .top-nav .tn-nav{ float:left; _display:inline; /*margin:0 0 0 151px; */} - .top-nav .tn-title{ float:left; font-size:12px; position:relative; } - .top-nav .tn-title .tn-tab{ border: 1px solid #FCFCFC; border-width: 0 1px; color:#4C4C4C; display: inline-block; line-height: 16px; cursor: pointer; position: relative; z-index:9999; padding:0 2px 0 0; } - - .top-nav .tn-title .tn-tab i,.top-nav .tn-title .tn-user i{ display: inline-block; height:17px; padding:12px 9px 12px 16px; vertical-align:bottom; _overflow: hidden; } - - .top-nav .tn-title .tn-user{display: inline-block; line-height: 16px; position: relative; z-index:9999; padding:0 2px 0 0;} - .top-nav .tn-title .tn-user i{padding-left: 0;padding-right:10px;color: #FF8400;} - .top-nav .tn-user a:link,.top-nav .tn-user a:visited{color:#FF8400;text-decoration:none;} - .top-nav .tn-user a:hover,.top-nav .tn-user a:active{color:#FF8400;text-decoration:underline;} - .top-nav .tn-logout{margin-left:5px;} - .top-nav .tn-onmouse .tn-tab{ color:#eee; } - .top-nav .tn-title .tn-tab:hover,.top-nav .tn-setting .tn-name:hover,.top-nav .tn-setting .tn-tab:hover,.top-nav .tn-onmouse .tn-tab,.top-nav .tn-onmouse .tn-tab{ border-color:#EDEEF0; background-color: #EDEEF0; text-decoration:none; color:#ff8400; } - - .top-nav .tn-onmouse .tn-tab i,.top-nav .tn-onmouse .tn-tab i{ color: #4C4C4C; } - .top-nav .tn-onmouse .tn-tab:hover i,.top-nav .tn-onmouse .tn-tab:hover i{color:#ff8400;} - .top-nav .tn-title-login .tn-tab a,.top-nav .tn-title-login .tn-tab a:hover{ color:#000; } - /*.top-nav .tn-title-login a.tn-tab:link,.top-nav .tn-title-login a.tn-tab:visited{ color:#000; background-color: #ff8500; } - .top-nav .tn-title-login a.tn-tab:hover{color:#333; background-color: #ff8500;} - .top-nav .tn-title-login a.tn-user,.top-nav .tn-title-login a.tn-user:hover{ color:#FF8400; background-color: #2D2D2D; }*/ - - /*.top-nav .tn-title-login .LoginIcon{display: none;}*/ - .top-nav .tn-person{ float: right;} - - .top-nav .tn-new{ position: absolute; margin:-10px 0 0 0; display:none; } - .tn-topmenulist{ position:absolute; border:1px solid #333; background:#fff; z-index:9998; font-size:12px; } - .tn-topmenulist { color:#333; } - .tn-topmenulist a{ color:#0a8cd2; } - .tn-topmenulist .tn-text-list { border-bottom:1px solid #FECC5B; margin-bottom: -2px; } - .tn-topmenulist .tn-text-list li{ /*height:31px; »áÒýÆð3ÏñËØbug*/ - line-height:31px; border-bottom: 1px solid #FECC5B; } - .tn-topmenulist .tn-text-list li a{ _zoom:1; display: block; color:#333; padding:0 15px; } - .tn-topmenulist .tn-text-list li a:hover{ color: #E67902; background:#FFF5DA; text-decoration:none; } - .tn-topmenulist .tn-text-list li em{ color:#DE1F26; float: right; } - .tn-topmenulist-a{ border: 1px solid #EBBE7A; border-top:0; overflow: hidden; -moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); top:41px; left:0;} - - .tn-topmenulist-b{border:0;top:42px;left:-110px;} - .tn-topmenulist-a-client{width:112px} - - .tn-topmenulist-a-nav{ width:110px;} - .tn-topmenulist-a-menu{ width:110px;} - .tn-topmenulist-a-weibo,.tn-topmenulist-a-other{ width:78px;} - .tn-topmenulist-a-mail,.tn-topmenulist-a-blog{ width:110px; } - .tn-topmenulist .tn-loading{ padding:10px 0; text-align:center; } - body,.top-nav,.top-nav dl,.top-nav dt,.top-nav dd,.top-nav ul,.top-nav ol,.top-nav li,.top-nav p,.top-nav form,.top-nav input,.top-nav textarea{ margin:0; padding:0; } - .top-nav li { list-style:none; } - .top-nav img { border:0; } - .top-nav a:focus{ outline-style:none; } - .top-nav em,.top-nav i{ font-style:normal; font-weight:normal; } - .top-nav a{ color:#FF8400; text-decoration:none; } - .top-nav a:hover { text-decoration:underline; } - .top-nav .tn-new { background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -1017px; width:14px; height:11px; } - .top-nav .tn-arrow { display:inline-block; width:8px; height:5px; margin:0 0 0 5px; overflow:hidden; vertical-align:middle; font-size:12px; line-height:13px; -webkit-transform:none; -moz-transform:none; -o-transform:none; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -977px no-repeat; } - .top-nav .tn-onmouse .tn-arrow{ /*-webkit-transform: rotate(180deg); -moz-transform: rotate(180deg); -o-transform: rotate(180deg); transform: rotate(180deg); -webkit-transition: all .25s ease 0s; -moz-transition: all .25s ease 0s; -o-transition: all .25s ease 0s; transition: all .25s ease 0s; */ - /*background-position: 0 -997px;*/ } - .clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } - .clearfix { display: inline-block; }* html .clearfix { height: 1%; } - .clearfix { display: block; } - .clear { clear:both; height:0; font:0/0 Arial; visibility:hidden; } - - /*---------------------------------- top-search.css*/ - /*Í·²¿ËÑË÷Ä£¿é*/ - .top-search-wrap{height: 58px;padding-top: 60px;width: 100%;min-width: 1000px;} - .top-search-wrap .top-search-frame{width: 1000px;margin: 0 auto;} - .top-search-wrap .sina-logo, .top-search-wrap .top-search, .top-search-wrap .now-wea-wrap{float: left;display: inline;} - .top-search-wrap .sina-logo{width:111px;height:47px;margin-left:19px;background-image:url(http://i1.sinaimg.cn/dy/deco/2013/0329/logo/LOGO_1x.png); - background-image:-webkit-image-set(url(http://i1.sinaimg.cn/dy/deco/2013/0329/logo/LOGO_1x.png) 1x,url(http://i2.sinaimg.cn/dy/deco/2013/0329/logo/LOGO_2x.png) 2x);background-repeat:no-repeat;} - .top-search-wrap .top-search{margin: 6px 0 0 23px;color: #666;} - .top-search .sim-select{float: left;display:inline;position: relative;width: 75px;height: 33px;border: 1px solid #c1c1c1;border-right:0px; border-radius: 3px 0 0 3px;margin-top:3px;background:#fff url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 74px -218px no-repeat;} - .top-search .sim-select h3{line-height: 33px;font-weight: normal;font-size: 14px;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 57px -340px no-repeat;padding-left: 15px;cursor: pointer;float: left;display: inline;width: 59px;} - /*.top-search .sim-select .v-line{height: 31px;width: 0px;border-left: 1px solid #c1c1c1;overflow: hidden;float: left;display: inline;margin: 1px 0;}*/ - .top-search .sim-select .sim-ul-flt{margin-top:-1px;position: absolute;left: -1px;top: 34px;z-index: 1000;} - .sim-select .sim-ul-bg{} - .sim-select ul{cursor: pointer;position: absolute;left: 0px;top: 0px;z-index: 1000; -moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1); box-shadow: 3px 3px 3px rgba(0, 0, 0, .1);} - .sim-select ul li{height: 29px;width:58px;border: 1px solid #d0d0d0;border-top: 0px;background-color: #fff;line-height: 29px;padding-left: 16px;} - .sim-select ul li.over{color: #e77802;background-color: #fff6dd;} - .top-search .inp-txt{width: 244px; color: #666; margin:0;height: 32px;line-height: 32px; padding: 0px 0 0px 14px;border:0px;font-size:14px;_height:30px;_line-height:30px;font-family: "Arial","SimSun","ËÎÌå";} - @media screen and (-webkit-min-device-pixel-ratio:0) {body:nth-of-type(1) .top-search .inp-txt{height:15px;line-height: 15px;padding: 9px 0 9px 14px;}} - .inp-txt-wrap{border: 1px solid #c1c1c1;float: left;display: inline;margin-top: 3px;border-radius: 0;font-family: "Arial","SimSun","ËÎÌå";height: 33px;width: 258px;border-left: 0px;font-size: 14px;} - .inp-txt-click{-moz-animation:bg .5s ease-in-out;-webkit-animation:bg .5s ease-in-out;-o-animation:bg .5s ease-in-out;} - @-moz-keyframes bg{ - 0%{background:rgba(255,170,170,0.18);} - 25%{background:rgba(255,170,170,0.5);} - 50%{background:rgba(255,170,170,0.1);} - 75%{background:rgba(255,170,170,0.5);} - 100%{background:rgba(255,170,170,0.18);} - } - @-webkit-keyframes bg{ - 0%{background:rgba(255,170,170,0.18);} - 25%{background:rgba(255,170,170,0.5);} - 50%{background:rgba(255,170,170,0.1);} - 75%{background:rgba(255,170,170,0.5);} - 100%{background:rgba(255,170,170,0.18);} - } - @-o-keyframes bg{ - 0%{background:rgba(255,170,170,0.18);} - 25%{background:rgba(255,170,170,0.5);} - 50%{background:rgba(255,170,170,0.1);} - 75%{background:rgba(255,170,170,0.5);} - 100%{background:rgba(255,170,170,0.18);} - } - .top-search .submit-second-btn{border:0px;float:left;display:inline;width: 66px;height: 35px;margin-top:3px;margin-right:6px;background:#ff8400 url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 0px 0px no-repeat;cursor: pointer;border-radius: 0px;} - .top-search .submit-second-btn-hover{background-position: -1px -64px;width: 72px;height: 42px;margin: 0px;background-color: transparent;} - .now-wea-wrap{color: #7a7874;margin: 19px 0 0 15px;} - .now-wea-wrap{width:180px;} - .now-wea-wrap a{_zoom:1;_float: left;} - .now-wea-wrap a:hover, .now-wea-wrap a:focus, .now-wea-wrap a:active{text-decoration: none;} - .now-wea-wrap a span, .now-wea-wrap a:visited span{color: #7a7874;cursor: pointer;} - .now-wea-wrap a:hover span, .now-wea-wrap a:active span, .now-wea-wrap a:focus span{color: #ff8400;text-decoration: none;} - .now-wea-wrap span{float: left;display: inline;height: 30px;line-height: 15px;} - /*.now-wea-wrap .now-wea-city{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 10px -478px no-repeat;}*/ - .now-wea-wrap .now-wea-i{padding: 0 5px;} - .now-wea-wrap .now-wea-i img{margin-top: -1px;} - .now-wea-wrap .now-wea-st{padding-right: 5px;}/*Í·²¿title*/ - - .now-wea-wrap {margin: 13px 0 0 15px;} - .now-wea-wrap span{ line-height: 32px; font-size: 14px;} - - .uni-blk{width: 360px;position: relative;} - .uni-blk .uni-blk-t{height: 34px;border: 1px solid #dbdee1;line-height: 34px;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -33px repeat-x;} - .uni-blk-t .order-menu{float: left;margin-left: -2px;} - .uni-blk-t .t-guide{float: right;display: inline;margin-right: 10px;} - .uni-blk .order-trigger, .uni-blk .order-reset{display: block;position: absolute;z-index: 1000;top: -16px;right: -4px;} - .uni-blk .order-trigger{width: 63px;height:25px;line-height:22px;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 0px -358px no-repeat;color: #fff;text-align: center;} - .uni-blk .order-trigger:visited{color: #fff;} - .uni-blk .order-trigger:hover,.uni-blk-t .order-trigger:active,.uni-blk-t .order-trigger:focus{color: #fff;text-decoration: none;background-position: 0px -333px;} - .uni-blk .order-reset{width: 149px;height: 25px;line-height: 300px;overflow: hidden;} - .uni-blk .order-menu span{float: left;height: 35px;line-height:35px;font-size: 16px;font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimHei","ºÚÌå";padding: 0 13px;margin-top: -1px;} - .uni-blk .order-menu a, .uni-blk .order-menu a:visited{color: #000;} - .uni-blk .order-menu a:hover, .uni-blk .order-menu a:active, .uni-blk .order-menu a:focus{color: #ff8400;text-decoration: none;} - .uni-blk .order-menu span.selected{height: 33px;line-height:29px;border-top: 3px solid #ff8400;border-left: 1px solid #dbdee1;border-right: 1px solid #dbdee1;background-color: #fff;_position: relative;_margin-bottom: -1px;padding:0 12px;} - .order-menu span.selected a, .order-menu span.selected em{} - .order-menu span.selected em{color: #000;font-style: normal;margin: 0 12px;} - .order-menu .vline{color: #000;font-style: normal;margin: 0 12px;} - .uni-blk .order-edit, .uni-blk .order-rest{color: #fff;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat;float: left;display: inline;text-align: center;width: 74px;} - .uni-blk .order-edit{background-position: 0px -403px;height: 22px;margin-right: 1px;} - .uni-blk .order-rest{background-position: -75px -403px;height: 25px;} - .uni-blk .order-edit:visited, .uni-blk .order-rest:visited{color: #fff;} - .uni-blk-t .order-edit:hover, .uni-blk-t .order-edit:focus, .uni-blk-t .order-edit:active, .uni-blk-t .order-rest:hover, .uni-blk-t .order-rest:focus, .uni-blk-t .order-rest:active{color: #fff;text-decoration: none;} - .uni-blk .order-edit:hover{background-position: 0px -435px;} - .uni-blk .order-rest:hover{background-position: -75px -435px;} - .uni-blk-t .order-changeit{width: 45px;padding-left: 10px;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 40px -144px no-repeat;float: left;display: inline;border-left:1px solid #dbdee1;border-right: 1px solid #dbdee1} - .uni-blk-t .order-changeit, .uni-blk-t .order-changeit:visited{color: #7b8695;} - .uni-blk-t .order-changeit:hover,.uni-blk-t .order-changeit:focus,.uni-blk-t .order-changeit:active{color: #ff8400;background-color:#fff;text-decoration: none;background-position: 40px -1379px;} - .uni-blk-orderlist{padding-top: 3px !important} - - .uni-blk-picwrap {} - .uni-blk-picwrap .uni-blk-bpic{width: 170px;height:119px;border: 1px solid #fff;} - .uni-blk-picwrap .uni-blk-bpic:hover, .uni-blk-picwrap .uni-blk-bpic:active, .uni-blk-picwrap .uni-blk-bpic:focus {border-color: #ff8400;text-decoration: none;} - .uni-blk-picwrap .uni-blk-bpic:hover span, .uni-blk-picwrap .uni-blk-bpic:active span, .uni-blk-picwrap .uni-blk-bpic:focus span {color: #ff8400;} - .uni-blk-picwrap .uni-blk-bpic span{width: 170px;} - - .weibo-login{display: block;position: absolute;z-index: 1000;top: 3px;right: 2px;height: 34px;line-height: 15px;width: 54px;text-align:center;color: #7a7a7a;} - .weibo-login:visited{color: #7a7a7a;} - .weibo-login:hover, .weibo-login:focus, .weibo-login:active{color: #ff8400;text-decoration: none;} - - /*ËÑË÷°å¿é*/ - .order-search{ float: right; display: inline; width: 73px; margin-right:-1px; position: relative; border-left: 1px solid #dbdee1; border-right: 1px solid #dbdee1; z-index: 10;} - .order-search a.order-seat{ display: block; text-align: center; padding: 0px; padding-left: 20px; color: #7a7a7a; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 17px -523px no-repeat; } - .order-search a.order-seat:visited{ color: #7a7a7a} - .order-search a.order-seat:hover, .order-search a.order-seat:focus, .order-search a.order-seat:active{ color: #ff8400; text-decoration: none; background-color: #fff; background-position: 17px -1096px;} - .sea-out-win{ position: absolute; z-index: 5000; top: 30px; border: 1px solid #ff8400; background: #fff; padding: 15px 14px 12px; } - .order-search-fin .sea-out-win{width: 262px;left: -218px;} - .order-search-blog .sea-out-win{width: 190px;left: -146px;} - .sea-out-win .sow-arr{ width: 15px; height: 6px; display: block; position: absolute; z-index: 10000; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -929px no-repeat;top: -6px; } - .order-search-fin .sow-arr{left: 252px;} - .order-search-blog .sow-arr{left: 176px;} - .sow-form form{position: relative;z-index: 300; _zoom:1;} - .sow-form .sim-select{float: left;display: inline;width: 58px; margin-right:12px;} - .sow-form .sim-select h3{font-weight: normal;color: #888;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 44px -840px no-repeat;height: 23px;line-height: 23px;border: 1px solid #cdcdcd;width: 48px;padding-left: 8px;font-size: 12px;cursor: pointer;} - .sow-form .sim-select ul{top: 25px;left: 0px;} - .sow-form .sim-select li{width: 48px;height: 23px;line-height: 23px;padding-left: 8px;color: #888;} - .sow-form .sow-ipt-w, .sow-form .sow-sub-wrap, .sow-form .sow-sub{ float: left; display: inline; } - .sow-form .sow-ipt-w{ width: 108px; height: 23px; border: 1px solid #cdcdcd; padding-left: 20px; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 5px -573px no-repeat; border-right: 0px; line-height: 21px;} - .sow-form .sow-ipt-w div{left: 79px !important;} - .sow-form .sow-ipt{ border: 0px; height: 22px; line-height: 22px; _height:21px;_line-height:21px;width: 104px; color: #888; } - .sow-form .sow-sub-wrap{border: 1px solid #cdcdcd;} - .sow-form .sow-sub{border:0px; height: 23px; line-height: 23px; width: 58px; text-align: center; cursor: pointer; background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0px -109px repeat-x;} - .sow-form .sow-sub-wrap:hover{border: 1px solid #eec57c;text-decoration: none;} - .sow-form .sow-sub-wrap:hover .sow-sub{background-position: 0px -136px;} - .sow-list{ line-height: 24px; padding-top: 8px; } - .sow-list li{ float: left; display: inline; width: 60px; } - - /*²Æ¾­ÄÚÈÝËÑË÷*/ - .uni-blk-form{margin-top: 15px;margin-bottom: 9px;} - .uni-blk-form .sow-form .sow-ipt-w{width: 208px;} - .uni-blk-form .sow-form .sow-ipt{width: 204px;} - .uni-blk-form .sow-form .sim-select{position: relative;z-index: 20;} - .uni-blk-form .sim-select ul{left: 0px;top: 25px;} - - /*µ×²¿ÐÅÏ¢²ã*/ - .uni-blk-b{padding-top: 10px;} - .uni-blk-b .uni-blk-bt{padding: 10px 0px 1px 0px;} - .uni-blk-b .uni-blk-list01{float: left;padding-left: 15px;position: relative;margin-top: -5px;width: 220px;overflow: hidden;} - .part-a .uni-blk-b .uni-blk-list01{padding-left:14px;} - .uni-blk-b .uni-blk-list01 li{line-height: 26px !important;} - .uni-blk-b .uni-blk-list02{padding: 0px 0px 0px 0px;} - /*¶¨ÖƸ¡²ã*/ - .uni-blk-f-w{position: absolute;z-index: 999;left: 0px;top: 0px;background: #fff;color: #596a7b;width: 360px;} - .uni-blk-f-w .order-menu{padding-left: 10px;} - .uni-blk-f-w .order-menu a{padding: 0 10px 0 10px;color: #000;float: left;} - .uni-blk-f-w .order-menu a:visited{color: #000;} - .uni-blk-f-w .order-menu a:hover{opacity: 0.7;filter:alpha(opacity=70);text-decoration: none;} - .uni-blk-f-w .order-menu span, .uni-blk-f-w .order-menu i{float: left;display: inline;} - .uni-blk-f-w .order-menu span{padding: 0px 5px 0 0;} - .uni-blk-f-w .order-menu i{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0px -32px no-repeat;width: 10px;height: 10px;margin-top: 13px;} - .uni-blk-f{overflow-x: hidden;overflow-y:hidden;border-left: 1px solid #dbdee1;border-right:1px solid #dbdee1;width: 358px;padding: 0 0 15px 0;} - .parent-menu{overflow-y: auto;padding-bottom: 15px;} - .parent-menu li{float: left;width: 70px;text-align: center;height:33px;line-height: 33px;font-size: 14px;display: inline;margin-top: 10px;margin-left: 14px;} - .parent-menu li a{display: block;overflow: hidden;background: #fff;color: #596a7b;} - .parent-menu li a:visited{color: #596a7b;} - .parent-menu li a:hover{color: #ff8400;text-decoration: none;} - .parent-menu li .son-menu{display: none;} - .parent-menu li.selected a.p-item{background-color: #ff8400;color: #fff;font-weight: bold;} - .parent-menu li.selected a.p-item:visited, .parent-menu li.selected a.p-item:hover, .parent-menu li.selected a.p-item:active, .parent-menu li.selected a.p-item:focus{color: #fff;text-decoration: none;} - .son-menu-wrap{background-color: #fbfbfd;padding-left: 10px;} - .son-menu-tip{line-height: 26px;} - .son-menu{margin-left: -10px;padding-bottom: 9px;} - .son-menu li{line-height: 31px;height: 31px;font-size: 12px;width: auto;float:left;padding-right: 3px;margin-left: 20px;display: inline;_overflow: hidden;} - .son-menu li a{white-space: nowrap;cursor: pointer;float: left;} - .son-menu li a, .son-menu li a:visited{color: #596a7b;} - .son-menu li a:hover, .son-menu li a:active, .son-menu li a:focus{color: #ff8400;} - .son-menu li span, .son-menu li i{display: inline-block;} - .son-menu li span{*vertical-align: -3px;_vertical-align: 0px;} - .son-menu li i{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -111px no-repeat;width: 11px;height: 10px;margin:10px 0 0 5px;} - .son-menu li a:hover i{opacity: 0.7;filter:alpha(opacity=70);} - .son-menu li.has-checked a,.son-menu li.has-checked a:visited{color: #ff8400;} - .son-menu li.has-checked a:hover,.son-menu li.has-checked a:focus,.son-menu li.has-checked a:active{color: #ff8400;} - .son-menu li.has-checked i{background-position: 0px -77px;width: 7px;height: 7px;margin-left: 7px;margin-right:2px;_vertical-align:-2px;} - - .btn-area{clear: both;border: 1px solid #dbdee1;height: 55px;overflow: hidden;_padding-bottom:13px;} - .btn-area a{background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat;float: left;display: inline;width: 78px;height: 32px;margin-top: 10px;display: inline;} - .btn-area a:hover{opacity: 0.8;filter:alpha(opacity=80);} - .btn-area .do-submit{background-position: -32px -190px;margin-left: 100px;} - .btn-area .do-cancel{background-position: -113px -190px;margin-left: 5px;} - - /*ͼÎÄ*/ - .uni-blk-pic{float: left;display: block;width: 105px;height: 90px;overflow: hidden;border:1px solid #fff;} - .uni-blk-pic span{width: 105px;text-align: center;color: #fff;height: 20px;line-height: 20px;display: block;background: #000;} - .uni-blk-b .uni-blk-pic span, .uni-blk-b .uni-blk-pic:visited span, .uni-blk-b .uni-blk-pic:hover span, .uni-blk-b .uni-blk-pic:active span, .uni-blk-b .uni-blk-pic:focus span{color: #fff;} - .uni-blk-b .uni-blk-pic:hover{border-color: #e66100;text-decoration: none;} - .uni-blk-b .uni-blk-pic:hover span, .uni-blk-b .uni-blk-pic:active span, .uni-blk-b .uni-blk-pic:focus span{text-decoration: none;color: #ff8400} - .uni-blk-b .uni-blk-pic .play-icon {position:absolute; width:40px; height:40px; top:55px; left:5px; cursor:pointer; background:url(http://i2.sinaimg.cn/dy/deco/2013/0316/play_icon_normal.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i2.sinaimg.cn/dy/deco/2013/0316/play_icon_normal.png');_background:none;} - .uni-blk-b .uni-blk-pic:hover .play-icon {background:url(http://i1.sinaimg.cn/dy/deco/2013/0316/play_icon_hover.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i1.sinaimg.cn/dy/deco/2013/0316/play_icon_hover.png');_background:none;} - - .uni-blk-bpic{width: 125px;height: 120px;position: relative;border:0px;} - .uni-blk-bpic span{position: absolute;z-index: 500;left: 0px;top: 70px;} - - .uni-blk-bpic span{width: 125px;height: 24px;line-height: 24px;top: 95px;background:none\9;filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 0,startColorstr = '#9A000000', endColorstr = '#9A000000' )\9;background-color:rgba( 0, 0, 0, .6 );*background-color:transparent\9;} - - .uni-blk-pic-c{float:none;height: 80px;margin:6px auto;position:relative;} - .videonewsList{width:230px;float:left;} - .videoLeftC{float:left;margin-right:16px;zoom:1;width:107px;} - .vid-play-icon{position: absolute;width: 22px;height: 22px;top: 33px;left: 3px;cursor: pointer;background: url(http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png) no-repeat;_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png');_background: none;} - .uni-blk-pic-c:hover .vid-play-icon{background: url(http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png) no-repeat;_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png');_background: none;} - - /*blk-line*/ - .blk-line{height: 2px;overflow: hidden;clear: both;background-color: #fff;} - .dot-line{height: 1px;overflow: hidden;clear: both;background: url(http://i1.sinaimg.cn/dy/deco/2013/0306/dot_line.png) 0 0 repeat-x;margin: 3px 0 3px 0} - .blk-line02{background: url(http://i2.sinaimg.cn/dy/deco/2013/0318/spe.png) 0 -1px no-repeat;height: 11px;overflow: hidden;clear: both;} - - /*others*/ - .no-bl{border-left: 0px !important;padding-left: 13px !important} - .main-nav{ overflow:hidden; width: 1000px; margin: 0 5px; overflow: hidden; font-family:"Microsoft YaHei", "΢ÈíÑźÚ", "SimSun", "ËÎÌå";} - .nav-mod-1,.nav-mod-2{ overflow:hidden; _display:inline-block; float:left; padding: 2px 5px 18px 0} - .nav-mod-1{ width:132px; background:url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat 136px -183px; margin-left:2px; display:inline; } - .nav-mod-2{ width:95px; } - .nav-w{ width:136px; background-position:140px -183px; } - .nav-w-2{width: 145px;background: none;} - .main-nav ul{ height:26px; clear:both; overflow: hidden;} - .main-nav li{ float:left; width:27px; margin-left:13px; line-height:26px; text-align: center; white-space: nowrap;display: inline;} - .main-nav .nav_1 li{ padding:0 6px 0 7px; } - .main-nav a,.main-nav a:visited{ color:#000; text-decoration:none; } - .main-nav a:hover,.main-nav a:active{ color:#e66100; text-decoration: underline; } - - .top-ads{ background-color: #f6f8f9; } - .top-ads a:link, .top-ads a:visited{ color: #666; } - .top-ads a:hover, .top-ads a:active, .top-ads a:focus{ color: #e66100; } - .top-ads-list{ height: 35px; } - .top-ads-list li{ line-height: 35px; height: 35px; float: left; display: inline; width: 125px; overflow: hidden; text-align:center; } - - .part-a{ clear: both; } - .part-a-l, .part-a-m, .part-a-r{ float: left; display: inline; } - .part-a-l{ width: 240px; margin-right: 20px; } - .part-a-m{ width: 360px; margin-right: 20px; } - .part-a-r{ width: 360px; } - - /*mod01*/ - .palm01-ad{ padding-top: 13px; } - - /*mod02*/ - .mod-02{ border: 1px solid #d9e0ee; border-top: 3px solid #ff8400; } - .mod-02 a{ color: #666; } - .mod-02 a:visited{ color: #666; } - .mod-02 a:hover, .mod-02 a:focus, .mod-02 a:active{ color: #ff8400; } - .mod02-cont{ padding: 7px 5px 0px 5px; } - .mod02-cont-t{ background: url(http://i1.sinaimg.cn/dy/deco/2013/0306/dot_line.png) 0 bottom repeat-x; width: 228px;} - .pro{ float: left; display: inline; width: 60px; text-align: center; margin: 0 8px; } - .pro span{ line-height: 26px; padding: 4px 0 2px 0;display: block; position: relative;} - .pro img{ clear: both; } - .mod02-cont-b{ padding: 4px 0 0; width: 228px;} - .mod02-cont-b li{ float: left; display: inline; width: 76px; text-align: center; padding-bottom: 4px; } - - /*mod03*/ - .mod03{ } - .mod03-cont{ border: 1px solid #e3e6ed; border-top: 0px; padding: 3px 8px 3px 15px; } - .mod03-list{} - .mod03-list li{float: left;display: inline;width: 105px;overflow: hidden;font-size: 12px;line-height: 24px;height:24px;padding-right: 1px;} - - /*mod04*/ - .mod-04 .uni-blk-b{ padding-top: 10px; } - .mod-04 .uni-blk-bt{padding-top: 0px;margin-top: 15px;padding-bottom: 0px;} - - /*mod05*/ - .mod-05 .order-menu em, .mod-05 .order-menu i{float: left;display: inline;} - .mod-05 .order-menu em{ margin: 0 12px; color: #000;font-style: normal;} - .mod-05 .order-menu span em{color: #000;font-style: normal;margin: 0;} - .mod-05 .order-menu span{padding:0 7px;} - .mod-05 .order-menu span.selected{padding:0 6px;} - .mod-05 .order-menu span.selected .mod-guess-control{margin-top:6px !important;} - .mod-05 .order-menu i{ width: 41px; height: 21px; line-height:21px;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -126px 0 no-repeat; margin: 8px 0 0 5px; cursor: pointer; font-size: 12px;color: #7a7a7a;padding-left: 24px;font-style: normal;font-family: "SimSun","ËÎÌå";} - .order-menu span.selected i{ margin-top: 5px; } - .mod-05 .order-menu i.over{ background-position: -126px -154px; color: #555556;} - .mod-05 .order-trigger{ width: 72px; padding: 0px; text-align: center; background: none; } - .mod-05 .mod05-cont{ padding: 10px 0 0px 0} - .mod-05 .list-a{ /*padding-bottom: 17px;*/ } - .mod-05 .mod05-ads a{float: left;display: inline;} - - /*mod06*/ - .mod-06 .vline{ color: #bfb3a8 !important; line-height: 25px !important; } - - .part-b{ } - .part-b-l, .part-b-m, .part-b-r{ float: left; display: inline; } - .part-b-l{ width: 240px; margin-right: 20px; } - .part-b-m{ width: 360px; margin-right: 20px; } - .part-b-r{ width: 360px; } - - /*mod07*/ - .mod-07 h3 a{height:35px;overflow:hidden; background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 68px -276px no-repeat; display: block;width: 110px;} - .mod-07 .s-btn{float: right; height: 24px; margin-top: 11px;_margin:11px 0 -1px 0;*position: relative;*z-index: 100} - .s-btn span{ height: 23px; line-height: 23px; float: left; display: inline; width: 40px; text-align: center; border: 1px solid #ddd;border-right:0px;border-bottom: 0px;background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -77px repeat-x; } - .s-btn span.selected{ background: #fff; } - /*.mod07-cont{ padding: 0 7px 0 7px; }*/ - .mod07-cont-t{ border-bottom: 1px solid #ddd; height: 79px; /*overflow-x: hidden;*/ padding: 5px 7px 0 7px; } - .mod07-cont-t .t-icon, .mod07-cont-t .s-score{ float: left; display: inline; width:110px;overflow: hidden;text-align: center;} - .mod07-cont-t .t-icon{ width: 57px; text-align: center; _margin:5px 0;} - .t-icon img{ clear: both; } - .t-icon:link span, .t-icon:visited span{ color: #505050; } - .t-icon:hover span, .t-icon:focus span, .t-icon:active span{ color: #ff8400} - .s-score{ margin-top: 10px; } - .s-score-t a{ display: block; text-align: center; line-height: 30px; } - .s-score-t a:link,.s-score-t a:visited{font-size: 22px; font-family: "Microsoft YaHei","΢ÈíÑźÚ","SimSun","ËÎÌå"; color: #343434; } - .s-score-t a:hover, .s-score-t a:active, .s-score-t a:focus{ color: #ff8400; text-decoration: none; } - .s-score-b a{padding: 0 2px 0 1px;} - .s-score-b a:link,.s-score-b a:visited{ color: #4f4f4f; } - .s-score-b a:hover, .s-score-b a:active, .s-score-b a:focus{ color: #ff8400; text-decoration: none; } - .mod07-cont-wrap{width: 238px;height: 172px;text-align: right;border-top: 1px solid #e3e6ed;margin-top: -1px;_overflow:hidden;} - .mod07-cont-wrap .loading{width:238px;height: 172px;} - .mod07-cb-item .team,.mod07-cb-item .label{float: left;display: inline;} - .mod07-cont-b{ padding: 12px 0 15px 0; } - .mod07-cb-item{ width: 106px; overflow: hidden; padding: 0 6px 0 5px; border-right: 1px solid #d9dce0; float: left; display: inline; } - .mod07-cb-item span{ color: #a4a4a4; } - .mod07-cont-wrap .last{border-right: 0;padding: 0 5px 0 6px;} - .s-list{} - .s-list li{ /*float: left; display: inline;*/ line-height: 20px; /*width: 50px; */} - /*mod12*/ - .mod-12{ border-bottom: 1px solid #e9e9e9; padding: 10px 0 6px 0; } - .mod12-item{ float: left; display: inline; padding-left: 18px; width: 120px; border-right: 1px solid #e9e9e9; } - .mod12-item a{ line-height: 24px; height:24px;overflow:hidden;display: block; color: #596a7b; } - .mod12-item a:visited{ color: #596a7b; } - .mod12-item a:hover, .mod12-item a:active, .mod12-item a:focus{ color: #e66100; } - .part-d-l, .part-d-m, .part-d-r{ float: left; display: inline; } - .part-d-l{ width: 240px; margin-right: 20px; } - .part-d-m{ width: 360px; margin-right: 20px; } - .part-d-r{ width: 360px; } - /*mod13*/ - .mod13-cont{ padding: 12px 5px 15px 9px; } - - .part-e{ width: 1000px; /*z-index: 1 !important*/} - /*scroll*/ - .scroll-pic-frame{ position: relative; overflow: hidden; z-index: 100; } - .scroll-pic-wrap{ position: relative; overflow: hidden; } - .scroll-item{ float: left; display: inline; width: 200px; height: 164px; overflow: hidden; } - .scroll-item a{ display: block; width: 198px; height: 162px; border: 1px solid #fff; position: relative; overflow: hidden; z-index: 50; } - .scroll-item a:hover{ border-color: #ff8400; } - .scroll-item .scroll-txt{ width: 198px; height: 30px; line-height: 30px; position: absolute; z-index: 1000; left: 0px; background: #262626; top: 132px; display: block; text-align: center; } - .scroll-item a:link .scroll-txt, .scroll-item a:visited .scroll-txt{ color: #fff; } - .scroll-item a:hover .scroll-txt, .scroll-item a:active .scroll-txt, .scroll-item a:focus .scroll-txt{ color: #ff8400; text-decoration: none; } - - .scroll-arr-l, .scroll-arr-r{ position: absolute; z-index: 20000; width: 29px; height: 43px; top: 48px; background: url(http://i1.sinaimg.cn/dy/deco/2013/0316/arr.png) no-repeat; } - .scroll-arr-l{ left: 1px; background-position:0 0; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i0.sinaimg.cn/dy/deco/2013/0316/arr_l.png'); } - .scroll-arr-r{ right: 1px; background-position: -29px 0px; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i2.sinaimg.cn/dy/deco/2013/0316/arr_r.png'); } - .scroll-arr-l:hover{ background-position:0 -43px; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i3.sinaimg.cn/dy/deco/2013/0316/arr_l_hover.png'); } - .scroll-arr-r:hover{ background-position: -29px -43px; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='http://i1.sinaimg.cn/dy/deco/2013/0316/arr_r_hover.png'); } - .scroll-dot-lists{ clear: both; text-align: center; height: 30px; padding-top: 7px; } - .scroll-dot-lists span{ display: inline-block; width: 15px; height: 15px; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 2px -485px no-repeat; cursor: pointer; margin: 0 3px; } - .scroll-dot-lists span.cur{ background-position: 0 -440px; } - .part-f{ padding: 5px 0; border-top: 1px solid #e9e9e9; border-bottom: 1px solid #e9e9e9; height: 49px;overflow: hidden;} - .pf-list{ width: 189px; padding-left: 10px; border-right: 1px solid #e9e9e9; float: left; } - .pf-list li{ line-height: 24px; clear: both; height: 24px;overflow: hidden;} - .pf-list a, .pf-list a:visited{ color: #596a7b; } - .pf-list a:hover, .pf-list a:focus, .pf-list a:active{ color: #e66100; } - - .part-g-l, .part-g-m, .part-g-r, .part-g-mr{ float: left; display: inline; } - .part-g-l{ width: 240px; margin-right: 20px; } - .part-g-mr{ width: 740px; } - .part-g-m{ width: 360px; margin-right: 20px; } - .part-g-r{ width: 360px; } - - /*mod17*/ - .mod-17{ border:1px solid #e3e6ed; border-top: 3px solid #ff8400; } - .mod17-cont{ padding: 12px 5px 12px 9px; } - .mod-17 .bz-order i{ display:block; width: 23px; height: 23px; background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -128px -100px no-repeat; margin: 5px 0 0 18px;*margin-left: 5px; cursor: pointer;} - .mod-17 .bz-order:hover i{ opacity: 0.7; filter:alpha(opacity=70); } - - /*mod19*/ - .mod-19 .uni-blk-b{ padding-top: 7px; } - .mod-19 .uni-blk-b .uni-blk-bt{ } - - /*mod20*/ - .book-cust{ } - .book-tit{ height: 20px; line-height: 20px; background: url(http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png) 0 -163px repeat-x; padding: 5px 0 7px 0} - .book-tit h3{ width: 102px; background:#fff url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -88px -49px no-repeat; font-weight: normal; } - .book-tit h3 a, .book-tit h3 a:visited{ color: #e66100; font-size: 14px; } - .book-tit h3 a:hover, .book-tit h3 a:active, .book-tit h3 a:focus{ color: #ff8400; } - - .book-list{ } - .book-list li{ width: 180px; float: left; display: inline; line-height: 24px; } - .book-list em{ font-weight: bold; color: #ff8400; font-family: "Arial"; padding-right: 12px; } - - .part-h-l, .part-h-m, .part-h-r{ float: left; display: inline; } - .part-h-l{ width: 240px; margin-right: 20px; } - .part-h-m{ width: 360px; margin-right: 20px; } - .part-h-r{ width: 360px; } - - /*mod21*/ - .ed-pic-lists{ float: right; height: 35px; margin-right: 10px; display: inline; } - .ed-pic-lists span{ float: left; display: inline; width: 13px; height: 13px; background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 1px -680px no-repeat; margin: 10px 2px 0; cursor: pointer; } - .ed-pic-lists span.cur{ background-position: 0 -632px; } - .mod21-cont{ padding: 7px 8px 0 8px; } - .ed-pic-wrap{ width: 218px; overflow: hidden; } - .ed-pic-item{ float: left; display: inline; overflow: hidden; width: 218px; } - .ed-pic-item .list-b{ height: 24px; padding: 3px 0; } - - /*mod22*/ - .mod-22{ border: 1px solid #d9e0ee; border-top: 0px; } - .mod22-cont{ padding-left: 10px; } - - /*mod24*/ - .mod24-t{_overflow:hidden;} - .mod24-menu{float: left;_zoom:1;} - .mod24-menu span{text-align:center; border-right: 1px solid #dbdee1;float: left;display:inline;height: 35px;line-height: 35px;} - .mod24-menu span a, .mod24-menu span a:visited{ color: #596a7b; font-size: 14px ; font-family:"SimSun","ËÎÌå"; padding: 0px; } - .mod24-menu span a:hover, .mod24-menu span a:active, .mod24-menu span a:focus{ color: #ff8400 !important; text-decoration: none; } - .mod24-menu span.selected{ border-top: 1px solid #dbdee1; height: 35px;background-color: #fff;line-height: 33px;margin-top: -1px;_margin-bottom: -1px;position: relative;} - .mod24-menu span.selected a{ line-height: 35px; } - - /*mod25*/ - .mod25-menu span.selected{ border-top: 3px solid #ff8400; height: 33px;background-color: #fff;px;margin-top: -1px;_margin-bottom: -1px;position: relative;} - .mod25-menu span.selected a{ line-height: 31px; } - - .part-j-l, .part-j-m, .part-j-r{ float: left; display: inline; } - .part-j-l{ width: 240px; margin-right: 20px; } - .part-j-m{ width: 360px; margin-right: 20px; } - .part-j-r{ width: 360px; } - - /*mod27*/ - .mod27-cont{ padding: 20px 10px 6px 10px} - - .part-k-l, .part-k-m, .part-k-r{ float: left; display: inline; } - .part-k-l{ width: 240px; margin-right: 20px; } - .part-k-m{ width: 360px; margin-right: 20px; } - .part-k-r{ width: 360px; } - .part-l-l, .part-l-m, .part-l-r{ float: left; display: inline; } - .part-l-l{ width: 240px; margin-right: 20px; } - .part-l-m{ width: 360px; margin-right: 20px; } - .part-l-r{ width: 360px; } - .part-n-l, .part-n-m, .part-n-r{ float: left; display: inline; } - .part-n-l{ width: 240px; margin-right: 20px; } - .part-n-m{ width: 360px; margin-right: 20px; } - .part-n-r{ width: 360px; } - - /*mod38*/ - .mod38-cont{ padding-top: 15px; } - - /*mod39*/ - .mod39-cont{ padding: 12px 10px 0; } - - .part-o-l, .part-o-m, .part-o-r{ float: left; display: inline; } - .part-o-l{ width: 240px; margin-right: 20px; } - .part-o-m{ width: 360px; margin-right: 20px; } - .part-o-r{ width: 360px; } - - /*mod42*/ - .mod42-cont{ padding: 18px 0 20px 12px; } - .mod42-cont-b{padding-top: 14px;} - - /*mod44*/ - .mod44-list{ float: right; display: inline; margin-right: 5px;} - .mod44-list li{ height: 34px; line-height: 34px; float: left; display: inline; margin-right: 5px; } - .mod44-list li a, .mod44-list li a:visited{ color: #7a7a7a} - .mod44-list li a:hover, .mod44-list li a:active, .mod44-list li a:focus{ color: #ff8400; } - - .part-q-l, .part-q-m, .part-q-r{ float: left; display: inline; } - .part-q-l{ width: 240px; margin-right: 20px; } - .part-q-m{ width: 360px; margin-right: 20px; } - .part-q-r{ width: 360px; } - - .part-r-l, .part-r-m, .part-r-r{ float: left; display: inline; } - .part-r-l{ width: 240px; margin-right: 20px; } - .part-r-m{ width: 360px; margin-right: 20px; } - .part-r-r{ width: 360px; } - - .part-s-l, .part-s-m, .part-s-r{ float: left; display: inline; } - .part-s-l{ width: 240px; margin-right: 20px; } - .part-s-m{ width: 360px; margin-right: 20px; } - .part-s-r{ width: 360px; } - /*mod52*/ - .mod52-fix-cont{ padding-top: 0px !important; } - .part-s-m .order-menu span.selected{ overflow: hidden; }.f596{color: #59687b;} - .f596:visited{color: #666;} - .f596:hover, .f596:active, .f596:focus{color: #ff8400;} - - .nmod01{border-top: 1px solid #e9e9e9;font-size: 14px;padding: 3px 0;clear: both;margin-top: 4px;} - .nmod01 a{line-height: 26px;} - - /*Æû³µÆµµÀ*/ - .car-nmod{float: left;width: 235px;display: inline;overflow: hidden;padding-left: 14px;margin-top: -3px;position: relative;padding-bottom: 4px;height: 98px;} - .car-nmod h3{font-size: 14px;font-weight: bold;line-height: 20px;padding-bottom: 6px;} - .car-nmod a, .car-nmod a:visited{color: #122e67;} - .car-nmod a:hover, .car-nmod a:active, .car-nmod a:focus{color: #ff8400} - - .car-nmod p{line-height: 24px;} - .wb-share, .wb-comment, .wb-like{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat;float: left;display: inline;height: 24px;margin-right: 5px;} - .wb-share, .wb-share:visited, .wb-share:active, .wb-share:focus, .wb-share:hover, .wb-comment, .wb-comment:visited, .wb-comment:hover, .wb-comment:active, .wb-comment:focus, .wb-like, .wb-like:visited, .wb-like:hover, .wb-like:active, .wb-like:focus{line-height: 24px;color: #7b7b7b;} - .wb-share{background-position: 0px -1185px;padding-left: 20px;} - .wb-comment{background-position: 0px -1243px;padding-left: 15px;} - .wb-like{background-position: 0px -1306px;padding-left: 15px;} - - /*×ۺϿÎÌÃ*/ - .vid-txt{} - .vid-txt .vid{float: left;width: 87px;height: 59px;overflow: hidden;display: block;position: relative;} - .vid-txt .txt{float: left;display: inline;margin-left: 12px;width: 120px;} - .vid-txt .txt h3{font-size: 12px;font-weight: normal;line-height: 18px;} - .vid-txt .free-listen{width: 69px;height: 23px;text-align: center;line-height: 23px;display: block;background-color: #ff8400;color: #fff;clear: both;margin-top: 18px;} - .vid-txt .free-listen:visited, .vid-txt .free-listen:hover, .vid-txt .free-listen:active, .vid-txt .free-listen:focus{color: #fff;text-decoration: none;} - .vid-txt .free-listen:hover, .vid-txt .free-listen:active, .vid-txt .free-listen:focus{opacity: 0.7;filter:alpha(opacity=70);} - .vid-txt .vid-play-icon {position:absolute; width:22px; height:22px; top:33px; left:3px; cursor:pointer; background:url(http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i0.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon.png');_background:none;} - .vid-txt:hover .vid-play-icon {background:url(http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png) no-repeat; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale, src='http://i3.sinaimg.cn/ent/deco/2012/0517/ent_zxh_0420_video_play_icon_h.png');_background:none;} - - /*΢²©×ª·¢°´Å¥*/ - .weibo_btn {position:fixed; left:50%; bottom:100px; margin:0 0 0 505px; text-align:center; color:#4c4c4c; width:26px; _position:absolute;} - - .weibo_btn .wt_link, .weibo_btn .wt_link:visited {background:#fff url(http://i0.sinaimg.cn/dy/2011/0905/U6893P1DT20110905170320.gif) no-repeat 4px 5px; width:21px;outline:none; overflow:hidden; display:block; cursor:pointer; color:#4c4c4c; border:solid 1px #ccc;padding:29px 2px 7px; line-height:14px;} - .weibo_btn .wt_link:hover { background-color:#eee;color:#4c4c4c; text-decoration:none;} - .weibo_btn .wt_link, .weibo_btn .wt_link:visited{text-decoration:none} - - /*ת·¢µ½Î¢²©°´Å¥*/ - .weibo_btn { color: #4C4C4C; } - .weibo_btn .wt_link, .weibo_btn .wt_link:visited {background:url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) 0 -490px no-repeat;height: 50px; width: 50px;_background:url(http://i0.sinaimg.cn/dy/deco/2012/1227/news_zxh_content_btn_bg.png) no-repeat; border:none;line-height:400px; padding: 0; filter:Alpha(Opacity=35); opacity:0.35;} - .weibo_btn .wt_link:hover { filter:Alpha(Opacity=50); opacity:0.5;} - - .side-btns-wrap{width:50px;left: 50%; margin:0 0 0 505px;position: fixed; _position:absolute;bottom: 60px;z-index:100; } - - div.nmod01{padding:0px 0 1px 0;margin-top:-1px; line-height:18px;padding-left:10px;*zoom:1;} - /*ÊÓƵֱ²¥*/ - textarea.hidden{position: absolute;top:-100px;left:-9999px;} - .mod07-cont .list-b{padding: 12px 0 0 9px;} - .mod07-cont .list-b li{text-align: left;} - .mod07-cont-b{padding-top: 8px;} - .mod07-cont-b .list-b{height:70px;overflow: hidden; padding-top:0;} - - /*¹º³µ*/ - .mod-a .hd{padding:3px 0 0 0px;height: 26px;line-height: 26px;border-top:1px solid #eee;margin-left:10px;_margin-left:5px;} - .mod-a .tab-nav-a{font-size:14px;float: left;} - .hd a, .hd a:visited{color: #58677a;} - .hd a:hover, .hd a:active, .hd a:focus{color: #ff8400} - .mod-a .extra{float:right;font-size:12px;} - .mod-a .selected:hover, .mod-a .selected:active, .mod-a .selected:focus{color: #58677a;text-decoration: none;} - .mod-a .tab-nav-a a{line-height: 23px;height:23px;padding:0;border-left: 0px;float: left;} - .mod-a .tab-nav-a span{line-height: 23px;height:23px;padding: 0 2px;border-left: 0px;float: left;} - .mod-a .tab-nav-a a.selected{color:#e66100!important;} - /*²Æ¾­ËÑË÷µ÷Õû*/ - .order-search-fin a.order-seat{background-position: 10px -523px;padding-left: 18px;} - .order-search-fin a.order-seat:hover, .order-search-fin a.order-seat:active, .order-search-fin a.order-seat:focus{background-position: 10px -1096px;} - .sow-ipt-w table{table-layout:fixed; } - .sow-ipt-w tbody td{width:68px;} - .sow-ipt-w td a {height:20px;overflow:hidden;} - - /*²Æ¾­Ä£¿éµ÷Õû*/ - .finance-pt{border:1px solid #fff;display: block;float: left;height: 90px;overflow: hidden;width: 105px;} - .finance-form{border: 1px solid #d6dadd;width: 100%} - .finance-form th, .finance-form td{height: 21px;line-height: 21px;overflow: hidden;border: 1px solid #d6dadd} - .finance-form th{background-color: #f7f7f7;color: #113066;text-align: center;font-size: 14px;} - .finance-form td{color: #58677a;text-align: center;} - .finance-form a, .finance-form a:visited{color: #58677a} - .finance-form a:hover, .finance-form a:active, .finance-form a:focus{color: #ff8400} - .finance-form .num{text-align: right;padding-right: 10px;display: block;width: 54px;height: 21px;overflow: hidden;} - .finance-form .down, .finance-form .up{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat;} - .finance-form .down{background-position: 58px -1435px;} - .finance-form .up{background-position: 58px -1485px;} - - /*ÌåÓýÄ£¿éµ×²¿¹ã¸æ*/ - .nmod01 a:link,.nmod01 a:visited{color:#596a7b;} - .nmod01 a:hover,.nmod01 a:active{color:#e66100;} - /*¶¥²¿¹Ø±Õ*/ - .tn-close{float:right;height:21px;margin:8px 0 0 3px;line-height:21px;_line-height:22px;width:54px;height:21px;overflow:hidden;border:1px solid #E2E2E2;font-size:12px;} - .tn-close a{display:block;height:21px;} - .tn-close a:link,.tn-close a:visited{color:#A7A5A0;text-decoration:none;} - .tn-close a:hover,.tn-close a:active{color:#938F8F;text-decoration:none;} - .tn-close i{float:left;display:inline;width:17px;height:17px;margin:2px 5px 0 2px;_margin-right:3px; overflow:hidden;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 3px -994px no-repeat #BEBCBC;_zoom:1;} - .tn-close a:hover i{background-color:#938F8F;} - - /*new icon*/ - .top-nav .tn-new2{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -1539px no-repeat;width: 17px;height: 13px;} - .pro-new{background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 0 -1539px no-repeat;width: 17px;height: 13px;position: absolute;left: 54px;top: 9px;*top:3px;_left:51px;_zoom:1;} - - /*³ÇÊÐÁªÃË*/ - .city-union{width:998px;border:1px solid #e9e9e9;line-height:21px;background:#fffcf1;color:#e66100;} - .city-union .clearit{overflow:hidden;} - .city-union .name{width:120px;float:left;text-align:center;padding:16px 0 0;position:relative;font-family: "Microsoft YaHei", "΢ÈíÑźÚ", "SimHei", "ºÚÌå";font-size: 16px;} - .city-union .name a{color:#e66100} - .city-union .name a:hover{color:#ff8400} - .city-union .clist{background:#fff;float:left;padding:6px 0 6px 35px;width:842px;} - .city-union .clist a,.city-union .clist span{margin:0 6px 0 0;color: #596976} - .city-union .clist a:hover{color: #596976} - .city-union .clist a:hover, .city-union .clist a:active, .city-union .clist a:focus{color: #ff8400} - .city-union .c-hot .clist{background:#fff;border-top:1px solid #e9e9e9} - .city-union .c-hot .name{border-top:1px solid #e9e9e9;padding:6px 0} - - /* ͨÀ¸¹ã¸æ×Ô¶¯¸ß¶È */ - .ad-banner{ width:1000px; } - .mb25{ margin-bottom:25px} - - /*network supervision*/ - .hxjzg{width: 103px;height: 50px;background: url(http://i0.sinaimg.cn/home/2014/1030/hxjzg103.jpg) 0 0 no-repeat;margin: 0px 0 0 0;padding-right:5px;float:right;} - .nwsu_Wrap{width: 133px;height: 50px;float: right;margin: 0px 0 0 0;overflow:hidden;} - .nwsu-item{width: 133px;height: 50px;} - .nwsu{width: 133px;height: 50px;background: url(http://i2.sinaimg.cn/home/2014/1030/jb5.jpg) 0 0 no-repeat;margin: 0px 0 0 0;display:block;} - - .nwsu2{width: 133px;height: 50px;background: url(http://i3.sinaimg.cn/home/main/index2013/0509/bkjb.png) 0 0 no-repeat;margin: 0px 0 0 0;display:block;} - - .nwsu3{width: 133px;height: 50px;background: url(http://i3.sinaimg.cn/home/main/index2013/0509/jbicon.png) 0 0 no-repeat;margin: 0px 0 0 0;display:block;} - - /*suggest*/ - .inp-txt-wrap{position: relative;z-index: 1} - .top-suggest-wrap{position: absolute;border: 1px solid #c1c1c1;background: #fff;width: 258px;z-index: 3000;left: -1px;top:33px;-moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, .2); -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, .2); box-shadow: 3px 3px 3px rgba(0, 0, 0, .2);font-family: "Arial","SimSun","ËÎÌå";overflow: hidden;} - .top-suggest-wrap .top-suggest-item,.top-suggest-wrap .top-suggest-tip,.top-suggest-wrap .top-suggest-more{height: 26px;line-height: 26px;padding-left: 14px;overflow: hidden;} - .top-suggest-wrap .top-suggest-item{cursor: pointer;} - .top-suggest-wrap .top-suggest-mover{background-color: #ddd;color: #000;} - .top-suggest-wrap .top-suggest-tip{color: #000;line-height: 30px;height: 30px;border-bottom: 1px dashed #eee;} - .top-suggest-wrap .top-suggest-more{font-size: 12px;border-top: 1px dashed #eee;height: 30px;line-height: 30px;} - .top-suggest-more a{display: inline;} - /*.top-suggest-more a:link, .top-suggest-more a:visited{color: #000;} - .top-suggest-more a:hover, .top-suggest-more a:active, .top-suggest-more a:focus{color: #ff8400}*/ - .top-suggest-more .top-suggest-hotAll{float: left;margin-left: 0px;} - .top-suggest-more .top-suggest-toHomePage{float:right;margin-right: 10px;} - .weibo-suggest .top-suggest-more{display: block;} - .news-suggest .top-suggest-more{display: none;} - - /*guess modify*/ - .mod-guess-cont,.mod-weiboGuess-cont{width:360px;overflow: hidden;height:208px;} - .mod-guess-cont ul{width:360px;float: left;overflow: hidden;} - .mod-weiboGuess-cont ul{width:180px;float: left;overflow: hidden;} - .mod-guess-control{height:19px !important;overflow:hidden;float: right;padding: 0px !important;margin-top: 9px !important;} - .mod-guess-control a{width:19px;height: 19px;display: inline;float: left;background: #000;margin:0 5px;text-indent: -9999em;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) no-repeat;} - - .mod-licaishiGuess-cont{width:360px;overflow: hidden;height:208px;} - .mod-licaishiGuess-cont ul{width:360px;float: left;overflow: hidden;} - .mod-licaishiGuess-cont {position: relative} - .mod-licaishiGuess-cont .lcs_b_logo {width:105px;height:63px;position:absolute;display:inline-block;z-index:99;right:0;top:0;} - - .selected .mod-guess-control a.mod-guess-prev{background-position: -146px -553px;} - .selected .mod-guess-control a.mod-guess-prev:hover{background-position: -148px -519px;} - .selected .mod-guess-control a.mod-guess-next{background-position: -172px -553px;} - .selected .mod-guess-control a.mod-guess-next:hover{background-position: -123px -519px;} - - .mod-guess-control a.mod-guess-prev{background-position: -146px -607px;} - .mod-guess-control a.mod-guess-prev:hover{background-position: -148px -581px;} - .mod-guess-control a.mod-guess-next{background-position: -172px -607px;} - .mod-guess-control a.mod-guess-next:hover{background-position: -123px -581px;} - - .mod-guess-control .mod-guess-dots{padding: 0px !important;height: 6px !important;overflow: hidden;margin-top: 7px !important;} - .mod-guess-dots span{width:6px !important;height:7px !important;display: inline;float: left;overflow:hidden;background: url(http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png) -175px -525px no-repeat;margin: 0 3px;padding: 0px !important} - .mod-guess-control .mod-guess-dots span.current{background-position: -185px -525px;} - .mod-guess-dots{float: left;display: inline;} - - /*background-color #FAFAFC*/ - /* dz»Òµ×É« */ - /* - .uni-blk, .uni-blk .order-menu span.selected, .blk-line, .mod24-menu span.selected, .mod-a .tab-nav-a a.selected,.uni-blk-b .uni-blk-list02{background-color: #fafafc;} - .uni-blk-pic{border-color:#fafafc;} - - */ - /*ÎÒ°®¿´Í¼*/ - /* HACK ScrollPic ¶Ôdisplay:none³õʼ»¯Ê±£¬²»ÄÜÕýÈ·Éú³Édots*/ - .part-e .part-econt{width:1000px;height:201px;overflow: hidden;position:relative} - .scroll-pic-frame{height:164px;overflow: hidden;} - .scroll-pic-frame .scroll-item{position: relative;} - .scroll-pic-guess-wrap .scroll-item a{text-align: center;background: #F6F6F6;} - .scroll-pic-guess-wrap .scroll-img{display: inline-block; *display:table-cell;width:198px;height:132px;background: #F6F6F6;text-align: center;cursor: pointer;overflow:hidden;position: relative;} - .scroll-pic-guess-wrap .scroll-img img{display: inline-block;*margin-top:-30px;border: none;vertical-align: middle;max-height: 100%;max-width: 100%;} - .scroll-pic-guess-wrap i{display: inline-block;height: 100%;line-height: 132px; vertical-align: middle;font-size: 0;} - .scroll-loading{width:1000px;height:132px;overflow: hidden;} - -/* ʱÉÐÈȵã */ - .xb-mod22-cont-pa{position:relative;zoom:1;width:220px;height:160px;} - .xb-mod22-cont-pa a{display:block;position:relative;zoom:1;width:220px;height:160px;} - .xb-mod22-cont-pa a:link,.xb-mod22-cont-pa a:visited{color:#fff;text-decoration:none;} - .xb-mod22-cont-pa a:hover{color:#fff;text-decoration:underline;} - .xb-mod22-cont-pa img{display:block;width:220px;height:160px;} - .xb-mod22-cont-pa span{cursor:pointer;zoom:1;position:absolute;left:0;bottom:0;display:block;width:220px;height:30px;font:500 14px/30px 'Microsoft Yahei','΢ÈíÑźÚ','Simsun','ËÎÌå';text-align:center;background:rgba(0,0,0,0.5);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#88000000',endColorstr='#88000000')\9;} - :root .xb-mod22-cont-pa span{filter:none\9;} - .xb-mod22-cont-pa a:hover span{text-decoration:underline;} - - /* 0904 side-btns-closer begin */ - .side-btns-wrap .side-btns-closer {height: 18px;overflow: hidden;clear: both;} - .side-btns-wrap .side-btns-closer a {display: block;width: 100%;height: 18px;overflow: hidden;line-height: 300px;background: url(http://i3.sinaimg.cn/dy/deco/2013/0913/close2.png) 0 0 no-repeat;} - .side-btns-wrap .side-btns-closer a:link, .side-btns-wrap .side-btns-closer a:visited {} - .side-btns-wrap .side-btns-closer a:hover, .side-btns-wrap .side-btns-closer a:active, .side-btns-wrap .side-btns-closer a:focus {opacity: 0.8;filter:alpha(opacity=80);} - /* 0904 side-btns-closer end */ - - /* 0909 history pictures begin */ - .history-pics-wrap {} - .history-pics-wrap .history-pics-arrleft-wrap, .history-pics-wrap .history-pics-arrright-wrap, .history-pics-wrap .history-pics-frame {float: left;display: inline;} - .history-pics-wrap .history-pics-arrleft-wrap, .history-pics-wrap .history-pics-arrright-wrap {width: 19px;} - .history-pics-wrap .history-pics-arrleft, .history-pics-wrap .history-pics-arrright{width: 19px;height: 26px;overflow: hidden;background: url(http://i3.sinaimg.cn/home/main/index2013/0904/history_arr.png) 0 0 no-repeat;display: block;margin-top: 35px;} - .history-pics-wrap .history-pics-arrleft{background-position: 0 0;} - .history-pics-wrap .history-pics-arrleft:hover{background-position: 0 -41px;} - .history-pics-wrap .history-pics-arrright{background-position: -12px 0;} - .history-pics-wrap .history-pics-arrright:hover{background-position: -12px -41px;} - .history-pics-wrap .history-pics-frame{width: 180px;overflow: hidden;} - .history-pics-wrap .history-pics-frame .history-pics-box{} - .history-pics-wrap .history-pics-frame .history-pics-item{float: left;display: inline;width: 180px;} - .history-pics-wrap .history-pics-item a {display: block;} - .history-pics-wrap .history-pics-item span {height: 21px;line-height: 21px;background-color: #000;text-align:center;display: block;} - .history-pics-wrap .history-pics-item a:link, .history-pics-wrap .history-pics-item a:visited{color: #fff;} - .history-pics-wrap .history-pics-item a:hover, .history-pics-wrap .history-pics-item a:focus, .history-pics-wrap .history-pics-item a:active{ color: #ff8400;text-decoration: none;} - .history-pics-wrap .history-pics-item a:link span, .history-pics-wrap .history-pics-item a:visited span{color: #fff;} - .history-pics-wrap .history-pics-item a:hover span, .history-pics-wrap .history-pics-item a:focus span, .history-pics-wrap .history-pics-item a:active span{ color: #ff8400;text-decoration: none;} - /* 0909 history pictures end */ - - .uni-blk-t .t-guidechange a{ - display: block; - width: 37px; - height: 34px; - padding-left: 25px; - background: url("http://i1.sinaimg.cn/dy/main/icon/changeicon_red4.png") 7px -26px no-repeat; - border-left: 1px solid #dbdee1; - color: #ff0000; - } - .uni-blk-t .t-guidechange a:visited{color: #ff0000;} - .uni-blk-t .t-guidechange a:hover{background: url("http://i1.sinaimg.cn/dy/main/icon/changeicon_red4.png") 7px -26px no-repeat;color: #ff0000;} - - /*addÆû³µÆµµÀ*/ - .selectCar{margin:8px 0;} - .selectLeft,.selectRight{float:left;} - .selectLeft{width:180px;} - .selectLeft form{float:left;width:140px;} - .selectLeft .sim-select{float: left;display: inline;width: 140px;margin-bottom:8px;background:#fff;position:relative;} - .selectLeft .sim-select h3{font-weight: normal;color: #333;background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) 120px -840px no-repeat;height: 30px;line-height: 30px;border: 1px solid #cdcdcd;width: 132px;padding-left: 8px;font-size: 12px;cursor: pointer;} - .selectLeft .sim-select .sim-ul-flt{} - .selectLeft .sim-select ul{top: 32px;left: 0px;background:#fff;} - .selectLeft .sim-select li{width: 132px;height: 30px;line-height: 30px;padding-left: 8px;color: #333;} - .selectLeft .selectBtn{width:140px;height:30px;line-height:30px;text-align:center;background:#ff8400;float:left;overflow:hidden;} - .selectLeft .selectBtn input{display:block;width:140px;height:30px;background:none;border:none;color:#fff;font-size:14px;} - .selectLeft .selectBtn input:hover{cursor:pointer;} - .selectLeft .carIndex{float:left;width:24px;margin:4px 10px 0 0;position:relative;} - .selectLeft span{width:24px;text-align:center;overflow:hidden;display:block;} - .selectLeft .carGap{background:#ebebeb;width:2px;height:16px;margin:0 auto;} - .selectLeft .carDot{width:24px;height:24px;line-height:24px;color:#cdcdcd;font-size:14px;background:url(http://i0.sinaimg.cn/home/main/index2013/0127/carIndex.jpg) 0px -113px no-repeat;} - .selectLeft .able{background-position:0px 0px;color:#fff;} - .selectRight{width:168px;padding-left:12px;} - .selectRight .cbox li{width:54px;overflow:hidden;float:left;text-align:center;} - .selectRight .cbox li a{line-height:26px;display: block;} - .selectRight .cbox .cborder{border-left:1px solid #eee;border-right:1px solid #eee;} - .selectRight .cbox2 a,.selectRight .cbox2 span{float:left;} - .selectRight .cbox2 span{padding:0 6px;} - .selectRight .cbox2 p{line-height:24px;} - .selectRight .cbox2 .clearfix{padding-left:8px;} - - .selectRight a:link{color:#122E67;text-decoration:none;} - .selectRight a:visited{color:#52687e;text-decoration:none;} - .selectRight a:hover,.list-a a:active{color:#ff8400;text-decoration:underline;} - - .carPics {padding-top:10px;position:absolute;background:#fff;} - .carPics .carPicL,.carPics .carPicR{float:left;height:360px;overflow:hidden;} - .carPics .carPicL .uni-blk-pic,.carPics .carPicL .uni-blk-pic span{width:160px;} - .carPics .carPicL{width:162px;margin-right:6px;} - .carPics .uni-blk-pic{margin-bottom:10px;} - .carPics .carPicR{width:192px;} - .carPics .carPicR .uni-blk-pic,.carPics .carPicR .uni-blk-pic span{width:190px;} - .carPics .carh1{height:108px;} - .carPics .carh2{height:238px;} - .carPics .carh3,.carPics .carh4{width:180px;display:block;text-align:left;margin-bottom:10px;float:left; padding-left:10px;} - .carPics .carh3{height:32px;font-size:16px;background:#ff8400;line-height:32px;} - .carPics .carh4{height:46px;background:#2375e2;} - .carPics .carh4 p{line-height:22px;} - .carPics .carh4 span{line-height:22px;display:block} - .carPics .carh3 a,.carPics .carh4 a{color:#fff;} - .carPics .carh5{height:124px;} - - span#SI_IP_Auto_City_Title{color:#58677a;} - - /* 0204 ÐÞ¸Ä ¿Æ¼¼ ʶȤ°å¿é */ - .shiqu-ml{ margin-left: 19px; margin-bottom: 7px; _margin-bottom: 0px; } - .shiqu-mt{ _margin-top: -3px; } - - /* 0316 ÐÞ¸Ä Í¼Æ¬ B °æ */ - #fc_B_pic{ position: relative; z-index: 98; } - #fc_B_pic_attachment{ position: absolute; margin: 13px 0 0 -1px; width: 361px; height: 250px; z-index: 99; overflow: hidden; background-color: white; } - .fc-B-pic-a-header{ border-left: solid 1px #dbdee1; border-top: solid 1px #dbdee1; border-bottom: solid 1px #dbdee1; height: 34px; background-color: #fafafa; } - .fc-B-pic-a-header a{ height: 34px; line-height: 34px; border-right: solid 1px #dbdee1; font-size: 14px; text-align: center; color: #333; } - .fc-B-pic-a-header a:hover{ color: #ff8400; text-decoration: none; } - .fc-B-pic-ah-hover{ border-bottom: solid 1px #fff; color: #ff8400!important; background-color: #fff; text-decoration: none!important; } - .fc-bpah-items{ float: left; width: 63px; } - .fc-bpah-fr{ float: right; width: 102px; text-indent: 15px; background: url(http://i0.sinaimg.cn/home/2015/0401/bg.png) no-repeat 10px 10px; color: #333; text-decoration: none; } - .fc-bpah-fr:hover{ color: #ff8400; text-decoration: none; background-position: 10px -25px; } - .fc-bpah-fr-hover{ color: #ff8400!important; background-position: 10px -25px; background-color: #fff!important; text-decoration: none!important; border-bottom: solid 1px #fff!important; } - - .fc-B-pic-a-cont{ width: 400px; margin-top: 18px; } - .fc-B-pic-a-cont a{ float: left; width: 105px; height: 70px; position: relative; overflow: hidden; border: solid 1px #fff; margin: 0 19px 28px 0; color: #fff; } - .fc-B-pic-a-cont a:visited{ color: #fff; } - .fc-B-pic-a-cont a:hover{ border-color: #e66100; color: #ff8400; } - .fc-B-pic-a-cont a:hover span{text-decoration: none; font-style: none; outline: none; } - .fc-B-pic-a-cont a img{ width: 100%; height: 100%; } - .fc-B-pic-a-cont a span{ position: absolute; width: 100%; height: 20px; bottom: 0px; left: 0; text-align: center; font-size: 12px; line-height: 20px; text-decoration: none!important; } - .fc-B-pic-a-cont a span.fc-bpac-bg{ background-color: #000; opacity: 0.7; _filter: alpha(opacity=70); } - .uni-blk-t .t-guide{outline: none!important;} - -/* - .fc-B-pic-a-intr{ position: absolute; width: 370px; top: 54px; left: 0; background-color: #fff; } - .fc-B-pic-a-intr a{ font-size: 14px; color: #333; line-height: 14px; float: left; height: 14px; width: 90px; text-align: center; margin-bottom: 20px; } - .fc-B-pic-a-intr a:hover{ color: #ff8400; text-decoration: none; } - .fc-B-pic-a-submit{ border-top: solid 1px #dbdee1; margin-top: -5px; padding-top: 15px; width: 360px; float: left; } - .fc-B-pic-a-submit span{ font-size: 14px; color: #666; line-height: 28px; } - a#fc_bpac_submit{ float: right; font-size: 14px; color: #fff; width: 70px; height: 28px; background-color: #ff8400; text-align: center; line-height: 28px; } - a#fc_bpac_submit:hover{ background-color: #ff9900; } - a.fc-B-pic-ai-hover{ color: #ff8400; background: url(http://i0.sinaimg.cn/home/2015/0401/bg.png) no-repeat 8px -73px; } -*/ - - </style> - -<script language="javascript" type="text/javascript"> -//<![CDATA[ -document.domain = "sina.com.cn"; -//]]> -</script> - -<script> - (function (d, s, id) { - var s, n = d.getElementsByTagName(s)[0]; - if (d.getElementById(id)) return; - s = d.createElement(s); - s.id = id; - s.setAttribute('charset', 'utf-8'); - s.src = '//d' + Math.floor(0 + Math.random() * (9 - 0 + 1)) + '.sina.com.cn/litong/zhitou/sinaads/release/sinaads.js'; - n.parentNode.insertBefore(s, n); - })(document, 'script', 'sinaads-script'); -</script> - -</head> -<body><!-- body code begin --> - -<!-- SUDA_CODE_START --> -<script type="text/javascript"> -//<!-- -(function(){var an="V=2.1.15";var ah=window,F=document,s=navigator,W=s.userAgent,ao=ah.screen,j=ah.location.href;var aD="https:"==ah.location.protocol?"https://s":"http://",ay="beacon.sina.com.cn";var N=aD+ay+"/a.gif?",z=aD+ay+"/g.gif?",R=aD+ay+"/f.gif?",ag=aD+ay+"/e.gif?",aB=aD+"beacon.sinauda.com/i.gif?";var aA=F.referrer.toLowerCase();var aa="SINAGLOBAL",Y="FSINAGLOBAL",H="Apache",P="ULV",l="SUP",aE="UOR",E="_s_acc",X="_s_tentry",n=false,az=false,B=(document.domain=="sina.com.cn")?true:false;var o=0;var aG=false,A=false;var al="";var m=16777215,Z=0,C,K=0;var r="",b="",a="";var M=[],S=[],I=[];var u=0;var v=0;var p="";var am=false;var w=false;function O(){var e=document.createElement("iframe");e.src=aD+ay+"/data.html?"+new Date().getTime();e.id="sudaDataFrame";e.style.height="0px";e.style.width="1px";e.style.overflow="hidden";e.frameborder="0";e.scrolling="no";document.getElementsByTagName("head")[0].appendChild(e)}function k(){var e=document.createElement("iframe");e.src=aD+ay+"/ckctl.html";e.id="ckctlFrame";e.style.height="0px";e.style.width="1px";e.style.overflow="hidden";e.frameborder="0";e.scrolling="no";document.getElementsByTagName("head")[0].appendChild(e)}function q(){var e=document.createElement("script");e.src=aD+ay+"/h.js";document.getElementsByTagName("head")[0].appendChild(e)}function h(aH,i){var D=F.getElementsByName(aH);var e=(i>0)?i:0;return(D.length>e)?D[e].content:""}function aF(){var aJ=F.getElementsByName("sudameta");var aR=[];for(var aO=0;aO<aJ.length;aO++){var aK=aJ[aO].content;if(aK){if(aK.indexOf(";")!=-1){var D=aK.split(";");for(var aH=0;aH<D.length;aH++){var aP=aw(D[aH]);if(!aP){continue}aR.push(aP)}}else{aR.push(aK)}}}var aM=F.getElementsByTagName("meta");for(var aO=0,aI=aM.length;aO<aI;aO++){var aN=aM[aO];if(aN.name=="tags"){aR.push("content_tags:"+encodeURI(aN.content))}}var aL=t("vjuids");aR.push("vjuids:"+aL);var e="";var aQ=j.indexOf("#");if(aQ!=-1){e=escape(j.substr(aQ+1))}aR.push("hashtag:"+e);return aR}function V(aK,D,aI,aH){if(aK==""){return""}aH=(aH=="")?"=":aH;D+=aH;var aJ=aK.indexOf(D);if(aJ<0){return""}aJ+=D.length;var i=aK.indexOf(aI,aJ);if(i<aJ){i=aK.length}return aK.substring(aJ,i)}function t(e){if(undefined==e||""==e){return""}return V(F.cookie,e,";","")}function at(aI,e,i,aH){if(e!=null){if((undefined==aH)||(null==aH)){aH="sina.com.cn"}if((undefined==i)||(null==i)||(""==i)){F.cookie=aI+"="+e+";domain="+aH+";path=/"}else{var D=new Date();var aJ=D.getTime();aJ=aJ+86400000*i;D.setTime(aJ);aJ=D.getTime();F.cookie=aI+"="+e+";domain="+aH+";expires="+D.toUTCString()+";path=/"}}}function f(D){try{var i=document.getElementById("sudaDataFrame").contentWindow.storage;return i.get(D)}catch(aH){return false}}function ar(D,aH){try{var i=document.getElementById("sudaDataFrame").contentWindow.storage;i.set(D,aH);return true}catch(aI){return false}}function L(){var aJ=15;var D=window.SUDA.etag;if(!B){return"-"}if(u==0){O();q()}if(D&&D!=undefined){w=true}ls_gid=f(aa);if(ls_gid===false||w==false){return false}else{am=true}if(ls_gid&&ls_gid.length>aJ){at(aa,ls_gid,3650);n=true;return ls_gid}else{if(D&&D.length>aJ){at(aa,D,3650);az=true}var i=0,aI=500;var aH=setInterval((function(){var e=t(aa);if(w){e=D}i+=1;if(i>3){clearInterval(aH)}if(e.length>aJ){clearInterval(aH);ar(aa,e)}}),aI);return w?D:t(aa)}}function U(e,aH,D){var i=e;if(i==null){return false}aH=aH||"click";if((typeof D).toLowerCase()!="function"){return}if(i.attachEvent){i.attachEvent("on"+aH,D)}else{if(i.addEventListener){i.addEventListener(aH,D,false)}else{i["on"+aH]=D}}return true}function af(){if(window.event!=null){return window.event}else{if(window.event){return window.event}var D=arguments.callee.caller;var i;var aH=0;while(D!=null&&aH<40){i=D.arguments[0];if(i&&(i.constructor==Event||i.constructor==MouseEvent||i.constructor==KeyboardEvent)){return i}aH++;D=D.caller}return i}}function g(i){i=i||af();if(!i.target){i.target=i.srcElement;i.pageX=i.x;i.pageY=i.y}if(typeof i.layerX=="undefined"){i.layerX=i.offsetX}if(typeof i.layerY=="undefined"){i.layerY=i.offsetY}return i}function aw(aH){if(typeof aH!=="string"){throw"trim need a string as parameter"}var e=aH.length;var D=0;var i=/(\u3000|\s|\t|\u00A0)/;while(D<e){if(!i.test(aH.charAt(D))){break}D+=1}while(e>D){if(!i.test(aH.charAt(e-1))){break}e-=1}return aH.slice(D,e)}function c(e){return Object.prototype.toString.call(e)==="[object Array]"}function J(aH,aL){var aN=aw(aH).split("&");var aM={};var D=function(i){if(aL){try{return decodeURIComponent(i)}catch(aP){return i}}else{return i}};for(var aJ=0,aK=aN.length;aJ<aK;aJ++){if(aN[aJ]){var aI=aN[aJ].split("=");var e=aI[0];var aO=aI[1];if(aI.length<2){aO=e;e="$nullName"}if(!aM[e]){aM[e]=D(aO)}else{if(c(aM[e])!=true){aM[e]=[aM[e]]}aM[e].push(D(aO))}}}return aM}function ac(D,aI){for(var aH=0,e=D.length;aH<e;aH++){aI(D[aH],aH)}}function ak(i){var e=new RegExp("^http(?:s)?://([^/]+)","im");if(i.match(e)){return i.match(e)[1].toString()}else{return""}}function aj(aO){try{var aL="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var D="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";var aQ=function(e){var aR="",aS=0;for(;aS<e.length;aS++){aR+="%"+aH(e[aS])}return decodeURIComponent(aR)};var aH=function(e){var i="0"+e.toString(16);return i.length<=2?i:i.substr(1)};var aP=function(aY,aV,aR){if(typeof(aY)=="string"){aY=aY.split("")}var aX=function(a7,a9){for(var a8=0;a8<a7.length;a8++){if(a7[a8]==a9){return a8}}return -1};var aS=[];var a6,a4,a1="";var a5,a3,a0,aZ="";if(aY.length%4!=0){}var e=/[^A-Za-z0-9\+\/\=]/g;var a2=aL.split("");if(aV=="urlsafe"){e=/[^A-Za-z0-9\-_\=]/g;a2=D.split("")}var aU=0;if(aV=="binnary"){a2=[];for(aU=0;aU<=64;aU++){a2[aU]=aU+128}}if(aV!="binnary"&&e.exec(aY.join(""))){return aR=="array"?[]:""}aU=0;do{a5=aX(a2,aY[aU++]);a3=aX(a2,aY[aU++]);a0=aX(a2,aY[aU++]);aZ=aX(a2,aY[aU++]);a6=(a5<<2)|(a3>>4);a4=((a3&15)<<4)|(a0>>2);a1=((a0&3)<<6)|aZ;aS.push(a6);if(a0!=64&&a0!=-1){aS.push(a4)}if(aZ!=64&&aZ!=-1){aS.push(a1)}a6=a4=a1="";a5=a3=a0=aZ=""}while(aU<aY.length);if(aR=="array"){return aS}var aW="",aT=0;for(;aT<aS.lenth;aT++){aW+=String.fromCharCode(aS[aT])}return aW};var aI=[];var aN=aO.substr(0,3);var aK=aO.substr(3);switch(aN){case"v01":for(var aJ=0;aJ<aK.length;aJ+=2){aI.push(parseInt(aK.substr(aJ,2),16))}return decodeURIComponent(aQ(aP(aI,"binnary","array")));break;case"v02":aI=aP(aK,"urlsafe","array");return aQ(aP(aI,"binnary","array"));break;default:return decodeURIComponent(aO)}}catch(aM){return""}}var ap={screenSize:function(){return(m&8388608==8388608)?ao.width+"x"+ao.height:""},colorDepth:function(){return(m&4194304==4194304)?ao.colorDepth:""},appCode:function(){return(m&2097152==2097152)?s.appCodeName:""},appName:function(){return(m&1048576==1048576)?((s.appName.indexOf("Microsoft Internet Explorer")>-1)?"MSIE":s.appName):""},cpu:function(){return(m&524288==524288)?(s.cpuClass||s.oscpu):""},platform:function(){return(m&262144==262144)?(s.platform):""},jsVer:function(){if(m&131072!=131072){return""}var aI,e,aK,D=1,aH=0,i=(s.appName.indexOf("Microsoft Internet Explorer")>-1)?"MSIE":s.appName,aJ=s.appVersion;if("MSIE"==i){e="MSIE";aI=aJ.indexOf(e);if(aI>=0){aK=window.parseInt(aJ.substring(aI+5));if(3<=aK){D=1.1;if(4<=aK){D=1.3}}}}else{if(("Netscape"==i)||("Opera"==i)||("Mozilla"==i)){D=1.3;e="Netscape6";aI=aJ.indexOf(e);if(aI>=0){D=1.5}}}return D},network:function(){if(m&65536!=65536){return""}var i="";i=(s.connection&&s.connection.type)?s.connection.type:i;try{F.body.addBehavior("#default#clientCaps");i=F.body.connectionType}catch(D){i="unkown"}return i},language:function(){return(m&32768==32768)?(s.systemLanguage||s.language):""},timezone:function(){return(m&16384==16384)?(new Date().getTimezoneOffset()/60):""},flashVer:function(){if(m&8192!=8192){return""}var aK=s.plugins,aH,aL,aN;if(aK&&aK.length){for(var aJ in aK){aL=aK[aJ];if(aL.description==null){continue}if(aH!=null){break}aN=aL.description.toLowerCase();if(aN.indexOf("flash")!=-1){aH=aL.version?parseInt(aL.version):aN.match(/\d+/);continue}}}else{if(window.ActiveXObject){for(var aI=10;aI>=2;aI--){try{var D=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+aI);if(D){aH=aI;break}}catch(aM){}}}else{if(W.indexOf("webtv/2.5")!=-1){aH=3}else{if(W.indexOf("webtv")!=-1){aH=2}}}}return aH},javaEnabled:function(){if(m&4096!=4096){return""}var D=s.plugins,i=s.javaEnabled(),aH,aI;if(i==true){return 1}if(D&&D.length){for(var e in D){aH=D[e];if(aH.description==null){continue}if(i!=null){break}aI=aH.description.toLowerCase();if(aI.indexOf("java plug-in")!=-1){i=parseInt(aH.version);continue}}}else{if(window.ActiveXObject){i=(new ActiveXObject("JavaWebStart.IsInstalled")!=null)}}return i?1:0}};var ad={pageId:function(i){var D=i||r,aK="-9999-0-0-1";if((undefined==D)||(""==D)){try{var aH=h("publishid");if(""!=aH){var aJ=aH.split(",");if(aJ.length>0){if(aJ.length>=3){aK="-9999-0-"+aJ[1]+"-"+aJ[2]}D=aJ[0]}}else{D="0"}}catch(aI){D="0"}D=D+aK}return D},sessionCount:function(){var e=t("_s_upa");if(e==""){e=0}return e},excuteCount:function(){return SUDA.sudaCount},referrer:function(){if(m&2048!=2048){return""}var e=/^[^\?&#]*.swf([\?#])?/;if((aA=="")||(aA.match(e))){var i=V(j,"ref","&","");if(i!=""){return escape(i)}}return escape(aA)},isHomepage:function(){if(m&1024!=1024){return""}var D="";try{F.body.addBehavior("#default#homePage");D=F.body.isHomePage(j)?"Y":"N"}catch(i){D="unkown"}return D},PGLS:function(){return(m&512==512)?h("stencil"):""},ZT:function(){if(m&256!=256){return""}var e=h("subjectid");e.replace(",",".");e.replace(";",",");return escape(e)},mediaType:function(){return(m&128==128)?h("mediaid"):""},domCount:function(){return(m&64==64)?F.getElementsByTagName("*").length:""},iframeCount:function(){return(m&32==32)?F.getElementsByTagName("iframe").length:""}};var av={visitorId:function(){var i=15;var e=t(aa);if(e.length>i&&u==0){return e}else{return}},fvisitorId:function(e){if(!e){var e=t(Y);return e}else{at(Y,e,3650)}},sessionId:function(){var e=t(H);if(""==e){var i=new Date();e=Math.random()*10000000000000+"."+i.getTime()}return e},flashCookie:function(e){if(e){}else{return p}},lastVisit:function(){var D=t(H);var aI=t(P);var aH=aI.split(":");var aJ="",i;if(aH.length>=6){if(D!=aH[4]){i=new Date();var e=new Date(window.parseInt(aH[0]));aH[1]=window.parseInt(aH[1])+1;if(i.getMonth()!=e.getMonth()){aH[2]=1}else{aH[2]=window.parseInt(aH[2])+1}if(((i.getTime()-e.getTime())/86400000)>=7){aH[3]=1}else{if(i.getDay()<e.getDay()){aH[3]=1}else{aH[3]=window.parseInt(aH[3])+1}}aJ=aH[0]+":"+aH[1]+":"+aH[2]+":"+aH[3];aH[5]=aH[0];aH[0]=i.getTime();at(P,aH[0]+":"+aH[1]+":"+aH[2]+":"+aH[3]+":"+D+":"+aH[5],360)}else{aJ=aH[5]+":"+aH[1]+":"+aH[2]+":"+aH[3]}}else{i=new Date();aJ=":1:1:1";at(P,i.getTime()+aJ+":"+D+":",360)}return aJ},userNick:function(){if(al!=""){return al}var D=unescape(t(l));if(D!=""){var i=V(D,"ag","&","");var e=V(D,"user","&","");var aH=V(D,"uid","&","");var aJ=V(D,"sex","&","");var aI=V(D,"dob","&","");al=i+":"+e+":"+aH+":"+aJ+":"+aI;return al}else{return""}},userOrigin:function(){if(m&4!=4){return""}var e=t(aE);var i=e.split(":");if(i.length>=2){return i[0]}else{return""}},advCount:function(){return(m&2==2)?t(E):""},setUOR:function(){var aL=t(aE),aP="",i="",aO="",aI="",aM=j.toLowerCase(),D=F.referrer.toLowerCase();var aQ=/[&|?]c=spr(_[A-Za-z0-9]{1,}){3,}/;var aK=new Date();if(aM.match(aQ)){aO=aM.match(aQ)[0]}else{if(D.match(aQ)){aO=D.match(aQ)[0]}}if(aO!=""){aO=aO.substr(3)+":"+aK.getTime()}if(aL==""){if(t(P)==""){aP=ak(D);i=ak(aM)}at(aE,aP+","+i+","+aO,365)}else{var aJ=0,aN=aL.split(",");if(aN.length>=1){aP=aN[0]}if(aN.length>=2){i=aN[1]}if(aN.length>=3){aI=aN[2]}if(aO!=""){aJ=1}else{var aH=aI.split(":");if(aH.length>=2){var e=new Date(window.parseInt(aH[1]));if(e.getTime()<(aK.getTime()-86400000*30)){aJ=1}}}if(aJ){at(aE,aP+","+i+","+aO,365)}}},setAEC:function(e){if(""==e){return}var i=t(E);if(i.indexOf(e+",")<0){i=i+e+","}at(E,i,7)},ssoInfo:function(){var D=unescape(aj(t("sso_info")));if(D!=""){if(D.indexOf("uid=")!=-1){var i=V(D,"uid","&","");return escape("uid:"+i)}else{var e=V(D,"u","&","");return escape("u:"+unescape(e))}}else{return""}},subp:function(){return t("SUBP")}};var ai={CI:function(){var e=["sz:"+ap.screenSize(),"dp:"+ap.colorDepth(),"ac:"+ap.appCode(),"an:"+ap.appName(),"cpu:"+ap.cpu(),"pf:"+ap.platform(),"jv:"+ap.jsVer(),"ct:"+ap.network(),"lg:"+ap.language(),"tz:"+ap.timezone(),"fv:"+ap.flashVer(),"ja:"+ap.javaEnabled()];return"CI="+e.join("|")},PI:function(e){var i=["pid:"+ad.pageId(e),"st:"+ad.sessionCount(),"et:"+ad.excuteCount(),"ref:"+ad.referrer(),"hp:"+ad.isHomepage(),"PGLS:"+ad.PGLS(),"ZT:"+ad.ZT(),"MT:"+ad.mediaType(),"keys:","dom:"+ad.domCount(),"ifr:"+ad.iframeCount()];return"PI="+i.join("|")},UI:function(){var e=["vid:"+av.visitorId(),"sid:"+av.sessionId(),"lv:"+av.lastVisit(),"un:"+av.userNick(),"uo:"+av.userOrigin(),"ae:"+av.advCount(),"lu:"+av.fvisitorId(),"si:"+av.ssoInfo(),"rs:"+(n?1:0),"dm:"+(B?1:0),"su:"+av.subp()];return"UI="+e.join("|")},EX:function(i,e){if(m&1!=1){return""}i=(null!=i)?i||"":b;e=(null!=e)?e||"":a;return"EX=ex1:"+i+"|ex2:"+e},MT:function(){return"MT="+aF().join("|")},V:function(){return an},R:function(){return"gUid_"+new Date().getTime()}};function ax(){var aK="-",aH=F.referrer.toLowerCase(),D=j.toLowerCase();if(""==t(X)){if(""!=aH){aK=ak(aH)}at(X,aK,"","weibo.com")}var aI=/weibo.com\/reg.php/;if(D.match(aI)){var aJ=V(unescape(D),"sharehost","&","");var i=V(unescape(D),"appkey","&","");if(""!=aJ){at(X,aJ,"","weibo.com")}at("appkey",i,"","weibo.com")}}function d(e,i){G(e,i)}function G(i,D){D=D||{};var e=new Image(),aH;if(D&&D.callback&&typeof D.callback=="function"){e.onload=function(){clearTimeout(aH);aH=null;D.callback(true)}}SUDA.img=e;e.src=i;aH=setTimeout(function(){if(D&&D.callback&&typeof D.callback=="function"){D.callback(false);e.onload=null}},D.timeout||2000)}function x(e,aH,D){SUDA.sudaCount++;if(!av.visitorId()&&!L()){if(u<3){u++;setTimeout(x,500);return}}var i=N+[ai.V(),ai.CI(),ai.PI(e),ai.UI(),ai.MT(),ai.EX(aH,D),ai.R()].join("&");G(i);if(window.location.host.search("auto.sina.com.cn")>=0){wrating_url="http://m.wrating.com/m.gif?a=&c=860010-2370010112&mcookie="+av.visitorId()+"&"+ai.R()+"=";G(wrating_url)}}function y(e,D,i){if(aG||A){return}if(SUDA.sudaCount!=0){return}x(e,D,i)}function ab(e,aH){if((""==e)||(undefined==e)){return}av.setAEC(e);if(0==aH){return}var D="AcTrack||"+t(aa)+"||"+t(H)+"||"+av.userNick()+"||"+e+"||";var i=ag+D+"&gUid_"+new Date().getTime();d(i)}function aq(aI,e,i,aJ){aJ=aJ||{};if(!i){i=""}else{i=escape(i)}var aH="UATrack||"+t(aa)+"||"+t(H)+"||"+av.userNick()+"||"+aI+"||"+e+"||"+ad.referrer()+"||"+i+"||"+(aJ.realUrl||"")+"||"+(aJ.ext||"");var D=ag+aH+"&gUid_"+new Date().getTime();d(D,aJ)}function aC(aK){var i=g(aK);var aI=i.target;var aH="",aL="",D="";var aJ;if(aI!=null&&aI.getAttribute&&(!aI.getAttribute("suda-uatrack")&&!aI.getAttribute("suda-actrack")&&!aI.getAttribute("suda-data"))){while(aI!=null&&aI.getAttribute&&(!!aI.getAttribute("suda-uatrack")||!!aI.getAttribute("suda-actrack")||!!aI.getAttribute("suda-data"))==false){if(aI==F.body){return}aI=aI.parentNode}}if(aI==null||aI.getAttribute==null){return}aH=aI.getAttribute("suda-actrack")||"";aL=aI.getAttribute("suda-uatrack")||aI.getAttribute("suda-data")||"";sudaUrls=aI.getAttribute("suda-urls")||"";if(aL){aJ=J(aL);if(aI.tagName.toLowerCase()=="a"){D=aI.href}opts={};opts.ext=(aJ.ext||"");aJ.key&&SUDA.uaTrack&&SUDA.uaTrack(aJ.key,aJ.value||aJ.key,D,opts)}if(aH){aJ=J(aH);aJ.key&&SUDA.acTrack&&SUDA.acTrack(aJ.key,aJ.value||aJ.key)}}if(window.SUDA&&Object.prototype.toString.call(window.SUDA)==="[object Array]"){for(var Q=0,ae=SUDA.length;Q<ae;Q++){switch(SUDA[Q][0]){case"setGatherType":m=SUDA[Q][1];break;case"setGatherInfo":r=SUDA[Q][1]||r;b=SUDA[Q][2]||b;a=SUDA[Q][3]||a;break;case"setPerformance":Z=SUDA[Q][1];break;case"setPerformanceFilter":C=SUDA[Q][1];break;case"setPerformanceInterval":K=SUDA[Q][1]*1||0;K=isNaN(K)?0:K;break;case"setGatherMore":M.push(SUDA[Q].slice(1));break;case"acTrack":S.push(SUDA[Q].slice(1));break;case"uaTrack":I.push(SUDA[Q].slice(1));break}}}aG=(function(D,i){if(ah.top==ah){return false}else{try{if(F.body.clientHeight==0){return false}return((F.body.clientHeight>=D)&&(F.body.clientWidth>=i))?false:true}catch(aH){return true}}})(320,240);A=(function(){return false})();av.setUOR();var au=av.sessionId();window.SUDA=window.SUDA||[];SUDA.sudaCount=SUDA.sudaCount||0;SUDA.log=function(){x.apply(null,arguments)};SUDA.acTrack=function(){ab.apply(null,arguments)};SUDA.uaTrack=function(){aq.apply(null,arguments)};U(F.body,"click",aC);window.GB_SUDA=SUDA;GB_SUDA._S_pSt=function(){};GB_SUDA._S_acTrack=function(){ab.apply(null,arguments)};GB_SUDA._S_uaTrack=function(){aq.apply(null,arguments)};window._S_pSt=function(){};window._S_acTrack=function(){ab.apply(null,arguments)};window._S_uaTrack=function(){aq.apply(null,arguments)};window._S_PID_="";y();try{k()}catch(T){}})(); -//--> -</script> -<noScript> -<div style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden'><img width=0 height=0 src='http://beacon.sina.com.cn/a.gif?noScript' border='0' alt='' /></div> -</noScript> -<!-- SUDA_CODE_END --> - -<!-- SSO_GETCOOKIE_START --> -<script type="text/javascript">var sinaSSOManager=sinaSSOManager||{};sinaSSOManager.getSinaCookie=function(){function dc(u){if(u==undefined){return""}var decoded=decodeURIComponent(u);return decoded=="null"?"":decoded}function ps(str){var arr=str.split("&");var arrtmp;var arrResult={};for(var i=0;i<arr.length;i++){arrtmp=arr[i].split("=");arrResult[arrtmp[0]]=dc(arrtmp[1])}return arrResult}function gC(name){var Res=eval("/"+name+"=([^;]+)/").exec(document.cookie);return Res==null?null:Res[1]}var sup=dc(gC("SUP"));if(!sup){sup=dc(gC("SUR"))}if(!sup){return null}return ps(sup)};</script> -<!-- SSO_GETCOOKIE_END --> - -<script type="text/javascript">new function(r,s,t){this.a=function(n,t,e){if(window.addEventListener){n.addEventListener(t,e,false);}else if(window.attachEvent){n.attachEvent("on"+t,e);}};this.b=function(f){var t=this;return function(){return f.apply(t,arguments);};};this.c=function(){var f=document.getElementsByTagName("form");for(var i=0;i<f.length;i++){var o=f[i].action;if(this.r.test(o)){f[i].action=o.replace(this.r,this.s);}}};this.r=r;this.s=s;this.d=setInterval(this.b(this.c),t);this.a(window,"load",this.b(function(){this.c();clearInterval(this.d);}));}(/http:\/\/www\.google\.c(om|n)\/search/, "http://keyword.sina.com.cn/searchword.php", 250);</script> -<!-- body code end --> - - -<!-- ±³¾°js·ÅÖÃλ --> - - <!-- Í·²¿ bar begin --> - <div id="SI_Top_Wrap" class="top-nav-wrap"> - <div class="top-nav"> - <div class="tn-bg"> - <div class="tn-header"> - <div class="tn-nav"> - <div class="tn-title" node-type="sethome"> - <a href="javascript:;" class="tn-tab" suda-uatrack="key=index_new_menu&value=set_index"><i>ÉèΪÊ×Ò³</i> - </a> - </div> - <div class="tn-title" node-type="menu" style="display:none;"> - <a href="javascript:;" class="tn-tab"> - <i> - ÎҵIJ˵¥ - <span class="tn-arrow"> </span> </i> - </a> - <div style="display:none;" class="tn-topmenulist tn-topmenulist-a tn-topmenulist-a-menu" node-type="menuList"> - </div> - </div> - <div class="tn-title"> - <a target="_blank" href="http://tech.sina.com.cn/z/sinawap/" class="tn-tab" suda-uatrack="key=index_new_menu&value=sina_wap"><i>ÊÖ»úÐÂÀËÍø</i> - </a> - </div> - <div class="tn-title" node-type="client"> - <a target="_blank" class="tn-tab" suda-uatrack="key=index_new_menu&value=sina_apps_click"> <i>Òƶ¯¿Í»§¶Ë -<em class="tn-new tn-new2" style="display: none; /* display: inline-block; */"></em> - <span class="tn-arrow"> </span></i> </a> - <div style="display:none;" class="tn-topmenulist tn-topmenulist-a tn-topmenulist-a-client" node-type="clientList"> - <ul class="tn-text-list"> -<li><a target="_blank" href="http://m.sina.com.cn/m/weibo.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀË΢²©</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinahome.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÐÂÎÅ</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinasports.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÌåÓý</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinaent.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÓéÀÖ</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/finance.html" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀ˲ƾ­</a></li> - -<li><a target="_blank" href="http://m.sina.com.cn/m/weather.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÌìÆøͨ</a></li> - -<li><a target="_blank" href="http://games.sina.com.cn/o/kb/12392.shtml" suda-uatrack="key=index_new_menu&value=sina_apps_list_click">ÐÂÀËÓÎÏ·</a></li> - - </ul> - </div> - </div> - </div> - <div class="tn-close" node-type="close" style="display:none;"><a href="javascript:;"><i></i>¹Ø±ÕÖö¥</a></div> - <div class="tn-person-r" style="float:right;"> - <div class="tn-title tn-title-login" id="SI_Top_Login"> - <a href="javascript:;" class="tn-tab" suda-uatrack="key=index_new_menu&value=weibo_signin"><i>µÇ¼</i> - </a> - <!-- <span style="display:none;" class="tn-tab"> <i id="SI_Top_Login"></i> - </span> --> - - <div style="" class="tn-topmenulist tn-topmenulist-b" id="SI_Top_LoginLayer"> - </div> - </div> - <div class="tn-title" id="SI_Top_Logout" style="display:none;"> - <span class="tn-user"><i>»¶Ó­Äú£¬<a href="javascript:;" target="_blank" id="SI_Top_Nick"></a> - <a class="tn-logout" href="javascript:;" id="SI_Top_Logout_a">Í˳ö</a></i> - </span> - </div> - <div class="tn-title" id="SI_Top_Weibo"> - <a target="_blank" href="http://weibo.com/" class="tn-tab" suda-uatrack="key=index_new_menu&value=weibo_click"> <i>΢²© - <em class="tn-new" style="display:none;"></em> - <span class="tn-arrow"> </span></i> </a> - </div> - <div class="tn-title" id="SI_Top_Blog"> - <a target="_blank" href="http://blog.sina.com.cn" class="tn-tab" suda-uatrack="key=index_new_menu&value=blog_click"> - <i>²©¿Í - <em class="tn-new" style="display:none;"></em> - <span class="tn-arrow"> </span></i> </a> - </div> - <div class="tn-title" id="SI_Top_Mail"> - <a target="_blank" href="http://mail.sina.com.cn" class="tn-tab" suda-uatrack="key=index_new_menu&value=mail_click"> <i>ÓÊÏä - <em class="tn-new" style="display:none;"></em> - <span class="tn-arrow"> </span></i> </a> - </div> - <div class="tn-title" node-type="nav"> - <a target="_blank" href="http://news.sina.com.cn/guide/" class="tn-tab" suda-uatrack="key=index_new_menu&value=guide"> - <i>ÍøÕ¾µ¼º½</i> </a> - </div> - </div> - - </div> - </div> - - </div> - </div> - <!-- Í·²¿ bar end --> - - <!-- Í·²¿ËÑË÷ begin --> - <div class="top-search-wrap"> - <div class="top-search-frame clearfix" data-sudaclick="blk_topsearch"> - <a class="sina-logo" href="http://sina.com.cn"></a> - <div class="top-search clearfix"> - <form name="SearchEcho" onsubmit="return SearchSubmit()"> - <select style="display: none;" name="SerchType" id="slt_01" autocomplete="off"> - <option value="΢²©" selected="selected">΢²©</option> - <option value="ÐÂÎÅ">ÐÂÎÅ</option> - <option value="ͼƬ">ͼƬ</option> - <option value="²©¿Í">²©¿Í</option> - <option value="ÊÓƵ">ÊÓƵ</option> - </select> - <div class="sim-select clearfix" id="SI_Search_Type_Hack"> - <h3>΢²©</h3> - <div class="v-line"></div> - </div> - <!-- <h3>ÐÂÎÅ</h3> - <div class="v-line"></div> - <div class="sim-ul-flt" style="display:none;"> - <div class="sim-ul-bg"></div> - <ul style=""> - <li>ÐÂÎÅ</li> - <li>ͼƬ</li> - <li>΢²©</li> - <li>²©¿Í</li> - <li>ÊÓƵ</li> - </ul> - </div> --> -<div class="inp-txt-wrap"> - <input type="text" maxlength="40" value="ÇëÊäÈë¹Ø¼ü×Ö" name="SerchKey" class="inp-txt" onfocus="if(this.value=='ÇëÊäÈë¹Ø¼ü×Ö'){this.value='';this.className='inp-txt inp-txt-active'}" onblur="if(this.value==''){this.value='ÇëÊäÈë¹Ø¼ü×Ö';this.className='inp-txt'}" /> -</div> - <input type="submit" name="SearchSubButton" class="submit-second-btn" value="" onmouseover="this.className='submit-second-btn submit-second-btn-hover'" onmouseout="this.className='submit-second-btn'" suda-uatrack="key=index_new_search&value=search_click" /> - </form> - <div style="display:none"> - <!-- ÐÂÎÅ --> - <form name="hform_02" action="http://search.sina.com.cn/" method="get" target="_blank"> - <input type="hidden" name="range" value="all"> - <input type="hidden" name="c" value="news"> - <input type="hidden" name="q" value=""> - <input type="hidden" name="from" value="home"> - </form> - <!-- ÊÓƵ --> - <form action="http://search.sina.com.cn/" method="get" name="hform_03" target="_blank"> - <input name="c" type="hidden" value="video" /> - <input name="range" type="hidden" value="title" /> - <input type="hidden" name="q" value=""> - <input type="hidden" name="from" value="home"> - </form> - <!-- ͼƬ --> - <form action="http://search.sina.com.cn/" name="hform_05" target="_blank"> - <input type="hidden" name="q" value=""> - <input type="hidden" name="c" value="img"> - <input type="hidden" name="from" value="home"> - </form> - <!-- ²©¿Í --> - <form action="http://search.sina.com.cn/" name="hform_08" target="_blank"> - <input type="hidden" name="c" value="blog"> - <input type="hidden" name="from" value="home"> - <input type="hidden" name="q" value=""> - </form> - <!-- ֪ʶÈË --> - <form onsubmit="if(document.f.key.value==''){window.open('http://iask.sina.com.cn/');return false;};" target="_blank" name="hform_09" action="http://iask.sina.com.cn/search_engine/search_knowledge_engine.php"> - <input type="hidden" name="fsh_s"> - <input type="text" value="" name="key"> - </form> - <!-- ΢²© --> - <form name="hform_10" action="http://s.weibo.com/weibo/@@key@@" method="GET" target="_blank"> - <input type="hidden" name="Refer" value="sina_index"/> - </form> - </div> - </div> - - <div id="SI_Weather_Wrap" class="now-wea-wrap clearfix"></div> - <div id="nwsu_Wrap" class="nwsu_Wrap"> - <div class='nwsu-item'> - <a href="http://news.sina.com.cn/z/wljbxz/" class="nwsu" target="_blank"></a> - </div> - <div class='nwsu-item'> - <a href="http://jubao.china.cn:13225/reportform.do" class="nwsu2" target="_blank"></a> - </div> - <div class='nwsu-item'> - <a href="http://www.12377.cn/txt/2015-01/20/content_7622927.htm" class="nwsu3" target="_blank"></a> - </div> - </div> - <a href="http://news.sina.com.cn/pc/2014-10-30/326/3095.html" class="hxjzg" target="_blank"></a> - - </div> - </div> - <!-- Í·²¿ËÑË÷ end --> - - <script> - jsLoader({ - name: 'shm', - callback: function(){ - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "nwsu_Wrap"; //ÄÚÈÝÈÝÆ÷ID - focusScroll.frameWidth = 50;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 50; //·­Ò³¿í¶È - focusScroll.upright = true; //´¹Ö±¹ö¶¯ - focusScroll.speed = 50; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 5; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - - } - - }) - </script> - -<!--XstartX--> -<!--_SINA_ADS_BEGIN_--> -<!--±³¾°¹ã¸æ begin--> -<style type="text/css"> - #bgLeftAd, #bgRightAd { - overflow: hidden; - } -</style> -<div id="bgAdWrap"></div> -<script> - function Schedule(e){e="string"==typeof e?[e]:e||[],this.ranges=[];var t,n=0,r=e.length,i,s,o=new Date,u=o.getFullYear()+"/"+(o.getMonth()+1)+"/"+o.getDate();for(;n<r;n++)t=e[n].replace(/\-/g,"/").split("~"),i=t[0],s=t[1]?t[1]:t[0],i.indexOf(":")===-1&&(i+=" 0:0:0"),s.indexOf(":")===-1&&(s+=" 0:0:0"),i.indexOf("/")===-1&&(i=u+" "+i),s.indexOf("/")===-1&&(s=u+" "+s),i=+this.parse(i),s=+this.parse(s),s<=i&&(s+=864e5),this.ranges[n]=[i,s]}Schedule.prototype={check:function(e){var t=this.ranges,n=0,r,i=t.length<=0,e=e?+this.parse(e):+(new Date);while(!i&&(r=t[n++]))i=e>=r[0]&&e<=r[1];return i},parse:function(e){var t=new RegExp("^\\d+(\\-|\\/)\\d+(\\-|\\/)\\d+$");if("string"==typeof e){if(t.test(e)||isNaN(Date.parse(e))){var n=e.split(/ |T/),r=n.length>1?n[1].split(/[^\d]/):[0,0,0],i=n[0].split(/[^\d]/);return new Date(i[0]-0,i[1]-1,i[2]-0,r[0]-0,r[1]-0,r[2]-0)}return new Date(e)}return e}} - if (new Schedule('2015-06-18 9:00:00~2015-06-19 8:59:59').check()) { - _sinaadsCacheData = window._sinaadsCacheData || {}; - _sinaadsCacheData["PDPS00000000bg01"] = { - size: "1600*600", - type: "bg", - content: [ - { - src: ["http://d2.sina.com.cn/201506/17/1032094.jpg"], - monitor: [""], - link: ["http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjgwMA%3D%3D&sign=243d46f2a8d461df&url=http%3A%2F%2Fclk.gentags.net%2Fclk%2Fiv-1579%2Fst-23%2Fcr-2%2Foi-259958%2For-3950%2Fadv-403%2Fpcon-0%2Fhttp%3A%2F%2Fdc2.jd.com%2Fauto.php%3Fservice%3Dtransfer%26type%3Ddmp%26from%3Ddmp%26kid%3D436%26klid%3D51247%26to%3Dhttp%3A%2F%2Fsale.jd.com%2Fact%2FcwMpj4ytUFA.html"], - type: ["image"] - } - ], - id: "PDPS00000000bg01" - }; - } -</script> -<ins class="sinaads" data-ad-pdps="PDPS00000000bg01"></ins> -<script>(sinaads = window.sinaads || []).push({params: {"sinaads_ad_width": 1600, "sinaads_bg_top": 120, "sinaads_bg_asideClick": 1}});</script> - -<!--±³¾°¹ã¸æ end--> -<!--_SINA_ADS_END_--> -<!--XendX--> - - <!--ad begin--> - <!--XAD_STARTX--> - <!--_SINA_ADS_BEGIN_--> - <!--È«ÆÁ¿ªÊ¼ Îð¶¯--> - <script type="text/javascript">document.write('<span id="FullScreenWrap"></span>');</script> - <!--È«ÆÁ½áÊø Îð¶¯--> - <!--_SINA_ADS_END_--> - <!--XAD_ENDX--> - <!--ad end--> - - <!-- main begin --> - <div class="main"> - -<a href="#jump0" class="JumpTo"><img src="http://i0.sinaimg.cn/cha/images/c.gif" width="1" height="1" alt="Ìø¹ýµ¼º½À¸" /></a> - -<!-- NAV_BEGIN --> - - <div class="main-nav" data-sudaclick="blk_mainnav"> - <div class="nav-mod-1"> - <ul> - <li><a href="http://news.sina.com.cn/"><b>ÐÂÎÅ</b></a></li> - <li><a href="http://mil.news.sina.com.cn">¾üÊÂ</a></li> - <li><a href="http://news.sina.com.cn/society/">Éç»á</a></li> - </ul> - <ul> - <li><a href="http://finance.sina.com.cn/"><b>²Æ¾­</b></a></li> - <li><a href="http://finance.sina.com.cn/stock/">¹ÉƱ</a></li> - <li><a href="http://finance.sina.com.cn/fund/">»ù½ð</a></li> - </ul> - <ul> - <li><a href="http://tech.sina.com.cn/"><b>¿Æ¼¼</b></a></li> - <li><a href="http://mobile.sina.com.cn/">ÊÖ»ú</a></li> - <li><a href="http://tech.sina.com.cn/discovery/">̽Ë÷</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w"> - <ul> - <li><a href="http://sports.sina.com.cn/"><b>ÌåÓý</b></a></li> - <li style="width:36px;"><a href="http://sports.sina.com.cn/nba/">NBA</a></li> - <li><a href="http://sports.sina.com.cn/csl/">Öг¬</a></li> - </ul> - <ul> - <li><a href="http://ent.sina.com.cn/"><b>ÓéÀÖ</b></a></li> - <li style="width:36px;"><a href="http://ent.sina.com.cn/star/">Ã÷ÐÇ</a></li> - <li><a href="http://astro.sina.com.cn/">ÐÇ×ù</a></li> - </ul> - <ul> - <li><a href="http://auto.sina.com.cn/"><b>Æû³µ</b></a></li> - <li style="width:36px;"><a href="http://dealer.auto.sina.com.cn/price/">±¨¼Û</a></li> - <li><a href="http://data.auto.sina.com.cn/">Âò³µ</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w"> - <ul> - <li><a href="http://blog.sina.com.cn/"><b>²©¿Í</b></a></li> - <li style="width:36px;"><a href="http://zhuanlan.sina.com.cn/">רÀ¸</a></li> - <li><a href="http://weather.sina.com.cn/">ÌìÆø</a></li> - </ul> - <ul> - <li><a href="http://video.sina.com.cn/"><b>ÊÓƵ</b></a></li> - <li style="width:36px;"><a href="http://ent.sina.com.cn/zongyi/">×ÛÒÕ</a></li> - <li><a href="http://baby.sina.com.cn/">Óý¶ù</a></li> - </ul> - <ul> - <li><a href="http://house.sina.com.cn/"><b>·¿²ú</b></a></li> - <li style="width:36px;"><a href="http://esf.sina.com.cn/">¶þÊÖ·¿</a></li> - <li><a href="http://jiaju.sina.com.cn/">¼Ò¾Ó</a></li> - </ul> - </div> - <div class="nav-mod-1"> - <ul> - <li><a href="http://book.sina.com.cn/"><b>¶ÁÊé</b></a></li> - <li><a href="http://history.sina.com.cn/">ÀúÊ·</a></li> - <li><a href="http://photo.sina.com.cn/" >ͼƬ</a></li> - </ul> - <ul> - <li><a href="http://edu.sina.com.cn/"><b>½ÌÓý</b></a></li> - <li><a href="http://health.sina.com.cn/">½¡¿µ</a></li> - <li><a href="http://zhongyi.sina.com/">ÖÐÒ½</a></li> - </ul> - <ul> - <li><a href="http://fashion.sina.com.cn/"><b>ʱÉÐ</b></a></li> - <li><a href="http://eladies.sina.com.cn/">Å®ÐÔ</a></li> - <li><a href="http://collection.sina.com.cn/">ÊÕ²Ø</a></li> - </ul> - </div> - <div class="nav-mod-1"> - <ul> - <li><a href="http://city.sina.com.cn/"><b>³ÇÊÐ</b></a></li> - <li><a href="http://sh.sina.com.cn/">ÉϺ£</a></li> - <li id="SI_Nav_City"><a href="http://beijing.51xiancheng.com/">ÃÀʳ</a></li> - - </ul> - <ul> - <li><a href="http://travel.sina.com.cn/"><b>ÂÃÓÎ</b></a></li> - <li><a href="http://sky.news.sina.com.cn/">º½¿Õ</a></li> - <li><a href="http://news.auto.sina.com.cn/review/tujie/" suda-uatrack="key=index_www_drive&value=drive_click">ÊÔ¼Ý</a></li> - </ul> - <ul> - <li><a href="http://bbs.sina.com.cn/"><b>ÂÛ̳</b></a></li> - <li><a href="http://edu.sina.com.cn/gaokao/" style="color:red">¸ß¿¼</a></li> - <li><a id="navLinkShow" href="http://show.sina.com.cn/">SHOW</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w"> - <ul> - <li><a href="http://games.sina.com.cn/"><b>ÓÎÏ·</b></a></li> - <li style="width:36px;"><a href="http://qipai.sina.com.cn/">ÆåÅÆ</a></li> - <li><a href="http://wanwan.sina.com.cn/">Ò³ÓÎ</a></li> - </ul> - <ul> - <li><a href="http://fo.sina.com.cn/"><b>·ðѧ</b></a></li> - <li style="width:36px;"><a href="http://golf.sina.com.cn/">¸ß¶û·ò</a></li> - <li><a href="http://lottery.sina.com.cn/">²ÊƱ</a></li> - </ul> - <ul> - <li><a href="http://app.sina.com.cn/?f=p_dh&amp;w=p_dh"><b>Ó¦ÓÃ</b></a></li> - <li style="width:36px;"><a href="http://app.sina.com.cn/installs.php?f=p_dh&amp;w=p_dh">±Ø±¸</a></li> - <li><a href="http://www.97973.com/">ÊÖÓÎ</a></li> - </ul> - </div> - <div class="nav-mod-1 nav-w-2"> - <ul> - <li><a href="http://search.sina.com.cn/">ËÑË÷</a></li> - <li style="width:40px;"><a href="http://iask.sina.com.cn/">°®ÎÊ</a></li> - <li><a href="http://weibo.com/">΢²©</a></li> - </ul> - <ul> - <li><a href="http://finance.sina.com.cn/sf/">·¨Ôº</a></li> - <li style="width:40px;"><a href="http://help.sina.com.cn/index.php">¿Í·þ</a></li> - <li><a href="http://mail.sina.com.cn/">ÓÊÏä</a></li> - - </ul> - <ul> - <li><a href="http://gongyi.sina.com.cn/">¹«Òæ</a></li> - <li style="width:40px;"><a href="http://english.sina.com/">English</a></li> - <li><a href="http://news.sina.com.cn/guide/">µ¼º½</a></li> - </ul> - </div> - </div> - -<!-- NAV_END --> - -<a name="jump0"></a> - - <!-- Í·²¿¹ã¸æ begin --> - -<!--XstartX--> - <!--_SINA_ADS_BEGIN_--> - - <div class="top-ads"> - - <!-- ÀÖ¾Ó¶¥Í¨ÉÏÎÄ×ÖÁ´ begin--> - <div id="LejuText1" class="top-ads-list"></div> - <script> - try { - lejuMedia.then(function (data) { - leju.text("LejuText1", data, 8); - }); - } catch (e) {} - </script> - <!-- ÀÖ¾Ó¶¥Í¨ÉÏÎÄ×ÖÁ´ end--> - - <div class="top-ads-fwrap"> - -<!--_SINA_ADS_BEGIN_--> -<div id="ad_45825"><ins class="sinaads" data-ad-pdps="PDPS000000045825"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!--_SINA_ADS_END_--> - - </div> - - <!-- ÀÖ¾Ó¶¥Í¨ÏÂÎÄ×ÖÁ´ begin--> - <div id="LejuText2" class="top-ads-list"></div> - <script> - try { - lejuMedia.then(function (data) { - leju.text("LejuText2", data, 8); - }); - } catch (e) {} - </script> - <!-- ÀÖ¾Ó¶¥Í¨ÏÂÎÄ×ÖÁ´ end--> - - </div> - - <!--_SINA_ADS_END_--> -<!--XendX--> - - <!-- Í·²¿¹ã¸æ end --> - <div class="blank-cont" style="height:25px;"></div> - <!-- part-a begin --> - - <div class="part-a clearfix"> - <div class="part-a-l"> - <!-- mod01 --> - <div class="mod-01"> - <div tab-type="tab-wrap" class="tit01 clearfix"> -<ins class="sinaads" data-ad-pdps="lejuguding"></ins> -<script>(sinaads = window.sinaads || []).push({});</script> - </div> - <div class="palm01-ad"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x350 5ÂÖ²¥µØÓò¶¨Ïò°´Å¥¹ã¸æ begin --> -<div id="ad_45976" style="width:240px; height:350px;"><ins class="sinaads" data-ad-pdps="PDPS000000045976"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x350 5ÂÖ²¥µØÓò¶¨ÏòͨÀ¸¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - </div> - <!-- mod01 --> - <div class="blank-cont" style="height:10px;"></div> - <!-- mod02 --> - <div class="mod-02"> - <div class="tit02 clearfix"> - <h3><a href="http://m.sina.com.cn/" target="_blank">ÐÂÀ˲úÆ·</a></h3> - <!--<a href="#url" target="_blank" class="go-personal">µÇ¼ÎÒµÄרҳ</a>--> - </div> - <div class="mod02-cont" data-sudaclick="blk_sinaproduct"> -<!-- publish_helper name='ÐÂÀ˲úÆ·' p_id='30' t_id='123' d_id='1' --> - - <div class="mod02-cont-t clearfix"> -<a href="http://m.sina.com.cn/m/sinahome.shtml" target="_blank" class="pro"> -<img src="http://i3.sinaimg.cn/home/2014/0108/U4167P30DT20140108175729.png" alt="ÐÂÀËÐÂÎÅ" width="58" heigh="58"/> -<span>ÐÂÀËÐÂÎÅ</span> -</a> - -<a href="http://finance.sina.com.cn/mobile/comfinanceweb.shtml" target="_blank" class="pro"> -<img src="http://i1.sinaimg.cn/home/2013/1008/U8455P30DT20131008135420.png" alt="ÐÂÀ˲ƾ­" width="58" heigh="58"/> -<span>ÐÂÀ˲ƾ­</span> -</a> - -<a href="http://m.sina.com.cn/m/sinasports.shtml" target="_blank" class="pro"> -<img src="http://i1.sinaimg.cn/home/2013/0725/U1022P30DT20130725092340.png" alt="ÐÂÀËÌåÓý" width="58" heigh="58"/> -<span>ÐÂÀËÌåÓý</span> -</a> - </div> - - <div class="mod02-cont-t clearfix" style="background:none;"> - <ul class="mod02-cont-b clearfix"> - -<li><a target="_blank" href="http://m.sina.com.cn/m/sinaent.shtml">ÐÂÀËÓéÀÖ</a></li> -<li><a target="_blank" href="http://www.yixia.com/miaopai">ÐÂÀËÃëÅÄ</a></li> -<li><a href="http://m.sina.com.cn/m/weather.shtml" target="_blank">ÌìÆøͨ</a></li> - -<li style="width: 220px;"><a target="_blank" href="http://zhiyuan.edu.sina.com.cn/">¸ß¿¼Ö¾Ô¸Í¨£º×¨¼ÒÒ»¶ÔÒ»°ïÄ㱨־Ը</a></li> - - </ul> - </div> - - </div> - </div> - <!-- mod02 --> - <div class="blank-cont" style="height:10px;"></div> - -<!-- mod03 --> - -<div class="mod03" tab-type="tab-wrap" id="SI_EDU_AD"> - <div class="tit03 clearfix"> - <span class="selected" tab-type="tab-nav"><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjYzMg%3D%3D&sign=a1d07451b568829b&url=http%3A%2F%2Fembachinese.cb.cityu.edu.hk%2F2015%2F" target="_blank">½ÌÓý</a></span> - - <span tab-type="tab-nav"><a href="http://redirect.simba.taobao.com/rd?c=un&w=unionpost&f=http%3A%2F%2Fwww.taobao.com%2Fgo%2Fact%2Fmmbd%2Fhd-home.php%3Fpid%3Dmm_15890324_2192376_23736178%26unid%3D&k=b93d93a3e5c25156&p=mm_15890324_2192376_23736178" target="_blank">ÈÈÂô</a></span> - - <span action-type="tab" tab-type="tab-nav"><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjY2OA%3D%3D&sign=4ab24fcfe9c5f130&url=http%3A%2F%2Fwww.571.com%2Fshop%2Fhzt%2Findex.html%3Fname%3D971002" target="_blank">Á·×Ö</a></span> - - <span action-type="tab" tab-type="tab-nav" class="last-index"><a href="http://redirect.simba.taobao.com/rd?c=un&w=unionpost&f=http%3A%2F%2Fwww.taobao.com%2Fgo%2Fact%2Fmmbd%2Fhd-home.php%3Fpid%3Dmm_15890324_2192376_23736178%26unid%3D&k=b93d93a3e5c25156&p=mm_15890324_2192376_23736178" target="_blank">ÌÔ±¦</a></span> - </div> -<div class="mod03-cont" style="padding: 2px 0px 3px 0;"> -<!--ad begin--> -<!--½ÌÓýÎÄ×ÖÁ´ begin--> -<style type="text/css"> .ad_edu_list{width:238px; height:170px; overflow:hidden} -.ad_edu_list ul{padding-left:9px;margin:5px 0 0 0} -.list-b li{padding-left:10px;line-height:24px;height:24px;overflow:hidden;font-size: 12px;background:url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px;} -.list-b a:link{color:#666;text-decoration:none;} -.list-b a:visited{color:#666;text-decoration:none;} -.list-b a:hover,.list-b a:active{color:#ff8400;text-decoration:underline;} -.ad_edu_list .pic_text{height:115px; overflow:hidden;zoom:1; text-align:center} -.ad_edu_list .pic_text img{ display:inline; width:234px; height:115px;} -</style> - -<div class="ad_edu_list" tab-type="tab-cont" data-sudaclick="blk_eduad_1" style="" id="ad_edu_01"> - <ins class="sinaads" data-ad-pdps="PDPS000000052420"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<div class="ad_edu_list" tab-type="tab-cont" style="display: none;" data-sudaclick="blk_eduad_2" id="ad_edu_02"> - <ins class="sinaads" data-ad-pdps="PDPS000000052423"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<div class="ad_edu_list" tab-type="tab-cont" style="display: none;" data-sudaclick="blk_eduad_3" id="ad_edu_03"> - <ins class="sinaads" data-ad-pdps="PDPS000000052426"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<div class="ad_edu_list" tab-type="tab-cont" style="display: none;" data-sudaclick="blk_eduad_4" id="ad_edu_04"> - <ins class="sinaads" data-ad-pdps="PDPS000000052429"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</div> - -<script type="text/javascript" src="http://d3.sina.com.cn/d1images/edu_ad_change/edu_ad_change.js"></script> -<!--½ÌÓýÎÄ×ÖÁ´ end--> -<!--ad end--> -</div> -</div> - -<!-- mod03 --> - - </div> - <div class="part-a-m"> - <!-- mod04 --> - <div class="mod-04 uni-blk" tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <div id="xy-tabA"> - <span class="no-bl selected" tab-type="tab-nav" id="video-tab"><a href="http://video.sina.com.cn/" target="_blank">ÊÓƵ</a></span> - <span tab-type="tab-nav"><a href="http://ent.sina.com.cn/zongyi/" target="_blank">×ÛÒÕ</a></span> - <span tab-type="tab-nav"><a href="http://www.yixia.com/miaopai" target="_blank">ÃëÅÄ</a></span> - </div> - - <div id="xy-tabB" style="display: none;"> - <span class="no-bl selected" id="zhuanlan-tab"><a href="http://photo.sina.com.cn/" target="_blank">ͼƬ</a></span> - </div> - </div> - -<span class="t-guide t-guidechange"><a id="xy-change" href="javascript:;" style="text-decoration:none;outline:none!important;" suda-uatrack="key=www_update_div&value=change">»»Ò»»»</a></span> - -<span class="t-guide" style="_width:85px; _height:30px; _overflow:hidden;"><!-- publish_helper name='ýÍØ-ÊÓƵÍƹãλ' p_id='30' t_id='123' d_id='6' --> -<a target="_blank" href="http://slide.news.sina.com.cn/green/slide_1_28436_85594.html#p=1" suda-uatrack="key=mt_cor_exchange&value=www_hot_promt" class="linkRed">ºÏ·¨á÷ÁÔÒ°Éú¶¯Îï</a></span> - - <span id="SI_IP_MT_1" class="t-guide"></span> - </div> - <div class="uni-blk-b"> - <div tab-type="tab-cont" blkclick="auto_nav" blktitle="ÊÓƵ" id="xy-contA"> -<!-- publish_helper name='ÊÓƵÇø¿é-ÐÂÎÅ' p_id='30' t_id='99' d_id='1' --> -<div class="uni-blk-bt clearfix" data-sudaclick="blk_video_news"> -<a href="http://news.video.sina.com.cn/" target="_blank" class="uni-blk-pic uni-blk-bpic"> -<img src="http://i1.sinaimg.cn/dy/2015/0618/U10893P1DT20150618131148.jpg" width="125" height="119" /> -<i class="play-icon"></i> -<span>Ïã¸ÛÕþ¸Ä·½°¸Ôâ·ñ¾ö</span> -</a><ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138275365" class="videoNewsLeft">ÆØ̨·Æ´¬½¢ÄϺ£¶ÔÖÅ»¥ÇºÂ¼Òô</a></li> -<li><a target="_blank" href="http://news.sina.com.cn/zxt/#vid=138293926" class="videoNewsLeft">ÃÀ´óºà·Å¿ñÑÔ</a> <a target="_blank" href="http://news.sina.com.cn/zxt/#vid=138292678">ÎÀ±øײ¿ªÓοÍ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138293114" class="videoNewsLeft">ÀϺºÅ­ÂîÅ®º¢</a> <a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138278171">´óÊåÆ­½»15Å®</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138275633" class="videoNewsLeft">´åÃñ±»ÔþËÀ</a> <a target="_blank" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138276293">Ä¿»÷Õß¼éÕØÊÂÆÞ</a></li> - -</ul> - -<ul style="margin-top:0px;" class="uni-blk-list01 list-a"> -<li><a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://video.sina.com.cn/ent/?opsubject_id=top1#1-28-138292542-1" class="videoNewsLeft">µË³¬±»Æسö¹ì ËïٳĸÇ×·ñÈÏ</a></li> -</ul> -</div> - -<!-- publish_helper name='ÊÓƵÇø¿é-ÌåÓý' p_id='30' t_id='99' d_id='5' --> -<div class="uni-blk-bt clearfix" data-sudaclick="blk_video_sports"> -<a href="http://video.sina.com.cn/z/sports/k/nba/150617gswcle/" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U6589P30DT20150617163449.jpg" width="125" height="119" /> - <i class="play-icon"></i> - <span>ÓÂÊ¿¶áNBA×ܹھü</span> - </a> - -<ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138271581" class="linkRed videoNewsLeft">MVÖ¾´Õ²»Ê</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/#138285768">ÓÂÊ¿Åõ±­Ë²¼ä</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138270279" class="videoNewsLeft">ÒÁ¸ê´ïÀ­»ñFMVP</a> <a target="_blank" href="http://video.sina.com.cn/z/sports/nba/officialbest/2015-06-17/#138271443">G6Îå¼ÑÇò</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/o/o/v/2015-06-18/085665026599.html" class="videoNewsLeft">ůÄÐÇó»é¹Ç°©Å®ÓÑ</a> <a target="_blank" href=" http://video.sina.com.cn/p/sports/pl/v/2015-06-17/212165026515.html">272Ñ°»¶</a></li> -</ul> - -<ul style="margin-top:0px;" class="uni-blk-list01 list-a"> -<li><a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292564-1" class="videoNewsLeft videoNewsLeft">»ô˼Ñà×ÓÂôÃÈ</a> <a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://ent.sina.com.cn/bn/entreport/#138287174">¿ìÅ®»ÆÓ¢²úÅ®</a></li> -<li><a suda-uatrack="key=www_ent_video&value=click" target="_blank" href="http://video.sina.com.cn/ent/#1-28-138277171-1" class="videoNewsLeft">¿¹ÈÕÉñ¾çÔÙÏÖ£¡×ÔÐгµ·´ÎïÀí</a></li> - -</ul> -</div> - - <div class="blank-cont" style="height:8px;"></div> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <div> - <span class="no-bl selected"><a href="http://weibo.com/" target="_blank">΢²©Èȵã</a></span> - </div> - </div> - </div> - <div class="blank-cont" style="height:8px;"></div> - <ul class="uni-blk-list02 list-a" style="padding-top:0px;_zoom:1;" data-sudaclick="blk_weibohot"> -<!-- publish_helper name='΢²©Èȵã-ÓéÀÖ' p_id='30' t_id='100' d_id='9' --> -<li><a suda-uatrack="key=index_weibohot&value=ent_link" href="http://weibo.com/1270492934/CmWhwaGeE?c=spr_wbprod_sina_lsywrd_weibo_t001" target="_blank" class="videoNewsLeft">ÁõÒà·ÆÖ÷ÑÝ¡¶ÈýÉúÈýÊÀ¡·</a> <a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmQCI9GjQ?c=spr_wbprod_sina_lsywrd_weibo_t001">µÚ3´ÎÔ¼»áVSµÚ30´ÎÔ¼»á</a></li> -<li><a suda-uatrack="key=index_weibohot&value=ent_link" href="http://weibo.com/1270492934/CmOnT4U8d?c=spr_wbprod_sina_lsywrd_weibo_t001" target="_blank" class="videoNewsLeft">ÕûÈ˲»³É·´±»Õû</a> <a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmR1nD7vX?c=spr_wbprod_sina_lsywrd_weibo_t001">Ê·ÉÏ×î´ó·Åƨ×øµæ×÷ÕߺÍËûµÄè</a></li> - -<li><a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmNcaokzU?c=spr_wbprod_sina_lsywrd_weibo_t001" class="videoNewsLeft">Âí±óÉæ×ß˽ÏãṈ̃»·£»ºÐÌ</a> <a suda-uatrack="key=index_weibohot&value=ent_link" target="_blank" href="http://weibo.com/1270492934/CmN4QfeRu?c=spr_wbprod_sina_lsywrd_weibo_t001">Àî°½Åú²ÌÒÀÁÖ×Ô³Æ&quot;ÀÏÄï&quot;</a></li> - -<!-- publish_helper name='΢²©Èȵã-ÊÓƵ' p_id='30' t_id='99' d_id='10' --> -<li><a suda-uatrack="key=index_weibohot&value=video_link" target="_blank" href="http://weibo.com/1640601392/CiJg49RAb?from=page_1002061640601392_profile&wvr=6&mod=weibotime&type=comment#_rnd1433228255488?c=spr_wbprod_sina_lsywrd_weibo_t001" class="videoNewsLeft">ÐÂÎÅÖÐÐÄÕÐƸÊÓƵ±à¼­</a> <a suda-uatrack="key=index_weibohot&value=video_link" target="_blank" href="http://weibo.com/1640601392/Cn0VgssR2?from=page_1002061640601392_profile&wvr=6&mod=weibotime&type=comment#_rnd1434554197838?c=spr_wbprod_sina_lsywrd_weibo_t001">³ÕÇéÄÐÏò»¼°©Å®Óѹ«¿ª±í°×</a></li> - -<!-- publish_helper name='΢²©Èȵã-΢²©' p_id='30' t_id='101' d_id='24' --> -<li><a target="_blank" href="http://weibo.com/1638781994/CclWdbgud??c=spr_wbprod_sina_lsywrd_weibo_t001">ÃɵÙÂÔÈÎÒâÇò±¬Éä</a> <a target="_blank" href="http://weibo.com/1638781994/Ccme9pTdD??c=spr_wbprod_sina_lsywrd_weibo_t001">ÀÉÕ÷ÍÆÞú¶ÔÊÖȾºì</a> <a target="_blank" href="http://weibo.com/1638781994/CcbVStX6Z??c=spr_wbprod_sina_lsywrd_weibo_t001">ÁõÏè10´ó¾­µä±ÈÈü</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_video_2" blkclick="auto_nav" blktitle="×ÛÒÕ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='×ÛÒÕÇø¿é' p_id='30' t_id='99' d_id='2' --> -<div class="uni-blk-bt clearfix"><a href="http://ent.sina.com.cn/f/z/foodmap2014/?opsubject_id=enttopnews" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i2.sinaimg.cn/home/2015/0612/U7647P30DT20150612113029.jpg?opsubject_id=enttopnews" width="125" height="119" /> - <i class="play-icon"></i> - <span>°×¾Ù¸Ùº°Äã»Ø¼Ò³Ô»ð¹ø</span> - </a> - <ul class="uni-blk-list01 list-a"> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-06-07/152465019495.html?opsubject_id=enttopnews" target="_blank">ͯÄêÔÙ¼û£¡¶­ºÆ×ÔÆØÃ÷ÄêÍËÐÝ</a></li> - -<li><a class="videoNewsLeft" href="http://ent.sina.com.cn/f/v/idolbb/?opsubject_id=enttopnews" target="_blank">°®¶¹±§±§:ÕÅÒÕÐËÂôÃÈ10Á¬ÅÄ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/zznzh2015/?opsubject_id=enttopnews#138254478" target="_blank">ÕæÄУºÔ¬ºëÅ®ÓÑÉúÈճɿ¼Ìâ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/bpbxd2/?opsubject_id=enttopnews#138241243" target="_blank">ÅÜÄУºÆæÅ®»ô˼Ñà±æʶÁ¦¾ªÈË</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/heysn2/?opsubject_id=enttopnews#138246497" target="_blank">»¨ÉÙ£º´ó½ãë°¢Ãô×í¾ÆÈ°ºÍ</a></li> -</ul></div> - -<div class="uni-blk-bt clearfix"><a href="http://video.sina.com.cn/p/ent/h/2015-06-07/230265019557.html?opsubject_id=enttopnews" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i1.sinaimg.cn/home/2015/0608/U5910P30DT20150608131810.jpg?opsubject_id=enttopnews" width="125" height="119" /> - <i class="play-icon"></i> - <span>Àּΰ®Í½ÐÄÇкȾƱ¬´Ö</span> - - </a> - <ul class="uni-blk-list01 list-a"> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/bbhll2/?opsubject_id=enttopnews#138246029" target="_blank">°Ö»Ø£ºÌðÜ°¼ÖÄËÁÁ±§Ð¡ÖíÇ«ÈÃ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/jxtz/?opsubject_id=enttopnews#138266584" target="_blank">¼«ÏÞÌôÕ½£ºÂÞÖ¾Ïé¿ñÇ׻Ʋ³</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/letusfallinlove/?opsubject_id=enttopnews#138250541" target="_blank">Ïà°®°É£ºÐìè´ÔâÇÇÈÎÁºÀäÂä</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/FightForYou/?opsubject_id=enttopnews#138249941" target="_blank">ΪËý£ºÕŽú¸ò󡹦Á¦¿Ë½Òã</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-06-16/112965025283.html?opsubject_id=enttopnews" target="_blank">°Ö°Ö£ººú¾ü½ÌÓý¶ù×Ó´ôÃÈ¿É°®</a></li> - -</ul></div> - - <ul class="uni-blk-list02 list-a" style="padding-top:0px;"> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-05-29/121264999605.html" target="_blank">Öйú˵Íõ¸ÕΪÔüÄбç½â</a> <a target="_blank" class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-06-12/093465022617.html">³ö·¢°É£ºÎ⾩ÔâÌßÒªº¦</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/vlist/ent/qclxs2015/#138223277" target="_blank">Á·Ï°ÉúÄáÀ¤³öôܼ±º°cut</a> <a target="_blank" href="http://ent.sina.com.cn/z/v/2015-06-05/doc-icrvvqrf4155141.shtml" class="videoNewsLeft">Ç°Íù£º´óÕÅΰÍ˳ö¼ÖÆ</a></li> - -<li><a href="http://video.sina.com.cn/p/ent/z/v/2015-06-12/143365023029.html" target="_blank" class="videoNewsLeft">³ø·¿£ºÐ»ÒÀÁرùÏä²Ø·¢Ã¹Ãæ°ü</a> <a target="_blank" href="http://ent.sina.com.cn/f/yydsk2015/video/#138188727" class="videoNewsLeft">´óʦ¿ÎÊÕ¹ÙÀá±ð</a></li> - -<li><a class="videoNewsLeft" href="http://ent.sina.com.cn/music/zy/2015-06-08/doc-icrvvpkk8085950.shtml" target="_blank">ÐǶ¯£ºÕÅÓÓºÕÖؽð¼ÓÃË</a> <a href="http://video.sina.com.cn/p/ent/z/y/2015-05-29/105064998767.html" target="_blank" class="videoNewsLeft">Å©¸è»á£º·ï»Ë´«ÆæÆðÄÚÚ§</a></li> - -<li><a class="videoNewsLeft" href="http://ent.sina.com.cn/z/v/2015-06-04/doc-icrvvrak2674989.shtml" target="_blank">ÄÐ×󣺳½ÒàÈåÁµÉÏmissAö­</a> <a href="http://ent.sina.com.cn/z/v/2015-05-27/doc-icpkqeaz5759787.shtml" target="_blank" class="videoNewsLeft">ºÃÉú»îÍô¶«³ÇÐãÈËÆø</a></li> - -<li><a class="videoNewsLeft" target="_blank" href="http://video.sina.com.cn/p/ent/z/v/2015-06-03/164265017077.html">ϲ¾çÈË£º¼ÖÁáÌìÆøÎè×ߺì</a> <a href="http://video.sina.com.cn/p/ent/z/v/2015-05-28/174264998501.html" target="_blank" class="videoNewsLeft">ÎÄѧÎâéÐ͵ѧÒ׽</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/p/ent/z/v/2015-02-12/094064615627.html" target="_blank">°ÙÍò·ÛË¿:ÃÍÄбäÎäÃÄÄï</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/z/v/2015-02-12/093664615613.html">ÐìÁ¢ÈüÇ°¶·×ì½âѹ</a> <a target="_blank" href="http://bwfs.ent.sina.com.cn">[רÌâ]</a></li> - - </ul> - </textarea> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_miaopai" blkclick="auto_nav" blktitle="ÃëÅÄ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÃëÅÄÇø¿é' p_id='30' t_id='139' d_id='1' --> - -<div class="uni-blk-bt clearfix"><a href="http://www.miaopai.com/stpid/aarcPc9gLhgSBOG6" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i0.sinaimg.cn/home/2015/0618/U10743P30DT20150618135844.jpg" width="125" height="119" /> - <i class="play-icon"></i> - <span>ǧçôÍþÎ俳Öñ×Ó</span> - </a> - <ul class="uni-blk-list01 list-a" src="http://i1.sinaimg.cn/home/2014/0129/U6864P30DT20140129155635.png" width="125" height="119"><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/nEN15S95IEFWVi66" target="_blank">Óöµ½ÕâÖÖŮ˾»ú ½»¾¯ÏÅÄòÁË</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/b3lFPW~cmd-kBFs9" target="_blank">ÕÔÀöÓ±¸ã¹ÖÁ·½£ ¹ÇÍ·ÃÈÃÈßÕ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/u/paike_ox2ha5f4e8" target="_blank">Ö£ÈݺÍÉîÒ¹·¢¸£Àû£¡Äã˯ÁËÂð</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/ZA1byjvzhBN9vRgf" target="_blank">ÄË°ÖÌðÜ°·­ÅÆÀ² ÐÒÔ˶ùÊÇË­</a></li><li><a target="_blank" class="videoNewsLeft" href="http://www.miaopai.com/u/paike_jzn3v9su6z">¡¶Ìý˵¡·³ÂÒ⺭Ï×ÎÇÅíÓÚêÌ</a></li></ul></div><div class="uni-blk-bt clearfix"><a href="http://www.miaopai.com/stpid/3VQ9X7inkrYeyXXa" target="_blank" class="uni-blk-pic uni-blk-bpic"> - <img src="http://i2.sinaimg.cn/home/2015/0618/U6864P30DT20150618101538.jpg" width="125" height="119" /> - <i class="play-icon"></i> - <span>ɱÂíÌØÐÇÈËÈëÇÖµØÇò</span> - </a> - <ul class="uni-blk-list01 list-a"><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/2TR647rsz8rgbjDQ" target="_blank">Âòµ¥ÆæÝâÊ£¡±ÈлÄÈÐÄÑÛ¶¼¶à</a></li><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/s-Xw8YePp5aYOSFm" target="_blank">ÄãÀÏÆÅ×óÐØÉÏÓÐÒ»¿ÅÖÒÐÄðë</a></li><li><a target="_blank" class="videoNewsLeft" href="http://www.miaopai.com/stpid/ThfMEy~6RVHrmzEH">Éñ´ð¸´£¡ÀÏÆÅÀÏÂèͬʱµôË®Àï</a></li><li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/oSCfo4vtFqDoEflm" target="_blank">Õâô¼úµÄµ¥Éí¹·»¹ÊǵÚÒ»´Î¼û</a></li><li><a href="http://www.miaopai.com/stpid/9znqWYLW1OiztxwP" target="_blank" class="videoNewsLeft">±¯´ß½á¾Ö£¡³¤µÃ³óµÄÖ»ÄÜÌøºÓ</a></li></ul></div> - - <ul class="uni-blk-list02 list-a"> -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/LagWWnMprKoSY5hy" target="_blank">À¸Ä¿|²»¿Þ²»¿Þ£¡µ¥Éí¹·µÄÐÄÉù</a> <a target="_blank" href="http://www.miaopai.com/stpid/uERliqBn4-qe~Pme">FBIÐèÒªÕâÑùµÄÖ¤ÈË</a></li><li><a href="http://www.miaopai.com/stpid/8oeM7a8HeGecge-j" target="_blank" class="videoNewsLeft">ÃÀÅ®|ÏòÅ®ÉñÌôÕ½¶·¼¦ÑÛ</a> <a target="_blank" href="http://www.miaopai.com/stpid/f19CgVnucvYangB9">Å®ÉúÒ»Ö±¶¼ÏëÎÊÄÐÉúµÄÎÊÌâ</a></li> - -<li><a class="videoNewsLeft" target="_blank" href="http://www.miaopai.com/stpid/Ur5e9dqIfRfKSaPd">¸ãЦ|ÃÀÅ®·´ÊÖÃþ¶ÇÆ걯²Òϳ¡</a> <a target="_blank" href="http://www.miaopai.com/stpid/r1KCvHL0IfB8jukL">ÏàÇ××îÏÔÄêÇáµÄ´©×Å</a></li> - -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/C~ZB36vCSNeRQYd~" target="_blank">¶º±È|ĪÃû¾Í¸ú×ÅàËÆðÀ´</a> <a href="http://www.miaopai.com/stpid/dYe3fR4-MoaVRO3W" target="_blank">ÈÃÄã×°±Æ£¬ÕâÏÂÔÔÁË°É£¡</a></li> - -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/gvrsBrSqzUQrZe18" target="_blank">Å£ÈË|OMG£¬ÕâÌáËÙÀÏÏÅÈËÁË</a> <a href="http://www.miaopai.com/stpid/gQHG7lU6~sA8Za1f" target="_blank">µõÕ¨Ìì¿áìÅ»¨Ê½×ÔÐгµ</a></li> - -<li><a target="_blank" href="http://www.miaopai.com/stpid/CrlNWE3Ivi3rBN6m" class="videoNewsLeft">Ãȳè|µ±¿Â»ùÁµÉϾµÍ·¿É°®Êº</a> <a target="_blank" href="http://www.miaopai.com/stpid/WcvbfzYcra55SEYE">¼ô¸öÍ··¢È¥ºÍС»¨Ô¼»á</a></li> - -<li><a class="videoNewsLeft" href="http://www.miaopai.com/stpid/acbl3g7vu9ObTui7" target="_blank">Ãȱ¦|³¬ÃÈÂÜÀòÏòÂèÂèÈÏ´í</a> <a target="_blank" href="http://www.miaopai.com/stpid/PeHdrfLW732suvnS">±¦±´ÑÝʾ³Ô»õµÄ×î¸ß¾³½ç</a></li> - </ul> - </textarea> - </div> - -<div id="xy-contB" class="xy-contB" style="display:none;"> - - <div blkclick="auto_nav" blktitle="ͼƬ" id="fc_B_pic"> -<!-- publish_helper name='ÒªÎÅ-ͼƬ' p_id='30' t_id='97' d_id='11' --> -<div class="uni-blk-bt clearfix" data-sudaclick="blk_photo1"> - -<a class="uni-blk-pic" target="_blank" href="http://slide.news.sina.com.cn/s/slide_1_2841_85574.html" style=""> - <img width="105" height="70" src="http://i1.sinaimg.cn/home/2015/0618/U7676P30DT20150618085819.jpg" /> -<span>Å®×Ó±»ÂãÉíËøÌúÁý</span>></a> -<a class="uni-blk-pic" target="_blank" href="http://slide.news.sina.com.cn/s/slide_1_2841_85573.html" style="margin-left:19px;"> - <img width="105" height="70" src="http://i2.sinaimg.cn/home/2015/0618/U7676P30DT20150618094919.jpg" /> -<span>Ä¿»÷ÕßÇÃÕ©ÔâÅ×ʬ</span>></a> - -<a class="uni-blk-pic" target="_blank" href="http://slide.photo.sina.com.cn/" style="margin-left:19px;"> - <img width="105" height="70" src="http://i2.sinaimg.cn/home/2015/0618/U7676P30DT20150618082703.jpg" /> -<span>ËûÓëÍæż¹²¶ÈÓàÉú</span> -</a> - -</div> - -<ul class="uni-blk-list02 list-a" style="padding-top:7px; _zoom:1;" data-sudaclick="blk_photo2"> -<li><a class="photoNewsLeft" href="http://slide.news.sina.com.cn/c/slide_1_2841_85577.html" target="_blank">½­ËÕÁ¬½µ±©ÓêÃñÖÚµ­¶¨»®´¬</a> <a target="_blank" href="http://slide.news.sina.com.cn/c/slide_1_2841_85581.html">¹¤ÈËÔâ»îÂñ±»Í½ÊÖÅÙ³ö</a></li> - -<li><a target="_blank" href="http://slide.news.sina.com.cn/w/slide_1_2841_85587.html" class="photoNewsLeft">·ÇÖÞСÕò¡°¹úÍõ¡±È¢°ÙλÆÞ×Ó</a> <a target="_blank" href="http://slide.news.sina.com.cn/s/slide_1_2841_85578.html">16ËêÉÙÅ®±»ËøľÎÝ5Äê</a></li> - - <li><a href="http://slide.news.sina.com.cn/s/slide_1_2841_85586.html" target="_blank" class="photoNewsLeft">Å®º¢×ß·ÍæÊÖ»úÏÝÏÂË®µÀ</a> <a target="_blank" href="http://slide.sports.sina.com.cn/k/slide_2_57057_83550.html">µã½«:Àú½ìNBA×ܾöÈüFMVP</a></li> - -</ul> - -<!-- publish_helper name='ÒªÎÅ-ͼƬ-ʱÉÐ' p_id='30' t_id='110' d_id='10' --> -<ul class="uni-blk-list02 list-a" data-sudaclick="blk_photo_fashion"> -<li><a class="photoNewsLeft" target="_blank" href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24709.html">ÕæÈËÐãÅ®ÐÇÉè¼ÆÓ¾×°ÅÄ´óƬ</a> <a target="_blank" href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24711.html">̨Íå°Ù´óÃÀÅ®°ñ³ö¯</a></li> -</ul> - - <div id="fc_B_pic_attachment" style="display:none;"> - <div class="uni-blk" tab-type="tab-wrap" style="z-index:1"> - <div class=""> - <div class="uni-blk-t mod24-t clearfix"> - <div class="mod24-menu clearfix" id="picBNav"> - <span class="selected" tab-type="tab-nav" style="border-left:0px;width:70px;" data-picb-uaTrack="news_show"><a href="http://slide.news.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=news_click">ÐÂÎÅ</a></span> - <span tab-type="tab-nav" style="width:72px;" data-picb-uaTrack="sports_show"><a href="http://slide.sports.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=sports_click">ÌåÓý</a></span> - <span tab-type="tab-nav" style="width:72px;" data-picb-uaTrack="ent_show"><a href="http://slide.ent.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=ent_click">ÓéÀÖ</a></span> - <span tab-type="tab-nav" style="width:70px;" data-picb-uaTrack="fashion_show"><a href="http://slide.fashion.sina.com.cn/?choice=1" target="_blank" suda-uatrack="key=index_wwwb_photo&value=fashion_click">ʱÉÐ</a></span> - <span tab-type="tab-nav" style="border-right:0px;width:70px;" data-picb-uaTrack="photo_show"><a href="http://photo.sina.com.cn/" target="_blank" suda-uatrack="key=index_wwwb_photo&value=photo_click">ͼÓï</a></span> - </div> - </div> - <div class="uni-blk-b" style="padding-top:0;"> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" data-sudaclick="blk_bpic_news"> -<a href="http://slide.news.sina.com.cn/s/slide_1_2841_85340.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0612/U10611P30DT20150612170157.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Î赸ϵһ×ÖÂíÕÕ</span> - </a><a href="http://slide.news.sina.com.cn/w/slide_1_2841_85339.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U10611P30DT20150612170227.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÄÐ×ÓÌæÅ®ÓѸ߿¼</span> - </a><a href="http://slide.news.sina.com.cn/w/slide_1_2841_85348.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0612/U10611P30DT20150612170302.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Å®ÇôÕùµ±¡°Óü»¨¡±</span> - </a><a href="http://slide.news.sina.com.cn/s/slide_1_2841_85338.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U7676P30DT20150612171058.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¸ß¿¼Éú˺ÃûÅÆ×¹Íö</span> - </a><a href="http://slide.news.sina.com.cn/w/slide_1_2841_85375.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U10611P30DT20150612170335.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¹·¹·ÌæÖ÷È˵²³µ»ö</span> - </a><a href="http://slide.news.sina.com.cn/s/slide_1_2841_85345.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0612/U10611P30DT20150612170425.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¿¼À­±§ÂèÂè×öÊÖÊõ</span> - </a> - - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_sports"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.sports.sina.com.cn/n_n/slide_2_789_83473.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0617/U6604P30DT20150617095905.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÈÕ±¾0-0мÓÆÂ</span> - </a><a href="http://slide.sports.sina.com.cn/g/slide_2_57057_83224.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0612/U4003P30DT20150612153638.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÃÀÖÞ±­Ì«Ì«ÍÅPK</span> - </a><a href="http://slide.sports.sina.com.cn/k/slide_2_57057_83550.html" target="_blank"> - <img src="http://i3.sinaimg.cn/home/2015/0618/U6604P30DT20150618095418.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Àú½ìNBAFMVP</span> - </a><a href="http://slide.sports.sina.com.cn/g/slide_2_730_83492.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0617/U6604P30DT20150617095501.jpg" /> - <span class="fc-bpac-bg"></span> - <span>°¢¸ùÍ¢1-0ÎÚÀ­¹ç</span> - </a><a href="http://slide.sports.sina.com.cn/n/slide_2_789_83486.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U6604P30DT20150617095656.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ýÌå¾Û½¹ÄÐ×ãÅ®×ã</span> - </a><a href="http://slide.sports.sina.com.cn/n_n/slide_2_789_83474.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U6604P30DT20150617095759.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÊÀÔ¤Èü¹ú×ã6-0</span> - </a> - - </textarea> - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_ent"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.ent.sina.com.cn/film/w/slide_4_704_112238.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0618/U2520P30DT20150618110711.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÁõÒà·ÆÉîVÀñȹÍÑË×</span> - </a><a href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112281.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0618/U2520P30DT20150618110730.jpg" /> - <span class="fc-bpac-bg"></span> - <span>³¬Ä£ÀÙË¿ÄÚÒÂÐã</span> - </a><a href="http://slide.ent.sina.com.cn/star/slide_4_704_112272.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0618/U2520P30DT20150618110743.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Öܶ¬Óê»ú³¡ÐãÃÀÍÈ</span> - </a><a href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112263.html" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0618/U2520P30DT20150618110803.jpg" /> - <span class="fc-bpac-bg"></span> - <span>¿ËÀÍð¥Å®¶ùÑÕÖµ¸ß</span> - </a><a href="http://slide.ent.sina.com.cn/film/h/slide_4_704_112268.html" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0618/U2520P30DT20150618110836.jpg" /> - <span class="fc-bpac-bg"></span> - <span>÷ÒÌÐÂƬÔìÐ͸´¹Å</span> - </a><a href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112278.html" target="_blank"> - <img src="http://i3.sinaimg.cn/home/2015/0618/U2520P30DT20150618110857.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÄÝ¿É·ÛûĨÔÈÁ³»¨</span> - </a> - - </textarea> - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_fashion"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60785.html" target="_blank"> - <img src="http://i1.sinaimg.cn/fashion/2015/0617/U5790P1503DT20150617111820.jpg" /> - <span class="fc-bpac-bg"></span> - <span>·¶±ù±ù˯ÒÂÉÏ·âÃæ</span> - </a><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60673.html" target="_blank"> - <img src="http://i2.sinaimg.cn/fashion/2015/0617/U5790P1503DT20150617111821.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ѧËýÃÇÓÅÑÅ´©ÉîV</span> - </a><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60780.html" target="_blank"> - <img src="http://i2.sinaimg.cn/fashion/2015/0617/U5790P1503DT20150617111821_1.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÖÜѸ»éºóÔìÐÍ·´¹¥</span> - </a><a href="http://slide.eladies.sina.com.cn/news/slide_3_65868_24172.html" target="_blank"> - <img src="http://i0.sinaimg.cn/lx/old2013/photo/idx/2015/0304/U6929P8T440D1F14806DT20150304145841.jpg" /> - <span class="fc-bpac-bg"></span> - <span>ÖìÀò¾ÉÕÕÌðËÆÃÛ</span> - </a><a href="http://slide.eladies.sina.com.cn/news/slide_3_65868_24181.html" target="_blank"> - <img src="http://i3.sinaimg.cn/lx/old2013/photo/idx/2015/0305/U6929P8T440D1F14806DT20150305145059.jpg" /> - <span class="fc-bpac-bg"></span> - <span>±´Â³ÆæÃÀÕÕÅ̵ã</span> - </a><a href="http://slide.eladies.sina.com.cn/news/slide_3_65868_24189.html" target="_blank"> - <img src="http://i2.sinaimg.cn/lx/old2013/photo/idx/2015/0306/U6929P8T440D1F14806DT20150306142910.jpg" /> - <span class="fc-bpac-bg"></span> - <span>Ó¾×°ÃÀÅ®ÐԸбÈÆ´</span> - </a> - - </textarea> - </div> - <div class="fc-B-pic-a-cont clearfix" tab-type="tab-cont" style="display:none;" data-sudaclick="blk_bpic_photo"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<a href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60818.html#p=1" target="_blank"> - <img src="http://i2.sinaimg.cn/home/2015/0617/U12708P30DT20150617113306.png" /> - <span class="fc-bpac-bg"></span> - <span>¸¸Ç×½ÚΪ°Ö°Ö×ö²Ë</span> - </a><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60816.html#p=1" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0617/U12708P30DT20150617113812.png" /> - <span class="fc-bpac-bg"></span> - <span>³¬¼¶¸ßÌú</span> - </a><a href="http://photo.auto.sina.com.cn/tuji/18245#53204155" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0617/U12708P30DT20150617142050.png" /> - <span class="fc-bpac-bg"></span> - <span>M135i ¶¯Á¦ÅìÅÈ</span> - </a><a href="http://photo.auto.sina.com.cn/tuji/18258#53273179" target="_blank"> - <img src="http://i0.sinaimg.cn/home/2015/0617/U12708P30DT20150617142302.png" /> - <span class="fc-bpac-bg"></span> - <span>°ÂµÏS7 È«ÃæÉý¼¶</span> - </a><a href="http://slide.news.sina.com.cn/green/slide_1_28436_85564.html#p=1" target="_blank"> - <img src="http://i1.sinaimg.cn/home/2015/0617/U12708P30DT20150617140521.png" /> - <span class="fc-bpac-bg"></span> - <span>ÐÜÂèÂè½ÌСÐܲ¶ÁÔ</span> - </a><a href="http://slide.baby.sina.com.cn/other/slide_10_846_28238.html#p=1" target="_blank"> - <img src="http://i3.sinaimg.cn/home/2015/0617/U12708P30DT20150617141854.png" /> - <span class="fc-bpac-bg"></span> - <span>ÒòΪÉÙÅ®ËùÒÔͯÄê</span> - </a> - - </textarea> - </div> - - </div> - </div> - </div> - </div> - - </div> - -<!-- - <div tab-type="tab-cont" style="display:none"> -{miaopai_ÃëÅÄÇø¿éB°æ} - </div> ---> - - <div class="blank-cont" style="height:13px;"></div> - - <div tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <span tab-type="tab-nav" class="no-bl selected"><a href="http://video.sina.com.cn/news/" target="_blank" suda-uatrack="key=www_yaowen&value=video">ÊÓƵ</a></span> - <span tab-type="tab-nav"><a href="http://www.yixia.com/miaopai" target="_blank">ÃëÅÄ</a></span> - </div> - </div> - <div class="blank-cont" style="height:13px;"></div> -<div tab-type="tab-cont"> - <div class="videoLeftC" data-sudaclick="blk_videopic"> -<!-- publish_helper name='ÓéÀÖÊÓƵͼ' p_id='30' t_id='100' d_id='13' --> -<a class="uni-blk-pic uni-blk-pic-c" target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292542-1"> - <img width="105" height="60" src="http://i1.sinaimg.cn/home/2015/0618/U7647P30DT20150618100655.jpg" /> - <i class="vid-play-icon"></i> -<span>µË³¬±»Æسö¹ì</span> -</a> - -<!-- publish_helper name='ÌåÓýÊÓƵͼ' p_id='30' t_id='101' d_id='22' --> -<a class="uni-blk-pic uni-blk-pic-c" target="_blank" href=" http://video.sina.com.cn/p/sports/g/v/2015-06-18/103965026697.html"> - <img width="105" height="60" src="http://i2.sinaimg.cn/home/2015/0618/U8059P30DT20150618104559.jpg" /> - <i class="vid-play-icon"></i> -<span>ÄÚÂí¶ûÌßÈËȾºì</span> -</a> - </div> - <ul class="list-a videonewsList" data-sudaclick="blk_videonews"> -<!-- publish_helper name='ÒªÎÅ-ÊÓƵ' p_id='30' t_id='99' d_id='13' --> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/#138278331" target="_blank">±í¾öÏÖ³¡-Ïã¸ÛÕû¸Ä·½°¸Ôâ·ñ¾ö</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138275365" target="_blank">̨Íå·ÆÂɱöÄϺ£¶ÔÖżÒôÆعâ</a></li> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138293926" target="_blank">ÃÀ×ÜͳºòÑ¡È˳öλÑÔÂÛ¶ºÐ¦Ö÷²¥</a></li> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138292174" target="_blank">¾ª´ô£¡¿¹ÈÕÉñ¾ç×ÔÐгµ¾ø¼¼À×ÈË</a></li> -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138293324" target="_blank">ÈÕ±¾²ñÈ®±äÉíÐÂÎÅÖ÷²¥ÂôÃȲ»¶Ï</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138293114" target="_blank">¼àÅÄÀϺº¹«½»ÉÏקŮº¢Âî15·ÖÖÓ</a></li> - -<li><a class="videoNewsLeft" href="http://video.sina.com.cn/news/spj/topvideoes20150618/?opsubject_id=top1#138278171" target="_blank">´óÊåÓÕ15´óѧÉúÆ­²ÆÉ«Í¥Éϱç½â</a></li> - - </ul> -</div> - - <div tab-type="tab-cont" style="display:none;"> -<!-- publish_helper name='ÃëÅÄÇø¿éB°æ' p_id='30' t_id='139' d_id='3' --> -<div class="videoLeftC" data-sudaclick="blk_miaopaipic"><a class="uni-blk-pic uni-blk-pic-c" target="_blank" href="http://www.miaopai.com/stpid/n1qzlQ72ZEcXZiRK"> - <img width="105" height="60" src="http://i0.sinaimg.cn/home/2015/0617/U10743P30DT20150617120246.jpg" /> - <i class="vid-play-icon"></i> - <span>Âòµ¥Óöµ½µÄÞÏÞÎÊÂ</span> - </a> - <a class="uni-blk-pic uni-blk-pic-c" target="_blank" href="http://www.miaopai.com/stpid/-p7W09VBG4SbXt60"> - <img width="105" height="60" src="http://i0.sinaimg.cn/home/2015/0618/U10743P30DT20150618112557.jpg" /> - <i class="vid-play-icon"></i> - <span>´øÌðÜ°È¥º£±ßÍæË£</span> - </a></div><ul class="list-a videonewsList" data-sudaclick="blk_miaopainews"><li><a class="videoNewsLeft" href="http://www.miaopai.com/show/nQJye~rg7zaegsCVPW981w__.htm" target="_blank">³ÉÁú²»ÐÅ·¶±ù±ùÓÐÄÐÓѲ»ÖªÀ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/kRqHb1NbxONo0lBm3ah3dQ__.htm" target="_blank">ÑîÑó²ÝµØÂôÃÈ×ö¸öÓÇÓô˧ÆøÐÍÄÐ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/rf0TXZRw9d-P6a3K1TqbDg__.htm" target="_blank">¸çÃDZð˵ÄãÊǼûÒåÓÂΪű»´òËÀ</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/TnLH-hEeMPMXOuSw4Az4xw__.htm" target="_blank">ÄÐÅóÓѵİ®³Æ°µ²ØÐþ»úСÐı»Æ­</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/IA4PhaElSwYI7TOhUw9aYw__.htm" target="_blank">ЦÅç!¹âÍ·Ç¿ºÍ¶þ¹·×ÓµÄÑóÎñÔ˶¯</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/~0CNpooVCgC2yBAEpBDfDQ__.htm" target="_blank">ÀÏÆÅÓÎÏ·Ö»ÄܶþÑ¡Ò»Äã»áÔõô×ö</a></li> - <li><a class="videoNewsLeft" href="http://www.miaopai.com/show/mDMTFA0eF5f6kx-EsPcNFw__.htm" target="_blank">µ±ÐֵܵıðÇî×·²»Éá¸ø¸ǫ̈½×ÏÂ</a></li></ul> - </div> - </div> - - </div> - - </div> - </div> - <!-- mod04 --> - <div class="blank-cont" style="height:19px;"></div> - <!-- mod05 --> - <div class="mod-05 uni-blk mod-guess" id="SI_Order_Guess" tab-type="tab-wrap" tab-data="touch=0"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span tab-type="tab-nav" id="SI_Guess_span" class="no-bl selected clearfix"> - <em>²ÂÄãϲ»¶</em> - <span class="mod-guess-control" id="SI_Guess_Control" style="display:none;"><a class="mod-guess-prev" href="javascript:;" title="ÉÏÒ»Ö¡" id="SI_Guess_Prev" hidefocus="true">ÉÏÒ»Ö¡</a><span class="mod-guess-dots" id="SI_Guess_Dots"></span><a class="mod-guess-next" href="javascript:;" title="ÏÂÒ»Ö¡" id="SI_Guess_Next" hidefocus="true">ÏÂÒ»Ö¡</a></span> - </span> - -<!-- -<span tab-type="tab-nav" id="SI_channel_show_span" class=" " style=""><em><a href="http://edu.sina.com.cn/gaokao/" target="_blank">2015¸ß¿¼</a></em></span> ---> - -<!-- -<span tab-type="tab-nav" id="SI_channel_show_span2" class=" " style=""><em><a href="http://huodong.weibo.com/qiche/" target="_blank">»¶ÀÖ¹º³µ¼¾</a></em></span> ---> - - <span tab-type="tab-nav" id="SI_WEIBORecommend_span" class=" " style=""><em>ÈÈÃÅ»°Ìâ</em></span> - - </div> - <a id="SI_Guess_Login_Btn" class="weibo-login" title="ÇëÓÃ΢²©Õ˺ŵǼ£¬²ÂÄãϲ»¶ÍƼöЧ¹û¸üºÃ£¡" href="javascript:;">µÇ¼΢²©Ð§¹û¸ü¼Ñ</a> - </div> - <div class="mod05-cont SC_Order_Fix_Cont" > - <div tab-type="tab-cont"> - <div id="SI_Guess_Wrap" data-sudaclick="blk_guess" class="mod-guess-cont" page-length="5" list-length="8" item-length="24"> - <p class="loading"></p> - </div> - </div> - -<!-- - <div tab-type="tab-cont" style='display:none'> -edu_2015¸ß¿¼ - </div> ---> -<!-- - <div tab-type="tab-cont" style='display:none'> -{auto_ÉϺ£³µÕ¹} - </div> ---> - <div tab-type="tab-cont" style='display:none'> - <div id="SI_WEIBORecommend_Wrap" data-sudaclick="blk_weibohottopic" class="mod-weiboGuess-cont" page-length="16" list-length="8" item-length="24"> - <p class="loading"></p> - </div> - </div> - - <div style="border-bottom:1px solid #e9e9e9;"> - <style type="text/css"> - /*.list-a-ad li{background: none;} - Ô­µãÑùʽ - .list-a-ad a:link,.nmod01 a:visited{color:#596a7b;} - Á´½ÓÑÕÉ« - */ - </style> - - <ul class="list-a list-a-ad" data-sudaclick="blk_mt_tg"> -<!-- publish_helper name='ýÍØ-²ÂÄãϲ»¶°å¿éÍƹã' p_id='30' t_id='123' d_id='7' --> -<li> - -<a target="_blank" href="http://auto.sina.com.cn/2015-06-16/detail-ifxczqap4176884.shtml">4¿î¸ßÆ·ÖʺÀ»ª³µÍƼö</a> <a target="_blank" href="http://photo.auto.sina.com.cn/tuji/18268">ÇÀÏÈʵÅÄÎÖ¶ûÎÖXC90 80ÍòÆðÊÛ</a></li> - </ul> - </div> - -<!--Ͷ×ʺ£µí begin--> - <div class="nmod01" data-sudaclick="blk_ad_tzhd" style="border-top:0px;"> - <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjE2MA%3D%3D&sign=74df9fa89934325d&url=http%3A%2F%2Finvest.bjhd.gov.cn%2F" target="_blank">Ͷ×ʺ£µí</a> | <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjE5NA%3D%3D&sign=423b0ef0acbb446d&url=http%3A%2F%2Fwww.zhsp.gov.cn%2F" target="_blank">Öйشå¹ú¼Òʾ·¶Çø</a> <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjE2MQ%3D%3D&sign=8835c2fd4467a441&url=http%3A%2F%2Finvest.bjhd.gov.cn%2Fzctx%2F" target="_blank">º£µíÇø1+4+1Õþ²ßÌåϵ</a> - </div> -<!--Ͷ×ʺ£µí begin--> - </div> - -<script> -/* ÈÈÃÅ»°Ì⡢ƵµÀ°å¿éËæ»úÏÔʾ */ - -/* -var fortab_random = parseInt(2*Math.random()); - if (fortab_random == "1"){ - document.getElementById("SI_WEIBORecommend_span").style.display = ""; - document.getElementById("SI_channel_show_span").style.display = "none"; - //document.getElementById("SI_channel_show_span2").style.display = "none"; - } - if (fortab_random == "0"){ - document.getElementById("SI_WEIBORecommend_span").style.display = "none"; - document.getElementById("SI_channel_show_span").style.display = ""; - //document.getElementById("SI_channel_show_span2").style.display = ""; - } -*/ -</script> - - </div> - <!-- mod05 --> - - </div> - <div class="part-a-r"> - <!-- mod06 --> - <div tab-type="tab-wrap" class="mod-06 uni-blk" id="wwwidx_imp_con"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - - <span tab-type="tab-nav" class="no-bl selected"><a href="http://news.sina.com.cn/" target="_blank" suda-uatrack="key=www_yaowen&value=news">ÐÂÎÅ</a></span> - <span tab-type="tab-nav" id="SI_IP_Tab_Nav_1" style="display:none;"></span> - -<span id="xy-imptabtp-A" style="padding:0; margin-top:0px;"> -<span class="order-menu-lnk" ><a target="_blank" href="http://photo.sina.com.cn/" suda-uatrack="key=www_yaowen&value=photo">ͼƬ</a></span> -<span class="order-menu-lnk" ><a target="_blank" href="http://zhuanlan.sina.com.cn/" suda-uatrack="key=www_yaowen&value=zhuanlan">רÀ¸</a></span> -</span> - -<div id="xy-imptabtp-B" style="display:none;"> -</div> - - </div> - -<span class="t-guide">2015.6.18</span> - - </div> - <div tab-type="tab-cont" class="mod06-cont" data-sudaclick="blk_news_all" blkclick="auto_nav" blktitle="ÒªÎÅ"> - <div class="blank-cont" style="height:20px"></div> - -<div id="xy-impcon-A"> -<!-- publish_helper name='ÒªÎÅ-ÐÂÎÅ' p_id='1' t_id='850' d_id='1' --> -<ul class="list-a" id="syncad_0" data-sudaclick="blk_news_0"> -<!--Ö±´ïÍ·ÌõλÖñê¼Ç--> -<!--ÿÐв»³¬¹ý25¸ö×Ö--> - -<li><a target="_blank" href="http://news.sina.com.cn/c/p/2015-06-17/231431962078.shtml">Ï°½üƽ¸ßËÙ·ÅÔ¿´³¬ÊРѯÎÊʳƷ±£ÖÊÆÚ</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/221831962034.shtml">ÏçÇ×Çé</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/162731961377.shtml">×ùÓÒÃú</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/191631961826.shtml">Àî¿ËÇ¿£º»¹ÓÐ1ÒÚ¶àÈËÉú»îÔÚÅﻧÇø ²»½â¾öºÎ̸¹«Æ½</a></li> - -<li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/175831961619.shtml">ÇÇʯÒÅÌåÖÜÎå»ð»¯Ìì°²ÃÅÏ°ëÆì</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/185531961733.shtml" >ÄÄЩÁìµ¼ÈËÊÅÊÀ½µÁËÆì</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/222731962040.shtml">ÐÂÀËÃñµ÷£º¹ÕÂô¶ùͯӦ¸ÃÒ»ÂÉÅÐËÀÐÌÂð£¿</a></li> - -<li><a href="http://news.sina.com.cn/c/2015-06-18/111031964858.shtml" target="_blank">Ò»¼üֱͨÖмÍί£¡»¶Ó­ÓÃÊÖ»úÅÄÉã¾Ù±¨¹«¿î³ÔºÈ</a></li> - -</ul> - -<div class="blank-d" style="height:10px"></div> -<ul class="list-a" id="syncad_1" data-sudaclick="blk_news_1"> - -<li><span class="fe661"><a target="_blank" href="http://news.sina.com.cn/china/">¹úÄÚ</a> | </span><a href="http://news.sina.com.cn/c/2015-06-18/100531964553.shtml" target="_blank">¹úÎñÔº£º7ÔÂÆð ̨°ûÀ´Íù´ó½ÃâÇ©</a> <a href="http://news.sina.com.cn/c/2015-06-18/124531965111.shtml" target="_blank">ÈçºÎ°ìÀí</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/120231965030.shtml">Èý²¿ÃÅ£ºÈ«ÃæÇåÀí¡°ÄãÂèÊÇÄãÂ衱µÈÆæÝâÖ¤Ã÷</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/131131965167.shtml">Ïã¸ÛÕþ¸Ä·½°¸ÔâÁ¢·¨»á·ñ¾ö</a></li> - -<li ><a target="_blank" href="http://finance.sina.com.cn/stock/jsy/20150618/142822466818.shtml">»¦Ö¸ÌøË®µøÓâ2%´´Òµ°å±©µø½ü5%</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/143722466876.shtml">½»Í¨ÒøÐб©µøÓâ8%</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/094031964472.shtml">102ËêÃñ¹ú²ÅÅ®ÕųäºÍÈ¥ÊÀ ºÏ·ÊËĽãÃóɾøÏì(ͼ)</a></li> - -<li><a href="http://news.sina.com.cn/c/2015-06-18/115131965018.shtml" target="_blank">ºÚÁú½­Í¨±¨¼Í¼ì¹ÙÔ±±»Î§Å¹ÖÂËÀ°¸:·¿²úÉ̲߻®</a></li> - -<li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/110231964841.shtml">¹ã¶«ÎªÇÀ¾Èº«¹úMERS»¼Õß15Ì컨µôÓâ800Íò</a></li> - -<li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/121231965051.shtml">¶­Ã÷Ö飺¹¤Ð½½×²ãÄêÊÕÈë10ÍòÔªÒÔϲ»Òª½»Ë°</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/c/z/dzzgr/">[ÖйúζÈ]</a><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/023331962458.shtml">ĸÇ×¼á³Ö258Ì콫ֲÎïÈËÅ®¶ù»½ÐÑ(ͼ)</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/zxt/#vid=138292678" class="videoNewsLeft">ÐÂÀË×ÊѶ̨£ºÏÖ³¡-ÓοÍÎóÈëÓ¢»Ê¼ÒÎÀ±ø¶ÓÁб»×²¿ª</a></li> - -<li><span class="fe661"><a href="http://zhuanlan.sina.com.cn/" target="_blank" suda-uatrack="key=index_column_click&value=click">רÀ¸</a></span> | <a target="_blank" href="http://zhuanlan.sina.com.cn/" suda-uatrack="key=index_column_click&value=click">ÈË··×ÓÒ»ÂÉËÀÐ̺ݻ°¹ý·ÖÂð</a> <a target="_blank" href="http://news.sina.com.cn/zl/zatan/2015-06-18/12353905.shtml" suda-uatrack="key=index_column_click&value=click">Íâ¹ú·¨ÂÉÈçºÎ³ÍÈË··</a></li> - -</ul> -<ul class="list-a" id="syncad_2" data-sudaclick="blk_news_2"> - -<li><span class="fe661"><a target="_blank" href="http://news.sina.com.cn/world/">¹ú¼Ê</a> | </span><a href="http://news.sina.com.cn/w/2015-06-18/075931964140.shtml" target="_blank" >·ÆÂɱö³öÏÖáÂî¿ÖÏÅÔÚ·ÆÖйú¹«Ãñ¼£Ïó</a></li> - -</ul> -</div> - -<div id="xy-impcon-B" class="xy-impcon-B" style="display:none;"> - <ul class="list-a" id="syncad_0_B" data-sudaclick="blk_news_0_B"> - <li><a target="_blank" href="http://news.sina.com.cn/c/p/2015-06-17/231431962078.shtml">Ï°½üƽ¸ßËÙ·ÅÔ¿´³¬ÊРѯÎÊʳƷ±£ÖÊÆÚ</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/221831962034.shtml">ÏçÇ×Çé</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/162731961377.shtml">×ùÓÒÃú</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/191631961826.shtml">Àî¿ËÇ¿£º»¹ÓÐ1ÒÚ¶àÈËÉú»îÔÚÅﻧÇø ²»½â¾öºÎ̸¹«Æ½</a></li><li ><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/175831961619.shtml">ÇÇʯÒÅÌåÖÜÎå»ð»¯Ìì°²ÃÅÏ°ëÆì</a> <a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/185531961733.shtml" >ÄÄЩÁìµ¼ÈËÊÅÊÀ½µÁËÆì</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-17/222731962040.shtml">ÐÂÀËÃñµ÷£º¹ÕÂô¶ùͯӦ¸ÃÒ»ÂÉÅÐËÀÐÌÂð£¿</a></li><li><a href="http://news.sina.com.cn/c/2015-06-18/111031964858.shtml" target="_blank">Ò»¼üֱͨÖмÍί£¡»¶Ó­ÓÃÊÖ»úÅÄÉã¾Ù±¨¹«¿î³ÔºÈ</a></li><li><span class="fe661"><a target="_blank" href="http://news.sina.com.cn/china/">¹úÄÚ</a> | </span><a href="http://news.sina.com.cn/c/2015-06-18/100531964553.shtml" target="_blank">¹úÎñÔº£º7ÔÂÆð ̨°ûÀ´Íù´ó½ÃâÇ©</a> <a href="http://news.sina.com.cn/c/2015-06-18/124531965111.shtml" target="_blank">ÈçºÎ°ìÀí</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/120231965030.shtml">Èý²¿ÃÅ£ºÈ«ÃæÇåÀí¡°ÄãÂèÊÇÄãÂ衱µÈÆæÝâÖ¤Ã÷</a></li><li><a target="_blank" href="http://news.sina.com.cn/c/2015-06-18/131131965167.shtml">Ïã¸ÛÕþ¸Ä·½°¸ÔâÁ¢·¨»á·ñ¾ö</a></li> - </ul> - - <div class="blank-cont" style="height:13px;"></div> - - <div tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://zhuanlan.sina.com.cn/" target="_blank">רÀ¸</a></span> -<!-- - <span tab-type="tab-nav" ><a href="http://weibo.com/" target="_blank">΢²©</a></span> ---> - </div> - </div> - - <div class="blank-cont" style="height:13px;"></div> - - <ul class="list-a" id="syncad_1_B" tab-type="tab-cont" data-sudaclick="blk_zhuanlan"> - <li><a target="_blank" href="http://finance.sina.com.cn/zl/management/20150618/112722465771.shtml">оýÈçºÎÕÆ¿ØȨÁ¦£¿</a> <a target="_blank" href="http://finance.sina.com.cn/focus/ggwd_zxy">Ò»´øһ·²»Äܱ§×ÅÕü¾ÈËûÈ˵ÄÐÄ̬</a> </li> -<li><a target="_blank" href="http://cul.history.sina.com.cn/zl/shiye/2015-06-15/15021153.shtml">²Â¶¡¿Ç£ºÓÎÏ·ÌåÏֵġ°¹«Æ½¡±</a> <a target="_blank" href="http://cul.history.sina.com.cn/zl/redian/2015-06-15/17491154.shtml">´Ó¸ß¿¼×÷ÎÄÈ«¹ú¾í˵¿ªÈ¥</a></li> -<li><a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/i/2015-06-18/pid_8481226.htm">360˽Óл¯ÊÇΪ»ØA¹ÉȦǮÂð</a> <a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/it/2015-06-18/pid_8481223.htm">Oculus£ºÐÂÒ»´úÔ¼ÅÚÉñÆ÷£¿</a></li> -<li><a href="http://ent.sina.com.cn/zl/" target="_blank">ÂÞÖ¾ÏéÍøºìл¶ÕûÈݾÉÕÕÁ³´ó</a><a href="http://ent.sina.com.cn/zl/bagua/blog/2015-06-16/15383552/1243021947/4a17027b0102vkcq.shtml" target="_blank"> 47ËêÅ®ÉñÕÅÃô¶Ì·¢Ã²ÃÀ</a></li> -<li><a href="http://sports.sina.com.cn/zl/basketball/2015-06-17/zldoc-ifxczqap4207893.shtml" target="_blank">ÑîÒã:ÓÂʿʱ´ú¿âÀïÔڵȴý</a> <a href="http://sports.sina.com.cn/zl/football/2015-06-17/zldoc-ifxczyze9659633.shtml" target="_blank">ÃÏ·±´ï:ÄÐ×ã×î´óѹÁ¦ÊÇÅ®×ã</a></li> -<li><a href="http://fashion.sina.com.cn/zl/fashion/2015-06-17/14423786.shtml" target="_blank">ûÊÂÒµÂí¼×Ïßզѡ±È»ùÄá</a> <a href="http://fashion.sina.com.cn/zl/fashion/2015-06-17/17063791.shtml" target="_blank">Ì©ÀÕ˹Íþ·òÌؽÖÅÄм¼ÄÜget</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/zl/edu/2015-06-17/10492798.shtml">Ê®´ó¸ßнÐÐÒµ</a> <a target="_blank" href="http://edu.sina.com.cn/zl/edu/blog/2015-06-17/10272797/1594826071/5f0f1d570102vp0j.shtml">»ªÅ©Ð£»¨Å®Íõ·¶(ͼ)</a> <a target="_blank" href="http://edu.sina.com.cn/zl/oversea/blog/2015-06-16/11102796/2771745342/a5357a3e0102vv45.shtml">ÄãÔÚÃÀ¹úÄÜÕõ¶àÉÙÇ®</a></li> - </ul> - -<!-- - <ul tab-type="tab-cont" class="uni-blk-list02 list-a" style="padding-top:0px;_zoom:1;display: none;" data-sudaclick="blk_weibo_1"> -{weibo_΢²©} - </ul> ---> - - </div> - -</div> - - <div class="blank-cont" style="height:13px"></div> - <ul class="list-a" id="syncad_3" data-sudaclick="blk_topfinance_1"> -<!-- publish_helper name='ÒªÎÅ-²Æ¾­' p_id='30' t_id='98' d_id='1' --> -<li><span class="fe661"><a href="http://finance.sina.com.cn/" target="_blank">²Æ¾­</a> | </span> <a target="_blank" href="http://finance.sina.com.cn/china/20150618/093122464500.shtml ">5ÔÂ20³Çз¿¼Û¸ñ»·±ÈÉÏÕÇ ÉîÛÚÕÇ·ù×î¸ß(¸½±í)</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/gsnews/20150618/052622464290.shtml">мÓÆÂÏòÖйú±¬ÁÏÑëÆó¾³ÍâÊÜ»ß ÄϺ½Á½Ô±¹¤»ñÐÌ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/gsnews/20150618/010922459366.shtml">ÑëÆó²©ÞÄ£º¡°Âò·½Â¢¶ÏÖÐÌú×Ü¡±µ£ÐÄÖгµ·´×ª»°ÓïȨ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/stock/level2/orderIntro.html" class="linkRed">ÐÂÀ˲ƾ­Ê×ÍƸ߶˰æA¹ÉÐÐÇé Äê·Ñ998Ôª</a> <a target="_blank" href="http://finance.sina.com.cn/focus/i300/" class="linkRed">i300Ö¸»ùÇÀ¹ºÖÐ</a></li> - - </ul> - <ul class="list-a" data-sudaclick="blk_tophouse_1"> -<!-- 13:16:46 --> -<li><a href="http://news.leju.com/" target="_blank">Íò¿Æ¸ß¹ÜÔٶȵ÷Õû</a> <a href="http://bj.house.sina.com.cn/news/2015-06-18/13006017163671862817221.shtml" target="_blank">ÊÀ½çO2O´ó»áºØÒúÓî̸Òƶ¯»¥Áª</a></li> - - </ul> - <ul class="list-a" id="syncad_4" data-sudaclick="blk_toptech_1"> -<!-- publish_helper name='ÒªÎÅ-¿Æ¼¼' p_id='30' t_id='103' d_id='1' --> -<li><span class="fe661"><a href="http://tech.sina.com.cn/" target="_blank">¿Æ¼¼</a> | </span><a href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxefurt9344968.shtml" target="_blank">Ê¢´óÓÎϷ˽Óл¯²ÆÍÅÔÙÉú±ä£ºÖÐÒøÈÞÒµÒâÍâ³ö¾Ö</a></li> - -<li><a href="http://tech.sina.com.cn/it/2015-06-17/doc-ifxefurq6045451.shtml" target="_blank">΢ÈíÖØ×é¹ÜÀí²ã£ºÅµ»ùÑÇÇ°CEO°£ÂåÆÕ½«ÀëÖ°</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-18/doc-ifxefurt9354794.shtml">ÎÒÃǵĴóÄÔ¿Õ¼ä»á±»ÓÃÍêÂð?</a> <a href="http://slide.tech.sina.com.cn/d/slide_5_453_60863.html" target="_blank">ÏÖʵ°æ±äÐνð¸Õ¼¸Ãë±äÆû³µ</a></li> - </ul> - <ul class="list-a" data-sudaclick="blk_topd_1"> -<!-- publish_helper name='ÒªÎÅ-ÔËÓª' p_id='30' t_id='123' d_id='2' --> -<li><span class="fe661"><a href="http://fashion.sina.com.cn/" target="_blank">ʱÉÐ</a> | </span> -<a href="http://fashion.sina.com.cn/" target="_blank">Áõ¼ÎÁáºÍÅ®ÍõÈ¥¿´ÂíÁË</a> -<a href="http://slide.fashion.sina.com.cn/m/slide_24_66132_60867.html" target="_blank">ÑîÃݸßÔ²Ô²°×T³¬´óÅÆ</a></li> - </ul> - - <ul class="list-a" data-sudaclick="blk_topd_2"> -<li> -<span class="fe661">Èȵã | </span> -<ins class="sinaads" data-ad-pdps="PDPS000000046154"></ins><script>(sinaads = window.sinaads || []).push({});</script> - <!--µØÓò¶¨ÏòÎÄ×ÖÁ´ begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000045978"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<!--µØÓò¶¨ÏòÎÄ×ÖÁ´ end--> -</li> - -<li> -<span class="fe661">¹Ø×¢ | </span> -<ins class="sinaads" data-ad-pdps="PDPS000000045979"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<ins class="sinaads" data-ad-pdps="PDPS000000045980"></ins><script>(sinaads = window.sinaads || []).push({});</script> -</li> - -<li> -<span class="fe661"><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDgzMg%3D%3D&sign=c1466af9aee00db5&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fguanzhu1%2F%3Ftel%3D1%26src%3D0001" target="_blank">±Ø¿´</a> | </span> -<a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDgzMg%3D%3D&sign=c1466af9aee00db5&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fguanzhu1%2F%3Ftel%3D1%26src%3D0001" target="_blank">2ÕÐ,ÈÃʧÃßÈË˯¸öºÃ¾õ</a> -<a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwMjk1NQ%3D%3D&sign=4f57cb0d7cc05f97&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fguanzhu-2a%2F" target="_blank">½ÒÃØ:ÌÇÄò²¡-ÕæÕý¸ùÔ´</a> -</li> - - </ul> - - </div> - <div tab-type="tab-cont" id="SI_IP_Tab_Cont_1" class="mod06-cont" style="display:none;" data-sudaclick="blk_topcity_1" blkclick="auto_nav" blktitle="µØ·½Õ¾"> - </div> - - </div> - <!-- mod06 --> - </div> - </div> - <!-- part-a end --> - -<!-- ÒªÎÅÇø¶¨Ïò¹ã¸æ´úÂë --> -<!-- nosmb begin --> -<script language="javascript" type="text/javascript"> -(function() { - function addEvent(obj, eventType, func) { - if(obj.attachEvent) { - obj.attachEvent("on" + eventType, func); - } else { - obj.addEventListener(eventType, func, false); - } - }; - - function attachURL2Window(id,url) { - var links; - try { - links = document.getElementById(id).getElementsByTagName("a"); - }catch(e) { - links = []; - } - for (var i = 0, len = links.length; i < len; i++) { - addEvent(links[i], "mousedown", function(e) { - var writeCookie = function(O, o, l, I, p) { - var i = "", - c = "", - path = ""; - if (l != null) { - if(l == "NaN"){ - i = ";"; - }else{ - i = new Date((new Date).getTime() + l * 3600000); - i = "; expires=" + i.toGMTString(); - } - }; - if (I != null) { - c = ";domain=" + I - }; - if(p != null){ - path = ";path=" + p; - }; - document.cookie = O + "=" + escape(o) + i + c + path; - }; - writeCookie("directAd","true",1,".sina.com.cn","/"); - //µã»÷¼à²â - var _clickStat = new Image(); - _clickStat.src = url + "&_=" + new Date().getTime() + "&url="; - }); - } - }; - - attachURL2Window("syncad_1","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,533936,539210&cid=0,0,0&sid=540113&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_2","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,534288,539558&cid=0,0,0&sid=540487&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_3","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,534289,539559&cid=0,0,0&sid=540488&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_4","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,539990,545264&cid=0,0,0&sid=546428&advid=358&camid=69129&show=ignore"); - attachURL2Window("syncad_0","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,547080,552353&cid=0,0,0&sid=553716&advid=358&camid=69129&show=ignore"); - - attachURL2Window("syncad_0_B","http://sina.allyes.com/main/adfclick?db=sina&bid=372535,547080,552353&cid=0,0,0&sid=553716&advid=358&camid=69129&show=ignore"); - -})() -</script> -<!-- nosmb end --> -<!-- ÒªÎÅÇø¶¨Ïò¹ã¸æ´úÂë --> - - <div class="blank-cont" style="height:20px;"></div> - - <!-- pageload firstpage --> - -<script src="http://i.sso.sina.com.cn/js/ssologin.js"></script> - -<!-- ABban --> -<script> - jsLoader({ - name: 'shm', - url: 'http://www.sina.com.cn/js/index/96/0801/shm.js' - }); - - // ÐÞ¸Ä 5 begin -jsLoader({ - name: 'shm', - callback: function () { - var sguid = SHM.util.cookie.getCookie('SINAGLOBAL'); - if (typeof sguid == 'string') { - lastNum = sguid.charAt(sguid.length - 1, 1); - if (lastNum == '6') { - var timer1 = null; - var pic_utils = { - $: function (id) { - return document.getElementById(id); - }, - fixEvent: function (e) { - var e = e || win.event; - e.target = e.target ? e.target : e.srcElement; - return e; - }, - delegateByTag: function(ele,tag,etype,fn){ - var that = this; - that.addEvent(ele,etype,function(ev){ - var e = that.fixEvent(ev); - var t = e.target; - tag = tag.toLowerCase(); - do { - if(t.nodeName && t.nodeName.toLowerCase() === tag){ - fn(e, t); - } - t = t.parentNode; - } while (t && t !== ele) - }); - }, - addEvent: document.addEventListener ? - function (elem, type, fn) { - elem.addEventListener(type, fn, false); - } : function (elem, type, fn) { - elem.attachEvent('on' + type, fn); - }, - removeEvent: document.removeEventListener ? - function (elem, type, fn) { - elem.removeEventListener(type, fn, false); - } : function (elem, type, fn) { - elem.detachEvent('on' + type, fn); - } - }; - var bPicArea = pic_utils.$('fc_B_pic'), - bPicAttachment = pic_utils.$('fc_B_pic_attachment'), - bPicShow = 0; - pic_utils.addEvent(bPicArea, 'mouseover', function (e) { - clearTimeout(timer1); - bPicAttachment.style.display = ''; - try { - ! bPicShow && _S_uaTrack('index_wwwb_photo', 'pic_show'); - bPicShow = 1; - } catch (e) {}; - }); - pic_utils.addEvent(bPicArea, 'mouseout', function () { - clearTimeout(timer1); - timer1 = setTimeout(function () { - bPicAttachment.style.display = 'none'; - bPicShow = 0; - }, 300); - }); - var picbd = document.getElementById('picBNav'), currentTag = ''; - pic_utils.delegateByTag(picbd, 'span', 'mouseover', function (e, t) { - // console.log(t); - if (t.getAttribute('data-picb-uaTrack') == currentTag) { - return; - } - currentTag = t.getAttribute('data-picb-uaTrack'); - try { - _S_uaTrack('index_wwwb_photo', currentTag); - } catch (e) {} - }); - } - } - } -}); - // ÐÞ¸Ä 5 end - - jsLoader({ - name: 'shm', - callback: function(){ - jsLoader({ - name: 'StateMgr', - url: 'http://www.sina.com.cn/js/96/2014/0317/StateMgr.js', - callback:function(){ - var guessCtr=document.getElementById('SI_Guess_Wrap'); - var mgr = new SHM.xy.stateMgr({ - timeSlice: 0, //min - state1Ids:['xy-tabA', 'xy-contA', 'xy-imptabtp-A', 'xy-impcon-A'], - state2Ids:['xy-tabB', 'xy-contB', 'xy-imptabtp-B', 'xy-impcon-B'], - s1Callback:function(){ - //guessCtr.style.height='186px';//8 Ìõ - SHM.app.tab.switchByEle(SHM.E('video-tab')); -try{_S_uaTrack("www_update_div", "a");}catch(e){} - }, - s2Callback:function(){ - //guessCtr.style.height='186px';//8 Ìõ - SHM.app.tab.switchByEle(SHM.E('zhuanlan-tab')); -try{_S_uaTrack("www_update_div", "b");}catch(e){} - } - }); - SHM.evt.addEvent(SHM.E('xy-change'), 'click', function(evt){ - mgr.toggleState(); - SHM.evt.preventDefault(evt); - }, false); - } - }); - } - }); -</script> - - <!-- µÇ¼¸¡²ã js plugin start --> - <script type="text/javascript" src="http://i.sso.sina.com.cn/js/outlogin_layer.js" charset="UTF-8"></script> - <!-- µÇ¼¸¡²ã js plugin end --> -<script type="text/javascript" src="http://i.sso.sina.com.cn/js/user_panel_homepage.js" charset="UTF-8"></script> - <script> - - // 20140403 MOD lqf {update the default hot} -jsLoader({name: "shm",callback: function() { - SHM.register("io.jsonp2", function($) { - return function(url, params, callback, fix) { - var head_dom, old_script, script_dom, byId = $.dom.byId, idStr = url + "&" + params, fun = ""; - byId(url) && document.body.removeChild(byId(url)), fix = fix || !1, fix ? "string" == typeof callback && (fun = callback) : (url = url + (-1 == url.indexOf("?") ? "?" : "&") + "_t=" + Math.random(), "function" == typeof callback && (fun = "fun_" + (new Date).getUTCMilliseconds() + ("" + Math.random()).substring(3), eval(fun + "=function(res){callback(res)}"))), url = url + "&_cb=" + fun, url = url + "&" + params, head_dom = document.getElementsByTagName("head")[0], old_script = byId(idStr), old_script && head_dom.removeChild(old_script), script_dom = $.C("script"), script_dom.src = url, script_dom.id = idStr, script_dom.type = "text/javascript", script_dom.language = "javascript", head_dom.appendChild(script_dom) - } - }), SHM.register("home.suggest", function(a) { - var b = {requestURL: "http://s.weibo.com/ajax/jsonp/suggestion?ver=1&Refer=sina_sug",searchURL: "http://s.weibo.com/weibo/@@key@@",interTime: 6e5}, c = "top-suggest-", d = c + "wrap", e = c + "item", f = c + "evt", g = window, h = g.document, j = ($globalInfo.ua.isIOS, a.str.trim), k = a.dom.addClass, m = a.dom.removeClass, n = a.dom.byAttr, o = a.io.jsonp2, p = a.evt.addEvent, q = a.evt.delegatedEvent, r = function(a) { - this.input = a.input, this.maxLen = a.maxLen || 10, this.onoff = a.onoff || "on", this.index = -1, this.cache = new Object, this.controlFunction = a.controlFunction || function() { - }, this.init.apply(this, arguments) - }; - return r.prototype = {init: function() { - var d, a = this, b = a.input; - return "off" === a.onoff ? !1 : (a.wrap = b.parentNode, b.setAttribute("autocomplete", "off"), d = q(a.wrap), a.setDefault(), a.getRandomKey(), d.add(f, "mouseover", function(b) { - var c = b.el; - a.select(c) - }), d.add(f, "mouseout", function(b) { - var d = b.el, e = c + "mover"; - d.className.indexOf(e) && m(d, e), !!a.cache.curitem && m(a.cache.curitem, e) - }), d.add(f, "mousedown", function(b) { - a.evtclick(b.el) - }), p(b, "focus", function() { - !a.cache.listStatus && a.getTimeOut(a.show, "show") - }), b.onpropertychange ? b.onpropertychange = function() { - a.sendRequest() - } : p(b, "input", function() { - a.sendRequest() - }), p(b, "blur", function() { - a.getTimeOut(a.hidden, "hidden") - }), p(b, "keydown", function(b) { - a.keydownEvt(b) - }), p(b, "keyup", function(b) { - var b = b || g.event; - return 38 == b.keyCode || 40 == b.keyCode || 27 == b.keyCode ? !1 : (a.sendRequest(), void 0) - }), void 0) - },getTimeOut: function(a, b) { - var c = this, d = c.cache["timeLayer_" + b]; - !!d && clearTimeout(d), c.cache["timeLayer_" + b] = setTimeout(function() { - a.apply(c, arguments) - }, 200) - },sendRequest: function() { - var a = this, c = a.getInputVal(); - a.setDefault(), "" !== c ? (a.getSugData(b.requestURL, "key=" + encodeURIComponent(c)), a.cache.listType = "sug") : (a.cache.hotList ? (a.sugWrap.innerHTML = a.cache.hotList, a.cache.curVal = "", a.curMaxLen = a.sugWrap.getElementsByTagName("DIV").length - 2, a.innerShowORHidden(!0)) : a.getHotData(b.requestURL, "", !0), a.cache.listStatus = !1, a.cache.listType = "hot") - },setDefault: function() { - var a = this; - a.cache.curitem = null, a.cache.curindex = -1 - },show: function() { - var a = this; - a.sugWrap ? a.innerShowORHidden(!0) : a.sugWrap = a.createSugList() - },hidden: function() { - this.innerShowORHidden(!1); - var a = this.getInputVal(); - "" !== a && "ÇëÊäÈë¹Ø¼ü×Ö" !== a && (this.cache.listStatus = !0) - },innerShowORHidden: function(a) { - var b = this; - b.sugWrap.className = "΢²©" === h.SearchEcho.SerchType.value ? "top-suggest-wrap weibo-suggest" : "top-suggest-wrap news-suggest", this.controlFunction() ? a ? (b.sugWrap.style.display = "block", b.cache.keyDownOff = !1) : (b.sugWrap.style.display = "none", b.cache.keyDownOff = !0) : (b.sugWrap.style.display = "none", b.cache.keyDownOff = !0) - },getInputVal: function() { - return j(this.input.value) - },evtclick: function(a) { - var c = a.innerHTML, d = encodeURIComponent(encodeURIComponent(c)); - this.input.value = c, "΢²©" === h.SearchEcho.SerchType.value ? (h.hform_10.Refer.value = void 0 != this.cache.curVal && c != j(this.cache.curVal) ? "sug" === this.cache.listType ? "sina_sug" : "sina_hot_sug" : "sina_index", h.hform_10.setAttribute("action", b.searchURL.replace("@@key@@", d)), h.hform_10.submit()) : "ÐÂÎÅ" === h.SearchEcho.SerchType.value && (h.hform_02.q.value = c, h.hform_02.submit()) - },keydownEvt: function() { - var c, d, a = this, b = arguments[0] || g.event; - if (a.cache.keyDownOff) - return !1; - switch (b.keyCode) { - case 38: - d = a.curMaxLen || a.maxLen, c = -1 === a.cache.curindex ? d - 1 : a.cache.curindex - 1, a.select(c, !0); - break; - case 40: - d = a.curMaxLen || a.maxLen, c = -1 === a.cache.curindex ? 0 : a.cache.curindex === d - 1 ? -1 : a.cache.curindex + 1, a.select(c, !0); - break; - case 13: - } - },select: function(a, b) { - var e, f, d = this, g = c + "mover", h = d.cache.curitem; - "object" == typeof a ? function() { - e = a, f = +e.getAttribute("index") - }() : function() { - -1 === a ? (e = null, f = -1) : (e = n(d.sugWrap, "index", a + "")[0], f = +a) - }(), !!h && m(h, g), e ? (k(e, g), d.cache.curitem = e, d.cache.curindex = f, b && (d.input.value = e.innerHTML)) : (d.input.value = d.cache.curVal, d.cache.curitem = null, d.cache.curindex = -1), setTimeout(function() { - d.setCursorPos(d.input.value.length) - }, -1) - },setCursorPos: function(a) { - var c, b = this.input; - b.setSelectionRange ? (b.setSelectionRange(a, a), b.focus()) : (c = b.createTextRange(), c.collapse(!0), c.moveEnd("character", a), c.moveStart("character", a), c.select()) - },createSugList: function() { - var c = this, e = c.input; - if (a.util.getUniqueKey(), !e) - throw "input is undefined!"; - - return c.sugWrap = h.createElement("DIV"), c.sugWrap.className = d, c.innerShowORHidden(!1), e.value = "", c.cache.hotList ? (c.sugWrap.innerHTML = c.cache.hotList, c.innerShowORHidden(!0)) : c.getHotData(b.requestURL, "", !0), c.wrap.appendChild(c.sugWrap), setInterval(function() { - c.getHotData(b.requestURL, "", !1) - }, b.interTime), c.sugWrap - },getHotData: function(a, b, c) { - var d = this, e = function(a) { - if (1e5 == a.code && a.data.list.length) { - var b = a.data.list; - c ? (d.cache.hotList = d.sugWrap.innerHTML = d.itemConsturctor(b, 0), d.innerShowORHidden(!0)) : d.cache.hotList = d.itemConsturctor(b, 0, !0) - } else - d.innerShowORHidden(!1) - }; - o(a, b, e) - },getSugData: function(a, b) { - var c = this, d = function(a) { - if (1e5 == a.code && a.data.length) { - if ("" !== c.getInputVal()) { - var b = a.data; - c.sugWrap.innerHTML = c.itemConsturctor(b, 1), c.innerShowORHidden(!0), c.cache.listStatus = !1 - } - } else - c.innerShowORHidden(!1) - }; - o(a, b, d) - },getRandomKey: function() { - var a = this, c = a.input, d = function(a, b) { - return Math.floor(a + Math.random() * (b - a)) - }, e = function(b) { - if (1e5 == b.code && b.data.list.length) { - var e = b.data.list, f = b.data.show, h = d(0, f); - - a.cache.hotList = a.itemConsturctor(e, 0); - // MOD lqf 20140414 {default search error} - a.cache.curVal = e[h]; - - g.___homeSugVal___ = c.value = "´ó¼ÒÕýÔÚËÑ£º" + e[h], a.cache.keyDownOff = !0 - } else - c.value = "ÇëÊäÈë¹Ø¼ü×Ö\r\n" - }; - o(b.requestURL, "", e) - },itemConsturctor: function(a, b, c) { - var g, h, i, j, k, d = this; - for (a = a, g = [], h = "word", i = "", j = "", l = a.length > d.maxLen ? d.maxLen : a.length, c || (d.curMaxLen = l, d.cache.curVal = d.input.value), 0 == b ? (h = "word", i = '<div class="top-suggest-tip">´ó¼ÒÕýÔÚËÑ£º\r\n</div>', j = '<div class="top-suggest-more clearfix"><a href="http://s.weibo.com/top/summary?Refer=sina_sug" target="_blank" class="top-suggest-hotAll">ÍêÕûÈÈËÑ°ñ&gt;&gt;</a><a href="http://s.weibo.com/?Refer=sina_sug" target="_blank" class="top-suggest-toHomePage">½øÈëËÑË÷Ê×Ò³&gt;&gt;</a></div>') : (h = "suggestion", i = "", j = ""), g.push(i), k = 0; l > k; k++) - g.push('<div class="'), g.push(e), g.push('" index="'), g.push(k), g.push('" action-type="'), g.push(f), g.push('">'), g.push(a[k]), g.push("</div>"); - return g.push(j), g.join("") - }}, r - }), window.search_suggest = new SHM.home.suggest({input: document.SearchEcho.SerchKey,maxLen: 10,onoff: "on",controlFunction: function() { - return "΢²©" === document.SearchEcho.SerchType.value || "ÐÂÎÅ" === document.SearchEcho.SerchType.value ? !0 : !1 - }}) - }}); -// 20140403 MOD lqf {update the default hot} end - - function tSearchUatrack(val) { - try{ - _S_uaTrack('index_new_search', val); - }catch(e){} - } - function formSubmit(form,isWb,key){ - var isFF = /firefox/.test(navigator.userAgent.toLowerCase()); - if(isFF){ - if(!isWb) { - setTimeout(function(){ - form.submit(); - },0); - } else { - setTimeout(function(){ - !!key ? form.setAttribute('action', 'http://s.weibo.com/weibo/@@key@@'.replace('@@key@@',key)) : - form.setAttribute('action', 'http://s.weibo.com/weibo/'); - form.submit(); - },0); - } - } else { - if(!isWb) { - form.submit(); - } else { - !!key ? form.setAttribute('action', 'http://s.weibo.com/weibo/@@key@@'.replace('@@key@@',key)) : - form.setAttribute('action', 'http://s.weibo.com/weibo/'); - form.submit(); - } - } - } - function SearchSubmit(){ - var key = document.SearchEcho.SerchKey.value.replace(/(^[\s\u3000]*)|([\s\u3000]*$)/g, ""); - var ipt = document.SearchEcho.SerchKey; - if(key == "ÇëÊä¹Ø¼ü´Ê" || key == "ÇëÊäÈë¹Ø¼ü×Ö" || key === "") - { - ipt.value = ""; - ipt.className = 'inp-txt inp-txt-click'; - setTimeout(function(){ipt.className='inp-txt'},500); - ipt.focus(); - return false; - } else if(key === window.___homeSugVal___) { - key = key.replace("\u5927\u5BB6\u6B63\u5728\u641C\uFF1A",""); - document.hform_10.Refer.value = 'sina_direct_index'; - } - switch(document.SearchEcho.SerchType.value){ - case "ÐÂÎÅ" : - document.hform_02.q.value = key; - tSearchUatrack('search_click_news'); - formSubmit(document.hform_02); - break; - case "ÊÓƵ" : - document.hform_03.q.value = key; - tSearchUatrack('search_click_video'); - formSubmit(document.hform_03); - break; - case "ͼƬ" : - document.hform_05.q.value = key; - tSearchUatrack('search_click_pic'); - formSubmit(document.hform_05); - break; - case "²©¿Í" : - document.hform_08.q.value = key; - tSearchUatrack('search_click_blog'); - formSubmit(document.hform_08); - break; - case "΢²©" : - var ReferEle = document.hform_10.Refer; - if(search_suggest.cache.curVal!=undefined && key != search_suggest.cache.curVal.replace(/(^[\s\u3000]*)|([\s\u3000]*$)/g, "") && search_suggest.sugWrap.style.display === 'block') { - if(search_suggest.cache.listType==='sug') { - ReferEle.value = 'sina_sug'; - } else { - ReferEle.value = 'sina_hot_sug'; - } - } else if(ReferEle.value != 'sina_direct_index') { - ReferEle.value = 'sina_index'; - } - key = encodeURIComponent(encodeURIComponent(key)); - tSearchUatrack('search_click_weibo'); - formSubmit(document.hform_10,true,key); - break; - case "֪ʶÈË" : - document.hform_09.key.value = key; - tSearchUatrack('search_click_knowledge'); - formSubmit(document.hform_09); - break; - default : //ÍøÒ³ - break; - } - return false; - } - - jsLoader({ - name: 'shm', - callback: function() { - SHM.register('home.custEvent.firstpage.fire', function($) { - $.evt.custEvent.fire($, 'firstPageEnd'); - }); - - //²âÊÔ²ÂÄãϲ»¶µÄµÇ¼ - } - }); - </script> - - <!-- / pageload firstpage --> - - <!-- part-b begin --> - - <div class="part-b clearfix"> - <div class="part-b-l"> - <!-- mod07 --> - -<!-- - <div tab-type="tab-wrap" class="mod-07 mod-02"> - <div class="tit02" style="border-bottom:0px;"> - <h3><a href="http://video.sina.com.cn/sports/" target="_blank">ÊÓƵֱ²¥</a></h3> - <div class="s-btn"> - <span tab-type="tab-nav" class="selected">½ñÈÕ</span> - <span tab-type="tab-nav">Ã÷ÈÕ</span> - </div> - </div> - <div id="SI_Live_Wrap" class="mod07-cont-wrap"> - <p class="loading"></p> - </div> -{sports_ÌåÓý_6_ÊÓƵֱ²¥²¹³ä} - </div> ---> - -<!-- ÐÂÀËÌåÓý̨ begin --> - <!-- mod-xltyt start --> - <style type="text/css"> - .mod-x{width:240px;height:210px;overflow: hidden;font:12px/20px "Microsoft Yahei","΢ÈíÑźÚ","SimSun","ËÎÌå","Arial Narrow",serif;float: left;display: inline;} - .mod-x .mod-hd{width:280px;height:35px;border-bottom: 1px solid #000;background: #292928;} - .mod-x .mod-hd a{width:119px; height:35px;overflow:hidden;line-height: 35px;float: left;display: inline;text-align: center;font-size: 17px;line-height: 35px;border:1px solid #000;border-width: 0 1px;padding:0;} - .mod-x .mod-hd a:link,.mod-x .mod-hd a:visited{color:#a0a0a0;text-decoration: none;} - .mod-x .mod-hd a:hover,.mod-x .mod-hd a:active{color:#a0a0a0;text-decoration: none;} - .mod-x .mod-hd a.left{border-right-color:#000;border-left-color:#292928;} - .mod-x .mod-hd a.right{border-right-color:#292928;border-left-color:#3A3939;} - .mod-x .mod-hd a.selected{color:#fff !important;background: #0056A3;} - .mod-x .mod-hd a.left.selected{border-left-color:#0056A3;} - .mod-x .mod-hd a.right.selected{border-right-color:#0056A3;border-left-color:#0068AE;} - - .mod-xltyt{background: url(http://i3.sinaimg.cn/ty/2011hqj/10151730/images/bg.png?v=44) 0 -64px no-repeat;} - .mod-xltyt .mod-bd{height:174px; overflow: hidden;position: relative;} - - .mod-xltyt .mod-hd a.left.selected{background: url(http://i1.sinaimg.cn/ty/2011hqj/10151730/images/bg.png) 0 0 no-repeat;border-left: 0;} - .mod-xltyt .mod-hd a.right.selected{background: url(http://i1.sinaimg.cn/ty/2011hqj/10151730/images/bg.png) 0 -50px no-repeat;border-right:0;border-left-color: #AC0000;} - - .mod-xltyt .item{display: block; border-top:1px solid #224553;border-bottom: 1px solid #000000;line-height: 25px;height: 25px;overflow: hidden;color:#fff;position: relative;} - .mod-xltyt .item:link,.mod-xltyt .item:visited{color:#fff;text-decoration: none;} - .mod-xltyt .item:hover,.mod-xltyt .item:active{color:#fff;text-decoration: none;cursor: pointer;} - .mod-xltyt .item .txt{position: relative;z-index: 10;_zoom:1;} - .mod-xltyt .item .bg{filter:alpha(opacity=10); opacity: 0.1;background: #fff;line-height: 25px;height: 25px;width: 100%;position: absolute;top:-999px;left: 0;} - .mod-xltyt .hover .bg,.mod-xltyt .item:hover .bg{top:0;} - .mod-xltyt .time{float: left;display: inline;width: 70px;text-align: right;} - .mod-xltyt .item2 .time{width: 40px;} - .mod-xltyt .date{float: left;display: inline;width: 60px;text-align: right;} - .mod-xltyt .team{padding-left: 10px;width: 175px;} - .mod-xltyt .blive{height:55px;border-top-color: #5A2020;line-height: 20px;} - .mod-xltyt .blive .txt{padding: 0 0 0 70px;} - .mod-xltyt .blive .bg,.mod-xltyt .blive:hover .bg{height: 55px;background: #4F1212;filter:alpha(opacity=50); opacity: 0.5;top:0;} - .mod-xltyt .blive .tip{color:#e82323;display: block;padding:8px 0 0 10px;} - .mod-xltyt .hot{height:42px;line-height: 20px;} - .mod-xltyt .hot .txt{padding: 0 0 0 70px;} - .mod-xltyt .hot:hover .bg{height: 42px;} - .mod-xltyt .hot .tip{display: block;padding:2px 0 0 10px;} - .mod-xltyt .item i{display: block;position: absolute;overflow: hidden;} - .mod-xltyt .blive i{width:53px;height:26px;background: url(http://i3.sinaimg.cn/ty/2011hqj/10151730/images/blive.gif);left:14px;top:14px;} - .mod-xltyt .slive i{width:28px;height:12px;background: url(http://i0.sinaimg.cn/ty/2011hqj/10151730/images/slive.gif);left:4px;top:7px;} - .mod-xltyt .hot i{width:25px;height:11px;background: url(http://i3.sinaimg.cn/ty/2011hqj/10151730/images/hot.png);_background: url(http://i2.sinaimg.cn/ty/2011hqj/10151730/images/hot_.png);left:30px;top:17px;} - </style> - <div class="mod-xltyt mod-x" tab-type="tab-wrap"> - <div class="mod-hd"> - <a href="http://sports.sina.com.cn/tv" target="_blank" class="left selected" tab-type="tab-nav"><span>ÐÂÀËÌåÓý̨</span></a> - <a href="http://video.sina.com.cn/sports/?show=live" target="_blank" class="right" tab-type="tab-nav"><span>Ò»Öܽ¹µãÖ±²¥</span></a> - </div> - <div class="mod-bd" tab-type="tab-cont" id="SI_XLTYT_Con0" data-sudaclick="sports_tyt1"> - </div> - <div class="mod-bd" tab-type="tab-cont" id="SI_XLTYT_Con1" style="display:none;" data-sudaclick="sports_tyt2"> - </div> - </div> - <script type="text/javascript" src="http://www.sina.com.cn/js/index/96/live.js"></script> - <!-- mod-xltyt end --> -<!-- ÐÂÀËÌåÓý̨ end --> - - <!-- mod07 --> - <div class="blank-cont" style="height:6px;"></div> - <!-- mod08 --> - <div class="mod-08"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x200 3ÂÖ²¥°´Å¥01¹ã¸æ begin --> -<div id="ad_16827" style="width:240px; height:200px;"> -<ins class="sinaads" data-ad-pdps="PDPS000000016827"></ins><script>(sinaads = window.sinaads || []).push({});</script> -</div> -<!-- 240x200 3ÂÖ²¥°´Å¥01¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod08 --> - </div> - <div class="part-b-m"> - <!-- mod09 --> - <div class="uni-blk" id="SI_Order_A" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://sports.sina.com.cn/" target="_blank">ÌåÓý</a></span> - <span tab-type="tab-nav"><a href="http://sports.sina.com.cn/nba/" target="_blank">NBA</a></span> - <span tab-type="tab-nav"><a href="http://video.sina.com.cn/sports/" target="_blank">ÌåÓýÊÓƵ</a></span> - </div> - -<ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://sports.sina.com.cn/csl/" target="_blank">Öг¬</a></li> -<li><a href="http://sports.sina.com.cn/g/championsleague/" target="_blank">Å·¹Ú</a></li> -<li><a href="http://sports.sina.com.cn/z/bjzjk/" target="_blank">¶¬°Â</a></li> -<li><a href="http://sports.sina.com.cn/tennis/frenchopen15/" target="_blank">·¨Íø</a></li> -</ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_sports_1" blkclick="auto_nav" blktitle="ÌåÓý"> -<!-- publish_helper name='ÌåÓýÇø¿é' p_id='30' t_id='101' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://sports.sina.com.cn/hdphoto/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U6599P30DT20150618101827.jpg" height="70" width="105" /> - - <span>Àú½ìNBA×ܾöÈüMVP</span> - - </a> - -<ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/">ΤµÂ:Õâ´Î×ܾöʧÀû¶ÔLBJ´ò»÷×î´ó</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09547637072.shtml">¿Æ±È×£ºØÓÂÊ¿</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/01237636921.shtml">JR×ÔÆØ»òÌø³öºÏͬ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/03107636932.shtml">ÆØÓÂÊ¿Óû½»Ò׶á¹Ú¹¦³¼ »ð¼ý½ÓÅÌ?</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09177637032.shtml">×ܾöÊÕÊÓ½ö´Î98ÄêÇǵ¤µÚ6¹Ú</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/">ÊÓƵ</a></li> - -</ul> - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://sports.sina.com.cn/csl/">Ëï¿É»ò7000Íòת»áÌ©´ï</a> <a target="_blank" href="http://sports.sina.com.cn/china/j/2015-06-18/doc-ifxefurq6405356.shtml">¿â¿¨¿Ö±»¶¨ÐÔŹ´ò²ÃÅнûÈüÊýÔÂ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/g/2015copaamerica/">ÃÀÖÞ±­-ÄÚÂí¶û±¨¸´ÌßÈËȾºì°ÍÎ÷¸º</a> <a target="_blank" href="http://sports.sina.com.cn/g/2015-06-18/08597637012.shtml">Éñͬ²½!ÕâÑù·À÷Î÷</a></li> - -<li><a href="http://sports.sina.com.cn/g/laliga/2015-06-18/08247636975.shtml" target="_blank">×îÁÁÓîÖæÐÇϵÒÔCÂÞÃüÃû</a> <a target="_blank" href="http://sports.sina.com.cn/g/laliga/2015-06-18/09237637037.shtml">¾ÞÐÇÒªÇóCÂÞÈóö»ÊÂíÈÎÒâÇòȨ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/g/laliga/2015-06-18/08447636987.shtml">ÆØ°²Ë§¶áÅ·¹ÚÕÕÑùÏ¿Î</a> <a target="_blank" href="http://sports.sina.com.cn/g/pl/2015-06-18/10057637095.shtml">ÂüÁª»ÊÂí̸ÅÐÏëÂòÄÂ˧¿àÇóÃû½«</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/z/others/2015snookerwc/">ÊÀ½ç±­¶¡¿¡êÍÂʶӺáɨÉýµÚ1</a> <a target="_blank" href="http://sports.sina.com.cn/cba/2015-06-18/doc-ifxefurt9362584.shtml">Âí²¼Àï·´ÊÖÃþ¶ÇÆêʧ°Ü(ͼ)</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/t/2015-06-18/10407637154.shtml">ÌÀΨÓÐÐËȤÖ÷ÑÝÀîÄÈ×Ô´«µçÓ°</a> <a target="_blank" href="http://sports.sina.com.cn/o/o/2015-06-17/22347636890.shtml">Éñ¾çÔÙÏÖ!×ÔÐгµ½ØÍ£»ð³µ</a></li> - -<li><a href="http://blog.sina.com.cn/lm/sports/" target="_blank">²©¿Í</a>-<a href="http://blog.sina.com.cn/s/blog_5c4bb2910102wde6.html?tj=1" target="_blank">ÍõÃÍ:±ÈÊäÓ®¸üÖØÒªµÄ</a> <a href="http://sports.sina.com.cn/zl/" target="_blank">רÀ¸</a>-<a href="http://sports.sina.com.cn/zl/basketball/2015-06-18/zldoc-ifxefurs2578675.shtml" target="_blank">ÖìÑå˶:×ܾöÈüûÊä¼Ò</a></li> - -<li><a class="videoNewsLeft" target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/101865026655.html">¡¶ÉùÉ«NBA¡·</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/095165026635.html">Õ²»Ê´ßÀáMV</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/g/v/2015-06-18/101665026653.html">8±¬ÈéÃÀŮȫÂã³ö¾µÃÀÖÞ±­</a></li> -<li><a href="http://lottery.sina.com.cn/" target="_blank">ÉñÈ˲ÂÖÐ1.8ÒÚ¾Þ½±¾¹Ò»·ÖδµÃ</a> <a href="http://sports.sina.com.cn/lotto/" target="_blank">´óÀÖ͸¿ª7עǧÍò¼¶Í·½±</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_sports_2" blkclick="auto_nav" blktitle="NBA"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='NBAÇø¿é' p_id='30' t_id='101' d_id='2' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://sports.sina.com.cn/nba/" target="_blank" class="uni-blk-pic"> - - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U7835P30DT20150617100106.jpg" width="105" height="70" /> - <span>ÓÂÊ¿»÷°ÜÆïÊ¿¶á¹Ú</span> - - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/02347636929.shtml">¶á¹ÚÒ¹°Â¿ËÀ¼ÇòÃÔÄð³åÍ»</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/00167636912.shtml">2015ÀÖ͸ÐãѲÀñÖ®ÐݳÇÀ¶Ä§¹í</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/13487637328.shtml">ÓÂÊ¿¶á¹Ú¿¿ÔËÆø£¿±ð¶ºÁË£¡</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09547637072.shtml">¿Æ±È·¢ÍƺØÓÂÊ¿¶á¹Ú</a></li> - -</ul> - - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://sports.sina.com.cn/nba/">ÆØÓÂÊ¿Óû½»Ò׶á¹Ú¹¦³¼</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/01237636921.shtml">JR×ÔÆØ»ò½«Ìø³öºÏͬ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/nbamitan/" class="linkRed videoNewsLeft">¡¶NBAÃÜ̽¡·</a> <a target="_blank" href="http://video.sina.com.cn/z/sports/k/nba/150601sinanba/" class="linkRed">¡¶ÀË˵NBA¡·ÂÖ²¥</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/095165026635.html">Õ²»Ê´ßÀáMV</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/105865026729.html" class="videoNewsLeft">G6΢µçÓ°</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-18/102465026663.html">ÓÂÊ¿¿­Ðý»Ø¼Ò</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/k/v/2015-06-17/172765026449.html">·çÁÖ»ðɽսÊõ¼¯½õ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09177637032.shtml">×ܾöÈüÊÕÊÓÈËÊý´´Ð¸ß</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09117637023.shtml">×î¼ÑµÚÁùÈËδÀ´È¥ÏòÎåÑ¡Ò»</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09257637040.shtml">ÐÝÈüÆÚÓÂÊ¿»áÓж¯×÷Âð£¿</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/10377637149.shtml">¸ñÁÖ£ºÔøÓÐÈË˵ÎÒÎÞ·¨Á¢×ã</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/09307637051.shtml">ΤµÂ£ºÕâ´ÎʧÀû¶ÔÕ²´ò»÷×î´ó</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/10507637178.shtml">ŵÌìÍõ̹³ÐáÛ·åÒѹý</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/11167637230.shtml">ÅÁ½ð˹:Õ²»ÊÅäµÃÉÏÊÀ½ç×î¼Ñ</a> <a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-18/11137637224.shtml">¼ÖÃ×É­»ØÒä¿Æ±È:ºÜºÃÏà´¦</a></li> - -<li><a target="_blank" href="http://slide.sports.sina.com.cn/k/slide_2_786_83545.html" class="linkRed">¸ßÇå-ÓÂÊ¿ÖÚ½«¿­Ðý</a> <a target="_blank" href="http://slide.sports.sina.com.cn/k/slide_2_786_83544.html" class="linkRed">¿âÀïÒ»¸ç±§×Ž±±­Ë¯×Å</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/2015-06-17/17217636778.shtml">½ñÈÕÉñͲÛ:Ò»¸çº¦¿âÀï¿ÞÔÎ Õ²»ÊŪ¶ªÇó»é½äÖ¸</a></li> - </ul> - </textarea> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_sports_3" blkclick="auto_nav" blktitle="ÌåÓýÊÓƵ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÌåÓýÊÓƵÇø¿é' p_id='30' t_id='101' d_id='3' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://video.sina.com.cn/z/sports/k/nba/150617gswcle/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U6589P30DT20150617163842.jpg" width="105" height="70" /> - <span>ÓÂÊ¿¶á15NBA×ܹھü</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138271581" class="linkRed videoNewsLeft">MVÖ¾´Õ²»Ê</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/#138285768">ÓÂÊ¿Åõ±­Ë²¼ä</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138270279" class="videoNewsLeft">ÒÁ¸ê´ïÀ­»ñFMVP</a> <a target="_blank" href="http://sports.sina.com.cn/nba/video/#138285972">LBJ¿âÀïÏàÓµ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/#138286970" class="videoNewsLeft">¿âÀïÈüºóÓµ±§×ܾöÈü½±±­</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/nba/video/matches/" class="videoNewsLeft liveNewsLeft">×ܾöÈüG6»ã×Ü</a> <a target="_blank" href="http://video.sina.com.cn/z/sports/nba/officialbest/2015-06-17/#138271443">NBA¹Ù·½5¼ÑÇò</a></li> -</ul> - - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/n/v/2015-06-16/222865025571.html" class="videoNewsLeft">¹ú×ã6-0²»µ¤È¡¿ªÃźì ÑîÐñ´÷ñ+2´«ÓÚ´ó±¦2Çò</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0613/ITA/" class="videoNewsLeft">Å·Ô¤Èü-²¼·ëÆ˵ãÒâ´óÀû1-1</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0613/NED/">ºÉÀ¼2-0</a> <a target="_blank" href="http://video.sina.com.cn/p/sports/g/v/2015-06-13/033465023405.html">±´¶ûÕ¶±ÈÀûʱ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0615/ENG/" class="videoNewsLeft">Ó¢¸ñÀ¼3-2</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0614/POR/">CÂÞ´÷ñÆÏÌÑÑÀ3-2</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0614/GER/">µÂ¹ú7-0</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/Fifavideo/0615/ESP/">Î÷°àÑÀ1-0</a></li> - -<li><a href="http://video.sina.com.cn/p/sports/pl/v/2015-06-16/112965025289.html" target="_blank" class="videoNewsLeft">Ó¢¸ñÀ¼¶ÓÊ·10¼ÑÇò</a> <a target="_blank" href=" http://video.sina.com.cn/p/sports/g/v/2015-06-16/095865025177.html">´ÈÉÆÈü¿ËÂåÔóµõÉäϷˣΫ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/p/sports/pl/v/2015-06-16/143565025367.html" class="videoNewsLeft">ǹÊÖÐÂÇòÒÂÕ𺳷¢²¼</a> <a target="_blank" href=" http://video.sina.com.cn/p/sports/seriea/v/2015-06-16/215065025567.html">MV¡¶ÄǾÍÕâÑù°É¡·ËͱðƤ²¨</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138199129" class="videoNewsLeft">Å·¹Ú|°ÍÈø3-1ÓÈÎÄ</a> <a href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138199143" target="_blank">¶á¹Ú°ä½±Â¼²¥</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/clear/victoryfootball/1514/#138199153">Å·¹ÚÈü¼¾10¼ÑÇò</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138215864" class="videoNewsLeft">MVÖ¾´¹Ú¾ü°ÍÈø</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/clear/victoryfootball/1514/#138231309">Å·¹ÚÈü¼¾È«¾°»Ø¹Ë</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/ucl/match/1415/13/Juve_Barca/#138199609">÷Î÷Å·¹ÚÈ«½øÇò</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/footballtactics/" class="videoNewsLeft">¡¶×ãÇòµÀÖеÀ¡·</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/clear/victoryfootball/">¡¶Ê¤Àû×ãÇò¡·</a> <a target="_blank" href="http://sports.sina.com.cn/video/cba20years/">¡¶CBA¶þÊ®Äê¡·</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/video/g/pl/" class="videoNewsLeft">Ó¢³¬ |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/laliga/">Î÷¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/seriea/">Òâ¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/bundesliga/">µÂ¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/g/ligue1/">·¨¼× |</a> <a target="_blank" href="http://sports.sina.com.cn/video/c/j/csl/">Öг¬ |</a> <a target="_blank" href="http://sports.sina.com.cn/video/c/j/afccl/">ÑǹÚ</a></li> - </ul> - </textarea> - </div> -<!-- 0316 nmod01 --> - <div class="nmod01" data-sudaclick="blk_sports_textad"> -<a target="_blank" href="http://sports.sina.com.cn/hdphoto/">¸ßÇåÃÀͼ</a>&nbsp;<ins class="sinaads" data-ad-pdps="PDPS000000045982"></ins><script>(sinaads = window.sinaads || []).push({});</script>&nbsp;<ins class="sinaads" data-ad-pdps="PDPS000000045983"></ins><script>(sinaads = window.sinaads || []).push({});</script> - - </div> - <!-- 0316 nmod01 --> - </div> - </div> - </div> - <!-- mod09 --> - </div> - <div class="part-b-r"> - <!-- mod10 --> - <div class="mod-10"> - <div class="uni-blk" id="SI_Order_B" tab-type="tab-wrap" struc="2-3"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://auto.sina.com.cn/" target="_blank">Æû³µ</a></span> - <span tab-type="tab-nav"><a href="http://auto.sina.com.cn/guide/" target="_blank">¹º³µ</a></span> - <span tab-type="tab-nav"><a href="http://photo.auto.sina.com.cn/" target="_blank">ͼÉÍ</a></span> - </div> - - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Car"> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_auto_search&value=auto_search">ËѳµÐÍ</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" method="GET" action="http://so.auto.sina.com.cn/search/" onsubmit="return carsearch(this,'car')"> - <select id="SI_Slt_05" name="by"> - <option value="cars" selected="selected">³µÐÍ</option> - <option value="kinds">Æ·ÅÆ</option> - </select> - <input type="hidden" name="c" value="car"> - <input type="hidden" name="range" value="article"> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" onblur="if(this.value==''){this.value='ÇëÊäÈë²éѯ´Ê'}" onfocus="if(this.value=='ÇëÊäÈë²éѯ´Ê'){this.value=''}" value="ÇëÊäÈë²éѯ´Ê" name="q"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_auto_search&value=auto_search_click"/> - </a> - </form> - </div> - </div> - </div> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden" style="display:none;"> - <li><a href="http://finance.sina.com.cn/sf/list/?cate_id=50025972&cat_name=%E6%9C%BA%E5%8A%A8%E8%BD%A6" target="_blank" suda-uatrack="key=index_sfpm&value=autosf">Æû³µÅÄÂô</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - - <!--adÆû³µ°å¿éÎÄ×ÖÁ´ begin--> - <div style="position:relative;" data-sudaclick="blk_auto_adtext"> - <ul class="uni-blk-list02 list-a" style=" position:absolute; top:320px; left:0px; width:360px;"> -<li><ins class="sinaads" data-ad-pdps="PDPS000000045984"></ins><script>(sinaads = window.sinaads || []).push({});</script>&nbsp;<ins class="sinaads" data-ad-pdps="PDPS000000045985"></ins><script>(sinaads = window.sinaads || []).push({});</script></li> - -<li><!--µØÓò¶¨ÏòÎÄ×ÖÁ´ begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000045986"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<ins class="sinaads" data-ad-pdps="PDPS000000045987"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<!--µØÓò¶¨ÏòÎÄ×ÖÁ´ end--></li> - </ul> - </div> - <!--adÆû³µ°å¿éÎÄ×ÖÁ´ end--> - - <div tab-type="tab-cont" blkclick="auto_nav" blktitle="Æû³µ" data-sudaclick="blk_auto_1"> -<!-- publish_helper name='Æû³µÇø¿é' p_id='30' t_id='102' d_id='1' --> - -<div class="uni-blk-bt clearfix"><a href="http://photo.auto.sina.com.cn/tuji/18269" target="_blank" suda-uatrack="key=sina_auto_xjdt&value=sina_auto_xjdt1" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U4982P30DT20150618085458.jpg" width="105" height="70" /> - <span>±¼³Û·¢²¼GLCÌæGLK</span> - </a> - - <ul class="uni-blk-list01 list-a" data-sudaclick="blk_auto_1wz1"><li><a target="_blank" href="http://auto.sina.com.cn/">±¼³Û±¦ÂíÇëÈò½£¡ÊÔ¼ÝȫаµÏTT</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/review/sinasupic/2015-06-18/detail-ifxczyze9690905.shtml">ÊÔ¼Ý6ÍòÔªSUV»ÃËÙS3 ȫϵ±êÅä7×ù </a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/car/2015-06-05/09421444537.shtml">³¤ÂíÐÂCX-5½ñÈÕÉÏÊÐ Ô¤ÊÛ17ÍòÆð</a></li><li><a target="_blank" href="http://auto.sina.com.cn/car/2015-06-11/13381445878.shtml">ÓÖ¼û¼«¹â£¿ Ë«ÁúSUV½ñÉÏÊлò13Íò</a></li> -</ul></div><div class="blk-line"></div><div class="uni-blk-bt clearfix" style="padding-top:5px"> - -<a href="http://photo.auto.sina.com.cn/tuji/18167/" target="_blank" suda-uatrack="key=sina_auto_xjdt&value=sina_auto_xjdt2" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U4982P30DT20150618085502.jpg" width="105" height="70" /> - <span>2015¿îCX-5½ñÉÏÊÐ</span> - - </a> - - <ul class="uni-blk-list01 list-a" data-sudaclick="blk_auto_1wz2"><li><a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxefurt9355520.shtml">¼ªÀûÎÖ¶ûÎÖÔì³µ ½ô´ÕSUVÆ¥µÐ¼«¹â</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczyze9679612.shtml">½Ý±ªÂ·»¢¿ÉÍÆÒ£¿ØŲ³µºÍ×Ô¶¯µ÷Í·</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxefurt9337492.shtml">°ÂµÏQ3¸Ä¿î ×Ô¶¯¼ÝʻʱËÙ130km/h</a></li><li><a class="photoNewsLeft" target="_blank" href="http://photo.auto.sina.com.cn/tuji/18267/">×î½ÚÓ͸߶û·ò</a> <a target="_blank" href="http://photo.auto.sina.com.cn/tuji/18262/">¸£ÌïÊ׿îSUV</a></li></ul></div> - - <ul class="uni-blk-list02 list-a" style="padding-top:0px;margin-top:0px;"> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxefurs2562286.shtml">±±¾©»ò½«Õ÷Óµ¶Â·ÑÈ¡ÏûÏÞÅÆÏÞÐÐ</a> <a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxczyze9695968.shtml">±êÖÂ308 GTI 25ÈÕÊ×·¢</a></li> -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxefurt9346113.shtml">Á¦·«820ÈçºÎÑ¡¼ö1.8LÊÖ¶¯ºÀ»ª</a> <a target="_blank" href="http://auto.sina.com.cn/2015-06-18/detail-ifxczyze9701151.shtml">ÐÂÓ¢ÖÂMPVÅäÌØ˹À­´óÆÁ </a></li> - -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczqan1518406.shtml">б¦ÂíX5²åµçʽ»ì¶¯Ô¼47.7Íò</a> <a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczqan1435616.shtml">MINI¼Ó³¤°æÆعâ»ò9ÔÂÊ×·¢</a></li> - -<li><a target="_blank" href="http://auto.sina.com.cn/2015-06-17/detail-ifxczqan1469420.shtml">duang!³¤³ÇÐû²¼½µ¼Û¹þ¸¥H6½µ6ǧ</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-18/07001447332.shtml">±öÀûÍÆȫг¨Åñ½ÎÅÜ</a></li> - - </ul> - </div> - <div tab-type="tab-cont" style="display:none" blkclick="auto_nav" blktitle="¹º³µ" data-sudaclick="blk_auto_2"> - <div class="selectCar clearfix"> - <div class="selectLeft" id="selectCar" data-sudaclick="blk_auto_2xc"> - <div class="carIndex clearfix"> - <span class="carDot able">1</span> - <span class="carGap"></span> - <span class="carDot" id="CSI_Slt_8">2</span> - <span class="carGap"></span> - <span class="carDot" id="CSI_Slt_7">3</span> - <span class="carGap"></span> - <span class="carDot" id="CSI_Slt_6">4</span> - </div> - <form action="http://data.auto.sina.com.cn/xuanche/index.php#ul_list" method="post" target="_blank" id="selectIndex"> - <select id="SI_Slt_9" name="price"> - <option value="0" selected="selected">Ñ¡Ôñ¼Û¸ñ</option> - <option value="0-5">0-5Íò</option> - <option value="5-8">5-8Íò</option> - <option value="8-11">8-11Íò</option> - <option value="11-15">11-15Íò</option> - <option value="15-20">15-20Íò</option> - <option value="20-25">20-25Íò</option> - <option value="25-35">25-35Íò</option> - <option value="35-50">35-50Íò</option> - <option value="50-70">50-70Íò</option> - <option value="70-100">70-100Íò</option> - <option value="100-999999">100ÍòÒÔÉÏ</option> - </select> - <select id="SI_Slt_8" name="type"> - <option value="0" selected="selected">Ñ¡Ôñ³µÐÍ</option> - <option value="1">½Î³µ</option> - <option value="2">Åܳµ</option> - <option value="3">SUV</option> - <option value="4">MPV</option> - <option value="5">Ãæ°ü³µ</option> - <option value="6">Ƥ¿¨</option> - </select> - <select id="SI_Slt_7" name="country"> - <option value="0" selected="selected">Ñ¡Ôñ¹ú±ð</option> - <option value="china">Ö§³Ö¹ú»õ</option> - <option value="germany">ÎÒÖ»ÒªµÂ¹ú³µ</option> - <option value="ou">Å·ÖÞ³µ¶¼ÐÐ</option> - <option value="america">ÎÒϲ»¶ÃÀ¹ú·¶</option> - <option value="nojp">²»ÂòÈÕ±¾³µ</option> - <option value="japan">Ö»ÂòÈÕ±¾³µ</option> - <option value="korea">º«¹ú³µË¼ÃÜ´ï</option> - </select> - <select id="SI_Slt_6" name="feature1"> - <option value="0" selected="selected">Ñ¡ÔñÌØÐÔ</option> - <option value="1">°²È«µÚÒ»</option> - <option value="3">¸Ü¸ÜµÄ¶¯Á¦ºÍ²Ù¿Ø</option> - <option value="2">´ó¿Õ¼äÓдó¶ÇÁ¿</option> - <option value="4">ºÃÑø»îµÄС»ï°é</option> - <option value="5">¿ª×Å×ø×Ŷ¼Êæ·þ</option> - <option value="6">ÅÀɽÉæË®µÄÔ½Ò°¸ßÊÖ</option> - </select> - <div class="selectBtn"><input type="submit" value="¿ªÊ¼Ñ¡³µ" /></div> - </form> - </div> - <div class="selectRight"> - <div class="cbox" data-sudaclick="blk_auto_2jgzc"> - <p>°´¼Û¸ñÕÒ³µ£º</p> - <ul class="clearfix"> - <li><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=0-5&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">5ÍòÒÔÏÂ</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=5-8&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">5-8Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=8-11&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">8-11Íò</a></li> - -<li class="cborder"><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=11-15&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">11-15Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=15-20&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">15-20Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=20-25&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">20-25Íò</a></li> - -<li><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=25-35&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">25-30Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=35-50&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">35-50Íò</a><a href="http://data.auto.sina.com.cn/#global:::orderby=pv&seq=desc&price=100-9999999&type=&outgas=&country=&color=&gear_box=&config=&seat_num=&cheshen=&hezi=&drive=&fuel=&page=1&limit=18&callback=" target="_blank">100ÍòÒÔÉÏ</a></li> - </ul> - </div> - <div class="cbox2" data-sudaclick="blk_auto_2_rmcx"> - <p>ÈÈÃųµÐÍ£º</p> -<!-- publish_helper name='ÈÈÃųµÐÍ' p_id='30' t_id='102' d_id='10' --> -<p class="clearfix"><a href="http://data.auto.sina.com.cn/632" target="_blank">ººÀ¼´ï</a><span>|</span><a href="http://data.auto.sina.com.cn/168" target="_blank">±¦Âí5ϵ</a><span>|</span><a href="http://data.auto.sina.com.cn/994" target="_blank">°º¿ÆÍþ</a></p> -<p class="clearfix"><a href="http://data.auto.sina.com.cn/2091/" target="_blank">Èñ½ç</a><span>|</span><a href="http://data.auto.sina.com.cn/410/" target="_blank">ËÙÌÚ</a><span>|</span><a href="http://data.auto.sina.com.cn/2119/" target="_blank">ÎåÊ®Áåmu-X</a></p> -<p class="clearfix"><a href="http://data.auto.sina.com.cn/776/" target="_blank">¹þ¸¥H6</a><span>|</span><a href="http://data.auto.sina.com.cn/535/" target="_blank">½Ý±ªXF</a><span>|</span><a href="http://data.auto.sina.com.cn/88" target="_blank">зɶÈ</a></p> - - </div> - </div> - </div> - <div class="blk-line" style="margin-top:5px;"></div> - <div class="mod-a" tab-type="tab-wrap"> - <div class="hd clearfix"> -<span class="extra" id="SI_IP_Auto_City_Title" style="" data-sudaclick="blk_auto_2city">ÆäËü³ÇÊУº<a href="http://tj.auto.sina.com.cn/" target="_blank">Ìì½ò</a>|<a href="http://sh.auto.sina.com.cn/" target="_blank">ÉϺ£</a>|<a href="http://cq.auto.sina.com.cn/" target="_blank">ÖØÇì</a>|<a href="http://gz.auto.sina.com.cn/" target="_blank">¹ãÖÝ</a>|<a href="http://cc.auto.sina.com.cn/" target="_blank">³¤´º</a></span> -<span class="tab-nav-a clearfix"><a tab-type="tab-nav" href="http://bj.auto.sina.com.cn/" style="" target="_blank" class="selected" id="SI_IP_Auto_Tab_Nav_1">±±¾©±¨¼Û</a><span>|</span><a tab-type="tab-nav" href="http://dealer.auto.sina.com.cn/" target="_blank" class=" " >È«¹ú±¨¼Û</a></span> - </div> - <div class="bd tab-cont-a" style="height:80px; overflow: hidden;"> - -<div id="SI_IP_Auto_Tab_Cont_1" style="zoom: 1; overflow: hidden;" data-sudaclick="blk_auto_gc2city"> - <ul tab-type="tab-cont" class="list-a" style=""> -<li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/17321445940.shtml">±¼³ÛE¼¶7.6ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09231446114.shtml">ÀÊÒÝÃë³µ¼Û9.29Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09291446115.shtml">¿Æ³×È8.2ÕÛÏúÊÛ</a></li> - - <li><a target="_blank" href="http://auto.sina.com.cn/car/2015-06-15/10521446451.shtml">¸£ÌØÒí²«×î¸ßÖ±½µ1.4Íò</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-15/11301446458.shtml">;¹Û8.7ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/10161445593.shtml">¸£¿Ë˹7.9ÕÛ</a></li> - - <li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/18361445945.shtml">Ó¢·ÆÄáµÏQ50 8.7ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09331446116.shtml">V60½µ7.69Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/18431445946.shtml">ÂõÈñ±¦17.19ÍòÆð</a></li> - - </ul> -</div> - - <ul tab-type="tab-cont" class="list-a" data-sudaclick="blk_auto_gc2" style="display:none;"> -<li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/16091446182.shtml ">±ð¿ËÓ¢ÀÊ7.7ÕÛÏúÊÛ</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/16041446181.shtml">ËÙÌÚ×î¸ßÓÅ»Ý2.5ÍòÔª</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/15551446179.shtml">;¹Û9.4ÕÛÆð</a></li><li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/14541446172.shtml">2015¿î°ÂµÏA4L 8ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/17321445940.shtml">±¼³ÛE¼¶7.6ÕÛÆð </a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09291446115.shtml">¿Æ³×ȵøÆÆ8Íò</a></li><li><a target="_blank" href="http://auto.sina.com.cn/news/2015-06-11/18251445943.shtml">Ö¸ÄÏÕß×î¸ß½µ4.1Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/09431446117.shtml">Âí×Ô´ïCX-5 9ÕÛÆð</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/11101445605.shtml">¸£¿Ë˹½µ2.5Íò</a></li><li><a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/18341445681.shtml">°ÂµÏQ5ÓŻݳ¬9Íò</a> <a target="_blank" href="http://auto.sina.com.cn/car/2015-06-10/19261445684.shtml">ÐùÒÝ×îµÍ²»×ã9Íò</a> <a target="_blank" href="http://auto.sina.com.cn/news/2015-06-12/16331446185.shtml">°º¿ÆÀ­È«³¡8.9ÕÛÆð</a></li> - - </ul> - - </div> - </div> - - </div> - <div tab-type="tab-cont" style="display:none" blkclick="auto_nav" blktitle="Æû³µÍ¼ÉÍ" data-sudaclick="blk_auto_3"> - <div class="carPics clearfix"> -<!-- publish_helper name='ͼÉÍ' p_id='30' t_id='102' d_id='11' --> -<div class="carPicL"> -<a href="http://photo.auto.sina.com.cn/tuji/18232/" target="_blank" class="uni-blk-pic carh1" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts1"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0616/U4982P30DT20150616150517.jpg" width="160" height="88" /> - <span>µÚËÄ´ú·»¢·¢ÏÖ82ÍòÆð</span> -</a> -<a href="http://photo.auto.sina.com.cn/tuji/18267/" target="_blank" class="uni-blk-pic carh2" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts2"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U4982P30DT20150618103700.jpg" width="160" height="218" /> - <span>Ê·ÉÏ×î½ÚÓ͸߶û·ò</span> - </a></div><div class="carPicR"><span class="carh3" data-sudaclick="blk_auto_31"><a href="http://photo.auto.sina.com.cn/tuji/18231/" target="_blank">°ÂµÏ³¬°ÙÍò¸ßÐÔÄܽÎÅÜ</a></span> - <span class="carh4" data-sudaclick="blk_auto_32"><span><a href="http://photo.auto.sina.com.cn/tuji/18197/" target="_blank">½Ö³µ±äÁ³ÁË£¡Ð¿îÔö¯ÊµÅÄ</a></span> - <span><a href="http://photo.auto.sina.com.cn/tuji/18213/" target="_blank">Ò°ÐÔÊ®×ã µÀÆæƤ¿¨Ô¼27ÍòÆð</a></span></span> - <a href="http://photo.auto.sina.com.cn/tuji/18244" target="_blank" class="uni-blk-pic carh5" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts3"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U4982P30DT20150617113030.jpg" width="190" height="104" /> - <span>ԭζÔ˶¯ ʵÅı¼³ÛC¼¶±ê×¼Öá¾à°æ</span> - </a> - <a href="http://photo.auto.sina.com.cn/tuji/18268/" target="_blank" class="uni-blk-pic carh5" suda-uatrack="key=index_new_auto_search&value=sina_auto_ts4"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U4982P30DT20150618105040.jpg" width="190" height="104" /> - <span>ʵÅÄÎÖ¶ûÎÖ×î¸ß¶ËSUV XC90</span> - </a></div> - </div> - </div> - </div> - </div> - </div> - </div> - <!-- mod10 --> - </div> - </div> - <!-- part-b end --> - <div class="blank-cont" style="height:23px;"></div> - <!-- part-c begin --> - - <span id="SI_IP_Part_1" style="display:none"></span> - - <div class="part-c"> - <!-- mod11 --> - <div class="mod-11"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸01¹ã¸æ begin --> -<div id="ad_25256" class="ad-banner"><ins class="sinaads" data-ad-pdps="PDPS000000025256"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸01¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod11 --> - <!-- mod12 --> - <!-- ÀÖ¾ÓµÚ¶þÆÁͨÀ¸ÏÂÎÄ×ÖÁ´(14Ìõ) begin--> - <div id="LejuText3" class="mod-12 clearfix"></div> - <script> - lejuMedia.then(function (data) { - leju.text2('LejuText3', data, 14); - }); - </script> - <!-- ÀÖ¾ÓµÚ¶þÆÁͨÀ¸ÏÂÎÄ×ÖÁ´(14Ìõ) end --> - <!-- mod12 --> - </div> - <!-- part-c end --> - <div class="blank-cont" style="height:25px;"></div> - <!-- part-d begin --> - - <div class="part-d clearfix"> - <div class="part-d-l"> - <!-- mod13 --> - <div class="mod-13 mod-02"> - <div class="tit02 clearfix"> - <h3><a href="http://music.sina.com.cn/" target="_blank">ÀÖ¿â</a></h3> - </div> - <div class="mod13-cont"> - <ul class="list-b" data-sudaclick="blk_music_1" blkclick="auto_nav" blktitle="ÀÖ¿â"> -<!-- publish_helper name='ÀÖ¿âÇø¿é' p_id='30' t_id='104' d_id='2' --> -<li><a href="http://music.sina.com.cn/yueku/a/244718.html" target="_blank">»ª³¿ÓÎÒ¹ÜÄã¡·</a> <a href="http://music.sina.com.cn/yueku/a/244703.html" target="_blank">Å·ºÀ¡¶So What!¡·</a> </li> -<li><a href="http://music.sina.com.cn/yueku/a/244736.html" target="_blank">ÀîÒ׷塶ÄêÉÙÓÐÄã¡·</a> <a href="http://music.sina.com.cn/yueku/a/244720.html" target="_blank">̷άά¡¶°®µ½µ×¡·</a></li> -<li><a href="http://music.sina.com.cn/yueku/a/244719.html" target="_blank">¡¶»¨Ç§¹Ç¡·²åÇú</a> <a href="http://music.sina.com.cn/yueku/a/244721.html" target="_blank">Ö£¾û¡¶·çÂí¡·Âý°æ</a></li> - -<li><a href="http://weibo.com/sinamusic" target="_blank">ÐÂÀËÀÖ¿â</a>|<a href="http://music.sina.com.cn/" target="_blank">ÒôÀÖÈË</a>|<a href="http://music.weibo.com/snake/snk_apply.php" target="_blank"><b>Èëפ</b></a> <a href="http://music.weibo.com/t/s/2740928150.html" target="_blank">°×¾Ù¸Ù</a> <a href="http://music.weibo.com/t/s/1844477730.html" target="_blank">Å·ºÀ</a></li> - </ul> - </div> - </div> - <!-- mod13 --> - <div class="blank-cont" style="height:20px;"></div> - <!-- mod14 --> - <div class="mod-14"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x200 2ÂÖ²¥°´Å¥02¹ã¸æ begin --> -<div id="ad_46010" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046010"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x200 2ÂÖ²¥°´Å¥02¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod14 --> - </div> - <div class="part-d-m"> - <!-- mod15 --> - <div class="uni-blk" id="SI_Order_C" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://ent.sina.com.cn/" target="_blank">ÓéÀÖ</a></span> - <span tab-type="tab-nav"><a href="http://ent.sina.com.cn/star/" target="_blank">°ËØÔ</a></span> - <span tab-type="tab-nav"><a href="http://video.sina.com.cn/ent/" target="_blank">ÓéÀÖÊÓƵ</a></span> - </div> - -<ul class="mod44-list clearfix SC_Order_Hidden" style="float:right; padding-right:5px;"> -<!-- -<li><a href="http://ent.sina.com.cn/f/z/2015cw/" target="_blank">ÑòÄê´ºÍí</a></li> ---> -</ul> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_2"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_ent_1" blkclick="auto_nav" blktitle="ÓéÀÖ"> -<!-- publish_helper name='ÓéÀÖÇø¿é' p_id='30' t_id='100' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112240.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U8551P30DT20150618085611.jpg" width="105" height="70" /> -<span>46ËêÐíÇç°×ÒÂÉÙÅ®</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxefurt9354264.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ËïÙ³ÂèÂè·ñÈϵ˳¬³ö¹ì£ºÐ¡ÈËÔìÒ¥</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxczyze9703841.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">Óá°×ü±ÙÒ¥×ÔÆØÄÛÄ£ ËïÙ³ËÍ×£¸£</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurs2568670.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">¹ù¾¸Ñ¾ÛÊ×£¡ºÃÓÑΪÃçÇÈΰÇìÉú</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxefurt9363347.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">»¬Ìú¬£¿ÀîÑÇÅô35ÒÚСÕò2ÒÚ˦Âô</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxczyze9700911.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">32ËêÈËÆÞÅ®ÐÇÅÄÂãÕÕÔâÆÅÆű©´ò</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112277.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">±ß²ß×·µ¿»á½¯Ð¡º­Ê§¿Ø</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurt9355689.shtml">´óS:ÍôС·Æ³ö¹ìÁ¢¿Ì·ÖÊÖ</a> <a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurs2577907.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">¸ÛÐÇÅóÓѶù×ÓÓë·ÆÓ¶ÉÏ´²È¾hiv</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/l/p/1696772.html" class="linkRed liveNewsLeft margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÃÀÉÙÄÐÑîÑó×ö¿Í°®¶¹±§±§</a> <a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-18/doc-ifxefurs2586000.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÍÀºé¸Õ3»éÉñÃؽ¿ÆÞÆøÖʼÑ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/m/c/2015-06-18/doc-ifxehfqi8029563.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ºîТÏÍ:ËÀºóÿ°ÙÄê¿´´Îµ±ÌìµçÓ°</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112299.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÀîÄî²ú¶þÌ¥ºóѸËÙÊÝÉí</a></li> - -<li><a target="_blank" href="http://slide.ent.sina.com.cn/star/slide_4_704_112311.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">Ҷ说îÉñÃØÄêÇáÄе±½ÖÇ×êÇ(ͼ)</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/slide_4_704_112302.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÇØá°´ø¸¸Ä¸¿´·¿ÏÔТÐÄ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurt9360889.shtml" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÂÞÖ¾ÏéÁµÉÏÍøºì·ÛË¿È°·ÖÊÖ</a> <a target="_blank" href="http://ent.sina.com.cn/f/m/siff18/" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">·¶±ù±ù»ñÀÏ°å³Ðŵ½ÇÉ«ÈÎÌô</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/photo/">ͼ</a>:<a target="_blank" href="http://slide.ent.sina.com.cn/film/w/slide_4_704_112238.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">ÁõÒà·ÆÉîVÇåÐÂ</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/k/slide_4_704_112260.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">º«À²À²¶Ó¿ªÍÈÈÈÎè</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/slide_4_704_112246.html" class="margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0 margin_l_0">¶Å½­Îª»ô˼Ñ࿪ÃÅ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138275167-1" class="videoNewsLeft">±»ÍµÅÄÂÞÖ¾Ïé³ÐÈÏÁµÇé</a> <a target="_blank" href="http://ent.sina.com.cn/bn/entreport/#138293078" class="videoNewsLeft">СS±§·¶·¶¶ù×Ó¶ÊÂÒµÏß</a></li> - -<li><a href="http://blog.sina.com.cn/lm/ent/" target="_blank">²©¿Í</a>|<a href="http://blog.sina.com.cn/lm/ent/" target="_blank">Ã÷ÐÇÔÙ»é¸ü·ç¹â</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_14b06494b0102voyh.html?tj=1">±¨¸´Ç°ÈÎ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_141f22bbf0102w8vq.html?tj=1">10´óĸŮ»¨</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_1423123bf0102vzre.html?tj=1">»¼ÄÑÈ´·ÖÊÖ</a></li> - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_ent_2" blkclick="auto_nav" blktitle="°ËØÔ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='°ËØÔÇø¿é' p_id='30' t_id='100' d_id='5' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.ent.sina.com.cn/film/w/slide_4_704_112238.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U8551P30DT20150618111738.jpg" width="105" height="70" /> -<span>µÍÐØ£¡ÁõÒà·ÆÃÀ·­</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurs2577907.shtml">¸ÛÅ®ÐÇÅóÓѶù×ÓÓë·ÆÓ¶ÉÏ´²È¾°¬×Ì</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/v/m/2015-06-17/doc-ifxefurt9342611.shtml">Ç°ÑëÊÓÖ÷²¥Âí±ó£ººó»Ú×ß˽ÏãÑÌ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-17/doc-ifxczyze9684814.shtml">СS±§·¶·¶¶ù×Ó¶ÊÂÒµÏß°×ðªÃÀÍÈ</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/s/h/2015-06-18/doc-ifxefurt9355689.shtml">´óS£º·¢ÏÖÍôС·Æ³ö¹ìÁ¢¿Ì·ÖÊÖ</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://e.weibo.com/entpaparazzi">΢²©</a>|<a target="_blank" href="http://ent.sina.com.cn/y/ygangtai/2015-06-16/doc-ifxczqap4181484.shtml">ÐÅ14ËêÅ®¶ù¿áËÆ°Ö°Ö(ͼ)</a> <a target="_blank" href="http://ent.sina.com.cn/s/m/2015-06-16/doc-ifxczqar0967926.shtml">ÕÅÜ°Óè°µÖ¸×Ô¼ºÕæʵ²»×°</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/korea/">º«Óé</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/y/k/slide_4_704_112161.html">º«¹úÅ®¸èÊÖÈÈÁ¦³ªÌø(ͼ)</a> <a target="_blank" href="http://slide.ent.sina.com.cn/tv/k/slide_4_704_112185.html">ºÓÖÇÔ·´©Ð£·þ±ä»Ø¸ßÖÐÉú</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/">ÈÕÓé</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/y/jp/slide_4_704_112167.html">¼¤ÃÈ£¡ÈÕ±¾16ËêÃÀÉÙÅ®×ߺì</a> <a target="_blank" href="http://ent.sina.com.cn/y/yrihan/2015-06-15/doc-ifxczqan0016921.shtml">Çå´¿Å®Ðǻ᳡¸îÍó×Ô²Ð</a></li> - -<li><a href="http://slide.ent.sina.com.cn/?cate=304" target="_blank">ÐÇÎÅ</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112158.html">ÈøÀ­¹«Ö÷ËÆ»³Ôи¹²¿Í¹Æð</a> <a target="_blank" href="http://slide.ent.sina.com.cn/y/k/slide_4_704_112157.html">EXO±ß²®ÏÍΪ°ôÇòÈü¿ªÇò</a></li> - -<li><a target="_blank" href="http://slide.ent.sina.com.cn/?cate=303">»¨±ß</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/y/h/slide_4_704_112194.html">ÂóÀò²»¹ÎҸë´©Àñ·þ³¬°­ÑÛ</a> <a target="_blank" href="http://ent.sina.com.cn/y/ygangtai/2015-06-17/doc-ifxczyze9646779.shtml">¹ùѩܽ³Æ°Ǫ̂°Ù´óÃÀÅ®</a></li> - -<li><a target="_blank" href="http://ent.sina.com.cn/">ÃÀͼ</a>|<a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112191.html">°î³½ÐãÄæÌìÃÀÍÈ</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112177.html">Ó¢³¬Å®Éñ½¿µÎµÎ</a> <a target="_blank" href="http://slide.ent.sina.com.cn/star/h/slide_4_704_112166.html">°²Äݹ«Ö÷´©¾Éȹ</a></li> - -<li><a target="_blank" href="http://blog.sina.com.cn/lm/ent/">ͲÛ</a>|<a href="http://blog.sina.com.cn/s/blog_7964e4ec0102vqpn.html?tj=1" target="_blank">Å̵㴩ɽկÀñ·þÔâ´òÁ³µÄÅ®ÐÇ</a><a target="_blank" href="http://blog.sina.com.cn/s/blog_4baa667b0102vo3t.html?tj=1"> ³Â³åÁ½¸öÅ®¶ù½ÔòÃÀ</a></li> -<li><a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-18/101365026649.html" class="videoNewsLeft">¹ù¾¸ÑÈýÊ®ÄêÔÙ¾ÛÊ×</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-18/102865026673.html" class="videoNewsLeft liveNewsLeft">´óS³Æ·¢ÏÖ³ö¹ìÁ¢¿Ì·ÅÊÖ</a></li> - -<li><a href="http://video.sina.com.cn/p/ent/2015-06-18/104165026707.html" target="_blank" class="videoNewsLeft">СS±§·¶·¶¶ù×Ó¶ÊÂÒµÏß</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/v/m/2015-06-18/093665026625.html" class="videoNewsLeft">¿¹ÈÕÉñ¾ç·´ÎïÀíÖƵÐ</a></li> - </ul> - </textarea> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_movie_1" blkclick="auto_nav" blktitle="´óƬ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='´óƬÇø¿é' p_id='30' t_id='99' d_id='4' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://video.sina.com.cn/ent/#1-28-138292542-1" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U7647P30DT20150618105718.jpg" width="105" height="70" /> - - <span>µË³¬±»Æسö¹ì</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://video.sina.com.cn/ent/#1-28-138277171-1" target="_blank" class="videoNewsLeft">¿¹ÈÕÉñ¾çÏÖ×ÔÐгµ·´ÎïÀíÖƵÐ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292564-1" class="videoNewsLeft">»ô˼Ñà¶ù×Ó×ê»õ¼Üµ÷Ƥ³¬ÃÈ</a></li> - -<li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138275167-1" class="videoNewsLeft">±»ÍµÅĺóÂÞÖ¾Ïé´óµ¨³ÐÈÏÁµÇé</a></li><li><a target="_blank" href="http://video.sina.com.cn/ent/#1-28-138292308-1" class="videoNewsLeft">ÀîÒ×·åÇ£ÊÖÅ®º¢Óо­Ñé¿¿ºÎêÁ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://ent.sina.com.cn/bn/entreport/ttbl/" class="videoNewsLeft">¿ì±¨Í·Ìõ</a>| <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/110265025261.html">·¶±ù±ùËͳµ»öСº¢¾ÍÒ½</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/112765025279.html">±£½£·æ±¨Ï²µ±µù</a></li><li><a href="http://ent.sina.com.cn/bn/entreport/bghb/" target="_blank" class="videoNewsLeft">¿ì±¨°ËØÔ</a>| <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-15/163765024877.html">Íô·å¶àÊ׸èײÃûÖ£¾û</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/111265025269.html">Íõʯ³ÆÌïÆÓ¬Bϱ¸¾</a></li> - -<li><a href="http://ent.sina.com.cn/bn/entreport/yqwx/" target="_blank" class="videoNewsLeft">¿ì±¨ÓéÇé</a>| <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-16/114065025291.html">л骶ù×Ó·¢¸ßÉÕ</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/2015-06-15/155265024853.html">Íõ±¦Ç¿ÇìÉú½¿ÆÞÏ×ÎÇ</a></li> - -<li><a href="http://video.sina.com.cn/ent/" target="_blank" class="videoNewsLeft">¶À¼Ò¶Ô»°</a>|<a href="http://video.sina.com.cn/p/ent/v/j/2015-05-18/165964960247.html" target="_blank">×Á÷³Ø²ýÐñ</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/v/m/2015-06-10/092665021023.html">ÐÂÇàÄêÑîÑó</a> <a target="_blank" href="http://video.sina.com.cn/p/ent/v/m/2015-06-11/094165021937.html">µçÊÓÈËÎâÀÚ</a></li> - -<li><a href="http://video.sina.com.cn/vlist/ent/idolbb/" target="_blank" class="videoNewsLeft">×ÔÖƽÚÄ¿</a>|<a href="http://ent.sina.com.cn/f/v/idolbb/" target="_blank">ÕÅÒÕÐËÏÖ³¡ÊªÉí</a> <a target="_blank" href="http://video.sina.com.cn/vlist/ent/cannes2015/#138106669">ºîТÏÍ»ñê©ÄÉ×î¼Ñµ¼ÑÝ</a></li> - -<li><a href="http://video.sina.com.cn/movie/category/teleplay/area/1.html" target="_blank" class="videoNewsLeft">¹ú²ú</a>|<a href="http://video.sina.com.cn/m/201505220332631_64988569.html" target="_blank">´ý¼ÞÀÏ°Ö</a> <a target="_blank" href="http://video.sina.com.cn/m/201505251126675_64992315.html">¶þÉô</a> <a target="_blank" href="http://video.sina.com.cn/m/201505190927653_64974419.html"> »éÒöʱ²î</a> <a target="_blank" href="http://video.sina.com.cn/m/201505050246701_64915825.html"> ÁÄիбà</a> <a target="_blank" href="http://video.sina.com.cn/m/201506050241698_65021591.html">¾ç³¡</a></li> - -<li><a href="http://video.sina.com.cn/movie/movie/" target="_blank" class="videoNewsLeft">µçÓ°</a>|<a href="http://video.sina.com.cn/m/yznaw_64759031.html" target="_blank">ÓÐÖÖÄã°®ÎÒ</a> <a href="http://video.sina.com.cn/m/bssn_63372523.html" target="_blank">°ëÊìÉÙÅ®</a> <a target="_blank" href="http://video.sina.com.cn/m/xjxs_61983055.html">Ð×¼äѩɽ</a> <a target="_blank" href="http://video.sina.com.cn/m/ysh_61625873.html">Ò¹ÉϺ£</a></li> - -<li><a href="http://video.sina.com.cn/movie/category/original/" target="_blank" class="videoNewsLeft">Ô­´´</a>|<a target="_blank" href="http://video.sina.com.cn/m/jf1_64489349.html">½Ó·¢</a> <a href="http://video.sina.com.cn/m/xkrj_64030295.html" target="_blank">ÐÇ¿ÕÈÕ¼Ç</a> <a href="http://video.sina.com.cn/m/qcxjbhw_64408185.html" target="_blank">Çà´ºÏà¼ú²»ºÞÍí</a><a target="_blank" href="http://video.sina.com.cn/m/aqh_64077739.html"> °®ÇÙº£</a></li> - -<li><a href="http://video.sina.com.cn/movie/category/cartoon/area/1.html" target="_blank" class="videoNewsLeft">¶¯»­</a>|<a href="http://video.sina.com.cn/m/xdcr_64045215.html" target="_blank">Ï̵°³¬ÈË</a> <a href="http://video.sina.com.cn/m/xdjh_63840289.html" target="_blank">Цµô½­ºþ</a> <a href="http://video.sina.com.cn/m/asatm_63821101.html" target="_blank">°¬Ë¹¡¤°ÂÌØÂü</a> <a target="_blank" href="http://video.sina.com.cn/m/dongbeiyijiaren_63825081.html">¶«±±Ò»¼ÒÈË</a></li> - - </ul> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod15 --> - </div> - <div class="part-d-r"> - <!-- mod16 --> - <div class="uni-blk" id="SI_Order_D" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://finance.sina.com.cn/" target="_blank">²Æ¾­</a></span> - <span tab-type="tab-nav"><a href="http://finance.sina.com.cn/stock/" target="_blank">¹ÉƱ</a></span> - <span tab-type="tab-nav"><a href="http://finance.sina.com.cn/money/" target="_blank">Àí²Æ</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden" style="float:left; padding-left:73px;"> - <li><a href="http://finance.sina.com.cn/sf/" target="_blank" suda-uatrack="key=index_sfpm&value=financesf">·¨Ôº</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Fin"> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_finance_search&value=finance_search">ËѹÉƱ</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" class="clearfix" method="GET" action="http://biz.finance.sina.com.cn/suggest/lookup_n.php"> - <select id="SI_Slt_02" name="country" onchange="changeViewInputs(this);"> - <option selected="selected" value="stock">¹ÉƱ</option> - <option value="fund">»ù½ð</option> - <option value="hkstock">¸Û¹É</option> - <option value="usstock">ÃÀ¹É</option> - </select> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" value="´úÂë/Ãû³Æ/Æ´Òô" name="q" id="textSuggest"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_finance_search&value=finance_search_click" /> - </a> - </form> - </div> - </div> - </div> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" id="blk_finance_1" data-sudaclick="blk_finance_1" blkclick="auto_nav" blktitle="²Æ¾­"> -<!-- publish_helper name='²Æ¾­Çø¿é' p_id='30' t_id='98' d_id='2' --> - - <div class="uni-blk-bt clearfix"> -<!-- ÐÐÇéͼ´úÂëbegin --> -<a href="http://finance.sina.com.cn/realstock/company/sh000001/nc.shtml" target="_blank" class="uni-blk-pic" style="border:#fff 1px solid;"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://image.sinajs.cn/newchart/small/t/sh000001.gif" width="103" height="68" /><span id="SI_Text_sh600001">ÉÏÖ¤</span></a> -<!-- ÐÐÇéͼ´úÂëend --> - -<ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/cyxw/20150617/230122458690.shtml " class="linkRed">´«¼à¹Ü²ãÄâ·Å¿ªÍâ×ʹºÂòÖйúÂ¥ÊÐ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/china/20150618/003722458786.shtml ">¶àµØÉç±£½É·Ñ»ùÊýËæƽ¾ù¹¤×ÊÉϵ÷</a></li> -<li><a target="_blank" href="http://finance.sina.com.cn/china/20150617/225922458678.shtml">ÍÁµØÒÀÀµÖ¢£¿µØ·½³Æ²»ÂôµØû¹¤×Ê</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/cyxw/20150618/132222466342.shtml">¹úÄÚÓͼ۵÷Õû»òÏÖÄêÄÚµÚ3´Î¸édz</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://finance.sina.com.cn/china/20150618/132522466355.shtml">Éç±£»ù½ðͶ×ÊÂìÒϽð·þÕ¼¹É5% ΪÆäÊ×µ¥Ö±Í¶</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/consume/puguangtai/20150618/012122459450.shtml ">½¡¿µÔª¡¢Ë¼²ºÆÕͨʳƷÖ÷´ò¼õ·Ê¹¦Ð§ »òÉæÎ¥¹æÐû´« </a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/chanjing/cyxw/20150617/225722458655.shtml ">Â̳ÇÄâÔڻʹ¬ÒÅÖ·ÉϽ¨ºÀÕ¬ ÔøÒòר¼ÒÇ¿ÁÒ¿¹ÒéÍ£¹¤ËÄÄê</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/china/20150618/111222465660.shtml">ÉÌÎñ²¿£ºWTO±£»¤ÆÚ½áÊøºó²»»á³öÏÖ½ø¿ÚÉÌÆ·¼Û¸ñ´ó½µ</a></li> - -<li><a href="http://finance.sina.com.cn/stock/" target="_blank">¹ÉƱ</a>|<a target="_blank" href="http://finance.sina.com.cn/stock/jsy/20150618/113322465808.shtml"> »¦Ö¸ÅÌÕû΢µø0.18% ½ðÈڹɵÍÃÔ</a> <a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150617/225622458649.shtml">²úÒµ×ʱ¾´óÌÓÍö</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/stock/stocklearnclass/20150618/065222463281.shtml">·è¿ñµÄÅä×ÊÆ­¾Ö£ºÕË»§¸ÄÃÜÌ×È¡±£Ö¤½ð</a> <a target="_blank" href="http://finance.sina.com.cn/stock/stocklearnclass/20150618/010922459340.shtml">¸Ü¸Ë×î¸ß´ï9±¶</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/stock/stocklearnclass/20150618/092422464435.shtml">³¤É³ºîÏÈÉúΪţÊÐÌøÂ¥µÚÒ»ÈË£¿¼ÒÊô¾¯·½·ñÈÏÒò³´¹ÉʧÀû</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/sjyhpc2015_zx/" class="linkRed">ÆÀ²â:ÖÐÐÅÊÖ»úÒøÐвúÆ·ØÑ·¦Ìøת»ºÂý</a> <a target="_blank" href="http://finance.sina.com.cn/money/bank/pingxuan2015.html" class="linkRed">ƱѡÖйúºÃÐг¤£¡</a></li> - -<li><a target="_blank" href="http://blog.sina.com.cn/lm/stock/">²©¿Í</a>| <a target="_blank" href="http://blog.sina.com.cn/lm/stock/">Å̹ţº¶þ´Î·´´ò͸¶Ö÷Á¦ÈýÒâͼ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_59902b790102w0qo.html?tj=fina">ÉÏÁË´´Òµ°åµÄµ±</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" id="blk_finance_2" data-sudaclick="blk_finance_2" blkclick="auto_nav" blktitle="¹ÉƱ"> -<!-- publish_helper name='¹ÉƱÇø¿é' p_id='30' t_id='98' d_id='4' --> - - <div class="uni-blk-bt clearfix"> -<div class="finance-pt"><table cellspacing="0" cellpadding="0" class="finance-form"><thead><tr><th colspan="2">±Ø¶ÁÊý¾Ý</th></tr></thead> - <tbody><tr><td><a href="http://finance.sina.com.cn/data/#visual-gnzz" target="_blank">Êг¡Èȵã</a></td> - <td><a href="http://finance.sina.com.cn/data/#visual-wbyq" target="_blank">΢²©ÓßÇé</a></td></tr> - <tr><td><a href="http://finance.sina.com.cn/data/#visual-agrt" target="_blank">A¹ÉÈÈͼ</a></td> - <td><a href="http://finance.sina.com.cn/data/#visual-mgrt" target="_blank">ÃÀ¹ÉÈÈͼ</a></td></tr> - <tr><td><a href="http://finance.sina.com.cn/data/#visual-hqgszz" target="_blank">»·Çò¹ÉÖ¸</a></td> - <td><a href="http://finance.sina.com.cn/data/#visual-agssdd" target="_blank">ʵʱ´óµ¥</a></td></tr></tbody></table></div><ul class="uni-blk-list01 list-a"><li>[<a href="http://blog.sina.com.cn/lm/stock/" target="_blank">²©¿Í</a>]<a href="http://blog.sina.com.cn/lm/stock/" target="_blank">¹ÉÊÐÕÇÂ¥ÊÐÒ»¶¨»áÕÇÂð</a></li> <li>[<a href="http://blog.sina.com.cn/lm/stock/" target="_blank">¶À¼Ò</a>]<a target="_blank" href="http://blog.sina.com.cn/s/blog_494225410102vhkq.html?tj=fina">Äϱ±³µºÏ²¢Î´´¥¼°¹úÆó¸Ä¸ï</a></li> - -<li>[<a href="http://finance.sina.com.cn/stock/hkstock/" target="_blank">¸Û¹É</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/hkstock/hkstocknews/20150618/071922463351.shtml">ÏÕ×ʳ­µ×²ÆÏո۹ɳÉÖ÷Á¦</a></li> - -<li>[<a href="http://finance.sina.com.cn/stock/usstock/" target="_blank">ÃÀ¹É</a>]<a href="http://finance.sina.com.cn/stock/usstock/c/20150618/021122460062.shtml" target="_blank">ÃÀÁª´¢°µÊ¾ÄêÄÚ¼ÓÏ¢</a></li></ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li>[<a href="http://finance.sina.com.cn/stock/roll/gushilive.html" target="_blank">´óÅÌ</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/130522466232.shtml ">¸ÖÌú¹É±©ÕÇ2¹ÉÕÇÍ£</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/114922465926.shtml ">º½¿Õ°å¿é4¹ÉÕÇÍ£</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/131622466314.shtml ">µØ²ú¹É´óÕÇ</a></li> -<li> [<a href="http://finance.sina.com.cn/focus/jyts/" target="_blank">°å¿é</a>]<a href="http://finance.sina.com.cn/stock/gujiayidong/20150618/131222466286.shtml " target="_blank">¾©½ò¼½¸ÅÄîì­Éý</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/133322466393.shtml ">ÓÐÉ«°å¿é´óÕÇ</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/142522466813.shtml ">»¥ÁªÍø¸ÅÄµø</a></li> -<li> [<a href="http://roll.finance.sina.com.cn/finance/zq1/zldx/index.shtml" target="_blank">¸ö¹É</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/132822466367.shtml ">µÏÊ¿Äá¸ÅÄî»îÔ¾</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/132422466353.shtml ">»Æ½ð°å¸ÅÄîì­Éý</a> <a target="_blank" href="http://finance.sina.com.cn/stock/gujiayidong/20150618/143022466833.shtml">°¢Àï¸ÅÄî¹É±©µø</a></li> -<li> [<a href="http://vip.stock.finance.sina.com.cn/q/go.php/vIR_CustomSearch/index.phtml" target="_blank">Ñо¿</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/084822464040.shtml">Ü÷Óñ¸ù:¸Ü¸ËûÄÇô¿ÉÅÂ</a> <a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/021922460170.shtml">ÐËÒµ:Å£ÊеÚÒ»½×¶ÎβÉù</a></li> -<li>[<a href="http://finance.sina.com.cn/blog/7.html" target="_blank">ÍƼö</a>]<a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/022422460734.shtml ">¹Ø×¢ÒøÐÐB֤ȯBµÄÀíÓÉ</a> <a target="_blank" href="http://finance.sina.com.cn/stock/marketresearch/20150618/012722459581.shtml">Öг¤ÆÚ·ç¿Ú:ÖйúÖÆÔì2025</a></li> -<li>[<a href="http://finance.sina.com.cn/blog/8.html" target="_blank">²©¿Í</a>]<a target="_blank" href="http://blog.sina.com.cn/s/blog_eb1cfc160102vyha.html?tj=fina">ÖйúÖгµ°ó¼Ü´óÅÌ</a> <a href="http://blog.sina.com.cn/s/blog_dbbd84730102wm12.html?tj=fina" target="_blank">»¦Ö¸ËõÁ¿ÕûÀí</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_634ca6e10102w45a.html?tj=fina">Ƶ·±¾ÞÕð²ØÒõı</a></li> -<li>[<a href="http://licaishi.sina.com.cn/web/plan?fr=stock_top" target="_blank" class="linkRed">Àí²Æʦ</a>]<a target="_blank" class="linkRed" href="http://licaishi.sina.com.cn/web/askList?is_p=1&fr=stock_top">ÎÊ:</a><a target="_blank" class="linkRed" href="http://licaishi.sina.com.cn/web/topic?tid=291&fr=stock_top">Å£ÊÐÏ´ÅÌ»¹ÊÇ×ßÐÜ</a> <a target="_blank" class="linkRed" href="http://licaishi.sina.com.cn/web/planList?s=2&fr=stock_top">Å£¼Æ»®</a> <a target="_blank" class="linkRed" href="http://finance.sina.com.cn/roll/20150617/134122455407.shtml">ƸÄÚÈÝÔËӪרԱ</a></li> -<li> [<a href="http://guba.sina.com.cn/" target=_blank>¹É°É</a>]<a target="_blank" href="http://guba.sina.com.cn/">»ú³¡¹ÉÓ­ÐÂÒ»ÂÖÀûºÃ(Ãûµ¥) </a> <a target="_blank"href="http://guba.sina.com.cn/?s=thread&tid=48386&bid=2285&dpc=1"target="_blank" >µØ·½¹úÆó¸Ä¸ï³É·ç¿Ú</a> -</li> -<li>[<a target="_blank" href="http://blog.sina.com.cn/lm/stock">Ãû¼Ò</a>]<a target="_blank" href="http://blog.sina.com.cn/lm/stock/">Å̹ţº¶þ´Î·´´ò͸¶Ö÷Á¦ÈýÒâͼ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_59902b790102w0qo.html?tj=fina">ÉÏÁË´´Òµ°åµÄ¶ñµ±</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" id="blk_finance_3" data-sudaclick="blk_finance_3" blkclick="auto_nav" blktitle="Àí²Æ"> -<!-- publish_helper name='Àí²ÆÇø¿é' p_id='30' t_id='98' d_id='3' --> - - <div class="uni-blk-bt clearfix"> - - <div class="finance-pt"> - <!-- finance table begin 0426 --> - <table cellspacing="0" cellpadding="0" class="finance-form"> - <thead> - <tr> - <th style="width:43px;">Æ·ÖÖ</th> - <th style="width:60px;">¼Û¸ñ</th> - </tr> - </thead> - <tbody> - <tr> - <td><a href="http://finance.sina.com.cn/money/future/GC/quote.shtml" target="_blank">»Æ½ð</a></td> - <td id="comex"><span class="num down"></span></td> - </tr> - <tr> - <td><a href="http://finance.sina.com.cn/money/future/CL/quote.shtml" target="_blank">Ô­ÓÍ</a></td> - <td id="nymex"><span class="num up"></span></td> - </tr> - <tr> - <td><a href="http://finance.sina.com.cn/money/forex/hq/USDCNY.shtml" target="_blank">ÃÀÔª</a></td> - <td id="usdcny"><span class="num down"></span></td> - </tr> - </tbody> - </table> - <script type="text/javascript"> - jsLoader({ - name : 'financeData', - url : 'http://hq.sinajs.cn/list=hf_GC,hf_CL,USDCNY', - callback : function() { - //»Æ½ð - var comexarr = hq_str_hf_GC.split(','); - //Ô­ÓÍ - var nymexarr = hq_str_hf_CL.split(','); - //ÃÀÔªÈËÃñ±Ò - var usdcnyarr = hq_str_USDCNY.split(','); - var byId = 'getElementById', - byTN = 'getElementsByTagName', - D = document, - T = 'SPAN', - comex = (D[byId]('comex'))[byTN](T)[0], - nymex = (D[byId]('nymex'))[byTN](T)[0], - usdcny = (D[byId]('usdcny'))[byTN](T)[0]; - - var setVal = function(obj,val,flag) { - if(parseFloat(flag) < 0) { - obj.className = 'num down'; - } else if(parseFloat(flag) > 0) { - obj.className = 'num up'; - } else { - obj.className = 'num'; - } - obj.innerHTML = val; - } - - setVal(comex,comexarr[0],comexarr[1]); - setVal(nymex,nymexarr[0],nymexarr[1]); - setVal(usdcny,usdcnyarr[1],parseFloat(usdcnyarr[1]) - parseFloat(usdcnyarr[3])); - } - }); - </script> - <!-- finance table end 0426 --> - </div> - -<ul class="uni-blk-list01 list-a"> -<li>[<a href="http://finance.sina.com.cn/fund/" target="_blank">»ù½ð</a>] <a target="_blank" href="http://finance.sina.com.cn/money/smjj/20150618/005922458908.shtml">5ÔÂ˽ļ¹Ú¾üÊÕÒ泬400%</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/fund/20150618/083122463866.shtml">ÂòÕâ2Ö»·Ö¼¶BË­´øÄã·ÉµÃÓÖÔ¶ÓÖÎÈ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/fund/20150618/012622459579.shtml">7ÔÂÆðͶ×ÊÕß½«¿ÉÔÚ¼ÒÂòÏã¸Û¹«Ä¼</a></li> - -<li><a href="http://finance.sina.com.cn/money/fund/20150618/082622463824.shtml" target="_blank">½ñÄêлù½ðÊ×·¢¹æÄ£ÆÆÍòÒÚÔª</a></li> -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://finance.sina.com.cn/money/">Àí²Æ|</a> -<a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/053922462422.shtml">½ü900ÒÚÔª¾Þ×ʳ­µ×A¹É ÈôÒÑϳµ¾ÍµÈÏÂÌË</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/bank_hydt/20150618/081622463753.shtml" class="linkRed">18ÈÕÔÚÊÛ¸ßÊÕÒæÒøÐÐÀí²Æ²úÆ·</a> <a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/082422463817.shtml" class="linkRed">ÖØÒªÀí²ÆÐÅÏ¢»ã×Ü</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/074622463547.shtml">¹ÉÊÐÎüÒýͶ×ÊÈËÑÛÇò ±¦±¦ÀàÊÕÒæµøÈë2ʱ´ú </a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/lczx/20150618/083022463885.shtml">׬ǮЧӦ͹ÏÔ Æ«¹É»ù½ðÄêÄڷֺ쳬¹ý420ÒÚÔª</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/bank_hydt/20150618/005922458900.shtml">´ó¶î´æµ¥×ªÈûúÖÆÔÝ佨Á¢ ½ö²¿·ÖÒøÐпɰìÀíÖÊѺ</a></li> - -<li><a target="_blank" href="http://finance.sina.com.cn/money/bank/bank_hydt/20150618/053922462573.shtml">ÉîÛÚ¶à¼ÒÒøÐÐÉϵ÷Ê×Ì×·¿´ûÀûÂÊ ³ÊÏÖÊÕ½ô̬ÊÆ</a></li> - -<li>[<a target="_blank" href="http://finance.sina.com.cn/forex/">Íâ»ã</a>] <a target="_blank" href="http://finance.sina.com.cn/money/forex/20150618/070022463306.shtml">ÃÀÁª´¢Ö÷ϯµ­»¯Ê״μÓÏ¢</a> <a target="_blank" href="http://finance.sina.com.cn/money/forex/20150618/070722463320.shtml">È«Çò½ðÈÚ×ʲúÔõô×ß</a></li> - -<li>[<a target="_blank" href="http://finance.sina.com.cn/nmetal/">»Æ½ð</a>] <a target="_blank" href="http://finance.sina.com.cn/money/nmetal/20150618/061322462693.shtml">¸ëÅÉÃÀÁª´¢Íƶ¯½ð¼ÛÖØ»Ø1180 ²¬½ðÔÙ´¥6ÄêеÍ</a></li> - -<li><a href="http://sports.sina.com.cn/l/2015-06-18/doc-ifxefurs2575240.shtml" target="_blank">90ºó´ò¹¤×Ð3ÔªÖÐ2400Íò:Ëæ»úÑ¡ºÅÔÙÐÞ¸Ä</a> <a href="http://slide.sports.sina.com.cn/l/slide_2_22616_83540.html" target="_blank">¸ßÇå×éͼ</a></li> - </ul> - </div> - </div> - </div> - </div> - -<!-- ²Æ¾­°å¿é¶¨Ïò begin --> -<script language="javascript" type="text/javascript"> -(function() { - function addEvent(obj, eventType, func) { - if(obj.attachEvent) { - obj.attachEvent("on" + eventType, func); - } else { - obj.addEventListener(eventType, func, false); - } - }; - - function attachURL2Window(id,url) { - var links; - try { - links = document.getElementById(id).getElementsByTagName("a"); - }catch(e) { - links = []; - } - for (var i = 0, len = links.length; i < len; i++) { - addEvent(links[i], "mousedown", function(e) { - var writeCookie = function(O, o, l, I, p) { - var i = "", - c = "", - path = ""; - if (l != null) { - if(l == "NaN"){ - i = ";"; - }else{ - i = new Date((new Date).getTime() + l * 3600000); - i = "; expires=" + i.toGMTString(); - } - }; - if (I != null) { - c = ";domain=" + I - }; - if(p != null){ - path = ";path=" + p; - }; - document.cookie = O + "=" + escape(o) + i + c + path; - }; - writeCookie("directAd_finance","true",1,".sina.com.cn","/"); - //µã»÷¼à²â - var _clickStat = new Image(); - _clickStat.src = url + "&_=" + new Date().getTime() + "&url="; - }); - } - }; - - attachURL2Window("blk_finance_1","http://sina.allyes.com/main/adfclick?db=sina&bid=202406,581303,586578&cid=0,0,0&sid=589122&advid=358&camid=36885&show=ignore"); - attachURL2Window("blk_finance_2","http://sina.allyes.com/main/adfclick?db=sina&bid=202406,581309,586584&cid=0,0,0&sid=589128&advid=358&camid=36885&show=ignore"); - attachURL2Window("blk_finance_3","http://sina.allyes.com/main/adfclick?db=sina&bid=202406,581310,586585&cid=0,0,0&sid=589129&advid=358&camid=36885&show=ignore"); - -})() -</script> -<!-- ²Æ¾­°å¿é¶¨Ïò end --> - -<script type="text/javascript" src="http://d3.sina.com.cn/d1images/sinaads_entry/sinaads_entry_index.js"></script> - - <!-- mod16 --> - </div> - </div> - <!-- part-d end --> - <div class="blank-cont" style="height:18px"></div> - - <!-- part-e begin --> - <div class="part-e uni-blk" tab-type="tab-wrap" tab-data="touch=0"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"><p> - <span tab-type="tab-nav" class="no-bl selected"><a href="http://photo.sina.com.cn/" target="_blank">ÎÒ°®¿´Í¼</a></span> - <span tab-type="tab-nav" id="SI_Scroll_Guess_Trigger" style="">²ÂÄãϲ»¶</span> - <span tab-type="tab-nav" id="SI_Scroll_WB_Trigger" style="display:none;"><a href="http://weibo.com/" target="_blank">΢²©ÈÈͼ</a></span> - </p></div> - <span class="t-guide" id="SI_IP_MT_9"></span> - </div> - <div class="blank-cont" style="height:20px"></div> - <div class="part-econt"> - <div tab-type="tab-cont" data-sudaclick="blk_kantu_all" blkclick="auto_nav" blktitle="ÎÒ°®¿´Í¼"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap"> - - <div class="scroll-item" data-sudaclick="blk_kantu_news"> -<!-- publish_helper name='ÐÂÎÅ£¨ÈÕ³££©' p_id='30' t_id='97' d_id='3' --> -<a href="http://slide.news.sina.com.cn/w/slide_1_2841_85583.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U10611P30DT20150618085209.jpg" width="198" height="132" /> - <span class="scroll-txt">¿ÏÄáÑÇÏÖÄÐÓÃÕê²Ù´ø ÉÏËø·ÀɧÈÅ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_sports"> -<!-- publish_helper name='ÌåÓýͼ£¨ÈÕ³££©' p_id='30' t_id='101' d_id='4' --> -<a href="http://slide.sports.sina.com.cn/k/slide_2_57057_83550.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U6604P30DT20150618094928.jpg" width="198" height="132" /> - <span class="scroll-txt">µã½«£ºÀú½ìNBA×ܾöÈüFMVP</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_ent"> -<!-- publish_helper name='ÓéÀÖͼ£¨°ËØÔ£©' p_id='30' t_id='100' d_id='3' --> -<a href="http://slide.ent.sina.com.cn/star/w/slide_4_704_112277.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U8551P30DT20150618103651.jpg" width="198" height="132" /> - <span class="scroll-txt">±ß²ß×·µ¿»á½¯Ð¡º­ÂäÀáÇéÐ÷ʧ¿Ø</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_mil"> -<!-- publish_helper name='¾üÊÂͼ' p_id='30' t_id='107' d_id='2' --> -<a href="http://slide.mil.news.sina.com.cn/k/slide_8_68162_36309.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0616/U10553P30DT20150616115148.jpg" width="198" height="132" /> - <span class="scroll-txt">èÉÁúÊ×´ÎÁÁÏà°ÍÀ躽չ²¢±íÑÝ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_history"> -<!-- publish_helper name='Àúʷͼ' p_id='30' t_id='121' d_id='9' --> -<a href="http://slide.history.sina.com.cn/y/slide_61_40602_51700.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11647P30DT20150618092220.jpg" width="198" height="132" /> - <span class="scroll-txt">ÆƱùÖ®Âãº1972ÄêÄá¿ËËɷûª</span> - </a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_news2"> -<!-- publish_helper name='ÐÂÎÅ£¨Ô­´´£©' p_id='30' t_id='97' d_id='8' --> -<a href="http://slide.news.sina.com.cn/j/slide_1_45272_85404.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U10611P30DT20150618085120.jpg" width="198" height="132" /> - <span class="scroll-txt">¼ÇÒ䣺Öйú³ö×â³µ¡°·Ý¶ùÇ®¡±±äǨʷ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_sports2"> -<!-- publish_helper name='ÌåÓýͼ£¨Ã÷ÐÇ£©' p_id='30' t_id='101' d_id='13' --> -<a href="http://slide.sports.sina.com.cn/g/slide_2_730_83546.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U6604P30DT20150618095020.jpg" width="198" height="132" /> - <span class="scroll-txt">ÐÔ¸ÐÑ¡ÃÀ¹Ú¾üÁ¦Í¦Ã·Î÷</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_ent2"> -<!-- publish_helper name='ÓéÀÖͼ£¨Ã÷ÐÇ£©' p_id='30' t_id='100' d_id='7' --> -<a href="http://slide.ent.sina.com.cn/tv/h/slide_4_704_112226.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U9988P30DT20150617182208.jpg" width="198" height="132" /> - <span class="scroll-txt">¡¶È¨Á¦µÄÓÎÏ·¡·ÃâËÀÃûµ¥´ó²Â²â£¡</span> - </a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_astro"> -<!-- publish_helper name='ÐÇ×ùͼ' p_id='30' t_id='120' d_id='2' --> -<a href="http://slide.astro.sina.com.cn/slide_52_42283_32893.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0617/U7132P30DT20150617184653.gif" width="198" height="132" /> -<span class="scroll-txt">12ÐÇ×ùºÝÓôÃÆ</span></a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_tech"> -<!-- publish_helper name='¿Æ¼¼Í¼' p_id='30' t_id='103' d_id='8' --> -<a href="http://slide.tech.sina.com.cn/d/slide_5_453_60814.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U2727P30DT20150617090629.jpg" width="198" height="132" /> - <span class="scroll-txt">Ï¡ÓÐÒÁÀçÊóÍÃÒòýÌ屨µÀÃæÁÙÃð¾ø</span> - </a> - </div> - - <div class="scroll-item" data-sudaclick="blk_kantu_auto"> -<!-- publish_helper name='Æû³µÍ¼' p_id='30' t_id='102' d_id='5' --> - - <a href="http://photo.auto.sina.com.cn/um/tuji/18214/" target="_blank" suda-uatrack="key=woaikantu_auto&value=woaikantu_auto1"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U4982P30DT20150618142426.jpg" width="198" height="132" /> - <span class="scroll-txt">À×ŵ¸ß¶Ë¿ç½çÂÃÐгµ Áé¸ÐÀ´×Ô·É»ú</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_blog"> -<!-- publish_helper name='²©¿Íͼ' p_id='30' t_id='105' d_id='3' --> -<a href="http://blog.sina.com.cn/lm/pic/" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U8214P30DT20150618095845.jpg" width="198" height="132" /> - <span class="scroll-txt">ÐüÔÚ¾ø±ÚÉϵIJ£Á§Õ»µÀ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_eladies"> -<!-- publish_helper name='Å®ÐÔͼ' p_id='30' t_id='110' d_id='4' --> -<a href="http://fashion.sina.com.cn/2015-06-18/0727/doc-ifxczqap4213453.shtml" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U5924P30DT20150618095551.jpg" width="198" height="132" /> - <span class="scroll-txt">¾Ý˵µÁĹ±Ê¼ÇºÃ¿´µÄÖ»ÓÐÑÕÖµ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_edu"> -<a href="http://slide.edu.sina.com.cn/slide_11_611_28256.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U5539P30DT20150618083421.jpg" alt="Öйú×îÃÀУ»¨ÐãÃÀͯÑÕ" width="198" height="132" /> - <span class="scroll-txt">Öйú×îÃÀУ»¨ÐãÃÀͯÑÕ</span> - </a> - </div> - <div class="scroll-item" data-sudaclick="blk_kantu_collection"> -<a href="http://slide.collection.sina.com.cn/slide_26_17348_36347.html" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U5083P30DT20150618092240.jpg" width="198" height="132" /> - <span class="scroll-txt">»Ø¹ËÁξ²ÎÄÉúǰ˲¼ä</span> - </a> - </div> - - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L" suda-uatrack="key=index_new_pic&value=i_love_pic_change"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R" suda-uatrack="key=index_new_pic&value=i_love_pic_change"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists"> - <span class="cur"></span> - <span></span> - </div> - </div> - <div tab-type="tab-cont" style=""> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap scroll-pic-guess-wrap" id="SI_Scroll_Guess_Wrap" list-length ="10" item-length="16"> - <p class="loading scroll-loading"></p> - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Guess_Arr_L" suda-uatrack="key=index_picguess&value=change"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Guess_Arr_R" suda-uatrack="key=index_picguess&value=change"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Guess_Dot_Lists"> - <span class="cur"></span> - <span></span> - </div> - </div> - - <div tab-type="tab-cont" data-sudaclick="blk_weibopic_all" blkclick="auto_nav" blktitle="΢²©ÈÈͼ"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap1"> -<!-- -{weibo_΢²©ÈÈͼ} ---> - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L1" suda-uatrack="key=index_new_pic&value=weibo_pic_change"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R1" suda-uatrack="key=index_new_pic&value=weibo_pic_change"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists1"> - <span class="cur"></span> - <span></span> - </div> - </div> - - </div> - </div> - <script type="text/javascript"> - jsLoader({ - name: 'shm', - callback: function() { - SHM.register('home.custEvent.secondpage.fire', function($) { - $.evt.custEvent.fire($, 'secondPageEnd'); - var eventType = 'mouseover'; - var hasTouch = (typeof(window.ontouchstart) !== 'undefined'); - if (hasTouch) { - eventType = 'touchstart'; - } - var wbTrigger = $.E('SI_Scroll_WB_Trigger'); - var guessCont = $.E('SI_Scroll_Guess_Wrap'); - var wbWrap = $.E('SI_Scroll_Wrap1'); - var guessWrap = guessCont.parentNode.parentNode; - $.evt.addEvent(wbTrigger, eventType, function() { - if (typeof guessWrap !== 'undefined' && guessWrap) { - guessWrap.style.display = 'none'; - } - var imgs = wbWrap.getElementsByTagName('img'); - if(imgs&&imgs.length>0){ - for (var i = imgs.length - 1; i >= 0; i--) { - var img = imgs[i]; - var src = img.getAttribute('data-src'); - if(src){ - img.src=src; - img.removeAttribute('data-src'); - } - }; - } - }); - }); - //²âÊÔ²ÂÄãϲ»¶µÄµÇ¼ - } - }); - - jsLoader({ - name : 'shm', - callback : function() { - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "SI_Scroll_Wrap"; //ÄÚÈÝÈÝÆ÷ID - focusScroll.dotListId = "SI_Scroll_Dot_Lists";//µãÁбíID - focusScroll.dotClassName = "";//µãclassName - focusScroll.dotOnClassName = "cur";//µ±Ç°µãclassName - focusScroll.listType = "";//ÁбíÀàÐÍ(number:Êý×Ö£¬ÆäËüΪ¿Õ) - focusScroll.listEvent = "onmouseover"; //Çл»Ê¼þ - focusScroll.frameWidth = 1000;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 1000; //·­Ò³¿í¶È - focusScroll.upright = false; //´¹Ö±¹ö¶¯ - focusScroll.speed = 10; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - - var focusScroll1 = new ScrollPic(); - focusScroll1.scrollContId = "SI_Scroll_Wrap1"; //ÄÚÈÝÈÝÆ÷ID - focusScroll1.dotListId = "SI_Scroll_Dot_Lists1";//µãÁбíID - focusScroll1.dotClassName = "";//µãclassName - focusScroll1.dotOnClassName = "cur";//µ±Ç°µãclassName - focusScroll1.listType = "";//ÁбíÀàÐÍ(number:Êý×Ö£¬ÆäËüΪ¿Õ) - focusScroll1.listEvent = "onmouseover"; //Çл»Ê¼þ - focusScroll1.frameWidth = 1000;//ÏÔʾ¿ò¿í¶È - focusScroll1.pageWidth = 1000; //·­Ò³¿í¶È - focusScroll1.upright = false; //´¹Ö±¹ö¶¯ - focusScroll1.speed = 10; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll1.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll1.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll1.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll1.circularly = true; - focusScroll1.initialize(); //³õʼ»¯ - - function $(id){ - return document.getElementById(id) || null; - } - - function attachEvent(obj, evt, func, eObj) { - eObj = !eObj ? obj : eObj; - if(obj.addEventListener) { - obj.addEventListener(evt , func, false); - } else if(eObj.attachEvent) { - obj.attachEvent('on' + evt, func); - } - } - - function getRandom(obj) { - var max = obj.pageLength - 1; - var min = 0; - var randomNum = Math.round(Math.random()*(max - min) + min); - obj.pageTo(randomNum); - } - - $('SI_Scroll_Arr_L').onmousedown = function(){ - focusScroll.pre(); - return false; - } - $('SI_Scroll_Arr_R').onmousedown = function(){ - focusScroll.next(); - return false; - } - - $('SI_Scroll_Arr_L1').onmousedown = function(){ - focusScroll1.pre(); - return false; - } - $('SI_Scroll_Arr_R1').onmousedown = function(){ - focusScroll1.next(); - return false; - } - - getRandom(focusScroll); - - attachEvent($('SI_Scroll_Dot_Lists'),'mouseover',function(event){ - var tar = event.target || event.srcElement; - if(tar.tagName == 'SPAN'){ - try{ - _S_uaTrack("index_new_pic", "i_love_pic_change_red_point"); - }catch(e){ - - } - } - }); - } - }); - </script> - <!-- part-e end --> - - <div class="blank-cont" style="height:10px"></div> - <!-- part-g begin --> - - <div class="part-g clearfix"> - <div class="part-g-l"> - <!-- mod17 --> - <div class="mod-17"> - <div class="tit02 tit04"> - <h3><a href="http://blog.sina.com.cn/lm/search/class/" target="_blank">²©Ö÷¶©ÔÄ</a></h3> - <a href="http://blog.sina.com.cn/lm/search/class/" class="more" target="_blank" style="border-right:0px;">¸ü¶à&gt;&gt;</a> -<!-- -<a href="http://zhuanlan.sina.com.cn/" class="bz-order" target="_blank"><i></i></a> ---> - </div> - <div class="mod17-cont"> - <ul class="list-b" data-sudaclick="blk_blog_dy" blkclick="auto_nav" blktitle="²©Ö÷¶©ÔÄ"> -<!-- publish_helper name='²©Ö÷¶©ÔÄ' p_id='30' t_id='105' d_id='2' --> -<li><a href="http://blog.sina.com.cn/s/blog_54648dbe0102wf27.html?tj=1" target="_blank">¸ß·£ºÖ÷³ÖÈËÂí±ó±»·£ºÎ±Ø²»Í´¿ì</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_4949b3d50102vnvm.html?tj=1" target="_blank">²éСÐÀ£ºÖÐÎÄÊÇÏã¸Û¹ú¼ÊѧУµÚ¶þÓïÑÔ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_43e6e0b00102vo41.html?tj=1" target="_blank">¶­¿Ëƽ£ºÀ±²»ÊÇζµÀ¶øÊÇÒ»ÖÖÍ´¾õ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_d7b481510102vmkg.html?tj=1" target="_blank">ÓμíÆÒÕ¯Îâ¸ç¿ßµÄʵÓù¥ÂÔ(ͼ)</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_474edc500102vsue.html?tj=1" target="_blank">³±°×£º¡°ËÄ´¨Ò½¿Æ´óѧ¡±¸ÄÃû·ç²¨</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_ec08dcae0102vfhk.html?tj=1" target="_blank">¶ËÎçÈý±¦Ö®×ÔÖÆÁ÷ÓÍÏÌѼµ°(×éͼ)</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_4b23705a0102vj97.html?tj=1" target="_blank">´òÔìÃ÷ÐÇ×î°®µÄ¼¦Èâ¼õ·Ê²Í(×éͼ)</a></li> - </ul> - </div> - </div> - <!-- mod17 --> - <div class="blank-cont" style="height:10px"></div> - <!-- mod18 --> - <div class="mod-18"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 2ÂÖ²¥°´Å¥03¹ã¸æ begin --> -<div id="ad_46011" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046011"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 2ÂÖ²¥°´Å¥03¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod18 --> - </div> - <div class="part-g-mr clearfix"> - <div class="part-g-m"> - <!-- mod19 --> - <div class="uni-blk mod-19" id="SI_Order_E" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://blog.sina.com.cn/" target="_blank">²©¿Í</a></span> - <span tab-type="tab-nav" style="display:none;"><a href="http://blog.sina.com.cn/lm/rank/" target="_blank">¾«Ñ¡</a></span> - <span tab-type="tab-nav" style="display:none;"><a href="http://weibo.com/" target="_blank">΢²©</a></span> - </div> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Blog"> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_blog_search&value=blog_search">ËÑË÷</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" method="GET" action="http://search.sina.com.cn/" onsubmit="return blogsearch(this,'blog')"> - <select id="SI_Slt_03" name="by"> - <option value="all" selected="selected">È«ÎÄ</option> - <option value="title">±êÌâ</option> - <option value="nick">×÷Õß</option> - <option value="tag">±êÇ©</option> - </select> - <input type="hidden" name="c" value="blog"> - <input type="hidden" name="range" value="article"> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" onblur="if(this.value==''){this.value='ÇëÊäÈë²éѯ´Ê'}" onfocus="if(this.value=='ÇëÊäÈë²éѯ´Ê'){this.value=''}" value="ÇëÊäÈë²éѯ´Ê" name="q"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_blog_search&value=blog_search_click"/> - </a> - </form> - </div> - </div> - </div> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_3"></li> - </ul> - - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_blog_1" blkclick="auto_nav" blktitle="²©¿Í"> -<!-- publish_helper name='²©¿ÍÇø¿é' p_id='30' t_id='105' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<div class="uni-blk-pic" id="blogPic0"><a href="http://blog.sina.com.cn/s/blog_518cc2930102vo6t.html?tj=1" target="_blank"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0617/U1748P30DT20150617162750.jpg" width="105" height="70" /> - <span>½ÖÅı±¾©ÇåÁ¹ÃÀÅ®</span></a> - -<!-- newitemÌæ»»±ê¼Ç0 --></div><ul class="uni-blk-list01 list-a " id="bloglist0"><li><a href="http://blog.sina.com.cn/" target="_blank">¡°··Âô¶ùͯһÂÉÅÐËÀÐÌ¡±Ôõ²»¿¿Æ×</a></li> - <li><a href="http://blog.sina.com.cn/s/blog_8db3ce3d0102wgpd.html?tj=1" target="_blank">Ò×ÏÜÈÝ£ºµ±Ç°ÖйúA¹ÉÔõ±©ÕDZ©µø</a></li> - <li><a target="_blank" href="http://blog.sina.com.cn/s/blog_477614640102vilt.html?tj=1">ÑîÀ½£ºÖ£¾ûÍõ½Ü×ÔÆز»ÎªÈËÖªÍùÊÂ</a></li> - <li><a href="http://blog.sina.com.cn/s/blog_4fc500400102vid3.html?tj=1" target="_blank">±±´ó˶ʿ×ö×°ÐÞ¹¤ÊÇÈ˲ÅÀË·ÑÂð£¿</a></li> -<!-- newitemÌæ»»±ê¼Ç1 --></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a " id="bloglist1"> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_496489160102vst0.html?tj=1">ÒÔʲô×ËÊÆÓ­½ÓÓñÁÖ¹·Èâ½ÚÖ®Õù</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_61b3435e0102vriq.html?tj=1">ÀÖÊÓºÍСÃ×µ½µ×³³Ê²Ã´</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_6011cb260102vl0z.html?tj=1" target="_blank">°²±¶·òÆÞ¡°·ò³ª¸¾²»Ë桱ÃØÃÜ</a> <a href="http://blog.sina.com.cn/s/blog_6dd414ed0102vr48.html?tj=1" target="_blank">Íâ½»²¿ÐÂÎÅ·¢ÑÔÈËÏàËƵã</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_48631e860102vnyz.html?tj=1">ÖйúÄÄ×ù³ÇÊоÓÃñ×î°®ÔĶÁ</a> <a href="http://blog.sina.com.cn/s/blog_4d77291f0102vhvw.html?tj=1" target="_blank">Ô¬ºêµÀ£ºÍíÃ÷Ê¿ÈË×ÝÀÖÉú»î</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_573c3a4d0102vkoa.html?tj=1" target="_blank">´ÏÃ÷Å®È˲»ÒªÖص¸¾ÓÀï·òÈ˸²ÕÞ</a> <a href="http://blog.sina.com.cn/s/blog_82b859870102wde7.html?tj=1" target="_blank">¼Ò³¤³£·¸µÄÓý¶ùÎóÇø</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/lm/ruiblog/">ÈÕ±¾Å®Ã÷ÐÇΪºÎ²»Ô¸¼ÞÍÁºÀ</a> <a target="_blank" href="http://blog.sina.com.cn/lm/lz/#sh">ΪºÎÄã×ÜÍÏƽ¾ù¹¤×ʵĺóÍÈ</a></li> -<li><a href="http://blog.sina.com.cn/lm/lz/#rw" target="_blank">Ò¶ÓÀÁÒ£ºÎÒÔŲ́Íå²éÔÄ´÷óÒµµ°¸</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_5ef43b490102vnj3.html?tj=1">°ÄÖÞÍÁÖøÉñÃرíÑÝ(ͼ)</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_54a625bf0102vtwz.html?tj=1" target="_blank">ÎÄâù£ºÈÃËÉ»¨µ°²»Õ³µ¶µÄÇÏÃÅ</a> <a href="http://blog.sina.com.cn/s/blog_621571b70102vje5.html?tj=1" target="_blank">×îÊʺϺ£ÊÄɽÃËÖ®µØ(ͼ)</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_4be8c9b30102vpnt.html?tj=1">ÓéÀÖȦǰÈÎÃǵİ®ºÞÇé³ð</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_ea61066a0102vvd1.html?tj=1">â¹ų̂¡¶°Ö°Ö3¡·Ð¦µã²»Óóî</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_61631ef60102vnly.html?tj=1" target="_blank">Òª²»ÒªÀë»éÖ»ÐèºâÁ¿Ò»¸öÎÊÌâ</a> <a href="http://blog.sina.com.cn/s/blog_4cb10b1c0102w3e8.html?tj=1" target="_blank">ÔõÍü¼ÇÍøÂçÓÎÏ·ÀïµÄÄÐÈË</a></li> - -<!-- newitemÌæ»»±ê¼Ç2 --> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_e91b9fb60102vuzp.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¹ÉÊн׶ÎÐÔµ÷ÕûºóÔõô²Ù×÷</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_43e6e0b00102vntq.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ôÕ×Ó×îÔçºÍÇüԭûһëǮ¹Øϵ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_699132e60102voup.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¡¶»¨Ç§¹Ç¡·Ê¥Ä¸ÂêÀöËÕ´«Ææ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_48c2bed00102vpnm.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ºÚ辯²ìÄܸϳ¬»úÆ÷èÂð</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_ea61066a0102vvd1.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">¡¶°Ö°Ö3¡·¿¿Ê²Ã´À­¸ßÊÕÊÓÂÊ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_477614640102vilt.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">Ö£¾ûÍõ½Ü²»ÎªÈËÖªµÄ¹ÊÊÂ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_5ef43b490102vnj3.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">À¶É½ÉñÃØÈÈÀ±µÄ°ÄÖÞÍÁÖø±íÑÝ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_621571b70102vje5.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">Òâ´óÀûÀËÂþÎåÓæ´åÈ«¹¥ÂÔ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_43e6e0b00102vo41.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">À±²»ÊÇζµÀ¶øÊÇÒ»ÖÖÍ´¾õ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_72d0cc2e0102vydz.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ÃÀζûÉÌÁ¿µÄСÁãʳը¶àζÓã</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_48dcdda20102vngm.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">³ÔÒâ´óÀû²Ë¿´À­Ë¹Î¬¼Ó˹¡°³¾¾í¡±</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_6ab1f9f80102vl79.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ÃÔʧÔÚ°ÄÖÞÃÀÀöº£µº</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_470bc6dd0102voc1.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">Ò¶ÓÀÁÒ:ÎÒÔŲ́Íå²éÔÄ´÷óÒµµ°¸</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_67f297b00102vx87.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ÃÀ¹úµØ·½·¨¹ÙµÄÌôÑ¡</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_476f46d50102vpe0.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">ÕÅÌúÁÖÒ»¸ö²¥ÖÖÕßµÄÉú»î</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_635c86d50102wcre.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">º«ÐŲ»Ôì·´ÒòΪÁõ°îÊÇůÄÐ</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_536e70930102vkex.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">άÃØгèÏËÑüÃÀÐض¼ÔÚÕâ¶ù</a> -<a class="blogNewItem" style="display: none" href="http://blog.sina.com.cn/s/blog_13762eb7d0102vybd.html?tj=1" target="_blank" suda-uatrack="key=www_blog_count&value=1">СÃ×ÓëÀÖÊÓ˺µ½Éî´¦</a> - - </ul> - - <ul class="uni-blk-list02 list-a "> -<li><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTU2NQ%3D%3D&sign=d4d4b3b820972b68&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fboke1%2F%3Ftel%3D17%26src%3D0017" target="_blank">Ãî:¸ßѪ֬µÄÈË,³ÔÕâ¸öÎȽµ</a> <a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTI1Ng%3D%3D&sign=6ece5959ef4f303d&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fboke-2b%2F"target="_blank">ÄÐÈËÇ°ÁÐÏÙ×ÔÎÒÁÆ·¨:ÊÓƵ</a></li> - </ul> - - </div> - -<script> - jsLoader({ - name: 'shm', - callback: function() { - - //var guessUrl = 'http://www.sina.com.cn/js/index/96/home.recommender.min.js'; - - var guessUrl = 'http://www.sina.com.cn/js/index/96/home.recommender.2014.min.js'; - -/* - var sguid = SHM.util.cookie.getCookie('SINAGLOBAL'); - if(typeof sguid == 'string'){ - lastNum = sguid.charAt(sguid.length - 1, 1); - if(lastNum == '8' || lastNum == '1' || lastNum == '4'){ - guessUrl = 'http://www.sina.com.cn/js/index/96/home.recommender.2014.min.js'; - } - } -*/ - - jsLoader({ - url : guessUrl, - callback : function () { - var Store = window.___CrossDomainStorage___; - Store.ready(function(st){ - //renderLinks(30, 'ud.fd.www.blogStorage0', 'bloglist0', 'blogNewItem', false, st); - renderLinks(50, 'ud.fd.www.blogStorage1', 'bloglist1', 'blogNewItem', false, st); - //renderLinks(50, 'ud.fd.www.blogStorage2', 'blogPic0', 'blogNewPic', true, st); - }); - } - }); - } - }); -</script> - -<script src="http://www.sina.com.cn/js/79/2013/0717/fix.js" charset="utf-8"></script> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_blog_2" blkclick="auto_nav" blktitle="¾«Ñ¡"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¾«Ñ¡Çø¿é' p_id='30' t_id='105' d_id='4' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/s/blog_493258a80102vib4.html?tj=1" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0518/U8214P30DT20150518105256.jpg" width="105" height="70" /> -<span>Ô¼¾»¨¿ª</span></a><ul class="uni-blk-list01 list-a"> -<li><a href="http://blog.sina.com.cn/s/blog_5edca6f40102vocb.html?tj=1" target="_blank">Âí¶úɽ¶Å¾é»¨º£ç²Àö¾°É«</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_5fd993e20102vmvx.html?tj=1" target="_blank">ÏÖʵÉú»îÖÐÇÚÀ͵Ļݰ²Å®</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_6b99ba750102w102.html?tj=1" target="_blank">ʵÅÄÄÏ°ëÇòСÕò×íÃÀÇïÌì</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_49aa2c640102vl1o.html?tj=1" target="_blank">ÐÐÉãÂÞȪ¹ÅÕòµÄ²×É£ËêÔÂ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://blog.sina.com.cn/s/blog_e91b9fb60102vuzp.html?tj=1" target="_blank">¹ÉÊн׶ÎÐÔµ÷ÕûºóÔõô²Ù×÷</a> <a href="http://blog.sina.com.cn/s/blog_43e6e0b00102vntq.html?tj=1" target="_blank">ôÕ×Ó×îÔçºÍÇüԭûһëǮ¹Øϵ</a></li><li><a href="http://blog.sina.com.cn/s/blog_699132e60102voup.html?tj=1" target="_blank">¡¶»¨Ç§¹Ç¡·Ê¥Ä¸ÂêÀöËÕ´«Ææ</a> <a href="http://blog.sina.com.cn/s/blog_48c2bed00102vpnm.html?tj=1" target="_blank">ºÚ辯²ìÄܸϳ¬»úÆ÷èÂð</a></li><li><a href="http://blog.sina.com.cn/s/blog_ea61066a0102vvd1.html?tj=1" target="_blank">¡¶°Ö°Ö3¡·¿¿Ê²Ã´À­¸ßÊÕÊÓÂÊ</a> <a href="http://blog.sina.com.cn/s/blog_477614640102vilt.html?tj=1" target="_blank">Ö£¾ûÍõ½Ü²»ÎªÈËÖªµÄ¹ÊÊÂ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_5ef43b490102vnj3.html?tj=1" target="_blank">À¶É½ÉñÃØÈÈÀ±µÄ°ÄÖÞÍÁÖø±íÑÝ</a> <a href="http://blog.sina.com.cn/s/blog_621571b70102vje5.html?tj=1" target="_blank">Òâ´óÀûÀËÂþÎåÓæ´åÈ«¹¥ÂÔ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_43e6e0b00102vo41.html?tj=1" target="_blank">À±²»ÊÇζµÀ¶øÊÇÒ»ÖÖÍ´¾õ</a> <a href="http://blog.sina.com.cn/s/blog_72d0cc2e0102vydz.html?tj=1" target="_blank">ÃÀζûÉÌÁ¿µÄСÁãʳը¶àζÓã</a></li><li><a href="http://blog.sina.com.cn/s/blog_48dcdda20102vngm.html?tj=1" target="_blank">³ÔÒâ´óÀû²Ë¿´À­Ë¹Î¬¼Ó˹¡°³¾¾í¡±</a> <a href="http://blog.sina.com.cn/s/blog_6ab1f9f80102vl79.html?tj=1" target="_blank">ÃÔʧÔÚ°ÄÖÞÃÀÀöº£µº</a></li> - -<li><a href="http://blog.sina.com.cn/s/blog_470bc6dd0102voc1.html?tj=1" target="_blank">Ò¶ÓÀÁÒ:ÎÒÔŲ́Íå²éÔÄ´÷óÒµµ°¸</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_67f297b00102vx87.html?tj=1">ÃÀ¹úµØ·½·¨¹ÙµÄÌôÑ¡</a></li><li><a href="http://blog.sina.com.cn/s/blog_476f46d50102vpe0.html?tj=1" target="_blank">ÕÅÌúÁÖÒ»¸ö²¥ÖÖÕßµÄÉú»î</a> <a href="http://blog.sina.com.cn/s/blog_635c86d50102wcre.html?tj=1" target="_blank">º«ÐŲ»Ôì·´ÒòΪÁõ°îÊÇůÄÐ</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_536e70930102vkex.html?tj=1">άÃØгèÏËÑüÃÀÐض¼ÔÚÕâ¶ù</a> <a href="http://blog.sina.com.cn/s/blog_13762eb7d0102vybd.html?tj=1" target="_blank">СÃ×ÓëÀÖÊÓ˺µ½Éî´¦</a></li> - </ul> - </textarea> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_weibo_2" blkclick="auto_nav" blktitle="΢²©"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- -{weibo_΢²©Çø¿é} ---> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod19 --> - </div> - <div class="part-g-r"> - <!-- mod20 --> - <div class="uni-blk mod-19" id="SI_Order_F" tab-type="tab-wrap" struc="1-8"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://book.sina.com.cn/" target="_blank">¶ÁÊé</a></span> - <span tab-type="tab-nav" style="display:none;"><a href="http://vip.book.sina.com.cn/book_lib.php?lib=001&order=fwc&sta=&pub=&dpc=1" target="_blank">С˵</a></span> - </div> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - - <div class="order-search order-search-fin SC_Order_Hidden" id="SI_Search_Book" style=""> - <a href="javascript:;" class="order-seat SC_Search_Btn" suda-uatrack="key=index_new_book_search&value=book_search">ËÑÊé</a> - <div class="sea-out-win SC_Search_Win" style="display:none"> - <em class="sow-arr"></em> - <div class="sow-cont"> - <div class="sow-form clearfix"> - <form target="_blank" method="GET" action="http://vip.book.sina.com.cn/s.php" onsubmit="return booksearch(this)"> - <select id="SI_Slt_04" name="s_type"> - <option value="" selected="selected">Ä£ºý</option> - <option value="1">ÊéÃû</option> - <option value="2">×÷Õß</option> - <option value="3">³ö°æÉç</option> - </select> - <div class="sow-ipt-w"> - <input type="text" class="sow-ipt" onblur="if(this.value==''){this.value='ÇëÊäÈë²éѯ´Ê'}" onfocus="if(this.value=='ÇëÊäÈë²éѯ´Ê'){this.value=''}" value="ÇëÊäÈë²éѯ´Ê" name="k"/> - </div> - <a href="javascript:;" class="sow-sub-wrap"> - <input type="submit" class="sow-sub" value="²éѯ" suda-uatrack="key=index_new_book_search&value=book_search_click" /> - </a> - </form> - </div> - </div> - </div> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_4"></li> - </ul> - - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_book_1" blkclick="auto_nav" blktitle="¶ÁÊé"> -<!-- publish_helper name='¶ÁÊéÇø¿é' p_id='30' t_id='106' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://book.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U11368P30DT20150618105830.jpg" width="105" height="70" /> - - <span>±»ÒÅÍüµÄÎÄѧ´óʦ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a target="_blank" href="http://book.sina.com.cn/top201504/">ÐÂÀËÖйúºÃÊé°ñ2015Äê4Ô°ñ½ÒÏþ</a></li> -<li><a target="_blank" href="http://book.sina.com.cn/news/c/2015-06-18/0853748804.shtml">ÓÚµ¤£ºÖйú¸¸Ç×ʧȥ¾«ÉñÒýÁì¼ÛÖµ</a></li> -<li><a target="_blank" href="http://book.sina.com.cn/news/c/2015-06-18/0914748807.shtml">ÁùСÁäͯ£ºÃûÖø¿É´´Ðµ«Îð¶ñ¸ã</a></li> -<li><a target="_blank" href="http://book.sina.com.cn/news/c/2015-06-18/0916748808.shtml">ÕÅÏÍÁÁÖø×÷¡¶ÁéÓëÈâ¡·½«ÅĵçÊÓ¾ç</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://book.sina.com.cn/255/2014/0121/75.shtml" target="_blank">ÎÄ»¯</a>| -<a href="http://book.sina.com.cn/news/c/2015-06-18/0926748809.shtml" target="_blank">¡¶µÁĹ±Ê¼Ç ¡·²îÆÀÈç³± ÄÏÅÉÈýÊ壺¶¼°ÑÎÒ¿´ÉµÁË</a></li><li><a href="http://book.sina.com.cn/255/2014/0120/73.shtml" target="_blank">ÊéÆÀ</a>| -<a href="http://book.sina.com.cn/news/review/w/2015-06-17/0926748552.shtml" target="_blank">¡¶¿à¼Ë»ØÒ伡·£º²¢·ÇËùÓеİ®¶¼ÊÇ¿íÀ«µÄº£Ñó</a></li> - -<li><a href="http://book.sina.com.cn/zl/" target="_blank">רÀ¸</a>| -<a href="http://book.sina.com.cn/zl/mingjia/2015-05-12/16461017.shtml" target="_blank">ËûÊÊÓ¦Á˶ÁÕßµÄÐèÒª¡ª¡ªÇ³ÒéÍô¹úÕæÓëÊ«¸èÔĶÁ</a></li> - -<li><a href="http://book.sina.com.cn/zl/" target="_blank">רÀ¸</a>| -<a href="http://book.sina.com.cn/zl/jiaodian/2015-05-26/17281018.shtml" target="_blank">ÌÆé¦:Óëʱ¼äÍæζ¡ª¡ª¹ØÓÚÎÄѧʷÉϵÄÈÕ¼ÇÓëÐżþ</a></li> - -<li><a href="http://book.sina.com.cn/excerpt/" target="_blank">ÊéÕª</a>| -<a href="http://book.sina.com.cn/excerpt/sz/rw/2015-05-26/1545743885.shtml" target="_blank"> -°ÂÆÕÀ­£º»¶ÓäÊÇÖÖÓлØÀ¡µÄÄÜÁ¿</a> -<a href="http://book.weibo.com/book/play/5347244-10256715.html" target="_blank">³¬Ô½¿ìÀÖÔ­Ôò</a></li> - -<li><a href="http://book.sina.com.cn/excerpt/" target="_blank">ÊéÕª</a>| -<a href="http://book.sina.com.cn/excerpt/sz/rw/2015-05-15/1705741716.shtml" target="_blank"> -Ì©ÀÕ¸ÐÇéµÄµÚÒ»´Î¼èÄѾñÔñ</a> -<a href="http://book.weibo.com/book/play/5347448-10274656.html" target="_blank">µ±ÉñʧȥËýµÄËù°®</a></li> - -<li><a href="http://book.sina.com.cn/zthz/" target="_blank">²ß»®</a>| -<a href="http://book.sina.com.cn/zt/jiangfeng.html" target="_blank">½¯·å:ÎÒÏàÐÅÎÄѧ»á²»Ðà</a> <a href="http://book.sina.com.cn/focusmedia/2015-05-05/1101739430.shtml" target="_blank">Ê«È˵ÄÁé»êÓÀÔ¶ÊôÓÚÊ«¸è</a></li> - -<li><a href="http://book.sina.com.cn/zthz/" target="_blank">²ß»®</a>| - <a href="http://book.sina.com.cn/zt/kanghe.html" target="_blank">¿µºÕ:¹Ø¼üÔÚ·ÅÆú¿Ö¾å¡ª¡ªËüÖ»Óб仯£¬Ã»ÓÐÖÕ¼«</a></li> - -<li><a href="http://city.sina.com.cn/">³ÇÊÐ</a>| <a href="http://city.sina.com.cn/" target="_blank">ÉϺ£±©ÓêÕþÎñ΢²©¿ìËÙÓ¦¶Ô</a> <a href="http://city.sina.com.cn/focus/t/2015-06-18/103950840.html" target="_blank">¿ØÑÌÁîϽäÑÌÕß±ä¶à</a></li> - </ul> - - <ul class="uni-blk-list02 list-a"> -<li><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTQwNQ%3D%3D&sign=be249e2a53b70f5b&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fdushu-1a%2F" target="_blank">¿ìѶ</a>| <a -href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDU0NA%3D%3D&sign=33ec0754c8336b6d&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fdushu1%2F%3Ftel%3D17%26src%3D0017" target="_blank">Ô´Í·"³Ôµô"¸ßѪѹ£¨Í¼£©</a> <a -href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNTgwOQ%3D%3D&sign=7547d7b72cb78fec&url=http%3A%2F%2Fhealth.hehuigj.com%2Fto%2Fs%2Fdushu2%2F%3Ftel%3D17%26src%3D0017" target="_blank">²ÍºóѪÌÇ6.5¾ÍÕâô³Ô</a></li> - </ul> - - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_book_2" blkclick="auto_nav" blktitle="С˵"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- -{book_¶ÁÊé_4_С˵Çø¿é} ---> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod20 --> - </div> - </div> - </div> - <!-- part-g end --> - <div class="blank-cont" style="height:19px;"></div> - <!-- part-ip-2 --> - <span id="SI_IP_Part_2"></span> - <!-- /part-ip-2 --> - - <!-- part-i begin --> - <div class="part-i"> - -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸02¹ã¸æ begin --> -<div id="ad_43762" class="ad-banner mb25"><ins class="sinaads" data-ad-pdps="PDPS000000043762"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸02¹ã¸æ end --> -<!--_SINA_ADS_END_--> - - </div> - <!-- part-i end --> - - <!-- part-h begin --> - <div class="part-h clearfix"> - <div class="part-h-l"> - <!-- mod21 --> - <div class="mod-21 mod-02"> - <div class="tit02"> - <h3><a href="http://tech.sina.com.cn/d/photo/" target="_blank">̽Ë÷Ȥͼ</a></h3> - <div class="ed-pic-lists clearfix" id="SI_Scroll_Sdot_Lists"></div> - </div> - <div class="mod21-cont" data-sudaclick="blk_tech_dispic" blkclick="auto_nav" blktitle="̽Ë÷Ȥͼ"> - <div class="ed-pic-wrap clearfix" id="SI_Scroll_Swrap"> -<!-- publish_helper name='¿Æ¼¼Ã¿ÈÕͼƬ' p_id='30' t_id='103' d_id='6' --> -<div class="ed-pic-item"><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60862.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U2727P30DT20150618082042.jpg" width="218" height="160" /></a> -<ul class="list-b"><li><a target="_blank" href="http://slide.tech.sina.com.cn/d/slide_5_453_60862.html">·ÇÖ޺Ϸ¨á÷ÁÔ£º´óÁ¿Ò°Éú¶¯ÎïÖƳɱ걾</a></li></ul></div> - </div> - </div> - </div> - <!-- mod21 --> - <!-- mod22 --> - <div class="mod-22"> - - <div class="mod22-cont clearfix" style="padding:6px 0 6px 8px;"> - <ul class="list-b" data-sudaclick="blk_tech_dispic_list" blkclick="auto_nav" blktitle="ȤͼÁбí"> -<!-- publish_helper name='¿Æ¼¼Ì½Ë÷Ȥͼ' p_id='30' t_id='103' d_id='7' --> -<li><a target="_blank" href="http://tech.sina.com.cn/d/f/2015-06-17/doc-ifxczqan1463329.shtml">Õ溺×Ó¿´ÊÖÖ¸:ʳָ±ÈÎÞÃûÖ¸¶Ì¸üÓÐÄÐÈËζ</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-17/doc-ifxczyze9666582.shtml">º¬·úÆøÌå¶ÔÎÒÃǵ½µ×ÓÐʲôΣº¦(ͼ)</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-17/doc-ifxczqap4206563.shtml">ÈËÏз´µ¹ÈÝÒ×Éú²¡£¿ÊʶȽôÕÅÌá¸ßÃâÒßÁ¦</a></li> - -<li><a target="_blank" href="http://slide.tech.sina.com.cn/digi/slide_5_30939_60865.html">¹âÓ°Á÷ÌʵÄÇéÐ÷ ²¶×½ÈËÎï×îϸ΢µÄÉñÔÏ</a></li> - </ul> - </div> - - </div> - <!-- mod22 --> - <div class="blank-cont" style="height:10px"></div> - <!-- nmod02 --> - <div class="nmod02"> - -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 3ÂÖ²¥°´Å¥04¹ã¸æ begin --> -<div id="ad_46013" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046013"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 3ÂÖ²¥°´Å¥04¹ã¸æ end --> -<!--_SINA_ADS_END_--> - - </div> - <!-- nmod02 --> - </div> - <div class="part-h-m"> - <!-- mod23 --> - <div class="uni-blk" id="SI_Order_G" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://tech.sina.com.cn/" target="_blank">¿Æ¼¼</a></span> - <span tab-type="tab-nav"><a href="http://tech.sina.com.cn/discovery/" target="_blank">̽Ë÷</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://tech.sina.com.cn/t/4g/" target="_blank">4G</a></li> -<li><a href="http://blog.sina.com.cn/lm/tech/" target="_blank">IT²©¿Í</a></li> -<li><a href="http://tech.sina.com.cn/internet/" target="_blank">»¥ÁªÍø</a></li> -<li><a href="http://tech.sina.com.cn/zl/" target="_blank">´´Ê¼Ç</a></li> -<li><a href="http://tech.sina.com.cn/zl/post/detail/2013-04-24/pid_8274000.htm" target="_blank">Ͷ¸å</a></li> - -<li id="SI_IP_MT_5"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_tech_1" blkclick="auto_nav" blktitle="¿Æ¼¼"> -<!-- publish_helper name='¿Æ¼¼Çø¿é' p_id='30' t_id='103' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://tech.sina.com.cn/d/photo/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U2727P30DT20150618082135.gif" width="105" height="70" /> - - <span>ÏÖʵ°æ±äÐνð¸Õ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://tech.sina.com.cn/it/2015-06-18/doc-ifxefurq6211346.shtml" target="_blank">Öйúµç×ÓÉÙÊýÁìµ¼ÄÚÍâ¹´½áÌ×¹ú×Ê</a></li> - -<li><a href="http://tech.sina.com.cn/it/2015-06-18/doc-ifxefurq6126833.shtml" target="_blank">ÌØ˹À­ÔÚ»ªÏúÁ¿²»¼Ñ£ºÄ£Ê½ÔâÖÊÒÉ</a></li> - -<li><a href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxehfqi8031856.shtml" target="_blank">°¢À︻ʿ¿µÍ¶ÈíÒøÆìÏ»úÆ÷È˹«Ë¾</a></li> - -<li><a href="http://tech.sina.com.cn/t/2015-06-18/doc-ifxefurt9352981.shtml" target="_blank">ÐźÅÆÁ±ÎÆ÷ËæÒâÂòÂô ¼à¹Ü´¦Ã¤Çø</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxefurt9362535.shtml">18ËêÄк¢ÓÃ×·×ÙAppÕÒµ½¶ªÊ§ÊÖ»ú Òª»Øδ¹û±»É± </a></li> - -<li><a href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxefurt9357771.shtml" target="_blank">ÏÕÆóÍøÏúƽ̨´æ©¶´ 1700ÍòÌõ¿Í»§ÐÅÏ¢±»Ð¹Â¶</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/i/2015-06-18/doc-ifxczyze9704690.shtml">±±¾©²é½ûÉ«Ç鱩Á¦ÍøÂç³ö°æÎï46ÖÖ ´¦·£ÓÅ¿áµÈ11¼ÒÍøÕ¾</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/z/roadshow/">´´ÒµÂ·ÑÝ</a>|<a target="_blank" href="http://tech.sina.com.cn/z/roadshow-ldl/">½¡×ßÅܲ½APP&quot;ÀÖ¶¯Á¦&quot;</a> <a target="_blank" href="http://tech.sina.com.cn/i/2015-06-05/doc-icrvvrak2740010.shtml" class="linkRed">ÉϺ£Â·Ñݱ¨Ãû</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/zl/">´´Ê¼Ç</a>| <a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/it/2015-06-18/pid_8481223.htm">Oculus£ºFacebookµÄÐÂÒ»´ú¡°Ô¼ÅÚ¡±¹¤¾ß£¿</a></li> -<li><a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/i/2015-06-18/pid_8481226.htm">360˽Óл¯ÊÇΪÁË»ØA¹ÉȦǮÂð</a> <a target="_blank" href="http://tech.sina.com.cn/zl/post/detail/i/2015-06-17/pid_8481148.htm">¿Æ¼¼¹«Ë¾ÈçºÎƭɵ×ÓÇ®</a></li> - -<li><a href="http://blog.sina.com.cn/lm/tech/" target="_blank">²©¿Í</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_40345c100102vzol.html?tj=tech">´¸×ÓƾʲôÐÂÈý°åÉÏÊÐ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_54789aa40102vs3m.html?tj=tech">Å̵ã×î¾ßµß¸²Á¦Ê®´óºÚ¿Æ¼¼</a></li> - - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_tech_2" blkclick="auto_nav" blktitle="̽Ë÷"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='̽Ë÷Çø¿é' p_id='30' t_id='103' d_id='3' --> - <div class="uni-blk-bt clearfix"> -<a href="http://tech.sina.com.cn/d/photo/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U2727P30DT20150618110834.jpg" width="105" height="70" /> - - <span>°ÔÆøºÀ»ªÔ½Ò°Ì¹¿Ë</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://tech.sina.com.cn/d/a/2015-06-18/doc-ifxczyze9699185.shtml" target="_blank">ɱÊÖµÄÑÝ»¯£ºÖ©Ö붾Һ´ÓºÎ¶øÀ´£¿</a></li> - -<li><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60813.html" target="_blank">¿Æѧ¼ÒÊ×´ÎÅĵ½±±¼«ÐܳԺ£ëà(ͼ)</a></li> - -<li><a href="http://tech.sina.com.cn/d/v/2015-06-18/doc-ifxefurs2586889.shtml" target="_blank">ÄãÕæµÄÃ÷°×ÐÄÀíѧ³£Ê¶ÔÚ˵ʲôÂð</a></li> - -<li><a href="http://tech.sina.com.cn/d/f/2015-06-18/doc-ifxefurq6678703.shtml" target="_blank">Å®ÐÔ¸ü³¤ÊÙ°ÂÃشƼ¤ËØÓ°Ïì¸Éϸ°û</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://tech.sina.com.cn/d/v/2015-06-18/doc-ifxefurt9354794.shtml">ÎÒÃǵĴóÄÔ¿Õ¼ä»á±»ÓÃÍêÂð£¿ÒÅÍüÒ²ÊÇÒ»ÖÖѧϰ</a></li> - -<li><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60863.html" target="_blank">ÏÖʵ°æ±äÐνð¸Õ£º»úÆ÷È˱äË«×ùÆû³µ½öÐ輸ÃëÖÓ(GIF)</a></li> - -<li><a href="http://slide.tech.sina.com.cn/d/slide_5_453_60862.html" target="_blank">·ÇÖ޺Ϸ¨á÷ÁÔ²úÒµ£º´óÁ¿Ò°Éú¶¯Îï±»ÖƳɱ걾(×éͼ)</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/d/a/2015-06-18/doc-ifxefurq6638019.shtml">»³ÔÐĸöèÔâÃÀÓæÃñÆʸ¹ 34ֻСöèÓã²ÒËÀ¸¹ÖÐ(ͼ)</a></li><li><a target="_blank" href="http://tech.sina.com.cn/d/s/2015-06-18/doc-ifxefurs2576226.shtml">ÃÀÓ¾Ö¹ÙÔ±³ÆÈôÕæÓÐÍâÐÇÈËÓ¦ÒÑÖªÏþÈËÀà´æÔÚ(ͼ)</a></li> - -<li><a target="_blank" href="http://tech.sina.com.cn/solarimpulse/live/abu_dhabi/">ÊÀ½çÌ«ÑôÄÜ·É»úÒòÌìÆøÔ­Òò±¸½µÈÕ±¾Ãû¹ÅÎÝ</a> <a target="_blank" href="http://solarimpulse.sina.com.cn/">¹ÙÍø</a></li> - -<li><a href="http://tech.sina.com.cn/blog/image/" target="_blank">ÃÀͼ</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_69f845650102w8qd.html?tj=tech">µûӼΪ±ÜÌìµÐαװ³É¶¾Éß</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_73f3af200102vohj.html?tj=tech">°ÄÖÞöùÓãͬÀàÏà²Ð</a></li> - - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod23 --> - <div class="blank-cont" style="height:16px"></div> - <!-- mod24 --> - <div class="uni-blk" tab-type="tab-wrap" style="z-index:1"> - <div class=""> - <div class="uni-blk-t mod24-t clearfix"> - <div class="mod24-menu clearfix"> - <span class="selected" tab-type="tab-nav" style="border-left:0px;width:56px;"><a href="http://games.sina.com.cn/" target="_blank">ÓÎÏ·</a></span> - <span tab-type="tab-nav" style="width:75px;"><a href="http://games.sina.com.cn/newgame/" target="_blank">ÐÂÍøÓÎ</a></span> - <span tab-type="tab-nav" style="width:75px;"><a href="http://ka.sina.com.cn/" target="_blank">ÐÂÊÖ¿¨</a></span> - <span tab-type="tab-nav" style="width:82px;"><a href="http://games.sina.com.cn/hd.shtml" target="_blank">Óн±»î¶¯</a></span> - <span tab-type="tab-nav" style="border-right:0px; width:66px;"><a href="http://www.97973.com/" target="_blank">ÊÖÓÎ</a></span> - </div> - </div> - <div class="uni-blk-b"> -<div class="uni-blk-bt clearfix" tab-type="tab-cont" data-sudaclick="blk_youxi_1" blkclick="auto_nav" blktitle="ÓÎÏ·"> -<!-- publish_helper name='ÓÎÏ·' p_id='30' t_id='108' d_id='2' --> -<a href="http://games.sina.com.cn/" target="_blank" class="uni-blk-pic"> <img src="http://i1.sinaimg.cn/home/2015/0618/U2456P30DT20150618114514.jpg" width="105" height="70" /> <span>ÃÀÍÈÅ®ÐÇ´úÑÔÓÎÏ·</span> </a> -<ul class="uni-blk-list01 list-a"> - -<li><a href="http://games.sina.com.cn/" target="_blank">ÔÙսȼÉÕ¾üÍŠħÊÞ6.2ÏÂÖÜËÄÉÏÏß</a></li> -<li><a href="http://games.sina.com.cn/y/n/2015-06-17/fxczqap4201308.shtml" target="_blank">¡¶Ïɽ£ÆæÏÀ´«¡·Ò»´úPC°æÒÆÖ²ÊÖ»ú</a></li> -<li><a href="http://www.97973.com/moxw/2015-06-18/ifxczyze9704479.shtml" target="_blank">¡¶»ð¾æÖ®¹â¡·Òƶ¯°æ½ØͼÊ×´ÎÆعâ</a></li> -<li><a href="http://games.sina.com.cn/g/g/2015-06-18/fxczyze9706967.shtml" target="_blank">Å©Ãñ¹¤³ÁÃÔÓÎÏ·»¨¹â»ýÐîÎÔ¹ì×Ôɱ</a></li> -</ul> - - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_5" blkclick="auto_nav" blktitle="ÐÂÍøÓÎ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÐÂÍøÓÎ' p_id='30' t_id='108' d_id='6' --> - <a href="http://games.sina.com.cn/newgame/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/Y8C--fxczqap4174218.jpg" width="105" height="70" /> -<span>ÉÏÖÜÊ×±¬ÐÂÓλعË</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://games.sina.com.cn/ol/n/2015-06-16/fxczqan0636608.shtml" target="_blank">΢Èí¹«²¼Ä£ÄâÏÖʵÍøÓÎ ¡¶ION¡·</a></li> -<li><a href="http://games.sina.com.cn/ol/n/2015-06-16/1608624682.shtml" target="_blank">ÂÝÐýèÐÔ¸ÐCOSÓ¢ÐÛÁªÃËŮӢÐÛ </a></li> -<li><a href="http://games.sina.com.cn/ng/wgujian/index.shtml" target="_blank">¹Å½£ÆæÌ·ÍøÂç°æÖäÒþÊÓƵÊ×Æعâ</a></li> -<li><a href="http://games.sina.com.cn/ol/n/2015-06-16/fxczqap4172157.shtml" target="_blank">¡¶È«Ö°´óʦ¡·Êײ⾫²ÊÊÓƵ¼¯½õ</a></li></ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_4" blkclick="auto_nav" blktitle="ÐÂÊÖ¿¨"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÐÂÊÖ¿¨' p_id='30' t_id='108' d_id='5' --> -<a href="http://ka.sina.com.cn/16532" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0612/U2457P30DT20150612174219.jpg" width="105" height="70" /> - - <span>¡¶ÌìÚÍ¡·Ê±×°Àñ°ü</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://ka.sina.com.cn/16470" target="_blank">¡¶Ä§Óò¡· ÆæÏëͯÀÖÐÂÊÖÏä</a> <a target="_blank" href="http://games.sina.com.cn/my/index.shtml">רÇø</a></li> - -<li><a href="http://ka.sina.com.cn/15015" target="_blank">¡¶ÎʵÀ¡· ¾öÕ½À¥ÂØÖÁ×ðÀñ°ü</a> <a target="_blank" href="http://games.sina.com.cn/o/z/askdao/">רÇø</a></li> - -<li><a href="http://ka.sina.com.cn/16571" target="_blank">¡¶²»´ò²»Ïàʶ¡·ºÀ»ªÀñ°ü</a> <a target="_blank" href="http://www.17g.com/union?link_id=182">רÇø</a></li> - -<li><a href="http://ka.sina.com.cn/16573" target="_blank">¡¶Ææ¼£MU¡·ÐÂÀ˶À¼ÒÀñ°ü</a> <a target="_blank" href="http://games.sina.com.cn/mu/index.shtml">רÇø</a></li></ul> - </textarea> - </div> - - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_3" blkclick="auto_nav" blktitle="Óн±»î¶¯"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='Óн±»î¶¯' p_id='30' t_id='108' d_id='4' --> -<a href="http://e.games.sina.com.cn/?proj=tianyu" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0616/U2456P30DT20150616122107.jpg" width="105" height="70" /> - - <span>ÍæÌìÚÍӮƻ¹ûÊÖ±í</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://e.games.sina.com.cn/?proj=bdbxs" target="_blank">²»´ò²»Ïàʶºì°ü¼¾ Éý¼¶ÁìÈ¡ºì°ü</a></li> - -<li><a href="http://e.games.sina.com.cn/?proj=moyu2015" target="_blank">¡¶Ä§Óò¡·¹«²â¿ªÆô ÍæÓÎÏ·Ëͺì°ü</a></li> - -<li><a href="http://e.games.sina.com.cn/?proj=qjmu" target="_blank">Í桶Ææ¼£MU¡·S9°æ±¾Ó®·áºñ½±Æ·</a></li> - -<li><a href="http://e.games.sina.com.cn/?proj=fbyx2015 " target="_blank">·ç±©Ó¢ÐÛ¹«²â ·¢Î¢²©Ó®Æ»¹ûÊÖ±í</a></li></ul> - </textarea> - </div> - - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_youxi_2" blkclick="auto_nav" blktitle="ÃÀÅ®COS"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='΢̳' p_id='30' t_id='108' d_id='3' --> -<a href="http://www.97973.com/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U2217P30DT20150617163149.jpg" width="105" height="70" /> - - <span>ÊÕ»ñÈÕµÇÒƶ¯Æ½Ì¨</span> - -</a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://www.97973.com/" target="_blank">¡¶Î´ÉÏËøµÄ·¿¼ä¡·ÑÇÖÞ°æÖ§³ÖÖÐÎÄ</a></li> - -<li><a href="http://www.97973.com/sjyj/2015-06-17/ifxczqap4199477.shtml" target="_blank">½Ò¶ÊÖ»úÓÎÏ·Éú̬ȦÄÚ²¿µÄºÚħ·¨</a></li> - -<li><a href="http://www.97973.com/2015-06-17/ifxczqar0987401.shtml" target="_blank">SE¹ÅĹÀöÓ°ÊÖÓΡ¶ÀÍÀ­:GO¡·ÁÁÏà</a></li> - -<li><a href="http://www.97973.com/moxw/2015-06-17/ifxczqap4202816.shtml" target="_blank">¡¶Íõ¹úÖ®ÐÄ:½â·ÅX¡·¹ÙÍøÒѾ­ÉÏÏß</a></li> - -</ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod24 --> - </div> - <div class="part-h-r"> - <!-- mod25 --> - <div class="uni-blk" id="SI_Order_H" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav" id="tech_mobi_tab"><a href="http://mobile.sina.com.cn/" target="_blank">ÊÖ»ú</a></span> - <span tab-type="tab-nav" id="tech_digi_tab"><a href="http://digi.sina.com.cn/" target="_blank">ÊýÂë</a></span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk" style="padding-right:6px;"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_5"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://shiqu.sina.com.cn/" target="_blank">ʶȤ</a></li> -<li><a href="http://tech.sina.com.cn/notebook/" target="_blank">±¾±¾</a></li> -<li><a href="http://tech.sina.com.cn/smart/" target="_blank">ÖÇÄܼҾÓ</a></li> -<li><a href="http://tech.sina.com.cn/down/" target="_blank">ÏÂÔØ</a></li> -<li><a href="http://tech.sina.com.cn/apple/" target="_blank">Æ»¹û»ã</a></li> - -<li id="SI_IP_MT_6"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_digi_1" blkclick="auto_nav" blktitle="ÊýÂë"> -<!-- publish_helper name='ÊýÂëÇø¿é' p_id='30' t_id='103' d_id='5' --> - <div class="uni-blk-bt clearfix"> -<a href="http://tech.sina.com.cn/zhongce/002.html" target="_blank" class="uni-blk-pic" border="0"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0616/U10175P30DT20150616105405.jpg" width="105" height="70" /><span>ÖÚ²â:ÊÖ»úÃâ·ÑÄÃ</span></a> -<ul class="uni-blk-list01 list-a"> - -<li><a href="http://tech.sina.com.cn/mobile/special/bestchoice20150615/" target="_blank">×îÍƼö:OPPO Find 7Çá×°°æ1999Ôª</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurs2575779.shtml" target="_blank">ѧÉú±Ø±¸»úÐÍ</a> - <a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxczyze9696633.shtml" target="_blank">Ö¸ÎÆʶ±ðÊÖ»úÍƼö</a> -</li> - -<li><a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurs2575562.shtml" target="_blank">´óÆÁÓéÀÖÊÖ»ú</a> - <a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurq6483408.shtml" target="_blank">³¬³¤Ðøº½ÊÖ»úÅ̵ã</a> -</li> - -<li><a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxefurt9352684.shtml" target="_blank">Ë«Ãæ²£Á§ÊÖ»ú</a> - <a href="http://tech.sina.com.cn/mobile/n/g/2015-06-18/doc-ifxczyze9695317.shtml" target="_blank">¸ßÏñËØÅÄÕÕÊÖ»ú»ã</a> -</li> - -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://tech.sina.com.cn/apple/" target="_blank">[Æ»¹û]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354574.shtml" target="_blank">iPhone±ØÐëÂô¸ß¼Û£¿</a> <a target="_blank" href="http://tech.sina.com.cn/it/2015-06-18/doc-ifxefurt9355899.shtml">Æ»¹ûϵͳÏÖÑÏÖØйÃÜ©¶´</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/tag/%E6%96%B0%E6%9C%BA%E6%9B%9D%E5%85%89" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9695986.shtml" target="_blank">Ò»¼ÓÊÖ»ú2¹Ù·½±¬ÁÏ</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurq6481350.shtml">ÈÙÒ«7±»Æؽ«ÓÃȫд¦ÀíÆ÷</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/tag/%E8%AF%84%E6%B5%8B%E8%A7%A3%E6%9E%90" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354298.shtml" target="_blank">ÈýÐÇNote 5»òÌáÇ°·¢²¼</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9696852.shtml">Win10ÊÖ»ú°æÔöµ¥ÊÖģʽ</a></li> - -<li><a href="http://tech.sina.com.cn/mobile/tag/%E6%96%B0%E6%9C%BA%E6%9B%9D%E5%85%89" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354532.shtml" target="_blank">Ï´úiPhone»òÓÐõ¹å½ðÅäÉ«</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9697330.shtml">ŵ»ùÑÇÇ°CEO½«ÀëÖ°</a> -</li> - -<li><a href="http://slide.tech.sina.com.cn/mobile/" target="_blank">[ÐÂÎÅ]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurq6506081.shtml" target="_blank">Lumia940»òÅäÈý¿ÅÉÁ¹âµÆ</a> <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurt9354994.shtml">÷ÈÀ¶2»ñ¹¤ÐŲ¿ÈëÍø</a> -</li> - -<li><a href="http://tech.sina.com.cn/mobile/cesasia2015/" target="_blank">[ÍƼö]</a> - <a href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxczyze9698349.shtml" target="_blank">ŵ»ùÑÇÊÖ»ú²»ÔÙ µ«Åµ»ùÑÇרÀûÎÞ´¦²»ÔÚ</a></li> - -<li><a href="http://slide.tech.sina.com.cn/mobile/" target="_blank">[ÐÂÎÅ]</a> - <a target="_blank" href="http://tech.sina.com.cn/mobile/n/n/2015-06-18/doc-ifxefurs2577517.shtml">ÄäÃûÔ±¹¤±¬ÁÏ£º»ªÎªµÄÈ·ÔÚÔìNexusÊÖ»ú</a></li> - - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_shiqu_1" blkclick="auto_nav" blktitle="ʶȤ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ʶȤÇø¿é' p_id='30' t_id='103' d_id='13' --> - <div class="uni-blk-bt clearfix"> -<a href="http://shiqu.sina.com.cn/" target="_blank" class="uni-blk-pic "><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U4373P30DT20150618084716.jpg" width="105" height="70" /><span>¼üÅ̳µÉñÐÂ×°±¸</span></a> - -<a href="http://tech.sina.com.cn/q/life/2015-06-18/doc-ifxefurt9355014.shtml" target="_blank" class="uni-blk-pic shiqu-ml"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U4373P30DT20150618084734.jpg" width="105" height="70" /><span>Àָ߽á»éµ°¸â</span></a> - -<a href="http://tech.sina.com.cn/q/life/2015-06-18/doc-ifxefurq6513360.shtml" target="_blank" class="uni-blk-pic shiqu-ml"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U4373P30DT20150618084812.jpg" width="105" height="70" /><span>ÒøÐÓÌ«ÑôÄܳäµçÆ÷</span></a> - - </div> - <div class="blk-line shiqu-mt"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://shiqu.sina.com.cn/toy/">[ʶȤÍæÎï]</a> <a href="http://tech.sina.com.cn/q/toy/2015-06-18/doc-ifxczyze9698024.shtml" target="_blank">ÕâÊǸöÉñÆæµÄÉ豸£ºAumeoÒôÀÖ½ÃÕýÆ÷</a></li> - -<li><a target="_blank" href="http://shiqu.sina.com.cn/life/">[ʶȤÉú»î]</a> <a href="http://tech.sina.com.cn/q/life/2015-06-18/doc-ifxefurs2576980.shtml" target="_blank">´¿ÊÖ¹¤´òÔìÒþÐÎ×ÔÐгµ£ºÈËÈ⶯Á¦Õ½¶·»ú</a></li> - -<li> -<a href="http://tech.sina.com.cn/notebook/" target="_blank">[±¾±¾]</a> -<a href="http://tech.sina.com.cn/n/g/2015-06-18/doc-ifxefurs2577987.shtml" target="_blank">ÈÈÏú¼ÒÍ¥ÓéÀֱʼDZ¾ÍƼö</a> -<a href="http://tech.sina.com.cn/notebook/pad/2015-06-18/doc-ifxefurs2576601.shtml" target="_blank">Surface Pro 3½µ¼Û</a> - -</li> - -<li><a href="http://tech.sina.com.cn/pad/" target="_blank">[ƽ°å]</a> -<a href="http://tech.sina.com.cn/n/t/2015-06-18/doc-ifxefurq6524613.shtml" target="_blank">Èý´óÒƶ¯²Ù×÷ϵͳÖÕ¼«PK</a> -<a href="http://tech.sina.com.cn/n/k/2015-06-18/doc-ifxefurs2576967.shtml" target="_blank">MacBook±¾¸Ãû½Ó¿Ú</a> -</li> -<li><a href="http://tech.sina.com.cn/digital/" target="_blank">[Ïà»ú]</a> <a target="_blank" href="http://tech.sina.com.cn/digi/dc/s/2015-06-18/doc-ifxczyze9697999.shtml">618½µ¼Ûµ¥·´/΢µ¥Å̵ã</a> <a target="_blank" href="http://tech.sina.com.cn/digi/dc/q/2015-06-18/doc-ifxefurs2577629.shtml">²ËÄñÉý¼¶×¨ÒµÉãӰʦÐĵÃ</a></li> - -<li><a href="http://club.tech.sina.com.cn/" target="_blank">[ÉçÇø]</a> -<a href="http://club.tech.sina.com.cn/mobile/thread-11474874-1-1.html" target="_blank">´Á´©Áù´óÓ²¼þα֪ʶ</a> -<a href="http://club.tech.sina.com.cn/mobile/thread-11474884-1-1.html" target="_blank">iPhone 6sÉÏÊÐʱ¼ä»òÆعâ</a> -</li> - -<li> -<a href="http://tech.sina.com.cn/elec/" target="_blank">[¼Òµç]</a> -<a href="http://tech.sina.com.cn/e/x/2015-06-18/doc-ifxczyze9695938.shtml">PPTV¿¿ËÕÄþÔìµçÊÓÉú̬</a> <a target="_blank" href="http://tech.sina.com.cn/e/x/2015-06-18/doc-ifxefurt9355053.shtml">ר¼ÒÆÀ¼ÖԾͤÀ´Ç®Ì«ÈÝÒ× </a> -</li> - - </ul> - </textarea> - </div> - </div> - </div> - </div> - -<script> -/* ÊÖ»ú¡¢ÊýÂë°å¿éËæ»úĬÈϳÊÏÖ */ -jsLoader({ - name: 'shm', - callback: function() { - var selected = Math.random()>0.5?'tech_digi_tab':'tech_mobi_tab'; - SHM.app.tab.switchByEle(SHM.dom.byId(selected)); - } -}); -</script> - <!-- mod25 --> - <div class="blank-cont" style="height:16px"></div> - <!-- mod26 --> - <div class="uni-blk" tab-type="tab-wrap" style="z-index:1"> - <div class=""> - <div class="uni-blk-t mod24-t clearfix"> - <div class="mod24-menu clearfix"> - <span class="selected" tab-type="tab-nav" style="border-left:0px;width:70px;"><a href="http://app.sina.com.cn/?f=p_binfen&w=p_binfen" target="_blank">Ó¦ÓÃÖÐÐÄ</a></span> - <span tab-type="tab-nav" style="width:72px;"><a href="http://app.sina.com.cn/app_index.php?f=p_binfen&w=p_binfen" target="_blank">°²×¿Ó¦ÓÃ</a></span> - <span tab-type="tab-nav" style="width:72px;"><a href="http://app.sina.com.cn/game_index.php?f=p_binfen&w=p_binfen" target="_blank">°²×¿ÓÎÏ·</a></span> - <span tab-type="tab-nav" style="width:70px;"><a href="http://app.sina.com.cn/installs.php?f=p_binfen&w=p_binfen" target="_blank">×°»ú±Ø±¸</a></span> - <span style="border-right:0px;width:70px;" tab-type="tab-nav"><a href="http://app.sina.com.cn/?f=p_binfen&w=p_binfen" target="_blank">ÐÂÆ·ÉϼÜ</a></span> - - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> -<!-- publish_helper name='Ó¦ÓÃÖÐÐÄ' p_id='30' t_id='122' d_id='1' --> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" data-sudaclick="blk_apps_1" blkclick="auto_nav" blktitle="Ó¦ÓÃÖÐÐÄ"> - <a href="http://app.sina.com.cn/appdetail.php?appID=2349268&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/sms/images/sms_image/appstore/diandianxs.png" width="105" height="70" /> - - <span>²Ý´ÔÓ¢ÐÛÆëµÇ³¡</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349109&f=p_binfen&w=p_binfen" target="_blank">·ÉԽδÀ´´ó¶¼Ìì¼Ê£º·ÉÌ컬°å¸ßÊÖ</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349154&f=p_binfen&w=p_binfen" target="_blank">30¿éÁìÍÁµÈÄãÕ÷·þ£ºÅÑÂÒÎäÊ¿Ö®Õ½</a></li> - - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2350985&f=p_binfen&w=p_binfen" target="_blank">ÆæÃîµÄħ»ÃÖ®ÂãºÐ¡Ð¡Ä§ÊÞ´óÕ½Õù</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2351044&f=p_binfen&w=p_binfen" target="_blank">µãȼս¶·Áé»ê£º³¬ºÏÌåħÊõ»úÆ÷ÈË</a></li> - </ul> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_2" blkclick="auto_nav" blktitle="°²×¿Ó¦ÓÃ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='°²×¿Ó¦ÓÃ' p_id='30' t_id='122' d_id='2' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=623838&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/sms/images/sms_image/appstore/meiyou.png" width="105" height="70" /> - - <span>ÃÀèÖ´óÒÌÂèÉñÆ÷</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=110&f=p_binfen&w=p_binfen" target="_blank">[ѧϰ°ì¹«]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=84472&f=p_binfen&w=p_binfen" target="_blank">Á¼Ê¦ÒæÓÑ£ºº£´Ê´Êµä</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=101&f=p_binfen&w=p_binfen" target="_blank">[ϵͳ¹¤¾ß]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=117176&f=p_binfen&w=p_binfen" target="_blank">±£»¤ÄãÒþ˽£ºÓ¦ÓÃËø</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=112&f=p_binfen&w=p_binfen" target="_blank">[½ðÈÚÀí²Æ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=84623&f=p_binfen&w=p_binfen" target="_blank">Ͷ×ÊÕß³´¹É£ºÍ¬»¨Ë³</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=103&f=p_binfen&w=p_binfen" target="_blank">[ÈÕ³£Éú»î]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=1237478&f=p_binfen&w=p_binfen" target="_blank">ʵʱȥ¶¨Î»£º¸úƨ³æ</a></li> - </ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_3" blkclick="auto_nav" blktitle="°²×¿ÓÎÏ·"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='°²×¿ÓÎÏ·' p_id='30' t_id='122' d_id='3' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=2348486&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/sms/images/sms_image/appstore/daocaor.png" width="105" height="70" /> - - <span>ÂóÌïÊØÍûÕß</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=201&f=p_binfen&w=p_binfen" target="_blank">[ÒæÖÇÐÝÏÐ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2347482&f=p_binfen&w=p_binfen" target="_blank">]»¥¶¯Ñݱ䣺¹ÖÎï½ø»¯</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=204&f=p_binfen&w=p_binfen" target="_blank">[½ÇÉ«°çÑÝ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2349163&f=p_binfen&w=p_binfen" target="_blank">Ê·Ê«¾ÞÏ×£º³Ç±¤·ç±©</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=203&f=p_binfen&w=p_binfen" target="_blank">[ÌåÓý¾ºËÙ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2351045&f=p_binfen&w=p_binfen" target="_blank">ÉúËÀÖ®¼ä£º·è¿ñƯÒÆ</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=200&secondcat=205&f=p_binfen&w=p_binfen" target="_blank">[·ÉÐÐÉä»÷]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=2350509&f=p_binfen&w=p_binfen" target="_blank">ûÓÐÍË·£º³Ç¼ÊºäÕ¨</a></li> - </ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_4" blkclick="auto_nav" blktitle="×°»ú±Ø±¸"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='×°»ú±Ø±¸' p_id='30' t_id='122' d_id='4' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=1118624&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/sms/images/sms_image/appstore/baogongzi.png" width="105" height="70" /> - - <span>Öª¼ºÖª±Ë×÷Õ½Ö°³¡</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=113&f=p_binfen&w=p_binfen" target="_blank">[µØͼµ¼º½]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=84453&f=p_binfen&w=p_binfen" target="_blank">³öÐÐͨ£º¿­Á¢µÂµ¼º½</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=102&f=p_binfen&w=p_binfen" target="_blank">[Ö÷Ìâ±ÚÖ½]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=101351&f=p_binfen&w=p_binfen" target="_blank">Ʒζ¸Ð¶¯£ºÆæ˼±ÚÖ½</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=107&f=p_binfen&w=p_binfen" target="_blank">[ÅÄÉãÃÀ»¯]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=118425&f=p_binfen&w=p_binfen" target="_blank">¿°±ÈÓ°Â¥£ºÌØЧÏà»ú</a></li> - <li><a href="http://app.sina.com.cn/catlist.php?cat=100&secondcat=108&f=p_binfen&w=p_binfen" target="_blank">[ÐÂÎÅ×ÊѶ]</a> - <a href="http://app.sina.com.cn/appdetail.php?appID=127035&f=p_binfen&w=p_binfen" target="_blank">ȨÍþ·¢²¼£ºÈËÃñÈÕ±¨</a></li> - </ul> - </textarea> - </div> - <div class="uni-blk-bt clearfix" tab-type="tab-cont" style="display:none" data-sudaclick="blk_apps_5" blkclick="auto_nav" blktitle="ÐÂÆ·ÉϼÜ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÐÂÆ·ÉϼÜ' p_id='30' t_id='122' d_id='5' --> - <a href="http://app.sina.com.cn/appdetail.php?appID=2350440&f=p_binfen&w=p_binfen" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/sms/images/sms_image/appstore/quantingzdy.png" width="105" height="70" /> - - <span>º£µ×ÊÀ½ç´óðÏÕ</span> - </a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2348348&f=p_binfen&w=p_binfen" target="_blank">½¨Ôì˽È˺À»ª´óÓÎͧ£º¿ìÀ´Ôì´¬°É</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2350477&f=p_binfen&w=p_binfen" target="_blank">¶À×ÔÒ»¸öÈ˽øÐÐá÷ÁÔ£º¾Ñ»÷ÊÖÁÔ¹</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349239&f=p_binfen&w=p_binfen" target="_blank">ÏòµÐÈË·¢³ö³¬¼¶Õ½¶·£ºÃȾü·ÉÐжÓ</a></li> - <li><a href="http://app.sina.com.cn/appdetail.php?appID=2349139&f=p_binfen&w=p_binfen" target="_blank">ÏÖ´ú±øÆ÷µÄ¿Ö²À¶Ô¾ö£ºCS·´¿Ö¾«Ó¢</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod26 --> - </div> - </div> - <!-- part-h end --> - - <div class="blank-cont" style="height:12px"></div> - <!-- part-j begin --> - - <div class="part-j clearfix"> - <div class="part-j-l"> - <!-- mod27 --> - <div class="mod-27 mod-02"> - <div class="tit02"> - <h3><a href="http://history.sina.com.cn/photo/" target="_blank">Àúʷͼ¿â</a></h3> - </div> - <div class="mod27-cont" data-sudaclick="blk_history_tk" blkclick="auto_nav" blktitle="Àúʷͼ¿â" style="padding:10px;"> - <div class="history-pics-wrap clearfix"> - <div class="history-pics-arrleft-wrap"> - <a href="javascript:;" class="history-pics-arrleft" id="SI_Scroll_History_Arr_L"></a> - </div> - <div class="history-pics-frame clearfix" id="SI_Scroll_History_Wrap" style="height:108px; overflow:hidden;"> -<!-- publish_helper name='Àúʷͼ¿â' p_id='30' t_id='121' d_id='8' --> -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/y/slide_61_40602_44368.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U3093P30DT20150617105708.jpg" width="180" height="87" /> -<span>ÀÏÕÕƬÖеIJпáºÍ±¯Çé˲¼ä</span> -</a></div> - -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/w/slide_61_40602_53152.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U3093P30DT20150618091721.jpg" width="180" height="87" /> -<span>1955ÄêµÄÏã¸Û°Ù̬</span> -</a></div> - -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/y/slide_61_40602_44454.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0617/U3093P30DT20150617105803.jpg" width="180" height="87" /> -<span>Äãû¼û¹ýµÄÓ¡¶ÈÀÏÕÕƬ</span> -</a></div> - -<div class="history-pics-item"><a href="http://slide.history.sina.com.cn/y/slide_61_40602_44443.html" target="_blank"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U3093P30DT20150617105635.jpg" width="180" height="87" /> -<span>Ç峯»Ê×åµÄÕæʵ³¤Ïà</span> -</a></div> - - </div> - <div class="history-pics-arrright-wrap"> - <a href="javascript:;" class="history-pics-arrright" id="SI_Scroll_History_Arr_R"></a> - </div> - </div> - </div> - </div> - <script type="text/javascript"> - jsLoader({ - name : 'shm', - callback : function() { - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "SI_Scroll_History_Wrap"; //ÄÚÈÝÈÝÆ÷ID - focusScroll.frameWidth = 180;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 180; //·­Ò³¿í¶È - focusScroll.upright = false; //´¹Ö±¹ö¶¯ - focusScroll.speed = 15; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 30; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = true; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - - SHM.dom.byId('SI_Scroll_History_Arr_L').onmousedown = function(){ - focusScroll.pre(); - return false; - } - SHM.dom.byId('SI_Scroll_History_Arr_R').onmousedown = function(){ - focusScroll.next(); - return false; - } - } - }); - </script> - <!-- mod27 --> - - <div class="blank-cont" style="height:20px;"></div> - <!-- mod28 --> - <div class="mod-28"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 1ÂÖ²¥°´Å¥05¹ã¸æ begin --> -<div id="ad_46012" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046012"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 1ÂÖ²¥°´Å¥05¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod28 --> - </div> - <div class="part-j-m"> - <!-- mod29 --> - <div class="uni-blk" id="SI_Order_I" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://history.sina.com.cn/" target="_blank">ÀúÊ·</a></span> - <span tab-type="tab-nav"><a href="http://cul.sina.com.cn/" target="_blank">ÎÄ»¯</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden" data-sudaclick="blk_history_menu"> -<li id="SI_IP_MT_8"></li> -<li><a href="http://history.sina.com.cn/digest/" target="_blank">Ê·º£¹³³Á</a></li> -<li><a href="http://history.sina.com.cn/photo/" target="_blank">ÀúʷͼƬ</a></li> -<li><a href="http://history.sina.com.cn/zt/" target="_blank">²ß»®</a></li> -<li><a href="http://history.sina.com.cn/zl/" target="_blank">רÀ¸</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_history_1" blkclick="auto_nav" blktitle="ÀúÊ·"> -<!-- publish_helper name='ÀúÊ·Çø¿é' p_id='30' t_id='121' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://history.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11647P30DT20150618091526.jpg" width="105" height="70" /> - - <span>³¯ÏʽðÈÕ³Éʱ´ú</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://history.sina.com.cn/" target="_blank">¿¹Õ½³õÆÚÖÐÈÕË«·½±øÁ¦¶Ô±È</a></li> - -<li><a href="http://blog.sina.com.cn/lm/history/" target="_blank">½¨¹úÖ®³õԪ˧Ҷ½£Ó¢ÎªºÎƵƵÓö´Ì</a></li> - -<li><a href="http://slide.history.sina.com.cn/y/slide_61_40602_46683.html" target="_blank">½â·ÅÇ°µÄÉϺ££º¶¯µ´Óë¾­¼Ã±ÀÀ£</a></li> - -<li><a href="http://history.sina.com.cn/zl/" target="_blank">Ï£ÂÞ¶àµÂΪºÎÕ¾ÔÚ²¨Ë¹µÄÁ¢³¡ÉÏ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://history.sina.com.cn/digest/">Î人¿¹Õ½£º¹ú¹²µÚ¶þ´ÎºÏ×÷»Æ½ðÄê´ú</a> <a target="_blank" href="http://history.sina.com.cn/bk/jgcqs/2015-06-18/0946121564.shtml">´÷¸ßÀÖ¼Ò×åÖйúÔµ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_3f5e61240102w8j0.html?tj=1">Ê׸öÍâ¹úÌ«¼àÖÂÔª³¯ÃðÍö</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_4ac5b19f0102vp7e.html?tj=1">Ë­×îÔç·¢ÏÖëÔó¶«ÓÐÐÛ²ÅΰÂÔ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_4b8bd1450102vljx.html?tj=1">Öй²µÚÒ»¼ÒÍ¥µÄ´ÈÉÆÓ빫Òæ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_a1929b370102vw32.html?tj=1">½¯½éʯÃØÃÜѵÁ·Ò»ÅúµÂеʦ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_e39346e40102vqbv.html?tj=1">ÖìԪ谺ÍÃ÷½ÌÊÇʲô¹Øϵ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_7e84ef460102vyih.html?tj=1">²ÜκÃû½«ÕÅàAÊDz»ÊÇËÀÓÚ·ÇÃü </a></li><li><a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-18/1016121572.shtml">ÀäÕ½Î÷µÂÏòÃÀӢתÒÆǧ¶Ö»Æ½ð</a> <a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-18/0952121566.shtml">¹Å°Íµ¼µ¯Î£»úÖеĴ«ÉùͲ</a></li><li><a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-17/1705121533.shtml">ƽÐ͹ذË·¾ü°ÑµÐ¾ü·Ö¸îÊý¶Î</a> <a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-17/1655121531.shtml">Ǭ¡ÉÝ»ª¶ËÎç°ÚǧÓàôÕ×Ó</a></li><li><a href="http://history.sina.com.cn/bk/jds/2015-06-17/1140121518.shtml" target="_blank">Ó¢¹úÁ½´ÎÈëÇÖÎ÷²Ø¶Ô²Ø¾ü´óÍÀɱ</a> <a target="_blank" href="http://history.sina.com.cn/bk/kzs/2015-06-17/1137121514.shtml">¹úÄÑ֮Ͻ¯½éʯµÄ»ú»á</a></li><li><a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-17/1117121512.shtml"> Ó¢°¢ÂíµºÖ®Õ½£º±¾¿É±ÜÃâµÄÕ½Õù</a> <a target="_blank" href="http://history.sina.com.cn/bk/gds/2015-06-18/1119121576.shtml">¹Å´úÓéÀÖȦµÄ»Æ½ðʱ´ú</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_cul_1" blkclick="auto_nav" blktitle="ÎÄ»¯"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÎÄ»¯Çø¿é' p_id='30' t_id='121' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/lm/history/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0611/U10606P30DT20150611094610.jpg" width="105" height="70" /> - - <span>¾ÉÅ·ÖÞÊøÑüÃÀÈË</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://cul.history.sina.com.cn/zl/" target="_blank">Âþ»°Â³Ñ¸£ºÏÖ´úÖйú×îÍ´¿àµÄÁé»ê</a></li> - -<li><a href="http://cul.history.sina.com.cn/zl/redian/2015-03-31/17321148.shtml" target="_blank">ÕŹúÈÙ£¬ÈËÉúûÓÐÄãÕæµÄ»á²»Í¬</a></li> - -<li><a href="http://cul.history.sina.com.cn/zl/redian/2015-03-11/16201138.shtml" target="_blank">ÀîÒøºÓ£ºÅ®ÈË£¬²»ÊÇÒ»ÖÖÐÔ±ð</a></li> - -<li><a href="http://cul.history.sina.com.cn/zl/redian/2015-03-25/09371146.shtml" target="_blank">ÎÒÃÇ»¹ÄÜ×øÁ®¼Ûº½¿Õ¹«Ë¾Âð£¿</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://history.sina.com.cn/bk/mqs/2015-06-11/1016121189.shtml">´óº½º£Ê±´ú£ºµÛ¹úÐËË¥ËõÓ°</a> <a target="_blank" href="http://history.sina.com.cn/bk/jds/2015-06-11/1046121192.shtml">´ÈìûÊÕÀñÇå³õ¹æ¾Ø´Ó´ËʧЧ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_c5026db80102vhi2.html?tj=1">¹²ºÍ¹úΨһһ´Î³¬¹æ¸ñÔáÀñ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_3f5e61240102w4g1.html?tj=1">µ±ÄêÃɹÅÈËΪºÎûÕ÷·þÈÕ±¾</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_7807f9150102vp55.html?tj=1">Ç峯ÐÂÄï³ö¼ÞÌØд(×éͼ) </a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_c4f2b62a0102vdvr.html?tj=1">ÀúÊ·ÉÏ×îÄÜ¡°×°¡±µÄËÄ´óÌì²Å</a></li><li><a target="_blank" href="http://blog.sina.com.cn/s/blog_50d4ea0e0102ebyp.html?tj=1">ÐÂËľüÅ®Ìع¤ÊæÈü</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_4496894d0102vo8v.html?tj=1">¹Å´úÎ书ÅÅÐÐ×îÇ¿ÊÇ¡¶¿û»¨±¦µä¡·</a></li><li><a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-10/1547121138.shtml">¹ÅÈËÑϽû·ÉÏÂÒµ¹À¬»øÎ¥ÕßÑϳÍ</a> <a target="_blank" href="http://history.sina.com.cn/bk/sjs/2015-06-11/0940121186.shtml">ÄÃÆÆÂØÍ··¢ÓëËÀÒòÖ®ÃÕ</a></li><li><a target="_blank" href="http://history.sina.com.cn/bk/jds/2015-06-12/0910121237.shtml">»ðÉÕÔ²Ã÷Ô°£ºÒ»¸öÍõ³¯µÄÌ®Ëú</a> <a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-11/1521121203.shtml">¶­´æÈðÄêÓ×ʱ»úÁ鵨´ó</a></li><li><a href="http://history.sina.com.cn/bk/gds/2015-06-12/0928121239.shtml" target="_blank">ÃÉÔª£ºÒ»¸öÊÀ½çÐÔµÄÂí°°µÛ¹ú</a> <a target="_blank" href="http://history.sina.com.cn/bk/gds/2015-05-05/0927119644.shtml">Áõ°îƽÃñ¼ÒÊÀÓë³öÉúÉñ»°</a></li><li><a target="_blank" href="http://history.sina.com.cn/his/jm/2015-06-11/1540121204.shtml">ÓîÎÄÌ©´´ÐÂÖÆÒÖÖÆÌ°¸¯</a> <a target="_blank" href="http://history.sina.com.cn/bk/jds/2015-04-30/0931119506.shtml">°ÙÈÕµøå´£ºÎìÐç±ä·¨µÄÇ°Òòºó¹û</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod29 --> - </div> - <div class="part-j-r"> - <!-- mod30 --> - <div class="uni-blk" id="SI_Order_J" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://mil.news.sina.com.cn/" target="_blank">¾üÊÂ</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://slide.mil.news.sina.com.cn/" target="_blank">¾üͼ</a></li> -<li><a href="http://mil.news.sina.com.cn/jssd/" target="_blank">Éî¶È</a></li> -<li><a href="http://mil.news.sina.com.cn/dgby/" target="_blank">´ó¹ú²©ÞÄ</a></li> -<li><a href="http://mil.news.sina.com.cn/jshm/" target="_blank">¾üÊ·</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_mil_1" blkclick="auto_nav" blktitle="¾üÊÂ"> -<!-- publish_helper name='¾üÊÂÇø¿é' p_id='30' t_id='107' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://slide.mil.news.sina.com.cn/k/slide_8_442_36356.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U10553P30DT20150618105342.jpg" width="105" height="70" /> - - <span>ÎÚ¿ËÀ¼°æÔË20£¿</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://mil.news.sina.com.cn/" target="_blank">ÈÕý³ÆÖйúºä6K¿É´ÓÈÕ±¾ÄÏ·½¹¥»÷</a></li> - -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0852833403.html" target="_blank">Öйúº£¾üҪץÅܵ½¼ÒÃÅ¿ÚµÄÃÀDZͧ</a></li> -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0715833379.html" target="_blank">Èո߹ٳÆÖйú½¨ÉèÄϺ£µº½¸Ã»Ö÷Ȩ</a></li> -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0844833393.html" target="_blank">·ÆÂɱöäÖȾ±»Á½°¶ÖйúÈËÒ»ÆðÆÛ¸º</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://mil.news.sina.com.cn/2015-06-18/0828833390.html" target="_blank">ÈÕ³ÆÖйúµ¼µ¯¿É¶Ô¸¶Èնᵺ²¿¶Ó</a> <a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0815833386.html">¼ÙÏëµöÓ㵺¹¥·ÀÕ½</a></li><li><a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0849833409.html">°ÍÌú·ÉÐÐÔ±³ÆèÉÁúÕ½»ú°ô¼«ÁË</a> <a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0923833411.html">Ãåµé»ò¹ºÂòèÉÁú</a></li><li><a href="http://mil.news.sina.com.cn/2015-06-18/0841833392.html" target="_blank">ÃÀ¹ú¾Ü¾øÖйúÌ«¿ÕºÏ×÷Ì«¹ÌÖ´ ÖÐÃÀˮƽ²î50¶àÄê</a></li><li><a target="_blank" href="http://mil.news.sina.com.cn/2015-06-18/0804833384.html">¶íý³ÆÖйú²»×¼±¸ÔÚÄϺ£Èò½ ÃÀ»ò¸üƵ·±Õì²ì</a></li><li><a target="_blank" href="http://mil.news.sina.com.cn/jssd/" class="linkRed">Èȵã½âÎö</a>|<a target="_blank" href="http://mil.news.sina.com.cn/jssd/">Ô½ÄϺ£¿Õ¾ü¶ÔÄϺ£ÓкÎÍþв ËÕ27½Ø»÷Î÷ɳ</a></li><li><a href="http://roll.mil.news.sina.com.cn/photo_hz/photo_hdphoto/index.shtml" target="_blank">×éͼ</a>£º<a target="_blank" href="http://slide.mil.news.sina.com.cn/k/slide_8_442_36356.html">ÎÚ¿ËÀ¼°²70ÔËÊä»ú»»×°ÎÐÉȶ¯Á¦±äÉíÕ½ÂÔÔËÊä»ú</a></li><li><a href="http://roll.mil.news.sina.com.cn/photo_hz/photo_hdphoto/index.shtml.shtml" target="_blank">×éͼ</a>£º<a href="http://slide.mil.news.sina.com.cn/l/slide_8_38692_36357.html" target="_blank">Öйú¾ü¹¤ÍƳöпîÍâóÐÍ97ʽ²½Ç¹ ÒÑÈ¡ÏûÌá°Ñ</a></li><li><a href="http://roll.mil.news.sina.com.cn/blog/js-jsrd/index.shtml" target="_blank">×éͼ</a>£º<a href="http://slide.mil.news.sina.com.cn/l/slide_8_646_36358.html" target="_blank">ÃÀ¹ú¹«Ë¾ÍƳöºÀ»ª°æÔ½Ò°Õ½³µ ÇëÀ´ÃÀÅ®°ïÊÛÂô</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod30 --> - </div> - </div> - <!-- part-j end --> - <div class="blank-cont" style="height:20px"></div> - <!-- npart-a begin --> - <div class="npart-a"> - -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸03¹ã¸æ begin --> -<div id="ad_05494" class="mb25"><ins class="sinaads" data-ad-pdps="PDPS000000005494"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸03¹ã¸æ end --> -<!--_SINA_ADS_END_--> - - </div> - <!-- npart-a end --> - - <!-- part-k begin --> - - <div class="part-k clearfix"> - -<script> - if ("°²»Õ" === remote_ip_info.province) { - document.write([ - '<div class="part-k-l">', - '<div class="mod-13 mod-02">', - '<div class="tit02 clearfix">', - '<h3>', - '<ins class="sinaads" data-ad-pdps="PDPS000000025252"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</', 'script>', - '</h3>', - '</div>', - '</div>', - '<ins class="sinaads" data-ad-pdps="3C1ABA5504C1"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</', 'script>', - '</div>' - ].join('')); - } else { - document.write([ - '<div class="part-k-l">', - '<div class="mod-13 mod-02">', - '<div class="tit02 clearfix">', - '<h3>', - '<ins class="sinaads" data-ad-pdps="PDPS000000025252"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</','script>', - '</h3>', - '</div>', - '<div class="mod13-cont" style="padding-top:5px; padding-bottom:5px;">', - '<ul class="list-b" id="gina_res_show1347">', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046014"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046015"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046016"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046017"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '<li>','<ins class="sinaads" data-ad-pdps="PDPS000000046018"></ins>','<script>(sinaads = window.sinaads || []).push({});</' , 'script>','</li>', - '</ul>', - '</div>', - '</div>', - '<div class="blank-cont" style="height:15px"></div>', - '<div class="mod-32" id="gina_res_show1348">', - '<ins class="sinaads" data-ad-pdps="PDPS000000046019"></ins>', - '<script>(sinaads = window.sinaads || []).push({});</' , 'script>', - '</div>', - '</div>' - ].join('')); - } -</script> - - <div class="part-k-m"> - <!-- mod33 --> - <div class="uni-blk" id="SI_Order_K" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://news.sina.com.cn/society/" target="_blank">Éç»á</a></span> - <span tab-type="tab-nav"><a href="http://gongyi.sina.com.cn/" target="_blank">¹«Òæ</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li id="SI_IP_MT_7"></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_society_1" blkclick="auto_nav" blktitle="Éç»á"> -<!-- publish_helper name='Éç»áÇø¿é' p_id='30' t_id='97' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://news.sina.com.cn/society/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150618/WpYj-fxefurs2578053.jpg" width="105" height="70" /> - - <span>Å®×ÓѧԺ±ÏÒµÕÕ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://news.sina.com.cn/society/" target="_blank">¸»½ãй¾À²øÕßÐÐ×Ù Æä×·ÇóÕßɱÈË</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/081731964210.shtml">º«¹ú¶ùͯ²»³ÔÅݲËÔâÀÏʦ¶¾´ò</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/023031962383.shtml">Ãñ¾¯ÓëÖƶ¾Ê¦ºÏ×÷Éú²ú°Ù¹«½ï±ù¶¾</a></li> - -<li><a href="http://news.sina.com.cn/s/2015-06-18/022431962374.shtml" target="_blank">ÄÐ×ÓÓë14ÃûÅ®´óѧÉúÍøÁµÆ­²ÆÆ­É«</a></li> - -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://news.sina.com.cn/s/p/2015-06-18/030031962605.shtml">ºóÂèÏÓŮͯ³Ô·¹ÂýÈÃÆäײǽ(ͼ)</a> <a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/081131964167.shtml">Å®×Óδ»éÏÈÔÐɱٶù</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/p/2015-06-18/032231962674.shtml">ÄÐ×Ó±»½¦Ò»ÉíÄà ±ÆÍ£½Î³µÒªÇó˾»úµÀǸ(ͼ)</a></li> - -<li><a href="http://news.sina.com.cn/s/2015-06-18/050031962820.shtml" target="_blank">³µÖ÷Ç¿Ðпª×ßÔâ½»¾¯²é¿Û³µÁ¾ ±»ÅÐÇÀ½Ù»ñ»ºÐÌ</a></li> - -<li><a href="http://news.sina.com.cn/s/2015-06-18/050731962857.shtml" target="_blank">Õã½­º£µº»Ä´åÍðÈçͯ»°ÊÀ½ç</a> <a href="http://news.sina.com.cn/s/2015-06-18/080931964162.shtml" target="_blank">ÂÉʦ΢²©ÎêÈè·¨¹Ù±»·£3Íò</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/053931963195.shtml">Àϸ¾Õù³è´òÉËÈýÊ®¶àËêСÇéÈËÏàºÃ</a> <a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/005931962235.shtml">Å®×ӳƴóÄÔ±»ÈË¿ØÖÆ</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-17/233031962105.shtml">ÄÐ×Ӿƺó¸øÁ÷ÀËÀÏÈËÂòʳÎï Ôâ¾Ü¾øÉȶԷ½¶ú¹â</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/p/2015-06-18/044531962817.shtml">·ŭ˾»ú¶à´Î³¬³µÎ´¹û ±ÆÍ£¶Ô·½ºó½Åõß³µÃÅ(ͼ)</a></li> - -<li><a target="_blank" href="http://news.sina.com.cn/s/2015-06-18/015831962308.shtml">ÕÉ·ò¸°Ì©¹úÂÃÓÎÄçÍö ÆÞ×ÓÆðËßÂÃÐÐÉçË÷Åâ°ÙÍò</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_gongyi_1" blkclick="auto_nav" blktitle="¹«Òæ"> -<textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¹«ÒæÇø¿é' p_id='30' t_id='126' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://gongyi.sina.com.cn" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0616/U7063P30DT20150616103412.jpg" width="105" height="70" /> - - <span>¹Ø°®µáÎ÷¿¹Õ½Àϱø</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://gongyi.sina.com.cn/" target="_blank">¹«°ìÑøÀÏÔº²»ÔÙ½ÓÊշDZ£Õ϶ÔÏó</a></li> - -<li><a href="http://gongyi.sina.com.cn/gyzx/2015-06-17/101352937.html" target="_blank">12ËêŮͯͶ¶¾°¸ÏÆ¿ªÉç»áÀ£Ññ</a></li> - -<li><a href="http://gongyi.sina.com.cn/gyzx/2015-06-17/101352938.html" target="_blank">Ê×½ì·Ç¹«Ä¼ÂÛ̳̽ÌÖ¹«Òæг£Ì¬</a></li> - -<li><a href="http://gongyi.sina.com.cn/weibo.com/p/1008083ff5b51b3d66a706c0e3e4072b473f2d" target="_blank">Ò»ÆðÄý¾Û#ÕýÄÜÁ¿# ´«µÝ#ÕýÄÜÁ¿#</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-16/091252926.html">¾©½ò¼½ÖÎÎ۹滮Æô¶¯</a> <a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-18/120352946.html">¡°ÖйúÃΠͯÑÕÃΡ±»î¶¯ÔÚ¾©¾Ù°ì</a></li><li><a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-16/092852929.html">ÎÒ¹ú½«°Ñ·ûºÏÌõ¼þµÄÉç»á°ìÒ½ÁÆ»ú¹¹ÄÉÈëÒ½±£¶¨µã·¶Î§</a></li><li><a href="http://gongyi.sina.com.cn/gyzx/ngo.html" target="_blank">µ÷²é</a>| <a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-12/110052911.html">Òæµ÷²é£º2014ÄêÉç»á¾èÔù604.4ÒÚÓÐÄãµÄÒ»·ÝÂð£¿</a></li><li><a href="http://gongyi.sina.com.cn/zhuantilist.html" target="_blank">´ÈÉÆ</a>| <a target="_blank" href="http://gongyi.sina.com.cn/gyzx/2015-06-02/103352788.html">2015º£Ï¿Á½°¶ô߸۰ĴÈÉÆÂÛ̳ÔŲ́±±³É¹¦¾Ù°ì</a></li><li><a href="http://weibo.com/gongyi" target="_blank">΢²©</a>| -<a target="_blank" href="http://weibo.com/p/10080885f06b8fa1f4455d23b8069efe0d46d0">Ò»Æð°ïÖúº¢×ÓÃÇ#ͯԸ³ÉÕæ# »ñµÃ¹Ø°®µÄȨÀû</a></li><li><a href="http://gongyi.sina.com.cn/zhuantilist.html" target="_blank">רÌâ</a>| <a target="_blank" href="http://gongyi.sina.com.cn/z/2015shijiexueyoubingri/index.shtml">¡°ÊÀ½çѪÓѲ¡ÈÕ¡±»½Æð¹«ÖÚ¶ÔѪÓѲ¡µÄÕýÈ·ÈÏÖª</a></li><li><a href="http://yangfanbook.sina.com.cn/" target="_blank">Ñï·«</a>| -<a target="_blank" href="http://yangfanbook.sina.com.cn/news/1231">ºþ±±Àû´¨´åС»Ø·Ã¼Ç</a> <a target="_blank" href="http://weibo.com/1274469185/CmG7f3Juu">ÔĶÁ¸øͬѧ´øÀ´µÄ±ä»¯</a></li> -<li><a href="http://green.sina.com.cn/" target="_blank">»·±£</a>| <a target="_blank" href="http://slide.news.sina.com.cn/green/slide_1_28436_85557.html#p=1">ÓñÁÖ¹···×ÓÖµ簮¹·Õß ×¼±¸¹·µÈÄãÀ´Âò£¨Í¼£©</a></li> - </ul> -</textarea> - </div> - - </div> - </div> - </div> - <!-- mod33 --> - </div> - <div class="part-k-r"> - <!-- mod34 --> - <div class="uni-blk" id="SI_Order_L" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://games.sina.com.cn/" target="_blank">ÓÎÏ·</a></span> - <span tab-type="tab-nav"><a href="http://kan.sina.com.cn/" target="_blank">¿´ÓÎÏ·</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://games.sina.com.cn/vg/" target="_blank">µçÍæ</a></li> -<li><a href="http://ka.sina.com.cn/" target="_blank">ÐÂÊÖ¿¨</a></li> -<li><a href="http://kan.sina.com.cn/" target="_blank">¿´ÓÎÏ·</a></li> -<li><a href="http://gameapi.g.sina.com.cn/statiApi.php?action=doRedirect&label=sinaMainGameModem" target="_blank">App</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_games_1" blkclick="auto_nav" blktitle="ÓÎÏ·"> -<!-- publish_helper name='ÓÎÏ·Çø¿é' p_id='30' t_id='108' d_id='9' --> - <div class="uni-blk-bt clearfix"> -<a href="http://games.sina.com.cn/" target="_blank" class="uni-blk-pic"> <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0617/U2456P30DT20150617153135.jpg" width="105" height="70" /> <span>ÓÎÏ·ÄÛÄ£ÖúÕóÊÖÓÎ</span> </a> -<ul class="uni-blk-list01 list-a"> - -<li><a href="http://games.sina.com.cn/" target="_blank">ÓÎÏ·µÄÊ¢Ñç E3³öÕ¹¾«²Ê´ó×÷Å̵ã</a></li> -<li><a href="http://games.sina.com.cn/ol/n/2015-06-17/fxczqap4207784.shtml" target="_blank">·ÅËÁÒ»ÏÄ£¡2015ÊîÆÚ±ØÍæÍøÓÎÍƼö</a></li> -<li><a href="http://games.sina.com.cn/y/n/2015-06-17/fxczqar0988039.shtml" target="_blank">ÈÕ±¾ÓÎÏ·´ÓÒµÕßÏÖ×´£º¸ßн¿¿¼Ó°à</a></li> -<li><a href="http://games.sina.com.cn/o/z/wow/2015-06-17/fxczqar0984639.shtml" target="_blank">ħÊÞ6.2µØÓü»ð±¤ÀÝʱ¼ä±íÒѹ«²¼</a></li> -</ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://games.sina.com.cn/o/z/hos/2015-06-17/1252624799.shtml" target="_blank">·ç±©Ó¢ÐÛÓÀºãÖ®Õ½E3Ðû´«Æ¬</a> <a target="_blank" href="http://games.sina.com.cn/j/n/2015-06-17/fxczqap4208661.shtml">Å̵ãÊ®´óÓÉС˵¸Ä±àµÄÓÎÏ·</a></li> - -<li><a target="_blank" href="http://games.sina.com.cn/ol/n/2015-06-17/fxczyze9668079.shtml">ÈýÌåµçÓ°°æµÚÒ»²¿ÅÄÉãÍê±Ï</a> <a target="_blank" href="http://www.97973.com/sjyj/2015-06-17/ifxczqar0986087.shtml">¡¶º£ÔôÍõ¡·³ÉÈ«ÇòµÚÒ»Âþ»­</a></li> - -<li><a href="http://games.sina.com.cn/g/p/2015-06-17/fxczqap4211214.shtml" target="_blank">ÿÈÕ‡åͼ£ºÈËÉú³äÂúÁ˾ªÏ²</a> <a href="http://games.sina.com.cn/o/z/wow/2015-06-17/fxczqan1598533.shtml" target="_blank">ħÊÞµÂÀ­ÅµÈ«Èü¼¾½±Àø×øÆï</a></li> - -<li><a href="http://ka.sina.com.cn/" target="_blank">·¢¿¨</a>| -<a href="http://ka.sina.com.cn/15015" target="_blank">ÎʵÀÖÁ×ð´óÀñ°ü</a> -<a href="http://ka.sina.com.cn/16532" target="_blank">ÌìÚÍʱװÀñ°ü</a> <a href="http://ka.sina.com.cn/16573" target="_blank">Ææ¼£MU¶À¼ÒÀñ°ü</a></li> - -<li><a href="http://games.sina.com.cn/newgame/" target="_blank">ÐÂÓÎ</a>| <a href="http://games.sina.com.cn/ol/n/2015-06-17/fxczyze9663433.shtml" target="_blank">ʹÃüÕÙ»½OLа汾ÉÏÏß</a> <a href="http://games.sina.com.cn/ol/n/dlwyxw/2015-06-17/fxczqap4199059.shtml" target="_blank">ÂåÆæÓ¢ÐÛ´«BOSS÷¶ûµÇ³¡</a></li> - -<li><a href="http://www.97973.com/" target="_blank">ÊÖÓÎ</a>| <a href="http://www.97973.com/moxw/2015-06-17/ifxczqap4202816.shtml" target="_blank">Íõ¹úÖ®ÐÄÊÖÓιÙÍøÉÏÏß</a> <a href="http://www.97973.com/moxw/2015-06-17/ifxczqap4210819.shtml" target="_blank">δÉÏËøµÄ·¿¼ä·¢²¼ÖÐÎÄ°æ</a></li> - -<li><a href="http://games.sina.com.cn/gamer" target="_blank">ȤÎÅ</a>| <a target="_blank" href="http://games.sina.com.cn/g/g/2015-06-17/fxczqap4209819.shtml">Íù½ìE3µÄÃÀÅ®SG´óÅ̵ã</a> <a href="http://games.sina.com.cn/y/n/2015-06-17/fxczqar0988039.shtml" target="_blank">ÈÕ±¾ÓÎÏ·´ÓÒµÕßÊÕÈëÏÖ×´</a></li> - -<li><a href="http://zq.games.sina.com.cn/" target="_blank">רÇø</a>| <a href="http://games.sina.com.cn/o/z/dota2/2015-06-17/1042624754.shtml" target="_blank">DOTA2×Ô¶¨ÒåµØͼ¼´½«ÉÏÏß</a> <a target="_blank" href="http://games.sina.com.cn/o/z/dota2/2015-06-17/1015624737.shtml">µç¾º¾ãÀÖ²¿¹æ·¶¹«²¼</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_games_2" blkclick="auto_nav" blktitle="¿´ÓÎÏ·"> -<textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¿´ÓÎÏ·Çø¿é' p_id='30' t_id='108' d_id='7' --> - <div class="uni-blk-bt clearfix"> -<a href="http://kan.sina.com.cn/zq/xlgxs" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U2456P30DT20150618134737.png" width="105" height="70" /> - - <span>³¬ÐÂÐÇÖÕ¼«×ܾöÈü</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://kan.sina.com.cn/u/chgk/3477513" target="_blank">¡¶·½ÖÛ:Éú´æ½ø»¯¡·Áª»úµÚËÄÆÚ</a></li> - -<li><a href="http://kan.sina.com.cn/u/2931323820/3477632" target="_blank">ºüÀ꿪Æô¡¶¹íÎÝħӰ¡·¿Ö²ÀÖ®ÂÃ</a></li> - -<li><a href="http://kan.sina.com.cn/u/1743000753/3475955" target="_blank">°µÒ¹¡¶Â¯Ê¯´«Ëµ¡·¾º¼¼³¡¶Ä²©Ä£Ê½</a></li> - -<li><a href="http://kan.sina.com.cn/u/2608720237/3477471" target="_blank">´óµ±¼Ò¡¶µ¶Ëþ´«Ææ¡·4.0¸üÐÂÌåÑé</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://kan.sina.com.cn/zq/wd" target="_blank">¡¶ÎʵÀ¡·Ã¿Íí¾¢±¬Ö±²¥</a> <a href="http://kan.sina.com.cn/zq/thyj" target="_blank">¡¶ÌÒ»¨Ô´¼Ç¡·7.3ÈÕÊ״ι«²â</a></li><li><a href="http://kan.sina.com.cn/zq/sqcs" target="_blank">¡¶ÉñÆ÷´«Ëµ¡·È«Ãñ¹«²â</a> <a href="http://kan.sina.com.cn/zq/qjmu" target="_blank">¡¶Ææ¼£MU¡·S9аæÕýʽÉÏÏß</a></li><li><a href="http://kan.sina.com.cn/zq/qbzz" target="_blank">¡¶³à±ÚÖ®Õ½¡·ÔÙÏÆÈÈѪ·ç³±</a> <a href="http://kan.sina.com.cn/zq/dtcq" target="_blank">¡¶µ¶Ëþ´«Ææ¡·ÐÂ×ÊÁÏƬÀ´Ï®</a></li><li><a href="http://kan.sina.com.cn/anchor/" target="_blank">Ã÷ÐÇÖ÷²¥</a>| -<a href="http://kan.sina.com.cn/u/1780682544" target="_blank">·½ÖÛ ÍÀÁúÓÂÊ¿K×Ü</a> -<a href="http://kan.sina.com.cn/u/yangxiaomu/3475091" target="_blank">¡¶ÓÀºãÖ®Ëþ¡·»³¾ÉÖ±²¥</a></li> -<li><a href="http://kan.sina.com.cn/activity/" target="_blank">»î¶¯ÈüÊÂ</a>| -<a href="http://kan.sina.com.cn/u/1875984205" target="_blank">WCAְҵԤѡÈü</a> <a target="_blank" href="http://kan.sina.com.cn/u/2609950594">2015̹¿ËÊÀ½ç³¬¼¶ÁªÈü¼¾ºóÈü</a></li> -<li><a href="http://kan.sina.com.cn/hotgirls/" target="_blank">ÃÀŮֱ²¥</a>| <a href="http://kan.sina.com.cn/u/2413262821/3476622" target="_blank">Ôºߺߺϳè¼Ç</a> <a href="http://kan.sina.com.cn/u/5611043726/3476536" target="_blank">ÃλÃÎ÷ÓÎÃÀòµÄµÚÒ»·òÈË</a></li> -<li><a href="http://kan.sina.com.cn/dj/" target="_blank">µç¾ºÊÀ½ç</a>| -<a href="http://kan.sina.com.cn/u/3976780317" target="_blank">ÂÞÂíÖ®¼Ò±ÈÈüÖ±²¥</a> <a target="_blank" href="http://kan.sina.com.cn/act/qmlushi">¯ʯ´«ËµÈ«Ãñ´´ÖÆ´óÈü</a></li> -<li><a href="http://kan.sina.com.cn/zq/gaoqing1" target="_blank">¸ßÇåƵµÀ</a>| -<a href="http://kan.sina.com.cn/u/2890524092/" target="_blank">DGµç¾º¾ãÀÖ²¿Ö±²¥</a> <a target="_blank" href="http://kan.sina.com.cn/u/2497298463">µçÍæƵµÀE3ÓÎÏ··¢²¼»á</a></li> - </ul> -</textarea> - </div> - - </div> - </div> - </div> - <!-- mod34 --> - </div> - </div> - <!-- part-k end --> - <div class="blank-cont" style="height:25px;"></div> - <!-- part-l begin --> - - <div class="part-l clearfix"> - <div class="part-l-l"> - <!-- mod35 --> - <div class="mod-13 mod-02" data-sudaclick="blk_zycg"> - <div class="tit02 clearfix"> - <h3><a href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNDIxNA%3D%3D&sign=02562632d22fe03f&url=http%3A%2F%2Fzhongyi.sina.com%2Fcustomer_index.shtml" target="_blank">ÖÐÒ½³É¹û</a></h3> - </div> - <div class="mod13-cont" style="width:240px;_width:238px;padding:0;margin-left:-1px; _margin-left:0px;"> -<a target="_blank" href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjc3MQ%3D%3D&sign=82b4c6ecb1dbf379&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fredian-1a%2F"><img src="http://d5.sina.com.cn/201506/16/1029597.jpg" style="width:240px;_width:238px;"/></a> - -<a target="_blank" href="http://sax.sina.com.cn/click?type=nonstd&t=REowMDAwNjY0MQ%3D%3D&sign=0ae3d42ac8ee03d9&url=http%3A%2F%2Fwww.zhongyi-800.com%2Fzt%2Fredian-2a%2F"><img src="http://d4.sina.com.cn/201506/16/1029596.jpg" style="width:240px;_width:238px;margin-top:5px;"/></a> - - </div> - </div> - <!-- mod35 --> - </div> - <div class="part-l-m"> - <!-- mod36 --> - <div class="uni-blk" id="SI_Order_M" tab-type="tab-wrap" struc="1-5"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://redirect.simba.taobao.com/rd?c=un&w=channel&f=http%3A%2F%2Fwww.taobao.com%2Fgo%2Fact%2Fmmbd%2Fpdnew.php%3Fpid%3Dmm_15890324_2192376_13096223%26unid%3D&k=30375390a8b21737&p=mm_15890324_2192376_13096223" target="_blank">ÉÌѶ</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - - <div class="uni-blk-b SC_Order_Fix_Cont"> - -<iframe src="http://d3.sina.com.cn/litong/zhitou/union/tanx.html?pid=mm_15890324_2192376_13096223&type=html" width="360" height="242" frameborder="0" scrolling="no"></iframe> - -<!-- -<iframe src="http://www.taobao.com/go/act/sale/xlsyzt.php" width="360" height="247" style="margin-left:-10px; margin-top:-10px;" frameborder="0" scrolling="no"></iframe> ---> - - </div> - - </div> - </div> - <!-- mod36 --> - </div> - <div class="part-l-r"> - <!-- mod37 --> - <div class="uni-blk" id="SI_Order_N" tab-type="tab-wrap" struc="1-5"> - - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://sea.sina.com.cn/" target="_blank">×ÊѶ</a></span> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li style="margin-right:20px;"><ins class="sinaads" data-ad-pdps="PDPS000000055132"></ins><script type="text/javascript">(sinaads = window.sinaads || []).push({})</script></li> -<li><a href="http://iask.sina.com.cn/" target="_blank">°®ÎÊ</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont"> - - <div class="uni-blk-bt clearfix"> - -<div id="gina_res_show1356" style="float:left;width:107px;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052113"></ins> - <script>(sinaads = window.sinaads || []).push({params: { - sinaads_ad_width: 105, - sinaads_ad_height: 90, - sinaads_ad_tpl: [ - '<a href="#{link0}" onclick="try{#{monitor}}catch(e){}" target="_blank" class="uni-blk-pic"><img src="#{src0}" width="105" height="70" />', - '<span>', - '#{src1}', - '</span>', - '</a>' - ].join('') - }});</script> - - <!-- ×ÊѶ105*90ͼÎĹã¸æ02 Start --> - <ins class="sinaads" data-ad-pdps="PDPS000000056020" style="padding-top:18px;"></ins> - <script>(sinaads = window.sinaads || []).push({params : { - sinaads_ad_width : 105, - sinaads_ad_height : 90, - sinaads_ad_tpl: [ - '<a href="#{link0}" onclick="try{#{monitor}}catch(e){}" target="_blank" class="uni-blk-pic"><img src="#{src0}" width="105" height="70" />', - '<span>', - '#{src1}', - '</span>', - '</a>' - ].join('') - }});</script> - <!-- ×ÊѶ105*90ͼÎĹã¸æ02 End --> -</div> - -<style> -.list-news20150310 li{ - padding-left: 10px; - line-height: 25px !important; - height: 25px; - overflow: hidden; - font-size: 14px; - background: url(http://i0.sinaimg.cn/home/main/index2013/0403/icon.png) no-repeat 0 -881px; - _zoom: 1; -} -</style> - -<ul class="uni-blk-list01 list-a list-news20150310" id="gina_res_show1355"> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052114"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052115"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052116"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052117"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="margin-top:9px;line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052119"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052121"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052123"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> - <li style="line-height:25px !important;"> - <ins class="sinaads" data-ad-pdps="PDPS000000052125"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> - </li> -</ul> - - </div> - <div class="blk-line"></div> - -<ul class="uni-blk-list02 list-a" id="gina_res_show1332"> -<li> - <ins class="sinaads" data-ad-pdps="PDPS000000052126"></ins> - <script>(sinaads = window.sinaads || []).push({});</script> -</li> -</ul> - - </div> - - </div> - </div> - </div> - <!-- mod37 --> - </div> - </div> - <!-- part-l end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-m begin --> - <div class="part-m"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸04¹ã¸æ begin --> -<div id="ad_46020" class="ad-banner mb25"> -<ins class="sinaads" data-ad-pdps="PDPS000000046020"></ins> -<script>(sinaads = window.sinaads || []).push({});</script> -</div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸04¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- part-m end --> - - <!-- part-n begin --> - - <div class="part-n clearfix"> - <div class="part-n-l"> - <!-- mod38 --> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x355 1ÂÖ²¥°´Å¥07¹ã¸æ begin --> -<div id="ad_46021" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046021"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x355 1ÂÖ²¥°´Å¥07¹ã¸æ end --> -<!--_SINA_ADS_END_--> - <!-- mod38 --> - </div> - <div class="part-n-m"> - <!-- mod41 --> - <div class="uni-blk" id="SI_Order_P" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://eladies.sina.com.cn/" target="_blank">Å®ÐÔ</a></span> - <span tab-type="tab-nav"><a href="http://eladies.sina.com.cn/feel/" target="_blank">Çé¸Ð</a></span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_3"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_eladies_1" blkclick="auto_nav" blktitle="Å®ÐÔ"> -<!-- publish_helper name='Å®ÐÔÇø¿é' p_id='30' t_id='110' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://eladies.sina.com.cn/photo/" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/lx/old2013/photo/idx/2015/0617/U6929P8T440D1F14806DT20150617152735.jpg" width="105" height="70" /> - - <span>̨Íå×îÃÀÕ¬ÄÐÅ®Éñ</span> - - </a><ul class="uni-blk-list01 list-a"><li><a href="http://eladies.sina.com.cn/" target="_blank" class="linkRed01">Í·Ìõ|²»ÅÂɽկ ÌÆæÌÓÐN¿îÏÞÁ¿°ü</a></li> - - <li><a href="http://eladies.sina.com.cn/feel/" target="_blank">Çé¸Ð</a>| <a target="_blank" href="http://eladies.sina.com.cn/feel/xinli/2015-06-18/0802/doc-ifxczyze9670917.shtml" class="linkRed01">Áµ°®8Àà¶ñÅ®</a> <a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0803/doc-ifxczyze9632377.shtml" class="linkRed01">ÎҰܸøСÈý</a></li> - - <li><a href="http://eladies.sina.com.cn/news/" target="_blank">»¨±ß</a>| <a href="http://eladies.sina.com.cn/news/star/2015-06-18/0759/doc-ifxczqan1507381.shtml" target="_blank" class="linkRed01">ÁÖ־ӱ쟹</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-18/0740/doc-ifxczqar0984241.shtml" class="linkRed01">³ÉÁú²»Ê¶À</a></li> - -<li><a href="http://fashion.sina.com.cn/luxury/" target="_blank" class="linkRed01">Éú»î</a>| <a target="_blank" href="http://fashion.sina.com.cn/luxury/watch/" class="linkRed01">ʱ÷Ö±ãÒËÍó±í</a> <a target="_blank" href="http://fashion.sina.com.cn/d/he/2015-06-18/0751/doc-ifxczqap3911739.shtml" class="linkRed01">6ÖÖ³¤ÊÙʳÎï</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://fashion.sina.com.cn/style/" target="_blank">·þÊÎ</a>| - -<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60851.html#p=1" class="linkRed01">×îÇ¿¼¡ÈâÄÐÐǽÖÅÄ</a> -<a target="_blank" href="http://fashion.sina.com.cn/s/ce/2015-06-18/0744/doc-ifxczyze9463092.shtml" class="linkRed01">±´Ð¡ÆßÍÁºÀ×°±¸</a> -<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60827.html#p=1" class="linkRed01">¾®°ØÈ»ÂôÃÈ</a> - -</li> - -<li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>| - <a target="_blank" href="http://fashion.sina.com.cn/b/mk/2015-06-18/0739/doc-ifxczyze9675538.shtml" class="linkRed01">Ñî×ÏײÁ³6Å®ÐÇ</a> -<a target="_blank" href="http://fashion.sina.com.cn/b/sk/2015-06-18/0748/doc-ifxczqar0956008.shtml" class="linkRed01">Å®ÐÇËØÑÕpkÕ½</a> -<a target="_blank" href="http://fashion.sina.com.cn/b/ha/2015-06-18/0748/doc-ifxczyze9594720.shtml" class="linkRed01">Í··¢±âËúÔõôÆÆ</a></li> - -<li><a href="http://fashion.sina.com.cn/wedding/" target="_blank" class="linkRed01">»é¼Þ</a>| <a href="http://fashion.sina.com.cn/w/re/2015-06-18/0755/doc-ifxczqap4212630.shtml" target="_blank" class="linkRed01">È«Ö°Ì«Ì«µÄ10¸ö±×¶Ë</a> - -<a href="http://fashion.sina.com.cn/match/" target="_blank">ÃÀ´î</a>| -<a href="http://slide.fashion.sina.com.cn/m/slide_24_66132_60808.html" target="_blank" class="linkRed01">¸ßÔ²Ô²BabyÐÔ¸ÐïοÕ</a></li> - -<li><a href="http://eladies.sina.com.cn/photo/" target="_blank">ÃÀͼ</a>| -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24707.html" target="_blank" class="linkRed01">ÁøÑÒË«·å°ÁÈË</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24714.html" target="_blank" class="linkRed01">˽·¿Ð´Õæ</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24712.html" target="_blank" class="linkRed01">ÏÄÈÕÅ®Éñ</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24715.html" target="_blank" class="linkRed01">´¿É«ÄÚÒÂÅ®ÀÉ</a></li> - -<li><a href="http://eladies.sina.com.cn/news/" target="_blank" class="linkRed01">°ËØÔ</a>| - <a href="http://eladies.sina.com.cn/news/star/2015-06-18/0759/doc-ifxczqar0983993.shtml" target="_blank" class="linkRed01">ÑëÊÓÇ°Ö÷²¥×ß˽</a> -<a href="http://eladies.sina.com.cn/news/star/2015-06-18/0800/doc-ifxczqan1500694.shtml" target="_blank" class="linkRed01">·¶±ù±ù¾ÈÄÐͯ</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-18/0800/doc-ifxczqap4197873.shtml" class="linkRed01">Íô·å¡°½è¼ø¡±Ö£¾û</a></li> - -<li><a href="http://eladies.sina.com.cn/qg/koushu/" target="_blank" class="linkRed01">¿ÚÊö</a>| -<a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0803/doc-ifxczqap4168902.shtml" class="linkRed01">ÒÔ»³ÔÐÍìÁôËû</a> <a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0805/doc-ifxczqar0954571.shtml" class="linkRed01">ÀϹ«°®¿´ÍøÉÏÃÀÅ®</a> <a target="_blank" href="http://eladies.sina.com.cn/feel/koushu/2015-06-18/0804/doc-iawzuney6592149.shtml" class="linkRed01">ÕÉ·òƵ·±³ö¹ì</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/column/">רÀ¸</a>| -<a target="_blank" href="http://blog.sina.com.cn/lm/eladies/ " class="linkRed01">ÄÐÅ®ºÃÉ«Çø±ð</a> -<a target="_blank" href="http://blog.sina.com.cn/s/blog_8e59d2630102vl07.html?tj=1" class="linkRed01">°®ÉÏ×ø̨Ůº¢</a> - -<a target="_blank" href="http://blog.sina.com.cn/s/blog_6f3ba5d90102vsqn.html?tj=1" class="linkRed01">ÄÐÓѽ»8¸öÇéÈË</a> -</li> - -<li><a target="_blank" href="http://eladies.sina.com.cn/bbs/">ÂÛ̳</a>| <a target="_blank" href="http://club.eladies.sina.com.cn/slide.php?tid=6461257" class="linkRed01">Å®Ö÷²¥ÉîÒ¹ÆØÂã±³(ͼ)</a> <a target="_blank" href="http://fashion.sina.com.cn/try/product/1055" class="linkRed01">ÇÀÖ²´åÐãÐÂÆ·Ë«É«ÕÚ覱Ê</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_eladies_3" blkclick="auto_nav" blktitle="Çé¸Ð"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='Çé¸ÐÇø¿é' p_id='30' t_id='110' d_id='3' --> - <div class="uni-blk-bt clearfix"> -<a href="http://eladies.sina.com.cn/feel/xinli/2015-06-18/0739/doc-ifxczyze9669913.shtml" target="_blank" class="uni-blk-pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150618/P5KK-fxefurs2581152.jpg" width="105" height="70" /> - - <span>½ÌÄãÈçºÎʶ±ðÔüÄÐ</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://eladies.sina.com.cn/feel/xinli/2015-06-17/0729/doc-ifxczyze9630586.shtml" target="_blank">½ÒÃØΪʲôÄÐŮϲ»¶¸ãêÓÃÁ</a></li> - -<li><a href="http://eladies.sina.com.cn/feel/xinli/2015-06-17/0729/doc-ifxczqar0954236.shtml" target="_blank">´óÊåµ±µÀ Å®ÈËΪºÎ»áϲ»¶ÀÏÄÐÈË</a></li> - -<li><a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqan0628752.shtml" target="_blank">ÕÅÌúÁÖÆØÓÐ˽Éú×Ó</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqan0631899.shtml">½´¨»éÀñ</a></li> - -<li><a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczyze9619106.shtml" target="_blank">·¶±ù±ù¾ÈÄк¢</a> <a target="_blank" href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqan0633143.shtml">´óSÔøΪСSÆíµ»</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1659/doc-ifxczqar1000167.shtml" target="_blank">ÀϹ«ÅÂÇéÈËÀ´¼Ò´óÄÖ¶øʧ×Ù</a> -<a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1722/doc-ifxczqar1001074.shtml" target="_blank">ÄÐÓѳԷ¹²»ÌÍÇ®ÎÒ»éÇ°ÑøËû</a></li><li><a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1725/doc-ifxczqap4215670.shtml" target="_blank">¹ëÃÜÇÀÁËÎÒÄÐÓÑÎÒ¾¹²»ÖªµÀ</a> -<a href="http://eladies.sina.com.cn/feel/koushu/2015-06-17/1729/doc-ifxczqap4215925.shtml" target="_blank">Ç°·òÕÒÉÏÃÅÎÒ²ÅÖªËýÀë¹ý»é</a></li><li><a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczyze9619722.shtml" target="_blank">Àî°½Åú²ÌÒÀÁÖ×Գơ°ÀÏÄ</a> -<a href="http://eladies.sina.com.cn/news/star/2015-06-17/0731/doc-ifxczqar0941188.shtml" target="_blank">47ËêÏ¢Ó°Å®ÐÇÕÅÃô½üÕÕÆعâ</a></li><li><a href="http://blog.sina.com.cn/s/blog_49f747bc0102voxt.html?tj=1" target="_blank">ÄãÕæÐÄÏëÒª×ö¡°¶¡¿Ë¡±Âð</a> -<a href="http://blog.sina.com.cn/s/blog_49b486130102vvuu.html?tj=1" target="_blank">ÖйúÄÐÈËÊܹ»ÁËÖйúÅ®ÈË£¿</a></li><li><a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24694.html" target="_blank">άÃØÌìʹÏÄÈÕÇåÐÂÓ¾×°´óƬ</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24656.html" target="_blank">Ð콿½üÕÕÄæÉú³¤ËÆÂÜÀò</a></li><li><a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24678.html" target="_blank">Á½´ó³¬Ä£º£±ßϷˮ˫·å°ÁÈË</a> -<a href="http://slide.eladies.sina.com.cn/news/slide_3_67873_24677.html" target="_blank">AKB48×îÐÔ¸ÐÅ®ÉñСëÑô²Ë</a></li> - -<li><a href="http://blog.sina.com.cn/s/blog_6f3ba5d90102vst3.html?tj=lady" target="_blank">ÎÒûÅö¹ýÅ®ÓÑËýÈ´»³ÔÐ</a> -<a href="http://blog.sina.com.cn/s/blog_51177cc40102vmh5.html?tj=lady" target="_blank">СÈýÉÏÃÅÀϹ«±§×ÅÎÒÈÃËý´ò</a></li> - -<li> - -<a href="http://fashion.sina.com.cn/zl/love/2015-05-05/14113459.shtml" target="_blank">ÖйúÄÐÈËΪʲôϲ»¶ÐíÇ磿</a> -<a href="http://fashion.sina.com.cn/zl/fashion/2015-06-16/16363778.shtml" target="_blank">¼Þ¸ø×êʯÄеÄÆ«Æ«ÊÇËýÃÇ</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod41 --> - - </div> - <div class="part-n-r"> - - <!-- mod40 --> - <div class="uni-blk" id="SI_Order_O" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://house.sina.com.cn/" target="_blank">·¿²ú</a></span> - <span tab-type="tab-nav"><a href="http://esf.sina.com.cn/" target="_blank">¶þÊÖ·¿</a></span> - <span tab-type="tab-nav"><a href="http://jiaju.sina.com.cn/" target="_blank">¼Ò¾Ó</a></span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_2"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - - <ul class="mod44-list clearfix SC_Order_Hidden"> - <li><a href="http://finance.sina.com.cn/sf/list/?cate_id=50025969&cat_name=%E6%88%BF%E4%BA%A7" target="_blank" suda-uatrack="key=index_sfpm&value=housesf">·¿²úÅÄÂô</a></li> - </ul> - - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_house_1" blkclick="auto_nav" blktitle="·¿²ú"> -<!-- publish_helper name='house_·¿²ú_Çø¿é' p_id='30' t_id='109' d_id='6' --> -<div class="uni-blk-bt clearfix" id="SI_IP_House_0"> -<!-- 09:43:41 --> -<a href="http://bj.house.sina.com.cn/zhuanti/zxsh/index.shtml" target="_blank" class="uni-blk-pic"><img src="http://src.house.sina.com.cn/imp/imp/deal/e8/c9/2/405057288770cda8e38fc45502c_p24_mk24.jpg" width="105" height="70"/><span>¶ËÎçôÕÏíÊ¢»Ý</span> -</a><ul class="uni-blk-list01 list-a"> -<li><a href="http://search.house.sina.com.cn/bj/news/" target="_blank" class="col_8">ÐÂÎÅ</a><i>|</i><a href="http://bj.house.sina.com.cn/" target="_blank">5Ô¾©ÉÌס¼Û¸ñ»·±ÈÕÇ1.4%</a></li> - -<li><a href="http://bj.house.sina.com.cn/exhibit/" target="_blank" class="col_8">רÌâ</a><i>|</i><a href="http://bj.house.sina.com.cn/exhibit/forlovepapa/index.shtml" target="_blank" class="col_8">Ϊ°®±¼ÅÜÀÖ¾Ó¸¸Ç×½ÚîÒ»Ý</a></li> - -<li><a href="http://bj.house.sina.com.cn/exhibit/" target="_blank" class="col_8">Êг¡</a><i>|</i><a href="http://bj.house.sina.com.cn/scan/2015-06-12/18406015075033695957695.shtml"target="_blank" class="col_8">ÂòºÃ·¿ÐÄÇéºÃ¹ý±±¾©À¶Ìì</a></li> - -<li><a href="http://data.house.sina.com.cn/bj/new/" target="_blank" class="col_8">¿´·¿</a><i>|</i><a href="http://bj.house.sina.com.cn/zhuanti/6.27dxkft/index.shtml" target="_blank" class="col_8">6.27ÏÄÈÕ¹º·¿¼¾¿´·¿ÍÅ - -</a></li> -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<!-- 10:20:10 --> -<li id="SI_IP_House_1"><a href="http://search.house.sina.com.cn/bj/news/scdt/" target="_blank" class="linkRed03">ÐÂÎÅ</a>| <a href="http://bj.house.sina.com.cn/news/2015-06-18/07096017075518384681085.shtml" target="_blank">±±¾©¹«»ý½ðÔ½ɴæÉÏÏÞÔö484Ôª</a> <a href="http://bj.house.sina.com.cn/news/2015-06-18/07226017078769838502906.shtml" target="_blank">ÀöÔóµØÏ»·ÀÈ¿ª½¨</a></li> - -<li id="SI_IP_House_2"><a href="http://data.house.sina.com.cn/bj/dianping/" target="_blank">Â¥ÆÀ</a>| <a target="_blank" href="http://bj.house.sina.com.cn/scan/2015-06-02/11236011341189431997262.shtml">ÌìÆøÈȲ»¼°Â¥ÊÐÈÈ</a> <a target="_blank" href="http://bj.house.sina.com.cn/scan/2015-06-04/11236012065931063505297.shtml?qq-pf-to=pcqq.discussion">×ß·¸ß¿¼²»ÏÞºÅ</a></li> - -<li id="SI_IP_House_3"><a href="http://bj.house.sina.com.cn/bbs/" target="_blank">»¥¶¯</a>| <a href="http://blog.sina.com.cn/s/blog_48f319170102vmvk.html?tj=1" target="_blank">¿ªÕ÷·¿²úË°¶ÔÂ¥ÊÐÁù´óºÃ´¦</a> <a href="http://bj.bbs.house.sina.com.cn/thread-6014597615063158347.html"target="_blank">6ºÅÏßÎ÷ÑÓ6Õ¾Á¬ÉÏÆ»¹ûÔ°</a> </li> - -<li id="SI_IP_House_4"><a href="http://house.sina.com.cn/" target="_blank">Èȵã</a>| </i><a href="http://bj.house.sina.com.cn/news/2015-06-18/06556017072009572561844.shtml" target="_blank">±±¾©²ð³ýȺ×â·¿573»§</a> <a href="http://bj.house.sina.com.cn/news/2015-06-18/06596017072981782868816.shtml" target="_blank">±¾ÔÂÖÁ9Ô½«¼¯ÖÐÖÎÀí</a></li> - -<li><a href="http://house.sina.com.cn/" target="_blank">ÒªÎÅ</a>| <a href="http://tj.house.sina.com.cn/news/2015-06-18/08116017090895957243317.shtml" target="_blank">Íâ×ʹºÂòÖйúÂ¥Êлò·Å¿ª</a> <a href="http://tj.house.sina.com.cn/news/2015-06-18/08096017090551437112820.shtml" target="_blank">ÍÁµØ²ÆÕþÒÀÀµÖ¢ÈÔδ½â</a></li> - -<li><a href="http://news.leju.com/" target="_blank">Éî¶È</a>| <a href="http://news.leju.com" target="_blank">Íò¿Æ¸ß¹ÜÔٶȵ÷Õû</a> <a href="http://news.leju.com/view/6017120441414930210.html" target="_blank">Â¥ÊÐÅÝÄ­µÄÒÕÊõ»¯ÓëÉú´æ</a></li> - -<li id="SI_IP_House_5"><a href="http://esf.sina.com.cn/" target="_blank">¶þÊÖ·¿</a>| <a href="http://bj.esf.sina.com.cn/act/house" target="_blank">ÈÏÖ¤·¿³ÏÐÅ·¿Ô´´óÁªÕ¹</a> <a href="http://j.eju.com/login" target="_blank">ÖйúÍøÂç¾­¼ÍÈËÁªÃË</a></li><li><a href="http://jiaju.sina.com.cn/" target="_blank" class="linkRed03">¼Ò¾Ó</a>| <a href="http://jiaju.sina.com.cn/news/j/20150618/6017110069639184416.shtml?utm_source=snls&utm_medium=nrw&utm_campaign=n_9999" target="_blank">½ÌÄã×°ÐÞͼֽµÄС֪ʶ</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/?utm_source=snls&utm_medium=nrw&utm_campaign=n_9998">148ƽÈËÎľӾ«ÖÂÉÏÑÝ</a></li> - </ul> - - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_house_2" blkclick="auto_nav" blktitle="¶þÊÖ·¿"> -<!-- publish_helper name='¶þÊÖ·¿Çø¿é' p_id='30' t_id='129' d_id='4' --> - - <div class="uni-blk-bt clearfix" id="SI_IP_House_10"> -<!-- 10:25:06 --> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_wx/weixin20150612xm/" target="_blank" - -class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.esfimg.com/imp/537d3c60d0c582b11a30d299d1cf5ee9_os433ec8.jpg" - -width="105" height="70" border="0" /><span>ÖÃÒµÕß×ø²»×¡ÁË</span> -</a> - -<ul class="uni-blk-list01 list-a"> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150611lzq/" - -target="_blank">µØÌú´ø»ðÑོ 8Ì×·¿ÇÀÏÈ¿´</a></li> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150611zwy/" - -target="_blank">¸ÄÉƵ±µÀ²ýƽ´ó»§¾ù¼Û2ÍòÆð</a></li> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150608gxz/" - -target="_blank">É˲»Æð£¡ÂòÍê2СÇø¾ÍÕǼÛ</a></li> -<li><a href="http://bj.esf.sina.com.cn/news/hd/sina_wx/weixin20150613gxz/" target="_blank"> - -ÂòѧÇø·¿Ç§Íò±ðÓÌÔ¥</a></li> -</ul> - - </div> - <div class="blk-line"></div> - -<!-- 10:21:04 --> -<ul class="uni-blk-list02 list-a" id="SI_IP_House_11"> - -<li> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50832" class="linkRed03">ÔçѶ</a>| -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50888" target="_blank">¾©Ð·¿¹©Ó¦Ôö¼Ó </a> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50881" target="_blank">ÉÏ°ëÔ¶þÊÖ·¿³É½»Á¿ÕÇ250%</a> -</li> - -<li> -<a href="http://esf.sina.com.cn/" >¿´µã</a>| -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50887" target="_blank">ͨÖݶþÊÖ·¿±©Õǽü15Íò</a> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50875" target="_blank">ºÀÕ¬³É½»Ê®Ç¿¾©Î÷Õ¼6</a> -</li> - -<li> -<a href="http://esf.sina.com.cn/" >½â¶Á</a>| -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50886" target="_blank">Âò·¿Ê²Ã´Ê±»ú×îºÏÊÊ</a> -<a href="http://bj.esf.sina.com.cn/news_show.php?id=50879" target="_blank">Ë­ÔÚΪ·è¿ñµÄºÀÕ¬Âòµ¥</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >רÌâ</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150608gxz/" target="_blank">Õâ2СÇøÂòÍê¾ÍÕǼÛ</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150604xm/" target="_blank">°Ù×ÓÍå´ø»ðºóÏÖ´ú³Ç</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >ÍƼö</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150605xjl/" target="_blank">¼ÒµÄºó»¨Ô°¾ÍÊÇÔ²Ã÷Ô°</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150605xjl/" target="_blank">¹«»ý½ðÂòµÃÆð·¿É½´ó·¿</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >¶À¼Ò</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150604lzq/" target="_blank">ÃûУÔú¶Ñ Íû¾©9·¿¼±ÊÛ</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150602gxz/" target="_blank">³´¹É²»ÈçÂò·¿Õæʵ</a> -</li> - -<li><a href="http://esf.sina.com.cn/" >µ¼¹º</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150529xjl/" target="_blank">Âò·¿£¡¼ÒÃÅ¿ÚÓÐË«µØÌú</a> -<a href="http://bj.esf.sina.com.cn/news/hd/sina_daogou/daogou20150529gxz/" target="_blank">¸Õ½úÉýѧÇøÈëÊÖÒ»Ì×£¡</a> -</li> - -<li> -<a href="http://esf.sina.com.cn/" >µ¼¹º</a>| -<a href="http://bj.esf.sina.com.cn/news/hd/index/" target="_blank">רÌâÍÆ·¿</a> -<a href="http://bj.esf.sina.com.cn/house/c1/" target="_blank">150ÍòÄÚ</a> -<a href="http://bj.esf.sina.com.cn/house/e1/" target="_blank">±±Æ¯</a> -<a href="http://bj.esf.sina.com.cn/house/c0,300-e3/" target="_blank">СÈý·¿</a> -<a href="http://bj.esf.sina.com.cn/house/b7-a16/" target="_blank">ºÀÕ¬</a> -<a href="http://bj.esf.sina.com.cn/house/oÐÂÕþ/?" target="_blank">ÐÂÕþ</a> -</li> - -</ul> - - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_house_3" blkclick="auto_nav" blktitle="¼Ò¾Ó"> -<!-- publish_helper name='¼Ò¾ÓÇø¿é' p_id='30' t_id='129' d_id='5' --> -<div class="uni-blk-bt clearfix"> <a href="http://zx.jiaju.sina.com.cn/anli/?utm_source=snls&utm_medium=nrw&utm_campaign=n_9993" target="_blank" class="uni-blk-pic" title="ÓÅÑÅÊæÊʼ«ÁË"> <img src="http://src.house.sina.com.cn/imp/imp/deal/ca/c3/2/c09258da42a8bbf06e08d25aaf4_p24_mk24.jpg" width="105" height="70" /><span>ÓÅÑÅÊæÊʼ«ÁË</span></a> - <ul class="uni-blk-list01 list-a"> - <li><a href="http://jiaju.sina.com.cn/news/j/20150618/6017110069639184416.shtml?utm_source=snls&utm_medium=nrw&utm_campaign=n_9997" target="_blank">½ÌÄãÈçºÎ¿´×°ÐÞͼֽµÄС֪ʶ</a></li> - <li><a href="http://jiaju.sina.com.cn/haoguanjia/119.html?utm_source=snls&utm_medium=nrw&utm_campaign=n_9996" target="_blank">ÈçºÎ¹¹ÖþȫеÄÉú»î·½Ê½Ìåϵ</a></li> - <li><a href="http://zx.jiaju.sina.com.cn/anli/105781.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9995" target="_blank">СÇåÐÂ133ƽìŲÊʱÉÐÏÖ´ú3¾Ó</a></li> - <li><a href="http://zx.jiaju.sina.com.cn/anli/105713.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9994" target="_blank">âñÈ»ÐĶ¯³©Ïí180ƽÃÀʽÎÂÜ°</a></li> - </ul> -</div> -<div class="blk-line"></div> -<ul class="uni-blk-list02 list-a"> - <li><a href="http://jiaju.sina.com.cn/news/20150618/6016885348175774650.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9992" target="_blank">¼Ò¾Ó·çË®²»Àû»áÈÃÄ㩲Æ</a> <a href="http://jiaju.sina.com.cn/news/fengshui/20150618/6017109213304914880.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9984" target="_blank">¸ÃÈçºÎÍØÕ¹ÄãµÄ¼Ò¾Ó²ÆÔË</a></li> - <li><a target="_blank" href="http://zx.jiaju.sina.com.cn/?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9976">¸ßÇå</a>| <a href="http://zx.jiaju.sina.com.cn/anli/106034.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9991" target="_blank">ÍñתµÄ¾ªÑÞ89ƽºÚ°×¾Ó</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/105871.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9983">ÑÅȤÈý¿ÚÖ®¼ÒÃ÷Ãĸñµ÷</a></li> - <li><a target="_blank" href="http://www.qianggongzhang.com/anli/">×°ÐÞ</a>| <a href="http://jiaju.sina.com.cn/news/20150617/6016758925029081130.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9990" target="_blank">¾«Ñ¡20Ìõ´ÉשװÐÞ¾÷ÇÏ</a> <a target="_blank" href="http://wh.jiaju.sina.com.cn/news/j/20150618/6017111381005110285.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9982">±ÜÃâ×°ÐÞÖÐÒ×·¸µÄ´íÎó</a></li> - <li><a target="_blank" href="http://jiaju.sina.com.cn/decoration/">¹¥ÂÔ</a>| <a href="http://tj.jiaju.sina.com.cn/news/j/20150618/6017106628254696245.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9985" target="_blank">Ïļ¾ÎÀÔ¡Æ·±£ÑøµÄÃØ·½</a> <a target="_blank" href="http://jiaju.sina.com.cn/news/j/20150618/6017111632969531740.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9977">ÈýÖÖÓÍÑÌ»úÓÅȱµã½âÎö</a></li> - <li><a target="_blank" href="http://jiaju.sina.com.cn/decoration/">רÌâ</a>| <a href="http://zx.jiaju.sina.com.cn/anli/105889.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9989" target="_blank">ÈáÇé119ƽÐÂÖÐʽ¼ò½à·ç</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/105820.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9981">¾øÃÀ·çÉÐ98ƽÐÄÁé¾»ÍÁ</a></li> - <li><a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9975">ÃÀͼ</a>| <a href="http://supports.jiaju.sina.com.cn/dzjz/index.php?_a=detail&id=1246?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9988" target="_blank">¸ÐÊÜÉú»îÇéȤµÄС¹«Ô¢</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/105623.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9980">125ƽ³Á¾²Ö®ÃÀйŵä</a></li> - <li><a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/c1/?utm_source=snls&utm_medium=nrw&utm_campaign=n_9972">Éè¼Æ</a>| <a href="http://zx.jiaju.sina.com.cn/anli/105788.html?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9973" target="_blank">150ƽÐÒ¸£ÒݼÒдÒâ¿Õ¼ä</a> <a target="_blank" href="http://zx.jiaju.sina.com.cn/anli/106017.html -?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9974">9Íò¸ÄÔìÔ¡»ðÖØÉú¾ÉÎÝ</a></li> - <li id="SI_IP_House_13"><a target="_blank" href="http://jiaju.sina.com.cn/decoration/">´îÅä</a>| <a target="_blank" href="http://sh.jiaju.sina.com.cn/news/j/20150617/6016888288424823016.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9986">½ÌÄãËÄÕÐÌù³öÍêÃÀµØÃæ</a> <a target="_blank" href="http://sz.jiaju.sina.com.cn/news/j/20150618/6017115031790225571.shtml?utm_source=snls&amp;utm_medium=nrw&amp;utm_campaign=n_9978">ÃÈÍÞÄÖ·­ÌìµØ°åÇÀ¾È·¨</a></li> -</ul> - - </div> - </div> - </div> - </div> - <!-- mod40 --> - - </div> - </div> - <!-- part-n end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-o begin --> - - <div class="part-o"> - <div class="part-o-l"> - <!-- mod42 --> - <div class="mod-42 mod-13 mod-02"> - <div class="tit02 clearfix"> - <h3><a href="http://open.sina.com.cn/" target="_blank">ÐÂÀ˹«¿ª¿Î</a></h3> - </div> - <div class="mod42-cont" data-sudaclick="blk_edu_wkt" blkclick="auto_nav" blktitle="΢¿ÎÌÃ"> -<!-- publish_helper name='ÐÂÀË΢¿ÎÌÃ' p_id='30' t_id='111' d_id='3' --> -<div class="vid-txt clearfix"><a href="http://open.sina.com.cn/course/id_1192" target="_blank" class="vid"> - <img src="http://i1.sinaimg.cn/home/2015/0611/U684P30DT20150611113718.jpg" /> - <i class="vid-play-icon"></i> - </a> - <div class="txt"><h3><a href="http://open.sina.com.cn/course/id_1192" target="_blank" class="videoNewsLeft">ÈÕ±¾´«Í³ÎÄ»¯Ê·</a></h3> - <a href="http://open.sina.com.cn/" target="_blank" class="free-listen">¸ü¶à¿Î³Ì</a></div></div><div class="mod42-cont-b"><a target="_blank" href="http://open.sina.com.cn/course/id_946" class="videoNewsLeft">ƽÃæÉè¼ÆÈëÃÅ</a> <a target="_blank" href="http://open.sina.com.cn/school/id_146/" class="linkRed">ר¼Ò½ÌÄã¸ß¿¼Ö¾Ô¸Ì</a></div> - </div> - </div> - <!-- mod42 --> - <div class="blank-cont" style="height:20px"></div> - <!-- mod43 --> - <div class="mod-43"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x170 2ÂÖ²¥°´Å¥08¹ã¸æ begin --> -<div id="ad_45990" style="width:240px; height:170px;"><ins class="sinaads" data-ad-pdps="PDPS000000045990"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x170 2ÂÖ²¥°´Å¥08¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- mod43 --> - </div> - <div class="part-o-m"> - <!-- mod44 --> - <div class="uni-blk" id="SI_Order_Q" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://edu.sina.com.cn/" target="_blank">½ÌÓý</a></span> - <span tab-type="tab-nav"><a href="http://edu.sina.com.cn/a/" target="_blank">³ö¹ú</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> - -<li><a href="http://edu.sina.com.cn/college/" target="_blank">¹À·ÖÑ¡´óѧ</a> <a href="http://zhiyuan.edu.sina.com.cn/query/view/" target="_blank">ÍùÄê·ÖÊýÏß</a> <a href="http://zhiyuan.edu.sina.com.cn/default/lesson/" target="_blank">Ö¾Ô¸²Ò°Ü°¸Àý</a></li> - -<!-- -<li><a href="http://open.sina.com.cn/" target="_blank">¹«¿ª¿Î</a></li> -<li><a href="http://edu.sina.com.cn/gaokao/" target="_blank">¸ß¿¼</a></li> -<li><a href="http://edu.sina.com.cn/zxx/" target="_blank">ÖÐСѧ</a></li> -<li><a href="http://edu.sina.com.cn/bschool/" target="_blank">ÉÌѧԺ</a></li> ---> - </ul> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_edu_1" blkclick="auto_nav" blktitle="½ÌÓý"> -<!-- publish_helper name='½ÌÓýÇø¿é-ͼÎÄ' p_id='30' t_id='111' d_id='1' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://edu.sina.com.cn/photo/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U5539P30DT20150618081358.jpg" width="105" height="70" /> - <span>жÈÄïÅÄѧʿ·þÕÕ</span> -</a><ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://edu.sina.com.cn/">ΪÆø³¡Ä¸Ç×»¨10ÍòΪٶù°ìÒôÀÖ»á</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/gaokao/">1977-2014È«¹ú¸ß¿¼Â¼È¡ÂÊͳ¼Æ</a></li><li><a target="_blank" href="http://edu.sina.com.cn/college/">¹À·ÖѡУ</a> <a target="_blank" href="http://edu.sina.com.cn/gaokao/2015-06-18/1221473847.shtml">ºÓ±±10%¿¼Éú¿É¸ß¿¼¼Ó·Ö</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/gaokao/bzy/" class="linkRed">ÌáÇ°Åú²»¿ÉÇáÒ×·ÅÆú</a> <a target="_blank" href="http://zhiyuan.edu.sina.com.cn" class="linkRed">¼ȡ·ÖÊýÏß</a></li> -</ul> - </div> - <div class="blk-line"></div> - -<!-- publish_helper name='½ÌÓýÇø¿é-Áбí' p_id='30' t_id='111' d_id='5' --> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://edu.sina.com.cn/kaoyan/">˶ʿЯ×Ó±ÏÒµ(ͼ)</a> <a target="_blank" href="http://edu.sina.com.cn/official/2015-06-18/0806473762.shtml">±¨¿¼¹«ÎñÔ±Éí·Ý±»Ã°ÓÃ</a> <a target="_blank" href="http://edu.sina.com.cn/official/">¼ªÁÖÊ¡¿¼ÃæÊÔ</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/a/">ÁôѧÉúÃÀ¹úÂôÈâ¼ÐâÉ</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/0817260908.shtml">ѧ·Ñ×îÖµÃÀ´óѧ</a> <a target="_blank" href="http://edu.sina.com.cn/yimin/">Ï£À°Âò·¿Èý´úÒÆÃñ</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/foreign/">˯¾õÒ²ÄܸßЧ¼Çµ¥´Ê</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/073590292.shtml">¾Ü¾øÀÏÌ×ÃæÊÔ</a> <a target="_blank" href="http://edu.sina.com.cn/yyks/2015-06-18/0738473756.shtml">½âÍи£ÔĶÁ³¤ÄѾä</a></li><li><a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1003473786.shtml">Âí»¯ÌÚÓëÀÏÆÅQQ½áÔµ</a> <a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1106473825.shtml">ÁõÇ¿¶«600ÒÚÄÄÀ´</a> <a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1039473803.shtml">Angelababy×ܲÃ</a></li> -<li><a target="_blank" href="http://edu.sina.com.cn/zxx/">10ÐÐΪ×îÉËÍÞ×Ô×ð</a> <a target="_blank" href="http://edu.sina.com.cn/zxx/2015-06-18/0955473782.shtml">±ð±Æº¢×Ó˵¼Ù»°</a> <a target="_blank" href="http://edu.sina.com.cn/zxx/2015-06-18/0836473766.shtml">Äк¢ÄçÍöͬ°é²ØÒÂ</a></li> -<li><a href="http://edu.sina.com.cn/ischool/" target="_blank">ÇîÑøº¢×ÓÓ°ÏìÖÇÁ¦</a> <a target="_blank" href="http://edu.sina.com.cn/bschool/2015-06-18/1109473828.shtml">µÏ°ÝÇîÈ˺ÀÕ¬</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_6252b0bb0102vrd5.html?tj=1">ÓÃiphoneµÄÈ˸ü´ÏÃ÷£¿</a></li> -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_aad920be0102vs5l.html?tj=1">17ËêÅ®Éú±»ÔÞ4000ÄêÄÑÓö(ͼ)</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_afe7c7fe0102vpjr.html?tj=1">²»¿°ÈëÄ¿ÈÕ±¾Å®º¢¹ë·¿</a></li><li><a target="_blank" href="http://open.sina.com.cn/course/id_818/" class="videoNewsLeft">½ÌÄãÍæתÊýѧħÊõ</a> <a target="_blank" href="http://open.sina.com.cn/course/id_1208">º«¹úÁÏÀíÅëâ¿ÈëÃÅ</a> <a href="http://open.sina.com.cn/course/id_1188" target="_blank">·¢ÏÖÐÄÀíѧ</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_edu_2" blkclick="auto_nav" blktitle="³ö¹ú"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='³ö¹úÇø¿é' p_id='30' t_id='111' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://open.sina.com.cn/course/id_304" target="_blank" class="uni-blk-pic"> - -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0611/U9906P30DT20150611114512.jpg" alt="ÐÂÀ˹«¿ª¿Î" width="105" height="70" /> - -<span>ÊÀ½çÃûУ±ÏÒµÑݽ²</span></a> - -<ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://edu.sina.com.cn/a/2015-06-03/1112260472.shtml">ÄãÖªµÀÈçºÎÑ¡ÔñÒÆÃñÖнé»ú¹¹Âð£¿</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1038260920.shtml" target="_blank">ÔÚ°Ä´óÀûÑÇÁôѧÒÔ·¿Ñøѧ¿¿²»¿¿Æ×</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/1055260922.shtml">ÃÀ¹ú12Ëê¾øÖ¢ÉÙÅ®´´·þ×°Æ·ÅÆ(ͼ)</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/104990300.shtml">ͼ½â2100ÄêµÄµØÇò½«ÓжàÈÈ(Ë«Óï)</a></li> -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://edu.sina.com.cn/highschool/">ÃÀ¹úº£ÉÏ¿´Ï¦Ñô±»·ç´µ×ß</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-17/1552260901.shtml">ÂèÂèÇ×Êö£ºÎÒÅã¶ù×Ó¶ÁÃÀ¸ß</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1014260915.shtml" target="_blank">¼ÓÖݹ«Ô¢Â¥Ëú6Ãû°®¶ûÀ¼Ñ§ÉúÉíÍö</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/0823260909.shtml">È«Çò³ÇÊÐÉú»î³É±¾ÅÅÃû</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1046260921.shtml" target="_blank">ÃÀ´óѧУÄÚÐÄÀí¸¨µ¼ÔâÖÊÒÉ</a> <a href="http://edu.sina.com.cn/a/2015-06-18/1011260914.shtml" target="_blank">Ϊº¢×ÓÁôѧº«¹úÏÖ´óÑã¼ÒÍ¥</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/100790294.shtml">ÓÐЧÀûÓÃͼÊé¹Ý</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/100190293.shtml">ÃÀ¹úÈËÊܲ»Á˼ÓÄôó</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/103790298.shtml">Å®×ãÊÀ½ç±­ÈËÆø</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/101490295.shtml">»¥ÁªÍøʱ´ú¹ý¶È×ÔÐÅ</a> <a target="_blank" href="http://m.sina.com.cn/m/sinaopencourse.shtml">¹«¿ª¿Î¿Í»§¶Ë</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/101890296.shtml">10¸öÔñÒµ´íÎóÏë·¨</a></li><li><a target="_blank" href=" http://edu.sina.com.cn/en/2015-06-18/104490299.shtml">¸øÁ¦ÍŶÓÒµ¼¨²»¼ÑÕÕÑùÄý±½ð</a> <a target="_blank" href="http://edu.sina.com.cn/en/2015-06-18/103390297.shtml">·¬Çѵ½µ×ÊÇË®¹û»¹ÊÇÊß²Ë</a></li> - -<li><a target="_blank" href="http://edu.sina.com.cn/yyks/2015-06-18/1055473813.shtml">ÑÅ˼ÌýÁ¦¿¼ÊÔÈý´ó²½Öè</a> <a target="_blank" href="http://edu.sina.com.cn/yyks/2015-06-18/1058473818.shtml">GRE×÷ÎÄÖÐArgument¾­µäÄ£°å¾ä</a></li> - -<li><a href="http://edu.sina.com.cn/a/2015-06-18/1004260913.shtml" target="_blank">¶¥¼â¿¼¹Åרҵº£ÍâԺУ</a> <a target="_blank" href="http://edu.sina.com.cn/a/2015-06-18/1125260926.shtml">ÖйúÂ踰ÃÀ²ú×ÓÓö¡°Ìì¼ÛÕ˵¥¡±</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod44 --> - </div> - <div class="part-o-r"> - <!-- mod45 --> - <div class="uni-blk" id="SI_Order_R" tab-type="tab-wrap" struc="1-7"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://baby.sina.com.cn/" target="_blank" suda-uatrack="key=index_www_baby&value=baby_click">Óý¶ù</a></span> - <span tab-type="tab-nav"><a href="http://baby.sina.com.cn/" target="_blank" suda-uatrack="key=index_www_baby&value=childbirth_click">Ôвú</a></span> - </div> - <ul class="mod44-list clearfix SC_Order_Hidden"> -<li><a href="http://baby.sina.com.cn/guide/zhunbei.html" target="_blank">È«³ÌÓý¶ùÖ¸µ¼</a> <a href="http://kid.baby.sina.com.cn/" target="_blank">ÐÂÀ˶ùͯ</a></li> - </ul> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_baby_1" blkclick="auto_nav" blktitle="Óý¶ù"> -<!-- publish_helper name='Óý¶ùÇø¿é' p_id='30' t_id='112' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://baby.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11426P30DT20150618082154.jpg" width="105" height="70" /> - - <span>¼ÒÓжþÌ¥Ã÷ÐÇ</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://baby.sina.com.cn" target="_blank">ÓëÀÏÈËͬס»áÔö¼Ó²úºóÒÖÓô·çÏÕ£¿</a></li> - -<li><a href="http://baby.sina.com.cn/photo/" target="_blank">ͼƬ</a>|<a href=" http://slide.baby.sina.com.cn/bbshai/slide_10_846_28126.html" target="_blank">ÌðÜ°³±×°³ö¾µ</a> <a href="http://slide.baby.sina.com.cn/bbshai/slide_10_846_28213.html" target="_blank">½ÒãÎåºÃ·òÆÞ</a></li> - -<li><a href=" http://slide.baby.sina.com.cn/bbshai/slide_10_846_28214.html" target="_blank">°ÂÀò°ÚÅÄ´ïÈË</a> <a target="_blank" href=" http://slide.baby.sina.com.cn/other/slide_10_846_28180.html">¶íÂÞ˹ѧУÍÞÍÞ±ø</a></li> - -<!--<li><a href="http://talk.baby.sina.com.cn/baby/zrjy/" target="_blank" class="linkRed liveNewsLeft">΢·Ã̸£ºÁÖâù̸½ÌÓýÓ¦ºÜ×ÔÈ»</a></li>--> - -<!--<li><a target="_blank" href="http://talk.baby.sina.com.cn/baby/zhzsz/" class="linkRed liveNewsLeft">ÕÅ˼À³Ì¸Ó¤Ó׿ÆѧιÑøÐÂÖ÷ÕÅ</a></li>--> - -<li><a href="http://baby.sina.com.cn/news/2015-06-18/0816/200868915.shtml" target="_blank">Ó¤¶ù³µÇ¿´î·öÌÝ Á½ÃûÓ¤¶ùÏÕÊÜÉË</a></li></ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://baby.sina.com.cn/z/yebd/" target="_blank">‡N°É</a>| <a href="http://baby.sina.com.cn/news/2015-06-17/1205/120568904.shtml" target="_blank">À­ÅóÓѸøÍÞͶƱÄãÍ·ÌÛÂð</a> <a href="http://baby.sina.com.cn/15/1806/2015-06-18/1157/1157298175.shtml" target="_blank">2Ë꺢±»¹·Ò§·ì20Õë</a></li> - -<li><a href="http://baby.sina.com.cn/baobao/" target="_blank">ÑøÓý</a>| <a href="http://baby.sina.com.cn/edu/15/0106/2015-06-18/0818/0925297198.shtml" target="_blank">¸ô±²½ÌÓýÔõô×ö</a> <a href="http://baby.sina.com.cn/edu/15/1206/2015-06-18/0818/1051297898.shtml" target="_blank">Óý¶ùÊ®´óÎóÇø</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/2705/2015-06-18/0818/0730296955.shtml">3ËêºóÐèÌ«Ñô¾µÂð</a></li> - -<li> -<a href="http://blog.baby.sina.com.cn/lm/baby/" target="_blank">²©¿Í</a>| -<a href="http://blog.baby.sina.com.cn/s/blog_3e9837d10102vkts.html " target="_blank">Ó׶ùÔ°ÍÞÒª½á»é</a> <a href="http://blog.baby.sina.com.cn/s/blog_44420d270102vnat.html " target="_blank">º¢×Ó³ÔÀ±ÌõÉíÍö</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_615329790102vo67.html ">ÍÁºÀ¼Ò±£Ä·É¶Ñù</a></li> - -<li><a href="http://baby.sina.com.cn/z/nyszd/" target="_blank">רÀ¸</a>| - <a href="http://baby.sina.com.cn/edu/15/1606/2015-06-16/1156/1156298024.shtml" target="_blank">¹ÃÂè±»µ±ÈË··Ôâ´ò</a> <a target="_blank" href="http://baby.sina.com.cn/z/dyqxmbnyddhz/">è°Ö´÷ÓñÇ¿ÓýÅ®</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_ed2ae0770102vokg.html">±¦¸ÃºÈ¶àÉÙË®</a></li> - -<li><a href="http://baby.sina.com.cn/tv/" target="_blank" class="linkRed">GIF </a>| -<a target="_blank" href="http://slide.baby.sina.com.cn/slide_10_846_27082.html#p=1" suda-uatrack="key=baby_ad&value=baby_adclick">ÓÐÄ̲»³ÔÄã·ÇàÜ</a> <a target="_blank" href="http://slide.baby.sina.com.cn/other/slide_10_846_27325.html#p=1 ">½æÄ©ÁñÁ«ÇåÁ¹ÓÍ</a> <a target="_blank" href="http://slide.baby.sina.com.cn/other/slide_10_846_27695.html#p=1 ">ÂèÂèÍü¼Ç³ÔÒ©ÁË</a></li> - -<li><a href="http://club.baby.sina.com.cn/" class="linkRed03" target="_blank">ÂÛ̳</a>| <a href="http://club.baby.sina.com.cn/thread-7336471-1-1.html " target="_blank">¿ÙÃÅÆÅÆÅÕûÌìÂîÎÒ</a> <a href="http://club.baby.sina.com.cn/thread-7336093-1-1.html " target="_blank">ÓöÒ»¼Ò¼«Æ·Õ¦°ì</a> <a target="_blank" href="http://club.baby.sina.com.cn/thread-7335788-1-1.html ">ºÍÉ©×ÓÇÀÆÅÆÅ</a></li> - -<li><a href="http://baby.sina.com.cn/zt/" target="_blank">רÌâ</a>| <a target="_blank" href="http://baby.sina.com.cn/z/muru/ ">Ö°³¡Âè±³ÄÌÈ«¹¥ÂÔ</a> <a target="_blank" href="http://baby.sina.com.cn/z/quwendazhan/">ÏÄÈÕ·ÀÎþøÕÐ</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1606/2015-06-16/1729/1729298041.shtml">±£½£·æ±¨Ï²µ±°Ö</a></li> - -<li><a href="http://baby.sina.com.cn/news/list.html" target="_blank">Èȵã</a>| <a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/200368914.shtml">9ËêÄÐͯÁ³±äÐÎ </a> <a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/183468910.shtml">½ûÖ¹Ó¤¶ù´©¶ú¶´</a> <a target="_blank" href="http://baby.sina.com.cn/ask/15/1706/2015-06-17/1009/1009298088.shtml">»³ÔиÃÖªµÀµÄÊÂ</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none" data-sudaclick="blk_baby_2" blkclick="auto_nav" blktitle="Ôвú"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÔвúÇø¿é' p_id='30' t_id='112' d_id='2' --> - <div class="uni-blk-bt clearfix"> -<a href="http://slide.baby.sina.com.cn/yjq/slide_10_846_28172.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/home/2015/0618/U11426P30DT20150618083814.jpg" width="105" height="70" /> - - <span>»ô˼ÑàÇ××ÓÕÕ</span> - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://baby.sina.com.cn/health/15/0206/2015-06-18/0815/0924297277.shtml" target="_blank">˭͵×ßÁËÅ®Ã÷ÐǵÄÉúÓýÄÜÁ¦£¿</a></li> - -<li><a href=" http://slide.baby.sina.com.cn/bbshai/slide_10_846_28092.html" target="_blank">¿á˧µÏ°ÝÃÈÍÞ</a> <a target="_blank" href="http://slide.baby.sina.com.cn/other/slide_10_846_28199.html">ÉúÄк¢²»¼ªÀû²¿Âä</a></li> - -<li><a href=" http://slide.baby.sina.com.cn/other/slide_10_846_28208.html" target="_blank">¶À±Û³åÀËÂè²ú×Ó</a> <a href=" http://slide.baby.sina.com.cn/mxx/slide_10_846_28215.html" target="_blank">¿¨´÷ɺΪº¢ÇìÉú</a></li> - -<!--<li><a target="_blank" href="http://talk.baby.sina.com.cn/baby/yyewy/" class="linkRed liveNewsLeft">ÓªÑøר¼Ò̸ӤÓ׶ùιÑøÖ¸µ¼</a></li>--> - -<li><a href="http://baby.sina.com.cn/news/2015-06-12/1203/120368858.shtml" target="_blank">СÂÜÀòËÍÄÌÄ̼Ҽ¸¸öÔºó´ò±äÉí£¡</a></li></ul> - - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://baby.sina.com.cn/health/15/1006/2015-06-18/0841/0807297715.shtml" target="_blank">Öκø¾¿Æ²¡ÔÙ±¸ÔÐ</a> <a href="http://baby.sina.com.cn/health/15/1006/2015-06-18/0841/0910297725.shtml" target="_blank">±¸ÔаְֵıØɱ¼¼</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1006/2015-06-17/0820/0821297717.shtml">¹¬ÍâÔÐÄܲ»ÄÜÔ¤·À</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1606/2015-06-18/0843/1045298017.shtml" target="_blank">Á÷²úºóÒªÁ¢¼´±ÜÔÐ</a> <a href="http://baby.sina.com.cn/health/15/1606/2015-06-18/0843/1424298025.shtml" target="_blank">Æʹ¬²ú²¢·Ç½Ý¾¶</a> <a href="http://baby.sina.com.cn/health/15/1606/2015-06-18/0843/1430298027.shtml" target="_blank">·ÖÃäÇ°Ò׺öÊӵŤ×÷</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1706/2015-06-18/0844/1118298106.shtml" target="_blank">²úºóµÚÒ»²Í³Ôʲô</a> <a href="http://baby.sina.com.cn/health/15/1706/2015-06-18/0844/1119298107.shtml" target="_blank">²úºó×¢ÒâÒâÍ⻳ÔÐ</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1706/2015-06-18/0844/1121298108.shtml">ʲôµ¼Ö²úºóÒÖÓô</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1206/2015-06-18/0845/0742297860.shtml" target="_blank">С¶ùѪÓѲ¡Ôç·¢ÏÖ</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1206/2015-06-18/0845/0745297861.shtml">±¦±¦ÒâÍâÌÌÉËĪ»Å</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1206/2015-06-18/0845/0750297862.shtml">ÈçºÎ»¤Àí¿ÚË®±¦±¦</a></li> - -<li><a href="http://blog.baby.sina.com.cn/s/blog_5cb098ae0102vn08.html " target="_blank">»³ÔÐ4ÔÂÐÄÇéµøå´</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_7285b5180102vnnb.html ">¶à´ÎÌ¥¼à²âÊÔÏÅ»µÎÒ</a> <a target="_blank" href="http://blog.baby.sina.com.cn/s/blog_768113ef0102voxf.html ">ĸÈéιÑøÓÐÈý¼É</a></li> - -<li><a href="http://baby.sina.com.cn/health/15/1206/2015-06-12/1153/1153297908.shtml" target="_blank">Å®ÓѱÆ×ÅÔìÈËÔõ°ì</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1606/2015-06-16/1729/1729298041.shtml">±£½£·æ±¨Ï²µ±°Ö°Ö</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_82b859870102wcmm.html?tj=1">±»±Æ³öÀ´µÄ»¢Âè</a></li> - -<li><a target="_blank" class="videoNewsLeft" href="http://video.baby.sina.com.cn/p/baby/v/2015-06-18/001365026543.html">B³¬¼ì²éÓ°ÏìÌ¥¶ù½¡¿µ?</a> <a target="_blank" href="http://video.baby.sina.com.cn/p/baby/v/2015-06-18/001365026545.html">º¢×Ó·¢ÉÕÄܾ­³£Ê¹ÓÃÍ·æßÂð</a></li> - -<li><a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/195468913.shtml">·¶Ò¯»ØÓ¦¾ÈÄÐͯ·ç²¨</a> <a target="_blank" href="http://baby.sina.com.cn/news/2015-06-18/0816/193968912.shtml">ÀîСÅôÀíÐÔ½Ì×Ó</a> <a target="_blank" href="http://baby.sina.com.cn/health/15/1506/2015-06-15/1352/1352297970.shtml">´óS²úºóÔõÊÝÉí</a></li> - - </ul> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod45 --> - </div> - </div> - <!-- part-o end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-p begin --> - <div class="part-p"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 2ÂÖ²¥Í¨À¸05¹ã¸æ begin --> -<div id="ad_46022" class="mb25"><ins class="sinaads" data-ad-pdps="PDPS000000056034"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 2ÂÖ²¥Í¨À¸05¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- part-p end --> - <!-- part-q begin --> - - <div class="part-q clearfix"> - <div class="part-q-l"> - <!-- mod46 --> - <div class="mod-02"> - <div class="tit02"><h3><a target="_blank" href="http://fashion.sina.com.cn/">ʱÉÐÈȵã</a></h3></div> - <div style="height:8px;" class="blank-cont"></div> - <div class="mod22-cont clearfix" data-sudaclick="blk_fashion_ssrd" blkclick="auto_nav" blktitle="ʱÉÐÈȵã"> -<!-- publish_helper name='ʱÉÐÈȵã' p_id='30' t_id='110' d_id='6' --> -<div class="xb-mod22-cont-pa"><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60851.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U5790P30DT20150618102211.jpg" width="220px" height="160px" /><span>ÉÏ°ëÄê×îÇ¿¼¡ÈâÄÐÐǽÖÅÄ</span></a></div><div style="height:5px" class="blank-d"></div><ul class="list-b list-c" style="padding-bottom:7px;"> - -<li><a target="_blank" href="http://fashion.sina.com.cn/s/in/2015-06-18/0733/doc-ifxczqap4215744.shtml">¼¯Æë10¸öÆ·ÅÆ ¿ÉÔÚÃ×À¼ÄÐ×°ÖÜÕÙ»½ÏÊÈâ</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/b/mk/2015-06-17/0649/doc-ifxczqar0953508.shtml">ÁøÑÒÆØËØÑÕ£¿ ÈÃÖ±ÄÐÉϵ±Â̲è×±³¤ÕâÑù</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/d/ft/2015-06-18/0734/doc-ifxczqan1552426.shtml">¸úùùһÆðÒ²OK ÅÖÃÃÈüÁÕÄȾ¹ÊÝ»ØÀ´ÁË</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/l/ts/2015-06-18/0756/doc-ifxczyze9588267.shtml">Éà¼âÉϵÄÓÕ»ó</a> <a target="_blank" href="http://fashion.sina.com.cn/l/ts/2015-06-18/0757/doc-ifxczqap4209837.shtml">ÆßÖÖÄã²»ÖªµÀµÄºÃ³ÔÌðÆ·</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/w/ho/2015-06-18/0753/doc-ifxczqap4211261.shtml">³ö·¢£¡2016Ê®´óÀËÂþÃÛÔÂÊ¥µØÅ̵ã</a></li></ul> - </div> - </div> - <!-- mod46 --> - </div> - <div class="part-q-m"> - <!-- mod47 --> - <div class="uni-blk" id="SI_Order_S" tab-type="tab-wrap" struc="1-4"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://fashion.sina.com.cn/" target="_blank">ʱÉÐ</a></span> - <span tab-type="tab-nav"><a href="http://fashion.sina.com.cn/photo/" target="_blank">ÊÓ¾õ</a></span> - - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_fashion_1" blkclick="auto_nav" blktitle="ʱÉÐ"> -<!-- publish_helper name='ÉÐÆ·Çø¿é' p_id='30' t_id='113' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://fashion.sina.com.cn/" target="_blank" class="uni-blk-pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U8586P30DT20150618101815.jpg" width="105" height="70" /> - - <span>±´°ÖСÆßÓа®Ë²¼ä</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://fashion.sina.com.cn/" target="_blank" class="linkRed01">̺ÐÇÍËÏ Áõ¼ÎÁáºÍÅ®ÍõÈ¥¿´ÂíÁË</a></li> - -<li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>|<a target="_blank" href="http://fashion.sina.com.cn/2015-06-18/0727/doc-ifxczqap4213453.shtml" class="linkRed01">¾Ý˵µÁĹ±Ê¼ÇºÃ¿´µÄÖ»ÓÐÑÕ</a></li> - -<li><a href="http://fashion.sina.com.cn/style/" target="_blank">ʱÉÐ</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60856.html" class="linkRed01">³ôÁ³Íõ×ÓСÇÇÖÎÏÓÆú±íÇé°ü</a></li> - -<li><a href="http://fashion.sina.com.cn/try/" target="_blank">ÊÔÓÃ</a>|<a target="_blank" href="http://fashion.sina.com.cn/try/product/1053" class="linkRed01">Òü¶÷»Ý×ŷÀ³ÑÅ»¤·¢Ì××°</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://fashion.sina.com.cn/style/" target="_blank" class="linkRed01">ʱװ</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60860.html#p=1" class="linkRed01">17ËêÏÊÈâ¿´Ðã</a> - -<a target="_blank" href="http://fashion.sina.com.cn/s/ce/2015-06-18/0740/doc-ifxczyze9671552.shtml" class="linkRed01">ÌÆæÌ´óÅÆÏÞÁ¿°ü</a> <a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60819.html#p=1" target="_blank" class="linkRed01">Å£×пã¸ã¶¨¿Ë³Äá</a></li> - -<li><a href="http://fashion.sina.com.cn/beauty/" target="_blank" class="linkRed01">ÃÀÈÝ</a>|<a target="_blank" href="http://fashion.sina.com.cn/b/mk/2015-06-18/0734/doc-icrvvqrf4562993.shtml" class="linkRed01">ÕâЩŮÉñ¾ÓÈ»ÊÇͬ°àͬѧ</a> <a target="_blank" href="http://fashion.sina.com.cn/b/ha/2015-06-18/0737/doc-ifxczqar0989595.shtml" class="linkRed01">¿ÕÆøÁõº£outÐÄÐÎÁõº£ÉÏ</a></li> - -<li><a href="http://fashion.sina.com.cn/body/" target="_blank">ÃÀÌå</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/d/slide_24_66332_60858.html#p=1" class="linkRed01">³£±»Îó½âµÄ7ÖÖ½¡¿µÊ³Æ·</a> -<a target="_blank" href="http://fashion.sina.com.cn/d/he/2015-06-18/0751/doc-ifxczyze9671160.shtml" class="linkRed01">6ÖÖʳÎï°ïÄã˦µô±ãÃØ</a></li> - -<li><a href="http://fashion.sina.com.cn/luxury/" target="_blank">ÉÐÆ·</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60818.html#p=1" class="linkRed01">¸¸Ç×½ÚΪ°Ö°Ö×öµÀϾƲË</a> -<a target="_blank" href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60830.html" class="linkRed01">ÒÉËÆÄ̲èÃÃÃúÀÕ¬Æعâ</a></li> - -<li><a href="http://fashion.sina.com.cn/wedding/" target="_blank">»é¼Þ</a>|<a target="_blank" href="http://slide.fashion.sina.com.cn/w/slide_24_66152_60841.html#p=1" class="linkRed01">Èðµä»ÊÊÒ»éÀñÉϵľøÃÀÀñ·þ</a> -<a href="http://slide.fashion.sina.com.cn/w/slide_24_66152_60743.html#p=1" target="_blank" class="linkRed01">É¢·¢×ÅÅ®ÈËÏãµÄ»éÉ´</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/column/">רÀ¸</a>|<a href="http://fashion.sina.com.cn/zl/fashion/2015-06-17/14103784.shtml" target="_blank" class="linkRed01">20¸öÇÏÃÅÈÃÄãʱÉиüʱÉÐ</a> -<a href="http://fashion.sina.com.cn/zl/beauty/2015-06-17/15053787.shtml" target="_blank" class="linkRed01">¿´±´É©½ÖÅÄѧְ³¡·¢ÐÍ</a></li> - -<li><a target="_blank" href="http://fashion.sina.com.cn/photo/">ͼ¿â</a>|<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60787.html#p=1" target="_blank" class="linkRed01">Ö£ÖݻƽðÄÚÒÂÄÚ¿ãÐã</a> -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60783.html#p=1" target="_blank" class="linkRed01">Âê¸êÂޱȾüÂ̱³´øÈÈ¿ã</a></li> - </ul> - </div> - - <div tab-type="tab-cont" style="display:none;" data-sudaclick="blk_fashion_2" blkclick="auto_nav" blktitle="ÊÓ¾õ"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='ÊÓ¾õÇø¿é' p_id='30' t_id='110' d_id='5' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60752.html" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0616/U5790P30DT20150616093757.jpg" width="105" height="70" /> - - <span>·ÆÀûÆÕÍõ×Ó½á»éÕÕ</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| <a href="http://slide.fashion.sina.com.cn/slide_24_60018_60755.html" target="_blank" class="linkRed01">·¶ÎÄ·¼Êܳè16ÄêÉÙÅ®ÐÄδ±ä</a></li> - - <li><a href="http://eladies.sina.com.cn/news/" target="_blank">»¨±ß</a>| <a href="http://eladies.sina.com.cn/news/star/2015-05-15/0758/doc-iawzuney5569497.shtml" target="_blank">СSɹ×ÔÅÄÒÉÏÖ¡°Ñ¹Á¦Íº¡±</a></li> - - <li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| <a href="http://slide.fashion.sina.com.cn/slide_24_60018_60754.html" target="_blank" class="linkRed01">±±¾©¸ßУģÌرÈÆ´ÐÔ¸ÐÓ¾×°</a></li> - <li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>| <a href="http://fashion.sina.com.cn/beauty/" target="_blank" class="linkRed01">ÕÔÀöÓ±±äÐÂÒ»´úÄÐÉñÊÕ¸î»ú</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60750.html" target="_blank" class="linkRed01">ÍþÁ®¹þÀï½á°é´òÂíÇò</a> -<a href="http://slide.fashion.sina.com.cn/slide_24_60018_60753.html" target="_blank" class="linkRed01">´óѧÉúº£±ßÅÄÉã¸öÐÔ±ÏÒµÕÕ</a></li><li><a href="http://fashion.sina.com.cn/photo/" target="_blank">ͼ¿â</a>| - - <a target="_blank" href="http://slide.fashion.sina.com.cn/slide_24_60018_60751.html" class="linkRed01">ÃÀÖÞ±­ÔÙÏÖÈéÉñ</a> <a target="_blank" href="http://slide.fashion.sina.com.cn/slide_24_60018_60749.html" class="linkRed01">±ÈÀûʱʾÍþÕß¡°ÌÉʬ¡±½ÖÍ·</a></li><li><a href="http://fashion.sina.com.cn/style/" target="_blank">ʱÉÐ</a>| -<a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60851.html#p=1" target="_blank" class="linkRed01">ÉÏ°ëÄê×îÇ¿¼¡ÈâÄÐÐǽÖÅÄ</a> -<a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60827.html#p=1" target="_blank" class="linkRed01">¾®±¦Í·´÷ÍÞÍÞñÂôÃÈ</a></li><li><a href="http://fashion.sina.com.cn/beauty/" target="_blank">ÃÀÈÝ</a>| -<a href="http://fashion.sina.com.cn/b/mk/2015-06-17/1501/doc-ifxczqap4209704.shtml" target="_blank" class="linkRed01">·¨¹úÅ®È˵ÄÓÅÑÅÃؼ®</a> -<a href="http://fashion.sina.com.cn/b/ha/2015-06-17/0703/doc-ifxczqar0757654.shtml" target="_blank" class="linkRed01">GAGA½ã¸ßÄÜÐü¸¡±èÁÁÁË</a></li><li><a href="http://fashion.sina.com.cn/body/" target="_blank">ÃÀÌå</a>| - <a href="http://fashion.sina.com.cn/d/ta/2015-06-18/0737/doc-ifxczqap4209515.shtml" target="_blank" class="linkRed01">Ï붴ó°×ÍÈ£ºÏ¥¸Ç¹»°×Âð</a> - <a href="http://fashion.sina.com.cn/d/he/2015-06-18/0752/doc-ifxczqap3911284.shtml" target="_blank" class="linkRed01">´©Ì«¶ÌСÐÄÁ½ÖÖ²¡</a></li><li><a href="http://fashion.sina.com.cn/luxury/" target="_blank">ÉÐÆ·</a>| -<a href="http://fashion.sina.com.cn/l/ds/2015-06-18/0758/doc-ifxczqan1557752.shtml" target="_blank" class="linkRed013">ÉñÃØŲÍþ ²»Ö»¼«¹â</a> -<a href="http://fashion.sina.com.cn/wedding/" target="_blank">»é¼Þ|</a> -<a href="http://slide.fashion.sina.com.cn/w/slide_24_66152_60149.html#p=1" target="_blank" class="linkRed01">˽È˶©ÖÆÄãµÄ»éÀñ</a></li><li><a target="_blank" href="http://fashion.sina.com.cn/zl/">רÀ¸</a>| -<a target="_blank" href="http://fashion.sina.com.cn/zl/fashion/blog/2015-06-12/15263753/1188369822/46d5159e0102vqni.shtml" class="linkRed01">´òÔ취ʽ·çÇéµÄʱÉÐÒªËØ</a> - -<a target="_blank" href="http://fashion.sina.com.cn/zl/style/2015-06-15/14403761.shtml" class="linkRed01">²ÌÀ½:¶ËÎç³ÔʲôôÕ×ÓºÃ</a></li> - </ul> - </textarea> - </div> - -<!--whs--> - - </div> - </div> - </div> - <!-- mod47 --> - </div> - <div class="part-q-r"> - <!-- mod48 --> - <div class="uni-blk" id="SI_Order_T" tab-type="tab-wrap" struc="1-4"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://travel.sina.com.cn/" target="_blank">ÂÃÓÎ</a></span> - <span tab-type="tab-nav"><a href="http://photo.weibo.com/welcome/hot?from=sina" target="_blank">Ïà²á</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_travel_1" blkclick="auto_nav" blktitle="ÂÃÓÎ"> -<!-- publish_helper name='ÂÃÓÎÇø¿é' p_id='30' t_id='116' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://weibo.com/p/1001603854451369721970" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/home/2015/0618/U10184P30DT20150618100710.jpg" width="105" height="70" /> - - <span>Îâ¸ç¿ß Õæ°®ÓÀºã</span> - </a><ul class="uni-blk-list01 list-a"><li><a target="_blank" href="http://weibo.com/p/1001603853199063809686">×îÃÀº£±õͽ²½µÀ ÓÌÈçÌìÌÃÖÐÂþ²½</a></li> - -<li><a href="http://weibo.com/p/1001603853939245237145" target="_blank">ËÕ¸ñÀ¼µÄÀä¿áÏɾ³ ±¥ÀÀ¾«»ªËùÔÚ</a></li> - -<li><a href="http://weibo.com/p/1001603854028139289130" target="_blank">´øן¢×ÓÂÃÐÐ ³¤³ÇÉϵıðÑùͯÄê</a></li> - -<li><a href="http://travel.sina.com.cn/china/2015-06-10/1703308514.shtml" target="_blank">¿áÊîÏ®À´ ÔÚ¸£ÖÝÍæË®µÄNÖÖ×ËÊÆ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://travel.sina.com.cn/lvyou/">¹úÄÚ|</a> <a target="_blank" href="http://travel.sina.com.cn/china/2015-05-22/1510307277.shtml">ʯ÷Íå·Ç³ÏÎðÈŵÄÃÀ¾°</a> <a target="_blank" href="http://travel.sina.com.cn/china/2015-06-02/1205307997.shtml">Õâ¸ö¸¸Ç×½Ú°Ö°ÖÈ¥ÄĶù</a></li><li><a target="_blank" href="http://travel.sina.com.cn/lvyou/">³ö¾³|</a> <a target="_blank" href="http://weibo.com/p/1001603853969347754469">°Â¿ËÀ¼ºÚɳ̲¡°Ìì¿ÕÖ®¾µ</a> <a href="http://weibo.com/p/1001603853762841175626 " target="_blank">ÈÕ±¾Á­²Ö÷Óê¼¾ÉÍ»¨</a></li><li><a target="_blank" href="http://data.travel.sina.com.cn/quanbu-remen/">¿ìѶ|</a> <a target="_blank" href="http://travel.sina.com.cn/world/2015-06-17/1650308995.shtml ">ÊîÆÚÐÞѧÓÎÉýÎÂ</a> <a target="_blank" href="http://travel.sina.com.cn/world/2015-06-17/1652308996.shtml ">Ç©Ö¤ÀûºÃÊîÆÚ³ö¾³ÓÎÔ¤¶©»ð±¬</a></li> -<li><a target="_blank" href="http://vi.travel.sina.com.cn/">ÀÖÏí|</a> <a target="_blank" href="http://slide.travel.sina.com.cn/slide_68_57328_26874.html">Å·ÖÞ&quot;¾ÅÕ¯¹µ&quot;</a> <a target="_blank" href="http://slide.travel.sina.com.cn/slide_68_57328_26829.html">¿¦À­¾þ²ÝÔ­</a> <a target="_blank" href="http://slide.travel.sina.com.cn/slide_68_57328_26535.html">åüÃÄÑÌÓêÑ°½­ÄÏ</a></li><li><a target="_blank" href="http://blog.sina.com.cn/lm/travel/">ÓμÇ|</a> <a href="http://blog.sina.com.cn/s/blog_6960d5f00102w3qs.html?tj=1" target="_blank">ϤÄáºì·ãÁÖ</a> <a href="http://blog.sina.com.cn/s/blog_7533c52c0102vxs2.html?tj=1" target="_blank">×íÃÀÎ÷ɳȺµº</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_7170ab0e0102vpe6.html?tj=1">ÐÁÌØÀ­Í¯»°Ãξ³</a></li><li><a target="_blank" href="http://weibo.com/tourer">»°Ìâ|</a> <a href="http://weibo.com/p/100808a09c808bb9b07843dbc9cab00a1991b7" target="_blank">#±ÏÒµÒ»Æð×ß#</a> <a target="_blank" href="http://weibo.com/p/10080861d7f53499e7dbe8c2422506dbceaa2c">#ÎÒÃÇ°®ÂÃÐÐ# </a> <a href="http://weibo.com/p/1008081598a5d7a224485db4e04b77899db798?k=%E5%86%8D%E4%B8%8D%E7%8E%A9%E5%B0%B1%E8%80%81%E4%BA%86&from=501&_from_=huati_topic" target="_blank">#ÔÙ²»Íæ¾ÍÀÏÁË#</a></li><li><a target="_blank" href="http://travel.sina.com.cn/">ÕÐļ|</a> <a href="http://weibo.com/1502844527/BAsrla37a?type=comment#_rnd1419168392865" target="_blank">Ãû²©ÁìÖ÷ËÙËÙ±¨Ãû</a> <a target="_blank" href="http://travel.sina.com.cn/z/dayulieren/">ÎÒÒªµ±ÁÔÈË</a> <a target="_blank" href="http://travel.weibo.com/">Íæ±éÌ©¹ú³ÔסÐÐ</a></li> - </ul> - </div> - <div tab-type="tab-cont" style="display:none;" data-sudaclick="blk_photo_1" blkclick="auto_nav" blktitle="Ïà²á"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='Ïà²áÇø¿é' p_id='30' t_id='115' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://photo.weibo.com/welcome/hot?from=sina" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0402/U8580P30DT20150402153323.png" width="105" height="70" /> - - <span>΢ЦÊÇÇ×ÇеÄÓïÑÔ</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://weibo.com/p/1038030002_874?from=sina&x=10" target="_blank">ÎÒΪÊÓƵ¿ñ ·Ö·ÖÖÓÈÃÄãàË·­Ìì</a></li> - -<li><a href="http://photo.weibo.com/events/pictag?from=sina&x=1" target="_blank">΢²©ÏÖÔÚ¿ÉÒÔ¸øÕÕƬÉÏ´ò±êÇ©à¶</a></li> - -<li><a href="http://weibo.com/p/1008083fd4566a4b5554651ac1b1156ac4e7d7?from=sina&x=2" target="_blank" class="linkRed">ÅÄÉí±ß#´ºÉ«# Õùµ±È«ÃñÉãӰʦ</a></li> - -<li><a href="http://weibo.com/1962310741/C9t5n5SjZ?from=sina&x=2" target="_blank">ÐÒ¸£²»ÊÇŬÁ¦È¥°® ¶øÊÇ°²ÐÄÉú»î</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://weibo.com/1962310741/CbjyxomhR?from=sina&x=3" target="_blank">¹ý×Ô¼ºµÄÈËÉú ÐÄÀï×°ÂúÁË°®</a> <a href="http://weibo.com/1962310741/Cbi1a0hV0?from=sina&x=3" target="_blank">Ëæ×Å·ç×ÔÓÉÔÚ·çÖпñÎè</a></li> - -<li><a href="http://weibo.com/1962310741/Cb4Sr6ZGT?from=sina&x=4" target="_blank">Ã÷ÐÇÑÛÖеĴºÉ«ÊÇÔõÑùµÄ</a> <a href="http://weibo.com/1962310741/Cb0HyiroA?from=sina&x=4" target="_blank">¶ùʱµÄ»¶ÀÖÊÇ×îµ¥´¿ÐÒ¸£</a></li> - -<li><a href="http://weibo.com/1962310741/CaZaajHiL?from=sina&x=5" target="_blank">̧ÆðÍ·ÑöÍûÀ¶ÌìÉîºôÎü</a> <a href="http://weibo.com/1962310741/CaXv6z3fU?from=sina&x=5" target="_blank">´ºÌìÎÒÁ÷À˹ýµÄµØ·½ËêÔ¼«ÃÀ</a></li> - -<li><a target="_blank" href="http://weibo.com/1962310741/CbpgGwBmo?from=sina&x=6">´ò¿ªÐÄÃÅ¿´¼ûÕû¸öÊÀ½ç</a> <a target="_blank" href="http://weibo.com/1962310741/CaQQ68oa3?from=sina&x=6">²»Öª²»¾õÂúÔ°´ºÉ«ÕÀ·ÅÃÀÈç»­</a></li> - -<li><a href="http://weibo.com/1962310741/CaBN61tls?from=sina&x=7" target="_blank">Ö»Ïë½øÐÐÒ»³¡ÂþÎÞÄ¿µÄµÄÂÃÐÐ</a> <a href="http://weibo.com/1962310741/Ca056BkYk?from=sina&x=7" target="_blank">ÏëÄîÄÏ·½µÄ´ºÉ«»¨º£</a></li> - -<li><a href="http://weibo.com/1962310741/CaclibPqq?from=sina&x=8" target="_blank">ÄÇÀﶼÊÇÎÒ¸ÃÈ¥µÄµØ·½</a> <a href="http://weibo.com/1962310741/Ca2Oqh3zQ?from=sina&x=8" target="_blank">Óε´ÊÀ½ç¸÷µØÊÕ¼¯ÆßÉ«º£Ì²</a></li> - -<li><a href="http://weibo.com/1962310741/CasmBrThq?from=sina&x=9" target="_blank">Ò»±­Çå²èÁ½ÏàÍû Çã³ÇÑÕ Ò÷ÝóÝç</a> <a href="http://weibo.com/1962310741/C9LWmtzng?from=sina&x=9" target="_blank">ϦÑôÓà»ÔϵÄËÕ×È´ï¶û</a></li> - </ul> - </textarea> - </div> - </div> - </div> - </div> - <!-- mod48 --> - </div> - </div> - <!-- part-q end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-r begin --> - - <div class="part-r clearfix"> - <div class="part-r-l"> -<!--_SINA_ADS_BEGIN_--> -<!-- 240x330 1ÂÖ²¥°´Å¥09¹ã¸æ begin --> -<div id="ad_46023" style="width:240px;"><ins class="sinaads" data-ad-pdps="PDPS000000046023"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 240x330 1ÂÖ²¥°´Å¥09¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <div class="part-r-m"> - <!-- mod49 --> - <div class="uni-blk" id="SI_Order_U" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://collection.sina.com.cn/" target="_blank">ÊÕ²Ø</a></span> - <span tab-type="tab-nav"><a href="http://golf.sina.com.cn/" target="_blank">¸ß¶û·ò</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_collection_1" blkclick="auto_nav" blktitle="ÊÕ²Ø"> -<!-- publish_helper name='ÊÕ²ØÇø¿é' p_id='30' t_id='117' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://collection.sina.com.cn/" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U5083P30DT20150618091151.jpg" width="105" height="70" /> - - <span>èó¸ßÓÍ»­Êä¸øʱ¼ä</span> - - </a><ul class="uni-blk-list01 list-a"> - -<li><a href="http://collection.sina.com.cn/yshq/20150618/0812189291.shtml" target="_blank" class="linkRed">×ÏÉ°ºøµÚÒ»¹ÉÁ¬ÐøÕÇÍ£ÈÇÕùÒé</a></li> - -<li><a href="http://collection.sina.com.cn/cjrw/20150618/0731189282.shtml" target="_blank">Áξ²ÎÄ£ºÒ»ÉúÊغòÐ챯ºè</a></li> - -<li><a href="http://collection.sina.com.cn/yjjj/20150618/0818189293.shtml" target="_blank">¹Ê¹¬¿ÍÁ÷¶¯Ì¬Ô¤¾¯2016ÄêÆôÓÃ</a></li> - -<li><a href="http://collection.sina.com.cn/cqty/20150618/0725189281.shtml" target="_blank">õ·Áê´É¼Û¸ñÉÏÕÇ ÒÕÊõ´ÉÓпռä</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/cqyw/index.shtml">¾Û½¹|</a> <a target="_blank" href="http://collection.sina.com.cn/yjjj/20150618/0705189277.shtml" class="linkRed">̨±±¹Ê¹¬ÄÏÔº½«¿ª¹ÝÊÔÓªÔË ºÄ×ʽü80ÒÚÐĄ̂±Ò</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/plfx/index.shtml">ÆÀÂÛ|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0741189284.shtml">Ǯѡ¼û¹ý¡¶Ïª°¶Í¼¡·Âð</a> <a target="_blank" href="http://collection.sina.com.cn/jczs/20150617/1641189267.shtml">°×½¶ÍíÄêÊé·¨ÊÖ¸åÓиÐ</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/jczs2/index.shtml">¼ø²Ø|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0746189286.shtml">ÄÏä±Ò»ÃÅÈý´úËÄ²Ø¼Ò </a> <a target="_blank" href="http://collection.sina.com.cn/cjrw/20150618/0736189283.shtml">Ê黭ֵǮÁËÎÒÈ´¸ü¹Â¶À</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/jczs2/index.shtml">Òµ½ç|</a> <a target="_blank" href="http://collection.sina.com.cn/zgsh/20150618/0815189292.shtml">Êé·¨¾¿¾¹ÊôÒÕ»¹ÊÇÊôѧ</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150617/1649189268.shtml">µ±ÒÕÊõ´´×÷±ä³ÉÒÕÊõÉú²ú</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/yjjj/index.shtml">Òµ½ç|</a> <a target="_blank" href="http://collection.sina.com.cn/zgsh/20150618/0708189278.shtml">Åþ¬Ë±ڻ­±£»¤¿Ì²»ÈÝ»º</a> <a target="_blank" href="http://collection.sina.com.cn/cqyw/20150618/0823189294.shtml">ÁÖ»ÕÒòÓë¾°Ì©À¶µÄÇéÔµ</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/cqyw/index.shtml">¹Ø×¢|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0754189288.shtml">°üºÀ˹²ØÆ·½»Ò×ʼĩ </a> <a target="_blank" href="http://collection.sina.com.cn/auction/pcdt/20150618/0702189276.shtml">³ÂÄËǬ´æÁôÐÅÔýÁÁÏàÅij¡</a></li> - -<li><a target="_blank" href="http://roll.collection.sina.com.cn/collection/hwdt/index.shtml">Õ¹ÀÀ|</a> <a target="_blank" href="http://collection.sina.com.cn/plfx/20150618/0745189285.shtml">²ßÕ¹È˳ÂÂÄÉú£ºÇ¶ÈëʽչÀÀ·½Ê½ÊÇÀϲ©Îï¹ÝÉú»ú</a></li> - - </ul> - </div> - - <div tab-type="tab-cont" style="display:none;" data-sudaclick="blk_golf_1" blkclick="auto_nav" blktitle="¸ß¶û·ò"> - <textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<!-- publish_helper name='¸ß¶û·òÇø¿é' p_id='30' t_id='101' d_id='11' --> - - <div class="uni-blk-bt clearfix"> -<a href="http://slide.sports.sina.com.cn/golf/slide_2_754_82711.html/d/8#p=1" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0602/U12660P30DT20150602125929.jpg" height="70" width="105" /> - - <span>СÂóÓëÐÂÅ®ÓÑÐã¶÷°®</span> - - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://sports.sina.com.cn/golf/2015usopengolf/" target="_blank">ÃÀ¹ú¸ß¶û·ò¹«¿ªÈü22ʱ¿ª´ò</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/02077636924.shtml" target="_blank">ÃÀÁª£ºÇ°ÇòÍõÎé×È´¿Êô×ÔÆÛÆÛÈË</a></li> - -<li><a href="http://sports.sina.com.cn/golf/pgatour/2015-06-18/doc-ifxehfqi8029184.shtml" target="_blank">Îé×ȱ»ÆØÓûÓëÇ°ÆÞÖØÐ޾ɺÃ</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/09307637052.shtml" target="_blank">ÃÀ¹ú¹«¿ªÈü½±½ðÉýÖÁǧÍòÃÀÔª</a></li> - -</ul> - </div> - <div class="blk-line" style=""></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/08557637009.shtml" target="_blank" >ËûÊÇÃÀ¹ú¹«¿ªÈüÖ÷Ô× Ë­ÄÜÌÓÍÑ£¿</a> <a href="http://sports.sina.com.cn/golf/2015-06-18/09207637036.shtml" taret="_blank">¼ÓÄôóÇòÔ±ÌôÐÆ´÷ά˹</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/10317637143.shtml" target="_blank">ÃÀ¹ú¹«¿ªÈüµ½Î÷ÑÅͼ¶à»ð£¿</a> <a href="http://sports.sina.com.cn/golf/2015-06-18/10237637114.shtml" target="_blank" >Ç®²®Ë¹Íå´òÇòʱ¼ä»ò´ï6Сʱ</a></li> - -<li><a href="http://slide.sports.sina.com.cn/golf/slide_2_754_83548.html?img=1526208#p=3" target="_blank" class="ideoNewsLeft linkRed01">¸ßÇå-Îé×ÈÃæ¶ÔС°×Çò¶àÑù±íÇé</a> <a href="http://sports.sina.com.cn/golf/2015-06-18/10287637122.shtml" target="_blank">ÅÁ¶ûĬ£ºËûÓÐÄÜÁ¦ÔÙ»ØÀ´</a></li> - -<li><a href="http://sports.sina.com.cn/golf/2015-06-18/03487636934.shtml" target="_blank">ÃÀ¹ú¹«¿ªÈüÓн±¾º²Â</a> <a href="http://slide.sports.sina.com.cn/golf/slide_2_754_83388.html" target="_blank" >18¶´ÇòµÀͼ</a> <a href="http://sports.sina.com.cn/golf/2015-06-16/doc-ifxczqar0962995.shtml" target="_blank" class="ideoNewsLeft linkRed01">¶á¹ÚÅâÂÊ</a> <a href="http://sports.sina.com.cn/golf/2015-06-14/21087634516.shtml" target="_blank">19µÀ¿¼Ìâ</a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/golf/2015-06-17/14437636684.shtml">Óà¸Ö£ºÃÀ¹ú¹«¿ªÈüÒòºÎΪǮ²®Ë¹Íå¡°»µ¡±¹æ¾Ø </a></li> - -<li><a target="_blank" href="http://sports.sina.com.cn/golf/2015-06-18/07587636971.shtml">ÃÀ¹ú¹«¿ªÈüµÄÁ½ÕÅ»ªÈËÃæ¿×£ºÁºÎijåÓëÅËÕþçý¼ûÃæ</a></li> - -<li><a href="http://sports.sina.com.cn/golf/blog/" target="_blank">²©¿Í</a>-<a href="http://blog.sina.com.cn/s/blog_4bcff9240102vqtp.html?tj=1" target="_blank">ÔÙ»áÁË Ê®ÈýÁêÇò³¡</a> <a href="http://blog.sina.com.cn/s/blog_66f24f360102vpbe.html?tj=tiyu" target="_blank">±£Àû36¶´£¬À϶ÎÅã´ò¡£</a></li> - - </ul> - </textarea> - </div> - - </div> - </div> - </div> - <!-- mod49 --> - </div> - <div class="part-r-r"> - <!-- mod50 --> - <div class="uni-blk" id="SI_Order_V" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://health.sina.com.cn/" target="_blank">½¡¿µ</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_health_1" blkclick="auto_nav" blktitle="½¡¿µ"> -<!-- publish_helper name='½¡¿µÇø¿é' p_id='30' t_id='118' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/s/blog_b8b22a140102w1ag.html?tj=1" target="_blank" class="uni-blk-pic"> -<img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0618/U5307P30DT20150618113217.bmp" width="105" height="70" /> - -<span>È«Çò×ÃÀÉí²Ä</span> - - </a><ul class="uni-blk-list01 list-a"><li><a href="http://health.sina.com.cn/" target="_blank" class="linkRed">3ÏîÖ¸±ê²âÊÙÃü</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_a554c60c0102vl28.html?tj=1">»ëÉíÊÇÒ©µÄ´óÖÚ²Ë</a></li> - -<li><a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173024.shtml">ÄÐÈ˱ر¸3ÖÖ»¤¸Î²è</a> <a target="_blank" href="http://health.sina.com.cn/hc/m/2015-06-18/0734173025.shtml">ºÃÉ«Å®ÈËÌØÕ÷</a></li> - -<li><a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173021.shtml">ÓÐÕâÖÖðëÊǸβ¡</a> <a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173017.shtml">ºÈ¶àÉپƻáÖ°©</a></li> - -<li><a href="http://blog.sina.com.cn/lm/health/" target="_blank">ÁùÖÖÅ®ÈËÒ׳ö¹ì</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_13c4a419c0102vtpw.html?tj=1">˯ǰ×öɶ»á¶ÌÃü</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><span style="color: #0c0000;"><a href="http://health.sina.com.cn/tiaoshi/" target="_blank">Ìôʳ</a></span>|<a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173029.shtml">3Öֲ˷À°©ÆæºÃ</a> <a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173027.shtml">ɽҩÊÇ×îºÃµÄ²¹Æ·</a> <a target="_blank" href="http://health.sina.com.cn/hc/ys/2015-06-18/0734173030.shtml">ºìÔæ×îÑø¸Î³Ô·¨</a></li> - -<li><span style="color:#0c0000;"><a href="http://health.sina.com.cn/hc/sh/" target="_blank">Éú»î</a>|<a target="_blank" href="http://health.sina.com.cn/hc/ct/2015-06-18/0734173014.shtml">40ËêÊǽ¡¿µ·ÖË®Áë</a> <a target="_blank" href="http://health.sina.com.cn/hc/ct/2015-06-18/0734173022.shtml">ס¼¸Â¥ÊÙÃü³¤</a> <a target="_blank" href="http://health.sina.com.cn/hc/mr/2015-06-18/0735173013.shtml">Å®ÈËÀϲ»ÀÏ¿´Õâ</a></span></li> - -<li><span style="color:#c00;"><a href="http://health.sina.com.cn/rdxw/" target="_blank">»î¶¯</a></span>|<a target="_blank" href="http://health.sina.com.cn/tiaoshi/">Ìôʳ£ºÔõô³ÔèÛè½ÄÜÖΰ׷¢</a> <a target="_blank" href="http://health.sina.com.cn/z/zhaojiling/">ר¼ÒÆÀ²âÍÅÑûÄã¼ÓÈë</a></li> - -<li><span style="color: #0c0000;"><a href="http://health.sina.com.cn/disease/" target="_blank">¼²²¡</a></span>|<a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173020.shtml">ÉíÌåȱɶ³¤°×·¢</a> <a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173012.shtml">ÕâÖÖÄÐÈË×ÊÙ</a> <a target="_blank" href="http://health.sina.com.cn/d/2015-06-18/0736173016.shtml">ÕâÖÖ°×·¢ÄܱäºÚ</a></li> - -<li><span style="color:#0c0000;"><a href="http://health.sina.com.cn/" target="_blank">Èȵã</a>|<a target="_blank" href="http://slide.health.sina.com.cn/hc/slide_31_28380_85477.html#p=1">ÃÀÅ®´©¶Ç¶µ³«Òé½â·ÅÈé·¿</a> <a target="_blank" href="http://slide.health.sina.com.cn/d/slide_31_28379_85559.html#p=1">Å®×ÓÖ»³ÔÅ£Èâ³É¹¦¼õ·Ê</a></span></li> - -<li><span style="color:#c00;"><a href="http://blog.sina.com.cn/lm/health/" target="_blank" class="linkRed03">²©¿Í</a></span>|<a href="http://blog.sina.com.cn/s/blog_ea18fbe40102vyk8.html?tj=1" target="_blank">¼ÒÀï·ÅɶÒ×Ö°©</a> <a href="http://blog.sina.com.cn/s/blog_c23914bb0102vo0a.html?tj=1" target="_blank">ÕâÑù³ÔÓã¶ÌÊÙ</a> <a href="http://blog.sina.com.cn/s/blog_132cb5ac10102vo6y.html?tj=1" target="_blank">ºú×Ó³¤µÃ¿ìԤʾɶ</a></li> - -<li><span style="color:#c00;"><a href="http://health.sina.com.cn/" target="_blank">ÄпÆ</a></span>|<a href="http://health.sina.com.cn/d/s/2015-06-18/0733172982.shtml" target="_blank">´Ó³¿²ª¿´ÄÐÈ˽¡¿µ</a> <a href="http://health.sina.com.cn/hc/s/2015-06-18/0732172983.shtml" target="_blank">ÐÔ°®ÖÐÄÐÈËÅÂʲô</a> <a target="_blank" href="http://health.sina.com.cn/hc/s/2015-06-18/0732172986.shtml">´ßÇéʳÆ×</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod50 --> - </div> - </div> - <!-- part-r end --> - <div class="blank-cont" style="height:25px"></div> - <!-- part-s begin --> - - <div class="part-s clearfix"> - <div class="part-s-l"> - <!-- mod51 --> - <div class="mod-13 mod-02" tab-type="tab-wrap"> - <div class="tit02 clearfix"> - <h3 tab-type="tab-nav"><a href="http://fo.sina.com.cn/" target="_blank">·ðѧ</a></h3> - </div> - - <div class="mod27-cont" tab-type="tab-cont" style="padding-top:15px; padding-right:2px;" data-sudaclick="blk_fo_1" blkclick="auto_nav" blktitle="·ðѧ"> - -<!-- publish_helper name='·ðѧÇø¿é' p_id='30' t_id='119' d_id='1' --> - - <div class="pic-txt clearfix"> -<a href="http://fo.sina.com.cn/" target="_blank" class="pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/119/2013/0314/U2333P30T119D1F3626DT20150617143852.jpg" width="65" height="65" /></a><div class="txt"><h3><a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_67296_28236.html">·ð½Ì¹©·î¶ÔÏóÓÐÄÄЩ</a></h3> - -<p><a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_67296_28272.html">Àú´ú¡¶Ðľ­¡·Êé·¨¸ÅÀÀ</a></p> - -<p><a href="http://slide.fo.sina.com.cn/slide_65_68449_28230.html" target="_blank">ŨÇé¶ËÎ磺×ÔÖÆËØôÕ×Ó</a></p></div> - </div> - - <div class="blank-d" style="height:2px"></div> - - <ul class="list-b"> -<li><a target="_blank" href="http://fo.sina.com.cn/intro/lecture/2015-06-16/doc-ifxczyze9621110.shtml">ÕÒ»Ø×Ô¼º±¾ÐÄ</a> <a target="_blank" href="http://fo.sina.com.cn/intro/lecture/2015-06-16/doc-ifxczqan0741850.shtml">Ò»ÐÐìøʦ£ºÍ´¿à²»ÊÇÈ«²¿</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/intro/basic/2015-06-17/doc-ifxczyze9662570.shtml">½ðÓ¹ÎäÏÀÌìÁú°Ë²¿Óë·ð½Ì</a> <a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_68422_28207.html">°Ë´óÆÐÈøÌÆ¿¨</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/intro/basic/index.shtml">³£Ê¶</a>|<a target="_blank" href="http://fo.sina.com.cn/intro/basic/2015-06-17/doc-ifxczqan1546103.shtml">ÐÞÈÌÈèÊÇÈÌÆøÍÌÉùÂð</a> <a target="_blank" href="http://fo.sina.com.cn/intro/basic/2015-06-18/doc-ifxczyze9704281.shtml">ʲôÊÇ°ËÕýµÀ</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/intro/lecture/index.shtml">¿ªÊ¾</a>|<a target="_blank" href="http://fo.sina.com.cn/intro/lecture/2015-06-17/doc-ifxczqap4207346.shtml">Éí·ÝÒÔÍâµÄÄã</a> <a target="_blank" href="http://fo.sina.com.cn/intro/2015-06-17/doc-ifxczyze9663136.shtml">»»½Ç¶È¿´ÎÊÌâ¿àÊÇÀÖ</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/xuefo/">ѧ·ð</a>|<a target="_blank" href="http://fo.sina.com.cn/xuefo/2015-06-16/doc-ifxczqar0950965.shtml">ÓàÇïÓê̸·ð·¨ÈËÉú</a> <a target="_blank" href="http://fo.sina.com.cn/xuefo/2015-06-17/doc-ifxczqap4199508.shtml">ºîСǿѧ·ð֮·</a></li> - -<li><a target="_blank" href="http://fo.sina.com.cn/blog/">²©¿Í</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_a64f18960102vre2.html?tj=1" class="linkRed">°ËÖ¤¾ÝÈÃÄãÏàÐÅÂÖ»Ø</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_773f4e890102w5pp.html?tj=1">ÐÞÐÐÈËÆ߸£±¨</a></li><li><a target="_blank" href="http://slide.fo.sina.com.cn/">ͼ¼¯</a>|<a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_67296_28173.html">·ð½ÌµÄ¼ªÏé°Ë±¦</a> <a target="_blank" href="http://slide.fo.sina.com.cn/slide_65_68460_28235.html">ÈÕ±¾ËÂÔº½¨ÖþÖ®ÃÀ</a></li><li><a href="http://fo.sina.com.cn/veg/" target="_blank">ËØʳ</a>|<a target="_blank" href="http://fo.sina.com.cn/veg/cp/2015-06-17/doc-ifxczqap4169384.shtml">¶¹¸¯É³À­</a> <a target="_blank" href="http://fo.sina.com.cn/veg/cp/2015-06-18/doc-ifxczqap4202913.shtml">Èý±¦¸þ(ͼ)</a> <a target="_blank" href="http://fo.sina.com.cn/veg/cp/2015-06-17/doc-ifxczqan1546531.shtml">²Ë½·³´ÖñËñ</a></li> - </ul> - - </div> - </div> - <!-- mod51 --> - </div> - <div class="part-s-m"> - <!-- mod52 --> - <div class="uni-blk" id="SI_Order_W" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"> -<!-- - <a href="http://pet.sina.com.cn/" target="_blank">³èÎï</a> ---> - <a href="http://eat.sina.com.cn/" target="_blank">ÃÀʳ</a> - </span> - <!-- ip¶¨ÏòÁ´½Ó --> - <span class="order-menu-lnk"><a href="javascript:;" target="_blank" id="SI_IP_Tab_Nav_4"></a></span> - <!-- /ip¶¨ÏòÁ´½Ó --> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b mod52-fix-cont SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_life_1" blkclick="auto_nav" blktitle="³èÎïÃÀʳ"> -<!-- publish_helper name='³èÎïÃÀʳÇø¿é' p_id='30' t_id='124' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://blog.sina.com.cn/s/blog_75282e070102vn84.html?tj=1" target="_blank" class="uni-blk-pic"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/home/2015/0618/U2062P30DT20150618142000.jpg" width="105" height="70" /> - <span>ÁñÁ«ÅûÈøÒý±¬Î¶ÀÙ</span> - </a><ul class="uni-blk-list01 list-a"> -<li><a href="http://blog.sina.com.cn/s/blog_ec08dcae0102vfhk.html?tj=1" target="_blank">¶ËÎçÈý±¦Á÷ÓÍÏÌѼµ°</a> <a href="http://blog.sina.com.cn/s/blog_4791337b0102vlbk.html?tj=1" target="_blank">¼¦Èâ¼õ·Ê²Í</a></li> - -<li><a href="http://blog.sina.com.cn/s/blog_798702850102xih9.html?tj=1" target="_blank">¿ªÎ¸ÊÝÉíɽÎ÷Ãò¼â</a> <a href="http://blog.sina.com.cn/s/blog_844d7ba90102vljb.html?tj=1" target="_blank">½ª±¬»Ø¹øÅŹÇ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_a1b136950102vr82.html?tj=1" target="_blank">ͼ½âËĽÇÁà°üôÕ</a> <a href="http://blog.sina.com.cn/s/blog_4791337b0102vlbk.html?tj=1" target="_blank">Õý×ÚÈÕʽըÖíÅÅ</a></li> -<li><a href="http://blog.sina.com.cn/s/blog_6f4231eb0102vmu4.html?tj=1" target="_blank">ÏÄÈÕÇåÁ¹ÌðÆ·</a> <a href="http://blog.sina.com.cn/s/blog_6747c5790102volh.html?tj=1" target="_blank">ÇåÐÂÃÛÌÒ֥ʿĽ˹</a></li> - -</ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://beijing.51xiancheng.com/pc/index/list?cate=1" target="_blank">ÃÀʳ</a>| <a href="http://beijing.51xiancheng.com/article/11615 -" target="_blank">²ØÔÚ¾ÓÃñÇøµÄ½ðÅÆËâÄàÁúϺ</a> <a href="http://beijing.51xiancheng.com/article/12192" target="_blank">Õý×Ú½­ÄÏÊ®ÈýÏãÂéС</a> </li> -<li><a href="http://beijing.51xiancheng.com/pc/index/list?cate=6" target="_blank">±¬¿î</a>| <a href="http://weibo.com/p/1001603854685999088573 -" target="_blank">²ØÔÚºúͬÀïµÄ±Æ¸ñ¿§·È¹Ý</a> <a href="http://weibo.com/p/1001603838743596431247" target="_blank">²»¿É´í¹ýµÄÄÞºç¹úÃÀʳ</a> </li> -<li><a href="http://beijing.51xiancheng.com/pc/index/list?cate=1" target="_blank">¹¥ÂÔ</a>| <a href="http://beijing.51xiancheng.com/article/11637" target="_blank">ÄêÇáÈËÔú¶ÑµÄÂéÀ±Ð¡ÁúϺ</a> <a href="http://beijing.51xiancheng.com/article/12239" target="_blank">Èë¿Ú³¬Ë¬µÄÃØÖÆСÁúϺ</a> </li> -<li><a href="http://beijing.51xiancheng.com/" target="_blank">±±¾©</a>| <a href="http://beijing.51xiancheng.com/article/12351" target="_blank">µÛ¶¼×î½²¾¿µÄ¾©Î¶²Ë</a> <a href="http://beijing.51xiancheng.com/article/12366" target="_blank">³ÔÍê¾Í¿ªÊ¼ÏëÄîµÄ±±¾©Ð¡³Ô</a></li> -<li><a href="http://edu.sina.com.cn/photo/" target="_blank">×éͼ</a>| <a target="_blank" href="http://slide.edu.sina.com.cn/slide_11_611_28251.html">»Æ²Ó²Ó½ø¾üÓéÀÖȦ</a> <a target="_blank" href="http://slide.edu.sina.com.cn/slide_11_611_28255.html">жÈÄïѧʿÕÕ</a> <a target="_blank" href="http://slide.edu.sina.com.cn/slide_11_611_28257.html">ÒÕУ¸Ö¹ÜÎèУ»¨</a></li> -<li><a href="http://blog.sina.com.cn/lm/edu/" target="_blank">²©¿Í</a>| <a target="_blank" href="http://blog.sina.com.cn/s/blog_539c5bd20102vjdk.html?tj=1">ÈçºÎ±¨Ö¾Ô¸Èø߿¼·ÖÊý²»ÀË·Ñ</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_a5357a3e0102vv45.html?tj=1">ÄãÔÚÃÀ¹úÕõ¶àÉÙÇ®</a></li> -<li><a href="http://edu.sina.com.cn/zl/" target="_blank">ÍƼö</a>| <a target="_blank" href="http://blog.sina.com.cn/s/blog_abb623400102vr31.html?tj=1">½ÒÃظßУÈËÌåÄ£ÌØ(ͼ)</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_903b54120102vre7.html?tj=1">ÈÈÇé±¼·Å×îÃÀУ»¨(ͼ)</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod52 --> - </div> - <div class="part-s-r"> - <!-- mod53 --> - <div class="uni-blk" id="SI_Order_X" tab-type="tab-wrap" struc="1-6"> - <div class="SC_Order_Fix"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix SC_Order_Fix_Menu"> - <span class="no-bl selected" tab-type="tab-nav"><a href="http://astro.sina.com.cn/" target="_blank">ÐÇ×ù</a></span> - </div> - <a href="javascript:;" action-type="order" class="order-trigger SC_Order_Do SC_Order_Hidden" style="display:none" dis-type="1">ÎÒÒª¶¨ÖÆ</a> - <a href="javascript:;" class="order-changeit SC_Order_Display SC_Order_Changeit" style="display:none">Ë¢ÐÂ</a> - <div class="order-reset SC_Order_Control clearfix" style="display:none" dis-type="0"> - <a href="javascript:;" class="order-edit" action-type="order" isedit="1">±à¼­¶¨ÖÆ</a> - <a href="javascript:;" class="order-rest SC_Order_Res">»Ö¸´Ä¬ÈÏ</a> - </div> - </div> - <div class="uni-blk-b mod52-fix-cont SC_Order_Fix_Cont"> - <div tab-type="tab-cont" data-sudaclick="blk_astro_1" blkclick="auto_nav" blktitle="ÐÇ×ù"> -<!-- publish_helper name='ÐÇ×ùÇø¿é' p_id='30' t_id='120' d_id='1' --> - <div class="uni-blk-bt clearfix"> -<a href="http://slide.astro.sina.com.cn/slide_52_42283_36327.html" target="_blank" class="uni-blk-pic"> - <img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/home/2015/0617/U7132P30DT20150617184803.gif" width="105" height="70" /> - - <span>12ÐÇ×ùÎü¾¦´ó·¨</span> - </a><ul class="uni-blk-list01 list-a"><li><a href="http://astro.sina.com.cn/" target="_blank">Å®ÈË͵͵²â:ÄãͯÕ껹ʣ¶àÉÙ</a></li> - -<li><a target="_blank" href="http://astro.sina.com.cn/v/ss/2015-06-17/doc-ifxczqar0990404.shtml">ΪǮ·­Á³µÄÐÇ×ù</a> <a target="_blank" href="http://astro.sina.com.cn/e/2015-06-17/doc-ifxczqap4211765.shtml">½ñÄê¶ËÎçË­µ¹Ã¹</a></li> - -<li><a target="_blank" href="http://astro.sina.com.cn/v/ss/2015-06-17/doc-ifxczqar0992909.shtml">ËÍ12ÐÇ×ù°Ö°ÖɶÀñÎï</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_61682aca0102vpjt.html?tj=1">3ÖÖÃβ»ÄÜ˵</a></li> - -<li><a target="_blank" href="http://blog.sina.com.cn/s/blog_5bd1ddf60102w059.html?tj=1">ÄãÊdz´¹É±ØÅâÃüÂð</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_50939dbf0102vwhd.html?tj=1">12ÐÇ×ùÌôÌÞÍõ</a></li></ul> - </div> - <div class="blk-line"></div> - <ul class="uni-blk-list02 list-a"> -<li><a href="http://astro.sina.com.cn/t/" target="_blank">²âÊÔ</a>|<a target="_blank" href="http://astro.sina.com.cn/t/aq/2015-06-17/doc-ifxczqar0990738.shtml">ÎÞÍ´·ÖÊÖÄãÐÐÂð</a> <a target="_blank" href="http://astro.sina.com.cn/t/aq/2015-06-17/doc-ifxczqap4205473.shtml">ÇéµÐºÚÄãÕ¦½â¾ö</a> <a target="_blank" href="http://astro.sina.com.cn/t/2015-06-17/doc-ifxczqar0995624.shtml">ÄãÂèÕ¦¿´ÄãµÄ</a></li><li><a href="http://astro.sina.com.cn/b/ysjj/" target="_blank">ÔËÊÆ</a>|<a target="_blank" href="http://blog.sina.com.cn/s/blog_61bd67650102vl7r.html?tj=1">ÈýÂèÖÜÔË</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_6431df490102vk3h.html?tj=1">AlexÖÜÔË</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_3e8e948a0102vl9o.html?tj=1">Î×Å®ÖÜÔË</a> <a target="_blank" href="http://blog.sina.com.cn/s/blog_4758ccc20102vq7d.html?tj=1">12ÐÇ×ù¿ªÔËÖ¸ÄÏ</a></li><li><a href="http://astro.sina.com.cn/l/" target="_blank">½Ì³Ì</a>|<a target="_blank" href="http://astro.sina.com.cn/e/2015-06-17/doc-ifxczqan1629906.shtml">¶ËÎç±Ùа´ó½ÒÃØ</a> <a target="_blank" href="http://astro.sina.com.cn/e/2015-06-17/doc-ifxczqap4210882.shtml">ɶÃüÒ»¶¨·¢ºá²Æ</a> <a target="_blank" href="http://astro.sina.com.cn/e/2015-06-16/doc-ifxczyze9636062.shtml">10ÖÖ·¿×Ó²»ÄÜÒª</a></li><li><a href="http://astro.sina.com.cn/xl/" target="_blank">ÐÄÀí</a>|<a target="_blank" href="http://astro.sina.com.cn/xl/hl/2015-06-17/doc-ifxczqar0988325.shtml">Å®ÈËÐØÐÍ¿´»éÒö</a> <a target="_blank" href="http://astro.sina.com.cn/xl/hl/2015-06-17/doc-ifxczqar0989128.shtml">10Ô¼»áÄÐÈË×îºÞ</a> <a target="_blank" href="http://astro.sina.com.cn/t/2015-06-17/doc-ifxczqan1584952.shtml">ÄãÊÇÇéÉ«¸ßÊÖÂð</a></li><li><a href="http://club.astro.sina.com.cn/" target="_blank">ÂÛ̳</a>|<a target="_blank" href="http://club.astro.sina.com.cn/thread-3771532-1-1.html">ͬÄêͬÔÂͬÈÕµÄÁ©Ìì³Ó</a> <a target="_blank" href="http://club.astro.sina.com.cn/thread-3727606-1-1.html">Ë«ÓãÅ®ÏñÇ×ÂèÒ»Ñù¿ÞÄÖ</a></li> -<li><a href="http://astro.sina.com.cn/bbs/" target="_blank">ÂÛ̳</a>|<a target="_blank" href="http://club.astro.sina.com.cn/thread-3751839-1-1.html">ħ¶¼Ê¨×ÓÇéÏÝÉÏÁ÷Éç»á</a> <a target="_blank" href="http://club.astro.sina.com.cn/thread-3774248-1-1.html">ÌìЫ׷²»µ½´¦Å®¿Þ³É¹·</a></li> -<li><a target="_blank" href="http://slide.astro.sina.com.cn/">GIF</a>|<a target="_blank" href="http://slide.astro.sina.com.cn/slide_52_42283_35835.html">12ÐÇ×ù±¿±¿ßÕ</a> <a target="_blank" href="http://slide.astro.sina.com.cn/slide_52_42283_35855.html">12ÐÇ×ùµÄÌØÒ칦ÄÜ</a> <a target="_blank" href="http://slide.astro.sina.com.cn/slide_52_42283_35879.html">12ÐÇ×ù×÷ËÀÉñ¼¼</a></li> - </ul> - </div> - </div> - </div> - </div> - <!-- mod53 --> - </div> - </div> - <!-- part-s end --> - -<div class="blank-cont" style="height:18px"></div> -<style> -.part-t{width:1000px;} -.part-t .part-tcont{width:1000px;height:201px;overflow:hidden;position:relative;} -.part-t .uni-blk-t .order-menu span{padding:0 29px;} -.part-t .uni-blk-t .order-menu span.no-bl{padding:0 29px 0 28px !important;} -.part-t .uni-blk-t .order-menu span.selected{padding:0 28px;} -</style> -<div class="part-t uni-blk" tab-type="tab-wrap"> - <div class="uni-blk-t clearfix"> - <div class="order-menu clearfix"><p> - <span tab-type="tab-nav" class="mod54-tab no-bl" id="testU"><a href="http://fashion.sina.com.cn/photo/" target="_blank" suda-uatrack="key=index_www_pic&value=pic_click">ÃÀͼ</a></span> - <span tab-type="tab-nav" class="mod54-tab"><a href="http://slide.astro.sina.com.cn/" target="_blank" suda-uatrack="key=index_www_pic&value=gif_click">GIF</a></span> - </p></div> - </div> - <div class="blank-cont" style="height:20px"></div> - <div class="part-tcont"> - <div tab-type="tab-cont" class="mod54-cont"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap_t00" data-sudaclick="blk_pic_fashion"> -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/s/slide_24_68372_60732.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/BsUl-fxczqar0946754.jpg" width="198" height="132" /> <span class="scroll-txt">º«¸ýÁη²³Ø²ýÐñ ÄÐÉñÆë¾ÛÐ㳡</span></a></div> - -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60756.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/A-ze-fxczqar0946802.jpg" width="198" height="132" /> <span class="scroll-txt">TaylorÁìÏÎÏÄÈÕÀÙË¿Ê¢Ñç </span></a></div> - -<div class="scroll-item"><a href="http://slide.edu.sina.com.cn/slide_11_611_28194.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/edu/2015/0616/U12690P42DT20150616112913.jpg" width="198" height="132" /> <span class="scroll-txt">»ªÅ©Ð£»¨É¹ÐÂÕÕ Å®Íõ·¶Ê®×ã</span></a></div> - -<div class="scroll-item"><a href="http://slide.baby.sina.com.cn/syj/slide_10_846_28178.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i0.sinaimg.cn/dy/2015/0616/U12222P1DT20150616112733.jpg" width="198" height="132" /> <span class="scroll-txt">ÈÕ±¾Õ¬Å®·¿¼ä£ºÕâÊÇÈËסµÄÂð£¿</span></a></div> - -<div class="scroll-item"><a href="http://slide.health.sina.com.cn/hc/slide_31_28380_85515.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i1.sinaimg.cn/health/2015/0616/U11489P434DT20150616112526.jpg" width="198" height="132" /> <span class="scroll-txt">¹ãÎ÷У»¨Ð£²Ý´óÈü Ñ¡ÊÖÓ¾×°Ðã</span></a></div> - -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/l/slide_24_66519_60684.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150616/BAkz-fxczyze9624350.jpg" width="198" height="132" /> <span class="scroll-txt">ÈÃÄãÐÒ¸£¸Ð±¬ÅïµÄ20¿îÌðÌðȦ</span></a></div> - -<div class="scroll-item"><a href="http://slide.baby.sina.com.cn/yjq/slide_10_846_28124.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i2.sinaimg.cn/dy/2015/0616/U12222P1DT20150616112740.jpg" width="198" height="132" /> <span class="scroll-txt">ÐìÎõæÂÓëÅ®¶ùºÏÓ°ÕÕÆعâ</span></a></div> - -<div class="scroll-item"><a href="http://slide.health.sina.com.cn/hc/slide_31_28380_85376.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/health/2015/0616/U11489P434DT20150616112830.jpg" width="198" height="132" /> <span class="scroll-txt">ÍÁ¶úÆä85ËêÀÏÈËÔÙµ±µù </span></a></div> - -<div class="scroll-item"><a href="http://slide.fashion.sina.com.cn/s/slide_24_66095_60764.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/transform/20150616/VfHT-fxczqan0672023.jpg" width="198" height="132" /> <span class="scroll-txt">ÂíÇòÈü ÇÇÖÎСÍõ×ÓÃÈ·­ÖÚÈË</span></a></div> - -<div class="scroll-item"><a href="http://slide.edu.sina.com.cn/slide_11_611_28091.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://i3.sinaimg.cn/edu/2015/0616/U12690P42DT20150616112913_1.jpg" width="198" height="132" /> <span class="scroll-txt">20Ë궫ʦÃÀÅ®ÉñËÆСÌÀΨ×ߺì</span></a></div> - - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L_t00"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R_t00"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists_t00"></div> - </div> - <div tab-type="tab-cont" class="mod54-cont"> - <div class="scroll-pic-frame"> - <div class="scroll-pic-wrap" id="SI_Scroll_Wrap_t01" data-sudaclick="blk_pic_astro"> -<textarea class="hidden" node-type="data-textarea" style="visibility:hidden;"> -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32866.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/b7K4-fxefurt9337403.gif" width="198" height="132" /> <span class="scroll-txt">12ÐÇ×ù±»Ë¦ÁË</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32949.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/ch7S-fxefurt9337413.gif" width="198" height="132" /> <span class="scroll-txt">12ÐÇ×ùµÄÃÈÄãÒ²ÊDz»¶®</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32969.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/8_Kt-fxefurs2560083.gif" width="198" height="132" /> <span class="scroll-txt">12ÐÇ×ùûÁ³¼ûÈË</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32890.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/yLbI-fxefurt9337448.gif" width="198" height="132" /> <span class="scroll-txt">ÐÐΪ¹Å¹ÖµÄ12ÐÇ×ù</span></a></div> - -<div class="scroll-item"><a href="http://slide.astro.sina.com.cn/slide_52_42283_32861.html" target="_blank"><img src="http://i1.sinaimg.cn/home/main/blk/d.gif" data-src="http://n.sinaimg.cn/default/20150617/4Xr6-fxefurt9337462.gif" width="198" height="132" /> <span class="scroll-txt">ÔãÁË£¡12ÐÇ×ù̯ÉÏ´óÊÂÁË£¡</span></a></div> - -</textarea> - </div> - <a href="javascript:;" class="scroll-arr-l" id="SI_Scroll_Arr_L_t01" style="display:none;"></a> - <a href="javascript:;" class="scroll-arr-r" id="SI_Scroll_Arr_R_t01" style="display:none;"></a> - </div> - <div class="scroll-dot-lists" id="SI_Scroll_Dot_Lists_t01" style="display:none;"></div> - </div> - - </div> - <script> - jsLoader({ - name : 'shm', - callback : function() { - for(var i = 0, l = 2; i < l; i++){ - var focusScroll = new ScrollPic(); - focusScroll.scrollContId = "SI_Scroll_Wrap_t0" + i; //ÄÚÈÝÈÝÆ÷ID - focusScroll.dotListId = "SI_Scroll_Dot_Lists_t0" + i;//µãÁбíID - focusScroll.arrLeftId = "SI_Scroll_Arr_L_t0" + i; - focusScroll.arrRightId = "SI_Scroll_Arr_R_t0" + i; - focusScroll.dotClassName = "";//µãclassName - focusScroll.dotOnClassName = "cur";//µ±Ç°µãclassName - focusScroll.listType = "";//ÁбíÀàÐÍ(number:Êý×Ö£¬ÆäËüΪ¿Õ) - focusScroll.listEvent = "onmouseover"; //Çл»Ê¼þ - focusScroll.frameWidth = 1000;//ÏÔʾ¿ò¿í¶È - focusScroll.pageWidth = 1000; //·­Ò³¿í¶È - focusScroll.upright = false; //´¹Ö±¹ö¶¯ - focusScroll.speed = 10; //Òƶ¯ËÙ¶È(µ¥Î»ºÁÃ룬ԽСԽ¿ì) - focusScroll.space = 40; //ÿ´ÎÒƶ¯ÏñËØ(µ¥Î»px£¬Ô½´óÔ½¿ì) - focusScroll.autoPlay = false; //×Ô¶¯²¥·Å - focusScroll.autoPlayTime = 15; //×Ô¶¯²¥·Å¼ä¸ôʱ¼ä(Ãë) - focusScroll.circularly = true; - focusScroll.initialize(); //³õʼ»¯ - } - var tabArr = SHM.dom.byClass("mod54-tab"), - contArr = SHM.dom.byClass("mod54-cont"); - - var defaultSelectedNavIndex = (Math.random()*10|0) < 5 ? 0 : 1; - - SHM.app.tab.switchByEle(tabArr[defaultSelectedNavIndex]); - contArr[defaultSelectedNavIndex?0:1].style.display = "none"; - } - }); - </script> -</div> -<div class="blank-cont" style="height:10px"></div> - -<!-- -<div class="blank-cont" style="height:25px"></div> ---> - -<!-- publish_helper name='³ÇÊÐÁªÃË' p_id='30' t_id='125' d_id='2' --> -<!-- city-union begin --> -<div class="city-union" data-sudaclick="blk_city_union"> - <div class="clearfix"> - <p class="name"><a target="_blank" href="http://city.sina.com.cn/">ÐÂÀ˳ÇÊÐ</a></p> - <div class="clist"> - <p><a target="_blank" href="http://sh.sina.com.cn/">ÉϺ£</a> <a href="http://tj.sina.com.cn/" target="_blank">Ìì½ò</a> <a target="_blank" href="http://cq.sina.com.cn/">ÖØÇì</a> <a target="_blank" href="http://gd.sina.com.cn/">¹ã¶«</a> <a target="_blank" href="http://henan.sina.com.cn/">ºÓÄÏ</a> <a target="_blank" href="http://sc.sina.com.cn/">ËÄ´¨</a> <a target="_blank" href="http://fj.sina.com.cn/">¸£½¨</a> <a target="_blank" href="http://mn.sina.com.cn/">ÃöÄÏ</a> <a target="_blank" href="http://zj.sina.com.cn/">Õã½­</a> <a target="_blank" href="http://jiangsu.sina.com.cn">½­ËÕ</a> <a target="_blank" href="http://hebei.sina.com.cn/">ºÓ±±</a> <a target="_blank" href="http://hb.sina.com.cn/">ºþ±±</a> <a target="_blank" href="http://hunan.sina.com.cn/">ºþÄÏ</a> <a target="_blank" href="http://sx.sina.com.cn/">ÉÂÎ÷</a> <a target="_blank" href="http://ln.sina.com.cn/">ÁÉÄþ</a> <a target="_blank" href="http://hlj.sina.com.cn">ºÚÁú½­</a> <a target="_blank" href="http://ah.sina.com.cn">°²»Õ</a> <a target="_blank" href="http://jx.sina.com.cn/">½­Î÷</a> <a target="_blank" href="http://jl.sina.com.cn/">¼ªÁÖ</a> <a target="_blank" href="http://shanxi.sina.com.cn/">ɽÎ÷</a> <a target="_blank" href="http://hainan.sina.com.cn/">º£ÄÏ</a> <a href="http://sd.sina.com.cn/" target="_blank">ɽ¶«</a> <a href="http://gx.sina.com.cn/" target="_blank">¹ãÎ÷</a></p> - <p><a href="http://nb.sina.com.cn/" target="_blank">Äþ²¨</a> <a target="_blank" href="http://dl.sina.com.cn/">´óÁ¬</a> <a href="http://wx.sina.com.cn/" target="_blank">ÎÞÎý</a> <a target="_blank" href="http://hlj.sina.com.cn/lyj/index.html ">±ù³Ç</a> <a href="http://jl.sina.com.cn/changchun/index.html" target="_blank">³¤´º</a> <a target="_blank" href="http://www.xian-tourism.com/">Î÷°²</a> <a target="_blank" href="http://city.sina.com.cn/city/f/sjzwx.html">ʯ¼Òׯ</a> <a target="_blank" href="http://www.jsjjw.cn">¾¸½­</a> <a target="_blank" href="http://sina.haian.gov.cn/">º£°²</a> <a target="_blank" href="http://www.haimen.gov.cn/">º£ÃÅ</a> <a target="_blank" href="http://www.sinasy.com.cn/">ÉÏÓÝ</a> <a target="_blank" href="http://www.yw.gov.cn/">ÒåÎÚ</a> <a target="_blank" href="http://hlj.sina.com.cn/shangzhi/">ÉÐÖ¾</a> <a href="http://sina.hd.cn/" target="_blank">ºªµ¦</a> <a href="http://ah.sina.com.cn/zt/travel/ahwenhuazhilv/index.shtml" target="_blank">ÃÀºÃ°²»Õ</a> <a href="http://weibo.com/hcxfjq" target="_blank">»Ê³ÇÏฮ</a> <a href="http://jl.sina.com.cn/yanbian/" target="_blank">ÑÓ±ß</a> <a href="http://yn.sina.com.cn/travel/zt/tiyandianyuetieluchuanyuemiguishiguang/index.shtml" target="_blank">ºìºÓ</a> <a href="http://www.qingdaochina.org/" target="_blank">Çൺ</a></p> - </div> - </div> - <div class="clearfix c-hot"> - <p class="name"><a target="_blank" href="http://city.sina.com.cn/">Éú»îÈÈÇø</a></p> - <p class="clist"><a target="_blank" href="http://hmgxq.haimen.gov.cn/">º£ÃŸÛÐÂÇø</a> <a target="_blank" href="http://sx.sina.com.cn/zt/city/xachanba/index.shtml">›ºå±Éú̬Çø</a> <a href="http://hlj.sina.com.cn/mdr/index.html" target="_blank">±ùÑ©´óÊÀ½ç</a> <a href="http://hlj.sina.com.cn/hanan/index.html" target="_blank">ÎåÉ«¹þÄÏ</a> <a href="http://jl.sina.com.cn/jlsgjt/index.html" target="_blank">¼ªÁÖÉ­¹¤</a> <a target="_blank" href="http://city.sina.com.cn/city/Declaration.html">[¹«¸æÉùÃ÷]</a></p> - </div> -</div> -<!-- city-union end --> - -<div class="blank-cont" style="height:25px"></div> - - <!-- part-t begin --> - <div class="part-t"> -<!--_SINA_ADS_BEGIN_--> -<!-- 1000x90 3ÂÖ²¥µ×²¿Í¨À¸¹ã¸æ begin --> -<div id="ad_16990" class="mb25"><ins class="sinaads" data-ad-pdps="PDPS000000016990"></ins><script>(sinaads = window.sinaads || []).push({});</script></div> -<!-- 1000x90 3ÂÖ²¥µ×²¿Í¨À¸¹ã¸æ end --> -<!--_SINA_ADS_END_--> - </div> - <!-- part-t end --> - - <!-- footer begin --> - <div id="footer" class="footer" data-sudaclick="blk_footer"> - <div class="ft-info"><a href="http://corp.sina.com.cn/chn/">ÐÂÀ˼ò½é</a> ©® <a href="http://corp.sina.com.cn/eng/">About Sina</a> ©® <a href="http://emarketing.sina.com.cn/">¹ã¸æ·þÎñ</a> ©® <a href="http://www.sina.com.cn/contactus.html">ÁªÏµÎÒÃÇ</a> ©® <a href="http://career.sina.com.cn/">³ÏƸӢ²Å</a> ©® <a href="http://www.sina.com.cn/intro/lawfirm.shtml">ÍøÕ¾ÂÉʦ</a> ©® <a href="http://english.sina.com">SINA English</a> ©® <a href="https://login.sina.com.cn/signup/signup.php">×¢²á</a> ©® <a href="http://help.sina.com.cn/">²úÆ·´ðÒÉ</a></div> - <p class="ft-copy">Copyright &copy;1996-2015 SINA Corporation, All Rights Reserved</p> - <div class="ft-list"> - <ul> - <li style="margin-left:0px;"> - <a href="http://www.itrust.org.cn" target="_blank"> - <img width="110" height="50" alt="Öйú»¥ÁªÍøЭ»á" src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo01.gif"></a> - </li> - <li> - <a href="http://www.hd315.gov.cn/beian/view.asp?bianhao=0102000102300001" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i2.sinaimg.cn/home/main/index2013/footerlogo/footer_logo02.gif" width="109" height="50" alt="¾­ÓªÐÔÍøÕ¾±¸°¸ÐÅÏ¢"></a> - </li> - <li> - <a href="http://www.12377.cn/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i3.sinaimg.cn/home/main/index2013/footerlogo/footer_logo03.gif" width="109" height="50" alt="²»Á¼ÐÅÏ¢¾Ù±¨ÖÐÐÄ"></a> - </li> - <li> - <a href="http://www.bnia.cn/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i0.sinaimg.cn/home/main/index2013/footerlogo/footer_logo04.gif" width="109" height="50" alt="±±¾©ÍøÂçÐÐҵЭ»á"></a> - </li> - - <li> - <a href="http://www.bj.cyberpolice.cn/index.htm" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo05.gif" width="105" height="50" alt="ÍøÂç110±¨¾¯·þÎñ"></a> - </li> - - <li> - <a href="https://ss.knet.cn/verifyseal.dll?sn=2010091500100002145&ct=df&a=1&pa=0.14296675658609825" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo10_1.gif" width="123" height="50" alt="¿ÉÐÅÍøÕ¾"></a> - </li> - - <li> - <a href="http://www.bjwhzf.gov.cn/accuse.do" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i3.sinaimg.cn/home/main/index2013/footerlogo/footer_logo07.gif" width="111" height="50" alt="±±¾©ÎÄ»¯Êг¡¾Ù±¨ÈÈÏß"></a> - </li> - <li> - <a href="http://www.allyes.com/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i0.sinaimg.cn/home/main/index2013/footerlogo/footer_logo08.gif" width="107" height="50" alt="ºÃÒ®¹ã¸æÍøÂç"></a> - </li> - <li> - <a href="http://www.bjjubao.org/" target="_blank"> - <img src="http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif" data-src="http://i1.sinaimg.cn/home/main/index2013/footerlogo/footer_logo09.gif" width="107" height="50" alt="±±¾©»¥ÁªÍø¾Ù±¨ÖÐÐÄ"></a> - </li> - </ul> - - </div> - <p><a href="http://corp.sina.com.cn/chn/sina_priv.html" target="_blank">Òþ˽±£»¤</a>¡¡ÐÂÀ˹«Ë¾¡¡<a href="http://www.sina.com.cn/intro/copyright.shtml">°æȨËùÓÐ</a>¡¡<a href="http://www.miibeian.gov.cn" target="_blank">¾©ICPÖ¤000007</a></p> - <p>¿Í»§·þÎñÈÈÏߣº4006900000¡¡Î¥·¨ºÍ²»Á¼ÐÅÏ¢¾Ù±¨µç»°£º010-62646869¡¡¾Ù±¨ÓÊÏ䣺<a href="mailto:jubao@vip.sina.com">jubao@vip.sina.com</a></p> - <p>&nbsp;</p> - <p><a href="http://www.sina.com.cn/licence/www0003.html" target="_blank">¾©ÍøÎÄ[2014]2045-295ºÅ</a>¡¡<a href="http://www.sina.com.cn/licence/news.html" target="_blank">»¥ÁªÍøÐÂÎÅÐÅÏ¢·þÎñÐí¿É</a></p> - <p><a href="http://www.sina.com.cn/licence/yjj0031.html" target="_blank">¹ú¼ÒÒ©¼à¾Ö£¨¾©£©-¾­ÓªÐÔ-2014-0004</a>¡¡<a href="http://www.sina.com.cn/licence/4.html" target="_blank">¾©½ÌÑÐ[2002]7ºÅ</a>¡¡<a href="http://www.sina.com.cn/licence/3.html" target="_blank">µçÐÅÒµÎñÉóÅú[2001]×ÖµÚ379ºÅ</a></p> - <p><a href="http://www.sina.com.cn/license/telecom09.html" target="_blank">ÔöÖµµçÐÅÒµÎñ¾­ÓªÐí¿ÉÖ¤B2-20090108</a>¡¡<a href="http://www.sina.com.cn/licence/dx000007.html" target="_blank">µçÐÅÓëÐÅÏ¢·þÎñÒµÎñ¾­ÓªÐí¿ÉÖ¤000007ºÅ</a>¡¡<a href="http://www.sina.com.cn/licence/wsxx.html" target="blank">¾©ÎÀÍøÉó[2014]µÚ0148ºÅ</a></p> - <p><a href="http://www.sina.com.cn/license/rtppl2009.html" target="_blank">¹ã²¥µçÊÓ½ÚÄ¿ÖÆ×÷¾­ÓªÐí¿ÉÖ¤£¨¾©£©×ÖµÚ828ºÅ</a> <a href="http://www.sina.com.cn/license/map2011.html" target="_blank">¼×²â×Ê×Ö1100078</a> ¾©¹«Íø°²±¸110000000016ºÅ</p> - </div> - <!-- footer end --> - </div> - <!-- main end --> - - <script type="text/javascript"> -// var ORDER_MAP = {'10100' : 'SI_Order_A', '10200' : 'SI_Order_B', '10300' : 'SI_Order_C', '10400' : 'SI_Order_D', '10500' : 'SI_Order_E', '10600' : 'SI_Order_F', '10700' : 'SI_Order_G', '10800' : 'SI_Order_H', '10900' : 'SI_Order_I', '11000' : 'SI_Order_J', '11100' : 'SI_Order_K', '11200' : 'SI_Order_L', '11500' : 'SI_Order_O', '11600' : 'SI_Order_P', '11700' : 'SI_Order_Q', '11800' : 'SI_Order_R', '11900' : 'SI_Order_S', '12000' : 'SI_Order_T', '12100' : 'SI_Order_U', '12200' : 'SI_Order_V', '12300' : 'SI_Order_W', '12400' : 'SI_Order_X'}; - jsLoader({ - name : 'middleJs', - url : 'http://finance.sina.com.cn/basejs/suggestServer.js', - callback: function() { - var suggestServer = new SuggestServer(); - suggestServer.bind({ - "input": "textSuggest", - "type": "stock", - "value": "@2@", - "width": 160, - "head": {"Ñ¡Ïî":'Ñ¡Ïî',"ÖÐÎÄÃû³Æ":'ÖÐÎÄÃû³Æ'}, - "body": {'0':'-1', '1':'4'}, - "link": "http://biz.finance.sina.com.cn/suggest/lookup_n.php?country=@type@&q=@2@" - }); - window.changeViewInputs = function changeViewInputs(__elementSelect) { - __elementSelect.form["q"].value = "´úÂë/Ãû³Æ/Æ´Òô"; - suggestServer.changeType(__elementSelect.value); - } - } - }); - /*jsLoader({ - name: 'shm', - callback: function() { - jsLoader({ - name: 'placeholderinit', - url: '../../js/placeholderinit.js' - }); - } - });*/ - -/* - jsLoader({ - name: 'shm', - callback: function() { - var byId = SHM.dom.byId, - addEvent = SHM.evt.addEvent, - unTrack = SHM.app.uaTrack, - getXY = SHM.dom.getXY, - W = window, - D = document; - DIV = D.createElement('DIV'), - tml = '<div class="top_btn" id="SI_Totop_Btn" style="visibility:hidden"><a class="toplink" href="javascript:;" title="·µ»Ø¶¥²¿" style="">TOP</a></div>'; - DIV.className = 'side-btns-wrap'; - DIV.setAttribute('id','SI_Sidebtns_Wrap'); - DIV.innerHTML = tml; - D.getElementsByTagName('BODY')[0].appendChild(DIV); - - var wrap = byId('SI_Sidebtns_Wrap'); - var btn = byId('SI_Totop_Btn'); - var isIE6 = $globalInfo.ua.isIE6; - var resetBtnLeft = function() { - var mLeft = parseInt(SHM.dom.getWinSize().width); - - mLeft < 1100 ? (wrap.style.marginLeft = (mLeft/2 - wrap.offsetWidth - 15) + 'px') : (wrap.style.marginLeft = '505px'); - }; - addEvent(W,'resize',function(){ - resetBtnLeft(); - }); - addEvent(W,'scroll',function(){ - var top = W.pageYOffset || D.documentElement.scrollTop || D.body.scrollTop; - top > 0 ? btn.style.visibility = 'visible' : btn.style.visibility = 'hidden'; - if(isIE6) { - var wh = W.innerHeight || D.documentElement.clientHeight || D.body.clientHeight; - wrap.style.top = (top + wh - 120) + 'px'; - } - }); - addEvent(btn,'click',function(){ - D.documentElement.scrollTop = 0; - D.body.scrollTop = 0; - unTrack('to_top','to_top'); - }); - } - }); -*/ - -/* - jsLoader({ - name: 'shm', - callback: function() { - jsLoader({ - name: 'shm_order', - url: 'http://ent.sina.com.cn/js/470/2013/0311/order.js' - }); - } - }); -*/ - jsLoader({ - name: 'shm', - callback: function() { - jsLoader({ - name: 'b_search', - url: 'http://www.sina.com.cn/js/index/96/temp/b_search.js', - callback : function() { - window.blogsearch = function(fn,strName) { - if(fn.q.value==""||fn.q.value=="ÇëÊäÈë²éѯ´Ê") { - fn.q.value="ÇëÊäÈë²éѯ´Ê"; - fn.q.focus(); - return false - } - if(strName!="blog") { - return false - } - fn.submit(); - return false - }; - window.booksearch = function(fn) { - if(fn.k.value==""||fn.k.value=="ÇëÊäÈë²éѯ´Ê") { - fn.k.value="ÇëÊäÈë²éѯ´Ê"; - fn.k.focus(); - return false; - } - fn.submit(); - return false; - }; - window.carsearch = function(fn,strName) { - if(fn.q.value==""||fn.q.value=="ÇëÊäÈë²éѯ´Ê") { - fn.q.value="ÇëÊäÈë²éѯ´Ê"; - fn.q.focus(); - return false - } - if(strName!="car") { - return false - } - if(fn.by.value == "cars"){ - window.open('http://so.auto.sina.com.cn/car/' + fn.q.value+'/'); - return false; - } - else if(fn.by.value == "kinds"){ - window.open('http://so.auto.sina.com.cn/search/' + fn.q.value+'/'); - return false; - } - }; - } - }); - } - }); - -var isIE6 = navigator.appVersion.indexOf("MSIE 6") != -1 ? true: false; -//ͼƬ¹ö¶¯¼ÓÔØ -~function() {var d = document, w = this, b = document.body, h = document.documentElement, p = [], eventFunc = function() {scrollLoader.scroll() }, bH = -1, timer, bT, bVH, iTotal = d.images.length; var sina = {$: function(objName) {if (d.getElementById) {return d.getElementById(objName) } else {return d.all[objName] } }, addEvent: function(obj, eventType, func) {if (obj.attachEvent) {obj.attachEvent("on" + eventType, func) } else {obj.addEventListener(eventType, func, false) } }, delEvent: function(obj, eventType, func) {if (obj.detachEvent) {obj.detachEvent("on" + eventType, func) } else {obj.removeEventListener(eventType, func, false) } }, absPosition: function(obj, parentObj) {var left = obj.offsetLeft; var top = obj.offsetTop; var tempObj = obj.offsetParent; try {while (tempObj != b && tempObj != d.documentElement && tempObj != parentObj && tempObj != null) {left += tempObj.offsetLeft; top += tempObj.offsetTop; tempObj = tempObj.offsetParent } } catch (e) {}; return {left: left, top: top } } }; var scrollLoader = {version: '1.1.0', status: "complete", mult: 2, init: function(ele) {var that = this, imgs, num = 0; if (ele && ele.getElementsByTagName) {imgs = ele.getElementsByTagName('img') } else {imgs = d.images }; for (var i = 0; i < imgs.length; i++) {if (imgs[i].getAttribute("data-src") && !imgs[i].__isSL) {if (imgs[i].offsetWidth == 0 && imgs[i].offsetHeight == 0) {imgs[i].__pObj = imgs[i].parentNode; while (imgs[i].__pObj.offsetWidth == 0 && imgs[i].__pObj.offsetHeight == 0) {imgs[i].__pObj = imgs[i].__pObj.parentNode } }; imgs[i].__isSL = true; p.push(imgs[i]); num++ } }; if (num > 0) {if (this.status != 'scrolling') {sina.addEvent(w, "scroll", eventFunc); this.status = "scrolling"; timer = setInterval(function() {that.timer() }, 200) }; this.scroll() } }, timer: function() {if (iTotal !== d.images.length) {iTotal = d.images.length; this.init() }; var vh = Math.min(h.clientHeight, b.clientHeight); var vt = (w.pageYOffset || b.scrollTop || h.scrollTop) - Math.round(vh * (this.mult - 1) / 2); var vb = vt + Math.round(vh * ((this.mult - 1) / 2 + 1)); if (bT !== vt || vb !== bVH) {this.scroll() } }, showImg: function(img) {if (img.getAttribute("data-src")) { img.removeAttribute("data-top"); img.__pObj = null; img.__isSL = null;img.src = img.getAttribute("data-src"); if(isIE6){return false;} } }, scroll: function() {if (this.status != "scrolling") {return }; var cache = 0; if (bH == d.body.scrollHeight) {cache = 1 } else {bH = d.body.scrollHeight }; var vh = Math.min(h.clientHeight, b.clientHeight); var vt = (w.pageYOffset || b.scrollTop || h.scrollTop) - Math.round(vh * (this.mult - 1) / 2); var vb = vt + Math.round(vh * ((this.mult - 1) / 2 + 1)); bT = vt; bVH = vb; var s = 0, posTop, obj; for (var i = 0; i < p.length; i++) {if (!p[i].getAttribute("data-src")) {continue }; s++; if (!cache) {if (p[i].offsetWidth == 0 && p[i].offsetHeight == 0) {p[i].__pObj = p[i].parentNode; if (!p[i].__pObj) {this.showImg(p[i]); continue }; while ( !! p[i].__pObj && p[i].__pObj.offsetWidth == 0 && p[i].__pObj.offsetHeight == 0) {p[i].__pObj = p[i].__pObj.parentNode } }; obj = p[i].__pObj || p[i]; posTop = sina.absPosition(obj, b).top; p[i].setAttribute("data-top", posTop) } else {posTop = p[i].getAttribute("data-top") } if (posTop >= vt && posTop <= vb) {this.showImg(p[i]) } }; if (s == 0) {this.status = "complete"; sina.delEvent(w, "scroll", eventFunc); clearInterval(timer) } } }; this.scrollLoader = scrollLoader }(); scrollLoader.init(); - - </script> - - <!-- ¼ì²éµØÓò begin --> - <script type="text/javascript"> - ;(function() { - //var shmIPlookup = null; - var handle = function(info, city) { - // infoΪremote_ip_info,cityΪÓëcookieÖеÄcity±È½ÏºóµÄ³ÇÊУ¬cookieÓÅÏÈ - var province = info.province; - city = info.city; - //var province = shmIPlookup.getPNameByCName(city); - //city = city; - - var desc = info.desc; - if (info.ret != 1) { - return; - } - - var autoJS = ''; - var areaJS = ''; - var mtJS = ''; - switch (province) { - case 'ÉϺ£': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sh.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/14_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shanghai.js'; - break; - - case 'ËÄ´¨': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sc.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/12_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/sichuan.js'; - break; - - case 'ºÓÄÏ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/henan.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/1_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/henan.js'; - break; - - case '¹ã¶«': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/gd.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/1031/26.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/guangdong.js'; - if (city == 'Ö麣' || desc == 'Zhuhai') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/zhuhai.js'; } - if (city == 'ÉîÛÚ' || desc == 'Shenzhen') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/shenzhen.js'; } - break; - - case '¸£½¨': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/fj.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/7_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/fujian.js'; - if (city == 'ÏÃÃÅ' || desc == 'Xiamen' || city == 'ÕÄÖÝ' || desc == 'Zhangzhou' || city == 'ȪÖÝ' || desc == 'Quanzhou') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/fj_mn.js'; } - break; - - case 'Õã½­': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/zj.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/4_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/zhejiang.js'; - if (city == 'Äþ²¨' || desc == 'Ningbo') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/zj_nb.js'; } - break; - - case 'ÖØÇì': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/cq.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/11_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/chongqing.js'; - break; - - case 'ºþÄÏ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hunan.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/10_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hunan.js'; - break; - - case 'ºþ±±': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hb.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/9_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hubei.js'; - break; - - case 'ÉÂÎ÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sx.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/13_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shannxi.js'; - break; - - case 'ÁÉÄþ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/ln.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/3_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/liaoning.js'; - if (city == '´óÁ¬' || desc == 'Dalian') - { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/ln_dl.js'; } - break; - - case 'ºÚÁú½­': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hlj.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/5_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/heilongjiang.js'; - break; - - case '°²»Õ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/ah.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/8_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/anhui.js'; - break; - - case 'ºÓ±±': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hebei.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/6_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hebei.js'; - break; - - case '½­ËÕ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jiangsu.js'; - autoJS = 'http://auto.sina.com.cn/867/2012/1217/2_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/jiangsu.js'; - if (city == 'ÎÞÎý') { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jiangsu_wx.js'; } - if (city == 'ËÕÖÝ') { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sz.js'; } - break; - - case 'Ìì½ò': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/tj.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/15_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/tianjin.js'; - break; - - case 'ɽÎ÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/shanxi.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/16_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shanxi.js'; - break; - - case '¼ªÁÖ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jl.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/19_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/jilin.js'; - break; - - case '½­Î÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/jx.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/17_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/jiangxi.js'; - break; - - case 'º£ÄÏ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/hainan.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/18_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/hainan.js'; - break; - - case 'ɽ¶«': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/sd.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0105/20_1.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/shandong.js'; - if (city == 'Çൺ') { areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/qd.js'; } - break; - - case '¹ãÎ÷': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/gx.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0528/22.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/guangxi.js'; - break; - - case 'ÔÆÄÏ': - autoJS = 'http://auto.sina.com.cn/867/2013/0528/23.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/yunnan.js'; - break; - - case '¹óÖÝ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/gz.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/0528/24.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/guizhou.js'; - break; - - case '¸ÊËà': - autoJS = 'http://auto.sina.com.cn/867/2013/0528/25.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/gansu.js'; - break; - - case 'н®': - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/xinjiang.js'; - break; - - case 'ÄÚÃɹÅ': - areaJS = 'http://www.sina.com.cn/js/67/sinaindex/2013/nmg.js'; - autoJS = 'http://auto.sina.com.cn/867/2013/1126/27.js'; - mtJS = 'http://www.sina.com.cn/js/135/2013/ipmt/neimenggu.js'; - break; - - default: - //autoJS = ''; - //areaJS = ''; - break; - } - // Æû³µip¶¨Ïò - if(autoJS){ - jsLoader({ - url : autoJS - }); - } - //µØ·½Õ¾ip¶¨Ïò - if(areaJS){ - jsLoader({ - url : areaJS - }); - } - //ýÍØip¶¨Ïò - if(mtJS){ - jsLoader({ - url : mtJS - }); - } - }; - - jsLoader({ - name: 'shm', - callback: function() { - SHM.home.iplookup.load(function(info, city) { - handle(info, city); - }); - } - }); - - //MT ip¶¨Ïò -/* - jsLoader({ - name: 'ipMT', - url:'http://www.sina.com.cn/js/67/index2013/ipMT.js' - }); -*/ - - })(); - -//·¿²úip¶¨Ïò -;(function(){ - var API = 'http://ip.house.sina.com.cn/sina_sanshou_2010.php'; - var render = function() { - for (var i = 0, len = SI_IP_House_.length; i < len; i++) { - var item = SI_IP_House_[i]; - var node = document.getElementById('SI_IP_House_'+i); - if (item&&node) { - node.innerHTML = item; - } - } - }; - jsLoader({ - name: 'ipHouse', - url:API, - callback: function() { - render(); - } - }); -})(); - - </script> - <!-- ¼ì²éµØÓò end --> - - <!-- ²Æ¾­°å¿éµ÷ÓÃjs begin --> - <script type="text/javascript"> - ;(function(){ - var render = function(id,html){ - var wrap = document.getElementById(id); - if(wrap){ - wrap.innerHTML = html; - } - }; - jsLoader({ - name : 'financeHQ', - url : 'http://hq.sinajs.cn/list=s_sh000001,s_sh000011', - callback : function(){ - var amtHQ = parseFloat( hq_str_s_sh000001.split(",")[1] ), - rateHQ = parseFloat( hq_str_s_sh000001.split(",")[3] ); - - render('SI_Text_sh600001', - "»¦ " + amtHQ.toFixed(1) + "(" + ( rateHQ > 0 ? "+" : ( rateHQ == 0 ? "" : "" ) ) + rateHQ.toFixed(1) + "%)" - ); - render('SI_Text_sh600011', - "ÉÏ»ù " + hq_str_s_sh000011.split(",")[1] - ); - } - }); - })(); - - </script> - <!-- ²Æ¾­°å¿éµ÷ÓÃjs end --> - -<!--_SINA_ADS_BEGIN_--> -<!-- ¿ØÖƽű¾¶¥ ÇëÎðÐ޸ĻòÒƶ¯ --> -<script language="javascript" type="text/javascript">function ADFunc(sFuncName){this.sFuncName = sFuncName;};function ADFuncSeq(){this.aryFunc = new Array();this.push = function(sFuncName){try{this.aryFunc.push(new ADFunc(sFuncName));}catch(e){}};this.shift = function(){try{return this.aryFunc.shift();}catch(e){}};};var arryADSeq = new ADFuncSeq();function nextAD(){var oFunAD = arryADSeq.shift();if (oFunAD != null){try{eval(oFunAD.sFuncName);}catch(e){}}};</script> -<!-- ¿ØÖƽű¾¶¥ ÇëÎðÐ޸ĻòÒƶ¯--> - -<!--¼ÓÔØÈ«ÆÁ begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000000001" data-ad-type="fullscreen"></ins><script>var FullScreenData=new Array();(sinaads = window.sinaads || []).push({});</script> -<!--¼ÓÔØÈ«ÆÁ end--> - -<!--¼ÓÔØÁ÷ýÌå begin--> -<span id="SteamMediaWrap"></span> -<ins class="sinaads" data-ad-pdps="PDPS000000002520" data-ad-type="stream"></ins><script>var SteamMediaData=new Array();(sinaads = window.sinaads || []).push({});</script> -<!--¼ÓÔØÁ÷ýÌå end--> - -<!--ϲ±¨ begin--> -<script> - function Schedule(e){e="string"==typeof e?[e]:e||[],this.ranges=[];var t,n=0,r=e.length,i,s,o=new Date,u=o.getFullYear()+"/"+(o.getMonth()+1)+"/"+o.getDate();for(;n<r;n++)t=e[n].replace(/\-/g,"/").split("~"),i=t[0],s=t[1]?t[1]:t[0],i.indexOf(":")===-1&&(i+=" 0:0:0"),s.indexOf(":")===-1&&(s+=" 0:0:0"),i.indexOf("/")===-1&&(i=u+" "+i),s.indexOf("/")===-1&&(s=u+" "+s),i=+this.parse(i),s=+this.parse(s),s<=i&&(s+=864e5),this.ranges[n]=[i,s]}Schedule.prototype={check:function(e){var t=this.ranges,n=0,r,i=t.length<=0,e=e?+this.parse(e):+(new Date);while(!i&&(r=t[n++]))i=e>=r[0]&&e<=r[1];return i},parse:function(e){var t=new RegExp("^\\d+(\\-|\\/)\\d+(\\-|\\/)\\d+$");if("string"==typeof e){if(t.test(e)||isNaN(Date.parse(e))){var n=e.split(/ |T/),r=n.length>1?n[1].split(/[^\d]/):[0,0,0],i=n[0].split(/[^\d]/);return new Date(i[0]-0,i[1]-1,i[2]-0,r[0]-0,r[1]-0,r[2]-0)}return new Date(e)}return e}} - - //618ºÅ9:00-12 ¿ØÖÆͶ·Åʱ¼ä - //if (new Schedule('2015-06-18 9:00:00~2015-06-18 12:59:59').check()) { - _sinaadsCacheData = window._sinaadsCacheData || {}; - _sinaadsCacheData['feibiao_xibao'] = { - "type" : "stream", - "content" : [ - { - "monitor":[""], - "link":[""], - "type":["js"], - "pv":[], - "src":[ - "http://rm.sina.com.cn/bj_chuanyang/tb20150618/index.js" - ] - } - ], - "size":"950*450", - "id":"feibiao_xibao" - }; - //} -</script> -<ins class="sinaads" data-ad-pdps="feibiao_xibao"></ins> -<script>(sinaads = window.sinaads || []).push({});</script> -<!--ϲ±¨ end--> - -<!--¼ÓÔØ¿çÀ¸ begin--> -<span id="CoupletMediaWrap"></span> -<ins class="sinaads" data-ad-pdps="PDPS000000006450" data-ad-type="couplet"></ins><script>var CoupletMediaData=new Array();(sinaads = window.sinaads || []).push({params:{sinaads_couple_top : 45}});</script> -<!--¼ÓÔØ¿çÀ¸ end--> - -<!--ÐÂÀËÊ×Ò³120x270ËæÆÁ¶ÔÁª begin--> -<ins class="sinaads" data-ad-pdps="PDPS000000054315" data-ad-type="float"></ins> -<script>(sinaads = window.sinaads || []).push({ - params : { - sinaads_float_show_pos: 800, //ËæÆÁ¶ÔÁª - sinaads_float_top : 46 - } -});</script> -<!--ÐÂÀËÊ×Ò³120x270ËæÆÁ¶ÔÁª end--> - -<!--ÐÂÀËÊ×Ò³¶þÂÖ²¥±³Í¶¹ã¸æ¿ªÊ¼--> -<ins class="sinaads" data-ad-pdps="PDPS000000051826" data-ad-type="bp"></ins><script>(sinaads = window.sinaads || []).push({});</script> -<!--ÐÂÀËÊ×Ò³¶þÂÖ²¥±³Í¶¹ã¸æ½áÊø--> - -<!-- CPMÊÓ´°¹ã¸æ ¿ªÊ¼ --> -<span id="videoWindowWrap"></span> -<ins class="sinaads" data-ad-pdps="PDPS000000052408" data-ad-type="videoWindow"></ins> -<script> -(sinaads = window.sinaads || []).push({ - params : { - sinaads_frequence : 60 * 10 - } -}); -</script> -<!-- CPMÊÓ´°¹ã¸æ ½áÊø --> - -<!-- ¿ØÖƽű¾Î² ÇëÎðÐ޸ĻòÒƶ¯ --> -<script type="text/javascript"> -jsLoader({ - name : 'salebottom', - url : 'http://d4.sina.com.cn/d1images/common/salebottom.js' -}); -</script> -<script type="text/javascript"> -jsLoader({ - name : 'salebottom', - callback : function(){ - try{nextAD();}catch(e){} - } -}); -</script> -<!-- ¿ØÖƽű¾Î² ÇëÎðÐ޸ĻòÒƶ¯--> -<!--_SINA_ADS_END_--> - -<!--ͨÀ¸¹ã¸æÒþ²Ø»úÖÆ--> -<script type="text/javascript"> -jsLoader({ - name: 'adNone', - url:'http://d1.sina.com.cn/d1images/common/adNone.js' -}); -</script> - -<script type="text/javascript" src="http://i1.sinaimg.cn/unipro/pub/suda_m_v629.js"></script> -<script type="text/javascript">suds_init(41,1.0000,1015,2);</script> - -<!-- body code begin --> -<script type="text/javascript"> -(function(){ - if(window.top !== window.self || window._thereIsNoRealTimeMessage){return}; - var script = document.createElement('script'); - script.setAttribute('charset', 'gb2312'); - script.src = 'http://news.sina.com.cn/js/694/2012/0830/realtime.js?ver=1.5.1'; - document.getElementsByTagName('head')[0].appendChild(script); -})(); -</script> - -<!-- SSO_UPDATECOOKIE_START --> -<script type="text/javascript">var sinaSSOManager=sinaSSOManager||{};sinaSSOManager.q=function(b){if(typeof b!="object"){return""}var a=new Array();for(key in b){a.push(key+"="+encodeURIComponent(b[key]))}return a.join("&")};sinaSSOManager.es=function(f,d,e){var c=document.getElementsByTagName("head")[0];var a=document.getElementById(f);if(a){c.removeChild(a)}var b=document.createElement("script");if(e){b.charset=e}else{b.charset="gb2312"}b.id=f;b.type="text/javascript";d+=(/\?/.test(d)?"&":"?")+"_="+(new Date()).getTime();b.src=d;c.appendChild(b)};sinaSSOManager.doCrossDomainCallBack=function(a){sinaSSOManager.crossDomainCounter++;document.getElementsByTagName("head")[0].removeChild(document.getElementById(a.scriptId))};sinaSSOManager.crossDomainCallBack=function(a){if(!a||a.retcode!=0){return false}var d=a.arrURL;var b,f;var e={callback:"sinaSSOManager.doCrossDomainCallBack"};sinaSSOManager.crossDomainCounter=0;if(d.length==0){return true}for(var c=0;c<d.length;c++){b=d[c];f="ssoscript"+c;e.scriptId=f;b=b+(/\?/.test(b)?"&":"?")+sinaSSOManager.q(e);sinaSSOManager.es(f,b)}};sinaSSOManager.updateCookieCallBack=function(c){var d="ssoCrossDomainScriptId";var a="http://login.sina.com.cn/sso/crossdomain.php";if(c.retcode==0){var e={scriptId:d,callback:"sinaSSOManager.crossDomainCallBack",action:"login",domain:"sina.com.cn"};var b=a+"?"+sinaSSOManager.q(e);sinaSSOManager.es(d,b)}else{}};sinaSSOManager.updateCookie=function(){var g=1800;var p=7200;var b="ssoLoginScript";var h=3600*24;var i="sina.com.cn";var m=1800;var l="http://login.sina.com.cn/sso/updatetgt.php";var n=null;var f=function(e){var r=null;var q=null;switch(e){case"sina.com.cn":q=sinaSSOManager.getSinaCookie();if(q){r=q.et}break;case"sina.cn":q=sinaSSOManager.getSinaCookie();if(q){r=q.et}break;case"51uc.com":q=sinaSSOManager.getSinaCookie();if(q){r=q.et}break}return r};var j=function(){try{return f(i)}catch(e){return null}};try{if(g>5){if(n!=null){clearTimeout(n)}n=setTimeout("sinaSSOManager.updateCookie()",g*1000)}var d=j();var c=(new Date()).getTime()/1000;var o={};if(d==null){o={retcode:6102}}else{if(d<c){o={retcode:6203}}else{if(d-h+m>c){o={retcode:6110}}else{if(d-c>p){o={retcode:6111}}}}}if(o.retcode!==undefined){return false}var a=l+"?callback=sinaSSOManager.updateCookieCallBack";sinaSSOManager.es(b,a)}catch(k){}return true};sinaSSOManager.updateCookie();</script> -<!-- SSO_UPDATECOOKIE_END --> - -<!-- Start Wrating --> -<script language="javascript"> -var wrUrl="//sina.wrating.com/";var wrDomain="sina.com.cn";var wratingDefaultAcc="860010-0323010000";var wratingAccArray={"history.sina.com.cn":"860010-0334010000","health.sina.com.cn":"860010-0330010000","fashion.sina.com.cn":"860010-0311010000","collection.sina.com.cn":"860010-0331010000","2014.sina.com.cn":"860010-0308160000","2012.sina.com.cn":"860010-0308150000","torch.2008.sina.com.cn":"860010-0308070000","video.sina.com.cn":"860010-0309010000","ent.sina.com.cn":"860010-0312010000","tech.sina.com.cn":"860010-0313010000","mobile.sina.com.cn":"860010-0313020000","house.sina.com.cn":"860010-0315010000","bj.house.sina.com.cn":"860010-0315020000","auto.sina.com.cn":"860010-0316010000","eladies.sina.com.cn":"860010-0317010000","woman.sina.com.cn":"860010-0317010000","games.sina.com.cn":"860010-0318010000","edu.sina.com.cn":"860010-0307010000","baby.sina.com.cn":"860010-0320010000","astro.sina.com.cn":"860010-0321020000","news.sina.com.cn":"860010-0310010000","weather.news.sina.com.cn":"860010-0310020000","mil.news.sina.com.cn":"860010-0310030000","www.sina.com.cn":"860010-0322010000","home.sina.com.cn":"860010-0322010000","sports.sina.com.cn":"860010-0308010000","shidefc.sina.com.cn":"860010-0308020000","weiqi.sina.com.cn":"860010-0308030000","f1.sina.com.cn":"860010-0308040000","golf.sina.com.cn":"860010-0308050000","2002.sina.com.cn":"860010-0308060000","2004.sina.com.cn":"860010-0308060000","2006.sina.com.cn":"860010-0308060000","2008.sina.com.cn":"860010-0308070000","yayun2002.sina.com.cn":"860010-0308060000","yayun2006.sina.com.cn":"860010-0308060000","book.sina.com.cn":"860010-0319010000","cul.book.sina.com.cn":"860010-0319020000","comic.book.sina.com.cn":"860010-0319030000","finance.sina.com.cn":"860010-0314010000","money.sina.com.cn":"860010-0314020000","yue.sina.com.cn":"860010-0324010000","www.sina.com":"860010-0322010000"};function vjTrack(){var U=1800;var T=false;var S=false;var R="";var Q="0";var P="";var N;var L;var K;var J;var I;var H="expires=Fri, 1 Jan 2038 00:00:00 GMT;";var G=0;if(document.location.protocol=="file:"){return }T=navigator.cookieEnabled?"1":"0";S=navigator.javaEnabled()?"1":"0";var F="0";var E;var C=-1;var D=document.cookie;if(T=="1"){C=D.indexOf("vjuids=");if(C<0){E=vjVisitorID();document.cookie="vjuids="+escape(E)+";"+H+";domain="+wrDomain+";path=/;";if(document.cookie.indexOf("vjuids=")<0){T="0"}else{Q="1"}}else{E=vjGetCookie("vjuids")}}L=document.referrer;if(!L||L==""){L=""}R=vjFlash();if(self.screen){N=screen.width+"x"+screen.height+"x"+screen.colorDepth}else{if(self.java){var M=java.awt.Toolkit.getDefaultToolkit();var O=M.getScreenSize();N=O.width+"x"+O.height+"x0"}}if(navigator.language){K=navigator.language.toLowerCase()}else{if(navigator.browserLanguage){K=navigator.browserLanguage.toLowerCase()}else{K="-"}}I="";var B;var X;X=new Date();J=X.getTimezoneOffset()/-60;J=X.getTimezoneOffset()/-60;B="&s="+N+"&l="+K+"&z="+J+"&j="+S+"&f="+R;if(T=="1"){C=document.cookie.indexOf("vjlast=");if(C<0){G=0}else{G=parseInt(vjGetCookie("vjlast"))}}if((X.getTime()/1000)-G>U){F="1";document.cookie="vjlast="+Math.round(X.getTime()/1000)+";"+H+";domain="+wrDomain+";path=/;"}if(L!=""){B=B+"&r="+escape(L)}if(F!="0"){B=B+"&n="+G}if(Q!="0"){B=B+"&u="+Q}var V;var A=vjGetAcc();var W=vjGetDomain();V=wrUrl+"a.gif?a="+X.getTime().toString(16)+"&t="+escape(I)+"&i="+escape(E)+"&b="+escape(document.location)+"&c="+A+B+"&ck="+W;document.write('<img src="'+V+'" width="1" height="1" style="visibility:hidden;position:absolute;left:0px;top:0px;z-index:-1" />')}function vjGetAcc(){var B=document.location.toString().toLowerCase();var C=(B.split("/"))[2];var A=wratingAccArray[C];if(typeof (A)=="undefined"){A=wratingDefaultAcc}return A}function vjFlash(){var _wr_f="-",_wr_n=navigator;if(_wr_n.plugins&&_wr_n.plugins.length){for(var ii=0;ii<_wr_n.plugins.length;ii++){if(_wr_n.plugins[ii].name.indexOf("Shockwave Flash")!=-1){_wr_f=_wr_n.plugins[ii].description.split("Shockwave Flash ")[1];break}}}else{if(window.ActiveXObject){for(var ii=10;ii>=2;ii--){try{var fl=eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+ii+"');");if(fl){_wr_f=ii+".0";break}}catch(e){}}}}return _wr_f}function vjHash(B){if(!B||B==""){return 0}var D=0;for(var C=B.length-1;C>=0;C--){var A=parseInt(B.charCodeAt(C));D=(D<<5)+D+A}return D}function vjVisitorID(){var B=vjHash(document.location+document.cookie+document.referrer).toString(16);var A;A=new Date();return B+"."+A.getTime().toString(16)+"."+Math.random().toString(16)}function vjGetCookieVal(B){var A=document.cookie.indexOf(";",B);if(A==-1){A=document.cookie.length}return unescape(document.cookie.substring(B,A))}function vjGetCookie(C){var B=C+"=";var F=B.length;var A=document.cookie.length;var E=0;while(E<A){var D=E+F;if(document.cookie.substring(E,D)==B){return vjGetCookieVal(D)}E=document.cookie.indexOf(" ",E)+1;if(E==0){break}}return null}function vjGetDomain(){var A=0;try{if(window.self.parent!=self){var D=/sina.com/i;var C=document.location.toString().toLowerCase();var B=parent.location.toString().toLowerCase();if(D.test(C)&&D.test(B)){A=1}}}catch(e){A=1}return A}vjTrack(); -</script> -<!-- End Wrating--> -<!-- body code end --> -</body> -</html> \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cacheUtil.py b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cacheUtil.py deleted file mode 100644 index 4565e9d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/cacheUtil.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -import urllib -import urllib2 -import json -class CacheUtils: - @staticmethod - def cbk(a, b, c): - '''''回调函数 - @a: å·²ç»ä¸‹è½½çš„æ•°æ®å— - @b: æ•°æ®å—çš„å¤§å° - @c: è¿œç¨‹æ–‡ä»¶çš„å¤§å° - ''' - per = 100.0 * a * b / c - if per > 100: - per = 100 - print '%.2f%%' % per - - def download(self, url, local): - urllib.urlretrieve(url, local, self.cbk) - - def cache(self, url, range): - fileName = url.split('/')[-1] - req = urllib2.Request(url) - req.add_header('Range', 'bytes=' + range) - response = urllib2.urlopen(req) - buffer = response.read() - with open("./cache/" + fileName + range, "a+") as fp: - fp.write(buffer) - - def saveReq(self, url, range): - - # Reading data back - with open('data.json', 'r') as fp: - data = json.load(fp) - data[url] = range - # Writing JSON data - with open('data.json', 'w') as fp: - json.dump(data, fp) - - - def checkReq(self, url): - # Reading data back - with open('data.json', 'r') as fp: - data = json.load(fp) - if data.get(url): - fileName = url.split('/')[-1] - with open('GotIt.txt', 'a+') as fp: - if data[url] == "None": - fp.write("./download/" + fileName + "\n") - else: - fp.write("./cache/" + fileName + " " + data[url] + "\n") - return True - else: - return False - -if __name__ == '__main__': - cacheUtils = CacheUtils() - - #url = "http://www.sina.com.cn" - #fileName = url.split('/')[-1] - #cacheUtils.download(url, "./cache/" + fileName) - - #cacheUtils.cache("http://www.baidu.com") - #cacheUtils.cache("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png", "0-7000") - #cacheUtils.cache("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png", "7001-14175") - - #cacheUtils.saveReq("http://www.sina.com.cn") - - #cacheUtils.loadReq() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/data.json b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/data.json deleted file mode 100644 index 8e364bb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/data.json +++ /dev/null @@ -1 +0,0 @@ -{"http://www.sina.com.cn": "helloworld"} \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/dd.json b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/dd.json deleted file mode 100644 index 55fe920..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/dd.json +++ /dev/null @@ -1 +0,0 @@ -{"www.baidu.com": 1000, "http://www.sina.com.cn": 4000} \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/py.txt b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/py.txt deleted file mode 100644 index d62d43a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/py.txt +++ /dev/null @@ -1,10 +0,0 @@ -test1test2test3test4test5test6test7test8test9test1 -test2 -test3 -test4 -test5 -test6 -test7 -test8 -test9 -test1test2test3test4test5test6test7test8test9 \ No newline at end of file diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/test.html b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/test.html deleted file mode 100644 index 64166dd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/test.html +++ /dev/null @@ -1,23 +0,0 @@ -<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="content-type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge"><meta content="always" name="referrer"><meta name="theme-color" content="#2932e1"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu.svg"><link rel="dns-prefetch" href="//s1.bdstatic.com"/><link rel="dns-prefetch" href="//t1.baidu.com"/><link rel="dns-prefetch" href="//t2.baidu.com"/><link rel="dns-prefetch" href="//t3.baidu.com"/><link rel="dns-prefetch" href="//t10.baidu.com"/><link rel="dns-prefetch" href="//t11.baidu.com"/><link rel="dns-prefetch" href="//t12.baidu.com"/><link rel="dns-prefetch" href="//b1.bdstatic.com"/><title>百度一下,你就知é“</title> -<style index="index" id="css_index">html,body{height:100%}html{overflow-y:auto}#wrapper{position:relative;_position:;min-height:100%}#head{padding-bottom:100px;text-align:center;*z-index:1}#ftCon{height:100px;position:absolute;bottom:44px;text-align:center;width:100%;margin:0 auto;z-index:0;overflow:hidden}#ftConw{width:720px;margin:0 auto}body{font:12px arial;text-align:;background:#fff}body,p,form,ul,li{margin:0;padding:0;list-style:none}body,form,#fm{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}.bg{background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png);background-repeat:no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif)}.bg_tuiguang_browser{width:16px;height:16px;background-position:-600px 0;display:inline-block;vertical-align:text-bottom;font-style:normal;overflow:hidden;margin-right:5px}.bg_tuiguang_browser_big{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-600px -24px} -.bg_tuiguang_weishi{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-672px -24px}.c-icon{display:inline-block;width:14px;height:14px;vertical-align:text-bottom;font-style normal;overflow:hidden;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png) no-repeat 0 0;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif)}.c-icon-triangle-down-blue{background-position:-480px -168px}.c-icon-chevron-unfold2{background-position:-504px -168px}#m{width:720px;margin:0 auto}#nv a,#nv b,.btn,#lk{font-size:14px}input{border:0;padding:0}#nv{height:19px;font-size:16px;margin:0 0 4px;text-align:left;text-indent:137px}.s_btn{width:95px;height:32px;padding-top:2px\9;font-size:14px;background-color:#ddd;background-position:0 -48px;cursor:pointer}.s_btn_h{background-position:-240px -48px}.s_btn_wr{width:97px;height:34px;display:inline-block;background-position:-120px -48px;*position:relative;z-index:0;vertical-align:top} -#lk{margin:33px 0}#lk span{font:14px "宋体"}#lh{margin:16px 0 5px}#cp,#cp a{color:#666}#cp .c-icon-icrlogo{width:14px;height:17px;display:inline-block;overflow:hidden;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_4e7241a3.png) no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d160197c.gif);background-position:-600px -96px;position:relative;top:3px}#shouji{margin-right:14px}#u{display:none}#c-tips-container{display:none}#wrapper{min-width:810px;height:100%;min-height:600px}#head{position:relative;padding-bottom:0;height:100%;min-height:600px}#head .head_wrapper{height:100%}#m{position:relative}#fm{padding-left:40px;top:-37px}#lh a{margin:0 10px}#lk{position:absolute;display:none;top:0;right:0}#nv{position:absolute;display:none;top:0;right:0}#lm{color:#666;width:100%;height:60px;margin-top:60px;line-height:15px;font-size:13px;position:absolute;top:0;left:0}#lm a{color:#666}#pad-version{line-height:40px} -.s_ipt_wr.bg,.s_btn_wr.bg,#su.bg{background-image:none}.s_btn_wr{width:auto;height:auto;border-bottom:1px solid transparent;*border-bottom:0}.s_btn{width:100px;height:36px;color:white;font-size:15px;letter-spacing:1px;background:#3385ff;border-bottom:1px solid #2d78f4;outline:medium;*border-bottom:0;-webkit-appearance:none;-webkit-border-radius:0}.s_btn.btnhover{background:#317ef3;border-bottom:1px solid #2868c8;*border-bottom:0;box-shadow:1px 1px 1px #ccc}.s_btn_h{background:#3075dc;box-shadow:inset 1px 1px 5px #2964bb;-webkit-box-shadow:inset 1px 1px 5px #2964bb;-moz-box-shadow:inset 1px 1px 5px #2964bb;-o-box-shadow:inset 1px 1px 5px #2964bb}#result_logo{display:none}#index_logo img{display:inline-block;width:270px;height:129px}#s_tab{display:none}.s_form{position:relative;top:38.2%}.s_form_wrapper{position:relative;top:-191px}.s_ipt_wr{height:34px}#head .c-icon-bear-round{display:none}#form{margin:22px auto 0;width:641px;text-align:left;z-index:100}#form .bdsug,#fm .bdsug{top:35px} -.bdsug{display:none;position:absolute;width:538px;background:#fff;border:1px solid #ccc;_overflow:hidden;box-shadow:1px 1px 3px #ededed;-webkit-box-shadow:1px 1px 3px #ededed;-moz-box-shadow:1px 1px 3px #ededed;-o-box-shadow:1px 1px 3px #ededed}.bdsug.bdsugbg ul{background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/sugbg_6a9201c2.png) 100% 100% no-repeat;background-size:100px 110px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/sugbg_d24a0811.gif)\9}.bdsug li{width:522px;color:#000;font:14px arial;line-height:25px;padding:0 8px;position:relative;cursor:default}.bdsug li.bdsug-s{background:#f0f0f0}.bdsug-store span,.bdsug-store b{color:#7a77c8}.bdsug-store-del{font-size:12px;color:#666;text-decoration:underline;position:absolute;right:8px;top:0;cursor:pointer;display:none}.bdsug-s .bdsug-store-del{display:inline-block}.bdsug-ala{display:inline-block;border-bottom:1px solid #e6e6e6}.bdsug-ala h3{line-height:14px;background:url(//www.baidu.com/img/sug_bd.png) no-repeat left center;margin:8px 0 5px 0;font-size:12px;font-weight:normal;color:#7b7b7b;padding-left:20px} -.bdsug-ala p{font-size:14px;font-weight:bold;padding-left:20px}.bdsug .bdsug-direct{width:auto;padding:0;border-bottom:1px solid #f1f1f1}.bdsug .bdsug-direct p{color:#00c;font-weight:bold;line-height:34px;padding:0 8px;cursor:pointer;white-space:nowrap;overflow:hidden}.bdsug .bdsug-direct p img{width:16px;height:16px;margin:7px 6px 9px 0;vertical-align:middle}.bdsug .bdsug-direct p span{margin-left:8px}.bdsug .bdsug-direct p i{font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;background-color:#2b99ff;display:inline;text-align:center;padding:1px 5px;*padding:2px 5px 0 5px;margin-left:8px;overflow:hidden}.bdsug .bdsug-pcDirect{color:#000;font-size:14px;line-height:30px;height:30px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip{position:absolute;right:15px;top:8px;width:55px;height:15px;display:block;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-s{background-color:#f0f0f0} -.bdsug .bdsug-pcDirect-is{color:#000;font-size:14px;line-height:22px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip-is{position:absolute;right:15px;top:3px;width:55px;height:15px;display:block;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-is-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-s .bdsug-pc-direct-tip,.bdsug .bdsug-pcDirect-is-s .bdsug-pc-direct-tip-is{background-position:0 -15px}.tools{position:absolute;right:-75px}#mHolder{width:62px;position:relative;z-index:296;display:none}#mCon{height:18px;line-height:18px;position:absolute;cursor:pointer}#mCon span{color:#00c;cursor:default;display:block;width:24px}#mCon .hw{text-decoration:underline;cursor:pointer;display:inline-block}#mCon .pinyin{display:inline-block}#mCon .c-icon-chevron-unfold2{margin-left:5px}#mMenu a{width:100%;height:100%;display:block;line-height:22px;text-indent:6px;text-decoration:none;filter:none\9}#mMenu,#user ul{box-shadow:1px 1px 2px #ccc;-moz-box-shadow:1px 1px 2px #ccc;-webkit-box-shadow:1px 1px 2px #ccc;filter:progid:DXImageTransform.Microsoft.Shadow(Strength=2,Direction=135,Color="#cccccc")\9} -#mMenu{width:56px;border:1px solid #9b9b9b;list-style:none;position:absolute;right:27px;top:28px;display:none;background:#fff}#mMenu a:hover{background:#ebebeb}#mMenu .ln{height:1px;background:#ebebeb;overflow:hidden;font-size:1px;line-height:1px;margin-top:-1px}#u1 a:link,#u1 a:visited{color:#666;text-decoration:none}#u1 a:hover,#u1 a:active{text-decoration:underline}#u1 a:active{color:#00c}#u1{z-index:2;color:white;position:absolute;right:0;top:0;margin:19px 0 5px 0;padding:0 96px 0 0}#u1 .reg{display:none}#u1 a.pf,#u1 a.pf:visited{display:inline-block;float:left;color:#333;line-height:24px;font-size:13px;margin-left:20px;overflow:hidden;text-decoration:underline}#u1 a.lb,#u1 a.lb:visited,#u1 a.username{display:inline-block;float:left;color:#333;font-size:13px;line-height:24px;margin-left:20px;text-decoration:underline}#u1 a.bri,#u1 a.bri:visited{display:inline-block;position:absolute;right:10px;width:60px;height:23px;float:left;color:white;background:#38f;line-height:24px;font-size:13px;text-align:center;overflow:hidden;border-bottom:1px solid #38f;margin-left:19px;margin-right:2px} -#u1 a.bri.brihover{display:none;text-decoration:none;color:#333;background:0;border-bottom:1px solid transparent;margin-left:19px}#u1 #lm a{color:#00c;text-decoration:underline}#u1 a.mnav,#u1 a.mnav:visited{float:left;color:#333;font-weight:bold;line-height:24px;margin-left:20px;font-size:13px;text-decoration:underline}#u1 a.pf:hover,#u1 a.lb:hover,#u1 a.mnav:hover{color:#00c}.briiconsbg{background-repeat:no-repeat;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png);background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9}.bdpfmenu{background-color:#fff;border:1px solid #d1d1d1;position:absolute;right:160px;width:68px;top:36px;margin-top:-1px;_margin-top:-3px;z-index:2;box-shadow:1px 1px 5px #d1d1d1;-webkit-box-shadow:1px 1px 5px #d1d1d1;-moz-box-shadow:1px 1px 5px #d1d1d1;-o-box-shadow:1px 1px 5px #d1d1d1}.bdpfmenu a{display:block;text-align:left;margin:0!important;padding:0 9px;line-height:26px;text-decoration:none} -#wrapper .bdpfmenu a:link,#wrapper .bdpfmenu a:visited{background:white;color:#333}#wrapper .bdpfmenu a:hover,#wrapper .bdpfmenu a:active{background:#38f;text-decoration:none;color:white}#wrapper .bdnuarrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-10px;left:50%;margin-left:-5px}#wrapper .bdnuarrow em,#wrapper .bdnuarrow i{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:5px solid transparent;border-style:dashed dashed solid dashed}#wrapper .bdnuarrow em{border-bottom-color:#d8d8d8;top:-1px}#wrapper .bdnuarrow i{border-bottom-color:#fff;top:0}.s-isindex-wrap #wrapper .bdnuarrow{height:13px;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png) no-repeat -90px -1px}#wrapper .bdnuarrow.bdbriarrow{right:104px;display:none!important}#wrapper .bdbri{width:85px;min-height:100px;border-left:1px solid #e7e7e7;position:absolute;background-color:#f9f9f9;overflow:hidden;z-index:2;right:0;top:0}#prefpanel{background:#fafafa;display:none;opacity:0;position:fixed;_position:absolute;top:-359px;z-index:1000;width:100%;min-width:960px;border-bottom:1px solid #ebebeb} -#prefpanel form{_width:850px}#wrapper .bdbriimgtitle{color:#333;text-align:center;width:66px;height:43px;line-height:43px;padding-top:9px;margin:0 auto;border-bottom:#f0f0f0 1px solid;font-size:13px;cursor:default}#wrapper .briscrollwrapper{overflow:hidden}#wrapper .briscrollwrapperContainer{position:relative}#wrapper .bdbri.bdbriimg .bdmainlink a,#wrapper .bdbri.bdbriimg .bdothlink a{display:block;text-align:center;width:66px;height:76px;margin:0 auto;border-bottom:#f0f0f0 1px solid;color:#666;text-decoration:none;overflow:hidden}#wrapper .bdbri.bdbriimg .bdmainlink a:visited,#wrapper .bdbri.bdbriimg .bdothlink a:visited{color:#666}#wrapper .bdbri.bdbriimg .bdmainlink a:hover,#wrapper .bdbri.bdbriimg .bdothlink a:hover{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdmainlink a:active,#wrapper .bdbri.bdbriimg .bdothlink a:active{color:#00c;text-decoration:underline}#wrapper .bdbri.bdbriimg span{width:36px;height:36px;display:block;margin:10px auto 5px;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/logos/bdbri_icons_737be4e5.png) no-repeat;cursor:pointer} -#wrapper .bdbri.bdbriimg .bdbrimore,#wrapper .bdbri.bdbriimg .bdbrievenmore{clear:both;text-align:center}#wrapper .bdbri.bdbriimg .bdbrievenmore{margin-top:15px;height:30px;width:85px;overflow:hidden}#wrapper .bdbri.bdbriimg span.bdbriimgitem_1{background-position:0 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_2{background-position:-36px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_3{width:40px;background-position:-72px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_4{background-position:-112px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_5{background-position:-148px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_6{background-position:-184px 0}#wrapper .bdbri.bdbriimg span.bdbriimgitem_7{background-position:-220px 0}#wrapper .bdbri.bdbriimg .bdbrievenmore a:link,#wrapper .bdbri.bdbriimg .bdbrievenmore a:visited{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdbrievenmore a:hover{color:#666;text-decoration:underline}#wrapper .bdbri.bdbriimg .bdbrievenmore a:active{color:#00c} -.bdbriscroll-ctrl-scroll{position:absolute;top:10px;right:1px;width:8px;border-top:1px solid #e4e4e4;border-left:1px solid #e4e4e4;cursor:default;-webkit-user-select:none;-moz-user-select:none}.bdbriscroll-ctrl-scroll .bdbriscroll-axis{width:8px;left:0;z-index:0;position:absolute;background:#f2f2f2}.bdbriscroll-ctrl-scroll-touch .bdbriscroll-axis{width:7px;background:#f2f2f2}.bdbriscroll-ctrl-scroll-hover .bdbriscroll-axis{background:#f2f2f2}.bdbriscroll-ctrl-scroll .bdbriscroll-slider{overflow:hidden;width:7px;height:14px;position:absolute;left:0;z-index:10;display:none;background:#d9d9d9;margin-top:-1px;margin-left:-1px;border-right:1px solid #cecece;border-bottom:1px solid #cecece;cursor:default}.bdbriscroll-ctrl-scroll-touch .bdbriscroll-slider,.bdbriscroll-ctrl-scroll-hover .bdbriscroll-slider{background:#b8b8b8;border-right:1px solid #afafaf;border-bottom:1px solid #afafaf}</style><!--[if lte IE 8]><style index="index" >#head{height:480px\9}.s_form{top:260px}</style><![endif]--><!--[if IE 8]><style index="index" >#u1 a.mnav,#u1 a.mnav:visited,#u1 a.lb,#u1 a.lb:visited,#u1 a.pf,#u1 a.pf:visited,#u1 a.bri,#u1 a.bri:visited{font-family:simsun}</style><![endif]--><style data-for="debug">#debug{display:none!important}</style><style data-for="result" id="css_index_result">#seth{display:none;behavior:url(#default#homepage)}#setf{display:none}#sekj{margin-left:14px}#st,#sekj{display:none}.s_ipt_wr{border:1px solid #b6b6b6;border-color:#7b7b7b #b6b6b6 #b6b6b6 #7b7b7b;background:#fff;display:inline-block;vertical-align:top;width:539px;margin-right:0;border-right-width:0;border-color:#b8b8b8 transparent #ccc #b8b8b8;overflow:hidden}.wrapper_s .s_ipt_wr{width:439px}.wrapper_s .s_ipt{width:434px}.wrapper_s .s_ipt_tip{width:434px}.s_ipt_wr:hover,.s_ipt_wr.ipthover{border-color:#999 transparent #b3b3b3 #999}.s_ipt_wr.iptfocus{border-color:#4791ff transparent #4791ff #4791ff}.s_ipt_tip{color:#aaa;position:absolute;z-index:-10;font:16px/22px arial;height:32px;line-height:32px;padding-left:7px;overflow:hidden;width:526px}.s_ipt{width:526px;height:22px;font:16px/18px arial;line-height:22px\9;margin:6px 0 0 7px;padding:0;background:transparent;border:0;outline:0;-webkit-appearance:none}#kw{position:relative}#u .username i{background-position:-408px -144px}.bdpfmenu,.usermenu{border:1px solid #d1d1d1;position:absolute;width:105px;top:36px;z-index:302;box-shadow:1px 1px 5px #d1d1d1;-webkit-box-shadow:1px 1px 5px #d1d1d1;-moz-box-shadow:1px 1px 5px #d1d1d1;-o-box-shadow:1px 1px 5px #d1d1d1} -.bdpfmenu{font-size:12px;background-color:#fff}.bdpfmenu a,.usermenu a{display:block;text-align:left;margin:0!important;padding:0 9px;line-height:26px;text-decoration:none}.briiconsbg{background-repeat:no-repeat;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png);background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9}#u{z-index:301;position:absolute;right:0;top:0;margin:21px 9px 5px 0;padding:0}.wrapper_s #u{margin-right:3px}#u a{text-decoration:underline;color:#333;margin:0 7px}.wrapper_s #u a{margin-right:0 6px}#u div a{text-decoration:none}#u a:hover{text-decoration:underline}#u .back_org{color:#666;float:left;display:inline-block;height:24px;line-height:24px}#u .bri{display:inline-block;width:24px;height:24px;float:left;line-height:24px;color:transparent;background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_c3b33b92.png) no-repeat 4px 3px;background-size:300px 18px;background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/icons_0a1fc6ac.gif)\9;overflow:hidden} -#u .bri:hover,#u .bri.brihover{background-position:-18px 3px}#mCon #imeSIcon{background-position:-408px -144px;margin-left:0}#mCon span{color:#333}.bdpfmenu a:link,.bdpfmenu a:visited,#u .usermenu a:link,#u .usermenu a:visited{background:white;color:#333}.bdpfmenu a:hover,.bdpfmenu a:active,#u .usermenu a:hover,#u .usermenu a:active{background:#38f;text-decoration:none;color:white}.bdpfmenu{width:70px}.usermenu{width:68px;right:8px}#wrapper .bdnuarrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-10px;left:50%;margin-left:-5px}#wrapper .bdnuarrow em,#wrapper .bdnuarrow i{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:5px solid transparent;border-style:dashed dashed solid dashed}#wrapper .bdnuarrow em{border-bottom-color:#d8d8d8;top:-1px}#wrapper .bdnuarrow i{border-bottom-color:#fff;top:0}#prefpanel{background:#fafafa;display:none;opacity:0;position:fixed;_position:absolute;top:-359px;z-index:500;width:100%;min-width:960px;border-bottom:1px solid #ebebeb} -#prefpanel form{_width:850px}#kw_tip{cursor:default;display:none;margin-top:1px}#bds-message-wrapper{top:43px}.quickdelete-wrap{position:relative}.quickdelete-wrap input{width:500px}.wrapper_l .quickdelete-wrap input{width:500px}.wrapper_s .quickdelete-wrap input{width:402px}input::-ms-clear{display:none}.quickdelete{width:32px;height:32px;background:url(http://s1.bdstatic.com/r/www/cache/static/global/img/quickdelete_9c14b01a.png) no-repeat;background-position:10px 10px;position:absolute;display:block}.quickdelete:hover{background-position:10px -24px}</style><script >function h(obj){obj.style.behavior='url(#default#homepage)';var a = obj.setHomePage('//www.baidu.com/');}</script><noscript><meta http-equiv="refresh" content="0; url=/baidu.html?from=noscript"/></noscript><script>window._ASYNC_START=new Date().getTime();</script></head><body link="#0000cc"><script>if (/Chrome\/37.0.2062.94/i.test(navigator.userAgent) && (/(windows 7)|(windows nt 6.1)/i.test(navigator.userAgent))) {var _chrome_37_fix = document.createElement("style"); _chrome_37_fix.type="text/css";_chrome_37_fix.setAttribute("data-for","result");_chrome_37_fix.innerHTML = ".t,.f16,#kw,.s_ipt,.c-title,.c-title-size,.to_zhidao,.to_tieba,.to_zhidao_bottom{font-size:15px;} .ec-hospital-info-main h2,.ad-widget-gx_sck-ylzx-doctor-info h2,.ec-card-main h2,.ad-widget-h1 h2,.ad-widget-title h2,.ad-widget-small-head h2,.ad-widget-small-head h2 a,.ad-widget-header .ec-figcaption h2{font-size: 15px !important;}";document.getElementsByTagName("head")[0].appendChild(_chrome_37_fix); }</script><div id="wrapper" style="display:none;"><script>if(window.bds&&bds.util&&bds.util.setContainerWidth){bds.util.setContainerWidth();}</script><div id="head"><div class="head_wrapper"><div class="s_form"><div class="s_form_wrapper"><div id="lg"><img hidefocus="true" src="//www.baidu.com/img/bd_logo1.png" width="270" height="129"></div><a href="/" id="result_logo" onmousedown="return c({'fm':'tab','tab':'logo'})"><img src="//www.baidu.com/img/baidu_jgylogo3.gif" alt="到百度首页" title="到百度首页"></a><form id="form" name="f" action="/s" class="fm"><input type="hidden" name="ie" value="utf-8"><input type="hidden" name="f" value="8"><input type="hidden" name="rsv_bp" value="1"><input type="hidden" name="rsv_idx" value="1"><input type=hidden name=ch value=""><input type=hidden name=tn value="baidu"><input type=hidden name=bar value=""><span class="bg s_ipt_wr"><input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off"></span><span class="bg s_btn_wr"><input type="submit" id="su" value="百度一下" class="bg s_btn"></span><span class="tools"><span id="mHolder"><div id="mCon"><span>输入法</span></div><ul id="mMenu"><li><a href="javascript:;" name="ime_hw">手写</a></li><li><a href="javascript:;" name="ime_py">拼音</a></li><li class="ln"></li><li><a href="javascript:;" name="ime_cl">关闭</a></li></ul></span></span><input type="hidden" name="rn" value=""><input type="hidden" name="rsv_pq" value="aaa8f1e10001a749"><input type="hidden" name="rsv_t" value="2553MAdK/XmtnVTsiU4Y5zlMC24Y6wP96QSkWAZ/aOi6cn+RITELOkpew0o"></form><div id="m"></div></div></div><div id="u"><a class="toindex" href="/">百度首页</a><a href="javascript:;" name="tj_settingicon" class="pf">设置<i class="c-icon c-icon-triangle-down"></i></a><a href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F" name="tj_login" class="lb" onclick="return false;">登录</a></div><div id="u1"><a href="http://news.baidu.com" name="tj_trnews" class="mnav">æ–°é—»</a><a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a><a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a><a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a><a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">è´´å§</a><a href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F" name="tj_login" class="lb" onclick="return false;">登录</a><a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf" class="">设置</a><a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产å“</a></div></div></div><div class="s_tab" id="s_tab"><b>网页</b><a href="http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'news'})">æ–°é—»</a><a href="http://tieba.baidu.com/f?kw=&fr=wwwt" wdfield="kw" onmousedown="return c({'fm':'tab','tab':'tieba'})">è´´å§</a><a href="http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=&fr=wwwt" wdfield="word" onmousedown="return c({'fm':'tab','tab':'zhidao'})">知é“</a><a href="http://music.baidu.com/search?fr=ps&ie=utf-8&key=" wdfield="key" onmousedown="return c({'fm':'tab','tab':'music'})">音ä¹</a><a href="http://image.baidu.com/i?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'pic'})">图片</a><a href="http://v.baidu.com/v?ct=301989888&rn=20&pn=0&db=0&s=25&ie=utf-8&word=" wdfield="word" onmousedown="return c({'fm':'tab','tab':'video'})">视频</a><a href="http://map.baidu.com/m?word=&fr=ps01000" wdfield="word" onmousedown="return c({'fm':'tab','tab':'map'})">地图</a><a href="http://wenku.baidu.com/search?word=&lm=0&od=0&ie=utf-8" wdfield="word" onmousedown="return c({'fm':'tab','tab':'wenku'})">文库</a><a href="//www.baidu.com/more/" onmousedown="return c({'fm':'tab','tab':'more'})">更多»</a></div><div id="ftCon"><div id="ftConw"><p id="lh"><a id="seth" onClick="h(this)" href="/" onmousedown="return ns_c({'fm':'behs','tab':'homepage','pos':0})">把百度设为主页</a><a id="setf" href="//www.baidu.com/cache/sethelp/help.html" onmousedown="return ns_c({'fm':'behs','tab':'favorites','pos':0})" target="_blank">把百度设为主页</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about'})" href="http://home.baidu.com">关于百度</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about_en'})" href="http://ir.baidu.com">About&nbsp;&nbsp;Baidu</a></p><p id="cp">&copy;2015&nbsp;Baidu&nbsp;<a href="http://www.baidu.com/duty/" onmousedown="return ns_c({'fm':'behs','tab':'tj_duty'})">使用百度å‰å¿…读</a>&nbsp;<a href="http://jianyi.baidu.com/" class="cp-feedback" onmousedown="return ns_c({'fm':'behs','tab':'tj_homefb'})">æ„è§å馈</a>&nbsp;京ICPè¯030173å·&nbsp;<i class="c-icon-icrlogo"></i></p></div></div><div id="wrapper_wrapper"></div></div><div class="c-tips-container" id="c-tips-container"></div><script>window.__async_strategy=2;</script><script>var bds={se:{},su:{urdata:[],urSendClick:function(){}},util:{},use:{},comm : {domain:"http://www.baidu.com",ubsurl : "http://sclick.baidu.com/w.gif",tn:"baidu",queryEnc:"",queryId:"",inter:"",templateName:"baidu",sugHost : "http://suggestion.baidu.com/su",query : "",qid : "aaa8f1e10001a749",cid : "0",sid : "14345_14593_1436_12658_14509_14444_12825_10812_12868_14622_13202_14870_12722_14626_14484_14920_14903_12397_10633",indexSid : "14345_14593_1436_12658_14509_14444_12825_10812_12868_14622_13202_14870_12722_14626_14484_14920_14903_12397_10633",stoken : "",serverTime : "1434531241",user : "",username : "",userid : "0",isBaixiaoduOn : "",loginAction : [],useFavo : "",pinyin : "",favoOn : "",cookie : {"BD_HOME":"0","BDSVRTM":"0","BAIDUID":"DA81113FF941F71891CB8DBA8CF86D3D:FG=1","BAIDUPSID":"DA81113FF941F71891CB8DBA8CF86D3D","BIDUPSID":"DA81113FF941F71891CB8DBA8CF86D3D","H_PS_PSSID":"14345_14593_1436_12658_14509_14444_12825_10812_12868_14622_13202_14870_12722_14626_14484_14920_14903_12397_10633","PSTM":"1432694482"},curResultNum:"0",rightResultExist:false,protectNum:0,zxlNum:0,pageNum:1,pageSize:10,newindex:0,async:2,maxPreloadThread:5,maxPreloadTimes:10,preloadMouseMoveDistance:5,switchAddMask:false,isDebug:false,ishome : 1,flagTranslateResult:0,globalLogFlag:0,encTn:'2553MAdK/XmtnVTsiU4Y5zlMC24Y6wP96QSkWAZ/aOi6cn+RITELOkpew0o'}};var name,navigate,al_arr=[];var selfOpen = window.open;eval("var open = selfOpen;");var isIE=navigator.userAgent.indexOf("MSIE")!=-1&&!window.opera;var E = bds.ecom= {};bds.se.mon = {'loadedItems':[],'load':function(){},'srvt':-1};try {bds.se.mon.srvt = parseInt(document.cookie.match(new RegExp("(^| )BDSVRTM=([^;]*)(;|$)"))[2]);document.cookie="BDSVRTM=;expires=Sat, 01 Jan 2000 00:00:00 GMT"; }catch(e){}var bdUser = bds.comm.user?bds.comm.user:null,bdQuery = bds.comm.query,bdUseFavo = bds.comm.useFavo,bdFavoOn = bds.comm.favoOn,bdCid = bds.comm.cid,bdSid = bds.comm.sid,bdServerTime = bds.comm.serverTime,bdQid = bds.comm.queryId,bdstoken = bds.comm.stoken,login_success = [];bds.util.domain = (function(){var list = {"vse.baidu.com":"http://vse.baidu.com","hdpreload.baidu.com":"http://hdpreload.baidu.com","lcr.open.baidu.com":"http://lcr.open.baidu.com","kankan.baidu.com":"http://kankan.baidu.com","xapp.baidu.com":"http://xapp.baidu.com","dr.dh.baidu.com":"http://dr.dh.baidu.com","xiaodu.baidu.com":"http://xiaodu.baidu.com","s1.bdstatic.com":"http://s1.bdstatic.com","olime.baidu.com":"http://olime.baidu.com","app.baidu.com":"http://app.baidu.com","i.baidu.com":"http://i.baidu.com","c.baidu.com":"http://c.baidu.com","sclick.baidu.com":"http://sclick.baidu.com","nsclick.baidu.com":"http://nsclick.baidu.com","eclick.baidu.com":"http://eclick.baidu.com","api.map.baidu.com":"http://api.map.baidu.com","ecma.bdimg.com":"http://ecma.bdimg.com","t10.baidu.com":"http://t10.baidu.com","t11.baidu.com":"http://t11.baidu.com","t12.baidu.com":"http://t12.baidu.com","i7.baidu.com":"http://i7.baidu.com","i8.baidu.com":"http://i8.baidu.com","i9.baidu.com":"http://i9.baidu.com","b1.bdstatic.com":"http://b1.bdstatic.com","ss.bdimg.com":"http://ss.bdimg.com","opendata.baidu.com":"http://opendata.baidu.com","api.open.baidu.com":"http://api.open.baidu.com","tag.baidu.com":"http://tag.baidu.com","f3.baidu.com":"http://f3.baidu.com","s.share.baidu.com":"http://s.share.baidu.com","bdimg.share.baidu.com":"http://bdimg.share.baidu.com"};var get = function(url) {if(location.protocol === "http") {return url;}var reg = /^(http[s]?:\/\/)?([^\/]+)(.*)/,matches = url.match(reg);url = list.hasOwnProperty(matches[2])&&(list[matches[2]] + matches[3]) || url;return url;},set = function(kdomain,vdomain) {list[kdomain] = vdomain;}; return {get : get,set : set}})();</script><script>if(!location.hash.match(/[^a-zA-Z0-9]wd=/)){document.getElementById("wrapper").style.display='block';setTimeout(function(){try{var kw=document.getElementById("kw");kw.focus();kw.parentNode.className="bg s_ipt_wr iptfocus quickdelete-wrap";}catch(e){}},0);}</script><script type="text/javascript" src="http://s1.bdstatic.com/r/www/cache/static/jquery/jquery-1.10.2.min_f2fb5194.js"></script><script>(function(){var result_common_css="<style data-for=\"result\" id=\"css_result\">body{color:#333;background:#fff;padding:6px 0 0;margin:0;position:relative;min-width:900px}body,th,td,.p1,.p2{font-family:arial}p,form,ol,ul,li,dl,dt,dd,h3{margin:0;padding:0;list-style:none}input{padding-top:0;padding-bottom:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}table,img{border:0}td{font-size:9pt;line-height:18px}em{font-style:normal;color:#c00}a em{text-decoration:underline}cite{font-style:normal;color:#008000}.m,a.m{color:#666}a.m:visited{color:#606}.g,a.g{color:#008000}.c{color:#77c}.f14{font-size:14px}.f10{font-size:10.5pt}.f16{font-size:16px}.f13{font-size:13px}.bg{background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_4e7241a3.png);background-repeat:no-repeat;_background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_d160197c.gif);background-repeat:no-repeat}.bg_tuiguang_browser{width:16px;height:16px;background-position:-600px 0;display:inline-block;vertical-align:text-bottom;font-style:normal;overflow:hidden;margin-right:5px}.bg_tuiguang_browser_big{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-600px -24px}.bg_tuiguang_weishi{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-672px -24px}#u,#head,#tool,#search,#foot{font-size:12px}.logo{width:117px;height:38px;cursor:pointer}.p1{line-height:120%;margin-left:-12pt}.p2{width:100%;line-height:120%;margin-left:-12pt}#wrapper{_zoom:1}#container{word-break:break-all;word-wrap:break-word}.container_s{width:1002px}.container_l{width:1222px}#content_left{width:636px;float:left;padding-left:35px}#content_right{border-left:1px solid #e1e1e1;float:right}.container_s #content_right{width:271px}.container_l #content_right{width:434px}.content_none{padding-left:35px}#u{color:#999;white-space:nowrap;position:absolute;right:10px;top:4px;z-index:299}#u a{color:#00c;margin:0 5px}#u .reg{margin:0}#u .last{margin-right:0}#u .un{font-weight:bold;margin-right:5px}#u ul{width:100%;background:#fff;border:1px solid #9b9b9b}#u li{height:25px}#u li a{width:100%;height:25px;line-height:25px;display:block;text-align:left;text-decoration:none;text-indent:6px;margin:0;filter:none\\9}#u li a:hover{background:#ebebeb}#u li.nl{border-top:1px solid #ebebeb}#user{display:inline-block}#user_center{position:relative;display:inline-block}#user_center .user_center_btn{margin-right:5px}.userMenu{width:64px;position:absolute;right:7px;_right:2px;top:15px;top:14px\\9;*top:15px;padding-top:4px;display:none;*background:#fff}#head{padding-left:35px;margin-bottom:20px;width:900px}.fm{clear:both;position:relative;z-index:297}.nv a,.nv b,.btn,#page,#more{font-size:14px}.s_nav{height:45px}.s_nav .s_logo{margin-right:20px;float:left}.s_nav .s_logo img{border:0;display:block}.s_tab{line-height:18px;padding:20px 0 0;float:left}.s_nav a{color:#00c;font-size:14px}.s_nav b{font-size:14px}.s_ipt_wr{width:536px;height:30px;display:inline-block;margin-right:5px;background-position:0 -96px;border:1px solid #b6b6b6;border-color:#7b7b7b #b6b6b6 #b6b6b6 #7b7b7b;vertical-align:top}.s_ipt{width:523px;height:22px;font:16px\/18px arial;line-height:22px\\9;margin:5px 0 0 7px;padding:0;background:#fff;border:0;outline:0;-webkit-appearance:none}.s_btn{width:95px;height:32px;padding-top:2px\\9;font-size:14px;padding:0;background-color:#ddd;background-position:0 -48px;border:0;cursor:pointer}.s_btn_h{background-position:-240px -48px}.s_btn_wr{width:97px;height:34px;display:inline-block;background-position:-120px -48px;*position:relative;z-index:0;vertical-align:top}.sethf{padding:0;margin:0;font-size:14px}.set_h{display:none;behavior:url(#default#homepage)}.set_f{display:none}.shouji{margin-left:19px}.shouji a{text-decoration:none}#head .bdsug{top:33px}#search form{position:relative}#search form .bdsug{bottom:33px}.bdsug{display:none;position:absolute;z-index:1;width:538px;background:#fff;border:1px solid #ccc;_overflow:hidden;box-shadow:1px 1px 3px #ededed;-webkit-box-shadow:1px 1px 3px #ededed;-moz-box-shadow:1px 1px 3px #ededed;-o-box-shadow:1px 1px 3px #ededed}.bdsug.bdsugbg ul{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/home\/img\/sugbg_6a9201c2.png) 100% 100% no-repeat;background-size:100px 110px;background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/home\/img\/sugbg_d24a0811.gif)\\9}.bdsug li{width:522px;color:#000;font:14px arial;line-height:22px;padding:0 8px;position:relative;cursor:default}.bdsug li.bdsug-s{background:#f0f0f0}.bdsug-store span,.bdsug-store b{color:#7a77c8}.bdsug-store-del{font-size:12px;color:#666;text-decoration:underline;position:absolute;right:8px;top:0;cursor:pointer;display:none}.bdsug-s .bdsug-store-del{display:inline-block}.bdsug-ala{display:inline-block;border-bottom:1px solid #e6e6e6}.bdsug-ala h3{line-height:14px;background:url(\/\/www.baidu.com\/img\/sug_bd.png) no-repeat left center;margin:8px 0 5px 0;font-size:12px;font-weight:normal;color:#7b7b7b;padding-left:20px}.bdsug-ala p{font-size:14px;font-weight:bold;padding-left:20px}.bdsug .bdsug-direct{width:auto;padding:0;border-bottom:1px solid #f1f1f1}.bdsug .bdsug-direct p{color:#00c;font-weight:bold;line-height:34px;padding:0 8px;cursor:pointer;white-space:nowrap;overflow:hidden}.bdsug .bdsug-direct p img{width:16px;height:16px;margin:7px 6px 9px 0;vertical-align:middle}.bdsug .bdsug-direct p span{margin-left:8px}.bdsug .bdsug-direct p i{font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;background-color:#2b99ff;display:inline;text-align:center;padding:1px 5px;*padding:2px 5px 0 5px;margin-left:8px;overflow:hidden}.bdsug .bdsug-pcDirect{color:#000;font-size:14px;line-height:30px;height:30px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip{position:absolute;right:15px;top:8px;width:55px;height:15px;display:block;background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-is{color:#000;font-size:14px;line-height:22px;background-color:#f8f8f8}.bdsug .bdsug-pc-direct-tip-is{position:absolute;right:15px;top:3px;width:55px;height:15px;display:block;background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/pc_direct_ffda303e.png) no-repeat 0 0}.bdsug li.bdsug-pcDirect-is-s{background-color:#f0f0f0}.bdsug .bdsug-pcDirect-s .bdsug-pc-direct-tip,.bdsug .bdsug-pcDirect-is-s .bdsug-pc-direct-tip-is{background-position:0 -15px}#tb_mr{color:#00c;cursor:pointer;position:relative;z-index:298}#tb_mr b{font-weight:normal;text-decoration:underline}#tb_mr small{font-size:11px}#page{font:14px arial;white-space:nowrap;padding-left:35px}#page a,#page strong{display:inline-block;vertical-align:text-bottom;height:66px;text-align:center;line-height:34px;text-decoration:none;overflow:hidden;margin-right:9px;background:white}#page a{cursor:pointer}#page a:hover{background:0}#page .n:hover,#page a:hover .pc{background:#f2f8ff;border:1px solid #38f}#page .n{height:34px;padding:0 18px;border:1px solid #e1e2e3}#page span{display:block}#page .pc{width:34px;height:34px;border:1px solid #e1e2e3;cursor:pointer}#page .fk{width:24px;height:24px;margin-bottom:6px;margin-left:6px;cursor:pointer}#page strong .fk,#page strong .pc{cursor:auto}#page .fk .c-icon-bear-pn{top:-3px;position:relative}#page .fkd .c-icon-bear-pn{top:3px;position:relative}#page .fk_cur .c-icon-bear-p{top:-2px;position:relative}#page strong .pc{border:0;width:36px;height:36px;line-height:36px}#page .nums{display:inline-block;vertical-align:text-bottom;height:36px;line-height:36px;margin-left:10px}#rs{width:900px;background:#fff;padding:8px 0;margin:20px 0 0 15px}#rs td{width:5%}#rs th{font-size:14px;font-weight:normal;line-height:19px;white-space:nowrap;text-align:left;vertical-align:top}#rs .tt{font-weight:bold;padding:0 10px 0 20px}#rs_top{font-size:14px;margin-bottom:22px}#rs_top a{margin-right:18px}#container .rs{margin:30px 0 20px 0;padding:5px 0 15px 0;font-size:14px;width:540px;padding-left:121px;position:relative;background-color:#fafafa}#container .noback{background-color:#fff}#content_left .rs{margin-left:-121px}#container .rs table{width:540px}#container .rs td{width:5px}#container .rs th{font-size:14px;font-weight:normal;white-space:nowrap;text-align:left;vertical-align:top;width:175px;line-height:22px}#container .rs .tt{font-weight:bold;padding:0 10px 0 20px;padding:0;line-height:30px;font-size:16px}#container .rs a{margin:0;height:24px;width:173px;display:inline-block;line-height:25px;border:1px solid #ebebeb;text-align:center;vertical-align:middle;overflow:hidden;outline:0;color:#333;background-color:#fff;text-decoration:none}#container .rs a:hover{border-color:#388bff}.c-tip-con .c-tip-menu-b ul{width:100px}.c-tip-con .c-tip-menu-b ul{text-align:center}.c-tip-con .c-tip-menu-b li a{display:block;text-decoration:none;cursor:pointer;background-color:#fff;padding:3px 0;color:#666}.c-tip-con .c-tip-menu-b li a:hover{display:block;background-color:#ebebeb}#search{width:900px;padding:35px 0 16px 35px}#search .s_help{position:relative;top:10px}#foot{height:20px;line-height:20px;color:#77c;background:#e6e6e6;text-align:center}#foot span{color:#666}.site_tip{font-size:12px;margin-bottom:20px}.site_tip_icon{width:56px;height:56px;background:url(\/\/www.baidu.com\/aladdin\/img\/tools\/tools-3.png) -288px 0 no-repeat}.to_zhidao,.to_tieba,.to_zhidao_bottom{font-size:16px;line-height:24px;margin:20px 0 0 35px}.to_tieba .c-icon-tieba{float:left}.f{line-height:115%;*line-height:120%;font-size:100%;width:33.7em;word-break:break-all;word-wrap:break-word}.h{margin-left:8px;width:100%}.r{word-break:break-all;cursor:hand;width:238px}.t{font-weight:normal;font-size:medium;margin-bottom:1px}.pl{padding-left:3px;height:8px;padding-right:2px;font-size:14px}.mo,a.mo:link,a.mo:visited{color:#666;font-size:100%;line-height:10px}.htb{margin-bottom:5px}.jc a{color:#c00}a font[size=\"3\"] font,font[size=\"3\"] a font{text-decoration:underline}div.blog,div.bbs{color:#707070;padding-top:2px;font-size:13px}.result{width:33.7em;table-layout:fixed}.result-op .f{word-wrap:normal}.nums{font-size:12px;color:#999}.tools{position:absolute;top:10px;white-space:nowrap}#mHolder{width:62px;position:relative;z-index:296;top:-18px;margin-left:9px;margin-right:-12px;display:none}#mCon{height:18px;position:absolute;top:3px;top:6px\\9;cursor:pointer;line-height:18px}.wrapper_l #mCon{right:7px}#mCon span{color:#00c;cursor:default;display:block}#mCon .hw{text-decoration:underline;cursor:pointer;display:inline-block}#mCon .pinyin{display:inline-block}#mCon .c-icon-chevron-unfold2{margin-left:5px}#mMenu{width:56px;border:1px solid #9b9b9b;position:absolute;right:7px;top:23px;display:none;background:#fff}#mMenu a{width:100%;height:100%;color:#00c;display:block;line-height:22px;text-indent:6px;text-decoration:none;filter:none\\9}#mMenu a:hover{background:#ebebeb}#mMenu .ln{height:1px;background:#ebebeb;overflow:hidden;font-size:1px;line-height:1px;margin-top:-1px}.op_LAMP{background:url(\"\/cache\/global\/img\/aladdinIcon-1.0.gif\") no-repeat 0 2px;color:#77C;display:inline-block;font-size:13px;height:12px;*height:14px;width:16px;text-decoration:none;zoom:1}.EC_mr15{margin-left:0}.pd15{padding-left:0}.map_1{width:30em;font-size:80%;line-height:145%}.map_2{width:25em;font-size:80%;line-height:145%}.favurl{background-repeat:no-repeat;background-position:0 1px;padding-left:20px}.dan_tip{font-size:12px;margin-top:4px}.dan_tip a{color:#b95b07}#more,#u ul,#mMenu,.msg_holder{box-shadow:1px 1px 2px #ccc;-moz-box-shadow:1px 1px 2px #ccc;-webkit-box-shadow:1px 1px 2px #ccc;filter:progid:DXImageTransform.Microsoft.Shadow(Strength=2,Direction=135,Color=\"#cccccc\")\\9}.hit_top{line-height:18px;margin:0 15px 10px 0;width:516px}.hit_top .c-icon-bear{height:18px;margin-right:4px}#rs_top_new,.hit_top_new{width:538px;font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all;margin:0 0 14px 0}.zhannei-si{margin:0 0 10px 121px}.zhannei-si-none{margin:10px 0 -10px 121px}.zhannei-search{margin:10px 0 0 121px;color:#999;font-size:14px}.f a font[size=\"3\"] font,.f font[size=\"-1\"] a font{text-decoration:underline}h3 a font{text-decoration:underline}.c-title{font-weight:normal;font-size:16px}.c-title-size{font-size:16px}.c-abstract{font-size:13px}.c-abstract-size{font-size:13px}.c-showurl{color:#008000;font-size:13px}.c-showurl-color{color:#008000}.c-cache-color{color:#666}.c-lightblue{color:#77C}.c-highlight-color{color:#C00}.c-clearfix:after{content:\".\";display:block;height:0;clear:both;visibility:hidden}.c-clearfix{zoom:1}.c-wrap{word-break:break-all;word-wrap:break-word}.c-icons-outer{overflow:hidden;display:inline-block;vertical-align:bottom;*vertical-align:-1px;_vertical-align:bottom}.c-icons-inner{margin-left:-4px}.c-container table.result,.c-container table.result-op{width:100%}.c-container td.f{font-size:13px;line-height:1.54;width:auto}.c-container .vd_newest_main{width:auto}.c-customicon{display:inline-block;width:16px;height:16px;vertical-align:text-bottom;font-style:normal;overflow:hidden}.c-tip-icon i{display:inline-block;cursor:pointer}.c-tip-con{position:absolute;z-index:1;top:22px;left:-35px;background:#fff;border:1px solid #dcdcdc;border:1px solid rgba(0,0,0,0.2);-webkit-transition:opacity .218s;transition:opacity .218s;-webkit-box-shadow:0 2px 4px rgba(0,0,0,0.2);box-shadow:0 2px 4px rgba(0,0,0,0.2);padding:5px 0 5px 0;display:none;font-size:12px;line-height:20px}.c-tip-arrow{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;top:-16px}.c-tip-arrow-down{top:auto;bottom:0}.c-tip-arrow em,.c-tip-arrow ins{width:0;height:0;font-size:0;line-height:0;display:block;position:absolute;border:8px solid transparent;border-style:dashed dashed solid dashed}.c-tip-arrow em{border-bottom-color:#d8d8d8}.c-tip-arrow ins{border-bottom-color:#fff;top:2px}.c-tip-arrow-down em,.c-tip-arrow-down ins{border-style:solid dashed dashed dashed;border-color:transparent}.c-tip-arrow-down em{border-top-color:#d8d8d8}.c-tip-arrow-down ins{border-top-color:#fff;top:-2px}.c-tip-con h3{font-size:12px}.c-tip-con .c-tip-title{margin:0 10px;display:inline-block;width:239px}.c-tip-con .c-tip-info{color:#666;margin:0 10px 1px 10px;width:239px}.c-tip-con .c-tip-cer{width:354px;color:#666;margin:0 10px 1px 10px}.c-tip-con .c-tip-title{width:auto;_width:354px}.c-tip-con .c-tip-item-i{padding:3px 0 3px 20px;line-height:14px}.c-tip-con .c-tip-item-i .c-tip-item-icon{margin-left:-20px}.c-tip-con .c-tip-menu ul{width:74px}.c-tip-con .c-tip-menu ul{text-align:center}.c-tip-con .c-tip-menu li a{display:block;text-decoration:none;cursor:pointer;background-color:#fff;padding:3px 0;color:#0000d0}.c-tip-con .c-tip-menu li a:hover{display:block;background-color:#ebebeb}.c-tip-con .c-tip-notice{width:239px;padding:0 10px}.c-tip-con .c-tip-notice .c-tip-notice-succ{color:#4cbd37}.c-tip-con .c-tip-notice .c-tip-notice-fail{color:#f13f40}.c-tip-con .c-tip-notice .c-tip-item-succ{color:#444}.c-tip-con .c-tip-notice .c-tip-item-fail{color:#aaa}.c-tip-con .c-tip-notice .c-tip-item-fail a{color:#aaa}.c-tip-close{right:10px;position:absolute;cursor:pointer}.ecard{height:86px;overflow:hidden}.c-tools{display:inline}.c-tools-share{width:239px;padding:0 10px}.c-fanyi{display:none;width:20px;height:20px;border:solid 1px #d1d1d1;cursor:pointer;position:absolute;margin-left:516px;text-align:center;color:#333;line-height:22px;opacity:.9;background-color:#fff}.c-fanyi:hover{background-color:#39f;color:#fff;border-color:#39f;opacity:1}.c-fanyi-title,.c-fanyi-abstract{display:none}.icp_info{color:#666;margin-top:2px;font-size:13px}.icon-gw,.icon-unsafe-icon{background:#2c99ff;vertical-align:text-bottom;*vertical-align:baseline;height:16px;padding-top:0;padding-bottom:0;padding-left:6px;padding-right:6px;line-height:16px;_padding-top:2px;_height:14px;_line-height:14px;font-size:12px;font-family:simsun;margin-left:10px;overflow:hidden;display:inline-block;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px;color:#fff}a.icon-gw{color:#fff;background:#2196ff;text-decoration:none;cursor:pointer}a.icon-gw:hover{background:#1e87ef}a.icon-gw:active{height:15px;_height:13px;line-height:15px;_line-height:13px;padding-left:5px;background:#1c80d9;border-left:1px solid #145997;border-top:1px solid #145997}.icon-unsafe-icon{background:#e54d4b}#con-at{margin-bottom:11px;padding-left:121px;border-bottom:1px #ebebeb solid}#con-at .result-op{font-size:13px;line-height:1.52em}.wrapper_l #con-at .result-op{width:1058px}.wrapper_s #con-at .result-op{width:869px}#con-ar{margin-bottom:40px}#con-ar .result-op{margin-bottom:28px;font-size:13px;line-height:1.52em}.result_hidden{position:absolute;top:-10000px;left:-10000px}#content_left .result-op,#content_left .result{margin-bottom:14px;border-collapse:collapse}#content_left .c-border .result-op,#content_left .c-border .result{margin-bottom:25px}#content_left .c-border .result-op:last-child,#content_left .c-border .result:last-child{margin-bottom:12px}#content_left .result .f,#content_left .result-op .f{padding:0}.subLink_factory{border-collapse:collapse}.subLink_factory td{padding:0}.subLink_factory td.middle,.subLink_factory td.last{color:#666}.subLink_factory td a{text-decoration:underline}.subLink_factory td.rightTd{text-align:right}.subLink_factory_right{width:100%}.subLink_factory_left td{padding-right:26px}.subLink_factory_left td.last{padding:0}.subLink_factory_left td.first{padding-right:75px}.subLink_factory_right td{width:90px}.subLink_factory_right td.first{width:auto}.general_image_pic a{background:#fff no-repeat center center;text-decoration:none;display:block;overflow:hidden;text-align:left}.res_top_banner{height:36px;text-align:left;border-bottom:1px solid #e3e3e3;background:#f7f7f7;font-size:13px;padding-left:8px;color:#333;position:relative;z-index:302}.res_top_banner span{_zoom:1}.res_top_banner .res_top_banner_icon{background-position:0 -216px;width:18px;height:18px;margin:9px 10px 0 0}.res_top_banner .res_top_banner_icon_baiduapp{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/baiduappLogo_7db5fd3c.png) no-repeat 0 0;width:24px;height:24px;margin:3px 10px 0 0;position:relative;top:3px}.res_top_banner .res_top_banner_download{display:inline-block;width:65px;line-height:21px;_padding-top:1px;margin:0 0 0 10px;color:#333;background:#fbfbfb;border:1px solid #b4b6b8;text-align:center;text-decoration:none}.res_top_banner .res_top_banner_download:hover{border:1px solid #38f}.res_top_banner .res_top_banner_download:active{background:#f0f0f0;border:1px solid #b4b6b8}.res_top_banner .res_top_banner_close{background-position:-672px -144px;cursor:pointer;position:absolute;right:10px;top:10px}.res-gap-right16{margin-right:16px}.res-border-top{border-top:1px solid #f3f3f3}.res-border-bottom{border-bottom:1px solid #f3f3f3}.res-queryext-pos{position:relative;top:1px;_top:0}.c-trust-ecard{height:86px;_height:97px;overflow:hidden}@-moz-document url-prefix(){.result,.f{width:538px}}body{min-width:1000px}#ftCon{display:none}#pad-version{display:none}#index_guide{display:none}#index_logo{display:none}#u1{display:none}.s_ipt_wr{height:32px}body{padding:0}.s_form:after,.s_tab:after{content:\".\";display:block;height:0;clear:both;visibility:hidden}.s_form{zoom:1;height:55px;padding:0 0 0 10px}#result_logo{float:left;margin:7px 0 0}#result_logo img{width:101px}#head{padding:0;margin:0;width:100%;position:absolute;z-index:301;min-width:1000px;background:#fff;border-bottom:1px solid #ebebeb;position:fixed;_position:absolute;-webkit-transform:translateZ(0)}#head .head_wrapper{_width:1000px}#head.s_down{box-shadow:0 0 5px #888}.fm{clear:none;float:left;margin:11px 0 0 10px}#s_tab{background:#f8f8f8;line-height:36px;height:38px;padding:55px 0 0 121px;float:none;zoom:1}#s_tab a,#s_tab b{width:54px;display:inline-block;text-decoration:none;text-align:center;color:#666;font-size:14px}#s_tab b{border-bottom:2px solid #38f;font-weight:bold;color:#323232}#s_tab a:hover{color:#323232}#content_left{width:540px;padding-left:121px;padding-top:5px}#content_right{margin-top:45px}#page{padding:0 0 0 121px;margin:30px 0 40px 0}.to_tieba,.to_zhidao_bottom{margin:10px 0 0 121px}.nums{margin:0 0 0 121px;height:42px;line-height:42px}#rs{padding:0;margin:6px 0 0 121px;width:600px}#rs th{width:175px;line-height:22px}#rs .tt{padding:0;line-height:30px}#rs td{width:5px}#rs table{width:540px}#help{background:#f5f6f5;zoom:1;padding:0 0 0 50px;float:right}#help a{color:#777;padding:0 15px;text-decoration:none}#help a:hover{color:#333}#foot{background:#f5f6f5;border-top:1px solid #ebebeb;text-align:left;height:42px;line-height:42px;margin-top:40px;*margin-top:0}#foot .foot_c{float:left;padding:0 0 0 121px}.content_none{padding:45px 0 25px 121px}.nors p{font-size:18px;font-family:microsoft yahei;color:#000}.nors p em{color:#c00}.nors .tip_head{color:#666;font-size:13px;line-height:28px}.nors li{color:#333;line-height:28px;font-size:13px;font-family:'\u5b8b\u4f53';padding-left:30px;list-style-position:inside;list-style-type:disc}#mCon{top:5px}.s_ipt_wr.bg,.s_btn_wr.bg,#su.bg{background-image:none}.s_ipt_wr.bg{background:0}.s_btn_wr{width:auto;height:auto;border-bottom:1px solid transparent;*border-bottom:0}.s_btn{width:100px;height:34px;color:white;letter-spacing:1px;background:#3385ff;border-bottom:1px solid #2d78f4;outline:medium;*border-bottom:0;-webkit-appearance:none;-webkit-border-radius:0}.s_btn.btnhover{background:#317ef3;border-bottom:1px solid #2868c8;*border-bottom:0;box-shadow:1px 1px 1px #ccc}.s_btn_h{background:#3075dc;box-shadow:inset 1px 1px 3px #2964bb;-webkit-box-shadow:inset 1px 1px 3px #2964bb;-moz-box-shadow:inset 1px 1px 3px #2964bb;-o-box-shadow:inset 1px 1px 3px #2964bb}#wrapper_wrapper .container_l .EC_ppim_top,#wrapper_wrapper .container_xl .EC_ppim_top{width:640px}#wrapper_wrapper .container_s .EC_ppim_top{width:570px}#head .c-icon-bear-round{display:none}.container_l #content_right{width:384px}.container_l{width:1212px}.container_xl #content_right{width:384px}.container_xl{width:1257px}.index_tab_top{display:none}.index_tab_bottom{display:none}#lg{display:none}#m{display:none}#ftCon{display:none}#ent_sug{position:absolute;margin:141px 0 0 130px;font-size:13px;color:#666}.foot_fixed_bottom{position:fixed;bottom:0;width:100%;_position:absolute;_bottom:auto}#head .headBlock{margin:-5px 0 6px 121px}#content_left .leftBlock{margin-bottom:14px;padding-bottom:5px;border-bottom:1px solid #f3f3f3}.hint_toprq_tips{position:relative;width:537px;height:19px;line-height:19px;overflow:hidden;display:none}.hint_toprq_tips span{color:#666}.hint_toprq_icon{margin:0 4px 0 0}.hint_toprq_tips_items{width:444px;_width:440px;max-height:38px;position:absolute;left:95px;top:1px}.hint_toprq_tips_items div{display:inline-block;float:left;height:19px;margin-right:18px;white-space:nowrap;word-break:keep-all}.nums{width:538px}.search_tool{_padding-top:15px}.head_nums_cont_outer{height:40px;overflow:hidden;position:relative}.head_nums_cont_inner{position:relative}.search_tool_conter .c-gap-left{margin-left:23px}.search_tool_conter .c-icon-triangle-down{opacity:.6}.search_tool_conter .c-icon-triangle-down:hover{opacity:1}.search_tool,.search_tool_close{float:right}.search_tool,.search_tool_conter span{cursor:pointer;color:#666}.search_tool:hover,.search_tool_conter span:hover{color:#333}.search_tool_conter{font-size:12px;color:#666;margin:0 0 0 121px;height:42px;width:538px;line-height:42px;*height:auto;*line-height:normal;*padding:14px 0}.search_tool_conter span strong{color:#666}.c-tip-con .c-tip-langfilter ul{width:80px;text-align:left;color:#666}.c-tip-con .c-tip-langfilter li a{text-indent:15px;color:#666}.c-tip-con .c-tip-langfilter li span{text-indent:15px;padding:3px 0;color:#999;display:block}.c-tip-con .c-tip-timerfilter ul{width:115px;text-align:left;color:#666}.c-tip-con .c-tip-timerfilter-ft ul{width:180px}.c-tip-con .c-tip-timerfilter-si ul{width:206px;padding:7px 10px 10px}.c-tip-con .c-tip-timerfilter li a{text-indent:15px;color:#666}.c-tip-con .c-tip-timerfilter li span{text-indent:15px;padding:3px 0;color:#999;display:block}.c-tip-con .c-tip-timerfilter-ft li a,.c-tip-con .c-tip-timerfilter-ft li span{text-indent:20px}.c-tip-custom{padding:0 15px 10px 15px;position:relative;zoom:1}.c-tip-custom hr{border:0;height:0;border-top:1px solid #ebebeb}.c-tip-custom p{color:#b6b6b6;height:25px;line-height:25px;margin:2px 0}.c-tip-custom .c-tip-custom-et{margin-bottom:7px}.c-tip-custom-input,.c-tip-si-input{display:inline-block;font-size:11px;color:#333;margin-left:4px;padding:0 2px;width:74%;height:16px;line-height:16px\\9;border:1px solid #ebebeb;outline:0;box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;overflow:hidden;position:relative}.c-tip-custom-input-init{color:#d4d4d4}.c-tip-custom-input-focus,.c-tip-si-input-focus{border:1px solid #3385ff}.c-tip-timerfilter-si .c-tip-si-input{width:138px;height:22px;line-height:22px;vertical-align:0;*vertical-align:-6px;_vertical-align:-5px;padding:0 5px;margin-left:0}.c-tip-con .c-tip-timerfilter li .c-tip-custom-submit,.c-tip-con .c-tip-timerfilter li .c-tip-timerfilter-si-submit{display:inline;padding:4px 10px;margin:0;color:#333;border:1px solid #d8d8d8;font-family:inherit;font-weight:normal;text-align:center;vertical-align:0;background-color:#f9f9f9;outline:0}.c-tip-con .c-tip-timerfilter li .c-tip-custom-submit:hover,.c-tip-con .c-tip-timerfilter li .c-tip-timerfilter-si-submit:hover{display:inline;border-color:#388bff}.c-tip-timerfilter-si-error,.c-tip-timerfilter-custom-error{display:none;color:#3385ff;padding-left:4px}.c-tip-timerfilter-custom-error{padding:0;margin:-5px -13px 7px 0}#c-tip-custom-calenderCont{position:absolute;background:#fff;white-space:nowrap;padding:5px 10px;color:#000;border:1px solid #e4e4e4;-webkit-box-shadow:0 2px 4px rgba(0,0,0,0.2);box-shadow:0 2px 4px rgba(0,0,0,0.2)}#c-tip-custom-calenderCont p{text-align:center;padding:2px 0 4px;*padding:4px 0}#c-tip-custom-calenderCont p i{color:#8e9977;cursor:pointer;text-decoration:underline;font-size:13px}#c-tip-custom-calenderCont .op_cal{background:#fff}.op_cal table{background:#eeefea;margin:0;border-collapse:separate}.op_btn_pre_month,.op_btn_next_month{cursor:pointer;display:block;margin-top:6px}.op_btn_pre_month{float:left;background-position:0 -46px}.op_btn_next_month{float:right;background-position:-18px -46px}.op_cal .op_mon_pre1{padding:0}.op_mon th{text-align:center;font-size:12px;background:#FFF;font-weight:bold;border:1px solid #FFF;padding:0}.op_mon td{text-align:center;cursor:pointer}.op_mon h5{margin:0;padding:0 4px;text-align:center;font-size:14px;background:#FFF;height:28px;line-height:28px;border-bottom:1px solid #f5f5f5;margin-bottom:5px}.op_mon strong{font-weight:bold}.op_mon td{padding:0 5px;border:1px solid #fff;font-size:12px;background:#fff;height:100%}.op_mon td.op_mon_pre_month{color:#a4a4a4}.op_mon td.op_mon_cur_month{color:#00c}.op_mon td.op_mon_next_month{color:#a4a4a4}.op_mon td.op_mon_day_hover{color:#000;border:1px solid #278df2}.op_mon td.op_mon_day_selected{color:#FFF;border:1px solid #278df2;background:#278df2}.op_mon td.op_mon_day_disabled{cursor:not-allowed;color:#ddd}.zhannei-si-none,.zhannei-si,.hit_quet,.zhannei-search{display:none}#c-tip-custom-calenderCont .op_mon td.op_mon_cur_month{color:#000}#c-tip-custom-calenderCont .op_mon td.op_mon_day_selected{color:#fff}.c-frame{margin-bottom:18px}.c-offset{padding-left:10px}.c-gray{color:#666}.c-gap-top-small{margin-top:5px}.c-gap-top{margin-top:10px}.c-gap-bottom-small{margin-bottom:5px}.c-gap-bottom{margin-bottom:10px}.c-gap-left{margin-left:12px}.c-gap-left-small{margin-left:6px}.c-gap-right{margin-right:12px}.c-gap-right-small{margin-right:6px}.c-gap-right-large{margin-right:16px}.c-gap-left-large{margin-left:16px}.c-gap-icon-right-small{margin-right:5px}.c-gap-icon-right{margin-right:10px}.c-gap-icon-left-small{margin-left:5px}.c-gap-icon-left{margin-left:10px}.c-container{width:538px;font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all}.c-container .c-container{width:auto}.c-container table{border-collapse:collapse;border-spacing:0}.c-container td{font-size:13px;line-height:1.54}.c-default{font-size:13px;line-height:1.54;word-wrap:break-word;word-break:break-all}.c-container .t,.c-default .t{line-height:1.54}.c-default .t{margin-bottom:0}.cr-content{width:259px;font-size:13px;line-height:1.54;color:#333;word-wrap:break-word;word-break:normal}.cr-content table{border-collapse:collapse;border-spacing:0}.cr-content td{font-size:13px;line-height:1.54;vertical-align:top}.cr-offset{padding-left:17px}.cr-title{font-size:14px;line-height:1.29;font-weight:bold}.cr-title-sub{float:right;font-size:13px;font-weight:normal}.c-row{*zoom:1}.c-row:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-span2{width:29px}.c-span3{width:52px}.c-span4{width:75px}.c-span5{width:98px}.c-span6{width:121px}.c-span7{width:144px}.c-span8{width:167px}.c-span9{width:190px}.c-span10{width:213px}.c-span11{width:236px}.c-span12{width:259px}.c-span13{width:282px}.c-span14{width:305px}.c-span15{width:328px}.c-span16{width:351px}.c-span17{width:374px}.c-span18{width:397px}.c-span19{width:420px}.c-span20{width:443px}.c-span21{width:466px}.c-span22{width:489px}.c-span23{width:512px}.c-span24{width:535px}.c-span2,.c-span3,.c-span4,.c-span5,.c-span6,.c-span7,.c-span8,.c-span9,.c-span10,.c-span11,.c-span12,.c-span13,.c-span14,.c-span15,.c-span16,.c-span17,.c-span18,.c-span19,.c-span20,.c-span21,.c-span22,.c-span23,.c-span24{float:left;_display:inline;margin-right:17px;list-style:none}.c-span-last{margin-right:0}.c-span-last-s{margin-right:0}.container_l .cr-content{width:351px}.container_l .cr-content .c-span-last-s{margin-right:17px}.container_l .cr-content-narrow{width:259px}.container_l .cr-content-narrow .c-span-last-s{margin-right:0}.c-border{width:518px;padding:9px;border:1px solid #e3e3e3;border-bottom-color:#e0e0e0;border-right-color:#ececec;box-shadow:1px 2px 1px rgba(0,0,0,0.072);-webkit-box-shadow:1px 2px 1px rgba(0,0,0,0.072);-moz-box-shadow:1px 2px 1px rgba(0,0,0,0.072);-o-box-shadow:1px 2px 1px rgba(0,0,0,0.072)}.c-border .c-gap-left{margin-left:10px}.c-border .c-gap-left-small{margin-left:5px}.c-border .c-gap-right{margin-right:10px}.c-border .c-gap-right-small{margin-right:5px}.c-border .c-border{width:auto;padding:0;border:0;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;-o-box-shadow:none}.c-border .c-span2{width:34px}.c-border .c-span3{width:56px}.c-border .c-span4{width:78px}.c-border .c-span5{width:100px}.c-border .c-span6{width:122px}.c-border .c-span7{width:144px}.c-border .c-span8{width:166px}.c-border .c-span9{width:188px}.c-border .c-span10{width:210px}.c-border .c-span11{width:232px}.c-border .c-span12{width:254px}.c-border .c-span13{width:276px}.c-border .c-span14{width:298px}.c-border .c-span15{width:320px}.c-border .c-span16{width:342px}.c-border .c-span17{width:364px}.c-border .c-span18{width:386px}.c-border .c-span19{width:408px}.c-border .c-span20{width:430px}.c-border .c-span21{width:452px}.c-border .c-span22{width:474px}.c-border .c-span23{width:496px}.c-border .c-span24{width:518px}.c-border .c-span2,.c-border .c-span3,.c-border .c-span4,.c-border .c-span5,.c-border .c-span6,.c-border .c-span7,.c-border .c-span8,.c-border .c-span9,.c-border .c-span10,.c-border .c-span11,.c-border .c-span12,.c-border .c-span13,.c-border .c-span14,.c-border .c-span15,.c-border .c-span16,.c-border .c-span17,.c-border .c-span18,.c-border .c-span19,.c-border .c-span20,.c-border .c-span21,.c-border .c-span22,.c-border .c-span23,.c-border .c-span24{margin-right:10px}.c-border .c-span-last{margin-right:0}.c-loading{display:block;width:50px;height:50px;background:url(\"\/\/www.baidu.com\/aladdin\/img\/tools\/loading.gif\") no-repeat 0 0}.c-vline{display:inline-block;margin:0 3px;border-left:1px solid #ddd;width:0;height:12px;_vertical-align:middle;_overflow:hidden}.c-icon{background:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_4e7241a3.png) no-repeat 0 0;_background-image:url(http:\/\/s1.bdstatic.com\/r\/www\/cache\/static\/global\/img\/icons_d160197c.gif)}.c-icon{display:inline-block;width:14px;height:14px;vertical-align:text-bottom;font-style:normal;overflow:hidden}.c-icon-unfold,.c-icon-fold,.c-icon-chevron-unfold,.c-icon-chevron-fold{width:12px;height:12px}.c-icon-star,.c-icon-star-gray{width:60px}.c-icon-qa-empty,.c-icon-safeguard,.c-icon-register-empty,.c-icon-zan,.c-icon-music,.c-icon-music-gray,.c-icon-location,.c-icon-warning,.c-icon-doc,.c-icon-xls,.c-icon-ppt,.c-icon-pdf,.c-icon-txt,.c-icon-play-black,.c-icon-gift,.c-icon-baidu-share,.c-icon-bear,.c-icon-bear-border,.c-icon-location-blue,.c-icon-hotAirBall,.c-icon-moon,.c-icon-streetMap,.c-icon-mv,.c-icon-zhidao-s,.c-icon-shopping{width:16px;height:16px}.c-icon-bear-circle,.c-icon-warning-circle,.c-icon-warning-triangle,.c-icon-warning-circle-gray{width:18px;height:18px}.c-icon-tieba,.c-icon-zhidao,.c-icon-bear-p,.c-icon-bear-pn{width:24px;height:24px}.c-icon-ball-blue,.c-icon-ball-red{width:38px;height:38px}.c-icon-unfold:hover,.c-icon-fold:hover,.c-icon-chevron-unfold:hover,.c-icon-chevron-fold:hover,.c-icon-download:hover,.c-icon-lyric:hover,.c-icon-v:hover,.c-icon-hui:hover,.c-icon-bao:hover,.c-icon-person:hover,.c-icon-high-v:hover,.c-icon-phone:hover,.c-icon-nuo:hover,.c-icon-med:hover,.c-icon-air:hover,.c-icon-share2:hover,.c-icon-v1:hover,.c-icon-v2:hover,.c-icon-v3:hover,.c-icon-write:hover{border-color:#388bff}.c-icon-unfold:active,.c-icon-fold:active,.c-icon-chevron-unfold:active,.c-icon-chevron-fold:active,.c-icon-download:active,.c-icon-lyric:active,.c-icon-v:active,.c-icon-hui:active,.c-icon-bao:active,.c-icon-person:active,.c-icon-high-v:active,.c-icon-phone:active,.c-icon-nuo:active,.c-icon-med:active,.c-icon-air:active,.c-icon-share2:active,.c-icon-v1:active,.c-icon-v2:active,.c-icon-v3:active,.c-icon-write:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}.c-icon-unfold,.c-icon-fold,.c-icon-chevron-unfold,.c-icon-chevron-fold,.c-icon-download,.c-icon-lyric{border:1px solid #d8d8d8;cursor:pointer}.c-icon-v,.c-icon-hui,.c-icon-bao,.c-icon-person,.c-icon-high-v,.c-icon-phone,.c-icon-nuo,.c-icon-med,.c-icon-air,.c-icon-share2,.c-icon-v1,.c-icon-v2,.c-icon-v3,.c-icon-write{border:1px solid #d8d8d8;cursor:pointer;border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347)}.c-icon-v1,.c-icon-v2,.c-icon-v3,.c-icon-v1-noborder,.c-icon-v2-noborder,.c-icon-v3-noborder,.c-icon-v1-noborder-disable,.c-icon-v2-noborder-disable,.c-icon-v3-noborder-disable{width:19px}.c-icon-download,.c-icon-lyric{width:16px;height:16px}.c-icon-play-circle,.c-icon-stop-circle{width:18px;height:18px}.c-icon-play-circle-middle,.c-icon-stop-circle-middle{width:24px;height:24px}.c-icon-play-black-large,.c-icon-stop-black-large{width:36px;height:36px}.c-icon-play-black-larger,.c-icon-stop-black-larger{width:52px;height:52px}.c-icon-flag{background-position:0 -144px}.c-icon-bus{background-position:-24px -144px}.c-icon-calendar{background-position:-48px -144px}.c-icon-street{background-position:-72px -144px}.c-icon-map{background-position:-96px -144px}.c-icon-bag{background-position:-120px -144px}.c-icon-money{background-position:-144px -144px}.c-icon-game{background-position:-168px -144px}.c-icon-user{background-position:-192px -144px}.c-icon-globe{background-position:-216px -144px}.c-icon-lock{background-position:-240px -144px}.c-icon-plane{background-position:-264px -144px}.c-icon-list{background-position:-288px -144px}.c-icon-star-gray{background-position:-312px -144px}.c-icon-circle-gray{background-position:-384px -144px}.c-icon-triangle-down{background-position:-408px -144px}.c-icon-triangle-up{background-position:-432px -144px}.c-icon-triangle-up-empty{background-position:-456px -144px}.c-icon-sort-gray{background-position:-480px -144px}.c-icon-sort-up{background-position:-504px -144px}.c-icon-sort-down{background-position:-528px -144px}.c-icon-down-gray{background-position:-552px -144px}.c-icon-up-gray{background-position:-576px -144px}.c-icon-download-noborder{background-position:-600px -144px}.c-icon-lyric-noborder{background-position:-624px -144px}.c-icon-download-white{background-position:-648px -144px}.c-icon-close{background-position:-672px -144px}.c-icon-fail{background-position:-696px -144px}.c-icon-success{background-position:-720px -144px}.c-icon-triangle-down-g{background-position:-744px -144px}.c-icon-refresh{background-position:-768px -144px}.c-icon-chevron-left-gray{background-position:-816px -144px}.c-icon-chevron-right-gray{background-position:-840px -144px}.c-icon-setting{background-position:-864px -144px}.c-icon-close2{background-position:-888px -144px}.c-icon-chevron-top-gray-s{background-position:-912px -144px}.c-icon-fullscreen{background-position:0 -168px}.c-icon-safe{background-position:-24px -168px}.c-icon-exchange{background-position:-48px -168px}.c-icon-chevron-bottom{background-position:-72px -168px}.c-icon-chevron-top{background-position:-96px -168px}.c-icon-unfold{background-position:-120px -168px}.c-icon-fold{background-position:-144px -168px}.c-icon-chevron-unfold{background-position:-168px -168px}.c-icon-qa{background-position:-192px -168px}.c-icon-register{background-position:-216px -168px}.c-icon-star{background-position:-240px -168px}.c-icon-star-gray{position:relative}.c-icon-star-gray .c-icon-star{position:absolute;top:0;left:0}.c-icon-play-blue{background-position:-312px -168px}.c-icon-pic{width:16px;background-position:-336px -168px}.c-icon-chevron-fold{background-position:-360px -168px}.c-icon-video{width:18px;background-position:-384px -168px}.c-icon-circle-blue{background-position:-408px -168px}.c-icon-circle-yellow{background-position:-432px -168px}.c-icon-play-white{background-position:-456px -168px}.c-icon-triangle-down-blue{background-position:-480px -168px}.c-icon-chevron-unfold2{background-position:-504px -168px}.c-icon-right{background-position:-528px -168px}.c-icon-right-empty{background-position:-552px -168px}.c-icon-new-corner{width:15px;background-position:-576px -168px}.c-icon-horn{background-position:-600px -168px}.c-icon-right-large{width:18px;background-position:-624px -168px}.c-icon-wrong-large{background-position:-648px -168px}.c-icon-circle-blue-s{background-position:-672px -168px}.c-icon-play-gray{background-position:-696px -168px}.c-icon-up{background-position:-720px -168px}.c-icon-down{background-position:-744px -168px}.c-icon-stable{background-position:-768px -168px}.c-icon-calendar-blue{background-position:-792px -168px}.c-icon-triangle-down-blue2{background-position:-816px -168px}.c-icon-triangle-up-blue2{background-position:-840px -168px}.c-icon-down-blue{background-position:-864px -168px}.c-icon-up-blue{background-position:-888px -168px}.c-icon-ting{background-position:-912px -168px}.c-icon-piao{background-position:-936px -168px}.c-icon-wrong-empty{background-position:-960px -168px}.c-icon-warning-circle-s{background-position:-984px -168px}.c-icon-chevron-left{background-position:-1008px -168px}.c-icon-chevron-right{background-position:-1032px -168px}.c-icon-circle-gray-s{background-position:-1056px -168px}.c-icon-v,.c-icon-v-noborder{background-position:0 -192px}.c-icon-hui{background-position:-24px -192px}.c-icon-bao{background-position:-48px -192px}.c-icon-phone{background-position:-72px -192px}.c-icon-qa-empty{background-position:-96px -192px}.c-icon-safeguard{background-position:-120px -192px}.c-icon-register-empty{background-position:-144px -192px}.c-icon-zan{background-position:-168px -192px}.c-icon-music{background-position:-192px -192px}.c-icon-music-gray{background-position:-216px -192px}.c-icon-location{background-position:-240px -192px}.c-icon-warning{background-position:-264px -192px}.c-icon-doc{background-position:-288px -192px}.c-icon-xls{background-position:-312px -192px}.c-icon-ppt{background-position:-336px -192px}.c-icon-pdf{background-position:-360px -192px}.c-icon-txt{background-position:-384px -192px}.c-icon-play-black{background-position:-408px -192px}.c-icon-play-black:hover{background-position:-432px -192px}.c-icon-gift{background-position:-456px -192px}.c-icon-baidu-share{background-position:-480px -192px}.c-icon-bear{background-position:-504px -192px}.c-icon-bear-border{background-position:-576px -192px}.c-icon-person,.c-icon-person-noborder{background-position:-600px -192px}.c-icon-location-blue{background-position:-624px -192px}.c-icon-hotAirBall{background-position:-648px -192px}.c-icon-moon{background-position:-672px -192px}.c-icon-streetMap{background-position:-696px -192px}.c-icon-high-v,.c-icon-high-v-noborder{background-position:-720px -192px}.c-icon-nuo{background-position:-744px -192px}.c-icon-mv{background-position:-768px -192px}.c-icon-med{background-position:-816px -192px}.c-icon-air{background-position:-840px -192px}.c-icon-share2{background-position:-864px -192px}.c-icon-v1,.c-icon-v1-noborder{background-position:-888px -192px}.c-icon-v2,.c-icon-v2-noborder{background-position:-912px -192px}.c-icon-v3,.c-icon-v3-noborder{background-position:-936px -192px}.c-icon-v1-noborder-disable{background-position:-960px -192px}.c-icon-v2-noborder-disable{background-position:-984px -192px}.c-icon-v3-noborder-disable{background-position:-1008px -192px}.c-icon-write{background-position:-1032px -192px}.c-icon-zhidao-s{background-position:-1056px -192px}.c-icon-shopping{background-position:-1080px -192px}.c-icon-bear-circle{background-position:0 -216px}.c-icon-warning-circle{background-position:-24px -216px}.c-icon-warning-triangle{width:24px;background-position:-48px -216px}.c-icon-warning-circle-gray{background-position:-72px -216px}.c-icon-ball-red{background-position:0 -240px}.c-icon-ball-blue{background-position:-48px -240px}.c-icon-tieba{background-position:0 -288px}.c-icon-zhidao{background-position:-48px -288px}.c-icon-bear-p{background-position:-96px -288px}.c-icon-bear-pn{background-position:-144px -288px}.c-icon-download{background-position:0 -336px}.c-icon-lyric{background-position:-24px -336px}.c-icon-play-circle{background-position:-48px -336px}.c-icon-play-circle:hover{background-position:-72px -336px}.c-icon-stop-circle{background-position:-96px -336px}.c-icon-stop-circle:hover{background-position:-120px -336px}.c-icon-play-circle-middle{background-position:0 -360px}.c-icon-play-circle-middle:hover{background-position:-48px -360px}.c-icon-stop-circle-middle{background-position:-96px -360px}.c-icon-stop-circle-middle:hover{background-position:-144px -360px}.c-icon-play-black-large{background-position:0 -408px}.c-icon-play-black-large:hover{background-position:-48px -408px}.c-icon-stop-black-large{background-position:-96px -408px}.c-icon-stop-black-large:hover{background-position:-144px -408px}.c-icon-play-black-larger{background-position:0 -456px}.c-icon-play-black-larger:hover{background-position:-72px -456px}.c-icon-stop-black-larger{background-position:-144px -456px}.c-icon-stop-black-larger:hover{background-position:-216px -456px}.c-recommend{font-size:0;padding:5px 0;border:1px solid #f3f3f3;border-left:none;border-right:0}.c-recommend .c-icon{margin-bottom:-4px}.c-recommend .c-gray,.c-recommend a{font-size:13px}.c-recommend-notopline{padding-top:0;border-top:0}.c-recommend-vline{display:inline-block;margin:0 10px -2px;border-left:1px solid #d8d8d8;width:0;height:12px;_vertical-align:middle;_overflow:hidden}.c-text{display:inline-block;padding:2px;text-align:center;vertical-align:text-bottom;font-size:12px;line-height:100%;font-style:normal;font-weight:normal;color:#fff;overflow:hidden}a.c-text{text-decoration:none}.c-text-new{background-color:#f13f40}.c-text-info{padding-left:0;padding-right:0;font-weight:bold;color:#2b99ff;*vertical-align:baseline;_position:relative;_top:2px}.c-text-info b{_position:relative;_top:-1px}.c-text-info span{padding:0 2px;font-weight:normal}.c-text-important{background-color:#1cb7fd}.c-text-public{background-color:#2b99ff}.c-text-warning{background-color:#ff830f}.c-text-prompt{background-color:#f5c537}.c-text-danger{background-color:#f13f40}.c-text-safe{background-color:#52c277}.c-text-empty{padding-top:1px;padding-bottom:1px;border:1px solid #d8d8d8;cursor:pointer;color:#23b9fd;background-color:#fff}.c-text-empty:hover{border-color:#388bff}.c-text-empty:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}.c-text-mult{padding-left:5px;padding-right:5px}.c-text-gray{background-color:#666}.c-btn,.c-btn:visited{color:#333!important}.c-btn{display:inline-block;padding:0 14px;margin:0;height:24px;line-height:25px;font-size:13px;filter:chroma(color=#000000);*zoom:1;border:1px solid #d8d8d8;cursor:pointer;font-family:inherit;font-weight:normal;text-align:center;vertical-align:middle;background-color:#f9f9f9;overflow:hidden;outline:0}.c-btn:hover{border-color:#388bff}.c-btn:active{border-color:#a2a6ab;background-color:#f0f0f0;box-shadow:inset 1px 1px 1px #c7c7c7;-webkit-box-shadow:inset 1px 1px 1px #c7c7c7;-moz-box-shadow:inset 1px 1px 1px #c7c7c7;-o-box-shadow:inset 1px 1px 1px #c7c7c7}a.c-btn{text-decoration:none}button.c-btn{height:26px;_line-height:18px;*overflow:visible}button.c-btn::-moz-focus-inner{padding:0;border:0}.c-btn .c-icon{margin-top:5px}.c-btn-disable{color:#999!important}.c-btn-disable:visited{color:#999!important}.c-btn-disable:hover{border:1px solid #d8d8d8;cursor:default}.c-btn-disable:active{border-color:#d8d8d8;background-color:#f9f9f9;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;-o-box-shadow:none}.c-btn-mini{padding-left:5px;padding-right:5px;height:18px;line-height:18px;font-size:12px}button.c-btn-mini{height:20px;_height:18px;_line-height:14px}.c-btn-mini .c-icon{margin-top:2px}.c-btn-large{height:28px;line-height:28px;font-size:14px;font-family:\"\u5fae\u8f6f\u96c5\u9ed1\",\"\u9ed1\u4f53\"}button.c-btn-large{height:30px;_line-height:24px}.c-btn-large .c-icon{margin-top:7px;_margin-top:6px}.c-btn-primary,.c-btn-primary:visited{color:#fff!important}.c-btn-primary{background-color:#388bff;border-color:#3c8dff #408ffe #3680e6}.c-btn-primary:hover{border-color:#2678ec #2575e7 #1c6fe2 #2677e7;background-color:#388bff;background-image:url(data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAMAAACuX0YVAAAABlBMVEVnpv85i\/9PO5r4AAAAD0lEQVR42gEEAPv\/AAAAAQAFAAIros7PAAAAAElFTkSuQmCC);*background-image:none;background-repeat:repeat-x;box-shadow:1px 1px 1px rgba(0,0,0,0.4);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.4);-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.4);-o-box-shadow:1px 1px 1px rgba(0,0,0,0.4)}.c-btn-primary:active{border-color:#178ee3 #1784d0 #177bbf #1780ca;background-color:#388bff;background-image:none;box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15);-o-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.15)}.c-btn .c-icon{float:left}.c-dropdown2{position:relative;display:inline-block;width:100%;height:26px;line-height:26px;font-size:13px;vertical-align:middle;outline:0;_font-family:SimSun;background-color:#fff;word-wrap:normal;word-break:normal}.c-dropdown2 .c-dropdown2-btn-group{position:relative;height:24px;border:1px solid #999;border-bottom-color:#d8d8d8;border-right-color:#d8d8d8;-moz-user-select:none;-webkit-user-select:none;user-select:none}.c-dropdown2:hover .c-dropdown2-btn-group,.c-dropdown2-hover .c-dropdown2-btn-group{box-shadow:inset 1px 1px 0 0 #d8d8d8;-webkit-box-shadow:inset 1px 1px 0 0 #d8d8d8;-moz-box-shadow:inset 1px 1px 0 0 #d8d8d8;-o-box-shadow:inset 1px 1px 0 0 #d8d8d8}.c-dropdown2:hover .c-dropdown2-btn-icon,.c-dropdown2-hover .c-dropdown2-btn-icon{box-shadow:inset 0 1px 0 0 #d8d8d8;-webkit-box-shadow:inset 0 1px 0 0 #d8d8d8;-moz-box-shadow:inset 0 1px 0 0 #d8d8d8;-o-box-shadow:inset 0 1px 0 0 #d8d8d8}.c-dropdown2:hover .c-dropdown2-btn-icon-border,.c-dropdown2-hover .c-dropdown2-btn-icon-border{background-color:#f2f2f2}.c-dropdown2 .c-dropdown2-btn{height:24px;padding-left:10px;padding-right:10px;cursor:default;overflow:hidden;white-space:nowrap}.c-dropdown2 .c-dropdown2-btn-icon{position:absolute;top:0;right:0;width:23px;height:24px;line-height:24px;background-color:#fff;padding:0 1px 0 10px}.c-dropdown2 .c-dropdown2-btn-icon-border{height:24px;width:23px;border-left:1px solid #d9d9d9;text-align:center;zoom:1}.c-dropdown2 .c-icon-triangle-down{*margin-top:5px;_margin-left:2px}.c-dropdown2 .c-dropdown2-menu{position:absolute;left:0;top:100%;_margin-top:0;width:100%;overflow:hidden;border:1px solid #bbb;background:#fff;visibility:hidden}.c-dropdown2 .c-dropdown2-menu-inner{overflow:hidden}.c-dropdown2 .c-dropdown2-option{background-color:#fff;cursor:pointer}.c-dropdown2 .c-dropdown2-selected{background-color:#f5f5f5}.c-dropdown2-common ul,.c-dropdown2-common li{margin:0;padding:0;list-style:none}.c-dropdown2-common .c-dropdown2-option{height:26px;line-height:26px;font-size:12px;color:#333;white-space:nowrap;cursor:pointer;padding-left:10px}.c-dropdown2-common .c-dropdown2-selected{background-color:#f5f5f5}.c-dropdown2-common .c-dropdown2-menu-group .c-dropdown2-group{padding-left:10px;font-weight:bold;cursor:default}.c-dropdown2-common .c-dropdown2-menu-group .c-dropdown2-option{padding-left:20px}.c-img{display:block;min-height:1px;border:none 0}.c-img3{width:52px}.c-img4{width:75px}.c-img6{width:121px}.c-img7{width:144px}.c-img12{width:259px}.c-img15{width:328px}.c-img18{width:397px}.c-border .c-img3{width:56px}.c-border .c-img4{width:78px}.c-border .c-img7{width:144px}.c-border .c-img12{width:254px}.c-border .c-img15{width:320px}.c-border .c-img18{width:386px}.c-index{display:inline-block;padding:1px 0;color:#fff;width:14px;line-height:100%;font-size:12px;text-align:center;background-color:#8eb9f5}.c-index-hot,.c-index-hot1{background-color:#f54545}.c-index-hot2{background-color:#ff8547}.c-index-hot3{background-color:#ffac38}.c-input{display:inline-block;padding:0 4px;height:24px;line-height:24px\\9;font-size:13px;border:1px solid #999;border-bottom-color:#d8d8d8;border-right-color:#d8d8d8;outline:0;box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;vertical-align:top;overflow:hidden}.c-input:hover{box-shadow:inset 1px 1px 1px 0 #d8d8d8;-webkit-box-shadow:inset 1px 1px 1px 0 #d8d8d8;-moz-box-shadow:inset 1px 1px 1px 0 #d8d8d8;-o-box-shadow:inset 1px 1px 1px 0 #d8d8d8}.c-input .c-icon{float:right;margin-top:6px}.c-input .c-icon-left{float:left;margin-right:4px}.c-input input{float:left;height:22px;*padding-top:4px;margin-top:2px;font-size:13px;border:0;outline:0}.c-input{width:180px}.c-input input{width:162px}.c-input-xmini{width:65px}.c-input-xmini input{width:47px}.c-input-mini{width:88px}.c-input-mini input{width:70px}.c-input-small{width:157px}.c-input-small input{width:139px}.c-input-large{width:203px}.c-input-large input{width:185px}.c-input-xlarge{width:341px}.c-input-xlarge input{width:323px}.c-input12{width:249px}.c-input12 input{width:231px}.c-input20{width:433px}.c-input20 input{width:415px}.c-border .c-input{width:178px}.c-border .c-input input{width:160px}.c-border .c-input-xmini{width:68px}.c-border .c-input-xmini input{width:50px}.c-border .c-input-mini{width:90px}.c-border .c-input-mini input{width:72px}.c-border .c-input-small{width:156px}.c-border .c-input-small input{width:138px}.c-border .c-input-large{width:200px}.c-border .c-input-large input{width:182px}.c-border .c-input-xlarge{width:332px}.c-border .c-input-xlarge input{width:314px}.c-border .c-input12{width:244px}.c-border .c-input12 input{width:226px}.c-border .c-input20{width:420px}.c-border .c-input20 input{width:402px}.c-numberset{*zoom:1}.c-numberset:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-numberset li{float:left;margin-right:17px;list-style:none}.c-numberset .c-numberset-last{margin-right:0}.c-numberset a{display:block;width:50px;text-decoration:none;text-align:center;border:1px solid #d8d8d8;cursor:pointer}.c-numberset a:hover{border-color:#388bff}.c-border .c-numberset li{margin-right:10px}.c-border .c-numberset .c-numberset-last{margin-right:0}.c-border .c-numberset a{width:54px}.c-table{width:100%;border-collapse:collapse;border-spacing:0}.c-table th,.c-table td{padding-left:10px;line-height:1.54;font-size:13px;border-bottom:1px solid #f3f3f3;text-align:left}.cr-content .c-table th:first-child,.cr-content .c-table td:first-child{padding-left:0}.c-table th{padding-top:4px;padding-bottom:4px;font-weight:normal;color:#666;border-color:#f0f0f0;white-space:nowrap;background-color:#fafafa}.c-table td{padding-top:6.5px;padding-bottom:6.5px}.c-table-hasimg td{padding-top:10px;padding-bottom:10px}.c-table a,.c-table em{text-decoration:none}.c-table a:hover,.c-table a:hover em{text-decoration:underline}.c-table a.c-icon:hover{text-decoration:none}.c-table .c-btn:hover,.c-table .c-btn:hover em{text-decoration:none}.c-table-nohihead th{background-color:transparent}.c-table-noborder td{border-bottom:0}.c-tabs-nav-movetop{margin:-10px -9px 0 -10px;position:relative}.c-tabs-nav{border-bottom:1px solid #d9d9d9;background-color:#fafafa;line-height:1.54;font-size:0;*zoom:1;_overflow-x:hidden;_position:relative}.c-tabs-nav:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-tabs-nav .c-tabs-nav-btn{float:right;_position:absolute;_top:0;_right:0;_z-index:1;background:#fafafa}.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-prev,.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-next{float:left;padding:6px 2px;cursor:pointer}.c-tabs-nav .c-tabs-nav-btn .c-tabs-nav-btn-disable{cursor:default}.c-tabs-nav .c-tabs-nav-view{_position:relative;overflow:hidden;*zoom:1;margin-bottom:-1px}.c-tabs-nav .c-tabs-nav-view .c-tabs-nav-li{margin-bottom:0}.c-tabs-nav .c-tabs-nav-more{float:left;white-space:nowrap}.c-tabs-nav li,.c-tabs-nav a{color:#666;font-size:13px;*zoom:1}.c-tabs-nav li{display:inline-block;margin-bottom:-1px;*display:inline;padding:3px 15px;vertical-align:bottom;border-style:solid;border-width:2px 1px 0 1px;border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347);list-style:none;cursor:pointer;white-space:nowrap;overflow:hidden}.c-tabs-nav a{text-decoration:none}.c-tabs-nav .c-tabs-nav-sep{height:16px;width:0;padding:0;margin-bottom:4px;border-style:solid;border-width:0 1px 0;border-color:transparent #fff transparent #dedede}.c-tabs-nav .c-tabs-nav-selected{_position:relative;border-color:#2c99ff #e4e4e4 #fff #dedede;background-color:#fff;color:#000;cursor:default}.c-tabs-nav-one .c-tabs-nav-selected{border-color:transparent;_border-color:tomato;_filter:chroma(color=#ff6347);background-color:transparent;color:#666}.c-tabs .c-tabs .c-tabs-nav{padding:10px 0 5px;border:none 0;background-color:#fff}.c-tabs .c-tabs .c-tabs-nav li,.c-tabs .c-tabs .c-tabs-nav a{color:#00c}.c-tabs .c-tabs .c-tabs-nav li{padding:0 5px;position:static;margin:0 10px;border:none 0;cursor:pointer;white-space:nowrap}.c-tabs .c-tabs .c-tabs-nav .c-tabs-nav-sep{height:11px;width:0;padding:0;margin:0 0 4px 0;border:none 0;border-left:1px solid #d8d8d8}.c-tabs .c-tabs .c-tabs-nav .c-tabs-nav-selected{background-color:#2c99ff;color:#fff;cursor:default}.c-tag{padding-top:3px;margin-bottom:3px;height:1.7em;font-size:13px;line-height:1.4em;transition:height .3s ease-in;-webkit-transition:height .3s ease-in;-moz-transition:height .3s ease-in;-ms-transition:height .3s ease-in;-o-transition:height .3s ease-in;*zoom:1;overflow:hidden}.c-tag:after{display:block;height:0;content:\"\";clear:both;visibility:hidden}.c-tag-cont{overflow:hidden;*zoom:1}.c-tag-type,.c-tag-li,.c-tag-more,.c-tag-cont span{margin:2px 0}.c-tag-type,.c-tag-li,.c-tag-cont span{float:left}.c-tag-type,.c-tag-more{color:#666}.c-tag-li,.c-tag-cont span{padding:0 4px;display:inline-block;margin-right:12px;white-space:nowrap;cursor:pointer;color:#00c}.c-tag .c-tag-selected{background:#388bff;color:#fff}.c-tag-more{float:right;background:#fff;cursor:pointer;*height:18px}.c-tool{display:inline-block;width:56px;height:56px;background:url(\"\/\/www.baidu.com\/aladdin\/img\/tools\/tools-5.png\") no-repeat}.c-tool-region{background-position:0 0}.c-tool-calendar{background-position:-72px 0}.c-tool-city{background-position:-144px 0}.c-tool-phone-pos{background-position:-216px 0}.c-tool-other{background-position:-288px 0}.c-tool-midnight{background-position:-360px 0}.c-tool-kefu{width:121px;background-position:-432px 0}.c-tool-phone{background-position:-576px 0}.c-tool-car{background-position:-648px 0}.c-tool-station{background-position:0 -72px}.c-tool-cheat{background-position:-72px -72px}.c-tool-counter{background-position:-144px -72px}.c-tool-time{background-position:-216px -72px}.c-tool-zip{background-position:-288px -72px}.c-tool-warning{background-position:-360px -72px}.c-tool-ip{background-position:0 -144px}.c-tool-unit{background-position:-72px -144px}.c-tool-rate{background-position:-144px -144px}.c-tool-conversion{background-position:-288px -144px}.c-tool-ads{background-position:-360px -144px}<\/style>";result_common_css=$(result_common_css);result_common_css.attr("data-for","result");var index_css= $('head [index]');var wrapper=$("#wrapper");window.index_on=function(){index_css.insertAfter("meta:eq(0)");result_common_css.remove();wrapper.show();if(bds.su&&bds.su.U&&bds.su.U.homeInit){bds.su.U.homeInit();}};window.index_off=function(){result_common_css.insertAfter("meta:eq(0)");wrapper.show();index_css.remove();};})();</script> -<script type="text/javascript">var Cookie={set:function(c,e,d,f,a,b){document.cookie=c+"="+(b?e:escape(e))+((a)?"; expires="+a.toGMTString():"")+((f)?"; path="+f:"; path=/")+((d)?"; domain="+d:"")},get:function(c,b){var a=document.cookie.match(new RegExp("(^| )"+c+"=([^;]*)(;|$)"));if(a!=null){return unescape(a[2])}return b},clear:function(a,c,b){if(this.get(a)){document.cookie=a+"="+((c)?"; path="+c:"; path=/")+((b)?"; domain="+b:"")+";expires=Fri, 02-Jan-1970 00:00:00 GMT"}}};(function(){var defaultOptions={sugSet:1,sugStoreSet:1,isSwitch:1,isJumpHttps:1,imeSwitch:0,resultNum:10,skinOpen:1,resultLang:0},options={},tmpName;var expire30y=new Date();expire30y.setTime(expire30y.getTime()+30*365*86400000);try{if(bds&&bds.comm&&bds.comm.personalData){if(typeof bds.comm.personalData=="string"){bds.comm.personalData=eval("("+bds.comm.personalData+")")}if(!bds.comm.personalData){return}for(tmpName in bds.comm.personalData){if(defaultOptions.hasOwnProperty(tmpName)&&bds.comm.personalData.hasOwnProperty(tmpName)){if(bds.comm.personalData[tmpName].ErrMsg=="SUCCESS"){options[tmpName]=bds.comm.personalData[tmpName].value -}}}}try{if(!parseInt(options.resultNum)){delete (options.resultNum)}if(!parseInt(options.resultLang)&&options.resultLang!="0"){delete (options.resultLang)}}catch(e){}writeCookie();if(!("sugSet" in options)){options.sugSet=(Cookie.get("sug",3)!=3?0:1)}if(!("sugStoreSet" in options)){options.sugStoreSet=Cookie.get("sugstore",0)}var BAIDUID=Cookie.get("BAIDUID");if(!("resultNum" in options)){if(/NR=(\d+)/.test(BAIDUID)){options.resultNum=RegExp.$1?parseInt(RegExp.$1):10}else{options.resultNum=10}}if(!("resultLang" in options)){if(/SL=(\d+)/.test(BAIDUID)){options.resultLang=RegExp.$1?parseInt(RegExp.$1):0}else{options.resultLang=0}}if(!("isSwitch" in options)){options.isSwitch=(Cookie.get("ORIGIN",0)==2?0:(Cookie.get("ORIGIN",0)==1?2:1))}if(!("imeSwitch" in options)){options.imeSwitch=Cookie.get("bdime",0)}}catch(e){}function save(callback){var optionsStr=[];for(tmpName in options){if(options.hasOwnProperty(tmpName)){optionsStr.push('"'+tmpName+'":"'+options[tmpName]+'"')}}var str="{"+optionsStr.join(",")+"}"; -if(bds.comm.personalData){$.ajax({url:"//www.baidu.com/ups/submit/addtips/?product=ps&tips="+encodeURIComponent(str)+"&_r="+new Date().getTime(),success:function(){writeCookie();if(typeof callback=="function"){callback()}}})}else{writeCookie();if(typeof callback=="function"){setTimeout(callback,0)}}}function set(optionName,value){options[optionName]=value}function get(optionName){return options[optionName]}function writeCookie(){if(options.hasOwnProperty("sugSet")){var value=options.sugSet=="0"?"0":"3";clearCookie("sug");Cookie.set("sug",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("sugStoreSet")){var value=options.sugStoreSet==0?"0":"1";clearCookie("sugstore");Cookie.set("sugstore",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("isSwitch")){var ORINGIN_MAP={0:"2",1:"0",2:"1"};var value=ORINGIN_MAP[options.isSwitch];clearCookie("ORIGIN");Cookie.set("ORIGIN",value,document.domain,"/",expire30y)}if(options.hasOwnProperty("imeSwitch")){var value=options.imeSwitch; -clearCookie("bdime");Cookie.set("bdime",value,document.domain,"/",expire30y)}}function writeBAIDUID(){var BAIDUID=Cookie.get("BAIDUID"),NR,FG,SL;if(/FG=(\d+)/.test(BAIDUID)){FG=RegExp.$1}if(/SL=(\d+)/.test(BAIDUID)){SL=RegExp.$1}if(/NR=(\d+)/.test(BAIDUID)){NR=RegExp.$1}if(options.hasOwnProperty("resultNum")){NR=options.resultNum}if(options.hasOwnProperty("resultLang")){SL=options.resultLang}Cookie.set("BAIDUID",BAIDUID.replace(/:.*$/,"")+(typeof SL!="undefined"?":SL="+SL:"")+(typeof NR!="undefined"?":NR="+NR:"")+(typeof FG!="undefined"?":FG="+FG:""),".baidu.com","/",expire30y,true)}function clearCookie(name){Cookie.clear(name,"/");Cookie.clear(name,"/",document.domain);Cookie.clear(name,"/","."+document.domain);Cookie.clear(name,"/",".baidu.com")}function reset(callback){options=defaultOptions;save(callback)}window.UPS={writeBAIDUID:writeBAIDUID,reset:reset,get:get,set:set,save:save}})();(function(){var c=(navigator&&navigator.userAgent)?navigator.userAgent:"";var b=(document&&document.cookie)?document.cookie:""; -var a=!!(c.match(/(msie [2-8])/i)||(c.match(/windows.*safari/i)&&!c.match(/chrome/i))||c.match(/(linux.*firefox)/i)||c.match(/Chrome\/29/i)||c.match(/mac os x.*firefox/i)||b.match(/\bISSW=1/)||UPS.get("isSwitch")==0);if(bds&&bds.comm){bds.comm.supportis=!a;bds.comm.isui=true;bds.comm.did=(function(){var d="";for(var e=0;e<32;e++){d+=Math.floor(Math.random()*16).toString(16)}return d})()}window.__restart_confirm_timeout=true;window.__confirm_timeout=8000;window.__disable_is_guide=true;window.__disable_swap_to_empty=true;window.__switch_add_mask=true;if(window._async_merge){if(a||window.__disable_predict||window.__disable_preload){document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_async_popstate1_b205ac11.js'><\/script>")}else{document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_instant_search1_b4e855a5.js'><\/script>")}}else{document.write("<script src='http://s1.bdstatic.com/r/www/cache/static/global/js/all_async_search_d94d0497.js'><\/script>") -}if(bds.comm.newindex){$(window).on("index_off",function(){$('<div class="c-tips-container" id="c-tips-container"></div>').insertAfter("#wrapper");if(window.__sample_dynamic_tab){$("#s_tab").remove()}})}if(!c.match(/(msie 6)/i)){$(function(){setTimeout(function(){$.ajax({url:"http://s1.bdstatic.com/r/www/cache/static/baiduia/baiduia_b45d552b.js",cache:true,dataType:"script"})},0)})}$(function(){setTimeout(function(){$.ajax({url:"http://s1.bdstatic.com/r/www/cache/static/plugins/every_cookie_9643229f.js",cache:true,dataType:"script"})},0)});if(bds.comm&&bds.comm.ishome&&Cookie.get("H_PS_PSSID")){bds.comm.indexSid=Cookie.get("H_PS_PSSID")}})();</script><script>if(bds.comm.supportis){window.__restart_confirm_timeout=true;window.__confirm_timeout=8000;window.__disable_is_guide=true;window.__disable_swap_to_empty=true;}initPreload({'isui':true,'index_form':"#form",'index_kw':"#kw",'result_form':"#form",'result_kw':"#kw"});</script><script>if(navigator.cookieEnabled){document.cookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT";}</script></body></html> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/testFileIO.py b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/testFileIO.py deleted file mode 100644 index f5a4304..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/testFileIO.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -""" -#fileIO read & print -with open("py.txt") as fp: - #data = fp.read() - data = fp.readline() - print(data) -""" - - -""" -#fileIO foreach write -with open("py.txt", 'a+') as fp: - for num in range(1,10): - #fp.write("test" + str(num) + "\n" ) - fp.writelines("test" + str(num)) -""" - - -with open("py.txt", 'a+') as fp: - for line in fp.readlines(): - line = line.strip() #去除首尾空白 - print(line) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/testUrllib.py b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/testUrllib.py deleted file mode 100644 index bdecb6e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/testUrllib.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -import urllib -import urllib2 -import os -def cbk(a, b, c): - '''''回调函数 - @a: å·²ç»ä¸‹è½½çš„æ•°æ®å— - @b: æ•°æ®å—çš„å¤§å° - @c: è¿œç¨‹æ–‡ä»¶çš„å¤§å° - ''' - per = 100.0 * a * b / c - if per > 100: - per = 100 - print '%.2f%%' % per - -""" urllib下载 -url = 'http://www.sina.com.cn' -#local = '/home/rh/my_code/OpenWrt_Luci_Lua/1_7.http_proxy_server/python/testCode/sina.html' -#local = '/home/rh/my_code/OpenWrt_Luci_Lua/1_7.http_proxy_server/python/testCode/test.html' -#local = './cache/backup' - -fileName = url.split('/')[-1] -local = os.path.join('./cache',fileName) - -urllib.urlretrieve(url, local, cbk) - -""" - -#url = "http://download.meizu.com/Firmware/Flyme/m1_note/4.2/cmcc/20150507154711/61746475/update.zip" -url = "https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png" -req = urllib2.Request(url) -req.add_header('Range', 'bytes=0-7000') -response = urllib2.urlopen(req) -buffer = response.read() -with open("./cache/test1.png", "a+") as fp: - fp.write(buffer) - - -req = urllib2.Request(url) -req.add_header('Range', 'bytes=7001-14175') -response = urllib2.urlopen(req) -buffer = response.read() -with open("./cache/test2.png", "a+") as fp: - fp.write(buffer) - - - - - - - -""" urllib2下载 request失败 -url = 'http://www.sina.com.cn' -req = urllib2.Request(url) -#req.add_header('range','byte:1-100') -response = urllib2.urlopen(req) -file = response.read() - -with open("urllib2test.html", "a+") as fp: - fp.write(file) -""" -"""urlopener 失败""" -url = 'http://www.sina.com.cn' -opener = urllib2.build_opener() -#ä¸åŠ å¤´ä¿¡æ¯åˆ™å‡ºçŽ°403é”™è¯¯å’Œä¹±ç  -opener.addheaders = [('User-agent', 'Mozilla/5.0')]; -#opener.addheaders = [('range', 'byte:1-100')] -htmlAll = opener.open( url ).read() -reg1Floor = '<div class="msgfont">(.*?)</div>' -#文件ä¿å­˜ç¼–ç å’Œæ–‡ä»¶ç¼–辑编ç éƒ½æ˜¯utf-8,所以decode一次,ä¸ç„¶ä¼šå‡ºçŽ°ä¹±ç ï¼Œä½†æ˜¯ä¸å½±å“结果。 -#htmlAll.decode('utf-8') -print(htmlAll) - - diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/url2.py b/1_6.h12_dev/1_7.http_proxy_server/python/testCode/url2.py deleted file mode 100644 index 031609f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/testCode/url2.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -import urllib2 -#url = "http://download.meizu.com/Firmware/Flyme/m1_note/4.2/cmcc/20150507154711/61746475/update.zip" -url = "https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png" - -#url = "http://www.sina.com.cn" -req = urllib2.Request(url) -req.add_header('Range', 'bytes=7001-14000') -response = urllib2.urlopen(req) -#print(response.info()) - -html = response.read() -with open("test4.png", "a+") as fp: - fp.write(html) -#print html diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/CacheUtils.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/CacheUtils.py deleted file mode 100644 index e705ba2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/CacheUtils.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -import urllib -import urllib2 -import json -class CacheUtils: - @staticmethod - def cbk(a, b, c): - '''''回调函数 - @a: å·²ç»ä¸‹è½½çš„æ•°æ®å— - @b: æ•°æ®å—çš„å¤§å° - @c: è¿œç¨‹æ–‡ä»¶çš„å¤§å° - ''' - per = 100.0 * a * b / c - if per > 100: - per = 100 - print '%.2f%%' % per - - def download(self, url, local): - urllib.urlretrieve(url, local, self.cbk) - - def cache(self, url, range): - fileName = url.split('/')[-1] - req = urllib2.Request(url) - req.add_header('Range', 'bytes=' + range) - response = urllib2.urlopen(req) - buffer = response.read() - with open("./cache/" + fileName + range, "a+") as fp: - fp.write(buffer) - - def saveReq(self, url): - - # Reading data back - with open('data.json', 'r') as fp: - data = json.load(fp) - data[url] = 4000 - # Writing JSON data - with open('data.json', 'w') as fp: - json.dump(data, fp) - - - def checkReq(self): - # Reading data back - with open('data.json', 'r') as fp: - data = json.load(fp) - #print(data) - #print(data.keys()) - print(data["www.baidu.com"]) - if data.get("key"): - print(data["key"]) - else: - print("error") - -""" -if __name__ == '__main__': - cacheUtils = CacheUtils() - - #url = "http://www.sina.com.cn" - #fileName = url.split('/')[-1] - #cacheUtils.download(url, "./cache/" + fileName) - - #cacheUtils.cache("http://www.baidu.com") - #cacheUtils.cache("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png", "0-7000") - #cacheUtils.cache("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png", "7001-14175") - - cacheUtils.saveReq("http://www.sina.com.cn") - - #cacheUtils.loadReq() -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/LICENSE b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/LICENSE deleted file mode 100644 index 636ff36..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -BSD License - -For twisted-connect-proxy software - -Copyright (c) 2014 Peter Ruibal. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the copyright holder nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/README.md b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/README.md deleted file mode 100644 index fdbb438..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/README.md +++ /dev/null @@ -1,24 +0,0 @@ -twisted-connect-proxy -===================== - -Default Twisted does not ship with a CONNECT-enabled HTTP(s) proxy. This code provides one. - -This code also provides an HTTP CONNECT proxy client that implements `IReactorTCP` and `IReactorSSL` - -Proxy Server ------------- - -To run an HTTP CONNECT proxy server on port 8080, run: - - ./server.py - -That was easy. - -Proxy Client ------------- - -The HTTP CONNECT proxy reactor can be used like this: -```python -proxy = HTTPProxyConnector(proxy_host, proxy_port) - -``` diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/client.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/client.py deleted file mode 100644 index 665e80e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/client.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python -# coding=UTF-8 -# Copyright (c) 2014, Peter Ruibal. All rights reserved. -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. -# -from twisted.internet import protocol, reactor -from twisted.internet.error import CannotListenError, ConnectError -from twisted.internet.interfaces import IReactorTCP, IReactorSSL - -from twisted.protocols import tls -from twisted.python import log - -from twisted.web import http - -from zope.interface import implements - - -class ProxyConnectError(ConnectError): - pass - - -class HTTPProxyConnector(object): - """Helper to wrap reactor connection API (TCP, SSL) via a CONNECT proxy.""" - implements(IReactorTCP, IReactorSSL) - - def __init__(self, proxy_host, proxy_port, - reactor=reactor): - self.proxy_host = proxy_host - self.proxy_port = proxy_port - self.reactor = reactor - - def listenTCP(port, factory, backlog=50, interface=''): - raise CannotListenError("Cannot BIND via HTTP proxies") - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - f = HTTPProxiedClientFactory(factory, host, port) - self.reactor.connectTCP(self.proxy_host, - self.proxy_port, - f, timeout, bindAddress) - - def listenSSL(self, port, factory, contextFactory, backlog=50, interface=''): - raise CannotListenError("Cannot BIND via HTTP proxies") - - def connectSSL(self, host, port, factory, contextFactory, timeout=30, - bindAddress=None): - tlsFactory = tls.TLSMemoryBIOFactory(contextFactory, True, factory) - return self.connectTCP(host, port, tlsFactory, timeout, bindAddress) - - -class HTTPProxiedClientFactory(protocol.ClientFactory): - """ClientFactory wrapper that triggers an HTTP proxy CONNECT on connect""" - def __init__(self, delegate, dst_host, dst_port): - self.delegate = delegate - self.dst_host = dst_host - self.dst_port = dst_port - - def startedConnecting(self, connector): - return self.delegate.startedConnecting(connector) - - def buildProtocol(self, addr): - p = HTTPConnectTunneler(self.dst_host, self.dst_port, addr) - p.factory = self - return p - - def clientConnectionFailed(self, connector, reason): - return self.delegate.clientConnectionFailed(connector, reason) - - def clientConnectionLost(self, connector, reason): - return self.delegate.clientConnectionLost(connector, reason) - - -class HTTPConnectTunneler(protocol.Protocol): - """Protocol that wraps transport with CONNECT proxy handshake on connect - - `factory` MUST be assigned in order to use this Protocol, and the value - *must* have a `delegate` attribute to trigger wrapped, post-connect, - factory (creation) methods. - """ - http = None - otherConn = None - noisy = True - - def __init__(self, host, port, orig_addr): - self.host = host - self.port = port - self.orig_addr = orig_addr - - def connectionMade(self): - self.http = HTTPConnectSetup(self.host, self.port) - self.http.parent = self - self.http.makeConnection(self.transport) - - def connectionLost(self, reason): - if self.noisy: - log.msg("HTTPConnectTunneler connectionLost", reason) - - if self.otherConn is not None: - self.otherConn.connectionLost(reason) - if self.http is not None: - self.http.connectionLost(reason) - - def proxyConnected(self): - # TODO: Bail if `self.factory` is unassigned or - # does not have a `delegate` - self.otherConn = self.factory.delegate.buildProtocol(self.orig_addr) - self.otherConn.makeConnection(self.transport) - - # Get any pending data from the http buf and forward it to otherConn - buf = self.http.clearLineBuffer() - if buf: - self.otherConn.dataReceived(buf) - - def dataReceived(self, data): - if self.otherConn is not None: - if self.noisy: - log.msg("%d bytes for otherConn %s" % - (len(data), self.otherConn)) - return self.otherConn.dataReceived(data) - elif self.http is not None: - if self.noisy: - log.msg("%d bytes for proxy %s" % - (len(data), self.otherConn)) - return self.http.dataReceived(data) - else: - raise Exception("No handler for received data... :(") - - -class HTTPConnectSetup(http.HTTPClient): - """HTTPClient protocol to send a CONNECT message for proxies. - - `parent` MUST be assigned to an HTTPConnectTunneler instance, or have a - `proxyConnected` method that will be invoked post-CONNECT (http request) - """ - noisy = True - - def __init__(self, host, port): - self.host = host - self.port = port - - def connectionMade(self): - self.sendCommand('CONNECT', '%s:%d' % (self.host, self.port)) - self.endHeaders() - - def handleStatus(self, version, status, message): - if self.noisy: - log.msg("Got Status :: %s %s %s" % (status, message, version)) - if str(status) != "200": - raise ProxyConnectError("Unexpected status on CONNECT: %s" % status) - - def handleHeader(self, key, val): - if self.noisy: - log.msg("Got Header :: %s: %s" % (key, val)) - - def handleEndHeaders(self): - if self.noisy: - log.msg("End Headers") - # TODO: Make sure parent is assigned, and has a proxyConnected callback - self.parent.proxyConnected() - - def handleResponse(self, body): - if self.noisy: - log.msg("Got Response :: %s" % (body)) - - -if __name__ == '__main__': - import sys - import argparse - - log.startLogging(sys.stderr) - - ap = argparse.ArgumentParser() - ap.add_argument('--proxy-host', default='localhost') - ap.add_argument('--proxy-port', default=8080, type=int) - ns = ap.parse_args() - - proxy = HTTPProxyConnector(proxy_host=ns.proxy_host, - proxy_port=ns.proxy_port) - - def cb(*args, **kwargs): - log.msg("Got callback: args=%s, kwargs=%s" % - (args, kwargs)) - - import twisted.web.client - agent = twisted.web.client.Agent(reactor=proxy) - #d = agent.request('GET', 'https://www.google.com/robots.txt') - #d = agent.request('GET', 'http://www.baidu.com') - d = agent.request('CONNECT', 'https://www.baidu.com') - d.addCallback(cb) - - reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/server.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/server.py deleted file mode 100644 index babea09..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/server.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env python -# coding=UTF-8 -# Copyright (c) 2014, Peter Ruibal. All rights reserved. -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. -# -from twisted.internet.protocol import Protocol, ClientFactory -from twisted.web.proxy import Proxy, ProxyRequest -from twisted.python import log - -import urlparse - - -class ConnectProxyRequest(ProxyRequest): - """HTTP ProxyRequest handler (factory) that supports CONNECT""" - - connectedProtocol = None - - def process(self): - # CONNECTå¦å†™å‡½æ•°processConnectRequest实现 - if self.method == 'CONNECT': - self.processConnectRequest() - else: - ProxyRequest.process(self) - - def fail(self, message, body): - self.setResponseCode(501, message) - self.responseHeaders.addRawHeader("Content-Type", "text/html") - self.write(body) - self.finish() - - def splitHostPort(self, hostport, default_port): - port = default_port - parts = hostport.split(':', 1) - if len(parts) == 2: - try: - port = int(parts[1]) - except ValueError: - pass - return parts[0], port - - def processConnectRequest(self): - parsed = urlparse.urlparse(self.uri) - default_port = self.ports.get(parsed.scheme) - - host, port = self.splitHostPort(parsed.netloc or parsed.path, - default_port) - if port is None: - self.fail("Bad CONNECT Request", - "Unable to parse port from URI: %s" % repr(self.uri)) - return - - clientFactory = ConnectProxyClientFactory(host, port, self) - - # TODO provide an API to set proxy connect timeouts - self.reactor.connectTCP(host, port, clientFactory) - -#类似protocol,在这里作为客户端的角色 -class ConnectProxy(Proxy): - """HTTP Server Protocol that supports CONNECT""" - requestFactory = ConnectProxyRequest - connectedRemote = None - - def requestDone(self, request): - """connect请求 && 属于远程客户端的请求,则将该客户端改æˆå½“å‰ä»£ç†æœåŠ¡å™¨""" - if request.method == 'CONNECT' and self.connectedRemote is not None: - self.connectedRemote.connectedClient = self - else: - Proxy.requestDone(self, request) - - def connectionLost(self, reason): - """代ç†æœåŠ¡å™¨è¯·æ±‚webæœåŠ¡å™¨æ—¶ï¼Œè¿žæŽ¥æ–­å¼€äº† - ,也è¦é€šçŸ¥å¹¶æ–­å¼€ä»£ç†æœåŠ¡å™¨ä¸Žå®¢æˆ·ç«¯çš„连接""" - if self.connectedRemote is not None: - self.connectedRemote.transport.loseConnection() - Proxy.connectionLost(self, reason) - - def dataReceived(self, data): - # æ•°æ®æ”¶åˆ°åŽï¼Œå¦‚果代ç†æœåŠ¡å™¨è‡ªå·±çš„请求,自己接收, - if self.connectedRemote is None: - Proxy.dataReceived(self, data) - else: - # Once proxy is connected, forward all bytes received - # from the original client to the remote server. - # 如果是远程客户端的请求,则将数æ®ä¼ ç»™è¿œç¨‹å®¢æˆ·ç«¯ - self.connectedRemote.transport.write(data) - -#作为普通server角色 -class ConnectProxyClient(Protocol): - connectedClient = None - - def connectionMade(self): - self.factory.request.channel.connectedRemote = self - self.factory.request.setResponseCode(200, "CONNECT OK") - self.factory.request.setHeader('X-Connected-IP', - self.transport.realAddress[0]) - self.factory.request.setHeader('Content-Length', '0') - self.factory.request.finish() - - def connectionLost(self, reason): - if self.connectedClient is not None: - self.connectedClient.transport.loseConnection() - - def dataReceived(self, data): - if self.connectedClient is not None: - # Forward all bytes from the remote server back to the - # original connected client - self.connectedClient.transport.write(data) - else: - log.msg("UNEXPECTED DATA RECEIVED:", data) - -#æ•°æ®æ”¶åˆ°åŽä¼šæ¿€æ´»è¯¥å¯¹è±¡ -class ConnectProxyClientFactory(ClientFactory): - protocol = ConnectProxyClient - - def __init__(self, host, port, request): - self.request = request - self.host = host - self.port = port - - def clientConnectionFailed(self, connector, reason): - self.request.fail("Gateway Error", str(reason)) - - -if __name__ == '__main__': - import sys - log.startLogging(sys.stderr) - - import argparse - ap = argparse.ArgumentParser() - ap.add_argument('port', default=8080, nargs='?', type=int) - ap.add_argument('--ssl-cert', type=str) - ap.add_argument('--ssl-key', type=str) - ns = ap.parse_args() - - import twisted.web.http - factory = twisted.web.http.HTTPFactory() - factory.protocol = ConnectProxy - - import twisted.internet - if ns.ssl_key and not ns.ssl_cert: - log.msg("--ssl-key must be used with --ssl-cert") - sys.exit(1) - if ns.ssl_cert: - from twisted.internet import ssl - with open(ns.ssl_cert, 'rb') as fp: - ssl_cert = fp.read() - if ns.ssl_key: - from OpenSSL import crypto - with open(ns.ssl_key, 'rb') as fp: - ssl_key = fp.read() - certificate = ssl.PrivateCertificate.load( - ssl_cert, - ssl.KeyPair.load(ssl_key, crypto.FILETYPE_PEM), - crypto.FILETYPE_PEM) - else: - certificate = ssl.PrivateCertificate.loadPEM(ssl_cert) - twisted.internet.reactor.listenSSL(ns.port, factory, - certificate.options()) - else: - twisted.internet.reactor.listenTCP(ns.port, factory) - twisted.internet.reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/tags b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/tags deleted file mode 100644 index d5a8e0a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-connect-proxy/tags +++ /dev/null @@ -1,66 +0,0 @@ -!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ -!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ -!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ -!_TAG_PROGRAM_NAME Exuberant Ctags // -!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ -!_TAG_PROGRAM_VERSION 5.9~svn20110310 // -ConnectProxy server.py /^class ConnectProxy(Proxy):$/;" c -ConnectProxyClient server.py /^class ConnectProxyClient(Protocol):$/;" c -ConnectProxyClientFactory server.py /^class ConnectProxyClientFactory(ClientFactory):$/;" c -ConnectProxyRequest server.py /^class ConnectProxyRequest(ProxyRequest):$/;" c -HTTPConnectSetup client.py /^class HTTPConnectSetup(http.HTTPClient):$/;" c -HTTPConnectTunneler client.py /^class HTTPConnectTunneler(protocol.Protocol):$/;" c -HTTPProxiedClientFactory client.py /^class HTTPProxiedClientFactory(protocol.ClientFactory):$/;" c -HTTPProxyConnector client.py /^class HTTPProxyConnector(object):$/;" c -ProxyConnectError client.py /^class ProxyConnectError(ConnectError):$/;" c -__init__ client.py /^ def __init__(self, delegate, dst_host, dst_port):$/;" m class:HTTPProxiedClientFactory -__init__ client.py /^ def __init__(self, host, port):$/;" m class:HTTPConnectSetup -__init__ client.py /^ def __init__(self, host, port, orig_addr):$/;" m class:HTTPConnectTunneler -__init__ client.py /^ def __init__(self, proxy_host, proxy_port,$/;" m class:HTTPProxyConnector -__init__ server.py /^ def __init__(self, host, port, request):$/;" m class:ConnectProxyClientFactory -agent client.py /^ agent = twisted.web.client.Agent(reactor=proxy)$/;" v -ap client.py /^ ap = argparse.ArgumentParser()$/;" v -ap server.py /^ ap = argparse.ArgumentParser()$/;" v -buildProtocol client.py /^ def buildProtocol(self, addr):$/;" m class:HTTPProxiedClientFactory -cb client.py /^ def cb(*args, **kwargs):$/;" f -clientConnectionFailed client.py /^ def clientConnectionFailed(self, connector, reason):$/;" m class:HTTPProxiedClientFactory -clientConnectionFailed server.py /^ def clientConnectionFailed(self, connector, reason):$/;" m class:ConnectProxyClientFactory -clientConnectionLost client.py /^ def clientConnectionLost(self, connector, reason):$/;" m class:HTTPProxiedClientFactory -connectSSL client.py /^ def connectSSL(self, host, port, factory, contextFactory, timeout=30,$/;" m class:HTTPProxyConnector -connectTCP client.py /^ def connectTCP(self, host, port, factory, timeout=30, bindAddress=None):$/;" m class:HTTPProxyConnector -connectedClient server.py /^ connectedClient = None$/;" v class:ConnectProxyClient -connectedProtocol server.py /^ connectedProtocol = None$/;" v class:ConnectProxyRequest -connectedRemote server.py /^ connectedRemote = None$/;" v class:ConnectProxy -connectionLost client.py /^ def connectionLost(self, reason):$/;" m class:HTTPConnectTunneler -connectionLost server.py /^ def connectionLost(self, reason):$/;" m class:ConnectProxy -connectionLost server.py /^ def connectionLost(self, reason):$/;" m class:ConnectProxyClient -connectionMade client.py /^ def connectionMade(self):$/;" m class:HTTPConnectSetup -connectionMade client.py /^ def connectionMade(self):$/;" m class:HTTPConnectTunneler -connectionMade server.py /^ def connectionMade(self):$/;" m class:ConnectProxyClient -d client.py /^ d = agent.request('CONNECT', 'https:\/\/www.baidu.com')$/;" v -dataReceived client.py /^ def dataReceived(self, data):$/;" m class:HTTPConnectTunneler -dataReceived server.py /^ def dataReceived(self, data):$/;" m class:ConnectProxy -dataReceived server.py /^ def dataReceived(self, data):$/;" m class:ConnectProxyClient -factory server.py /^ factory = twisted.web.http.HTTPFactory()$/;" v -fail server.py /^ def fail(self, message, body):$/;" m class:ConnectProxyRequest -handleEndHeaders client.py /^ def handleEndHeaders(self):$/;" m class:HTTPConnectSetup -handleHeader client.py /^ def handleHeader(self, key, val):$/;" m class:HTTPConnectSetup -handleResponse client.py /^ def handleResponse(self, body):$/;" m class:HTTPConnectSetup -handleStatus client.py /^ def handleStatus(self, version, status, message):$/;" m class:HTTPConnectSetup -http client.py /^ http = None$/;" v class:HTTPConnectTunneler -listenSSL client.py /^ def listenSSL(self, port, factory, contextFactory, backlog=50, interface=''):$/;" m class:HTTPProxyConnector -listenTCP client.py /^ def listenTCP(port, factory, backlog=50, interface=''):$/;" m class:HTTPProxyConnector -noisy client.py /^ noisy = True$/;" v class:HTTPConnectSetup -noisy client.py /^ noisy = True$/;" v class:HTTPConnectTunneler -ns client.py /^ ns = ap.parse_args()$/;" v -ns server.py /^ ns = ap.parse_args()$/;" v -otherConn client.py /^ otherConn = None$/;" v class:HTTPConnectTunneler -process server.py /^ def process(self):$/;" m class:ConnectProxyRequest -processConnectRequest server.py /^ def processConnectRequest(self):$/;" m class:ConnectProxyRequest -protocol server.py /^ protocol = ConnectProxyClient$/;" v class:ConnectProxyClientFactory -proxy client.py /^ proxy = HTTPProxyConnector(proxy_host=ns.proxy_host,$/;" v -proxyConnected client.py /^ def proxyConnected(self):$/;" m class:HTTPConnectTunneler -requestDone server.py /^ def requestDone(self, request):$/;" m class:ConnectProxy -requestFactory server.py /^ requestFactory = ConnectProxyRequest$/;" v class:ConnectProxy -splitHostPort server.py /^ def splitHostPort(self, hostport, default_port):$/;" m class:ConnectProxyRequest -startedConnecting client.py /^ def startedConnecting(self, connector):$/;" m class:HTTPProxiedClientFactory diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/.gitignore b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/.gitignore deleted file mode 100644 index a1e70eb..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -twistd.log* -twistd.pid -*.pyc -_trial_temp -twisted/plugins/dropin.cache diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/LICENSE b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/LICENSE deleted file mode 100644 index f99dfaa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2009-2010 Dave Peticolas - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/README b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/README deleted file mode 100644 index 26c8ef7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/README +++ /dev/null @@ -1,6 +0,0 @@ -These are the supporting files for an introduction to Twisted -and asynchronous programming in Python located here: - - http://krondo.com/?page_id=1327 - -Dave Peticolas <dave@krondo.com> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/async-client/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/async-client/get-poetry.py deleted file mode 100644 index 2fb1f44..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/async-client/get-poetry.py +++ /dev/null @@ -1,139 +0,0 @@ -# This is the asynchronous Get Poetry Now! client. - -import datetime, errno, optparse, select, socket - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, asynchronous edition. -Run it like this: - - python get-poetry.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python async-client/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -def get_poetry(sockets): - """Download poety from all the given sockets.""" - - poems = dict.fromkeys(sockets, '') # socket -> accumulated poem - - # socket -> task numbers - sock2task = dict([(s, i + 1) for i, s in enumerate(sockets)]) - - sockets = list(sockets) # make a copy - - # we go around this loop until we've gotten all the poetry - # from all the sockets. This is the 'reactor loop'. - - while sockets: - # this select call blocks until one or more of the - # sockets is ready for read I/O - rlist, _, _ = select.select(sockets, [], []) - - # rlist is the list of sockets with data ready to read - - for sock in rlist: - data = '' - - while True: - try: - new_data = sock.recv(1024) - except socket.error, e: - if e.args[0] == errno.EWOULDBLOCK: - # this error code means we would have - # blocked if the socket was blocking. - # instead we skip to the next socket - break - raise - else: - if not new_data: - break - else: - data += new_data - - # Each execution of this inner loop corresponds to - # working on one asynchronous task in Figure 3 here: - # http://krondo.com/?p=1209#figure3 - - task_num = sock2task[sock] - - if not data: - sockets.remove(sock) - sock.close() - print 'Task %d finished' % task_num - else: - addr_fmt = format_address(sock.getpeername()) - msg = 'Task %d: got %d bytes of poetry from %s' - print msg % (task_num, len(data), addr_fmt) - - poems[sock] += data - - return poems - - -def connect(address): - """Connect to the given server and return a non-blocking socket.""" - - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect(address) - sock.setblocking(0) - return sock - - -def format_address(address): - host, port = address - return '%s:%s' % (host or '127.0.0.1', port) - - -def main(): - addresses = parse_args() - - start = datetime.datetime.now() - - sockets = map(connect, addresses) - - poems = get_poetry(sockets) - - elapsed = datetime.datetime.now() - start - - for i, sock in enumerate(sockets): - print 'Task %d: %d bytes of poetry' % (i + 1, len(poems[sock])) - - print 'Got %d poems in %s' % (len(addresses), elapsed) - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/countdown.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/countdown.py deleted file mode 100644 index 4dbdec2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/countdown.py +++ /dev/null @@ -1,20 +0,0 @@ - -class Countdown(object): - - counter = 5 - - def count(self): - if self.counter == 0: - reactor.stop() - else: - print self.counter, '...' - self.counter -= 1 - reactor.callLater(1, self.count) - -from twisted.internet import reactor - -reactor.callWhenRunning(Countdown().count) - -print 'Start!' -reactor.run() -print 'Stop!' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/exception.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/exception.py deleted file mode 100644 index 2395588..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/exception.py +++ /dev/null @@ -1,15 +0,0 @@ - -def falldown(): - raise Exception('I fall down.') - -def upagain(): - print 'But I get up again.' - reactor.stop() - -from twisted.internet import reactor - -reactor.callWhenRunning(falldown) -reactor.callWhenRunning(upagain) - -print 'Starting the reactor.' -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/hello.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/hello.py deleted file mode 100644 index abfb20e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/hello.py +++ /dev/null @@ -1,11 +0,0 @@ - -def hello(): - print 'Hello from the reactor loop!' - print 'Lately I feel like I\'m stuck in a rut.' - -from twisted.internet import reactor - -reactor.callWhenRunning(hello) - -print 'Starting the reactor.' -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/log.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/log.py deleted file mode 100644 index 8488579..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/log.py +++ /dev/null @@ -1,35 +0,0 @@ -import sys - -from twisted.python import log -from twisted.internet import defer - -"""This example illustrates some Twisted logging basics.""" - -log.msg('This will not be logged, we have not installed a logger.') - -log.startLogging(sys.stdout) - -log.msg('This will be logged.') -log.err('This will be logged as an error.') - -def bad_callback(result): - xxx - -try: - bad_callback() -except: - log.err('The next function call will log the traceback as an error.') - log.err() - -d = defer.Deferred() - -def on_error(failure): - log.err('The next function call will log the failure as an error.') - log.err(failure) - -d.addCallback(bad_callback) -d.addErrback(on_error) - -d.callback(True) - -log.msg('End of example.') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/simple-poll.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/simple-poll.py deleted file mode 100644 index 4392f39..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/simple-poll.py +++ /dev/null @@ -1,5 +0,0 @@ -from twisted.internet import pollreactor -pollreactor.install() - -from twisted.internet import reactor -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/simple.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/simple.py deleted file mode 100644 index 0561510..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/simple.py +++ /dev/null @@ -1,2 +0,0 @@ -from twisted.internet import reactor -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/stack.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/stack.py deleted file mode 100644 index cfe3683..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/basic-twisted/stack.py +++ /dev/null @@ -1,9 +0,0 @@ -import traceback - -def stack(): - print 'The python stack:' - traceback.print_stack() - -from twisted.internet import reactor -reactor.callWhenRunning(stack) -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/blocking-client/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/blocking-client/get-poetry.py deleted file mode 100644 index d080b30..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/blocking-client/get-poetry.py +++ /dev/null @@ -1,107 +0,0 @@ -# This is the blocking Get Poetry Now! client. - -import datetime, optparse, socket - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, blocking edition. -Run it like this: - - python get-poetry.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python blocking-client/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -def get_poetry(address): - """Download a piece of poetry from the given address.""" - - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect(address) - - poem = '' - - while True: - - # This is the 'blocking' call in this synchronous program. - # The recv() method will block for an indeterminate period - # of time waiting for bytes to be received from the server. - - data = sock.recv(1024) - - if not data: - sock.close() - break - - poem += data - - return poem - - -def format_address(address): - host, port = address - return '%s:%s' % (host or '127.0.0.1', port) - - -def main(): - addresses = parse_args() - - elapsed = datetime.timedelta() - - for i, address in enumerate(addresses): - addr_fmt = format_address(address) - - print 'Task %d: get poetry from: %s' % (i + 1, addr_fmt) - - start = datetime.datetime.now() - - # Each execution of 'get_poetry' corresponds to the - # execution of one synchronous task in Figure 1 here: - # http://krondo.com/?p=1209#figure1 - - poem = get_poetry(address) - - time = datetime.datetime.now() - start - - msg = 'Task %d: got %d bytes of poetry from %s in %s' - print msg % (i + 1, len(poem), addr_fmt, time) - - elapsed += time - - print 'Got %d poems in %s' % (len(addresses), elapsed) - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/blocking-server/slowpoetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/blocking-server/slowpoetry.py deleted file mode 100644 index 4cd8d08..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/blocking-server/slowpoetry.py +++ /dev/null @@ -1,98 +0,0 @@ -# This is the blocking version of the Slow Poetry Server. - -import optparse, os, socket, time - - -def parse_args(): - usage = """usage: %prog [options] poetry-file - -This is the Slow Poetry Server, blocking edition. -Run it like this: - - python slowpoetry.py <path-to-poetry-file> - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python blocking-server/slowpoetry.py poetry/ecstasy.txt - -to serve up John Donne's Ecstasy, which I know you want to do. -""" - - parser = optparse.OptionParser(usage) - - help = "The port to listen on. Default to a random available port." - parser.add_option('--port', type='int', help=help) - - help = "The interface to listen on. Default is localhost." - parser.add_option('--iface', help=help, default='localhost') - - help = "The number of seconds between sending bytes." - parser.add_option('--delay', type='float', help=help, default=.7) - - help = "The number of bytes to send at a time." - parser.add_option('--num-bytes', type='int', help=help, default=10) - - options, args = parser.parse_args() - - if len(args) != 1: - parser.error('Provide exactly one poetry file.') - - poetry_file = args[0] - - if not os.path.exists(args[0]): - parser.error('No such file: %s' % poetry_file) - - return options, poetry_file - - -def send_poetry(sock, poetry_file, num_bytes, delay): - """Send some poetry slowly down the socket.""" - - inputf = open(poetry_file) - - while True: - bytes = inputf.read(num_bytes) - - if not bytes: # no more poetry :( - sock.close() - inputf.close() - return - - print 'Sending %d bytes' % len(bytes) - - try: - sock.sendall(bytes) # this is a blocking call - except socket.error: - sock.close() - inputf.close() - return - - time.sleep(delay) - - -def serve(listen_socket, poetry_file, num_bytes, delay): - while True: - sock, addr = listen_socket.accept() - - print 'Somebody at %s wants poetry!' % (addr,) - - send_poetry(sock, poetry_file, num_bytes, delay) - - -def main(): - options, poetry_file= parse_args() - - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((options.iface, options.port or 0)) - - sock.listen(5) - - print 'Serving %s on port %s.' % (poetry_file, sock.getsockname()[1]) - - serve(sock, poetry_file, options.num_bytes, options.delay) - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-1.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-1.py deleted file mode 100644 index 40f341f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-1.py +++ /dev/null @@ -1,9 +0,0 @@ -from twisted.internet import defer - -def callback(res): - print 'callback got:', res - -d = defer.Deferred() -d.addCallback(callback) -d.cancel() -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-10.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-10.py deleted file mode 100644 index ed2490a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-10.py +++ /dev/null @@ -1,32 +0,0 @@ -from twisted.internet.defer import Deferred - -def send_poem(d): - print 'Sending poem' - d.callback('Once upon a midnight dreary') - -def get_poem(): - """Return a poem 5 seconds later.""" - from twisted.internet import reactor - d = Deferred() - reactor.callLater(5, send_poem, d) - return d - - -def got_poem(poem): - print 'I got a poem:', poem - -def poem_error(err): - print 'get_poem failed:', err - -def main(): - from twisted.internet import reactor - reactor.callLater(10, reactor.stop) # stop the reactor in 10 seconds - - d = get_poem() - d.addCallbacks(got_poem, poem_error) - - reactor.callLater(2, d.cancel) # cancel after 2 seconds - - reactor.run() - -main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-11.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-11.py deleted file mode 100644 index b16761a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-11.py +++ /dev/null @@ -1,45 +0,0 @@ -from twisted.internet.defer import Deferred - -def send_poem(d): - print 'Sending poem' - d.callback('Once upon a midnight dreary') - -def get_poem(): - """Return a poem 5 seconds later.""" - - def canceler(d): - # They don't want the poem anymore, so cancel the delayed call - delayed_call.cancel() - - # At this point we have three choices: - # 1. Do nothing, and the deferred will fire the errback - # chain with CancelledError. - # 2. Fire the errback chain with a different error. - # 3. Fire the callback chain with an alternative result. - - d = Deferred(canceler) - - from twisted.internet import reactor - delayed_call = reactor.callLater(5, send_poem, d) - - return d - - -def got_poem(poem): - print 'I got a poem:', poem - -def poem_error(err): - print 'get_poem failed:', err - -def main(): - from twisted.internet import reactor - reactor.callLater(10, reactor.stop) # stop the reactor in 10 seconds - - d = get_poem() - d.addCallbacks(got_poem, poem_error) - - reactor.callLater(2, d.cancel) # cancel after 2 seconds - - reactor.run() - -main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-12.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-12.py deleted file mode 100644 index c8e86c4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-12.py +++ /dev/null @@ -1,33 +0,0 @@ -from twisted.internet import defer - -def cancel_outer(d): - print "outer cancel callback." - -def cancel_inner(d): - print "inner cancel callback." - -def first_outer_callback(res): - print 'first outer callback, returning inner deferred' - return inner_d - -def second_outer_callback(res): - print 'second outer callback got:', res - -def outer_errback(err): - print 'outer errback got:', err - -outer_d = defer.Deferred(cancel_outer) -inner_d = defer.Deferred(cancel_inner) - -outer_d.addCallback(first_outer_callback) -outer_d.addCallbacks(second_outer_callback, outer_errback) - -outer_d.callback('result') - -# at this point the outer deferred has fired, but is paused -# on the inner deferred. - -print 'canceling outer deferred.' -outer_d.cancel() - -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-2.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-2.py deleted file mode 100644 index 2b27a98..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-2.py +++ /dev/null @@ -1,12 +0,0 @@ -from twisted.internet import defer - -def callback(res): - print 'callback got:', res - -def errback(err): - print 'errback got:', err - -d = defer.Deferred() -d.addCallbacks(callback, errback) -d.cancel() -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-3.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-3.py deleted file mode 100644 index 341fb56..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-3.py +++ /dev/null @@ -1,13 +0,0 @@ -from twisted.internet import defer - -def callback(res): - print 'callback got:', res - -def errback(err): - print 'errback got:', err - -d = defer.Deferred() -d.addCallbacks(callback, errback) -d.callback('result') -d.cancel() -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-4.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-4.py deleted file mode 100644 index f5cc666..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-4.py +++ /dev/null @@ -1,13 +0,0 @@ -from twisted.internet import defer - -def callback(res): - print 'callback got:', res - -def errback(err): - print 'errback got:', err - -d = defer.Deferred() -d.addCallbacks(callback, errback) -d.cancel() -d.callback('result') -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-5.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-5.py deleted file mode 100644 index b13b8e4..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-5.py +++ /dev/null @@ -1,15 +0,0 @@ -from twisted.internet import defer - -def canceller(d): - print "I need to cancel this deferred:", d - -def callback(res): - print 'callback got:', res - -def errback(err): - print 'errback got:', err - -d = defer.Deferred(canceller) # created by lower-level code -d.addCallbacks(callback, errback) # added by higher-level code -d.cancel() -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-6.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-6.py deleted file mode 100644 index a5290d9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-6.py +++ /dev/null @@ -1,17 +0,0 @@ -from twisted.internet import defer - -def canceller(d): - print "I need to cancel this deferred:", d - print "Firing the deferred with a result" - d.callback('result') - -def callback(res): - print 'callback got:', res - -def errback(err): - print 'errback got:', err - -d = defer.Deferred(canceller) # created by lower-level code -d.addCallbacks(callback, errback) # added by higher-level code -d.cancel() -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-7.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-7.py deleted file mode 100644 index 600a763..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-7.py +++ /dev/null @@ -1,17 +0,0 @@ -from twisted.internet import defer - -def canceller(d): - print "I need to cancel this deferred:", d - print "Firing the deferred with an error" - d.errback(Exception('error!')) - -def callback(res): - print 'callback got:', res - -def errback(err): - print 'errback got:', err - -d = defer.Deferred(canceller) # created by lower-level code -d.addCallbacks(callback, errback) # added by higher-level code -d.cancel() -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-8.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-8.py deleted file mode 100644 index 73fe934..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-8.py +++ /dev/null @@ -1,16 +0,0 @@ -from twisted.internet import defer - -def canceller(d): - print "I need to cancel this deferred:", d - -def callback(res): - print 'callback got:', res - -def errback(err): - print 'errback got:', err - -d = defer.Deferred(canceller) # created by lower-level code -d.addCallbacks(callback, errback) # added by higher-level code -d.callback('result') -d.cancel() -print 'done' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-9.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-9.py deleted file mode 100644 index c3c967b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-cancel/defer-cancel-9.py +++ /dev/null @@ -1,30 +0,0 @@ -from twisted.internet.defer import Deferred - -def send_poem(d): - print 'Sending poem' - d.callback('Once upon a midnight dreary') - -def get_poem(): - """Return a poem 5 seconds later.""" - from twisted.internet import reactor - d = Deferred() - reactor.callLater(5, send_poem, d) - return d - - -def got_poem(poem): - print 'I got a poem:', poem - -def poem_error(err): - print 'get_poem failed:', err - -def main(): - from twisted.internet import reactor - reactor.callLater(10, reactor.stop) # stop the reactor in 10 seconds - - d = get_poem() - d.addCallbacks(got_poem, poem_error) - - reactor.run() - -main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-1.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-1.py deleted file mode 100644 index 9f36aea..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-1.py +++ /dev/null @@ -1,9 +0,0 @@ -from twisted.internet import defer - -def got_results(res): - print 'We got:', res - -print 'Empty List.' -d = defer.DeferredList([]) -print 'Adding Callback.' -d.addCallback(got_results) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-2.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-2.py deleted file mode 100644 index 283435d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-2.py +++ /dev/null @@ -1,12 +0,0 @@ -from twisted.internet import defer - -def got_results(res): - print 'We got:', res - -print 'One Deferred.' -d1 = defer.Deferred() -d = defer.DeferredList([d1]) -print 'Adding Callback.' -d.addCallback(got_results) -print 'Firing d1.' -d1.callback('d1 result') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-3.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-3.py deleted file mode 100644 index 04fd448..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-3.py +++ /dev/null @@ -1,15 +0,0 @@ -from twisted.internet import defer - -def got_results(res): - print 'We got:', res - -print 'Two Deferreds.' -d1 = defer.Deferred() -d2 = defer.Deferred() -d = defer.DeferredList([d1, d2]) -print 'Adding Callback.' -d.addCallback(got_results) -print 'Firing d1.' -d1.callback('d1 result') -print 'Firing d2.' -d2.callback('d2 result') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-4.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-4.py deleted file mode 100644 index 29135d3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-4.py +++ /dev/null @@ -1,15 +0,0 @@ -from twisted.internet import defer - -def got_results(res): - print 'We got:', res - -print 'Two Deferreds.' -d1 = defer.Deferred() -d2 = defer.Deferred() -d = defer.DeferredList([d1, d2]) -print 'Adding Callback.' -d.addCallback(got_results) -print 'Firing d2.' -d2.callback('d2 result') -print 'Firing d1.' -d1.callback('d1 result') diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-5.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-5.py deleted file mode 100644 index 34c2b6b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-5.py +++ /dev/null @@ -1,13 +0,0 @@ -from twisted.internet import defer - -def got_results(res): - print 'We got:', res - -d1 = defer.Deferred() -d2 = defer.Deferred() -d = defer.DeferredList([d1, d2], consumeErrors=True) -d.addCallback(got_results) -print 'Firing d1.' -d1.callback('d1 result') -print 'Firing d2 with errback.' -d2.errback(Exception('d2 failure')) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-6.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-6.py deleted file mode 100644 index eabbbf7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-6.py +++ /dev/null @@ -1,13 +0,0 @@ -from twisted.internet import defer - -def got_results(res): - print 'We got:', res - -d1 = defer.Deferred() -d2 = defer.Deferred() -d = defer.DeferredList([d1, d2]) -d.addCallback(got_results) -print 'Firing d1.' -d1.callback('d1 result') -print 'Firing d2 with errback.' -d2.errback(Exception('d2 failure')) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-7.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-7.py deleted file mode 100644 index ef1387d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/deferred-list/deferred-list-7.py +++ /dev/null @@ -1,14 +0,0 @@ -from twisted.internet import defer - -def got_results(res): - print 'We got:', res - -d1 = defer.Deferred() -d2 = defer.Deferred() -d = defer.DeferredList([d1, d2]) -d2.addErrback(lambda err: None) # handle d2 error -d.addCallback(got_results) -print 'Firing d1.' -d1.callback('d1 result') -print 'Firing d2 with errback.' -d2.errback(Exception('d2 failure')) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/erlang-client-1/get-poetry b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/erlang-client-1/get-poetry deleted file mode 100755 index 6615fc3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/erlang-client-1/get-poetry +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- -%%! -smp enable - --mode(compile). - - -usage() -> - io:format("usage: get-poetry [hostname]:port ... - -This is the Get Poetry Now! client, Erlang Edition. -Run it like this: - - get-poetry port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - erlang-client/get-poetry 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -"), - halt(1). - - -parse_args(Args) -> - try - [parse_addr(Arg) || Arg <- Args] - catch - _:_ -> - usage() - end. - - -parse_addr(Addr) -> - parse_addr(Addr, []). - -parse_addr([], Accum) -> - {"localhost", erlang:list_to_integer(lists:reverse(Accum))}; -parse_addr([$:|Addr], Accum) -> - {lists:reverse(Accum), erlang:list_to_integer(Addr)}; -parse_addr([Ch|Addr], Accum) -> - parse_addr(Addr, [Ch|Accum]). - - -enumerate(L) -> - enumerate(L, 1). - -enumerate([], _) -> - []; -enumerate([X|Xs], N) -> - [{N, X} | enumerate(Xs, N+1)]. - - -collect_poems(0, Poems) -> - [io:format("~s\n", [P]) || P <- Poems]; -collect_poems(N, Poems) -> - receive - {'DOWN', _, _, _, _} -> - collect_poems(N-1, Poems); - {poem, Poem} -> - collect_poems(N, [Poem|Poems]) - end. - - -peername(Socket) -> - {ok, {IP, Port}} = inet:peername(Socket), - format_ip(IP) ++ ":" ++ erlang:integer_to_list(Port). - -format_ip(IP) when is_tuple(IP) -> - format_ip(erlang:tuple_to_list(IP)); -format_ip(IP) -> - string:join([erlang:integer_to_list(N) || N <- IP], ":"). - - -get_poetry(Tasknum, Addr, Main) -> - {Host, Port} = Addr, - {ok, Socket} = gen_tcp:connect(Host, Port, - [binary, {active, false}, {packet, 0}]), - get_poetry(Tasknum, Socket, Main, []). - -get_poetry(Tasknum, Socket, Main, Packets) -> - case gen_tcp:recv(Socket, 0) of - {ok, Packet} -> - io:format("Task ~w: got ~w bytes of poetry from ~s\n", - [Tasknum, size(Packet), peername(Socket)]), - get_poetry(Tasknum, Socket, Main, [Packet|Packets]); - {error, _} -> - Main ! {poem, list_to_binary(lists:reverse(Packets))} - end. - - -main([]) -> - usage(); - -main(Args) -> - Addresses = parse_args(Args), - Main = self(), - [erlang:spawn_monitor(fun () -> get_poetry(TaskNum, Addr, Main) end) - || {TaskNum, Addr} <- enumerate(Addresses)], - collect_poems(length(Addresses), []). diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-1/.gitignore b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-1/.gitignore deleted file mode 100644 index 77f73c1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-1/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.o -*.hi -get-poetry diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-1/get-poetry.hs b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-1/get-poetry.hs deleted file mode 100644 index a64da3f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-1/get-poetry.hs +++ /dev/null @@ -1,79 +0,0 @@ -{- -A Get Poetry Now! client in Haskell. - -Avert your eyes, I don't really know what I'm doing. -This just illustrates Haskell's use of asynchronous IO. - -To build the program, run this: - - ghc --make get-poetry.hs - -Then run it like this: - - ./get-poetry 10000 10001 10002 - -You'll need to have poetry servers running on those ports, of course. --} - -import Network -import System.IO -import System.Environment -import Control.Concurrent -import Control.Exception - -data Task = - Task { taskNum :: Int, - taskHostname :: HostName, - taskPort :: PortNumber } - deriving (Show) - - -parseServer :: String -> (HostName, PortNumber) -parseServer arg - | ':' `elem` arg = (host, to_port portstr) - | otherwise = ("localhost", to_port arg) - where - (host, (_:portstr)) = break ((==) ':') arg - to_port = fromIntegral . (read :: String -> Integer) - -makeTasks :: [String] -> [Task] -makeTasks args = zipWith makeTask args [1..] - where - makeTask arg num = - let (host, port) = parseServer arg - in Task { taskNum = num, - taskHostname = host, - taskPort = port } - -getPoetry :: Handle -> Task -> IO () -getPoetry h task = do - -- it looks like we read the whole poem here, but Haskell is lazy, - -- like Python generators, or some programmers you may know - poem <- hGetContents h - mapM_ gotLine $ lines poem - putStrLn poem - where - prefix = "Task " ++ (show $ taskNum task) ++ ": got " - suffix = concat [" bytes of poetry from ", - (taskHostname task), ":", - (show $ taskPort task)] - gotLine line = - putStrLn $ prefix ++ (show numbytes) ++ suffix - where numbytes = (length line) + 1 - -runTask :: Task -> IO (MVar ()) -runTask task = do - h <- connectTo (taskHostname task) (PortNumber $ taskPort task) - - mvar <- newEmptyMVar - - -- read each poem in a Haskell lightweight thread - _ <- forkIO $ getPoetry h task `finally` putMVar mvar () - - return mvar - -main :: IO () -main = do - args <- getArgs - mvars <- mapM runTask $ makeTasks args - mapM_ takeMVar mvars -- wait for all the threads to finish diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-2/.gitignore b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-2/.gitignore deleted file mode 100644 index 77f73c1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-2/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.o -*.hi -get-poetry diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-2/get-poetry.hs b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-2/get-poetry.hs deleted file mode 100644 index 00fe2c5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/haskell-client-2/get-poetry.hs +++ /dev/null @@ -1,44 +0,0 @@ -{- -A Get Poetry Now! client in Haskell. - -Avert your eyes, I don't really know what I'm doing. -This just illustrates Haskell's use of asynchronous IO. - -To build the program, run this: - - ghc --make get-poetry.hs - -Then run it like this: - - ./get-poetry 10000 10001 10002 - -You'll need to have poetry servers running on those ports, of course. --} - -import Network -import System.IO -import System.Environment -import Control.Concurrent - -parseServer :: String -> (HostName, PortNumber) -parseServer arg - | ':' `elem` arg = (host, to_port portstr) - | otherwise = ("localhost", to_port arg) - where - (host, (_:portstr)) = break ((==) ':') arg - to_port = fromIntegral . (read :: String -> Integer) - -getPoem :: (HostName, PortNumber) -> IO (MVar String) -getPoem (host, port) = do - mvar <- newEmptyMVar - _ <- forkIO (do h <- connectTo host (PortNumber $ port) - poem <- hGetContents h - putMVar mvar poem) - return mvar - -main :: IO () -main = do - args <- getArgs - mvars <- mapM getPoem (map parseServer args) - mapM_ (\mvar -> do poem <- takeMVar mvar - putStrLn poem) mvars diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/.gitignore b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/.gitignore deleted file mode 100644 index e33609d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.png diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/Makefile b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/Makefile deleted file mode 100644 index ebf487e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -CONVERT=convert -SOURCES=*.svg -IMAGES=$(SOURCES:.svg=.png) - -all: $(SOURCES) $(IMAGES) - -%.png : %.svg - $(CONVERT) $< $@ - -clean: - rm *.png diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/application.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/application.svg deleted file mode 100644 index f44a0c3..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/application.svg +++ /dev/null @@ -1,842 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="350.67001" - height="277.07999" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="application.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/application.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4552" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective3669" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3696" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3979" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4219" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4328" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4356" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-4" - style="overflow:visible"> - <path - id="path3871-5-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4384" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4511" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-0" - style="overflow:visible"> - <path - id="path3871-5-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-7" - style="overflow:visible"> - <path - id="path4552-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-47" - style="overflow:visible"> - <path - id="path3871-5-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005-9" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-77" - style="overflow:visible"> - <path - id="path4552-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-41" - style="overflow:visible"> - <path - id="path3871-5-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5056" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5110" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5154" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5182" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-64" - style="overflow:visible"> - <path - id="path3871-16" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5210" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-5" - style="overflow:visible"> - <path - id="path4552-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-9" - style="overflow:visible"> - <path - id="path3871-5-15" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5462" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5522" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-09" - style="overflow:visible"> - <path - id="path3871-5-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5713" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-1" - style="overflow:visible"> - <path - id="path3871-5-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5741" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-00" - style="overflow:visible"> - <path - id="path3871-5-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5788" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5836" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5903" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-91" - style="overflow:visible"> - <path - id="path3871-5-89" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5931" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-6" - style="overflow:visible"> - <path - id="path3871-5-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5994" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5994-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6066" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-5" - style="overflow:visible"> - <path - id="path3871-5-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6094" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-3" - style="overflow:visible"> - <path - id="path3871-5-29" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6094-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-39" - style="overflow:visible"> - <path - id="path3871-5-49" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6137" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-08" - style="overflow:visible"> - <path - id="path3871-5-35" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6182" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-2" - style="overflow:visible"> - <path - id="path3871-5-25" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6559" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6590" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6643" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.019148" - inkscape:cx="83.259152" - inkscape:cy="39.891461" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="false" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:object-paths="true" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-smooth-nodes="true" - inkscape:snap-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="3.8850459,741.09642" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="86.717556,327.94403" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(57.080616,-25.750116)"> - <g - id="g5130-7" - transform="translate(-343.41623,-183.43568)"> - <rect - y="219.18733" - x="411.13821" - height="52.004227" - width="101.06481" - id="rect3686-6-9-9-5" - style="opacity:0.98999999;fill:#bbef95;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-9" - y="249.33345" - x="461.8735" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="249.33345" - x="461.8735" - sodipodi:role="line" - id="tspan5086-7">Application</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart-5);marker-end:url(#Arrow2Lend-9)" - d="m 168.78677,191.76375 37.77667,49.06059" - id="path3999-1-61-1" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart-5);marker-end:url(#Arrow2Lend-9)" - d="m 118.25438,87.75588 0,52.00365" - id="path3999-1-61-1-5-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart-5);marker-end:url(#Arrow2Lend-9)" - d="M 27.982893,240.82434 67.721985,191.76375" - id="path3999-1-61-1-5-9-2" - sodipodi:nodetypes="cc" /> - <g - id="g5130-7-1" - transform="translate(-343.41623,-79.427803)"> - <rect - y="219.18733" - x="411.13821" - height="52.004227" - width="101.06481" - id="rect3686-6-9-9-5-3" - style="opacity:0.98999999;fill:#e29eda;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-9-0" - y="250.99745" - x="461.76849" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="250.99745" - x="461.76849" - sodipodi:role="line" - id="tspan5086-7-9">Multiservice</tspan></text> - </g> - <g - id="g5130-7-1-9" - transform="translate(-458.21801,21.637007)"> - <rect - y="219.18733" - x="411.13821" - height="52.004227" - width="101.06481" - id="rect3686-6-9-9-5-3-5" - style="opacity:0.98999999;fill:#9bd1e0;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-9-0-2" - y="249.10945" - x="461.8085" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="249.10945" - x="461.8085" - sodipodi:role="line" - id="tspan5086-7-9-0">PoetryService</tspan></text> - </g> - <g - id="g5130-7-1-9-5" - transform="translate(-228.61445,21.637007)"> - <rect - y="219.18733" - x="411.13821" - height="52.004227" - width="101.06481" - id="rect3686-6-9-9-5-3-5-5" - style="opacity:0.98999999;fill:#9bd1e0;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-9-0-2-3" - y="250.55745" - x="461.59711" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="250.55745" - x="461.59711" - sodipodi:role="line" - id="tspan5086-7-9-0-9">TCPServer</tspan></text> - </g> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/async-exceptions.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/async-exceptions.svg deleted file mode 100644 index a04420c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/async-exceptions.svg +++ /dev/null @@ -1,388 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="422.04303" - height="244.62401" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre2 r22153" - sodipodi:docname="async-exceptions.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/async-exceptions.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart" - style="overflow:visible"> - <path - id="path4011" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective4861" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4930" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4955" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4983" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5566" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5591" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart-1" - style="overflow:visible"> - <path - id="path4011-9" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <inkscape:perspective - id="perspective5995" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6028" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6127" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2" - inkscape:cx="273.43216" - inkscape:cy="104.84801" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1" - inkscape:snap-grids="true"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-111.90566,-31.395745)"> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#Arrow1Mend)" - d="m 201.35366,53.171746 0,205.231994" - id="path2403" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="305.60617" - y="43.171745" - id="text3479"><tspan - sodipodi:role="line" - id="tspan3481" - x="305.60617" - y="43.171745">Python Stack</tspan></text> - <rect - style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="rect4851" - width="160.228" - height="205.23199" - x="271.35367" - y="53.171745" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="289.55365" - y="78.171745" - id="text2403-1" - inkscape:export-filename="/home/dave/src/twisted-intro/images/rect4851.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"><tspan - sodipodi:role="line" - id="tspan2405-6" - x="289.55365" - y="78.171745">reactor.run()</tspan></text> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,403.96767,44.998162)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-9" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,403.96767,54.998144)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-1" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,403.96767,64.998126)" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="275.74899" - y="158.17175" - id="text2403-1-1"><tspan - sodipodi:role="line" - id="tspan2405-6-5" - x="275.74899" - y="158.17175">connectionLost()</tspan></text> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-6" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,403.96767,124.99815)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-9-8" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,403.96767,134.99814)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-1-2" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,403.96767,144.99812)" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="304.5224" - y="243.17175" - id="text2403-1-1-7"><tspan - sodipodi:role="line" - id="tspan2405-6-5-4" - x="304.5224" - y="243.17175">got_poem()</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="479.22662" - y="273.40375" - id="text3479-1"><tspan - sodipodi:role="line" - id="tspan3481-9" - x="479.22662" - y="273.40375">exceptions</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow1Mstart);marker-end:none" - d="m 506.80966,52.938806 0,205.464934" - id="path2403-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Vera Sans" - x="201.38" - y="45.78775" - id="text3479-1-1"><tspan - sodipodi:role="line" - x="201.38" - y="45.78775" - id="tspan6012" - style="-inkscape-font-specification:Bitstream Vera Sans">callbacks</tspan></text> - <text - xml:space="preserve" - style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="-67" - y="-30.826294" - id="text6016" - transform="translate(211.35366,52.49804)"><tspan - sodipodi:role="line" - id="tspan6018" - x="-67" - y="-30.826294" /></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="111.80966" - y="233.40375" - id="text3479-1-2"><tspan - sodipodi:role="line" - id="tspan3481-9-03" - x="111.80966" - y="233.40375">high-context,</tspan><tspan - sodipodi:role="line" - x="111.80966" - y="248.40375" - id="tspan6045">special-purpose</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="111.58166" - y="70.78775" - id="text3479-1-2-5"><tspan - sodipodi:role="line" - id="tspan3481-9-03-1" - x="111.58166" - y="70.78775">low-context,</tspan><tspan - sodipodi:role="line" - x="111.58166" - y="85.78775" - id="tspan6045-5">general-purpose</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/async.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/async.svg deleted file mode 100644 index e697d79..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/async.svg +++ /dev/null @@ -1,258 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="176.02422" - height="360.8425" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - sodipodi:docname="async.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/async.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.08" - inkscape:cx="290.04597" - inkscape:cy="233.54437" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-171.60965,-52.259392)"> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.07314342px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2401" - width="20.059799" - height="20.162561" - x="271.0903" - y="52.66296" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="171.35365" - y="82.921135" - id="text2403"><tspan - sodipodi:role="line" - id="tspan2405" - x="171.35365" - y="82.921135">Task 1</tspan></text> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.07306382px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2383" - width="20.059942" - height="20.118561" - x="271.35367" - y="72.921135" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="171.35365" - y="162.92114" - id="text2385"><tspan - sodipodi:role="line" - id="tspan2387" - x="171.35365" - y="162.92114">Task 2</tspan></text> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.10292919px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2389" - width="19.964426" - height="40.118259" - x="271.38925" - y="112.92113" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="171.35365" - y="242.92114" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="171.35365" - y="242.92114">Task 3</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" - d="M 331.09766,52.694204 L 331.09766,372.82516" - id="path2403" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="314.80136" - y="403.12976" - id="text3953"><tspan - sodipodi:role="line" - id="tspan3955" - x="314.80136" - y="403.12976">time</tspan></text> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.07314342px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2576" - width="20.059799" - height="20.162561" - x="271.35367" - y="92.758575" /> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.07314342px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2578" - width="20.059799" - height="20.162561" - x="271.35367" - y="152.92114" /> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.07314342px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2580" - width="20.059799" - height="20.162561" - x="271.35367" - y="172.92114" /> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.07306382px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2582" - width="20.059942" - height="20.118561" - x="271.35367" - y="192.92114" /> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.07269067px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2584" - width="19.994631" - height="19.978628" - x="271.37415" - y="212.90048" /> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.12610641px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2586" - width="20.007036" - height="60.091549" - x="271.32019" - y="232.99925" /> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.07269067px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2588" - width="19.994631" - height="19.978628" - x="271.35904" - y="292.9425" /> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.07314342px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2590" - width="20.059799" - height="20.162561" - x="271.35367" - y="312.92114" /> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.07306382px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2592" - width="20.059942" - height="20.118561" - x="271.35367" - y="332.92114" /> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.07314342px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2594" - width="20.059799" - height="20.162561" - x="271.35367" - y="352.92114" /> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.10292919px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2596" - width="19.964426" - height="40.118259" - x="271.38925" - y="372.92114" /> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.07306382px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2598" - width="20.059942" - height="20.118561" - x="181.35365" - y="92.802574" /> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.07314342px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2600" - width="20.059799" - height="20.162561" - x="181.35365" - y="172.92114" /> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.07269067px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2602" - width="19.994631" - height="19.978628" - x="181.35902" - y="252.94252" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/block.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/block.svg deleted file mode 100644 index e55bd5a..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/block.svg +++ /dev/null @@ -1,240 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="256.53622" - height="360.67371" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - sodipodi:docname="block.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/block.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart" - style="overflow:visible"> - <path - id="path4011" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.7356407" - inkscape:cx="118.18537" - inkscape:cy="180.33685" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-211.35366,-52.49804)"> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.17800596px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2401" - width="19.954937" - height="120.04401" - x="271.14273" - y="52.715393" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="211.09766" - y="72.759392" - id="text2403"><tspan - sodipodi:role="line" - id="tspan2405" - x="211.09766" - y="72.759392">Task 1</tspan></text> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.17804013px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2383" - width="19.954966" - height="120.08995" - x="271.39871" - y="172.83118" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="211.35365" - y="192.83118" - id="text2385"><tspan - sodipodi:role="line" - id="tspan2387" - x="211.35365" - y="192.83118">Task 2</tspan></text> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.17773573px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2389" - width="19.88962" - height="120.07285" - x="271.35367" - y="293.01004" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="211.35365" - y="312.92114" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="211.35365" - y="312.92114">Task 3</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" - d="M 451.35366,52.938803 L 451.35366,383.08288" - id="path2403" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="435.05737" - y="405.22025" - id="text3953"><tspan - sodipodi:role="line" - id="tspan3955" - x="435.05737" - y="405.22025">time</tspan></text> - <rect - style="fill:#666666" - id="rect2683" - width="20" - height="20" - x="271.35367" - y="73.082878" /> - <rect - style="fill:#666666" - id="rect3465" - width="20" - height="20" - x="271.35367" - y="123.08288" /> - <rect - style="fill:#666666" - id="rect3467" - width="20" - height="20" - x="271.35367" - y="193.08289" /> - <rect - style="fill:#666666" - id="rect3469" - width="20" - height="20" - x="271.35367" - y="233.08289" /> - <rect - style="fill:#666666" - id="rect3471" - width="20" - height="20" - x="271.35367" - y="313.08289" /> - <rect - style="fill:#666666" - id="rect3473" - width="20" - height="20" - x="271.35367" - y="343.08289" /> - <rect - style="fill:#666666" - id="rect3475" - width="20" - height="20" - x="271.35367" - y="383.08289" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="377.89673" - y="211.55859" - id="text3479"><tspan - sodipodi:role="line" - id="tspan3481" - x="377.89673" - y="211.55859">Waiting</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" - d="m 371.99137,203.08288 -80,-120.000002" - id="path4786" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Mend)" - d="M 372.42627,213.17404 292.31076,133.05515" - id="path5309" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/callback-loop.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/callback-loop.svg deleted file mode 100644 index 605eace..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/callback-loop.svg +++ /dev/null @@ -1,230 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="192.20482" - height="167.83548" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="callback-loop.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/callback-loop.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path4516" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="96.892906" - inkscape:cy="40.570746" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1"> - <sodipodi:guide - orientation="1,0" - position="-285.29575,705.4036" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-202.46324,292.25121" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-232.10018,-99.301761)"> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.54283696, 4.62851088;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="67.525047" - sodipodi:ry="67.525047" - d="m 458.32888,240.35509 c 37.29285,0.12409 67.42408,30.45652 67.29998,67.74937 -0.1241,37.29285 -30.45652,67.42407 -67.74937,67.29997 -37.29285,-0.12409 -67.42407,-30.45652 -67.29998,-67.74937 0.12287,-36.9217 29.87786,-66.89889 66.79763,-67.29643" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-307.41619,-189.66008)" - sodipodi:open="true" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="262.27097" - y="187.36349" - id="text2391"><tspan - sodipodi:role="line" - x="262.27097" - y="187.36349" - id="tspan4482">dataReceived Loop</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-1.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-1.svg deleted file mode 100644 index 0212afe..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-1.svg +++ /dev/null @@ -1,360 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="635.58539" - height="324.63458" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="deferred-1.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-1.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="345.72741" - inkscape:cy="146.70398" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(88.97474,155.53727)" - style="display:inline"> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4537" - width="269.32486" - height="298.74652" - x="95.297516" - y="-130.6492" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="194.22926" - y="-141.85927" - id="text4539"><tspan - sodipodi:role="line" - id="tspan4541" - x="194.22926" - y="-141.85927">A Deferred</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 472.03978,-119.3284 C 443.67265,-139.8343 369.45319,-127.88463 345.34117,-112.58563" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="474.22925" - y="-101.85926" - id="text7565"><tspan - sodipodi:role="line" - id="tspan7567" - x="474.22925" - y="-101.85926">Errback chain</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#00c800;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3240" - width="79.684219" - height="27.921125" - x="124.72926" - y="-100.28039" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="134.47421" - y="-82.246391" - id="text3242"><tspan - sodipodi:role="line" - id="tspan3244" - x="134.47421" - y="-82.246391">1st callback</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#c80000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3246" - width="79.684219" - height="27.921125" - x="254.04504" - y="-100.28039" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="263.78998" - y="-82.246391" - id="text3248"><tspan - sodipodi:role="line" - x="263.78998" - y="-82.246391" - id="tspan3252">1st errback</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#00c800;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3272" - width="79.684219" - height="27.921125" - x="124.72926" - y="-31.359262" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="134.47421" - y="-13.325265" - id="text3274"><tspan - sodipodi:role="line" - x="134.47421" - y="-13.325265" - id="tspan3308">2nd callback</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#c80000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3278" - width="79.684219" - height="27.921125" - x="254.04504" - y="-31.359262" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="263.78998" - y="-13.325265" - id="text3280"><tspan - sodipodi:role="line" - x="263.78998" - y="-13.325265" - id="tspan3282">2nd errback</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#00c800;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3284" - width="79.684219" - height="27.921125" - x="124.72926" - y="39.719612" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="134.47421" - y="57.753609" - id="text3286"><tspan - sodipodi:role="line" - id="tspan3288" - x="134.47421" - y="57.753609">3rd callback</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#c80000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3290" - width="79.684219" - height="27.921125" - x="254.04504" - y="39.719612" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="263.78998" - y="57.753609" - id="text3292"><tspan - sodipodi:role="line" - x="263.78998" - y="57.753609" - id="tspan3294">3rd errback</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#00c800;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3296" - width="79.684219" - height="27.921125" - x="124.22926" - y="108.14074" /> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="155.06076" - y="122.02874" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="155.06076" - y="122.02874">...</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#c80000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3302" - width="79.684219" - height="27.921125" - x="253.54504" - y="108.14074" /> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.06076" - y="122.02874" - id="text3304"><tspan - sodipodi:role="line" - x="285.06076" - y="122.02874" - id="tspan3306">...</tspan></text> - <rect - style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 3;stroke-dashoffset:0;stroke-opacity:1" - id="rect3312" - width="100.03716" - height="259.96307" - x="114.21068" - y="-111.80377" /> - <rect - style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 3;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3314" - width="100.03716" - height="259.96307" - x="243.69209" - y="-112.32233" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M -13.600131,-119.29865 C 14.766999,-139.80455 88.986459,-127.85488 113.09848,-112.55588" - id="path3316" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="-86.16674" - y="-104.89526" - id="text3318"><tspan - sodipodi:role="line" - id="tspan3320" - x="-86.16674" - y="-104.89526">Callback chain</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-10.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-10.svg deleted file mode 100644 index 7c7fed6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-10.svg +++ /dev/null @@ -1,891 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="636.1745" - height="452.07321" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - version="1.0" - sodipodi:docname="deferred-10.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-4.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8371" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-38" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter8473" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur8475" - in="SourceAlpha" - stdDeviation="2.000000" - result="blur" /> - <feColorMatrix - id="feColorMatrix8477" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /> - <feOffset - id="feOffset8479" - in="bluralpha" - dx="4.000000" - dy="4.000000" - result="offsetBlur" /> - <feMerge - id="feMerge8481"> - <feMergeNode - id="feMergeNode8483" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode8485" - in="SourceGraphic" /> - </feMerge> - </filter> - <inkscape:perspective - id="perspective8730" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4237" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3184" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-45" - style="overflow:visible"> - <path - id="path7124-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-3" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4130" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-61" - style="overflow:visible"> - <path - id="path7124-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4173" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-36" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-02" - style="overflow:visible"> - <path - id="path7124-69" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4210" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4235" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-01" - style="overflow:visible"> - <path - id="path7124-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4263" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="364.01284" - inkscape:cy="229.25167" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - borderlayer="false" - inkscape:snap-nodes="true" - inkscape:snap-object-midpoints="false" - inkscape:snap-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="-312.08705,950.51981" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-229.25454,537.36742" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(7.2024841,207.24821)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter8473)" - id="rect4537" - width="400" - height="299.38214" - x="94.297516" - y="-130.90268" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="150.06825" - height="29.377707" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="150.06825" - height="29.903984" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="150.06825" - height="30.430273" - x="124.22926" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="159.46164" - y="-83.353531" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="159.46164" - y="-83.353531">cummingsify</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240-3" - width="150.06825" - height="29.377707" - x="314.29752" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272-4" - width="150.06825" - height="29.903984" - x="314.29752" - y="-30.902681" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6" - width="150.06825" - height="30.430273" - x="314.29752" - y="39.097321" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="155.99626" - y="-14.102674" - id="text3298-6"><tspan - sodipodi:role="line" - id="tspan3300-9" - x="155.99626" - y="-14.102674">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="169.91777" - y="55.922184" - id="text3298-7"><tspan - sodipodi:role="line" - id="tspan3300-6" - x="169.91777" - y="55.922184">got_poem</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Bitstream Vera Sans" - x="346.06451" - y="-82.927536" - id="text3298-3"><tspan - sodipodi:role="line" - id="tspan3300-2" - x="346.06451" - y="-82.927536" - style="font-weight:normal;-inkscape-font-specification:Bitstream Vera Sans">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="324.22827" - y="-13.712689" - id="text3298-8"><tspan - sodipodi:role="line" - id="tspan3300-24" - x="324.22827" - y="-13.712689">cummingsify_failed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="349.58389" - y="56.352459" - id="text3298-76"><tspan - sodipodi:role="line" - id="tspan3300-3" - x="349.58389" - y="56.352459">poem_failed</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-63" - width="150.06825" - height="30.430273" - x="124.22926" - y="109.53703" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6-2" - width="150.06825" - height="30.430273" - x="314.29752" - y="109.96732" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="166.92039" - y="126.79218" - id="text3298-7-0"><tspan - sodipodi:role="line" - id="tspan3300-6-3" - x="166.92039" - y="126.79218">poem_done</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="356.98865" - y="127.22245" - id="text3298-76-1"><tspan - sodipodi:role="line" - id="tspan3300-3-9" - x="356.98865" - y="127.22245">poem_done</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 349.43098,-160.79327 c -31.79496,0.57301 -51.15856,45.39631 -143.65095,37.45936" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="349.73898" - y="-158.13728" - id="text7565"><tspan - sodipodi:role="line" - x="349.73898" - y="-158.13728" - id="tspan8758">The poem from the server</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 199.25375,-142.40426 4e-5,40.2995" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="149.65352" - y="-145.25626" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="149.65352" - y="-145.25626">callback(poem)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 274.29752,-70.902679 40,39.999998" - id="path6900-25-9-0-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 538.9336,-90.757171 c -7.5112,39.42701 -148.29357,26.66313 -235.92921,42.31611" - id="path7563-3" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="506.63202" - y="-91.927773" - id="text7565-6"><tspan - sodipodi:role="line" - x="506.63202" - y="-91.927773" - id="tspan8758-7" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">CannotCummingsify</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 314.29752,-0.99869728 -40,39.66574028" - id="path6900-25-9-0-3-1" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 539.35041,-23.794947 c -17.05635,40.00179 -149.89392,54.9559 -242.38631,47.01894" - id="path7563-3-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="514.8609" - y="-27.791002" - id="text7565-0"><tspan - sodipodi:role="line" - x="514.8609" - y="-27.791002" - id="tspan8758-6">The original poem</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 199.26339,69.097321 0,40.439709" - id="path6900-25-9-0-4" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 529.94224,48.788459 C 512.88589,88.790259 298.8712,103.05055 206.37881,95.113592" - id="path7563-3-7-2" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="516.24213" - y="48.144463" - id="text7565-6-7"><tspan - sodipodi:role="line" - x="516.24213" - y="48.144463" - id="tspan8758-7-9">None</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-11.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-11.svg deleted file mode 100644 index 331669d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-11.svg +++ /dev/null @@ -1,880 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="598.9035" - height="511.25705" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="deferred-11.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-11.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8068" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-8" - style="overflow:visible"> - <path - id="path7124-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8100" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-45" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4033" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4116" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-24" - style="overflow:visible"> - <path - id="path7124-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4144" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-62" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4172" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-49" - style="overflow:visible"> - <path - id="path7124-24" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4200" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-82" - style="overflow:visible"> - <path - id="path7124-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective5980" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-8" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6014" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6048" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-47" - style="overflow:visible"> - <path - id="path3871-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6086" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2950" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-63" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2991" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="390.96501" - inkscape:cy="251.4152" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="-256.13176,1057.1418" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-173.29925,643.98941" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(63.157773,159.81003)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect4537" - width="269.32486" - height="454.16254" - x="95.297516" - y="-130.6492" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="79.684219" - height="27.921125" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="79.684219" - height="27.921125" - x="124.22926" - y="120.50148" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3290" - width="79.684219" - height="27.921125" - x="253.54504" - y="189.97519" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3296" - width="79.684219" - height="27.921125" - x="124.22926" - y="259.44888" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 203.91348,147.87001 49.63156,42.10519" - id="path6900-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 255.93646,217.89632 206.3049,259.44889" - id="path6900-6-7" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.50068,-72.290327 32.024,47.484466" - id="path6900-25-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 164.06173,-142.40425 4e-5,40.29949" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="118.07087" - y="-152.14203" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="118.07087" - y="-152.14203">callback(...)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.47236,299.41609 0.69386,50.70681" - id="path6900-25-9-5" - sodipodi:nodetypes="cc" /> - <g - id="g4220" - transform="translate(324.22964,75.626543)"> - <rect - y="-100.4324" - x="-125.70496" - height="97.538284" - width="87.932358" - id="rect4537-9" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" /> - <rect - y="-87.826103" - x="-111.17357" - height="14.044698" - width="20.01557" - id="rect3240-4" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" /> - <rect - y="-58.685619" - x="-72.319565" - height="14.044698" - width="20.01557" - id="rect3240-4-8" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" /> - <rect - y="-29.545115" - x="-111.17357" - height="14.044698" - width="20.01557" - id="rect3240-4-0" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" /> - <path - sodipodi:nodetypes="cc" - id="path6900-25-9-6" - d="m -101.17543,-119.54264 4e-5,29.892163" - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" /> - <path - sodipodi:nodetypes="cc" - id="path6900-2-5" - d="m -91.157997,-73.781403 18.838432,15.095784" - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" /> - <path - sodipodi:nodetypes="cc" - id="path6900-25-9-6-4" - d="m -72.319565,-44.640923 -18.838432,15.095808" - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" /> - <path - sodipodi:nodetypes="cc" - id="path6900-25-9-6-8" - d="m -101.17543,-14.500417 -58.98284,59.375354" - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" /> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 35.233165,-98.490096 c 28.770729,8.309648 15.944895,-5.133614 56.666232,-11.682924" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="-63.349773" - y="-99.703369" - id="text7565"><tspan - sodipodi:role="line" - x="-63.349773" - y="-99.703369" - id="tspan8758">The outer deferred</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 44.86643,59.251824 C 96.330053,91.740623 157.80335,30.512592 198.52468,23.963282" - id="path7563-4" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="-53.411819" - y="60.40115" - id="text7565-6"><tspan - sodipodi:role="line" - x="-53.411819" - y="60.40115" - id="tspan8758-4">The inner deferred</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 403.88478,-66.72693 c -98.66177,29.054556 -154.65074,-14.029719 -221.3721,18.178836" - id="path7563-4-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="410.59622" - y="-96.485771" - id="text7565-6-6"><tspan - sodipodi:role="line" - x="410.59622" - y="-96.485771" - id="tspan8758-4-5">The outer deferred</tspan><tspan - sodipodi:role="line" - x="410.59622" - y="-81.485771" - id="tspan6074">pauses when the inner</tspan><tspan - sodipodi:role="line" - x="410.59622" - y="-66.485771" - id="tspan6076">deferred is returned</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 403.3504,82.776613 C 311.06651,73.073305 257.83112,116.49674 193.56279,90.813803" - id="path7563-4-1-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="410.06183" - y="88.402664" - id="text7565-6-6-3"><tspan - sodipodi:role="line" - x="410.06183" - y="88.402664" - id="tspan8758-4-5-4">The outer deferred</tspan><tspan - sodipodi:role="line" - x="410.06183" - y="103.40266" - id="tspan6074-0">resumes when the inner</tspan><tspan - sodipodi:role="line" - x="410.06183" - y="118.40266" - id="tspan6076-9">deferred is fired</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 404.28072,26.950722 C 357.09523,58.876701 327.1743,32.300677 233.07164,53.103777" - id="path7563-4-1-1-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="410.06183" - y="10.681701" - id="text7565-6-6-3-8"><tspan - sodipodi:role="line" - x="410.06183" - y="10.681701" - id="tspan8758-4-5-4-0">This callback was</tspan><tspan - sodipodi:role="line" - x="410.06183" - y="25.681702" - id="tspan6076-9-1">added by the outer</tspan><tspan - sodipodi:role="line" - x="410.06183" - y="25.681702" - id="tspan3024">deferred</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-12.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-12.svg deleted file mode 100644 index fda4187..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-12.svg +++ /dev/null @@ -1,440 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="653.93842" - height="582.4375" - id="svg2" - version="1.1" - inkscape:version="0.47 r22583" - sodipodi:docname="deferred-12.svg" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-12.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path3808" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="CurveOut" - orient="auto" - refY="0" - refX="0" - id="CurveOut" - style="overflow:visible"> - <path - id="path3969" - d="m -5.4129913,-5.0456926 c 2.76,0 4.99999999,2.24 4.99999999,5.00000002 0,2.75999998 -2.23999999,4.99999998 -4.99999999,4.99999998" - style="fill:none;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none" - transform="scale(0.6,0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3802" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lend" - style="overflow:visible"> - <path - id="path3784" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.8,0,0,-0.8,-10,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective4672" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5490" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5518" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5545" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3802-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5573" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5613" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-64" - style="overflow:visible"> - <path - id="path3802-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5641" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5685" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-62" - style="overflow:visible"> - <path - id="path3802-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5722" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-8" - style="overflow:visible"> - <path - id="path3802-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5775" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3802-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5803" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="0.98994949" - inkscape:cx="367.19792" - inkscape:cy="226.8877" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-bbox="true" - inkscape:bbox-nodes="true" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:object-paths="true" - inkscape:snap-midpoints="true" - inkscape:snap-global="false" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-39.177129,-11.405061)"> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 4;stroke-dashoffset:0;marker-start:none" - d="m 356.24603,11.905061 0,581.437499" - id="path2816" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="224.43396" - y="21.709061" - id="text7565"><tspan - sodipodi:role="line" - x="224.43396" - y="21.709061" - id="tspan8758">The reactor loop</tspan></text> - <text - id="text4716" - y="21.709061" - x="387.13882" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - id="tspan4718" - y="21.709061" - x="387.13882" - sodipodi:role="line">Callbacks</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)" - d="m 275,44.505039 0,80.714281 167.85714,0 0,76.42858 -167.85714,0 0,226.42857 167.85714,0 0,77.14286 -167.85714,0 0,76.01886" - id="path4720" - sodipodi:nodetypes="cccccccccc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 101.13869,158.48756 c 51.46362,32.4888 112.93692,-28.73923 153.65825,-35.28854" - id="path7563-4" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="43.311642" - y="130.93176" - id="text7565-0"><tspan - sodipodi:role="line" - x="43.311642" - y="130.93176" - id="tspan8758-5">The outer deferred</tspan><tspan - sodipodi:role="line" - x="43.311642" - y="148.43176" - id="tspan5535">is fired here</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 517.92252,174.45894 c -13.07782,16.32635 -6.12345,31.82197 -49.87524,26.28281" - id="path7563-4-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="531.0545" - y="169.40817" - id="text7565-0-3"><tspan - sodipodi:role="line" - x="531.0545" - y="169.40817" - id="tspan8758-5-1">A callback returns the</tspan><tspan - sodipodi:role="line" - x="531.0545" - y="186.90817" - id="tspan5535-3">inner deferred here. The</tspan><tspan - sodipodi:role="line" - x="531.0545" - y="204.40817" - id="tspan5597">outer deferred returns</tspan><tspan - sodipodi:role="line" - x="531.0545" - y="221.90817" - id="tspan5599">control to the reactor.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 500.11917,331.51195 c -13.07782,16.32635 -69.76306,3.5377 -101.39302,-23.21466" - id="path7563-4-1-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="500.15717" - y="285.30215" - id="text7565-0-3-1"><tspan - sodipodi:role="line" - x="500.15717" - y="285.30215" - id="tspan5599-8">During this period unrelated</tspan><tspan - sodipodi:role="line" - x="500.15717" - y="302.80215" - id="tspan5675">callbacks and deferreds</tspan><tspan - sodipodi:role="line" - x="500.15717" - y="320.30215" - id="tspan5833">may fire.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 96.780178,463.31462 C 148.2438,495.80342 209.7171,434.57539 250.43843,428.02608" - id="path7563-4-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="38.953129" - y="435.75882" - id="text7565-0-6"><tspan - sodipodi:role="line" - x="38.953129" - y="435.75882" - id="tspan8758-5-7">The inner deferred</tspan><tspan - sodipodi:role="line" - x="38.953129" - y="453.25882" - id="tspan5535-4">is fired here</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 515.41488,455.41424 c -13.07782,16.32635 -6.12345,31.82197 -49.87524,26.28281" - id="path7563-4-1-11" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="528.54688" - y="450.36346" - id="text7565-0-3-8"><tspan - sodipodi:role="line" - x="528.54688" - y="450.36346" - id="tspan5599-9">The inner deferred runs</tspan><tspan - sodipodi:role="line" - x="528.54688" - y="467.86346" - id="tspan5763">its chain, causing the outer</tspan><tspan - sodipodi:role="line" - x="528.54688" - y="485.36346" - id="tspan5765">deferred to resume firing.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 206.37833,60.990843 c 21.15905,-24.07974 20.00289,-16.617399 57.69376,-13.065184" - id="path7563-4-8" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="61.495102" - y="61.473606" - id="text7565-0-9"><tspan - sodipodi:role="line" - x="61.495102" - y="61.473606" - id="tspan5535-9">The thread of control.</tspan><tspan - sodipodi:role="line" - x="61.495102" - y="78.97361" - id="tspan5825">Time is going downwards.</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-13.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-13.svg deleted file mode 100644 index 6fd63e6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-13.svg +++ /dev/null @@ -1,737 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="271.32486" - height="280.98169" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="deferred-13.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-11.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8068" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-8" - style="overflow:visible"> - <path - id="path7124-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8100" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-45" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4033" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4116" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-24" - style="overflow:visible"> - <path - id="path7124-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4144" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-62" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4172" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-49" - style="overflow:visible"> - <path - id="path7124-24" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4200" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-82" - style="overflow:visible"> - <path - id="path7124-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective5980" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-8" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6014" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6048" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-47" - style="overflow:visible"> - <path - id="path3871-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6086" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2950" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-63" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2991" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9415" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-49" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="233.50972" - inkscape:cy="48.892709" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="-413.58705,826.86645" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-330.75454,413.71406" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-94.297516,159.81003)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect4537" - width="269.32486" - height="222.42616" - x="95.297516" - y="-130.6492" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="79.684219" - height="27.921125" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3290" - width="79.684219" - height="27.921125" - x="253.54504" - y="-29.254084" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3296" - width="79.684219" - height="27.921125" - x="124.22926" - y="40.219612" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 203.91348,-71.359262 49.63156,42.10519" - id="path6900-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 255.93646,-1.3329525 206.3049,40.219618" - id="path6900-6-7" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 164.06173,-142.40425 4e-5,40.29949" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="118.07087" - y="-152.14203" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="118.07087" - y="-152.14203">callback(...)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.47236,69.140738 0.69386,50.706812" - id="path6900-25-9-5" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-14.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-14.svg deleted file mode 100644 index cb74f22..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-14.svg +++ /dev/null @@ -1,796 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="271.32486" - height="357.38049" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="deferred-14.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-14.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8068" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-8" - style="overflow:visible"> - <path - id="path7124-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8100" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-45" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4033" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4116" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-24" - style="overflow:visible"> - <path - id="path7124-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4144" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-62" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4172" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-49" - style="overflow:visible"> - <path - id="path7124-24" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4200" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-82" - style="overflow:visible"> - <path - id="path7124-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective5980" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-8" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6014" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6048" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-47" - style="overflow:visible"> - <path - id="path3871-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6086" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2950" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-63" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2991" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9415" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-49" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9474" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9496" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-10" - style="overflow:visible"> - <path - id="path7124-72" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9524" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-12" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="144.00675" - inkscape:cy="125.29153" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="-413.58705,903.26527" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-330.75454,490.11288" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-94.297516,159.81003)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect4537" - width="269.32486" - height="302.21564" - x="95.297516" - y="-130.6492" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="79.684219" - height="27.921125" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3290" - width="79.684219" - height="27.921125" - x="253.54504" - y="-29.254084" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3296" - width="79.684219" - height="27.921125" - x="124.53137" - y="40.219612" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 203.91348,-71.359262 49.63156,42.10519" - id="path6900-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 255.93646,-1.3329525 206.3049,40.219618" - id="path6900-6-7" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 164.06173,-142.40425 4e-5,40.29949" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="118.07087" - y="-152.14203" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="118.07087" - y="-152.14203">callback(...)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 164.37348,145.53955 0.69386,50.70681" - id="path6900-25-9-5" - sodipodi:nodetypes="cc" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3296-4" - width="79.684219" - height="27.921125" - x="124.53137" - y="117.61842" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 164.07137,68.140739 0.30211,49.477681" - id="path6900-25-9-5-5" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-2.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-2.svg deleted file mode 100644 index 920bf89..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-2.svg +++ /dev/null @@ -1,617 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="325.72849" - height="321.37259" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre2 r22153" - version="1.0" - sodipodi:docname="deferred-2.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-2.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="187.15987" - inkscape:cy="120.22576" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="-413.58704,874.79211" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-330.75453,461.63972" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-94.297516,152.27527)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect4537" - width="269.32486" - height="298.74652" - x="95.297516" - y="-130.6492" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="194.22926" - y="-141.85927" - id="text4539"><tspan - sodipodi:role="line" - id="tspan4541" - x="194.22926" - y="-141.85927">A Deferred</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="79.684219" - height="27.921125" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3246" - width="79.684219" - height="27.921125" - x="253.54504" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="79.684219" - height="27.921125" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3278" - width="79.684219" - height="27.921125" - x="253.54504" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="79.684219" - height="27.921125" - x="124.22926" - y="38.667046" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3290" - width="79.684219" - height="27.921125" - x="253.54504" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="140.54303" - y="-111.00749" - id="text3292"><tspan - sodipodi:role="line" - x="140.54303" - y="-111.00749" - id="tspan3294">callbacks</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1,3;stroke-dashoffset:0;display:inline" - id="rect3296" - width="79.684219" - height="27.921125" - x="124.22926" - y="108.14074" /> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="155.06076" - y="122.02874" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="155.06076" - y="122.02874">...</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1,3;stroke-dashoffset:0;display:inline" - id="rect3302" - width="79.684219" - height="27.921125" - x="253.54504" - y="108.14074" /> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.06076" - y="122.02874" - id="text3304"><tspan - sodipodi:role="line" - x="285.06076" - y="122.02874" - id="tspan3306">...</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="M 292.88822,83.178009 342.51978,124.7306" - id="path6900" - transform="translate(-88.97474,-155.53727)" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 203.91348,-3.4381371 253.54504,38.667046" - id="path6900-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 203.91348,66.588173 49.63156,41.552567" - id="path6900-6" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 293.34926,-72.29033 -4e-5,40.299489" - id="path6900-25" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 293.37758,-2.7629966 -4e-5,39.6056686" - id="path6900-25-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 293.72449,66.200528 -0.34695,41.687142" - id="path6900-25-8" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 255.93646,-72.359257 -49.63156,41.55259" - id="path6900-29" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 255.93646,-3.4381371 206.3049,38.667052" - id="path6900-2-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 255.93646,66.588172 206.3049,108.14074" - id="path6900-6-7" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.50068,-72.290327 4e-5,40.29949" - id="path6900-25-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.47236,-2.7629941 4e-5,39.6056661" - id="path6900-25-3-8" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.12545,66.200532 0.34695,41.687138" - id="path6900-25-8-8" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="381.57257" - y="-82.882393" - id="text3242-6"><tspan - sodipodi:role="line" - id="tspan3244-5" - x="381.57257" - y="-82.882393">Stage 0</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="381.57257" - y="-13.961265" - id="text3242-6-1"><tspan - sodipodi:role="line" - x="381.57257" - y="-13.961265" - id="tspan7985">Stage 1</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="381.57257" - y="57.117607" - id="text3242-6-18"><tspan - sodipodi:role="line" - id="tspan3244-5-52" - x="381.57257" - y="57.117607">Stage 2</tspan></text> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="380.49258" - y="122.02874" - id="text3304-9"><tspan - sodipodi:role="line" - x="380.49258" - y="122.02874" - id="tspan3306-9">...</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="271.41739" - y="-111.00749" - id="text3292-1"><tspan - sodipodi:role="line" - x="271.41739" - y="-111.00749" - id="tspan3294-8">errbacks</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-3.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-3.svg deleted file mode 100644 index 087c07d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-3.svg +++ /dev/null @@ -1,513 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="271.32486" - height="348.90283" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre2 r22153" - version="1.0" - sodipodi:docname="deferred-3.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-3.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8068" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-8" - style="overflow:visible"> - <path - id="path7124-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8100" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-45" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="172.60784" - inkscape:cy="167.97409" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="-413.58705,894.78758" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-330.75454,481.63519" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-94.297516,159.81003)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect4537" - width="269.32486" - height="298.74652" - x="95.297516" - y="-130.6492" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="79.684219" - height="27.921125" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="79.684219" - height="27.921125" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3290" - width="79.684219" - height="27.921125" - x="253.54504" - y="38.667046" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3296" - width="79.684219" - height="27.921125" - x="124.22926" - y="108.14074" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 203.91348,-3.4381371 253.54504,38.667046" - id="path6900-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 255.93646,66.588172 206.3049,108.14074" - id="path6900-6-7" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.50068,-72.290327 4e-5,40.29949" - id="path6900-25-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 164.06173,-142.40425 4e-5,40.29949" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="118.07087" - y="-152.14203" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="118.07087" - y="-152.14203">callback(...)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.47236,137.06186 0.69386,50.70681" - id="path6900-25-9-5" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-4.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-4.svg deleted file mode 100644 index 493b46b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-4.svg +++ /dev/null @@ -1,632 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="654.15454" - height="348" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - version="1.0" - sodipodi:docname="deferred-4.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-4.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8371" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-38" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter8473" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur8475" - in="SourceAlpha" - stdDeviation="2.000000" - result="blur" /> - <feColorMatrix - id="feColorMatrix8477" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /> - <feOffset - id="feOffset8479" - in="bluralpha" - dx="4.000000" - dy="4.000000" - result="offsetBlur" /> - <feMerge - id="feMerge8481"> - <feMergeNode - id="feMergeNode8483" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode8485" - in="SourceGraphic" /> - </feMerge> - </filter> - <inkscape:perspective - id="perspective8730" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.019148" - inkscape:cx="403.45626" - inkscape:cy="142.52397" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="false" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - borderlayer="false" - inkscape:snap-nodes="false"> - <sodipodi:guide - orientation="1,0" - position="-312.08705,863.79211" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-229.25454,450.63972" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(7.2024841,189.90268)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter8473)" - id="rect4537" - width="400" - height="230" - x="94.297516" - y="-130.90268" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="150.06825" - height="29.377707" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="150.06825" - height="29.903984" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="150.06825" - height="30.430273" - x="124.22926" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="134.22002" - y="-83.353531" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="134.22002" - y="-83.353531">try_to_cummingsify</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240-3" - width="150.06825" - height="29.377707" - x="314.29752" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272-4" - width="150.06825" - height="29.903984" - x="314.29752" - y="-30.902681" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6" - width="150.06825" - height="30.430273" - x="314.29752" - y="39.097321" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="169.91777" - y="-14.102674" - id="text3298-6"><tspan - sodipodi:role="line" - id="tspan3300-9" - x="169.91777" - y="-14.102674">got_poem</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="166.92039" - y="55.922184" - id="text3298-7"><tspan - sodipodi:role="line" - id="tspan3300-6" - x="166.92039" - y="55.922184">poem_done</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Bitstream Vera Sans" - x="346.06451" - y="-82.927536" - id="text3298-3"><tspan - sodipodi:role="line" - id="tspan3300-2" - x="346.06451" - y="-82.927536" - style="font-weight:normal;-inkscape-font-specification:Bitstream Vera Sans">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="349.58389" - y="-13.712689" - id="text3298-8"><tspan - sodipodi:role="line" - id="tspan3300-24" - x="349.58389" - y="-13.712689">poem_failed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="356.98865" - y="56.352459" - id="text3298-76"><tspan - sodipodi:role="line" - id="tspan3300-3" - x="356.98865" - y="56.352459">poem_done</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 546.26662,-146.75943 c -24.85675,11.67415 -55.32149,-39.94373 -81.90084,46.47904" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="549.39526" - y="-143.07068" - id="text7565"><tspan - sodipodi:role="line" - id="tspan7567" - x="549.39526" - y="-143.07068">Added implicitly</tspan><tspan - sodipodi:role="line" - x="549.39526" - y="-128.07068" - id="tspan8758">by <tspan - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - id="tspan8756">addCallback</tspan></tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-5.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-5.svg deleted file mode 100644 index 2c96237..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-5.svg +++ /dev/null @@ -1,801 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="634.88373" - height="348" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre2 r22153" - version="1.0" - sodipodi:docname="deferred-5.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-4.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8371" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-38" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter8473" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur8475" - in="SourceAlpha" - stdDeviation="2.000000" - result="blur" /> - <feColorMatrix - id="feColorMatrix8477" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /> - <feOffset - id="feOffset8479" - in="bluralpha" - dx="4.000000" - dy="4.000000" - result="offsetBlur" /> - <feMerge - id="feMerge8481"> - <feMergeNode - id="feMergeNode8483" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode8485" - in="SourceGraphic" /> - </feMerge> - </filter> - <inkscape:perspective - id="perspective8730" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9010" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-7" - style="overflow:visible"> - <path - id="path7124-29" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-47" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9085" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-59" - style="overflow:visible"> - <path - id="path7124-67" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9115" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9149" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="130.37547" - inkscape:cy="165.5152" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - borderlayer="false" - inkscape:snap-nodes="true"> - <sodipodi:guide - orientation="1,0" - position="-312.08705,863.79211" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-229.25454,450.63972" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(7.2024841,189.90268)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter8473)" - id="rect4537" - width="400" - height="230" - x="94.297516" - y="-130.90268" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="150.06825" - height="29.377707" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="150.06825" - height="29.903984" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="150.06825" - height="30.430273" - x="124.22926" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="134.22002" - y="-83.353531" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="134.22002" - y="-83.353531">try_to_cummingsify</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240-3" - width="150.06825" - height="29.377707" - x="314.29752" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272-4" - width="150.06825" - height="29.903984" - x="314.29752" - y="-30.902681" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6" - width="150.06825" - height="30.430273" - x="314.29752" - y="39.097321" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="169.91777" - y="-14.102674" - id="text3298-6"><tspan - sodipodi:role="line" - id="tspan3300-9" - x="169.91777" - y="-14.102674">got_poem</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="166.92039" - y="55.922184" - id="text3298-7"><tspan - sodipodi:role="line" - id="tspan3300-6" - x="166.92039" - y="55.922184">poem_done</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Bitstream Vera Sans" - x="346.06451" - y="-82.927536" - id="text3298-3"><tspan - sodipodi:role="line" - id="tspan3300-2" - x="346.06451" - y="-82.927536" - style="font-weight:normal;-inkscape-font-specification:Bitstream Vera Sans">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="349.58389" - y="-13.712689" - id="text3298-8"><tspan - sodipodi:role="line" - id="tspan3300-24" - x="349.58389" - y="-13.712689">poem_failed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="356.98865" - y="56.352459" - id="text3298-76"><tspan - sodipodi:role="line" - id="tspan3300-3" - x="356.98865" - y="56.352459">poem_done</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 351.30278,-160.63586 c -31.79496,0.57301 -51.15856,45.39631 -143.65095,37.45936" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="351.61078" - y="-157.97986" - id="text7565"><tspan - sodipodi:role="line" - x="351.61078" - y="-157.97986" - id="tspan8758">The poem from the server</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 199.25375,-142.40426 4e-5,40.2995" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="149.65352" - y="-145.25626" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="149.65352" - y="-145.25626">callback(poem)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 199.85262,-70.849075 -0.69378,38.218036" - id="path6900-25-9-0-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 199.85262,-1.3753245 199.15884,36.842716" - id="path6900-25-9-0-3-1" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 538.54828,-93.981637 C 518.54829,-55.942266 299.36409,-44.422398 206.8717,-52.359348" - id="path7563-3" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="508.32812" - y="-97.097633" - id="text7565-6"><tspan - sodipodi:role="line" - x="508.32812" - y="-97.097633" - id="tspan8758-7">The transformed poem</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 539.35041,-23.794948 c -19.99999,38.03937 -239.18419,49.55924 -331.67658,41.62228" - id="path7563-3-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="525.65027" - y="-24.438948" - id="text7565-6-7"><tspan - sodipodi:role="line" - x="525.65027" - y="-24.438948" - id="tspan8758-7-9">None</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-6.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-6.svg deleted file mode 100644 index 6062e38..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-6.svg +++ /dev/null @@ -1,802 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="634.88373" - height="348" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre2 r22153" - version="1.0" - sodipodi:docname="deferred-6.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-4.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8371" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-38" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter8473" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur8475" - in="SourceAlpha" - stdDeviation="2.000000" - result="blur" /> - <feColorMatrix - id="feColorMatrix8477" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /> - <feOffset - id="feOffset8479" - in="bluralpha" - dx="4.000000" - dy="4.000000" - result="offsetBlur" /> - <feMerge - id="feMerge8481"> - <feMergeNode - id="feMergeNode8483" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode8485" - in="SourceGraphic" /> - </feMerge> - </filter> - <inkscape:perspective - id="perspective8730" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9010" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-7" - style="overflow:visible"> - <path - id="path7124-29" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-47" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9085" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-59" - style="overflow:visible"> - <path - id="path7124-67" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9115" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9149" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="338.47258" - inkscape:cy="165.5152" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - borderlayer="false" - inkscape:snap-nodes="true"> - <sodipodi:guide - orientation="1,0" - position="-312.08705,863.79211" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-229.25454,450.63972" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(7.2024841,189.90268)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter8473)" - id="rect4537" - width="400" - height="230" - x="94.297516" - y="-130.90268" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="150.06825" - height="29.377707" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="150.06825" - height="29.903984" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="150.06825" - height="30.430273" - x="124.22926" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="134.22002" - y="-83.353531" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="134.22002" - y="-83.353531">try_to_cummingsify</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240-3" - width="150.06825" - height="29.377707" - x="314.29752" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272-4" - width="150.06825" - height="29.903984" - x="314.29752" - y="-30.902681" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6" - width="150.06825" - height="30.430273" - x="314.29752" - y="39.097321" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="169.91777" - y="-14.102674" - id="text3298-6"><tspan - sodipodi:role="line" - id="tspan3300-9" - x="169.91777" - y="-14.102674">got_poem</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="166.92039" - y="55.922184" - id="text3298-7"><tspan - sodipodi:role="line" - id="tspan3300-6" - x="166.92039" - y="55.922184">poem_done</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Bitstream Vera Sans" - x="346.06451" - y="-82.927536" - id="text3298-3"><tspan - sodipodi:role="line" - id="tspan3300-2" - x="346.06451" - y="-82.927536" - style="font-weight:normal;-inkscape-font-specification:Bitstream Vera Sans">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="349.58389" - y="-13.712689" - id="text3298-8"><tspan - sodipodi:role="line" - id="tspan3300-24" - x="349.58389" - y="-13.712689">poem_failed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="356.98865" - y="56.352459" - id="text3298-76"><tspan - sodipodi:role="line" - id="tspan3300-3" - x="356.98865" - y="56.352459">poem_done</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 351.30278,-160.63586 c -31.79496,0.57301 -51.15856,45.39631 -143.65095,37.45936" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="351.61078" - y="-157.97986" - id="text7565"><tspan - sodipodi:role="line" - x="351.61078" - y="-157.97986" - id="tspan8758">The poem from the server</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 199.25375,-142.40426 4e-5,40.2995" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="149.65352" - y="-145.25626" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="149.65352" - y="-145.25626">callback(poem)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 274.29752,-70.902679 40,39.999998" - id="path6900-25-9-0-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 314.29752,-0.99869728 -40,39.66574328" - id="path6900-25-9-0-3-1" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 539.2421,-90.095536 c -7.5112,39.427014 -148.29357,26.66313 -235.92921,42.31611" - id="path7563-3" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="506.94049" - y="-91.266144" - id="text7565-6"><tspan - sodipodi:role="line" - x="506.94049" - y="-91.266144" - id="tspan8758-7" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">GibberishError</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 539.35041,-23.794948 C 522.29406,16.206846 389.45649,31.160957 296.9641,23.223997" - id="path7563-3-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="525.65027" - y="-24.438948" - id="text7565-6-7"><tspan - sodipodi:role="line" - x="525.65027" - y="-24.438948" - id="tspan8758-7-9">None</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-7.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-7.svg deleted file mode 100644 index bd5b839..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-7.svg +++ /dev/null @@ -1,801 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="634.88373" - height="348" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - version="1.0" - sodipodi:docname="deferred-7.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-4.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8371" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-38" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter8473" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur8475" - in="SourceAlpha" - stdDeviation="2.000000" - result="blur" /> - <feColorMatrix - id="feColorMatrix8477" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /> - <feOffset - id="feOffset8479" - in="bluralpha" - dx="4.000000" - dy="4.000000" - result="offsetBlur" /> - <feMerge - id="feMerge8481"> - <feMergeNode - id="feMergeNode8483" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode8485" - in="SourceGraphic" /> - </feMerge> - </filter> - <inkscape:perspective - id="perspective8730" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9010" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-7" - style="overflow:visible"> - <path - id="path7124-29" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-47" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9085" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-59" - style="overflow:visible"> - <path - id="path7124-67" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9115" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9149" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="358.68327" - inkscape:cy="164.12756" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - borderlayer="false" - inkscape:snap-nodes="true"> - <sodipodi:guide - orientation="1,0" - position="-312.08705,863.79211" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-229.25454,450.63972" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(7.2024841,189.90268)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter8473)" - id="rect4537" - width="400" - height="230" - x="94.297516" - y="-130.90268" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="150.06825" - height="29.377707" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="150.06825" - height="29.903984" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="150.06825" - height="30.430273" - x="124.22926" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="134.22002" - y="-83.353531" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="134.22002" - y="-83.353531">try_to_cummingsify</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240-3" - width="150.06825" - height="29.377707" - x="314.29752" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272-4" - width="150.06825" - height="29.903984" - x="314.29752" - y="-30.902681" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6" - width="150.06825" - height="30.430273" - x="314.29752" - y="39.097321" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="169.91777" - y="-14.102674" - id="text3298-6"><tspan - sodipodi:role="line" - id="tspan3300-9" - x="169.91777" - y="-14.102674">got_poem</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="166.92039" - y="55.922184" - id="text3298-7"><tspan - sodipodi:role="line" - id="tspan3300-6" - x="166.92039" - y="55.922184">poem_done</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Bitstream Vera Sans" - x="346.06451" - y="-82.927536" - id="text3298-3"><tspan - sodipodi:role="line" - id="tspan3300-2" - x="346.06451" - y="-82.927536" - style="font-weight:normal;-inkscape-font-specification:Bitstream Vera Sans">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="349.58389" - y="-13.712689" - id="text3298-8"><tspan - sodipodi:role="line" - id="tspan3300-24" - x="349.58389" - y="-13.712689">poem_failed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="356.98865" - y="56.352459" - id="text3298-76"><tspan - sodipodi:role="line" - id="tspan3300-3" - x="356.98865" - y="56.352459">poem_done</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 351.30278,-160.63586 c -31.79496,0.57301 -51.15856,45.39631 -143.65095,37.45936" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="351.61078" - y="-157.97986" - id="text7565"><tspan - sodipodi:role="line" - x="351.61078" - y="-157.97986" - id="tspan8758">The poem from the server</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 199.25375,-142.40426 4e-5,40.2995" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="149.65352" - y="-145.25626" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="149.65352" - y="-145.25626">callback(poem)</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 199.85262,-70.849075 -0.69378,38.218036" - id="path6900-25-9-0-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 199.85262,-1.3753245 199.15884,36.842716" - id="path6900-25-9-0-3-1" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 538.54828,-93.981637 C 518.54829,-55.942266 299.36409,-44.422398 206.8717,-52.359348" - id="path7563-3" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="508.32812" - y="-97.097633" - id="text7565-6"><tspan - sodipodi:role="line" - x="508.32812" - y="-97.097633" - id="tspan8758-7">The same poem</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 539.35041,-23.794948 c -19.99999,38.03937 -239.18419,49.55924 -331.67658,41.62228" - id="path7563-3-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="525.65027" - y="-24.438948" - id="text7565-6-7"><tspan - sodipodi:role="line" - x="525.65027" - y="-24.438948" - id="tspan8758-7-9">None</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-8.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-8.svg deleted file mode 100644 index 35de16f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-8.svg +++ /dev/null @@ -1,791 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="634.88373" - height="348" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - version="1.0" - sodipodi:docname="deferred-8.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-4.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8371" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-38" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter8473" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur8475" - in="SourceAlpha" - stdDeviation="2.000000" - result="blur" /> - <feColorMatrix - id="feColorMatrix8477" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /> - <feOffset - id="feOffset8479" - in="bluralpha" - dx="4.000000" - dy="4.000000" - result="offsetBlur" /> - <feMerge - id="feMerge8481"> - <feMergeNode - id="feMergeNode8483" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode8485" - in="SourceGraphic" /> - </feMerge> - </filter> - <inkscape:perspective - id="perspective8730" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9010" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-7" - style="overflow:visible"> - <path - id="path7124-29" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-47" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9044-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9085" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-59" - style="overflow:visible"> - <path - id="path7124-67" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective9115" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9149" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="374.90246" - inkscape:cy="163.78065" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - borderlayer="false" - inkscape:snap-nodes="true"> - <sodipodi:guide - orientation="1,0" - position="-312.08705,863.79211" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-229.25454,450.63972" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(7.2024841,189.90268)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter8473)" - id="rect4537" - width="400" - height="230" - x="94.297516" - y="-130.90268" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="150.06825" - height="29.377707" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="150.06825" - height="29.903984" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="150.06825" - height="30.430273" - x="124.22926" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="134.22002" - y="-83.353531" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="134.22002" - y="-83.353531">try_to_cummingsify</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240-3" - width="150.06825" - height="29.377707" - x="314.29752" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272-4" - width="150.06825" - height="29.903984" - x="314.29752" - y="-30.902681" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6" - width="150.06825" - height="30.430273" - x="314.29752" - y="39.097321" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="169.91777" - y="-14.102674" - id="text3298-6"><tspan - sodipodi:role="line" - id="tspan3300-9" - x="169.91777" - y="-14.102674">got_poem</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="166.92039" - y="55.922184" - id="text3298-7"><tspan - sodipodi:role="line" - id="tspan3300-6" - x="166.92039" - y="55.922184">poem_done</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Bitstream Vera Sans" - x="346.06451" - y="-82.927536" - id="text3298-3"><tspan - sodipodi:role="line" - id="tspan3300-2" - x="346.06451" - y="-82.927536" - style="font-weight:normal;-inkscape-font-specification:Bitstream Vera Sans">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="349.58389" - y="-13.712689" - id="text3298-8"><tspan - sodipodi:role="line" - id="tspan3300-24" - x="349.58389" - y="-13.712689">poem_failed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="356.98865" - y="56.352459" - id="text3298-76"><tspan - sodipodi:role="line" - id="tspan3300-3" - x="356.98865" - y="56.352459">poem_done</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 457.76547,-157.97986 c -35.26407,20.69384 -7.75581,44.12795 -62.78184,36.88482" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="457.76547" - y="-157.97986" - id="text7565"><tspan - sodipodi:role="line" - x="457.76547" - y="-157.97986" - id="tspan8758">ConnectionRefusedError</tspan></text> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 389.322,-142.40426 4e-5,40.2995" - id="path6900-25-9-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="346.92252" - y="-145.25626" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="346.92252" - y="-145.25626">errback(err)</tspan></text> - <path - style="opacity:0.98999999;fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 389.92087,-70.849075 -0.69378,38.218036" - id="path6900-25-9-0-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 314.29752,-0.99869728 -40,39.66574328" - id="path6900-25-9-0-3-1" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 548.26178,-153.65029 c -38.03935,36.65173 -42.8327,111.309356 -151.28299,103.372406" - id="path7563-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 539.35041,-23.794948 C 519.35042,14.244422 389.66919,32.702507 297.1768,24.765547" - id="path7563-3-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="525.65027" - y="-24.438948" - id="text7565-6-7"><tspan - sodipodi:role="line" - x="525.65027" - y="-24.438948" - id="tspan8758-7-9">None</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-9.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-9.svg deleted file mode 100644 index 41e12b0..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-9.svg +++ /dev/null @@ -1,652 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="603" - height="452.07321" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - version="1.0" - sodipodi:docname="deferred-9.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-4.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8371" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-38" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8412-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter8473" - inkscape:label="Drop shadow" - width="1.5" - height="1.5" - x="-0.25" - y="-0.25" - color-interpolation-filters="sRGB"> - <feGaussianBlur - id="feGaussianBlur8475" - in="SourceAlpha" - stdDeviation="2.000000" - result="blur" /> - <feColorMatrix - id="feColorMatrix8477" - result="bluralpha" - type="matrix" - values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /> - <feOffset - id="feOffset8479" - in="bluralpha" - dx="4.000000" - dy="4.000000" - result="offsetBlur" /> - <feMerge - id="feMerge8481"> - <feMergeNode - id="feMergeNode8483" - in="offsetBlur" /> - <feMergeNode - id="feMergeNode8485" - in="SourceGraphic" /> - </feMerge> - </filter> - <inkscape:perspective - id="perspective8730" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4237" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="391.31438" - inkscape:cy="229.25167" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="false" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:snap-grids="true" - inkscape:snap-bbox-edge-midpoints="true" - borderlayer="false" - inkscape:snap-nodes="false"> - <sodipodi:guide - orientation="1,0" - position="-312.08705,950.51981" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-229.25454,537.36742" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(7.2024841,207.24821)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter8473)" - id="rect4537" - width="400" - height="299.38214" - x="94.297516" - y="-130.90268" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="150.06825" - height="29.377707" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="150.06825" - height="29.903984" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="150.06825" - height="30.430273" - x="124.22926" - y="38.667046" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="159.46164" - y="-83.353531" - id="text3298"><tspan - sodipodi:role="line" - id="tspan3300" - x="159.46164" - y="-83.353531">cummingsify</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240-3" - width="150.06825" - height="29.377707" - x="314.29752" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272-4" - width="150.06825" - height="29.903984" - x="314.29752" - y="-30.902681" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6" - width="150.06825" - height="30.430273" - x="314.29752" - y="39.097321" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="155.99626" - y="-14.102674" - id="text3298-6"><tspan - sodipodi:role="line" - id="tspan3300-9" - x="155.99626" - y="-14.102674">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="169.91777" - y="55.922184" - id="text3298-7"><tspan - sodipodi:role="line" - id="tspan3300-6" - x="169.91777" - y="55.922184">got_poem</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Bitstream Vera Sans" - x="346.06451" - y="-82.927536" - id="text3298-3"><tspan - sodipodi:role="line" - id="tspan3300-2" - x="346.06451" - y="-82.927536" - style="font-weight:normal;-inkscape-font-specification:Bitstream Vera Sans">pass-through</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="324.22827" - y="-13.712689" - id="text3298-8"><tspan - sodipodi:role="line" - id="tspan3300-24" - x="324.22827" - y="-13.712689">cummingsify_failed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="349.58389" - y="56.352459" - id="text3298-76"><tspan - sodipodi:role="line" - id="tspan3300-3" - x="349.58389" - y="56.352459">poem_failed</tspan></text> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-63" - width="150.06825" - height="30.430273" - x="124.22926" - y="109.53703" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284-6-2" - width="150.06825" - height="30.430273" - x="314.29752" - y="109.96732" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="166.92039" - y="126.79218" - id="text3298-7-0"><tspan - sodipodi:role="line" - id="tspan3300-6-3" - x="166.92039" - y="126.79218">poem_done</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="356.98865" - y="127.22245" - id="text3298-76-1"><tspan - sodipodi:role="line" - id="tspan3300-3-9" - x="356.98865" - y="127.22245">poem_done</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-cancel.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-cancel.svg deleted file mode 100644 index a9525bf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-cancel.svg +++ /dev/null @@ -1,551 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="396.27017" - height="241.65062" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="deferred-cancel.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-cancel.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8962" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="167.02156" - inkscape:cy="69.455711" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true"> - <sodipodi:guide - orientation="1,0" - position="-346.30384,824.02206" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-263.47133,410.86967" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-27.014313,123.32334)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect4537" - width="269.32486" - height="213.40648" - x="95.297516" - y="-122.32334" - rx="0" - ry="0" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3240" - width="79.684219" - height="27.921125" - x="124.22926" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3246" - width="79.684219" - height="27.921125" - x="253.54504" - y="-100.28039" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3272" - width="79.684219" - height="27.921125" - x="124.22926" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3278" - width="79.684219" - height="27.921125" - x="253.54504" - y="-30.806665" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3284" - width="79.684219" - height="27.921125" - x="124.22926" - y="38.667046" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect3290" - width="79.684219" - height="27.921125" - x="253.54504" - y="38.667046" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="M 292.88822,83.178009 342.51978,124.7306" - id="path6900" - transform="translate(-88.97474,-155.53727)" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 203.91348,-3.4381371 253.54504,38.667046" - id="path6900-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 293.34926,-72.29033 -4e-5,40.299489" - id="path6900-25" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 293.37758,-2.7629966 -4e-5,39.6056686" - id="path6900-25-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 255.93646,-72.359257 -49.63156,41.55259" - id="path6900-29" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 255.93646,-3.4381371 206.3049,38.667052" - id="path6900-2-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.50068,-72.290327 4e-5,40.29949" - id="path6900-25-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 166.47236,-2.7629941 4e-5,39.6056661" - id="path6900-25-3-8" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 60.638299,-119.53242 c 0,199.12677 0,199.12677 0,199.12677" - id="path7854" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" - x="60.582672" - y="100.83118" - id="text8948"><tspan - sodipodi:role="line" - id="tspan8950" - x="60.582672" - y="100.83118">Return</tspan><tspan - sodipodi:role="line" - x="60.582672" - y="115.83118" - id="tspan8952">Information</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Lstart);marker-end:none;display:inline" - d="m 399.24635,-119.53242 c 0,199.126769 0,199.126769 0,199.126769" - id="path7854-1" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Vera Sans" - x="399.19073" - y="100.83118" - id="text8948-5"><tspan - sodipodi:role="line" - id="tspan8950-6" - x="399.19073" - y="100.83118">Cancel</tspan><tspan - sodipodi:role="line" - x="399.19073" - y="115.83118" - id="tspan8952-5">Request</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-list.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-list.svg deleted file mode 100644 index d942cd1..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/deferred-list.svg +++ /dev/null @@ -1,937 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="610.03003" - height="340.26208" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="deferred-list.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/deferred-list.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7124" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective7754" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path7124-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7124-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7754-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-4" - style="overflow:visible"> - <path - id="path7124-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7124-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7808-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7124-73" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7849" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path7124-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7855" - style="overflow:visible"> - <path - id="path7857" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7859" - style="overflow:visible"> - <path - id="path7861" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7863" - style="overflow:visible"> - <path - id="path7865" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7867" - style="overflow:visible"> - <path - id="path7869" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker7871" - style="overflow:visible"> - <path - id="path7873" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7932" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7957-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7997" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8022" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8068" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-8" - style="overflow:visible"> - <path - id="path7124-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8100" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path7124-45" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4033" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4077-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4116" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-24" - style="overflow:visible"> - <path - id="path7124-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4144" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-62" - style="overflow:visible"> - <path - id="path7124-71" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4172" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-49" - style="overflow:visible"> - <path - id="path7124-24" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective4200" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-82" - style="overflow:visible"> - <path - id="path7124-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective5980" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-8" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6014" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6048" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-47" - style="overflow:visible"> - <path - id="path3871-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6086" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2950" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-63" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective2991" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5386" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5386-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5446" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective2943" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective2943-0" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective2982" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-76" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective3525" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-69" - style="overflow:visible"> - <path - id="path7124-29" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective3553" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-19" - style="overflow:visible"> - <path - id="path7124-63" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.038296" - inkscape:cx="267.47909" - inkscape:cy="173.29565" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-grids="false" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-midpoints="true" - inkscape:object-paths="true"> - <sodipodi:guide - orientation="1,0" - position="-351.77842,869.39846" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-268.94591,456.24607" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-32.488894,176.55842)" - style="display:inline"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect4537" - width="483.71573" - height="144.02432" - x="95.297516" - y="-130.6492" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 416.3576,-9.5242157 435.66423,59.946191" - id="path6900-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 141.08658,-10.115329 1.38674,71.399771" - id="path6900-6-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="33.964817" - y="78.09153" - id="text8088"><tspan - sodipodi:role="line" - id="tspan8090" - x="33.964817" - y="78.09153">( (True, result1), (True, result2), (False, failure3), (True, result4) )</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 181.8619,-170.10633 c 38.71489,1.30169 54.88336,7.47875 67.95147,39.6873" - id="path7563-4-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="161.51431" - y="131.08768" - id="text7565-6-6"><tspan - sodipodi:role="line" - x="161.51431" - y="131.08768" - id="tspan3577">The result of the DeferredList.</tspan><tspan - sodipodi:role="line" - x="161.51431" - y="146.08768" - id="tspan3581">Each element is a result from</tspan><tspan - sodipodi:role="line" - x="161.51431" - y="161.08768" - id="tspan3583">a deferred in the original list.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 149.41173,143.13909 C 94.594198,141.76164 39.258319,129.44587 36.046281,89.886495" - id="path7563-4-1-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="344.84259" - y="-166.93011" - id="text7565-6-6-3"><tspan - sodipodi:role="line" - x="344.84259" - y="-166.93011" - id="tspan6076-9">Deferreds in the list</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 335.82291,-170.39922 c -46.49167,2.78548 -54.44083,20.22484 -67.36637,57.67966" - id="path7563-4-1-1-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="98.535973" - y="-167.63042" - id="text7565-6-6-3-8"><tspan - sodipodi:role="line" - x="98.535973" - y="-167.63042" - id="tspan3024">A DeferredList</tspan></text> - <g - id="g5426" - transform="translate(-498.73454,-106.05399)"> - <rect - y="-1.5996236" - x="616.46637" - height="97.538284" - width="87.932358" - id="rect4537-9" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" /> - <g - id="g5422"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;display:inline" - id="rect3240-4" - width="20.01557" - height="14.044698" - x="630.9978" - y="11.006677" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;display:inline" - id="rect3240-4-8" - width="20.01557" - height="14.044698" - x="669.85181" - y="11.006677" /> - </g> - <g - transform="translate(-2.8407636,-6.7831508)" - id="g5414"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;display:inline" - id="rect3240-4-9" - width="20.01557" - height="14.044698" - x="635.2262" - y="48.162891" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;display:inline" - id="rect3240-4-8-2" - width="20.01557" - height="14.044698" - x="674.0802" - y="48.162891" /> - </g> - <g - transform="translate(-1.4531206,-31.915789)" - id="g5418"> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;display:inline" - id="rect3240-4-3" - width="20.01557" - height="14.044698" - x="631.06329" - y="103.66861" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;display:inline" - id="rect3240-4-8-6" - width="20.01557" - height="14.044698" - x="669.9173" - y="103.66861" /> - </g> - </g> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect4537-9-3" - width="87.932358" - height="97.538284" - x="235.19974" - y="-108.24473" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect4537-9-3-4" - width="87.932358" - height="97.538284" - x="352.66763" - y="-107.0625" /> - <rect - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" - id="rect4537-9-3-5" - width="87.932358" - height="97.538284" - x="470.13553" - y="-107.75632" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 452.12436,-170.38663 c 29.13487,2.09166 55.87679,32.0198 58.90914,56.29202" - id="path7563-4-1-1-1-7" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="m 255.20442,-10.706444 29.57272,72.060403" - id="path6900-6-7-0" - sodipodi:nodetypes="cc" /> - <path - style="fill:#ff0000;fill-opacity:1;stroke:#3cff3c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Mend);display:inline" - d="M 493.49028,-10.218033 583.4546,64.440409" - id="path6900-6-7-0-6" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-1.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-1.svg deleted file mode 100644 index 8420667..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-1.svg +++ /dev/null @@ -1,552 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="203.08299" - height="289.59155" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="erlang-1.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/erlang-1.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Send" - orient="auto" - refY="0" - refX="0" - id="Arrow1Send" - style="overflow:visible"> - <path - id="path4504" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path4516" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5988" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker5994" - style="overflow:visible"> - <path - id="path5996" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6439" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-2" /> - </marker> - <marker - style="overflow:visible" - id="marker6445" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447" /> - </marker> - <inkscape:perspective - id="perspective6439-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-7" /> - </marker> - <marker - style="overflow:visible" - id="marker6445-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447-1" /> - </marker> - <inkscape:perspective - id="perspective6492" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-59" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-59" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520-5" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-63" - style="overflow:visible"> - <path - id="path3871-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7014" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7039" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-49" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker7045" - style="overflow:visible"> - <path - id="path7047" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7075" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-03" - style="overflow:visible"> - <path - id="path3871-06" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker7081" - style="overflow:visible"> - <path - id="path7083" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7113" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="141.54333" - inkscape:cy="136.6558" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1"> - <sodipodi:guide - orientation="1,0" - position="-319.37862,683.74324" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-236.54611,270.59085" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-266.18305,44.114674)"> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 c 7.2195,0.024 13.05259,5.89606 13.02857,13.11557 -0.024,7.21951 -5.89607,13.0526 -13.11557,13.02857 -7.21951,-0.024 -13.0526,-5.89606 -13.02858,-13.11557 0.0238,-7.14766 5.78405,-12.95093 12.93133,-13.02789" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-194.57683,-174.4513)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-0" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 c 7.2195,0.024 13.05259,5.89606 13.02857,13.11557 -0.024,7.21951 -5.89607,13.0526 -13.11557,13.02857 -7.21951,-0.024 -13.0526,-5.89606 -13.02858,-13.11557 0.0238,-7.14766 5.78405,-12.95093 12.93133,-13.02789" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-267.89424,-175.40838)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-6" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 c 7.2195,0.024 13.05259,5.89606 13.02857,13.11557 -0.024,7.21951 -5.89607,13.0526 -13.11557,13.02857 -7.21951,-0.024 -13.0526,-5.89606 -13.02858,-13.11557 0.0238,-7.14766 5.78405,-12.95093 12.93133,-13.02789" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-341.21165,-173.44596)" - sodipodi:open="true" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 318.64882,135.49821 -24.03969,42.1921" - id="path3379-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 367.70693,140.22962 0,34.34241" - id="path3379-9-6" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 414.77981,135.49821 24.03969,42.1921" - id="path3379-9-2" - sodipodi:nodetypes="cc" /> - <g - id="g7141" - transform="translate(2.6142344,0)"> - <path - sodipodi:open="true" - transform="matrix(1.3874983,0,0,1.2111208,-270.50847,-328.36062)" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - d="m 458.32888,240.35509 c 37.29285,0.12409 67.42408,30.45652 67.29998,67.74937 -0.1241,37.29285 -30.45652,67.42407 -67.74937,67.29997 -37.29285,-0.12409 -67.42407,-30.45652 -67.29998,-67.74937 0.12287,-36.9217 29.87786,-66.89889 66.79763,-67.29643" - sodipodi:ry="67.525047" - sodipodi:rx="67.525047" - sodipodi:cy="307.87976" - sodipodi:cx="458.10419" - id="path2554-5" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.53025278, 5.06050555;stroke-dashoffset:0;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none" - sodipodi:type="arc" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="310.40295" - y="48.662956" - id="text2391-4"><tspan - style="font-size:16px" - sodipodi:role="line" - id="tspan2393" - x="310.40295" - y="48.662956">Erlang Runtime</tspan></text> - </g> - <text - id="text2391-4-6" - y="242.42488" - x="317.211" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="242.42488" - x="317.211" - id="tspan2393-3" - sodipodi:role="line" - style="font-size:14px">Erlang Processes</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-2.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-2.svg deleted file mode 100644 index 370e00d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-2.svg +++ /dev/null @@ -1,925 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="345" - height="238.99316" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="erlang-2.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/erlang-2.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Send" - orient="auto" - refY="0" - refX="0" - id="Arrow1Send" - style="overflow:visible"> - <path - id="path4504" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path4516" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5988" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker5994" - style="overflow:visible"> - <path - id="path5996" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6439" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-2" /> - </marker> - <marker - style="overflow:visible" - id="marker6445" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447" /> - </marker> - <inkscape:perspective - id="perspective6439-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-7" /> - </marker> - <marker - style="overflow:visible" - id="marker6445-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447-1" /> - </marker> - <inkscape:perspective - id="perspective6492" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-59" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-59" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520-5" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-63" - style="overflow:visible"> - <path - id="path3871-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7014" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7039" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-49" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker7045" - style="overflow:visible"> - <path - id="path7047" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7075" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-03" - style="overflow:visible"> - <path - id="path3871-06" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker7081" - style="overflow:visible"> - <path - id="path7083" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7113" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7180" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-6" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-9" /> - </marker> - <marker - style="overflow:visible" - id="marker7186" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188" /> - </marker> - <inkscape:perspective - id="perspective7180-0" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-42" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-0" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-2" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-0" /> - </marker> - <inkscape:perspective - id="perspective7180-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-5" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-3" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-8" /> - </marker> - <inkscape:perspective - id="perspective7180-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-5" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-6" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-4" /> - </marker> - <inkscape:perspective - id="perspective7180-89" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-73" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-1" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-86" /> - </marker> - <inkscape:perspective - id="perspective7180-2" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-3" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-3" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-46" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-7" /> - </marker> - <inkscape:perspective - id="perspective7180-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-70" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-14" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-49" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-2" /> - </marker> - <inkscape:perspective - id="perspective7824" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path4516-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7852" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path4516-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7880" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="191.82478" - inkscape:cy="116.49731" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:object-paths="true" - inkscape:snap-smooth-nodes="true"> - <sodipodi:guide - orientation="1,0" - position="-285.75802,688.40277" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-202.92551,275.25038" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-232.56245,-11.143252)"> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-198.81365,-297.95153)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-0" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-270.74342,-312.09122)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-6" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-345.44847,-297.64001)" - sodipodi:open="true" /> - <text - id="text2391-4" - y="22.919254" - x="238.20496" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="22.919254" - x="238.20496" - id="tspan2393" - sodipodi:role="line" - style="font-size:16px">Erlang Runtime</tspan></text> - <text - id="text2391-4-6" - y="247.08441" - x="357.84894" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="247.08441" - x="357.84894" - id="tspan2393-3" - sodipodi:role="line" - style="font-size:14px">Erlang Processes</tspan></text> - <rect - style="fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect7170" - width="331.159" - height="191.3363" - x="239.48296" - y="27.157255" - ry="10.927689" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-3" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-125.28445,-298.77662)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-67" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-348.69498,-242.57708)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-8" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-269.59933,-242.57708)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-9" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-307.75951,-188.459)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-39" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-192.58514,-243.96472)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-7" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-196.74807,-198.1725)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-4" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-116.95859,-225.23154)" - sodipodi:open="true" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 503.4723,88.762646 c -6.82259,15.806904 -6.11811,31.076164 5.36193,45.575734" - id="path7310" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 436.27842,231.00721 c 2.00831,-12.51365 -12.75594,-24.80617 -6.67256,-42.68659" - id="path7310-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 365.8735,229.90253 c -2.71619,-28.27355 -10.80533,-19.64699 -21.80209,-38.37544" - id="path7310-3-6" - sodipodi:nodetypes="cc" /> - <text - id="text2391-4-6-2" - y="111.4867" - x="509.36386" - style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="111.4867" - x="509.36386" - id="tspan2393-3-9" - sodipodi:role="line" - style="font-size:10px">Message</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-3.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-3.svg deleted file mode 100644 index a03a064..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/erlang-3.svg +++ /dev/null @@ -1,958 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="345" - height="238.99316" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="erlang-3.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/erlang-3.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Send" - orient="auto" - refY="0" - refX="0" - id="Arrow1Send" - style="overflow:visible"> - <path - id="path4504" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path4516" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5988" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker5994" - style="overflow:visible"> - <path - id="path5996" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6439" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-2" /> - </marker> - <marker - style="overflow:visible" - id="marker6445" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447" /> - </marker> - <inkscape:perspective - id="perspective6439-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-7" /> - </marker> - <marker - style="overflow:visible" - id="marker6445-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447-1" /> - </marker> - <inkscape:perspective - id="perspective6492" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-59" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-59" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520-5" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-63" - style="overflow:visible"> - <path - id="path3871-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7014" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7039" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-49" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker7045" - style="overflow:visible"> - <path - id="path7047" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7075" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-03" - style="overflow:visible"> - <path - id="path3871-06" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker7081" - style="overflow:visible"> - <path - id="path7083" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective7113" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective7180" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-6" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-9" /> - </marker> - <marker - style="overflow:visible" - id="marker7186" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188" /> - </marker> - <inkscape:perspective - id="perspective7180-0" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-42" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-0" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-2" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-0" /> - </marker> - <inkscape:perspective - id="perspective7180-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-5" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-3" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-8" /> - </marker> - <inkscape:perspective - id="perspective7180-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-5" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-6" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-4" /> - </marker> - <inkscape:perspective - id="perspective7180-89" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-73" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-1" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-86" /> - </marker> - <inkscape:perspective - id="perspective7180-2" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-3" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-3" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-46" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-7" /> - </marker> - <inkscape:perspective - id="perspective7180-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-70" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-14" /> - </marker> - <marker - style="overflow:visible" - id="marker7186-49" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path7188-2" /> - </marker> - <inkscape:perspective - id="perspective7824" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path4516-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7852" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-6" - style="overflow:visible"> - <path - id="path4516-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective7880" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8344" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path4516-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8372" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8397" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-1" - style="overflow:visible"> - <path - id="path4516-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8425" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-5" - style="overflow:visible"> - <path - id="path4516-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8453" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="147.91555" - inkscape:cy="116.49731" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:object-paths="true" - inkscape:snap-smooth-nodes="true"> - <sodipodi:guide - orientation="1,0" - position="-285.75802,688.40277" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-202.92551,275.25038" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-232.56245,-11.143252)"> - <text - id="text2391-4" - y="22.919254" - x="238.20496" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="22.919254" - x="238.20496" - id="tspan2393" - sodipodi:role="line" - style="font-size:16px">Erlang Runtime</tspan></text> - <text - id="text2391-4-6" - y="244.63138" - x="321.78598" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="244.63138" - x="321.78598" - id="tspan2393-3" - sodipodi:role="line" - style="font-size:12px">get_poetry processes</tspan></text> - <rect - style="fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="rect7170" - width="272.77689" - height="191.3363" - x="239.48296" - y="27.157255" - ry="10.927689" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-3" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-256.71635,-302.91438)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-8" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-256.71635,-217.25794)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-9" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-330.81798,-217.25794)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-7" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 a 13.072145,13.072145 0 1 1 -0.18425,6.8e-4" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-183.07852,-217.25794)" - sodipodi:open="true" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 315.84591,143.06271 c -6.82259,-15.8069 33.78841,-30.08303 46.74028,-58.810162" - id="path7310" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 381.82116,231.00721 c 0,0 -1.43176,-53.71873 -1.43176,-53.71873" - id="path7310-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 358.0238,232.35556 c 0,0 -38.65764,-60.47704 -38.65764,-60.47704" - id="path7310-3-6" - sodipodi:nodetypes="cc" /> - <text - id="text2391-4-6-2" - y="105.10883" - x="310.05603" - style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="105.10883" - x="310.05603" - id="tspan2393-3-9" - sodipodi:role="line" - style="font-size:10px">poem</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 411.43897,233.80544 c 0,0 31.84984,-55.50304 31.84984,-55.50304" - id="path7310-3-6-1" - sodipodi:nodetypes="cc" /> - <text - id="text2391-4-6-5" - y="49.544178" - x="428.68607" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="49.544178" - x="428.68607" - id="tspan2393-3-1" - sodipodi:role="line" - style="font-size:12px">main process</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="M 424.14001,39.728725 C 408.48651,25.393643 394.19464,33.965732 386.05045,49.883731" - id="path7310-8" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 394.13299,147.02131 c 13.69107,-10.41023 22.90683,-40.46413 2.59587,-62.322773" - id="path7310-0" - sodipodi:nodetypes="cc" /> - <text - id="text2391-4-6-2-2" - y="107.26329" - x="413.72076" - style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="107.26329" - x="413.72076" - id="tspan2393-3-9-1" - sodipodi:role="line" - style="font-size:10px">DOWN</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/generator-callbacks.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/generator-callbacks.svg deleted file mode 100644 index b916823..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/generator-callbacks.svg +++ /dev/null @@ -1,403 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="427.67349" - height="234.71854" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - sodipodi:docname="generator-callbacks.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/generator-callbacks.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart" - style="overflow:visible"> - <path - id="path4011" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective4861" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4930" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4955" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4983" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5566" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5591" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart-1" - style="overflow:visible"> - <path - id="path4011-9" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <inkscape:perspective - id="perspective5995" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6028" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6127" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8725" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective10522" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective10566" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-7" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective10566-2" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective10619" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective10619-5" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2" - inkscape:cx="183.50088" - inkscape:cy="116.94389" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1" - inkscape:snap-grids="false" - inkscape:snap-bbox="true" - inkscape:bbox-nodes="true" - inkscape:guide-bbox="true"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-116.90566,-34.785388)"> - <text - xml:space="preserve" - style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="-67" - y="-30.826294" - id="text6016" - transform="translate(211.35366,52.49804)"><tspan - sodipodi:role="line" - id="tspan6018" - x="-67" - y="-30.826294" /></text> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="116.90566" - y="46.019753" - id="text2403-1-2" - inkscape:export-filename="/home/dave/src/twisted-intro/images/rect4851.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"><tspan - sodipodi:role="line" - id="tspan2405-6-9" - x="116.90566" - y="46.019753">def my_generator(arg1, arg2):</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="66.019737" - id="tspan8744"> blah = blah * arg1</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="86.019714" - id="tspan8748"> blah2 = blahblah(blah)</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="106.0197" - id="tspan8750"> result = yield blah * 3</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="126.01968" - id="tspan8752" /><tspan - sodipodi:role="line" - x="116.90566" - y="146.01967" - id="tspan8754"> foo = result + 7</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="166.01964" - id="tspan8758"> result = yield something()</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="186.01962" - id="tspan8762" /><tspan - sodipodi:role="line" - x="116.90566" - y="206.01961" - id="tspan8764"> try:</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="226.01959" - id="tspan8766"> something_else(result)</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="246.01958" - id="tspan8768"> except BadThings:</tspan><tspan - sodipodi:role="line" - x="116.90566" - y="266.01956" - id="tspan8770"> handle_bad_things(arg2)</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="409.99454" - y="81.519753" - id="text7565-6-6"><tspan - sodipodi:role="line" - x="409.99454" - y="81.519753" - id="tspan6076">First Callback</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="411.69141" - y="156.74237" - id="text7565-6-6-5"><tspan - sodipodi:role="line" - x="411.69141" - y="156.74237" - id="tspan6076-4">Second Callback</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="410.10254" - y="238.74237" - id="text7565-6-6-2"><tspan - sodipodi:role="line" - x="410.10254" - y="238.74237" - id="tspan6076-41">Third Callback</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 400.40566,55.003924 0,51.999996" - id="path10609" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 399.90566,134.50392 0,38" - id="path10609-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 398.40566,200.00392 0,67" - id="path10609-0" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/haskell.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/haskell.svg deleted file mode 100644 index e9d4598..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/haskell.svg +++ /dev/null @@ -1,525 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="469.81" - height="177.26727" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="haskell.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/haskell.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Send" - orient="auto" - refY="0" - refX="0" - id="Arrow1Send" - style="overflow:visible"> - <path - id="path4504" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path4516" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5988" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker5994" - style="overflow:visible"> - <path - id="path5996" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6439" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-2" /> - </marker> - <marker - style="overflow:visible" - id="marker6445" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447" /> - </marker> - <inkscape:perspective - id="perspective6439-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-7" /> - </marker> - <marker - style="overflow:visible" - id="marker6445-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447-1" /> - </marker> - <inkscape:perspective - id="perspective6492" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-59" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-59" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520-5" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-63" - style="overflow:visible"> - <path - id="path3871-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9391" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9391-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9794" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-44" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9822" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-57" - style="overflow:visible"> - <path - id="path3871-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9850" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-00" - style="overflow:visible"> - <path - id="path3871-45" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="203.30154" - inkscape:cy="68.91073" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1"> - <sodipodi:guide - orientation="1,0" - position="-285.78037,674.87088" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-202.94786,261.71849" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-232.5848,-59.337246)"> - <g - id="g3374" - transform="translate(6.9049173,-104.42405)"> - <path - sodipodi:open="true" - transform="matrix(1.3874983,0,0,1.2111208,-308.3974,-120.48465)" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - d="m 458.32888,240.35509 a 67.525047,67.525047 0 1 1 -0.95174,0.004" - sodipodi:ry="67.525047" - sodipodi:rx="67.525047" - sodipodi:cy="307.87976" - sodipodi:cx="458.10419" - id="path2554-2" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.26512631, 1.26512631;stroke-dashoffset:0;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none" - sodipodi:type="arc" /> - <text - id="text2391-4" - y="258.20294" - x="269.49838" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="258.20294" - x="269.49838" - id="tspan2393" - sodipodi:role="line">Haskell Runtime</tspan></text> - </g> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" - x="476.42191" - y="81.995453" - id="text9379"><tspan - sodipodi:role="line" - id="tspan9381" - x="476.42191" - y="81.995453">[1, 2, 3, 4, 5, ...]</tspan></text> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" - x="476.42191" - y="152.73074" - id="text9379-2"><tspan - sodipodi:role="line" - id="tspan9381-0" - x="476.42191" - y="152.73074">[2, 4, 6, 8, 10, ...]</tspan></text> - <text - xml:space="preserve" - style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" - x="476.42191" - y="223.46603" - id="text9379-1"><tspan - sodipodi:role="line" - id="tspan9381-1" - x="476.42191" - y="223.46603">[3, 6, 9, 12, 15, ...]</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="M 470.42893,75.591039 420.47378,98.8323" - id="path3379-9-6" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="M 470.79487,217.23405 420.83972,193.99279" - id="path3379-9-6-3" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 473.57759,140.89771 -31.22198,0.34867" - id="path3379-9-6-3-4" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/inline-callbacks.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/inline-callbacks.svg deleted file mode 100644 index c892ef5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/inline-callbacks.svg +++ /dev/null @@ -1,436 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="653.93842" - height="582.4375" - id="svg2" - version="1.1" - inkscape:version="0.47 r22583" - sodipodi:docname="inline-callbacks.svg" - inkscape:export-filename="/home/dave/src/twisted-intro/images/inline-callbacks.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path3808" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="CurveOut" - orient="auto" - refY="0" - refX="0" - id="CurveOut" - style="overflow:visible"> - <path - id="path3969" - d="m -5.4129913,-5.0456926 c 2.76,0 4.99999999,2.24 4.99999999,5.00000002 0,2.75999998 -2.23999999,4.99999998 -4.99999999,4.99999998" - style="fill:none;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none" - transform="scale(0.6,0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3802" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lend" - style="overflow:visible"> - <path - id="path3784" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.8,0,0,-0.8,-10,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective4672" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5490" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5518" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5545" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3802-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5573" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5613" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-64" - style="overflow:visible"> - <path - id="path3802-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5641" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5685" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-62" - style="overflow:visible"> - <path - id="path3802-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5722" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-8" - style="overflow:visible"> - <path - id="path3802-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5775" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3802-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5803" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="0.98994949" - inkscape:cx="367.19792" - inkscape:cy="226.8877" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:snap-bbox="true" - inkscape:bbox-nodes="true" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:object-paths="true" - inkscape:snap-midpoints="true" - inkscape:snap-global="false" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-39.177129,-11.405061)"> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 4;stroke-dashoffset:0;marker-start:none" - d="m 356.24603,11.905061 0,581.437499" - id="path2816" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="224.43396" - y="21.709061" - id="text7565"><tspan - sodipodi:role="line" - x="224.43396" - y="21.709061" - id="tspan8758">The reactor loop</tspan></text> - <text - id="text4716" - y="21.709061" - x="387.13882" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - id="tspan4718" - y="21.709061" - x="387.13882" - sodipodi:role="line">Inline Callbacks</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)" - d="m 275,44.505039 0,80.714281 167.85714,0 0,76.42858 -167.85714,0 0,226.42857 167.85714,0 0,77.14286 -167.85714,0 0,76.01886" - id="path4720" - sodipodi:nodetypes="cccccccccc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 135.48388,142.32512 c 20.14889,-37.21173 60.40898,-34.80015 119.31306,-19.1261" - id="path7563-4" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="55.433472" - y="163.25664" - id="text7565-0"><tspan - sodipodi:role="line" - x="55.433472" - y="163.25664" - id="tspan8758-5">The generator function is called</tspan><tspan - sodipodi:role="line" - x="55.433472" - y="180.75664" - id="tspan5535">and the first inline callback runs.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 517.92252,174.45894 c -13.07782,16.32635 -6.12345,31.82197 -49.87524,26.28281" - id="path7563-4-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="531.0545" - y="169.40817" - id="text7565-0-3"><tspan - sodipodi:role="line" - x="531.0545" - y="169.40817" - id="tspan8758-5-1">The generator yields a</tspan><tspan - sodipodi:role="line" - x="531.0545" - y="186.90817" - id="tspan5535-3">deferred here. Control</tspan><tspan - sodipodi:role="line" - x="531.0545" - y="204.40817" - id="tspan5599">returns to the reactor.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 500.11917,331.51195 c -13.07782,16.32635 -69.76306,3.5377 -101.39302,-23.21466" - id="path7563-4-1-1" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="500.15717" - y="285.30215" - id="text7565-0-3-1"><tspan - sodipodi:role="line" - x="500.15717" - y="285.30215" - id="tspan5599-8">During this period unrelated</tspan><tspan - sodipodi:role="line" - x="500.15717" - y="302.80215" - id="tspan5675">callbacks and deferreds</tspan><tspan - sodipodi:role="line" - x="500.15717" - y="320.30215" - id="tspan5833">may fire.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="M 96.780178,463.31462 C 148.2438,495.80342 209.7171,434.57539 250.43843,428.02608" - id="path7563-4-7" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="44.003891" - y="433.73853" - id="text7565-0-6"><tspan - sodipodi:role="line" - x="44.003891" - y="433.73853" - id="tspan8758-5-7">The deferred yielded above</tspan><tspan - sodipodi:role="line" - x="44.003891" - y="451.23853" - id="tspan5535-4">is fired here</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 515.41488,455.41424 c -13.07782,16.32635 -6.12345,31.82197 -49.87524,26.28281" - id="path7563-4-1-11" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="528.54688" - y="450.36346" - id="text7565-0-3-8"><tspan - sodipodi:role="line" - x="528.54688" - y="450.36346" - id="tspan5599-9">The generator resumes</tspan><tspan - sodipodi:role="line" - x="528.54688" - y="467.86346" - id="tspan4727">and the second inline</tspan><tspan - sodipodi:role="line" - x="528.54688" - y="485.36346" - id="tspan5765">callback runs.</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend);display:inline" - d="m 206.37833,60.990843 c 21.15905,-24.07974 20.00289,-16.617399 57.69376,-13.065184" - id="path7563-4-8" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="61.495102" - y="61.473606" - id="text7565-0-9"><tspan - sodipodi:role="line" - x="61.495102" - y="61.473606" - id="tspan5535-9">The thread of control.</tspan><tspan - sodipodi:role="line" - x="61.495102" - y="78.97361" - id="tspan5825">Time is going downwards.</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/protocols-1.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/protocols-1.svg deleted file mode 100644 index 6781526..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/protocols-1.svg +++ /dev/null @@ -1,302 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="482.08957" - height="358.32596" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="protocols-1.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/protocol-1.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " - transform="scale(1.1) translate(1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="258.65281" - inkscape:cy="208.45409" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="27"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-14.229261,120.18522)" - style="display:inline"> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.03557789;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4537" - width="139.46442" - height="99.964424" - x="133.92305" - y="-102.79601" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="133.05527" - y="-107.26322" - id="text4539"><tspan - sodipodi:role="line" - id="tspan4541" - x="133.05527" - y="-107.26322">Protocol Factory</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.20609272;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4545" - width="139.79391" - height="160.24844" - x="134.0083" - y="77.289246" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="133.55527" - y="74.3442" - id="text4547"><tspan - sodipodi:role="line" - id="tspan4549" - x="133.55527" - y="74.3442">Protocol</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.12293684;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - d="M 233.90554,-1.7523316 L 233.90554,75.07236" - id="path4553" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="172.44125" - y="-78.97126" - id="text6415"><tspan - sodipodi:role="line" - id="tspan6417" - x="172.44125" - y="-78.97126">.buildProtocol()</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="238.79213" - y="18.680021" - id="text6423"><tspan - sodipodi:role="line" - id="tspan6425" - x="238.79213" - y="18.680021">2. which builds an</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="133.90526" - y="97.186203" - id="text6427"><tspan - sodipodi:role="line" - id="tspan6429" - x="133.90526" - y="97.186203">.factory</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1" - d="M -80,-54.33844 C -80,-54.33844 -137.18171,-118.42992 -130,-154.33846 C -120,-204.33846 -80,-224.33844 -80,-224.33844" - id="path6431" - transform="translate(213.90526,151.52464)" - sodipodi:nodetypes="csc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="13.905261" - y="-58.641823" - id="text6966"><tspan - sodipodi:role="line" - id="tspan6968" - x="13.905261" - y="-58.641823">5. which refers to</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 400.92787,-93.998692 C 372.56074,-114.5046 298.34128,-102.55493 274.22926,-87.255927" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="404.22925" - y="-81.859261" - id="text7565"><tspan - sodipodi:role="line" - id="tspan7567" - x="404.22925" - y="-81.859261">1. Twisted calls</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 233.90526,51.358176 C 233.90526,51.358176 273.90526,65.807604 253.90526,115.80761 C 247.35118,132.19281 221.75633,140.57332 212.23112,133.03232 C 196.27939,120.40352 183.90526,101.35818 183.90526,101.35818" - id="path7569" - sodipodi:nodetypes="cssc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="203.90526" - y="151.35817" - id="text7571"><tspan - sodipodi:role="line" - id="tspan7573" - x="203.90526" - y="151.35817">4. and sets</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="138.83687" - y="-11.204698" - id="text7575"><tspan - sodipodi:role="line" - id="tspan7577" - x="138.83687" - y="-11.204698">.protocol</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Lstart);marker-end:none;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline;marker-mid:none" - d="M 164.22926,-1.8592617 C 184.22926,28.140738 204.22926,38.140738 234.22926,43.140738" - id="path7579" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="120.39326" - y="39.864738" - id="text9721"><tspan - sodipodi:role="line" - id="tspan9723" - x="120.39326" - y="39.864738">3. instance of</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/protocols-2.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/protocols-2.svg deleted file mode 100644 index 4f4c466..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/protocols-2.svg +++ /dev/null @@ -1,335 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="491.15036" - height="428.32596" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="protocols-2.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/protocols-2.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="258.65281" - inkscape:cy="208.45409" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="27"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-82.78128,120.18522)" - style="display:inline"> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.03557789;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4537" - width="139.46442" - height="99.964424" - x="133.92305" - y="-102.79601" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="133.05527" - y="-107.26322" - id="text4539"><tspan - sodipodi:role="line" - id="tspan4541" - x="133.05527" - y="-107.26322">Protocol Factory</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.58935499;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4545" - width="169.23466" - height="229.86519" - x="134.19994" - y="77.480873" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="133.55527" - y="74.3442" - id="text4547"><tspan - sodipodi:role="line" - id="tspan4549" - x="133.55527" - y="74.3442">Protocol</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="139.46007" - y="97.080742" - id="text6427"><tspan - sodipodi:role="line" - id="tspan6429" - x="139.46007" - y="97.080742">.factory</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1" - d="M -80,-54.33844 C -80,-54.33844 -137.18171,-118.42992 -130,-154.33846 C -120,-204.33846 -80,-224.33844 -80,-224.33844" - id="path6431" - transform="translate(213.90526,151.52464)" - sodipodi:nodetypes="csc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 404.22926,68.140738 C 394.22926,108.14074 339.11009,106.43134 304.22926,118.14074" - id="path7563" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="404.22925" - y="68.140739" - id="text7565"><tspan - sodipodi:role="line" - id="tspan7567" - x="404.22925" - y="68.140739">1. Twisted calls</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="139.46007" - y="122.59674" - id="text9876"><tspan - sodipodi:role="line" - id="tspan9878" - x="139.46007" - y="122.59674">.makeConnection(transport)</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.9157092;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect9880" - width="129.24455" - height="99.913368" - x="444.22925" - y="138.14073" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="443.53317" - y="135.00616" - id="text9882"><tspan - sodipodi:role="line" - id="tspan9884" - x="443.53317" - y="135.00616">Transport</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="234.22926" - y="198.14073" - id="text9886"><tspan - sodipodi:role="line" - id="tspan9888" - x="234.22926" - y="198.14073">.transport</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 244.22926,128.14074 C 234.22926,168.14074 266.72243,148.14074 264.22926,188.14074" - id="path9890" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="164.22926" - y="158.14073" - id="text9892"><tspan - sodipodi:role="line" - id="tspan9894" - x="164.22926" - y="158.14073">2. which sets</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 304.22926,198.14074 C 304.22926,198.14074 414.22926,198.14074 444.22926,198.14074" - id="path9896" - sodipodi:nodetypes="cs" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="327.0329" - y="191.25563" - id="text9898"><tspan - sodipodi:role="line" - id="tspan9900" - x="327.0329" - y="191.25563">3. which refers to</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 252.78128,158.14074 C 222.78128,178.14074 212.78128,198.14074 232.78128,238.14074" - id="path9902" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="232.78128" - y="248.14073" - id="text9904"><tspan - sodipodi:role="line" - id="tspan9906" - x="232.78128" - y="248.14073">.connected</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="141.3521" - y="225.69273" - id="text9908"><tspan - sodipodi:role="line" - id="tspan9910" - x="141.3521" - y="225.69273">4. and also sets</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.61072743;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:0.6107274, 0.6107274;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 302.58664,248.14161 C 302.58664,248.14161 341.67428,248.14161 352.33455,248.14161" - id="path9912" - sodipodi:nodetypes="cs" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="355.55658" - y="250.91602" - id="text9918"><tspan - sodipodi:role="line" - id="tspan9920" - x="355.55658" - y="250.91602">True</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/proxy.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/proxy.svg deleted file mode 100644 index d94c2dc..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/proxy.svg +++ /dev/null @@ -1,886 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="665.88116" - height="433.69446" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="proxy.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/proxy.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4552" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective3669" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3696" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3979" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4219" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4328" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4356" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-4" - style="overflow:visible"> - <path - id="path3871-5-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4384" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4511" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-0" - style="overflow:visible"> - <path - id="path3871-5-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-7" - style="overflow:visible"> - <path - id="path4552-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-47" - style="overflow:visible"> - <path - id="path3871-5-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005-9" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-77" - style="overflow:visible"> - <path - id="path4552-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-41" - style="overflow:visible"> - <path - id="path3871-5-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5056" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5110" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5154" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5182" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-64" - style="overflow:visible"> - <path - id="path3871-16" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5210" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-5" - style="overflow:visible"> - <path - id="path4552-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-9" - style="overflow:visible"> - <path - id="path3871-5-15" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5462" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5522" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-09" - style="overflow:visible"> - <path - id="path3871-5-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5713" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-1" - style="overflow:visible"> - <path - id="path3871-5-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5741" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-00" - style="overflow:visible"> - <path - id="path3871-5-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5788" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5836" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5903" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-91" - style="overflow:visible"> - <path - id="path3871-5-89" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5931" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-6" - style="overflow:visible"> - <path - id="path3871-5-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5994" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5994-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6066" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-5" - style="overflow:visible"> - <path - id="path3871-5-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6094" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-3" - style="overflow:visible"> - <path - id="path3871-5-29" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6094-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-39" - style="overflow:visible"> - <path - id="path3871-5-49" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6137" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-08" - style="overflow:visible"> - <path - id="path3871-5-35" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6182" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-2" - style="overflow:visible"> - <path - id="path3871-5-25" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.019148" - inkscape:cx="326.07198" - inkscape:cy="199.33837" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="false" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:object-paths="true" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-smooth-nodes="true"> - <sodipodi:guide - orientation="1,0" - position="171.49144,900.54333" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="254.32395,487.39094" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(224.68701,-28.582576)"> - <g - id="g5141" - transform="translate(172.19327,0)"> - <path - sodipodi:open="true" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - transform="translate(177.11921,58.508332)" - d="m -150.97601,-29.925756 c 21.67621,0.398521 39.18978,97.80712 39.11765,217.568196 -0.0721,119.76107 -17.70265,216.52354 -39.37886,216.12502 -21.67621,-0.39852 -39.18978,-97.80712 -39.11765,-217.56819 0.0714,-118.569201 17.3663,-214.837005 38.82567,-216.113656" - sodipodi:ry="216.84781" - sodipodi:rx="39.24847" - sodipodi:cy="186.92085" - sodipodi:cx="-151.10661" - id="path3647" - style="opacity:0.98999999;fill:#a1e7c2;fill-opacity:1;stroke:none" - sodipodi:type="arc" /> - <text - id="text2391-0" - y="129.76579" - x="26.032473" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:tb-rl;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="26.032473" - x="129.76579" - id="tspan2393-2" - sodipodi:role="line">The Internet</tspan></text> - </g> - <g - id="g5821" - transform="translate(-79.615461,114.69943)"> - <g - transform="translate(1.2380755,-118.87857)" - id="g5130"> - <rect - style="opacity:0.98999999;fill:#8589ed;fill-opacity:1;stroke:none" - id="rect3686-6-9-9" - width="79.478157" - height="52.004227" - x="411.13821" - y="219.18733" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="450.8313" - y="239.33345" - id="text2391-8-2-6-0"><tspan - id="tspan5086" - sodipodi:role="line" - x="450.8313" - y="239.33345">External</tspan><tspan - sodipodi:role="line" - x="450.8313" - y="259.33344" - id="tspan6159">Server</tspan></text> - </g> - </g> - <g - id="g5130-7" - transform="translate(-427.09189,0.24036364)"> - <rect - y="219.18733" - x="411.13821" - height="52.004227" - width="79.478157" - id="rect3686-6-9-9-5" - style="opacity:0.98999999;fill:#bde07e;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-9" - y="248.81345" - x="450.53442" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="248.81345" - x="450.53442" - sodipodi:role="line" - id="tspan5086-7">Proxy</tspan></text> - </g> - <g - id="g5951" - transform="translate(-590.15721,-114.43075)"> - <rect - y="205.67021" - x="390.00049" - height="52.004227" - width="79.478157" - id="rect3686-6-9-9-7" - style="opacity:0.98999999;fill:#eb9bb4;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-5" - y="237.24033" - x="430.1767" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="237.24033" - x="430.1767" - sodipodi:role="line" - id="tspan5086-71">Client 1</tspan></text> - </g> - <g - id="g5951-1" - transform="translate(-590.15721,13.757484)"> - <rect - y="205.67021" - x="390.00049" - height="52.004227" - width="79.478157" - id="rect3686-6-9-9-7-3" - style="opacity:0.98999999;fill:#eb9bb4;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-5-3" - y="237.24033" - x="429.80869" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="237.24033" - x="429.80869" - sodipodi:role="line" - id="tspan5086-71-3">Client 2</tspan></text> - </g> - <g - id="g5951-9" - transform="translate(-590.15721,141.9457)"> - <rect - y="205.67021" - x="390.00049" - height="52.004227" - width="79.478157" - id="rect3686-6-9-9-7-8" - style="opacity:0.98999999;fill:#eb9bb4;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-5-6" - y="237.24033" - x="429.91269" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="237.24033" - x="429.91269" - sodipodi:role="line" - id="tspan5086-71-7">Client 3</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9);marker-start:url(#Arrow2Lstart-5)" - d="M -120.67857,143.24369 -15.953676,219.4277" - id="path3999-1-61-1" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9);marker-start:url(#Arrow2Lstart-5)" - d="m -120.67856,244.46601 104.724884,2.4e-4" - id="path3999-1-61-1-5" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9);marker-start:url(#Arrow2Lstart-5)" - d="M -120.67857,347.61591 -15.953676,271.43192" - id="path3999-1-61-1-55" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9);marker-start:url(#Arrow2Lstart-5)" - d="m 63.524481,241.02771 93.478469,2.4e-4" - id="path3999-1-61-1-5-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9);marker-start:url(#Arrow2Lstart-5)" - d="m 237.95434,241.02771 93.47847,2.4e-4" - id="path3999-1-61-1-5-9-2" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-2.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-2.svg deleted file mode 100644 index 2ecc79f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-2.svg +++ /dev/null @@ -1,246 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="203.08299" - height="285.52893" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="reactor-2.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/reactor-2.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="109.44577" - inkscape:cy="153.5483" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1"> - <sodipodi:guide - orientation="1,0" - position="-279.85667,818.38115" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-197.02416,405.22876" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-226.6611,-94.585864)"> - <g - id="g3374" - transform="translate(0.98121181,-69.175432)"> - <path - sodipodi:open="true" - transform="matrix(1.3874983,0,0,1.2111208,-308.3974,-120.48465)" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - d="m 458.32888,240.35509 c 37.29285,0.12409 67.42408,30.45652 67.29998,67.74937 -0.1241,37.29285 -30.45652,67.42407 -67.74937,67.29997 -37.29285,-0.12409 -67.42407,-30.45652 -67.29998,-67.74937 0.12287,-36.9217 29.87786,-66.89889 66.79763,-67.29643" - sodipodi:ry="67.525047" - sodipodi:rx="67.525047" - sodipodi:cy="307.87976" - sodipodi:cx="458.10419" - id="path2554" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.26512631, 1.26512631;stroke-dashoffset:0;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none" - sodipodi:type="arc" /> - <text - id="text2391" - y="256.01892" - x="281.06375" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="256.01892" - x="281.06375" - id="tspan2393" - sodipodi:role="line">Reactor Loop</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 382.68308,272.35314 37.28605,71.62846" - id="path3379" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 332.08626,272.35314 1.47182,71.62846" - id="path3379-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="M 283.1545,272.35314 245.86845,343.9816" - id="path3379-7" - sodipodi:nodetypes="cc" /> - <text - id="text2391-8" - y="377.8428" - x="278.14337" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="377.8428" - x="278.14337" - id="tspan2393-0" - sodipodi:role="line">dataReceived(...)</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-3.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-3.svg deleted file mode 100644 index 54ab7ff..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-3.svg +++ /dev/null @@ -1,460 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="206.92343" - height="259.67175" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="reactor-3.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/reactor-3.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Send" - orient="auto" - refY="0" - refX="0" - id="Arrow1Send" - style="overflow:visible"> - <path - id="path4504" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path4516" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5988" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker5994" - style="overflow:visible"> - <path - id="path5996" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6439" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-2" /> - </marker> - <marker - style="overflow:visible" - id="marker6445" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447" /> - </marker> - <inkscape:perspective - id="perspective6439-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-7" /> - </marker> - <marker - style="overflow:visible" - id="marker6445-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447-1" /> - </marker> - <inkscape:perspective - id="perspective6492" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-59" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-59" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520-5" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-63" - style="overflow:visible"> - <path - id="path3871-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="153.05833" - inkscape:cy="82.088895" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1"> - <sodipodi:guide - orientation="1,0" - position="-307.86362,707.67328" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-225.03111,294.52089" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-254.66805,-9.7351661)"> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.54283696, 4.62851088;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 c 7.2195,0.024 13.05259,5.89606 13.02857,13.11557 -0.024,7.21951 -5.89607,13.0526 -13.11557,13.02857 -7.21951,-0.024 -13.0526,-5.89606 -13.02858,-13.11557 0.0238,-7.14766 5.78405,-12.95093 12.93133,-13.02789" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-194.57683,-122.44707)" - sodipodi:open="true" /> - <g - id="g3374" - transform="translate(28.988165,-154.02613)"> - <path - sodipodi:open="true" - transform="matrix(1.3874983,0,0,1.2111208,-308.3974,-120.48465)" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - d="m 458.32888,240.35509 c 37.29285,0.12409 67.42408,30.45652 67.29998,67.74937 -0.1241,37.29285 -30.45652,67.42407 -67.74937,67.29997 -37.29285,-0.12409 -67.42407,-30.45652 -67.29998,-67.74937 0.12287,-36.9217 29.87786,-66.89889 66.79763,-67.29643" - sodipodi:ry="67.525047" - sodipodi:rx="67.525047" - sodipodi:cy="307.87976" - sodipodi:cx="458.10419" - id="path2554-2" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.26512631, 1.26512631;stroke-dashoffset:0;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none" - sodipodi:type="arc" /> - <text - id="text2391-4" - y="256.01892" - x="281.06375" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="256.01892" - x="281.06375" - id="tspan2393" - sodipodi:role="line">Reactor Loop</tspan></text> - </g> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.54283696, 4.62851088;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-0" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 c 7.2195,0.024 13.05259,5.89606 13.02857,13.11557 -0.024,7.21951 -5.89607,13.0526 -13.11557,13.02857 -7.21951,-0.024 -13.0526,-5.89606 -13.02858,-13.11557 0.0238,-7.14766 5.78405,-12.95093 12.93133,-13.02789" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-267.89424,-123.40415)" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.54283696, 4.62851088;stroke-dashoffset:0;marker-start:url(#Arrow1Mend);marker-mid:url(#Arrow1Mend);marker-end:none" - id="path2554-6" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="13.072145" - sodipodi:ry="13.072145" - d="m 458.14769,294.80769 c 7.2195,0.024 13.05259,5.89606 13.02857,13.11557 -0.024,7.21951 -5.89607,13.0526 -13.11557,13.02857 -7.21951,-0.024 -13.0526,-5.89606 -13.02858,-13.11557 0.0238,-7.14766 5.78405,-12.95093 12.93133,-13.02789" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-341.21165,-121.44173)" - sodipodi:open="true" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 318.64882,187.50244 -24.03969,42.1921" - id="path3379-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 367.70693,192.23385 0,34.34241" - id="path3379-9-6" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" - d="m 414.77981,187.50244 24.03969,42.1921" - id="path3379-9-2" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-callback.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-callback.svg deleted file mode 100644 index 6f614be..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-callback.svg +++ /dev/null @@ -1,217 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="216.86661" - height="254.12202" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="reactor-callback.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/reactor-callback.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="116.30494" - inkscape:cy="115.027" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="27"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-213.90526,-173.06416)"> - <path - sodipodi:type="arc" - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none;stroke-miterlimit:4;stroke-dasharray:1.26512631, 1.26512631;stroke-dashoffset:0;stroke-opacity:1" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="102.53049" - sodipodi:ry="118.18785" - d="M 386.64999,392.63956 A 102.53049,118.18785 0 1 1 533.9846,387.36376" - sodipodi:start="2.3418716" - sodipodi:end="7.0207974" - transform="matrix(0.7911476,0,0,0.6905776,-34.961338,42.522473)" - sodipodi:open="true" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.12573" - y="255.47725" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="285.12573" - y="255.47725">Reactor Loop</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.94501448;stroke-linecap:butt;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 388.02353,309.31726 C 370.90421,324.1122 359.98637,327.7451 359.31642,343.61473 C 358.3632,366.19432 359.41203,399.38036 359.41203,399.38036 C 359.43962,415.47376 342.96042,426.74125 331.16946,426.71363 C 318.48016,426.6839 309.36592,419.167 303.69554,410.52364 C 292.51889,393.4871 303.56868,357.84101 295.35524,342.82003 C 287.14181,327.79905 274.25918,317.30851 274.25918,317.30851" - id="path8437" - sodipodi:nodetypes="csssszc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 2;stroke-dashoffset:0;stroke-opacity:1" - d="M 37.286049,289.94809 L 253.15265,289.94809" - id="path8984" - transform="translate(177.11921,71.024349)" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.96089" - y="375.69064" - id="text8986"><tspan - sodipodi:role="line" - id="tspan8988" - x="218.96089" - y="375.69064">Our code</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:4, 1;stroke-dashoffset:0;stroke-opacity:1" - d="M 378.26763,335.68062 L 378.26763,383.26939" - id="path8990" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.22089" - y="353.07852" - id="text9527"><tspan - sodipodi:role="line" - id="tspan9529" - x="218.22089" - y="353.07852">Twisted code</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="381.10205" - y="346.70062" - id="text9531"><tspan - sodipodi:role="line" - id="tspan9533" - x="381.10205" - y="346.70062">Callback</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-data-received.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-data-received.svg deleted file mode 100644 index d0ba6a8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-data-received.svg +++ /dev/null @@ -1,257 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="339.33142" - height="335.02487" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="reactor-data-received.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/reactor-doread.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="202.36359" - inkscape:cy="154.27547" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="27"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-213.96284,-151.52464)" - style="display:inline"> - <path - sodipodi:type="arc" - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none;stroke-miterlimit:4;stroke-dasharray:1.26512631, 1.26512631;stroke-dashoffset:0;stroke-opacity:1" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="102.53049" - sodipodi:ry="118.18785" - d="M 386.64999,392.63956 A 102.53049,118.18785 0 1 1 533.9846,387.36376" - sodipodi:start="2.3418716" - sodipodi:end="7.0207974" - transform="matrix(0.7911476,0,0,0.6905776,-34.961338,42.522473)" - sodipodi:open="true" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.12573" - y="255.47725" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="285.12573" - y="255.47725">Reactor Loop</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.14342451;stroke-linecap:butt;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 385.97827,311.6906 C 368.88661,333.38529 359.94805,340.8543 359.27918,364.12488 C 358.32749,397.23466 359.37463,445.89733 359.37463,445.89733 C 359.40218,469.49603 342.9496,486.01821 331.17769,485.97772 C 318.5089,485.93412 309.40939,474.91165 303.74818,462.23737 C 292.58958,437.25568 304.67699,385.16387 295.42135,362.95956 C 286.23998,340.93341 276.81141,320.42013 276.81141,320.42013" - id="path8437" - sodipodi:nodetypes="csssszc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.10428166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.10428167, 2.20856333;stroke-dashoffset:0;stroke-opacity:1" - d="M 214.51498,411.99545 L 477.75091,411.99545" - id="path8984" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.96089" - y="426.71365" - id="text8986"><tspan - sodipodi:role="line" - id="tspan8988" - x="218.96089" - y="426.71365">Our code</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99051297;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:3.96205189, 0.99051297;stroke-dashoffset:0;stroke-opacity:1" - d="M 378.26761,335.67588 L 378.26761,382.30954" - id="path8990" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.22089" - y="404.10153" - id="text9527"><tspan - sodipodi:role="line" - id="tspan9529" - x="218.22089" - y="404.10153">Twisted code</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="382.08325" - y="346.70062" - id="text9531"><tspan - sodipodi:role="line" - id="tspan9533" - x="382.08325" - y="346.70062">reader.doRead()</tspan></text> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="280.62766" - y="165.20264" - id="text2540"><tspan - sodipodi:role="line" - id="tspan2542" - x="280.62766" - y="165.20264">Wait for Events</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-opacity:1" - d="M 166.80601,-11.295769 C 166.80601,-11.295769 196.25809,1.9920778 206.75877,13.055307 C 218.26562,25.178614 229.57117,47.703118 230.58477,64.748146 C 231.29885,76.756337 226.09024,94.879014 219.93282,111.58885 C 211.84296,133.54286 202.12963,153.05721 202.12963,153.05721" - id="path2546" - transform="translate(213.90526,173.06416)" - sodipodi:nodetypes="csssc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="450.61453" - y="245.67635" - id="text2548"><tspan - sodipodi:role="line" - id="tspan2550" - x="450.61453" - y="245.67635">A socket is ready</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="369.65387" - y="393.08154" - id="text2408"><tspan - sodipodi:role="line" - id="tspan2410" - x="369.65387" - y="393.08154">protocol.dataReceived(data)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99051297;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:3.96205189, 0.99051297;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 378.26761,399.53444 L 378.26761,446.1681" - id="path2412" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-deferred-callback.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-deferred-callback.svg deleted file mode 100644 index a0305da..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-deferred-callback.svg +++ /dev/null @@ -1,285 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="332.51373" - height="553.59967" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="reactor-deferred-callback.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/reactor-deferred-callback.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="190.22171" - inkscape:cy="234.16707" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-245.86213,-151.52464)" - style="display:inline"> - <path - sodipodi:type="arc" - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.35289788;stroke-linecap:square;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none;stroke-miterlimit:4;stroke-dasharray:1.35289783, 1.35289783;stroke-dashoffset:0;stroke-opacity:1" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="102.53049" - sodipodi:ry="118.18785" - d="M 386.64999,392.63956 A 102.53049,118.18785 0 1 1 533.9846,387.36376" - sodipodi:start="2.3418716" - sodipodi:end="7.0207974" - transform="matrix(0.7911476,0,0,0.6905776,-34.961338,42.522473)" - sodipodi:open="true" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.12573" - y="255.47725" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="285.12573" - y="255.47725">Reactor Loop</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 385.97827,311.6906 C 368.88661,333.38529 359.94805,340.8543 359.27918,364.12488 C 358.32749,397.23466 359.37463,445.89733 359.37463,445.89733 C 359.13338,459.98133 359.36,659.46355 354.17637,679.16367 C 349.4105,697.27611 339.61594,704.87256 330.68708,704.61815 C 324.16372,704.43228 314.27502,695.25688 309.07065,679.03948 C 304.17184,663.77423 303.75896,473.16773 303.74818,462.23737 C 303.7212,434.87684 304.67699,385.16387 295.42135,362.95956 C 286.23998,340.93341 276.81141,320.42013 276.81141,320.42013" - id="path8437" - sodipodi:nodetypes="csssssszc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:4, 1;stroke-dashoffset:0;stroke-opacity:1" - d="M 378.28299,335.67588 L 378.28299,382.30954" - id="path8990" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="382.08325" - y="346.70062" - id="text9531"><tspan - sodipodi:role="line" - id="tspan9533" - x="382.08325" - y="346.70062">protocol.connectionLost(reason)</tspan></text> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="280.62766" - y="165.20264" - id="text2540"><tspan - sodipodi:role="line" - id="tspan2542" - x="280.62766" - y="165.20264">Wait for Events</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-opacity:1" - d="M 166.80601,-11.295769 C 166.80601,-11.295769 196.25809,1.9920778 206.75877,13.055307 C 218.26562,25.178614 229.57117,47.703118 230.58477,64.748146 C 231.29885,76.756337 226.09024,94.879014 219.93282,111.58885 C 211.84296,133.54286 202.12963,153.05721 202.12963,153.05721" - id="path2546" - transform="translate(213.90526,173.06416)" - sodipodi:nodetypes="csssc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="450.61453" - y="245.67635" - id="text2548"><tspan - sodipodi:role="line" - id="tspan2550" - x="450.61453" - y="245.67635">A socket was closed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="369.16483" - y="393.08154" - id="text2408"><tspan - sodipodi:role="line" - id="tspan2410" - x="369.16483" - y="393.08154">protocol.poemReceived(poem)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:4, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 378.28299,399.53444 L 378.28299,446.1681" - id="path2412" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="368.79282" - y="460.78516" - id="text2434"><tspan - sodipodi:role="line" - id="tspan2436" - x="368.79282" - y="460.78516">factory.poem_finished(poem)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:4, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 378.28299,467.72866 L 378.28299,514.36232" - id="path2591" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="370.68881" - y="681.62012" - id="text2593"><tspan - sodipodi:role="line" - id="tspan2595" - x="370.68881" - y="681.62012">got_poem(poem)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:4, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 378.28299,542.01099 L 378.28299,588.64465" - id="path3230" /> - <text - xml:space="preserve" - style="font-size:19.69865036px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="457.05344" - y="485.19855" - id="text3232" - transform="scale(0.8021324,1.246677)"><tspan - sodipodi:role="line" - id="tspan3234" - x="457.05344" - y="485.19855">...</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="370.68881" - y="531.87183" - id="text3236"><tspan - sodipodi:role="line" - id="tspan3238" - x="370.68881" - y="531.87183">d.callback(poem)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:4, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 378.28299,620.33719 L 378.28299,666.97085" - id="path3240" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-doread.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-doread.svg deleted file mode 100644 index beaea75..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-doread.svg +++ /dev/null @@ -1,243 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="346.39001" - height="275.66156" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="reactor-doread.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/reactor-doread.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="202.36359" - inkscape:cy="115.027" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="27"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-213.90526,-151.52464)" - style="display:inline"> - <path - sodipodi:type="arc" - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none;stroke-miterlimit:4;stroke-dasharray:1.26512631, 1.26512631;stroke-dashoffset:0;stroke-opacity:1" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="102.53049" - sodipodi:ry="118.18785" - d="M 386.64999,392.63956 A 102.53049,118.18785 0 1 1 533.9846,387.36376" - sodipodi:start="2.3418716" - sodipodi:end="7.0207974" - transform="matrix(0.7911476,0,0,0.6905776,-34.961338,42.522473)" - sodipodi:open="true" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.12573" - y="255.47725" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="285.12573" - y="255.47725">Reactor Loop</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.94501448;stroke-linecap:butt;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 388.02353,309.31726 C 370.90421,324.1122 359.98637,327.7451 359.31642,343.61473 C 358.3632,366.19432 359.41203,399.38036 359.41203,399.38036 C 359.43962,415.47376 342.96042,426.74125 331.16946,426.71363 C 318.48016,426.6839 309.36592,419.167 303.69554,410.52364 C 292.51889,393.4871 303.56868,357.84101 295.35524,342.82003 C 287.14181,327.79905 274.25918,317.30851 274.25918,317.30851" - id="path8437" - sodipodi:nodetypes="csssszc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.10428166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.10428167, 2.20856333;stroke-dashoffset:0;stroke-opacity:1" - d="M 214.51498,360.97244 L 477.75091,360.97244" - id="path8984" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.96089" - y="375.69064" - id="text8986"><tspan - sodipodi:role="line" - id="tspan8988" - x="218.96089" - y="375.69064">Our code</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:4, 1;stroke-dashoffset:0;stroke-opacity:1" - d="M 378.26763,335.68062 L 378.26763,383.26939" - id="path8990" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.22089" - y="353.07852" - id="text9527"><tspan - sodipodi:role="line" - id="tspan9529" - x="218.22089" - y="353.07852">Twisted code</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="382.08325" - y="346.70062" - id="text9531"><tspan - sodipodi:role="line" - id="tspan9533" - x="382.08325" - y="346.70062">reader.doRead()</tspan></text> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="280.62766" - y="165.20264" - id="text2540"><tspan - sodipodi:role="line" - id="tspan2542" - x="280.62766" - y="165.20264">Wait for Events</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-opacity:1" - d="M 166.80601,-11.295769 C 166.80601,-11.295769 196.25809,1.9920778 206.75877,13.055307 C 218.26562,25.178614 229.57117,47.703118 230.58477,64.748146 C 231.29885,76.756337 226.09024,94.879014 219.93282,111.58885 C 211.84296,133.54286 202.12963,153.05721 202.12963,153.05721" - id="path2546" - transform="translate(213.90526,173.06416)" - sodipodi:nodetypes="csssc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="450.61453" - y="245.67635" - id="text2548"><tspan - sodipodi:role="line" - id="tspan2550" - x="450.61453" - y="245.67635">A socket is ready</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-poem-callback.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-poem-callback.svg deleted file mode 100644 index 1b27e7e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor-poem-callback.svg +++ /dev/null @@ -1,281 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="364.41302" - height="385.07275" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="reactor-poem-callback.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/reactor-poem-callback.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="202.36359" - inkscape:cy="173.89971" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="27"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-213.96284,-151.52464)" - style="display:inline"> - <path - sodipodi:type="arc" - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512635;stroke-linecap:square;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none;stroke-miterlimit:4;stroke-dasharray:1.26512631, 1.26512631;stroke-dashoffset:0;stroke-opacity:1" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="102.53049" - sodipodi:ry="118.18785" - d="M 386.64999,392.63956 A 102.53049,118.18785 0 1 1 533.9846,387.36376" - sodipodi:start="2.3418716" - sodipodi:end="7.0207974" - transform="matrix(0.7911476,0,0,0.6905776,-34.961338,42.522473)" - sodipodi:open="true" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.12573" - y="255.47725" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="285.12573" - y="255.47725">Reactor Loop</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.14342451;stroke-linecap:butt;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 385.97827,311.6906 C 368.88661,333.38529 359.94805,340.8543 359.27918,364.12488 C 358.32749,397.23466 359.37463,445.89733 359.37463,445.89733 C 359.13338,459.98133 359.36,490.86492 354.17637,510.56504 C 349.4105,528.67748 339.61594,536.27393 330.68708,536.01952 C 324.16372,535.83365 314.27502,526.65825 309.07065,510.44085 C 304.17184,495.1756 303.75896,473.16773 303.74818,462.23737 C 303.7212,434.87684 304.67699,385.16387 295.42135,362.95956 C 286.23998,340.93341 276.81141,320.42013 276.81141,320.42013" - id="path8437" - sodipodi:nodetypes="csssssszc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.10428166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.10428167, 2.20856333;stroke-dashoffset:0;stroke-opacity:1" - d="M 214.51498,363.42547 L 477.75091,363.42547" - id="path8984" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.96089" - y="378.14368" - id="text8986"><tspan - sodipodi:role="line" - id="tspan8988" - x="218.96089" - y="378.14368">Our code</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99051297;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:3.96205189, 0.99051297;stroke-dashoffset:0;stroke-opacity:1" - d="M 378.28299,335.67588 L 378.28299,382.30954" - id="path8990" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="218.22089" - y="355.53156" - id="text9527"><tspan - sodipodi:role="line" - id="tspan9529" - x="218.22089" - y="355.53156">Twisted code</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="382.08325" - y="346.70062" - id="text9531"><tspan - sodipodi:role="line" - id="tspan9533" - x="382.08325" - y="346.70062">protocol.connectionLost(reason)</tspan></text> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="280.62766" - y="165.20264" - id="text2540"><tspan - sodipodi:role="line" - id="tspan2542" - x="280.62766" - y="165.20264">Wait for Events</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-opacity:1" - d="M 166.80601,-11.295769 C 166.80601,-11.295769 196.25809,1.9920778 206.75877,13.055307 C 218.26562,25.178614 229.57117,47.703118 230.58477,64.748146 C 231.29885,76.756337 226.09024,94.879014 219.93282,111.58885 C 211.84296,133.54286 202.12963,153.05721 202.12963,153.05721" - id="path2546" - transform="translate(213.90526,173.06416)" - sodipodi:nodetypes="csssc" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="450.61453" - y="245.67635" - id="text2548"><tspan - sodipodi:role="line" - id="tspan2550" - x="450.61453" - y="245.67635">A socket was closed</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="369.16483" - y="393.08154" - id="text2408"><tspan - sodipodi:role="line" - id="tspan2410" - x="369.16483" - y="393.08154">protocol.poemReceived(poem)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99051297;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:3.96205189, 0.99051297;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 378.28299,399.53444 L 378.28299,446.1681" - id="path2412" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="368.79282" - y="460.78516" - id="text2434"><tspan - sodipodi:role="line" - id="tspan2436" - x="368.79282" - y="460.78516">factory.poem_finished(poem)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99051297;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:3.96205189, 0.99051297;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 378.28299,467.72866 L 378.28299,514.36232" - id="path2591" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:LMTypewriter10;-inkscape-font-specification:LMTypewriter10" - x="370.68881" - y="528.97937" - id="text2593"><tspan - sodipodi:role="line" - id="tspan2595" - x="370.68881" - y="528.97937">got_poem(poem)</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor.svg deleted file mode 100644 index 4ef378c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/reactor.svg +++ /dev/null @@ -1,184 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="300.20435" - height="365.5014" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="reactor-1.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="2.0382959" - inkscape:cx="220.804" - inkscape:cy="190.33501" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="27"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-177.11921,-71.024349)"> - <path - sodipodi:type="arc" - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.26512631;stroke-linecap:square;stroke-linejoin:bevel;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none;stroke-miterlimit:4;stroke-dasharray:1.26512631,1.26512631;stroke-dashoffset:0;stroke-opacity:1" - id="path2554" - sodipodi:cx="458.10419" - sodipodi:cy="307.87976" - sodipodi:rx="102.53049" - sodipodi:ry="118.18785" - d="M 458.44537,189.69256 A 102.53049,118.18785 0 1 1 457.00023,189.69876" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - transform="matrix(1.3874983,0,0,1.2111208,-308.3974,-120.48465)" - sodipodi:open="true" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="285.12573" - y="255.47725" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="285.12573" - y="255.47725">Reactor Loop</tspan></text> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="273.75134" - y="86.656349" - id="text7823"><tspan - sodipodi:role="line" - id="tspan7825" - x="273.75134" - y="86.656349">Wait for Events</tspan></text> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="277.66342" - y="433.26175" - id="text7827"><tspan - sodipodi:role="line" - id="tspan7829" - x="277.66342" - y="433.26175">Handle Events</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/server-1.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/server-1.svg deleted file mode 100644 index d359530..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/server-1.svg +++ /dev/null @@ -1,901 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="720.94507" - height="463.8298" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="server-1.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4552" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective3669" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3696" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3979" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4219" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4328" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4356" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-4" - style="overflow:visible"> - <path - id="path3871-5-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4384" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4511" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-0" - style="overflow:visible"> - <path - id="path3871-5-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-7" - style="overflow:visible"> - <path - id="path4552-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-47" - style="overflow:visible"> - <path - id="path3871-5-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005-9" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-77" - style="overflow:visible"> - <path - id="path4552-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-41" - style="overflow:visible"> - <path - id="path3871-5-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5056" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5110" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5154" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5182" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-64" - style="overflow:visible"> - <path - id="path3871-16" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5210" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-5" - style="overflow:visible"> - <path - id="path4552-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-9" - style="overflow:visible"> - <path - id="path3871-5-15" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5462" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5522" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-09" - style="overflow:visible"> - <path - id="path3871-5-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.019148" - inkscape:cx="363.37449" - inkscape:cy="237.93315" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:object-paths="true"> - <sodipodi:guide - orientation="1,0" - position="112.36374,922.39025" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="195.19625,509.23786" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(165.55931,-20.294124)"> - <g - id="g3769" - transform="translate(123.65591,153.10679)"> - <path - sodipodi:open="true" - transform="matrix(1.3874983,0,0,1.2111208,-308.3974,-120.48465)" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - d="m 458.24064,266.87421 c 22.64674,0.0754 40.94446,18.49526 40.8691,41.142 -0.0754,22.64674 -18.49526,40.94446 -41.142,40.8691 -22.64675,-0.0754 -40.94447,-18.49526 -40.86911,-41.142 0.0746,-22.42136 18.14386,-40.62554 40.56404,-40.86695" - sodipodi:ry="41.005779" - sodipodi:rx="41.005779" - sodipodi:cy="307.87976" - sodipodi:cx="458.10419" - id="path2554" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.77141845;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:0.77141848, 0.77141848;stroke-dashoffset:0;marker-start:url(#Arrow2Lend);marker-mid:url(#Arrow2Lend);marker-end:none" - sodipodi:type="arc" /> - <text - id="text2391" - y="255.47725" - x="281.06375" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="255.47725" - x="281.06375" - id="tspan2393" - sodipodi:role="line">Reactor Loop</tspan></text> - </g> - <g - id="g5141"> - <path - sodipodi:open="true" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - transform="translate(177.11921,58.508332)" - d="m -150.97601,-29.925756 c 21.67621,0.398521 39.18978,97.80712 39.11765,217.568196 -0.0721,119.76107 -17.70265,216.52354 -39.37886,216.12502 -21.67621,-0.39852 -39.18978,-97.80712 -39.11765,-217.56819 0.0714,-118.569201 17.3663,-214.837005 38.82567,-216.113656" - sodipodi:ry="216.84781" - sodipodi:rx="39.24847" - sodipodi:cy="186.92085" - sodipodi:cx="-151.10661" - id="path3647" - style="opacity:0.98999999;fill:#ff7d7d;fill-opacity:1;stroke:none" - sodipodi:type="arc" /> - <text - id="text2391-0" - y="139.38979" - x="26.032473" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:tb-rl;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="26.032473" - x="139.38979" - id="tspan2393-2" - sodipodi:role="line">The Network</tspan></text> - </g> - <g - id="g4254"> - <rect - y="99.808762" - x="-165.55931" - height="52.004227" - width="79.478157" - id="rect3686" - style="opacity:0.98999999;fill:#7dc2ff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8" - y="131.60287" - x="-152.74248" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="131.60287" - x="-152.74248" - id="tspan2393-0" - sodipodi:role="line">Client 1</tspan></text> - </g> - <g - id="g4259"> - <rect - y="219.42769" - x="-165.55931" - height="52.004227" - width="79.478157" - id="rect3686-7" - style="opacity:0.98999999;fill:#7dc2ff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-6" - y="251.2218" - x="-152.74249" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="251.2218" - x="-152.74249" - id="tspan2393-0-8" - sodipodi:role="line">Client 2</tspan></text> - </g> - <g - id="g4264"> - <rect - y="339.0466" - x="-165.55931" - height="52.004227" - width="79.478157" - id="rect3686-9" - style="opacity:0.98999999;fill:#7dc2ff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-3" - y="370.84073" - x="-152.74249" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="370.84073" - x="-152.74249" - id="tspan2393-0-7" - sodipodi:role="line">Client 3</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m -263.20036,28.784409 c 2.94363,-43.17332 25.71994,-34.6775624 43.40891,-30.2562202 l 43.23165,10.8057088" - id="path3779" - transform="translate(177.11921,71.024349)" - sodipodi:nodetypes="csc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m -86.081154,391.05084 c 2.943633,43.17332 25.719943,34.67756 43.408913,30.25622 L 0.55940913,410.50135" - id="path3779-7" - sodipodi:nodetypes="csc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9)" - d="m -263.20036,171.22147 72.84944,0.005" - id="path3999" - transform="translate(177.11921,71.024349)" /> - <g - id="g4449" - transform="translate(124.15833,0)"> - <g - transform="translate(16.92564,27.32198)" - id="g4269"> - <rect - style="opacity:0.98999999;fill:#7dff84;fill-opacity:1;stroke:none" - id="rect3686-6" - width="79.478157" - height="52.004227" - x="121.68074" - y="72.986778" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="132.4207" - y="104.78089" - id="text2391-8-2"><tspan - sodipodi:role="line" - id="tspan2393-0-74" - x="132.4207" - y="104.78089">Protocol</tspan></text> - </g> - </g> - <g - id="g4443" - transform="translate(124.15833,0)"> - <g - id="g4269-7" - transform="translate(16.92564,146.20056)"> - <rect - style="opacity:0.98999999;fill:#7dff84;fill-opacity:1;stroke:none" - id="rect3686-6-9" - width="79.478157" - height="52.004227" - x="121.68074" - y="72.986778" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="132.4207" - y="104.78089" - id="text2391-8-2-6"><tspan - sodipodi:role="line" - id="tspan2393-0-74-9" - x="132.4207" - y="104.78089">Protocol</tspan></text> - </g> - </g> - <g - transform="translate(141.08397,266.05982)" - id="g4269-2"> - <rect - y="72.986778" - x="121.68074" - height="52.004227" - width="79.478157" - id="rect3686-6-8" - style="opacity:0.98999999;fill:#7dff84;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-8" - y="104.78089" - x="132.4207" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="104.78089" - x="132.4207" - id="tspan2393-0-74-4" - sodipodi:role="line">Protocol</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="M 138.10638,99.808758 C 135.16275,56.635437 112.38644,65.131194 94.697471,69.552537 L 51.465822,80.358245" - id="path3779-1" - sodipodi:nodetypes="csc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9)" - d="m 138.10638,242.21059 -72.849441,0.005" - id="path3999-1" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 138.60638,391.05082 c -2.94363,43.17332 -25.71994,34.67756 -43.408909,30.25622 L 51.965824,410.50133" - id="path3779-7-9" - sodipodi:nodetypes="csc" /> - <g - id="g4438" - transform="translate(-159.69248,80.788628)"> - <rect - y="19.02013" - x="298.29886" - height="52.004227" - width="79.478157" - id="rect3686-6-6" - style="opacity:0.98999999;fill:#ef7dff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7" - y="50.814243" - x="303.88843" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="50.814243" - x="303.88843" - id="tspan2393-0-74-2" - sodipodi:role="line">Transport</tspan></text> - </g> - <g - id="g4438-5" - transform="translate(-159.69248,200.40756)"> - <rect - y="19.02013" - x="298.29886" - height="52.004227" - width="79.478157" - id="rect3686-6-6-5" - style="opacity:0.98999999;fill:#ef7dff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7-7" - y="50.814243" - x="303.88843" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="50.814243" - x="303.88843" - id="tspan2393-0-74-2-8" - sodipodi:role="line">Transport</tspan></text> - </g> - <g - id="g4438-3" - transform="translate(-159.69248,320.02647)"> - <rect - y="19.02013" - x="298.29886" - height="52.004227" - width="79.478157" - id="rect3686-6-6-1" - style="opacity:0.98999999;fill:#ef7dff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7-9" - y="50.814243" - x="303.88843" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="50.814243" - x="303.88843" - id="tspan2393-0-74-2-6" - sodipodi:role="line">Transport</tspan></text> - </g> - <rect - style="opacity:0.98999999;fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3, 3;stroke-dashoffset:0" - id="rect4501" - width="472.94409" - height="448.41379" - x="-95.177544" - y="-35.814224" - transform="translate(177.11921,71.024349)" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend-9)" - d="m 262.76471,245.16811 -42.02414,0.005" - id="path3999-1-6" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend-9)" - d="m 261.43669,126.30837 -42.02414,0.005" - id="path3999-1-6-9" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend-9)" - d="m 261.43669,365.04621 -42.02414,0.005" - id="path3999-1-6-3" - sodipodi:nodetypes="cc" /> - <g - id="g5130"> - <rect - y="219.18733" - x="411.13821" - height="52.004227" - width="79.478157" - id="rect3686-6-9-9" - style="opacity:0.98999999;fill:#19bc50;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0" - y="239.33345" - x="450.8313" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="239.33345" - x="450.8313" - id="tspan2393-0-74-9-3" - sodipodi:role="line">Protocol</tspan><tspan - y="259.33344" - x="450.8313" - sodipodi:role="line" - id="tspan5086">Factory</tspan></text> - </g> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="318.26822" - y="31.222124" - id="text2391-8-2-6-0-0"><tspan - id="tspan5086-1" - sodipodi:role="line" - x="318.26822" - y="31.222124">Poetry Server</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 342.24288,152.31298 c 5.99443,33.68934 36.5715,53.82748 68.89533,66.87435" - id="path3779-1-5" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 342.74287,338.57931 c 5.99443,-33.68934 36.5715,-53.82748 68.89533,-66.87435" - id="path3779-1-5-8" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend-9)" - d="m 342.24287,244.22213 68.89534,0.98621" - id="path3999-1-6-8" - sodipodi:nodetypes="cc" /> - <g - id="g5508" - transform="translate(9.0664978,-52.985438)"> - <rect - y="99.979492" - x="402.07172" - height="52.004227" - width="79.478157" - id="rect3686-6-85" - style="opacity:0.98999999;fill:#db3e90;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-1" - y="121.54961" - x="441.68631" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="121.54961" - x="441.68631" - id="tspan2393-0-74-8" - sodipodi:role="line">Listening</tspan><tspan - y="141.54961" - x="441.68631" - sodipodi:role="line" - id="tspan5492">Socket</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9)" - d="m 408.98349,56.293685 -363.756681,0.005" - id="path3999-1-5" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:FreeSans;-inkscape-font-specification:FreeSans Oblique" - x="283.6232" - y="455.66879" - id="text5542"><tspan - sodipodi:role="line" - id="tspan5544" - x="283.6232" - y="455.66879">the reactor is monitoring the three client</tspan><tspan - sodipodi:role="line" - x="283.6232" - y="470.66879" - id="tspan5546">sockets and the listening socket</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/server-2.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/server-2.svg deleted file mode 100644 index 6c743ab..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/server-2.svg +++ /dev/null @@ -1,860 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="568.62164" - height="463.8298" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="server-2.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/server-2.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4552" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective3669" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3696" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3979" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4219" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4328" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4356" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-4" - style="overflow:visible"> - <path - id="path3871-5-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4384" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4511" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-0" - style="overflow:visible"> - <path - id="path3871-5-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-7" - style="overflow:visible"> - <path - id="path4552-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-47" - style="overflow:visible"> - <path - id="path3871-5-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005-9" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-77" - style="overflow:visible"> - <path - id="path4552-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-41" - style="overflow:visible"> - <path - id="path3871-5-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5056" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5110" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5154" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5182" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-64" - style="overflow:visible"> - <path - id="path3871-16" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5210" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-5" - style="overflow:visible"> - <path - id="path4552-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-9" - style="overflow:visible"> - <path - id="path3871-5-15" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5462" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5522" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-09" - style="overflow:visible"> - <path - id="path3871-5-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5713" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-1" - style="overflow:visible"> - <path - id="path3871-5-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5741" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-00" - style="overflow:visible"> - <path - id="path3871-5-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5788" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5836" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5903" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-91" - style="overflow:visible"> - <path - id="path3871-5-89" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5931" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-6" - style="overflow:visible"> - <path - id="path3871-5-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.019148" - inkscape:cx="296.63563" - inkscape:cy="221.18528" - inkscape:document-units="px" - inkscape:current-layer="g5141" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1272" - inkscape:window-height="971" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="0" - inkscape:object-paths="true"> - <sodipodi:guide - orientation="1,0" - position="-39.959693,922.39024" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="42.872817,509.23785" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(13.235878,-20.294124)"> - <g - id="g5141"> - <path - sodipodi:open="true" - sodipodi:end="10.984807" - sodipodi:start="4.7157166" - transform="translate(177.11921,58.508332)" - d="m -150.97601,-29.925756 c 21.67621,0.398521 39.18978,97.80712 39.11765,217.568196 -0.0721,119.76107 -17.70265,216.52354 -39.37886,216.12502 -21.67621,-0.39852 -39.18978,-97.80712 -39.11765,-217.56819 0.0714,-118.569201 17.3663,-214.837005 38.82567,-216.113656" - sodipodi:ry="216.84781" - sodipodi:rx="39.24847" - sodipodi:cy="186.92085" - sodipodi:cx="-151.10661" - id="path3647" - style="opacity:0.98999999000000005;fill:#a1e7c2;fill-opacity:1;stroke:none" - sodipodi:type="arc" /> - <text - id="text2391-0" - y="139.38979" - x="26.032473" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:tb-rl;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="26.032473" - x="139.38979" - id="tspan2393-2" - sodipodi:role="line">The Network</tspan></text> - </g> - <g - id="g4449" - transform="translate(124.15833,0)"> - <g - transform="translate(16.92564,27.32198)" - id="g4269"> - <rect - style="opacity:0.98999999000000005;fill:#6c69d6;fill-opacity:1;stroke:none" - id="rect3686-6" - width="79.478157" - height="52.004227" - x="121.68074" - y="72.986778" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="132.4207" - y="104.78089" - id="text2391-8-2"><tspan - sodipodi:role="line" - id="tspan2393-0-74" - x="132.4207" - y="104.78089">Protocol</tspan></text> - </g> - </g> - <g - id="g4443" - transform="translate(124.15833,92.23391)"> - <g - id="g5775"> - <rect - style="opacity:0.98999999000000005;fill:#a7d164;fill-opacity:1;stroke:none" - id="rect3686-6-9" - width="79.478157" - height="52.004227" - x="138.60638" - y="219.18733" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="149.34634" - y="250.98145" - id="text2391-8-2-6"><tspan - sodipodi:role="line" - id="tspan2393-0-74-9" - x="149.34634" - y="250.98145">Protocol</tspan></text> - </g> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9)" - d="m 138.10638,334.4445 -76.294296,0.005" - id="path3999-1" - sodipodi:nodetypes="cc" /> - <g - id="g4438" - transform="translate(-159.69248,80.788628)"> - <rect - y="19.02013" - x="298.29886" - height="52.004227" - width="79.478157" - id="rect3686-6-6" - style="opacity:0.98999999000000005;fill:#6065aa;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7" - y="50.814243" - x="303.88843" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="50.814243" - x="303.88843" - id="tspan2393-0-74-2" - sodipodi:role="line">Transport</tspan></text> - </g> - <g - id="g4438-5" - transform="translate(-159.69248,292.64147)"> - <g - id="g5766"> - <g - id="g5761"> - <rect - y="19.02013" - x="298.29886" - height="52.004227" - width="79.478157" - id="rect3686-6-6-5" - style="opacity:0.98999999000000005;fill:#84be45;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7-7" - y="50.814243" - x="303.88843" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="50.814243" - x="303.88843" - id="tspan2393-0-74-2-8" - sodipodi:role="line">Transport</tspan></text> - </g> - </g> - </g> - <rect - style="opacity:0.98999999;fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3, 3;stroke-dashoffset:0" - id="rect4501" - width="472.94409" - height="448.41379" - x="-95.177544" - y="-35.814224" - transform="translate(177.11921,71.024349)" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend-9)" - d="m 262.76471,337.40202 -42.02414,0.005" - id="path3999-1-6" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend-9)" - d="m 261.43669,126.30837 -42.02414,0.005" - id="path3999-1-6-9" - sodipodi:nodetypes="cc" /> - <g - id="g5821" - transform="translate(-23.08951,-4.874878e-6)"> - <g - transform="translate(1.2380755,-118.87857)" - id="g5130"> - <rect - style="opacity:0.98999999000000005;fill:#8589ed;fill-opacity:1;stroke:none" - id="rect3686-6-9-9" - width="79.478157" - height="52.004227" - x="411.13821" - y="219.18733" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="450.8313" - y="239.33345" - id="text2391-8-2-6-0"><tspan - sodipodi:role="line" - id="tspan2393-0-74-9-3" - x="450.8313" - y="239.33345">Protocol</tspan><tspan - id="tspan5086" - sodipodi:role="line" - x="450.8313" - y="259.33344">Factory</tspan></text> - </g> - </g> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="318.26822" - y="31.222124" - id="text2391-8-2-6-0-0"><tspan - id="tspan5086-1" - sodipodi:role="line" - x="318.26822" - y="31.222124">Poetry Server</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend-9)" - d="m 342.24287,336.45604 45.71582,0.98621" - id="path3999-1-6-8" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend-9)" - d="m 342.65311,127.01225 45.30541,0.98621" - id="path3999-1-6-8-7" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-9)" - d="m 138.60638,126.17269 -79.805464,2.4e-4" - id="path3999-1-61" - sodipodi:nodetypes="cc" /> - <g - id="g5130-7" - transform="translate(-21.851435,91.844318)"> - <rect - y="219.18733" - x="411.13821" - height="52.004227" - width="79.478157" - id="rect3686-6-9-9-5" - style="opacity:0.98999999;fill:#bde07e;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-9" - y="239.33345" - x="450.8313" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="239.33345" - x="450.8313" - id="tspan2393-0-74-9-3-3" - sodipodi:role="line">Protocol</tspan><tspan - y="259.33344" - x="450.8313" - sodipodi:role="line" - id="tspan5086-7">Factory</tspan></text> - </g> - <g - id="g5951"> - <rect - y="205.67021" - x="390.00049" - height="52.004227" - width="79.478157" - id="rect3686-6-9-9-7" - style="opacity:0.98999999000000005;fill:#eb9bb4;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-6-0-5" - y="237.24033" - x="429.59744" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="237.24033" - x="429.59744" - sodipodi:role="line" - id="tspan5086-71">Service</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend-9)" - d="m 429.00785,152.31298 4.9e-4,51.75732" - id="path3999-1-6-8-7-2" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-start:none;marker-end:url(#Arrow2Lend-9)" - d="m 427.64009,310.75978 4.9e-4,-51.75732" - id="path3999-1-6-8-7-2-0" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-async.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-async.svg deleted file mode 100644 index 13fdae8..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-async.svg +++ /dev/null @@ -1,305 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="620.5" - height="178.52078" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.46" - version="1.0" - sodipodi:docname="sync-async.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/sync-async.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4576" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - id="path3187" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.4412929" - inkscape:cx="347.72595" - inkscape:cy="89.116796" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25"> - <sodipodi:guide - orientation="1,0" - position="-230.31478,874.7921" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-147.48227,461.63971" - id="guide7821" /> - <inkscape:grid - type="xygrid" - id="grid8435" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(29.474739,138.66301)" - style="display:inline"> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3240" - width="140" - height="30" - x="121.02526" - y="-100.90269" - ry="0.69382149" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="134.47421" - y="-82.246391" - id="text3242"><tspan - sodipodi:role="line" - id="tspan3244" - x="134.47421" - y="-82.246391">Synchronous function</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 21.02526,-130.90269 C 49.39239,-151.40859 100.69439,-124.34631 121.02526,-100.90269" - id="path3316" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="-9.7363653" - y="-119.38269" - id="text3318"><tspan - sodipodi:role="line" - id="tspan3320" - x="-9.7363653" - y="-119.38269">Call a</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 121.02526,-70.902687 C 111.02526,-20.902687 101.02526,-20.902687 51.02526,-10.902687" - id="path3248" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="101.02526" - y="-10.902687" - id="text3250"><tspan - sodipodi:role="line" - id="tspan3252" - x="101.02526" - y="-10.902687">Get the</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3254" - width="80.5" - height="29.5" - x="-28.974739" - y="-10.902687" - ry="0.69382149" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="-19.27474" - y="6.6493125" - id="text3256"><tspan - sodipodi:role="line" - id="tspan3258" - x="-19.27474" - y="6.6493125">Final result</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3260" - width="140" - height="30" - x="450.52527" - y="-100.90269" - ry="0.69382149" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="463.97424" - y="-82.246391" - id="text3262"><tspan - sodipodi:role="line" - id="tspan3264" - x="463.97424" - y="-82.246391">Aynchronous function</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 350.52526,-130.90269 C 378.89239,-151.40859 430.19439,-124.34631 450.52526,-100.90269" - id="path3266" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="319.76364" - y="-119.38269" - id="text3268"><tspan - sodipodi:role="line" - id="tspan3270" - x="319.76364" - y="-119.38269">Call an</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" - d="M 450.52526,-70.902685 C 440.52526,-20.902689 430.52526,-20.902689 380.52526,-10.902689" - id="path3272" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="430.52527" - y="-10.902687" - id="text3274"><tspan - sodipodi:role="line" - id="tspan3276" - x="430.52527" - y="-10.902687">Get a</tspan></text> - <rect - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" - id="rect3278" - width="70.000008" - height="29.5" - x="311.02527" - y="-10.902687" - ry="0.69382149" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="321.02527" - y="9.0973129" - id="text3280"><tspan - sodipodi:role="line" - id="tspan3282" - x="321.02527" - y="9.0973129">Deferred</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="279.44449" - y="35.189766" - id="text3284"><tspan - sodipodi:role="line" - id="tspan3286" - x="279.44449" - y="35.189766">&quot;The Result is on the Way&quot;</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-cancel.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-cancel.svg deleted file mode 100644 index 2191260..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-cancel.svg +++ /dev/null @@ -1,395 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="376.1084" - height="256.54401" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - sodipodi:docname="sync-cancel.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/sync-cancel.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart" - style="overflow:visible"> - <path - id="path4011" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective4861" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4930" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4955" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4983" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5566" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5591" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart-1" - style="overflow:visible"> - <path - id="path4011-9" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <inkscape:perspective - id="perspective5995" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6028" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3239" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend-6" - style="overflow:visible"> - <path - id="path3187-9" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - id="perspective3267" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2" - inkscape:cx="162.00639" - inkscape:cy="109.86601" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1" - inkscape:snap-grids="true"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-193.89353,-24.243745)"> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#Arrow1Mend)" - d="m 215.35366,53.171746 0,210.232944" - id="path2403" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="292.99216" - y="43.171745" - id="text3479"><tspan - sodipodi:role="line" - id="tspan3481" - x="292.99216" - y="43.171745">Python Stack</tspan></text> - <rect - style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="rect4851" - width="134.99998" - height="210" - x="271.35367" - y="53.171745" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="311.28729" - y="78.171745" - id="text2403-1"><tspan - sodipodi:role="line" - id="tspan2405-6" - x="311.28729" - y="78.171745">main()</tspan></text> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,44.998162)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-9" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,54.998144)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-1" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,64.998126)" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="282.31464" - y="158.17175" - id="text2403-1-1"><tspan - sodipodi:role="line" - id="tspan2405-6-5" - x="282.31464" - y="158.17175">get_poetry()</tspan></text> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-6" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,124.99815)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-9-8" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,134.99814)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-1-2" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,144.99812)" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="272.50607" - y="243.17175" - id="text2403-1-1-7"><tspan - sodipodi:role="line" - id="tspan2405-6-5-4" - x="272.50607" - y="243.17175">sock.connect()</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="431.77063" - y="278.17175" - id="text3479-1"><tspan - sodipodi:role="line" - id="tspan3481-9" - x="431.77063" - y="278.17175">exceptions</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow1Mstart);marker-end:none" - d="m 459.35366,52.938806 0,210.232954" - id="path2403-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Vera Sans" - x="215.28381" - y="33.171745" - id="text3479-1-1"><tspan - sodipodi:role="line" - id="tspan3481-9-0" - x="215.28381" - y="33.171745" - style="-inkscape-font-specification:Bitstream Vera Sans">function</tspan><tspan - sodipodi:role="line" - x="215.28381" - y="48.171745" - id="tspan6012" - style="-inkscape-font-specification:Bitstream Vera Sans">calls</tspan></text> - <text - xml:space="preserve" - style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="-67" - y="-30.826294" - id="text6016" - transform="translate(211.35366,52.49804)"><tspan - sodipodi:role="line" - id="tspan6018" - x="-67" - y="-30.826294" /></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1,2;marker-start:none;marker-end:url(#Arrow1Mend);stroke-dashoffset:0" - d="m 536.58166,55.787751 0,210.232939" - id="path2403-8" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="502.71738" - y="278.17175" - id="text3479-1-0"><tspan - sodipodi:role="line" - id="tspan3481-9-4" - x="502.71738" - y="278.17175">cancellations</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-exceptions.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-exceptions.svg deleted file mode 100644 index 6ed3b40..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync-exceptions.svg +++ /dev/null @@ -1,381 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="386.91104" - height="256.54401" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre2 r22153" - sodipodi:docname="sync-exceptions.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/sync-exceptions.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart" - style="overflow:visible"> - <path - id="path4011" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective4861" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4899-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4930" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4955" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4983" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5566" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5591" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mstart-1" - style="overflow:visible"> - <path - id="path4011-9" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.4,0,0,0.4,4,0)" /> - </marker> - <inkscape:perspective - id="perspective5995" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6028" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective6055" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="2" - inkscape:cx="188.2337" - inkscape:cy="109.86601" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1" - inkscape:snap-grids="true"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-111.58166,-24.243745)"> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#Arrow1Mend)" - d="m 201.35366,53.171746 0,210.232944" - id="path2403" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="292.99216" - y="43.171745" - id="text3479"><tspan - sodipodi:role="line" - id="tspan3481" - x="292.99216" - y="43.171745">Python Stack</tspan></text> - <rect - style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="rect4851" - width="134.99998" - height="210" - x="271.35367" - y="53.171745" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="311.28729" - y="78.171745" - id="text2403-1"><tspan - sodipodi:role="line" - id="tspan2405-6" - x="311.28729" - y="78.171745">main()</tspan></text> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,44.998162)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-9" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,54.998144)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-1" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,64.998126)" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="282.31464" - y="158.17175" - id="text2403-1-1"><tspan - sodipodi:role="line" - id="tspan2405-6-5" - x="282.31464" - y="158.17175">get_poetry()</tspan></text> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-6" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,124.99815)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-9-8" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,134.99814)" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="path4889-1-2" - sodipodi:cx="-52.5" - sodipodi:cy="58.173706" - sodipodi:rx="2.5" - sodipodi:ry="2.5" - d="m -50,58.173706 c 0,1.380712 -1.119288,2.5 -2.5,2.5 -1.380712,0 -2.5,-1.119288 -2.5,-2.5 0,-1.380712 1.119288,-2.5 2.5,-2.5 1.380712,0 2.5,1.119288 2.5,2.5 z" - transform="matrix(1,0,0,0.99999821,391.35366,144.99812)" /> - <text - xml:space="preserve" - style="font-size:15.99998569px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="272.50607" - y="243.17175" - id="text2403-1-1-7"><tspan - sodipodi:role="line" - id="tspan2405-6-5-4" - x="272.50607" - y="243.17175">sock.connect()</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="443.77063" - y="278.17175" - id="text3479-1"><tspan - sodipodi:role="line" - id="tspan3481-9" - x="443.77063" - y="278.17175">exceptions</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow1Mstart);marker-end:none" - d="m 471.35366,52.938806 0,210.232954" - id="path2403-0" - sodipodi:nodetypes="cc" /> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Vera Sans" - x="201.28381" - y="33.171745" - id="text3479-1-1"><tspan - sodipodi:role="line" - id="tspan3481-9-0" - x="201.28381" - y="33.171745" - style="-inkscape-font-specification:Bitstream Vera Sans">function</tspan><tspan - sodipodi:role="line" - x="201.28381" - y="48.171745" - id="tspan6012" - style="-inkscape-font-specification:Bitstream Vera Sans">calls</tspan></text> - <text - xml:space="preserve" - style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" - x="-67" - y="-30.826294" - id="text6016" - transform="translate(211.35366,52.49804)"><tspan - sodipodi:role="line" - id="tspan6018" - x="-67" - y="-30.826294" /></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="111.35366" - y="68.171745" - id="text3479-1-2"><tspan - sodipodi:role="line" - id="tspan3481-9-03" - x="111.35366" - y="68.171745">high-context,</tspan><tspan - sodipodi:role="line" - x="111.35366" - y="83.171745" - id="tspan6045">special-purpose</tspan></text> - <text - xml:space="preserve" - style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="111.25766" - y="233.17175" - id="text3479-1-2-5"><tspan - sodipodi:role="line" - id="tspan3481-9-03-1" - x="111.25766" - y="233.17175">low-context,</tspan><tspan - sodipodi:role="line" - x="111.25766" - y="248.17175" - id="tspan6045-5">general-purpose</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync.svg deleted file mode 100644 index f40c560..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/sync.svg +++ /dev/null @@ -1,160 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="136.28021" - height="360.82349" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - sodipodi:docname="sync.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/sync.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.08" - inkscape:cx="135.41634" - inkscape:cy="233.54437" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-211.35366,-52.259392)"> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.17800596px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2401" - width="19.954937" - height="120.04401" - x="271.14273" - y="52.715393" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="211.09766" - y="72.759392" - id="text2403"><tspan - sodipodi:role="line" - id="tspan2405" - x="211.09766" - y="72.759392">Task 1</tspan></text> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.17804013px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2383" - width="19.954966" - height="120.08995" - x="271.39871" - y="172.83118" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="211.35365" - y="192.83118" - id="text2385"><tspan - sodipodi:role="line" - id="tspan2387" - x="211.35365" - y="192.83118">Task 2</tspan></text> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.17773573px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2389" - width="19.88962" - height="120.07285" - x="271.35367" - y="293.01004" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="211.35365" - y="312.92114" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="211.35365" - y="312.92114">Task 3</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" - d="M 331.09766,52.700155 L 331.09766,382.84423" - id="path2403" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="314.80136" - y="404.9816" - id="text3953"><tspan - sodipodi:role="line" - id="tspan3955" - x="314.80136" - y="404.9816">time</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/test-1.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/test-1.svg deleted file mode 100644 index e878e14..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/test-1.svg +++ /dev/null @@ -1,1308 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="583.95001" - height="463.8298" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="test-1.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4"> - <linearGradient - inkscape:collect="always" - id="linearGradient3079"> - <stop - style="stop-color:#7dff84;stop-opacity:1;" - offset="0" - id="stop3081" /> - <stop - style="stop-color:#7dff84;stop-opacity:0;" - offset="1" - id="stop3083" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3071"> - <stop - style="stop-color:#ef7dff;stop-opacity:1;" - offset="0" - id="stop3073" /> - <stop - style="stop-color:#ef7dff;stop-opacity:0;" - offset="1" - id="stop3075" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient9179"> - <stop - style="stop-color:#ef7dff;stop-opacity:1;" - offset="0" - id="stop9181" /> - <stop - style="stop-color:#ef7dff;stop-opacity:0;" - offset="1" - id="stop9183" /> - </linearGradient> - <linearGradient - id="linearGradient9171"> - <stop - style="stop-color:#ef7dff;stop-opacity:1;" - offset="0" - id="stop9173" /> - <stop - style="stop-color:#ef7dff;stop-opacity:0;" - offset="1" - id="stop9175" /> - </linearGradient> - <linearGradient - id="linearGradient9119"> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="0" - id="stop9121" /> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="1" - id="stop9123" /> - </linearGradient> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path7788" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow1Send" - orient="auto" - refY="0" - refX="0" - id="Arrow1Send" - style="overflow:visible"> - <path - id="path7776" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lend" - style="overflow:visible"> - <path - id="path7764" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.8,0,0,-0.8,-10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart" - style="overflow:visible"> - <path - id="path4552" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective3669" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3696" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3721-8" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective3979" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4219" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4282-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4328" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4356" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-4" - style="overflow:visible"> - <path - id="path3871-5-9" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4384" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4412" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4463-4" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4511" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-0" - style="overflow:visible"> - <path - id="path3871-5-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-7" - style="overflow:visible"> - <path - id="path4552-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-47" - style="overflow:visible"> - <path - id="path3871-5-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5005-9" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-77" - style="overflow:visible"> - <path - id="path4552-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-41" - style="overflow:visible"> - <path - id="path3871-5-7" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5056" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5110" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5154" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5182" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-64" - style="overflow:visible"> - <path - id="path3871-16" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5210" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lstart-5" - style="overflow:visible"> - <path - id="path4552-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(1.1,0,0,1.1,1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-9" - style="overflow:visible"> - <path - id="path3871-5-15" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective5462" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5522" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-9-09" - style="overflow:visible"> - <path - id="path3871-5-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective8706" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-0" - style="overflow:visible"> - <path - id="path7788-2" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8734" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-2" - style="overflow:visible"> - <path - id="path7788-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker8740" - style="overflow:visible"> - <path - id="path8742" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8773" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend-3" - style="overflow:visible"> - <path - id="path7788-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="marker8779" - style="overflow:visible"> - <path - id="path8781" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <inkscape:perspective - id="perspective8812" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8881" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8881-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective8982" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-98" - style="overflow:visible"> - <path - id="path3871-24" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective8982-0" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-982" - style="overflow:visible"> - <path - id="path3871-49" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9023" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9023-6" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <filter - id="filter9071" - inkscape:menu-tooltip="Make the lightest parts of the object progressively transparent" - inkscape:menu="Transparency utilities" - inkscape:label="Light eraser" - height="1" - width="1" - y="0" - x="0" - color-interpolation-filters="sRGB"> - <feColorMatrix - id="feColorMatrix9073" - result="result14" - type="luminanceToAlpha" - in="SourceGraphic" /> - <feComposite - id="feComposite9075" - in2="result14" - in="SourceGraphic" - result="fbSourceGraphic" - operator="out" /> - <feBlend - id="feBlend9077" - in2="fbSourceGraphic" - mode="normal" - result="fbSourceGraphic" /> - <feColorMatrix - result="fbSourceGraphicAlpha" - in="fbSourceGraphic" - values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0" - id="feColorMatrix9079" /> - <feColorMatrix - id="feColorMatrix9081" - result="result14" - type="luminanceToAlpha" - in="fbSourceGraphic" /> - <feComposite - id="feComposite9083" - in2="result14" - in="fbSourceGraphic" - result="fbSourceGraphic" - operator="out" /> - <feBlend - id="feBlend9085" - in2="fbSourceGraphic" - mode="normal" - result="fbSourceGraphic" /> - <feColorMatrix - result="fbSourceGraphicAlpha" - in="fbSourceGraphic" - values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0" - id="feColorMatrix9087" /> - <feColorMatrix - id="feColorMatrix9089" - result="result14" - type="luminanceToAlpha" - in="fbSourceGraphic" /> - <feComposite - id="feComposite9091" - in2="result14" - in="fbSourceGraphic" - result="fbSourceGraphic" - operator="out" /> - <feBlend - id="feBlend9093" - in2="fbSourceGraphic" - mode="normal" - result="result15" /> - </filter> - <filter - id="filter9095" - inkscape:label="filter2" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient9119" - id="linearGradient9125" - x1="358.1423" - y1="87.535103" - x2="357.16107" - y2="-0.28335771" - gradientUnits="userSpaceOnUse" /> - <mask - maskUnits="userSpaceOnUse" - id="mask9139"> - <g - transform="translate(101.41685,-286.8348)" - id="g9141"> - <g - transform="translate(367.10363,124.35372)" - id="g9143"> - <rect - style="opacity:0.98999999;fill:#7dc2ff;fill-opacity:1;stroke:none" - id="rect9145" - width="101.06482" - height="52.004227" - x="-165.55931" - y="99.808762" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="-163.05141" - y="128.53087" - id="text9147"><tspan - sodipodi:role="line" - id="tspan9149" - x="-163.05141" - y="128.53087">test_rhyme</tspan></text> - </g> - <g - transform="translate(-58.73238,15.845715)" - id="g9151"> - <rect - style="opacity:0.98999999;fill:#7dff84;fill-opacity:1;stroke:none" - id="rect9153" - width="101.06499" - height="52.004227" - x="260.27661" - y="126.30837" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="251.15814" - y="174.92177" - id="text9155" - transform="scale(1.1276556,0.88679557)"><tspan - sodipodi:role="line" - id="tspan9157" - x="251.15814" - y="174.92177">setUp</tspan></text> - </g> - <g - transform="translate(-58.732418,5.0523862)" - id="g9159"> - <g - transform="translate(0,247.26536)" - id="g9161"> - <rect - y="53.853149" - x="260.27664" - height="52.004227" - width="101.065" - id="rect9163" - style="opacity:0.98999999;fill:#ef7dff;fill-opacity:1;stroke:none" /> - <text - id="text9165" - y="84.447266" - x="272.26566" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - xml:space="preserve"><tspan - y="84.447266" - x="272.26566" - id="tspan9167" - sodipodi:role="line">tearDown</tspan></text> - </g> - </g> - <rect - y="130.04816" - x="166.22069" - height="244.32175" - width="171.7121" - id="rect9169" - style="opacity:0.98999999;fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.99999995, 2.99999995;stroke-dashoffset:0" /> - </g> - </mask> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient9179" - id="linearGradient9185" - x1="352.02176" - y1="87.535103" - x2="352.02182" - y2="-0.28335771" - gradientUnits="userSpaceOnUse" /> - <inkscape:perspective - id="perspective3007" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3071" - id="linearGradient3077" - x1="309.57059" - y1="105.85738" - x2="308.58939" - y2="53.853149" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3079" - id="linearGradient3085" - x1="309.57056" - y1="126.30837" - x2="309.57056" - y2="178.31259" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.019148" - inkscape:cx="343.321" - inkscape:cy="196.72226" - inkscape:document-units="px" - inkscape:current-layer="g7748-22" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="false" - inkscape:bbox-nodes="false" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1" - inkscape:object-paths="true" - inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-intersection-paths="true"> - <sodipodi:guide - orientation="1,0" - position="112.36374,922.39025" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="195.19625,509.23786" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(165.55931,-20.294124)"> - <g - id="g5141" - transform="translate(-57.399542,-5.2549788)"> - <rect - style="opacity:0.98999999;fill:#ffd2b7;fill-opacity:0.98823529;stroke:none" - id="rect6845" - width="107.9333" - height="408.18408" - x="-64.494499" - y="53.371964" /> - <text - id="text2391-0" - y="262.608" - x="-53.3951" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - xml:space="preserve"><tspan - y="262.608" - x="-53.3951" - id="tspan2393-2" - sodipodi:role="line">reactor/trial</tspan></text> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m -12.960746,157.82637 148.652726,0.005" - id="path3999-1" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="M 17.553642,410.67506 C 23.440918,393.01325 38.203254,390.57104 35.961074,374.20888 34.12026,360.77564 22.165699,344.34134 22.165699,344.34134" - id="path3779-7-9" - sodipodi:nodetypes="csc" /> - <g - id="g8857" - transform="translate(-64.142456,0)"> - <g - transform="translate(367.10363,124.35372)" - id="g4254"> - <rect - style="opacity:0.98999999;fill:#7dc2ff;fill-opacity:1;stroke:none" - id="rect3686" - width="101.06482" - height="52.004227" - x="-165.55931" - y="99.808762" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="-163.05141" - y="128.53087" - id="text2391-8"><tspan - sodipodi:role="line" - id="tspan2393-0" - x="-163.05141" - y="128.53087">test_rhyme</tspan></text> - </g> - <g - transform="translate(-58.73238,15.845715)" - id="g7748"> - <rect - style="opacity:0.98999999;fill:#7dff84;fill-opacity:1;stroke:none" - id="rect3686-6" - width="101.06499" - height="52.004227" - x="260.27661" - y="126.30837" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="251.15814" - y="174.92177" - id="text2391-8-2" - transform="scale(1.1276556,0.88679557)"><tspan - sodipodi:role="line" - id="tspan2393-0-74" - x="251.15814" - y="174.92177">setUp</tspan></text> - </g> - <g - transform="translate(-58.732418,5.0523862)" - id="g7740"> - <g - transform="translate(0,247.26536)" - id="g7753"> - <rect - y="53.853149" - x="260.27664" - height="52.004227" - width="101.065" - id="rect3686-6-6" - style="opacity:0.98999999;fill:#ef7dff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7" - y="84.447266" - x="272.26566" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - xml:space="preserve"><tspan - y="84.447266" - x="272.26566" - id="tspan2393-0-74-2" - sodipodi:role="line">tearDown</tspan></text> - </g> - </g> - <rect - y="130.04816" - x="166.22069" - height="244.32175" - width="171.7121" - id="rect4501" - style="opacity:0.98999999;fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.99999995, 2.99999995;stroke-dashoffset:0" /> - </g> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="332.54181" - y="256.35303" - id="text2391-8-2-6-0-0"><tspan - id="tspan5086-1" - sodipodi:role="line" - x="332.54181" - y="256.35303">A single test</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 137.34074,178.41196 -148.652739,0.005" - id="path3999-1-3" /> - <path - style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m -12.960746,237.85389 148.652746,0.005" - id="path3999-1-0" /> - <path - style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 137.34074,262.46599 -148.652739,0.005" - id="path3999-1-3-9" /> - <path - style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="M -13.960746,319.7254 134.692,319.7304" - id="path3999-1-0-5" /> - <path - style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#Arrow2Mend)" - d="m 136.34074,344.3375 -148.652736,0.005" - id="path3999-1-3-9-5" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="-3.9518054" - y="427.85712" - id="text2391-8-2-6-0-0-2"><tspan - id="tspan5086-1-4" - sodipodi:role="line" - x="-3.9518054" - y="427.85712">Possibly</tspan><tspan - sodipodi:role="line" - x="-3.9518054" - y="447.85712" - id="tspan8829">asynchronous</tspan></text> - <g - transform="translate(-64.142456,264.29488)" - id="g8857-29"> - <g - transform="translate(367.10363,124.35372)" - id="g4254-7"> - <rect - style="opacity:0.98999999;fill:#7dc2ff;fill-opacity:1;stroke:none" - id="rect3686-5" - width="101.06482" - height="52.004227" - x="-165.55931" - y="99.808762" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="-163.05141" - y="128.53087" - id="text2391-8-9"><tspan - sodipodi:role="line" - id="tspan2393-0-0" - x="-163.05141" - y="128.53087">test_rhyme</tspan></text> - </g> - <g - transform="translate(-58.73238,15.845715)" - id="g7748-22"> - <rect - style="opacity:0.98999999000000005;fill:url(#linearGradient3085);fill-opacity:1;stroke:none" - id="rect3686-6-3" - width="101.06499" - height="52.004227" - x="260.27661" - y="126.30837" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="251.15814" - y="174.92177" - id="text2391-8-2-2" - transform="scale(1.1276556,0.88679557)"><tspan - sodipodi:role="line" - id="tspan2393-0-74-0" - x="251.15814" - y="174.92177">setUp</tspan></text> - </g> - <g - transform="translate(-58.732418,5.0523862)" - id="g7740-5"> - <g - transform="translate(0,247.26536)" - id="g7753-4"> - <rect - y="53.853149" - x="260.27664" - height="52.004227" - width="101.065" - id="rect3686-6-6-5" - style="opacity:0.98999999;fill:#ef7dff;fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7-0" - y="84.447266" - x="272.26566" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - xml:space="preserve"><tspan - y="84.447266" - x="272.26566" - id="tspan2393-0-74-2-2" - sodipodi:role="line">tearDown</tspan></text> - </g> - </g> - <rect - y="130.04816" - x="166.22069" - height="244.32175" - width="171.7121" - id="rect4501-7" - style="opacity:0.98999999;fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.99999995, 2.99999995;stroke-dashoffset:0" /> - </g> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 35.018132,369.70117 c 5.88728,-17.66181 15.403248,-48.43193 14.482583,-64.92132 -0.859598,-15.39566 -6.927141,-42.31067 -6.927141,-42.31067" - id="path3779-7-9-5" - sodipodi:nodetypes="csc" /> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 48.647128,295.9681 c 5.88728,-17.66181 24.479679,-57.50429 26.448364,-73.9016 2.084037,-17.35809 -7.9082,-43.65218 -7.9082,-43.65218" - id="path3779-7-9-2" - sodipodi:nodetypes="csc" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="334.04504" - y="74.196571" - id="text2391-8-2-6-0-0-8"><tspan - id="tspan5086-1-6" - sodipodi:role="line" - x="334.04504" - y="74.196571">Previous test</tspan></text> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="320.65405" - y="437.2449" - id="text2391-8-2-6-0-0-0"><tspan - id="tspan5086-1-68" - sodipodi:role="line" - x="320.65405" - y="437.2449">Next test</tspan></text> - <g - transform="translate(-64.142456,-264.57825)" - id="g8857-29-8"> - <g - transform="translate(367.10363,124.35372)" - id="g4254-7-1"> - <rect - style="opacity:0.98999999;fill:#7dc2ff;fill-opacity:1;stroke:none" - id="rect3686-5-2" - width="101.06482" - height="52.004227" - x="-165.55931" - y="99.808762" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="-163.05141" - y="128.53087" - id="text2391-8-9-9"><tspan - sodipodi:role="line" - id="tspan2393-0-0-3" - x="-163.05141" - y="128.53087">test_rhyme</tspan></text> - </g> - <g - transform="translate(-58.73238,15.845715)" - id="g7748-22-9"> - <rect - style="opacity:0.98999999;fill:#7dff84;fill-opacity:1;stroke:none" - id="rect3686-6-3-0" - width="101.06499" - height="52.004227" - x="260.27661" - y="126.30837" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - x="251.15814" - y="174.92177" - id="text2391-8-2-2-8" - transform="scale(1.1276556,0.88679557)"><tspan - sodipodi:role="line" - id="tspan2393-0-74-0-8" - x="251.15814" - y="174.92177">setUp</tspan></text> - </g> - <g - transform="translate(-58.732418,5.0523862)" - id="g7740-5-5"> - <g - transform="translate(0,247.26536)" - id="g7753-4-0"> - <rect - y="53.853149" - x="260.27664" - height="52.004227" - width="101.065" - id="rect3686-6-6-5-9" - style="opacity:0.98999999000000005;fill:url(#linearGradient3077);fill-opacity:1;stroke:none" /> - <text - id="text2391-8-2-7-0-6" - y="84.447266" - x="272.26566" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch" - xml:space="preserve"><tspan - y="84.447266" - x="272.26566" - id="tspan2393-0-74-2-2-3" - sodipodi:role="line">tearDown</tspan></text> - </g> - </g> - <rect - y="130.04816" - x="166.22069" - height="244.32175" - width="171.7121" - id="rect4501-7-8" - style="opacity:0.98999999;fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.99999995, 2.99999995;stroke-dashoffset:0" /> - </g> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/theend.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/theend.svg deleted file mode 100644 index bdd9091..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/theend.svg +++ /dev/null @@ -1,641 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="490.29999" - height="302.20999" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="theend.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - inkscape:export-filename="/home/dave/src/twisted-intro/images/theend.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Send" - orient="auto" - refY="0" - refX="0" - id="Arrow1Send" - style="overflow:visible"> - <path - id="path4504" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mend" - style="overflow:visible"> - <path - id="path4516" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(-0.6,-0.6)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend" - style="overflow:visible"> - <path - id="path3871" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lstart" - orient="auto" - refY="0" - refX="0" - id="Arrow1Lstart" - style="overflow:visible"> - <path - id="path3850" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(0.8,0,0,0.8,10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Mstart" - orient="auto" - refY="0" - refX="0" - id="Arrow2Mstart" - style="overflow:visible"> - <path - id="path3874" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="scale(0.6,0.6)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <inkscape:perspective - id="perspective2492" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_x="0 : 526.18109 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187" /> - </marker> - <inkscape:perspective - id="perspective4375" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-5" - style="overflow:visible"> - <path - id="path3871-8" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4375-7" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-6" - style="overflow:visible"> - <path - id="path3871-5" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective4441" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective5988" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-4" - style="overflow:visible"> - <path - id="path3871-4" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="marker5994" - style="overflow:visible"> - <path - id="path5996" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6439" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-9" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-2" /> - </marker> - <marker - style="overflow:visible" - id="marker6445" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447" /> - </marker> - <inkscape:perspective - id="perspective6439-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - style="overflow:visible" - id="Arrow1Mend-4" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path3187-7" /> - </marker> - <marker - style="overflow:visible" - id="marker6445-7" - refX="0" - refY="0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="matrix(-0.4,0,0,-0.4,-4,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" - id="path6447-1" /> - </marker> - <inkscape:perspective - id="perspective6492" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-0" - style="overflow:visible"> - <path - id="path3871-59" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-59" - style="overflow:visible"> - <path - id="path3871-6" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective6520-5" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-63" - style="overflow:visible"> - <path - id="path3871-0" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9391" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9391-3" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective9794" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-2" - style="overflow:visible"> - <path - id="path3871-44" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9822" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-57" - style="overflow:visible"> - <path - id="path3871-3" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective9850" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-00" - style="overflow:visible"> - <path - id="path3871-45" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective10822" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-8" - style="overflow:visible"> - <path - id="path3871-51" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - <inkscape:perspective - id="perspective10858" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0" - refX="0" - id="Arrow2Lend-05" - style="overflow:visible"> - <path - id="path3871-1" - style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" - d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" - transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.019148" - inkscape:cx="172.48801" - inkscape:cy="131.15338" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:snap-bbox="true" - inkscape:object-nodes="true" - inkscape:bbox-paths="true" - inkscape:bbox-nodes="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:snap-global="true" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - inkscape:window-maximized="1"> - <sodipodi:guide - orientation="1,0" - position="-394.91969,630.41912" - id="guide7819" /> - <sodipodi:guide - orientation="1,0" - position="-312.08718,217.26673" - id="guide7821" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-341.72412,110.05771)"> - <text - xml:space="preserve" - style="font-size:20px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" - x="639.3244" - y="134.4532" - id="text9379-1"><tspan - sodipodi:role="line" - id="tspan9381-1" - x="639.3244" - y="134.4532">you</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 639.53924,141.59113 c 0,0 -32.58218,32.66978 -83.84868,5.44901 -9.0668,-4.81415 -73.05856,-13.97209 -73.05856,-13.97209" - id="path3379-9-6-3" - sodipodi:nodetypes="csc" /> - <path - style="fill:none;stroke:#000000;stroke-width:0.58449632px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 437.15372,136.22305 -29.60415,46.63664" - id="path9891" /> - <use - x="0" - y="0" - xlink:href="#path9891" - id="use9893" - transform="matrix(-1,0,0,1,874.89191,1.255529e-8)" - width="469.81" - height="177.26727" /> - <path - style="fill:none;stroke:#000000;stroke-width:0.58449632px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 437.15372,136.22305 436.34265,92.425134" - id="path9895" /> - <path - style="fill:none;stroke:#000000;stroke-width:0.58449632px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 405.92744,117.16283 29.19859,-11.76054 37.71486,8.92179" - id="path9897" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="path9899" - sodipodi:cx="130.78535" - sodipodi:cy="128.69977" - sodipodi:rx="4.5098414" - sodipodi:ry="5.5505743" - d="m 130.80036,123.14922 a 4.5098414,5.5505743 0 1 1 -0.0636,3e-4" - transform="matrix(0.58449632,0,0,0.58449632,329.47508,45.182558)" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="path9901" - sodipodi:cx="253.93867" - sodipodi:cy="123.4961" - sodipodi:rx="4.1629281" - sodipodi:ry="5.2036633" - d="m 253.95253,118.29247 a 4.1629281,5.2036633 0 1 1 -0.0587,2.7e-4" - transform="matrix(0.58449632,0,0,0.58449632,327.43237,41.938288)" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - sodipodi:open="true" /> - <path - sodipodi:type="arc" - style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" - id="path10795" - sodipodi:cx="173.62883" - sodipodi:cy="62.78672" - sodipodi:rx="13.009153" - sodipodi:ry="11.101145" - d="m 173.67212,51.685637 a 13.009153,11.101145 0 1 1 -0.18336,5.82e-4" - transform="matrix(0.58449632,0,0,0.58449632,334.75581,49.035171)" - sodipodi:start="4.7157166" - sodipodi:end="10.984807" - sodipodi:open="true" /> - <g - id="g10808" - transform="matrix(0.58449632,0,0,0.58449632,192.18878,10.500178)"> - <path - transform="translate(232.5848,59.337246)" - id="path10800" - d="m 175.63691,39.89762 c 0.98121,-71.628461 0.98121,-71.628461 0.98121,-71.628461" - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> - <use - height="177.26727" - width="469.81" - transform="translate(16.680601,0)" - id="use10802" - xlink:href="#path10800" - y="0" - x="0" /> - <path - transform="translate(232.5848,59.337246)" - id="path10804" - d="M 176.61812,-31.730841 C 46.116955,-129.85202 45.135743,-129.85202 45.135743,-129.85202" - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> - <use - height="177.26727" - width="469.81" - transform="matrix(-1,0,0,1,835.08644,0)" - id="use10806" - xlink:href="#path10804" - y="0" - x="0" /> - </g> - <text - xml:space="preserve" - style="font-size:20px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" - x="604.39813" - y="2.6558828" - id="text9379-1-8"><tspan - sodipodi:role="line" - id="tspan9381-1-5" - x="604.39813" - y="2.6558828">the knowledge funnel</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 604.613,9.7938188 c 0,0 -8.05189,20.8952412 -40.67536,12.3174972 -9.92817,-2.61043 -44.60342,-45.370872 -44.60342,-45.370872" - id="path3379-9-6-3-2" - sodipodi:nodetypes="csc" /> - <path - sodipodi:type="spiral" - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="path10848" - sodipodi:cx="192.31752" - sodipodi:cy="-182.83746" - sodipodi:expansion="1" - sodipodi:revolution="3" - sodipodi:radius="61.449245" - sodipodi:argument="-20.762302" - sodipodi:t0="0" - d="m 192.31752,-182.83746 c -1.03313,-2.90259 3.40292,-2.82467 4.82429,-1.71713 3.85182,3.00138 1.92423,8.84556 -1.39005,11.36571 -5.92845,4.50795 -14.28504,1.39658 -17.90711,-4.49722 -5.31554,-8.64938 -0.88874,-19.81112 7.60438,-24.44853 11.32,-6.18093 25.36963,-0.39146 30.98994,10.71156 7.07259,13.97201 -0.0999,30.94399 -13.81872,37.53135 -16.61532,7.97818 -36.52738,-0.58779 -44.07277,-16.92589 -8.89198,-19.25388 1.07347,-42.11639 20.03306,-50.61418 21.8896,-9.81103 47.70917,1.55767 57.1556,23.14023 10.73362,24.52347 -2.04085,53.30458 -26.2474,63.697 -27.15609,11.65873 -58.90192,-2.52327 -70.23842,-29.35456 -12.58566,-29.78781 3.00516,-64.5007 32.46173,-76.77983" - transform="matrix(0.58449632,0,0,0.58449632,326.815,44.966995)" /> - <text - xml:space="preserve" - style="font-size:20px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" - x="574.11536" - y="-69.654007" - id="text9379-1-8-3"><tspan - sodipodi:role="line" - id="tspan9381-1-5-0" - x="574.11536" - y="-69.654007">twisted knowledge</tspan></text> - <path - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)" - d="m 571.3866,-90.971219 c 0,0 -2.16462,-17.372031 -46.56263,-5.34433 -9.90846,2.68426 -56.37796,9.57699 -56.37796,9.57699" - id="path3379-9-6-3-2-1" - sodipodi:nodetypes="csc" /> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/threaded.svg b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/threaded.svg deleted file mode 100644 index 1544239..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/images/threaded.svg +++ /dev/null @@ -1,160 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="378.38803" - height="120.38375" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47pre4 r22446" - sodipodi:docname="threaded.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - inkscape:export-filename="/home/dave/src/twisted-intro/images/threaded.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0" - refX="0" - id="Arrow1Mend" - style="overflow:visible"> - <path - id="path3187" - d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" - transform="matrix(-0.4,0,0,-0.4,-4,0)" /> - </marker> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="6.1230318e-14 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="1" - inkscape:pageshadow="2" - inkscape:zoom="1.08" - inkscape:cx="290.04597" - inkscape:cy="7.3060278" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:snap-global="false" - inkscape:window-width="1280" - inkscape:window-height="974" - inkscape:window-x="0" - inkscape:window-y="25" - showguides="true" - inkscape:window-maximized="1"> - <inkscape:grid - type="xygrid" - id="grid2397" - visible="true" - enabled="true" - empspacing="5" - snapvisiblegridlinesonly="true" /> - </sodipodi:namedview> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-211.35366,-52.62639)"> - <rect - style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.17800596px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2401" - width="19.954937" - height="120.04401" - x="271.14273" - y="52.715393" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="211.09766" - y="72.759392" - id="text2403"><tspan - sodipodi:role="line" - id="tspan2405" - x="211.09766" - y="72.759392">Task 1</tspan></text> - <rect - style="fill:#00ff00;fill-rule:evenodd;stroke:#000000;stroke-width:0.17804013px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2383" - width="19.954966" - height="120.08995" - x="391.35367" - y="52.831169" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="331.30862" - y="72.831169" - id="text2385"><tspan - sodipodi:role="line" - id="tspan2387" - x="331.30862" - y="72.831169">Task 2</tspan></text> - <rect - style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:0.17773573px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="rect2389" - width="19.88962" - height="120.07285" - x="511.46405" - y="52.848289" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="451.35367" - y="72.848289" - id="text2391"><tspan - sodipodi:role="line" - id="tspan2393" - x="451.35367" - y="72.848289">Task 3</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" - d="M 571.35366,52.937653 L 571.35366,146.67294" - id="path2403" /> - <text - xml:space="preserve" - style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter" - x="556.90918" - y="166.52412" - id="text3953"><tspan - sodipodi:role="line" - id="tspan3955" - x="556.90918" - y="166.52412">time</tspan></text> - </g> -</svg> diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-1.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-1.py deleted file mode 100644 index bd4d43b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-1.py +++ /dev/null @@ -1,12 +0,0 @@ - -def my_generator(): - print 'starting up' - yield 1 - print "workin'" - yield 2 - print "still workin'" - yield 3 - print 'done' - -for n in my_generator(): - print n diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-2.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-2.py deleted file mode 100644 index aac1c14..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-2.py +++ /dev/null @@ -1,19 +0,0 @@ - -def my_generator(): - print 'starting up' - yield 1 - print "workin'" - yield 2 - print "still workin'" - yield 3 - print 'done' - -gen = my_generator() - -while True: - try: - n = gen.next() - except StopIteration: - break - else: - print n diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-3.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-3.py deleted file mode 100644 index 72603f2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-3.py +++ /dev/null @@ -1,22 +0,0 @@ - -def my_generator(): - yield 1 - yield 2 - yield 3 - -def my_other_generator(): - yield 10 - yield 20 - yield 30 - yield 40 - -gens = [my_generator(), my_other_generator()] - -while gens: - for g in gens[:]: - try: - n = g.next() - except StopIteration: - gens.remove(g) - else: - print n diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-4.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-4.py deleted file mode 100644 index dc17b71..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/gen-4.py +++ /dev/null @@ -1,33 +0,0 @@ - -class Malfunction(Exception): - pass - -def my_generator(): - print 'starting up' - - val = yield 1 - print 'got:', val - - val = yield 2 - print 'got:', val - - try: - yield 3 - except Malfunction: - print 'malfunction!' - - yield 4 - - print 'done' - -gen = my_generator() - -print gen.next() # start the generator -print gen.send(10) # send the value 10 -print gen.send(20) # send the value 20 -print gen.throw(Malfunction()) # raise an exception inside the generator - -try: - gen.next() -except StopIteration: - pass diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-1.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-1.py deleted file mode 100644 index a6445e9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-1.py +++ /dev/null @@ -1,32 +0,0 @@ - -from twisted.internet.defer import inlineCallbacks, Deferred - -@inlineCallbacks -def my_callbacks(): - from twisted.internet import reactor - - print 'first callback' - result = yield 1 # yielded values that aren't deferred come right back - - print 'second callback got', result - d = Deferred() - reactor.callLater(5, d.callback, 2) - result = yield d # yielded deferreds will pause the generator - - print 'third callback got', result # the result of the deferred - - d = Deferred() - reactor.callLater(5, d.errback, Exception(3)) - - try: - yield d - except Exception, e: - result = e - - print 'fourth callback got', repr(result) # the exception from the deferred - - reactor.stop() - -from twisted.internet import reactor -reactor.callWhenRunning(my_callbacks) -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-2.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-2.py deleted file mode 100644 index 549a297..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-2.py +++ /dev/null @@ -1,66 +0,0 @@ - -from twisted.internet.defer import inlineCallbacks, Deferred, returnValue - -@inlineCallbacks -def my_callbacks_1(): - from twisted.internet import reactor - - print 'my_callbacks_1 first callback' - d = Deferred() - reactor.callLater(2, d.callback, None) - yield d - - print 'my_callbacks_1 second callback' - d = Deferred() - reactor.callLater(2, d.callback, None) - yield d - - print 'my_callbacks_1 third callback' - returnValue(1) - -@inlineCallbacks -def my_callbacks_err(): - from twisted.internet import reactor - - print 'my_callbacks_err first callback' - d = Deferred() - reactor.callLater(3, d.callback, None) - yield d - - print 'my_callbacks_err second callback' - d = Deferred() - reactor.callLater(3, d.callback, None) - yield d - - print 'my_callbacks_err third callback' - raise Exception('uh oh') - -def got_result(res): - print 'got result:', res - -def got_error(err): - print 'got error:', err - -def run_callbacks(): - d1 = my_callbacks_1() - d1.addCallbacks(got_result, got_error) - - d2 = my_callbacks_err() - d2.addCallbacks(got_result, got_error) - - from twisted.internet import reactor - - def callbacks_finished(_): - callbacks_finished.count += 1 - if callbacks_finished.count == 2: - print 'all done' - reactor.stop() - callbacks_finished.count = 0 - - d1.addBoth(callbacks_finished) - d2.addBoth(callbacks_finished) - - -from twisted.internet import reactor -reactor.callWhenRunning(run_callbacks) -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-tb.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-tb.py deleted file mode 100644 index be8e55e..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/inline-callbacks/inline-callbacks-tb.py +++ /dev/null @@ -1,15 +0,0 @@ - -import traceback - -from twisted.internet.defer import inlineCallbacks - -@inlineCallbacks -def my_callbacks(): - yield 1 - traceback.print_stack() - from twisted.internet import reactor - reactor.stop() - -from twisted.internet import reactor -reactor.callWhenRunning(my_callbacks) -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/ecstasy.txt b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/ecstasy.txt deleted file mode 100644 index fb9ac19..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/ecstasy.txt +++ /dev/null @@ -1,80 +0,0 @@ -The Ecstasy - -Where, like a pillow on a bed - A pregnant bank swell'd up to rest -The violet's reclining head, - Sat we two, one another's best. -Our hands were firmly cemented - With a fast balm, which thence did spring; -Our eye-beams twisted, and did thread - Our eyes upon one double string; -So to'intergraft our hands, as yet - Was all the means to make us one, -And pictures in our eyes to get - Was all our propagation. -As 'twixt two equal armies fate - Suspends uncertain victory, -Our souls (which to advance their state - Were gone out) hung 'twixt her and me. -And whilst our souls negotiate there, - We like sepulchral statues lay; -All day, the same our postures were, - And we said nothing, all the day. -If any, so by love refin'd - That he soul's language understood, -And by good love were grown all mind, - Within convenient distance stood, -He (though he knew not which soul spake, - Because both meant, both spake the same) -Might thence a new concoction take - And part far purer than he came. -This ecstasy doth unperplex, - We said, and tell us what we love; -We see by this it was not sex, - We see we saw not what did move; -But as all several souls contain - Mixture of things, they know not what, -Love these mix'd souls doth mix again - And makes both one, each this and that. -A single violet transplant, - The strength, the colour, and the size, -(All which before was poor and scant) - Redoubles still, and multiplies. -When love with one another so - Interinanimates two souls, -That abler soul, which thence doth flow, - Defects of loneliness controls. -We then, who are this new soul, know - Of what we are compos'd and made, -For th' atomies of which we grow - Are souls. whom no change can invade. -But oh alas, so long, so far, - Our bodies why do we forbear? -They'are ours, though they'are not we; we are - The intelligences, they the spheres. -We owe them thanks, because they thus - Did us, to us, at first convey, -Yielded their senses' force to us, - Nor are dross to us, but allay. -On man heaven's influence works not so, - But that it first imprints the air; -So soul into the soul may flow, - Though it to body first repair. -As our blood labors to beget - Spirits, as like souls as it can, -Because such fingers need to knit - That subtle knot which makes us man, -So must pure lovers' souls descend - T' affections, and to faculties, -Which sense may reach and apprehend, - Else a great prince in prison lies. -To'our bodies turn we then, that so - Weak men on love reveal'd may look; -Love's mysteries in souls do grow, - But yet the body is his book. -And if some lover, such as we, - Have heard this dialogue of one, -Let him still mark us, he shall see - Small change, when we'are to bodies gone. - - -- John Donne diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/fascination.txt b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/fascination.txt deleted file mode 100644 index 3450a1d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/fascination.txt +++ /dev/null @@ -1,17 +0,0 @@ -The Fascination of what's Difficult - -The fascination of what's difficult -Has dried the sap out of my veins, and rent -Spontaneous joy and natural content -Out of my heart. There's something ails our colt -That must, as if it had not holy blood -Nor on Olympus leaped from cloud to cloud, -Shiver under the lash, strain, sweat and jolt -As though it dragged road metal. My curse on plays -That have to be set up in fifty ways, -On the day's war with every knave and dolt, -Theatre business, management of men. -I swear before the dawn comes round again -I'll find the stable and pull out the bolt. - - -- William Butler Yeats diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/science.txt b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/science.txt deleted file mode 100644 index 7409386..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/poetry/science.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sonnet - To Science - -Science! true daughter of Old Time thou art! -Who alterest all things with thy peering eyes. -Why preyest thou thus upon the poet's heart, -Vulture, whose wings are dull realities? -How should he love thee? or how deem thee wise, -Who wouldst not leave him in his wandering -To seek for treasure in the jewelled skies, -Albeit he soared with an undaunted wing? -Hast thou not dragged Diana from her car? -And driven the Hamadryad from the wood -To seek a shelter in some happier star? -Hast thou not torn the Naiad from her flood, -The Elfin from the green grass, and from me -The summer dream beneath the tamarind tree? - - -- Edgar Allen Poe diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/solutions/README b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/solutions/README deleted file mode 100644 index 7ff3b45..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/solutions/README +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains my own solutions to some of the exercises. -I will post more as I have time. diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/solutions/part-8/number-1/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/solutions/part-8/number-1/get-poetry.py deleted file mode 100644 index 7be720f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/solutions/part-8/number-1/get-poetry.py +++ /dev/null @@ -1,150 +0,0 @@ -import optparse, sys - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory - - -class TimeoutError(Exception): - pass - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -Get Poetry Now! - -Run it like this: - - python get-poetry.py port1 port2 port3 ... -""" - - parser = optparse.OptionParser(usage) - - help = "Timeout in seconds." - parser.add_option('-t', '--timeout', type='float', help=help, default=5.0) - - options, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses), options - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred, timeout): - self.deferred = deferred - self.timeout = timeout - self.timeout_call = None - - def startedConnecting(self, connector): - from twisted.internet import reactor - self.timeout_call = reactor.callLater(self.timeout, - self.on_timeout, - connector) - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - self.cancel_timeout() - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - self.cancel_timeout() - - def on_timeout(self, connector): - self.timeout_call = None - - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(TimeoutError()) - connector.disconnect() - - def cancel_timeout(self): - if self.timeout_call is not None: - call, self.timeout_call = self.timeout_call, None - call.cancel() - - -def get_poetry(host, port, timeout): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - - If timeout seconds elapse before the poem is received, the - Deferred will fire with a TimeoutError. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d, timeout) - reactor.connectTCP(host, port, factory) - return d - - -def poetry_main(): - addresses, options = parse_args() - - from twisted.internet import reactor - - poems = [] - errors = [] - - def got_poem(poem): - poems.append(poem) - - def poem_failed(err): - print >>sys.stderr, 'Poem failed:', err - errors.append(err) - - def poem_done(_): - if len(poems) + len(errors) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - d = get_poetry(host, port, options.timeout) - d.addCallbacks(got_poem, poem_failed) - d.addBoth(poem_done) - - reactor.run() - - for poem in poems: - print poem - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/tests/test_poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/tests/test_poetry.py deleted file mode 100644 index 3185bec..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/tests/test_poetry.py +++ /dev/null @@ -1,95 +0,0 @@ -from twisted.internet.defer import Deferred -from twisted.internet.error import ConnectError -from twisted.internet.protocol import ClientFactory, ServerFactory, Protocol -from twisted.trial.unittest import TestCase - -# Normally we would import the classes we want to test. -# But to make the examples self-contained, we're just -# copying them here, with a few modifications. - -class PoetryServerProtocol(Protocol): - - def connectionMade(self): - self.transport.write(self.factory.poem) - self.transport.loseConnection() - -class PoetryServerFactory(ServerFactory): - - protocol = PoetryServerProtocol - - def __init__(self, poem): - self.poem = poem - - -class PoetryClientProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryClientProtocol - - def __init__(self): - self.deferred = Deferred() - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -def get_poetry(host, port): - from twisted.internet import reactor - factory = PoetryClientFactory() - reactor.connectTCP(host, port, factory) - return factory.deferred - - -TEST_POEM = '''\ -This is a test. -This is only a test.''' - - -class PoetryTestCase(TestCase): - - def setUp(self): - factory = PoetryServerFactory(TEST_POEM) - from twisted.internet import reactor - self.port = reactor.listenTCP(0, factory, interface="127.0.0.1") - self.portnum = self.port.getHost().port - - def tearDown(self): - port, self.port = self.port, None - return port.stopListening() - - def test_client(self): - """The correct poem is returned by get_poetry.""" - d = get_poetry('127.0.0.1', self.portnum) - - def got_poem(poem): - self.assertEquals(poem, TEST_POEM) - - d.addCallback(got_poem) - - return d - - def test_failure(self): - """The correct failure is returned by get_poetry when - connecting to a port with no server.""" - d = get_poetry('127.0.0.1', 0) - return self.assertFailure(d, ConnectError) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-1/get-poetry-broken.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-1/get-poetry-broken.py deleted file mode 100644 index d4e6096..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-1/get-poetry-broken.py +++ /dev/null @@ -1,134 +0,0 @@ -# This is the *Broken* Twisted Get Poetry Now! client, version 1.0. - -# NOTE: This should not be used as the basis for production code. -# It uses low-level Twisted APIs as a learning exercise. - -# Also, it's totally broken. See the explanation in Part 4 -# to understand why. - -import datetime, optparse, socket - -from twisted.internet import main - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the *Broken* Get Poetry Now! client, Twisted version 1.0. -Run it like this: - - python get-poetry-broken.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-1/get-poetry-broken.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetrySocket(object): - - poem = '' - - def __init__(self, task_num, address): - self.task_num = task_num - self.address = address - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.connect(address) - #self.sock.setblocking(0) we don't set non-blocking -- broken! - - # tell the Twisted reactor to monitor this socket for reading - from twisted.internet import reactor - reactor.addReader(self) - - def fileno(self): - try: - return self.sock.fileno() - except socket.error: - return -1 - - def connectionLost(self, reason): - self.sock.close() - - # stop monitoring this socket - from twisted.internet import reactor - reactor.removeReader(self) - - # see if there are any poetry sockets left - for reader in reactor.getReaders(): - if isinstance(reader, PoetrySocket): - return - - reactor.stop() # no more poetry - - def doRead(self): - poem = '' - - while True: # we're just reading everything (blocking) -- broken! - bytes = self.sock.recv(1024) - if not bytes: - break - poem += bytes - - msg = 'Task %d: got %d bytes of poetry from %s' - print msg % (self.task_num, len(poem), self.format_addr()) - - self.poem = poem - - return main.CONNECTION_DONE - - def logPrefix(self): - return 'poetry' - - def format_addr(self): - host, port = self.address - return '%s:%s' % (host or '127.0.0.1', port) - - -def poetry_main(): - addresses = parse_args() - - start = datetime.datetime.now() - - sockets = [PoetrySocket(i + 1, addr) for i, addr in enumerate(addresses)] - - from twisted.internet import reactor - reactor.run() - - elapsed = datetime.datetime.now() - start - - for i, sock in enumerate(sockets): - print 'Task %d: %d bytes of poetry' % (i + 1, len(sock.poem)) - - print 'Got %d poems in %s' % (len(addresses), elapsed) - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-1/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-1/get-poetry.py deleted file mode 100644 index ab5c79d..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-1/get-poetry.py +++ /dev/null @@ -1,139 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 1.0. - -# NOTE: This should not be used as the basis for production code. -# It uses low-level Twisted APIs as a learning exercise. - -import datetime, errno, optparse, socket - -from twisted.internet import main - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 1.0. -Run it like this: - - python get-poetry.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-1/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetrySocket(object): - - poem = '' - - def __init__(self, task_num, address): - self.task_num = task_num - self.address = address - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.connect(address) - self.sock.setblocking(0) - - # tell the Twisted reactor to monitor this socket for reading - from twisted.internet import reactor - reactor.addReader(self) - - def fileno(self): - try: - return self.sock.fileno() - except socket.error: - return -1 - - def connectionLost(self, reason): - self.sock.close() - - # stop monitoring this socket - from twisted.internet import reactor - reactor.removeReader(self) - - # see if there are any poetry sockets left - for reader in reactor.getReaders(): - if isinstance(reader, PoetrySocket): - return - - reactor.stop() # no more poetry - - def doRead(self): - bytes = '' - - while True: - try: - bytesread = self.sock.recv(1024) - if not bytesread: - break - else: - bytes += bytesread - except socket.error, e: - if e.args[0] == errno.EWOULDBLOCK: - break - return main.CONNECTION_LOST - - if not bytes: - print 'Task %d finished' % self.task_num - return main.CONNECTION_DONE - else: - msg = 'Task %d: got %d bytes of poetry from %s' - print msg % (self.task_num, len(bytes), self.format_addr()) - - self.poem += bytes - - def logPrefix(self): - return 'poetry' - - def format_addr(self): - host, port = self.address - return '%s:%s' % (host or '127.0.0.1', port) - - -def poetry_main(): - addresses = parse_args() - - start = datetime.datetime.now() - - sockets = [PoetrySocket(i + 1, addr) for i, addr in enumerate(addresses)] - - from twisted.internet import reactor - reactor.run() - - elapsed = datetime.datetime.now() - start - - for i, sock in enumerate(sockets): - print 'Task %d: %d bytes of poetry' % (i + 1, len(sock.poem)) - - print 'Got %d poems in %s' % (len(addresses), elapsed) - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry-simple.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry-simple.py deleted file mode 100644 index 77cad68..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry-simple.py +++ /dev/null @@ -1,109 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 2.1. - -# NOTE: This should not be used as the basis for production code. - -import optparse - -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 2.1. -Run it like this: - - python get-poetry-simple.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-2/get-poetry-simple.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol # tell base class what proto to build - - def __init__(self, poetry_count): - self.poetry_count = poetry_count - self.poems = [] - - def poem_finished(self, poem=None): - if poem is not None: - self.poems.append(poem) - - self.poetry_count -= 1 - - if self.poetry_count == 0: - self.report() - from twisted.internet import reactor - reactor.stop() - - def report(self): - for poem in self.poems: - print poem - - def clientConnectionFailed(self, connector, reason): - print 'Failed to connect to:', connector.getDestination() - self.poem_finished() - - -def poetry_main(): - addresses = parse_args() - - factory = PoetryClientFactory(len(addresses)) - - from twisted.internet import reactor - - for address in addresses: - host, port = address - reactor.connectTCP(host, port, factory) - - reactor.run() - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry-stack.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry-stack.py deleted file mode 100644 index 6d2b5b5..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry-stack.py +++ /dev/null @@ -1,123 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 2.0, with stacktrace. - -# NOTE: This should not be used as the basis for production code. - -import datetime, optparse, os, traceback - -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 2.0, with stacktrace. -Run it like this: - - python get-poetry-stack.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-2/get-poetry-stack.py 10001 10002 10003 - -But it's just going to print out a stacktrace as soon as it -gets the first bits of a poem. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - task_num = 0 - - def dataReceived(self, data): - traceback.print_stack() - os._exit(0) - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(self.task_num, poem) - - -class PoetryClientFactory(ClientFactory): - - task_num = 1 - - protocol = PoetryProtocol # tell base class what proto to build - - def __init__(self, poetry_count): - self.poetry_count = poetry_count - self.poems = {} # task num -> poem - - def buildProtocol(self, address): - proto = ClientFactory.buildProtocol(self, address) - proto.task_num = self.task_num - self.task_num += 1 - return proto - - def poem_finished(self, task_num=None, poem=None): - if task_num is not None: - self.poems[task_num] = poem - - self.poetry_count -= 1 - - if self.poetry_count == 0: - self.report() - from twisted.internet import reactor - reactor.stop() - - def report(self): - for i in self.poems: - print 'Task %d: %d bytes of poetry' % (i, len(self.poems[i])) - - def clientConnectionFailed(self, connector, reason): - print 'Failed to connect to:', connector.getDestination() - self.poem_finished() - - -def poetry_main(): - addresses = parse_args() - - start = datetime.datetime.now() - - factory = PoetryClientFactory(len(addresses)) - - from twisted.internet import reactor - - for address in addresses: - host, port = address - reactor.connectTCP(host, port, factory) - - reactor.run() - - elapsed = datetime.datetime.now() - start - - print 'Got %d poems in %s' % (len(addresses), elapsed) - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry.py deleted file mode 100644 index 570d3b6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-2/get-poetry.py +++ /dev/null @@ -1,126 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 2.0. - -# NOTE: This should not be used as the basis for production code. - -import datetime, optparse - -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 2.0. -Run it like this: - - python get-poetry.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-2/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - task_num = 0 - - def dataReceived(self, data): - self.poem += data - msg = 'Task %d: got %d bytes of poetry from %s' - print msg % (self.task_num, len(data), self.transport.getPeer()) - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(self.task_num, poem) - - -class PoetryClientFactory(ClientFactory): - - task_num = 1 - - protocol = PoetryProtocol # tell base class what proto to build - - def __init__(self, poetry_count): - self.poetry_count = poetry_count - self.poems = {} # task num -> poem - - def buildProtocol(self, address): - proto = ClientFactory.buildProtocol(self, address) - proto.task_num = self.task_num - self.task_num += 1 - return proto - - def poem_finished(self, task_num=None, poem=None): - if task_num is not None: - self.poems[task_num] = poem - - self.poetry_count -= 1 - - if self.poetry_count == 0: - self.report() - from twisted.internet import reactor - reactor.stop() - - def report(self): - for i in self.poems: - print 'Task %d: %d bytes of poetry' % (i, len(self.poems[i])) - - def clientConnectionFailed(self, connector, reason): - print 'Failed to connect to:', connector.getDestination() - self.poem_finished() - - -def poetry_main(): - addresses = parse_args() - - start = datetime.datetime.now() - - factory = PoetryClientFactory(len(addresses)) - - from twisted.internet import reactor - - for address in addresses: - host, port = address - reactor.connectTCP(host, port, factory) - - reactor.run() - - elapsed = datetime.datetime.now() - start - - print 'Got %d poems in %s' % (len(addresses), elapsed) - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-3/get-poetry-1.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-3/get-poetry-1.py deleted file mode 100644 index 4487b2f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-3/get-poetry-1.py +++ /dev/null @@ -1,130 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 3.1. - -# NOTE: This should not be used as the basis for production code. - -import optparse, sys - -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 3.1 -Run it like this: - - python get-poetry-1.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-3/get-poetry-1.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, callback, errback): - self.callback = callback - self.errback = errback - - def poem_finished(self, poem): - self.callback(poem) - - def clientConnectionFailed(self, connector, reason): - self.errback(reason) - - -def get_poetry(host, port, callback, errback): - """ - Download a poem from the given host and port and invoke - - callback(poem) - - when the poem is complete. If there is a failure, invoke: - - errback(err) - - instead, where err is a twisted.python.failure.Failure instance. - """ - from twisted.internet import reactor - factory = PoetryClientFactory(callback, errback) - reactor.connectTCP(host, port, factory) - - -def poetry_main(): - addresses = parse_args() - - from twisted.internet import reactor - - poems = [] - errors = [] - - def got_poem(poem): - poems.append(poem) - poem_done() - - def poem_failed(err): - print >>sys.stderr, 'Poem failed:', err - errors.append(err) - poem_done() - - def poem_done(): - if len(poems) + len(errors) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - get_poetry(host, port, got_poem, poem_failed) - - reactor.run() - - for poem in poems: - print poem - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-3/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-3/get-poetry.py deleted file mode 100644 index 83f2238..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-3/get-poetry.py +++ /dev/null @@ -1,113 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 3.0. - -# NOTE: This should not be used as the basis for production code. - -import optparse - -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 3.0 -Run it like this: - - python get-poetry-1.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-3/get-poetry-1.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, callback): - self.callback = callback - - def poem_finished(self, poem): - self.callback(poem) - - -def get_poetry(host, port, callback): - """ - Download a poem from the given host and port and invoke - - callback(poem) - - when the poem is complete. - """ - from twisted.internet import reactor - factory = PoetryClientFactory(callback) - reactor.connectTCP(host, port, factory) - - -def poetry_main(): - addresses = parse_args() - - from twisted.internet import reactor - - poems = [] - - def got_poem(poem): - poems.append(poem) - if len(poems) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - get_poetry(host, port, got_poem) - - reactor.run() - - for poem in poems: - print poem - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-4/get-poetry-stack.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-4/get-poetry-stack.py deleted file mode 100644 index b6f67fa..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-4/get-poetry-stack.py +++ /dev/null @@ -1,129 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 4.0, with stacktrace. - -import optparse, os, sys, traceback - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 4.0, with stacktrace. -Run it like this: - - python get-poetry-stack.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-4/get-poetry-stack.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -But it's just going to print out a stacktrace as soon as it -gets the first poem. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -def get_poetry(host, port): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d) - reactor.connectTCP(host, port, factory) - return d - - -def poetry_main(): - addresses = parse_args() - - from twisted.internet import reactor - - poems = [] - errors = [] - - def got_poem(poem): - traceback.print_stack() - os._exit(0) - - def poem_failed(err): - print >>sys.stderr, 'Poem failed:', err - errors.append(err) - - def poem_done(_): - if len(poems) + len(errors) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - d = get_poetry(host, port) - d.addCallbacks(got_poem, poem_failed) - d.addBoth(poem_done) - - reactor.run() - - for poem in poems: - print poem - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-4/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-4/get-poetry.py deleted file mode 100644 index 4faa594..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-4/get-poetry.py +++ /dev/null @@ -1,128 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 4.0 - -import optparse, sys - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 4.0 -Run it like this: - - python get-poetry.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-4/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -def get_poetry(host, port): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d) - reactor.connectTCP(host, port, factory) - return d - - -def poetry_main(): - addresses = parse_args() - - from twisted.internet import reactor - - poems = [] - errors = [] - - def got_poem(poem): - poems.append(poem) - - def poem_failed(err): - print >>sys.stderr, 'Poem failed:', err - errors.append(err) - - def poem_done(_): - if len(poems) + len(errors) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - d = get_poetry(host, port) - d.addCallbacks(got_poem, poem_failed) - d.addBoth(poem_done) - - reactor.run() - - for poem in poems: - print poem - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-5/get-poetry-1.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-5/get-poetry-1.py deleted file mode 100644 index 09afbc7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-5/get-poetry-1.py +++ /dev/null @@ -1,160 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 5.1 - -import optparse, random, sys - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 5.1 -Run it like this: - - python get-poetry-1.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-5/get-poetry-1.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -def get_poetry(host, port): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d) - reactor.connectTCP(host, port, factory) - return d - - -class GibberishError(Exception): pass - -class CannotCummingsify(Exception): pass - -def cummingsify(poem): - """ - Randomly do one of the following: - - 1. Return a cummingsified version of the poem. - 2. Raise a GibberishError. - 3. Raise a CannotCummingsify error with the original poem - as the first argument. - """ - - def success(): - return poem.lower() - - def gibberish(): - raise GibberishError() - - def bug(): - raise CannotCummingsify(poem) - - return random.choice([success, gibberish, bug])() - - -def poetry_main(): - addresses = parse_args() - - from twisted.internet import reactor - - poems = [] - errors = [] - - def cummingsify_failed(err): - if err.check(CannotCummingsify): - print 'Cummingsify failed!' - return err.value.args[0] - return err - - def got_poem(poem): - print poem - poems.append(poem) - - def poem_failed(err): - print >>sys.stderr, 'The poem download failed.' - errors.append(err) - - def poem_done(_): - if len(poems) + len(errors) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - d = get_poetry(host, port) - d.addCallback(cummingsify) - d.addErrback(cummingsify_failed) - d.addCallbacks(got_poem, poem_failed) - d.addBoth(poem_done) - - reactor.run() - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-5/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-5/get-poetry.py deleted file mode 100644 index 99ed98f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-5/get-poetry.py +++ /dev/null @@ -1,159 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 5.0 - -import optparse, random, sys - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 5.0 -Run it like this: - - python get-poetry.py port1 port2 port3 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-5/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10001, 10002, and 10003. - -Of course, there need to be servers listening on those ports -for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if not addresses: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -def get_poetry(host, port): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d) - reactor.connectTCP(host, port, factory) - return d - - -class GibberishError(Exception): pass - -def cummingsify(poem): - """ - Randomly do one of the following: - - 1. Return a cummingsified version of the poem. - 2. Raise a GibberishError. - 3. Raise a ValueError. - """ - - def success(): - return poem.lower() - - def gibberish(): - raise GibberishError() - - def bug(): - raise ValueError() - - return random.choice([success, gibberish, bug])() - - -def poetry_main(): - addresses = parse_args() - - from twisted.internet import reactor - - poems = [] - errors = [] - - def try_to_cummingsify(poem): - try: - return cummingsify(poem) - except GibberishError: - raise - except: - print 'Cummingsify failed!' - return poem - - def got_poem(poem): - print poem - poems.append(poem) - - def poem_failed(err): - print >>sys.stderr, 'The poem download failed.' - errors.append(err) - - def poem_done(_): - if len(poems) + len(errors) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - d = get_poetry(host, port) - d.addCallback(try_to_cummingsify) - d.addCallbacks(got_poem, poem_failed) - d.addBoth(poem_done) - - reactor.run() - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-6/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-6/get-poetry.py deleted file mode 100644 index dd36fed..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-6/get-poetry.py +++ /dev/null @@ -1,195 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 6.0 - -import optparse, sys - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory -from twisted.protocols.basic import NetstringReceiver - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 6.0 -Run it like this: - - python get-poetry.py xform-port port1 port2 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-6/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10002, and 10003 and transform -it using the server on port 10001. - -Of course, there need to be appropriate servers listening on those -ports for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if len(addresses) < 2: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -class TransformClientProtocol(NetstringReceiver): - - def connectionMade(self): - self.sendRequest(self.factory.xform_name, self.factory.poem) - - def sendRequest(self, xform_name, poem): - self.sendString(xform_name + '.' + poem) - - def stringReceived(self, s): - self.transport.loseConnection() - self.poemReceived(s) - - def poemReceived(self, poem): - self.factory.handlePoem(poem) - - -class TransformClientFactory(ClientFactory): - - protocol = TransformClientProtocol - - def __init__(self, xform_name, poem): - self.xform_name = xform_name - self.poem = poem - self.deferred = defer.Deferred() - - def handlePoem(self, poem): - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionLost(self, _, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - clientConnectionFailed = clientConnectionLost - - -class TransformProxy(object): - """ - I proxy requests to a transformation service. - """ - - def __init__(self, host, port): - self.host = host - self.port = port - - def xform(self, xform_name, poem): - factory = TransformClientFactory(xform_name, poem) - from twisted.internet import reactor - reactor.connectTCP(self.host, self.port, factory) - return factory.deferred - - -def get_poetry(host, port): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d) - reactor.connectTCP(host, port, factory) - return d - - -def poetry_main(): - addresses = parse_args() - - xform_addr = addresses.pop(0) - - proxy = TransformProxy(*xform_addr) - - from twisted.internet import reactor - - poems = [] - errors = [] - - def try_to_cummingsify(poem): - d = proxy.xform('cummingsify', poem) - - def fail(err): - print >>sys.stderr, 'Cummingsify failed!' - return poem - - return d.addErrback(fail) - - def got_poem(poem): - print poem - poems.append(poem) - - def poem_failed(err): - print >>sys.stderr, 'The poem download failed.' - errors.append(err) - - def poem_done(_): - if len(poems) + len(errors) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - d = get_poetry(host, port) - d.addCallback(try_to_cummingsify) - d.addCallbacks(got_poem, poem_failed) - d.addBoth(poem_done) - - reactor.run() - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-7/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-7/get-poetry.py deleted file mode 100644 index baaa711..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-7/get-poetry.py +++ /dev/null @@ -1,195 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 7.0 - -import optparse, sys - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory -from twisted.protocols.basic import NetstringReceiver - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 7.0 -Run it like this: - - python get-poetry.py xform-port port1 port2 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-6/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10002, and 10003 and transform -it using the server on port 10001. - -Of course, there need to be appropriate servers listening on those -ports for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if len(addresses) < 2: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -class TransformClientProtocol(NetstringReceiver): - - def connectionMade(self): - self.sendRequest(self.factory.xform_name, self.factory.poem) - - def sendRequest(self, xform_name, poem): - self.sendString(xform_name + '.' + poem) - - def stringReceived(self, s): - self.transport.loseConnection() - self.poemReceived(s) - - def poemReceived(self, poem): - self.factory.handlePoem(poem) - - -class TransformClientFactory(ClientFactory): - - protocol = TransformClientProtocol - - def __init__(self, xform_name, poem): - self.xform_name = xform_name - self.poem = poem - self.deferred = defer.Deferred() - - def handlePoem(self, poem): - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionLost(self, _, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - clientConnectionFailed = clientConnectionLost - - -class TransformProxy(object): - """ - I proxy requests to a transformation service. - """ - - def __init__(self, host, port): - self.host = host - self.port = port - - def xform(self, xform_name, poem): - factory = TransformClientFactory(xform_name, poem) - from twisted.internet import reactor - reactor.connectTCP(self.host, self.port, factory) - return factory.deferred - - -def get_poetry(host, port): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d) - reactor.connectTCP(host, port, factory) - return d - - -def poetry_main(): - addresses = parse_args() - - xform_addr = addresses.pop(0) - - proxy = TransformProxy(*xform_addr) - - from twisted.internet import reactor - - results = [] - - @defer.inlineCallbacks - def get_transformed_poem(host, port): - try: - poem = yield get_poetry(host, port) - except Exception, e: - print >>sys.stderr, 'The poem download failed:', e - raise - - try: - poem = yield proxy.xform('cummingsify', poem) - except Exception: - print >>sys.stderr, 'Cummingsify failed!' - - defer.returnValue(poem) - - def got_poem(poem): - print poem - - def poem_done(_): - results.append(_) - if len(results) == len(addresses): - reactor.stop() - - for address in addresses: - host, port = address - d = get_transformed_poem(host, port) - d.addCallbacks(got_poem) - d.addBoth(poem_done) - - reactor.run() - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-8/get-poetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-8/get-poetry.py deleted file mode 100644 index 45aecd6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-client-8/get-poetry.py +++ /dev/null @@ -1,192 +0,0 @@ -# This is the Twisted Get Poetry Now! client, version 8.0 - -import optparse, sys - -from twisted.internet import defer -from twisted.internet.protocol import Protocol, ClientFactory -from twisted.protocols.basic import NetstringReceiver - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port ... - -This is the Get Poetry Now! client, Twisted version 8.0 -Run it like this: - - python get-poetry.py xform-port port1 port2 ... - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-client-6/get-poetry.py 10001 10002 10003 - -to grab poetry from servers on ports 10002, and 10003 and transform -it using the server on port 10001. - -Of course, there need to be appropriate servers listening on those -ports for that to work. -""" - - parser = optparse.OptionParser(usage) - - _, addresses = parser.parse_args() - - if len(addresses) < 2: - print parser.format_help() - parser.exit() - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return map(parse_address, addresses) - - -class PoetryProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -class TransformClientProtocol(NetstringReceiver): - - def connectionMade(self): - self.sendRequest(self.factory.xform_name, self.factory.poem) - - def sendRequest(self, xform_name, poem): - self.sendString(xform_name + '.' + poem) - - def stringReceived(self, s): - self.transport.loseConnection() - self.poemReceived(s) - - def poemReceived(self, poem): - self.factory.handlePoem(poem) - - -class TransformClientFactory(ClientFactory): - - protocol = TransformClientProtocol - - def __init__(self, xform_name, poem): - self.xform_name = xform_name - self.poem = poem - self.deferred = defer.Deferred() - - def handlePoem(self, poem): - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionLost(self, _, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - clientConnectionFailed = clientConnectionLost - - -class TransformProxy(object): - """ - I proxy requests to a transformation service. - """ - - def __init__(self, host, port): - self.host = host - self.port = port - - def xform(self, xform_name, poem): - factory = TransformClientFactory(xform_name, poem) - from twisted.internet import reactor - reactor.connectTCP(self.host, self.port, factory) - return factory.deferred - - -def get_poetry(host, port): - """ - Download a poem from the given host and port. This function - returns a Deferred which will be fired with the complete text of - the poem or a Failure if the poem could not be downloaded. - """ - d = defer.Deferred() - from twisted.internet import reactor - factory = PoetryClientFactory(d) - reactor.connectTCP(host, port, factory) - return d - - -def poetry_main(): - addresses = parse_args() - - xform_addr = addresses.pop(0) - - proxy = TransformProxy(*xform_addr) - - from twisted.internet import reactor - - @defer.inlineCallbacks - def get_transformed_poem(host, port): - try: - poem = yield get_poetry(host, port) - except Exception, e: - print >>sys.stderr, 'The poem download failed:', e - raise - - try: - poem = yield proxy.xform('cummingsify', poem) - except Exception: - print >>sys.stderr, 'Cummingsify failed!' - - defer.returnValue(poem) - - def got_poem(poem): - print poem - - ds = [] - - for (host, port) in addresses: - d = get_transformed_poem(host, port) - d.addCallbacks(got_poem) - ds.append(d) - - dlist = defer.DeferredList(ds, consumeErrors=True) - dlist.addCallback(lambda res : reactor.stop()) - - reactor.run() - - -if __name__ == '__main__': - poetry_main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-1.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-1.py deleted file mode 100644 index 441893c..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-1.py +++ /dev/null @@ -1,18 +0,0 @@ -from twisted.internet.defer import Deferred - -def got_poem(res): - print 'Your poem is served:' - print res - -def poem_failed(err): - print 'No poetry for you.' - -d = Deferred() - -# add a callback/errback pair to the chain -d.addCallbacks(got_poem, poem_failed) - -# fire the chain with a normal result -d.callback('This poem is short.') - -print "Finished" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-10.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-10.py deleted file mode 100644 index 4987159..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-10.py +++ /dev/null @@ -1,102 +0,0 @@ -from twisted.internet.defer import Deferred - -print """ -This example illustrates how callbacks in a deferred -chain can return deferreds themselves. -""" - -# three simple callbacks - -def callback_1(res): - print 'callback_1 got', res - return 1 - -def callback_2(res): - print 'callback_2 got', res - return 2 - -def callback_3(res): - print 'callback_3 got', res - return 3 - - -# We add them all to a deferred and fire it: - -d = Deferred() - -d.addCallback(callback_1) -d.addCallback(callback_2) -d.addCallback(callback_3) - -print """ -Here we are firing a deferred with three callbacks that just print -their argument and return simple values: -""" - -d.callback(0) - -# And you get output like this: -# callback_1 got 0 -# callback_2 got 1 -# callback_3 got 2 - - -# Now we make a callback that returns a deferred: - -deferred_2 = None # NOTE: because we aren't using a reactor, we have - # to fire this deferred from the 'outside'. - # We store it in a global variable for this - # purpose. In a normal Twisted program you - # would never store a deferred in a global or - # fire it from the outside. By 'outside' we - # mean the deferred is not being fired by an - # action set in motion by the callback that - # created and returned the deferred, as is - # normally the case. - -def callback_2_async(res): - print 'callback_2 got', res - global deferred_2 # never do this in a real program - deferred_2 = Deferred() - return deferred_2 - - -# We do the same thing, but use the async callback: - -d = Deferred() - -d.addCallback(callback_1) -d.addCallback(callback_2_async) -d.addCallback(callback_3) - -print """ -Here we are firing a deferred as above but the middle callback is -returning a deferred: -""" - -d.callback(0) - -# And you get output like this: -# callback_1 got 0 -# callback_2 got 1 - -print """ -Notice the output from the third callback is missing. That's because -the second callback returned a deferred and now the 'outer' deferred -is paused. It's not waiting in a thread or anything like that, it just -stopped invoking the callbacks in the chain. Instead, it registered -some callbacks on the 'inner' deferred which will start the outer -deferred back up when the inner deferred is fired. - -We can see this in action by firing the inner deferred: -""" - -deferred_2.callback(2) - -# And you get output like this: -# callback_3 got 2 - -print """ -Note the argument to the inner deferred's callback() method became -the result passed to the next callback in the outer deferred. -""" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-11.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-11.py deleted file mode 100644 index 78b5766..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-11.py +++ /dev/null @@ -1,63 +0,0 @@ -from twisted.internet.defer import Deferred - -print """\ -This example illustrates how deferreds can -be fired before they are returned. First we -make a new deferred, fire it, then add some -callbacks. -""" - -# three simple callbacks - -def callback_1(res): - print 'callback_1 got', res - return 1 - -def callback_2(res): - print 'callback_2 got', res - return 2 - -def callback_3(res): - print 'callback_3 got', res - return 3 - -# We create a deferred and fire it immediately: -d = Deferred() - -print 'Firing empty deferred.' -d.callback(0) - -# Now we add the callbacks to the deferred. -# Notice how each callback fires immediately. - -print 'Adding first callback.' -d.addCallback(callback_1) - -print 'Adding second callback.' -d.addCallback(callback_2) - -print 'Adding third callback.' -d.addCallback(callback_3) - -print""" -Because the deferred was already fired, it -invoked each callback as soon as it was added. - -Now we create a deferred and fire it, but -pause it first with the pause() method. -""" - -# We do the same thing, but pause the deferred: - -d = Deferred() -print 'Pausing, then firing deferred.' -d.pause() -d.callback(0) - -print 'Adding callbacks.' -d.addCallback(callback_1) -d.addCallback(callback_2) -d.addCallback(callback_3) - -print 'Unpausing the deferred.' -d.unpause() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-2.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-2.py deleted file mode 100644 index d2110bd..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-2.py +++ /dev/null @@ -1,19 +0,0 @@ -from twisted.internet.defer import Deferred -from twisted.python.failure import Failure - -def got_poem(res): - print 'Your poem is served:' - print res - -def poem_failed(err): - print 'No poetry for you.' - -d = Deferred() - -# add a callback/errback pair to the chain -d.addCallbacks(got_poem, poem_failed) - -# fire the chain with an error result -d.errback(Failure(Exception('I have failed.'))) - -print "Finished" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-3.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-3.py deleted file mode 100644 index aff77a7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-3.py +++ /dev/null @@ -1,18 +0,0 @@ -from twisted.internet.defer import Deferred - -def got_poem(res): - print 'Your poem is served:' - print res - -def poem_failed(err): - print err.__class__ - print err - print 'No poetry for you.' - -d = Deferred() - -# add a callback/errback pair to the chain -d.addCallbacks(got_poem, poem_failed) - -# fire the chain with an error result -d.errback(Exception('I have failed.')) diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-4.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-4.py deleted file mode 100644 index 73b4b16..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-4.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.internet.defer import Deferred -def out(s): print s -d = Deferred() -d.addCallbacks(out, out) -d.callback('First result') -d.callback('Second result') -print 'Finished' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-5.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-5.py deleted file mode 100644 index c6377b6..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-5.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.internet.defer import Deferred -def out(s): print s -d = Deferred() -d.addCallbacks(out, out) -d.callback('First result') -d.errback(Exception('First error')) -print 'Finished' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-6.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-6.py deleted file mode 100644 index 99d1dcf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-6.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.internet.defer import Deferred -def out(s): print s -d = Deferred() -d.addCallbacks(out, out) -d.errback(Exception('First error')) -d.errback(Exception('Second error')) -print 'Finished' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-7.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-7.py deleted file mode 100644 index ee801b9..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-7.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.internet.defer import Deferred -def out(s): print s -d = Deferred() -d.addCallbacks(out, out) -d.errback(Exception('First error')) -d.callback('First result') -print 'Finished' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-8.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-8.py deleted file mode 100644 index 121fbf2..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-8.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys - -from twisted.internet.defer import Deferred - -def got_poem(poem): - print poem - from twisted.internet import reactor - reactor.stop() - -def poem_failed(err): - print >>sys.stderr, 'poem download failed' - print >>sys.stderr, 'I am terribly sorry' - print >>sys.stderr, 'try again later?' - from twisted.internet import reactor - reactor.stop() - -d = Deferred() - -d.addCallbacks(got_poem, poem_failed) - -from twisted.internet import reactor - -reactor.callWhenRunning(d.callback, 'Another short poem.') - -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-9.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-9.py deleted file mode 100644 index 17f738b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-9.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys - -from twisted.internet.defer import Deferred - -def got_poem(poem): - print poem - -def poem_failed(err): - print >>sys.stderr, 'poem download failed' - print >>sys.stderr, 'I am terribly sorry' - print >>sys.stderr, 'try again later?' - -def poem_done(_): - from twisted.internet import reactor - reactor.stop() - -d = Deferred() - -d.addCallbacks(got_poem, poem_failed) -d.addBoth(poem_done) - -from twisted.internet import reactor - -reactor.callWhenRunning(d.callback, 'Another short poem.') - -reactor.run() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-block.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-block.py deleted file mode 100644 index 421d652..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-block.py +++ /dev/null @@ -1,53 +0,0 @@ -import sys, time - -from twisted.internet.defer import Deferred - -def start_chain(_): - print "The start of the callback chain." - -def blocking_poem(_): - def delayed_write(s, delay): - time.sleep(delay) - sys.stdout.write(s) - sys.stdout.flush() - - delayed_write('\n', 0) - delayed_write('I', .6) - delayed_write(' block', .4) - delayed_write('\n and', 1) - delayed_write(' the', .4) - delayed_write(' deferred', .6) - delayed_write('\n blocks', 1.5) - delayed_write(' with', .2) - delayed_write(' me', .2) - delayed_write('\nas does', 1) - delayed_write('\n the reactor', .6) - delayed_write('\nkeep that', 1) - delayed_write('\n factor', .6) - delayed_write('\nin', 1) - delayed_write(' mind', .4) - delayed_write('\n\n', 2) - -def end_chain(_): - print "The end of the callback chain." - from twisted.internet import reactor - reactor.stop() - -d = Deferred() - -d.addCallback(start_chain) -d.addCallback(blocking_poem) -d.addCallback(end_chain) - -def fire(): - print 'Firing deferred.' - d.callback(True) - print 'Firing finished.' - -from twisted.internet import reactor - -reactor.callWhenRunning(fire) - -print 'Starting reactor.' -reactor.run() -print 'Done.' diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-unhandled.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-unhandled.py deleted file mode 100644 index 83d9d6b..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/defer-unhandled.py +++ /dev/null @@ -1,12 +0,0 @@ -from twisted.internet.defer import Deferred - -def callback(res): - raise Exception('oops') - -d = Deferred() - -d.addCallback(callback) - -d.callback('Here is your result.') - -print "Finished" diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/deferred-simulator.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/deferred-simulator.py deleted file mode 100644 index a61b697..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-deferred/deferred-simulator.py +++ /dev/null @@ -1,444 +0,0 @@ -#!/usr/bin/env python - -import optparse, sys - -from twisted.internet import defer -from twisted.python.failure import Failure - -__doc__ = """\ -usage: %prog -A Deferred simulator. Use this to see how a particular -set of callbacks and errbacks will fire in a deferred.\ -""" - -class BadInput(Exception): pass - - -def parse_args(): - parser = optparse.OptionParser(usage=__doc__) - - help = "draw all three chains in one column" - parser.add_option('--narrow', action='store_true', help=help) - - options, args = parser.parse_args() - - if args: - parser.error('No arguments supported.') - - return options - - -class Screen(object): - """An ascii screen.""" - - def __init__(self): - self.pixels = {} # (x, y) -> char - - def draw_char(self, x, y, char): - self.pixels[x,y] = char - - def draw_horiz_line(self, x, y, width): - for i in range(width): - self.draw_char(x + i, y, '-') - - def draw_vert_line(self, x, y, height, end_arrow=False): - for i in range(height): - self.draw_char(x, y + i, '|') - if end_arrow: - self.draw_char(x - 1, y + height - 1, '\\') - self.draw_char(x + 1, y + height - 1, '/') - - def draw_text(self, x, y, text): - for i, char in enumerate(text): - self.draw_char(x + i, y, char) - - def clear(self): - self.pixels.clear() - - def __str__(self): - width = max([p[0] + 1 for p in self.pixels] + [0]) - height = max([p[1] + 1 for p in self.pixels] + [0]) - - s = '' - - for y in range(height): - for x in range(width): - s += self.pixels.get((x,y), ' ') - s += '\n' - - return s - - -class Callback(object): - """ - A widget representing a single callback or errback. - - Each callback widget has one of three styles: - - return - a callback that returns a given value - fail - a callback that raises an Exception(value) - passthru - a callback that returns its argument unchanged - - The widget is also a callable that behaves according - to the widget's style. - """ - - height = 5 - - def __init__(self, style, value=None): - self.style = style - self.value = value - self.min_width = len('0123456*') + len('return ') + 3 - - def __call__(self, res): - if self.style == 'return': - return self.value - if self.style == 'fail': - return Failure(Exception(self.value)) - return res - - @property - def caption(self): - if self.style == 'passthru': - return 'passthru' - return self.style + ' ' + self.value - - def format_value(self, res): - if isinstance(res, Failure): - return res.value.args[0] + '*' - return res - - def draw_passive(self, screen, x, y, width): - self.draw_box(screen, x, y, width) - self.draw_text(screen, x, y + 2, width, self.caption) - - def draw_active(self, screen, x, y, width, res): - self.draw_box(screen, x, y, width) - self.draw_text(screen, x, y + 1, width, self.format_value(res)) - self.draw_text(screen, x, y + 3, width, self.format_value(self(res))) - - def draw_box(self, screen, x, y, width): - screen.draw_horiz_line(x, y, width) - screen.draw_horiz_line(x, y + 4, width) - screen.draw_vert_line(x, y + 1, 3) - screen.draw_vert_line(x + width - 1, y + 1, 3) - - def draw_text(self, screen, x, y, width, text): - screen.draw_text(x + 1, y, text.center(width - 2)) - - -class Deferred(object): - """ - An widget for a deferred. - - It is initialize with a non-empty list of Callback pairs, - representing a callback chain in a Twisted Deferred. - """ - - def __init__(self, pairs): - assert pairs - self.pairs = pairs - self.callback_width = max([p[0].min_width for p in self.pairs] + [0]) - self.callback_width = max([p[1].min_width for p in self.pairs] - + [self.callback_width]) - self.width = self.callback_width * 2 + 2 - self.height = Callback.height * len(self.pairs) - self.height += 3 * len(self.pairs[1:]) - - def draw(self, screen, x, y): - """ - Draw a representation of the callback/errback chain - on the given screen at the given coordinates. - """ - for callback, errback in self.pairs: - callback.draw_passive(screen, x, y, self.callback_width) - errback.draw_passive(screen, x + self.callback_width + 2, - y, self.callback_width) - y += Callback.height + 3 - - -class FiredDeferred(object): - """ - A widget for a fired deferred. - - It is initialized with a Deferred widget (not a real deferred) - and the method name ('callback' or 'errback') to draw the firing - sequence for. - """ - - callback_y_offset = 4 - - def __init__(self, deferred, method): - self.deferred = deferred - self.method = method - self.height = deferred.height + 8 - self.width = deferred.width - - def draw(self, screen, x, y, result='initial'): - d = self.make_drawing_deferred(screen, x, y) - - if self.method == 'callback': - d.callback(result) - else: - d.errback(Exception(result)) - - def make_drawing_deferred(self, screen, x, y): - """ - Return a new deferred that, when fired, will draw its - firing sequence onto the given screen at the given coordinates. - """ - - callback_width = self.deferred.callback_width - - callback_mid_x = x - 1 + callback_width / 2 - - errback_left_x = x + callback_width + 2 - errback_mid_x = errback_left_x - 1 + callback_width / 2 - - class DrawState(object): - last_x = None - last_y = None - - state = DrawState() - - def draw_connection(x): - if state.last_x == x: - screen.draw_vert_line(x - 1 + callback_width / 2, - state.last_y - 3, 3, True) - return - - if state.last_x < x: - screen.draw_vert_line(callback_mid_x, state.last_y - 3, 2) - screen.draw_vert_line(errback_mid_x, - state.last_y - 2, 2, True) - else: - screen.draw_vert_line(errback_mid_x, state.last_y - 3, 2) - screen.draw_vert_line(callback_mid_x, - state.last_y - 2, 2, True) - - screen.draw_horiz_line(callback_mid_x + 1, - state.last_y - 2, - errback_mid_x - callback_mid_x - 1) - - def wrap_callback(cb, x): - def callback(res): - cb.draw_active(screen, x, state.last_y, callback_width, res) - draw_connection(x) - state.last_x = x - state.last_y += cb.height + 3 - return cb(res) - return callback - - def draw_value(res, y): - if isinstance(res, Failure): - text = res.value.args[0] + '*' - text = text.center(callback_width + 20) - screen.draw_text(errback_left_x - 10, y, text) - else: - screen.draw_text(x, y, res.center(callback_width)) - - def draw_start(res): - draw_value(res, y) - if isinstance(res, Failure): - state.last_x = errback_left_x - else: - state.last_x = x - state.last_y = y + 4 - return res - - def draw_end(res): - draw_value(res, state.last_y) - if isinstance(res, Failure): - draw_connection(errback_left_x) - else: - draw_connection(x) - - d = defer.Deferred() - - d.addBoth(draw_start) - - for pair in self.deferred.pairs: - callback = wrap_callback(pair[0], x) - errback = wrap_callback(pair[1], errback_left_x) - d.addCallbacks(callback, errback) - - d.addBoth(draw_end) - - return d - - -def get_next_pair(): - """Get the next callback/errback pair from the user.""" - - def get_cb(): - if not parts: - raise BadInput('missing command') - - cmd = parts.pop(0).lower() - - for command in ('return', 'fail', 'passthru'): - if command.startswith(cmd): - cmd = command - break - else: - raise BadInput('bad command: %s' % cmd) - - if cmd in ('return', 'fail'): - if not parts: - raise BadInput('missing argument') - - result = parts.pop(0) - - if len(result) > 6: - raise BadInput('result more than 6 chars long', result) - - return Callback(cmd, result) - else: - return Callback(cmd) - - try: - line = raw_input() - except EOFError: - sys.exit() - - if not line: - return None - - parts = line.strip().split() - - callback, errback = get_cb(), get_cb() - - if parts: - raise BadInput('extra arguments') - - return callback, errback - - -def get_pairs(): - """ - Get the list of callback/errback pairs from the user. - They are returned as Callback widgets. - """ - - print """\ -Enter a list of callback/errback pairs in the form: - - CALLBACK ERRBACK - -Where CALLBACK and ERRBACK are one of: - - return VALUE - fail VALUE - passthru - -And where VALUE is a string of only letters and numbers (no spaces), -no more than 6 characters long. - -Each pair should be on a single line and you can abbreviate -return/fail/passthru as r/f/p. - -Examples: - - r good f bad # callback returns 'good' - # and errback raises Exception('bad') - - f googly p # callback raises Exception('googly') - # and errback passes its failure along - -Enter a blank line when you are done, and a diagram of the deferred -will be printed next to the firing patterns for both the callback() -and errback() methods. In the diagram, a value followed by '*' is -really an Exception wrapped in a Failure, i.e: - - value* == Failure(Exception(value)) - -You will want to make your terminal as wide as possible. -""" - - pairs = [] - - while True: - try: - pair = get_next_pair() - except BadInput, e: - print 'ERROR:', e - continue - - if pair is None: - if not pairs: - print 'You must enter at least one pair.' - continue - else: - break - - pairs.append(pair) - - return pairs - - -def draw_single_column(d, callback, errback): - screen = Screen() - - screen.draw_text(0, 1, 'Deferred'.center(d.width)) - screen.draw_text(0, 2, '--------'.center(d.width)) - - d.draw(screen, 0, 4) - - print screen - - screen.clear() - - screen.draw_text(0, 2, 'd.callback(initial)'.center(d.width)) - screen.draw_text(0, 3, '-------------------'.center(d.width)) - - callback.draw(screen, 0, 5) - - print screen - - screen.clear() - - screen.draw_text(0, 2, 'd.errback(initial*)'.center(d.width)) - screen.draw_text(0, 3, '-------------------'.center(d.width)) - - errback.draw(screen, 0, 5) - - print screen - - -def draw_multi_column(d, callback, errback): - screen = Screen() - - screen.draw_text(0, 0, 'Deferred'.center(d.width)) - screen.draw_text(0, 1, '--------'.center(d.width)) - - screen.draw_text(d.width + 6, 0, 'd.callback(initial)'.center(d.width)) - screen.draw_text(d.width + 6, 1, '-------------------'.center(d.width)) - - screen.draw_text(2 * (d.width + 6), 0, 'd.errback(initial*)'.center(d.width)) - screen.draw_text(2 * (d.width + 6), 1, '-------------------'.center(d.width)) - - d.draw(screen, 0, callback.callback_y_offset + 3) - callback.draw(screen, d.width + 6, 3) - errback.draw(screen, 2 * (d.width + 6), 3) - - screen.draw_vert_line(d.width + 3, 3, callback.height) - screen.draw_vert_line(d.width + 3 + d.width + 6, 3, callback.height) - - print screen - - -def main(): - options = parse_args() - - d = Deferred(get_pairs()) - callback = FiredDeferred(d, 'callback') - errback = FiredDeferred(d, 'errback') - - if options.narrow: - draw_single_column(d, callback, errback) - else: - draw_multi_column(d, callback, errback) - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-failure/failure-examples.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-failure/failure-examples.py deleted file mode 100644 index 30a9386..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-failure/failure-examples.py +++ /dev/null @@ -1,40 +0,0 @@ -# This code illustrates a few aspects of Failures. -# Generally, Twisted makes Failures for us. - -from twisted.python.failure import Failure - -class RhymeSchemeViolation(Exception): pass - - -print 'Just making an exception:' -print - -e = RhymeSchemeViolation() - -failure = Failure(e) - -# Note this failure doesn't include any traceback info -print failure - -print -print - -print 'Catching an exception:' -print - -def analyze_poem(poem): - raise RhymeSchemeViolation() - -try: - analyze_poem("""\ -Roses are red. -Violets are violet. -That's why they're called Violets. -Duh. -""") -except: - failure = Failure() - - -# This failure saved both the exception and the traceback -print failure diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/fastpoetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/fastpoetry.py deleted file mode 100644 index 58f1483..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/fastpoetry.py +++ /dev/null @@ -1,78 +0,0 @@ -# This is the Twisted Fast Poetry Server, version 1.0 - -import optparse, os - -from twisted.internet.protocol import ServerFactory, Protocol - - -def parse_args(): - usage = """usage: %prog [options] poetry-file - -This is the Fast Poetry Server, Twisted edition. -Run it like this: - - python fastpoetry.py <path-to-poetry-file> - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-server-1/fastpoetry.py poetry/ecstasy.txt - -to serve up John Donne's Ecstasy, which I know you want to do. -""" - - parser = optparse.OptionParser(usage) - - help = "The port to listen on. Default to a random available port." - parser.add_option('--port', type='int', help=help) - - help = "The interface to listen on. Default is localhost." - parser.add_option('--iface', help=help, default='localhost') - - options, args = parser.parse_args() - - if len(args) != 1: - parser.error('Provide exactly one poetry file.') - - poetry_file = args[0] - - if not os.path.exists(args[0]): - parser.error('No such file: %s' % poetry_file) - - return options, poetry_file - - -class PoetryProtocol(Protocol): - - def connectionMade(self): - self.transport.write(self.factory.poem) - self.transport.loseConnection() - - -class PoetryFactory(ServerFactory): - - protocol = PoetryProtocol - - def __init__(self, poem): - self.poem = poem - - -def main(): - options, poetry_file = parse_args() - - poem = open(poetry_file).read() - - factory = PoetryFactory(poem) - - from twisted.internet import reactor - - port = reactor.listenTCP(options.port or 0, factory, - interface=options.iface) - - print 'Serving %s on %s.' % (poetry_file, port.getHost()) - - reactor.run() - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/poetry-proxy.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/poetry-proxy.py deleted file mode 100644 index 36d0c88..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/poetry-proxy.py +++ /dev/null @@ -1,143 +0,0 @@ -# This is the Twisted Poetry Proxy, version 1.0 - -import optparse - -from twisted.internet.defer import Deferred, maybeDeferred -from twisted.internet.protocol import ClientFactory, ServerFactory, Protocol - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port - -This is the Poetry Proxy, version 1.0. - - python poetry-proxy.py [hostname]:port - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-server-1/poetry-proxy.py 10000 - -to proxy the poem for the server running on port 10000. -""" - - parser = optparse.OptionParser(usage) - - help = "The port to listen on. Default to a random available port." - parser.add_option('--port', type='int', help=help) - - help = "The interface to listen on. Default is localhost." - parser.add_option('--iface', help=help, default='localhost') - - options, args = parser.parse_args() - - if len(args) != 1: - parser.error('Provide exactly one server address.') - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return options, parse_address(args[0]) - - -class PoetryProxyProtocol(Protocol): - - def connectionMade(self): - d = maybeDeferred(self.factory.service.get_poem) - d.addCallback(self.transport.write) - d.addBoth(lambda r: self.transport.loseConnection()) - - -class PoetryProxyFactory(ServerFactory): - - protocol = PoetryProxyProtocol - - def __init__(self, service): - self.service = service - - -class PoetryClientProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryClientProtocol - - def __init__(self): - self.deferred = Deferred() - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -class ProxyService(object): - - poem = None # the cached poem - - def __init__(self, host, port): - self.host = host - self.port = port - - def get_poem(self): - if self.poem is not None: - print 'Using cached poem.' - return self.poem - - print 'Fetching poem from server.' - factory = PoetryClientFactory() - factory.deferred.addCallback(self.set_poem) - from twisted.internet import reactor - reactor.connectTCP(self.host, self.port, factory) - return factory.deferred - - def set_poem(self, poem): - self.poem = poem - return poem - - -def main(): - options, server_addr = parse_args() - - service = ProxyService(*server_addr) - - factory = PoetryProxyFactory(service) - - from twisted.internet import reactor - - port = reactor.listenTCP(options.port or 0, factory, - interface=options.iface) - - print 'Proxying %s on %s.' % (server_addr, port.getHost()) - - reactor.run() - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/transform-test b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/transform-test deleted file mode 100755 index a0f2eea..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/transform-test +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -echo -n "27:cummingsify.HERE IS MY POEM," | netcat -q -1 localhost $1 -echo diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/transformedpoetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/transformedpoetry.py deleted file mode 100644 index e2ab7cf..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-1/transformedpoetry.py +++ /dev/null @@ -1,107 +0,0 @@ -# This is the Twisted Poetry Transform Server, version 1.0 - -import optparse - -from twisted.internet.protocol import ServerFactory -from twisted.protocols.basic import NetstringReceiver - - -def parse_args(): - usage = """usage: %prog [options] - -This is the Poetry Transform Server. -Run it like this: - - python transformedpoetry.py - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-server-1/transformedpoetry.py --port 11000 - -to provide poetry transformation on port 11000. -""" - - parser = optparse.OptionParser(usage) - - help = "The port to listen on. Default to a random available port." - parser.add_option('--port', type='int', help=help) - - help = "The interface to listen on. Default is localhost." - parser.add_option('--iface', help=help, default='localhost') - - options, args = parser.parse_args() - - if len(args) != 0: - parser.error('Bad arguments.') - - return options - - -class TransformService(object): - - def cummingsify(self, poem): - return poem.lower() - - -class TransformProtocol(NetstringReceiver): - - def stringReceived(self, request): - if '.' not in request: # bad request - self.transport.loseConnection() - return - - xform_name, poem = request.split('.', 1) - - self.xformRequestReceived(xform_name, poem) - - def xformRequestReceived(self, xform_name, poem): - new_poem = self.factory.transform(xform_name, poem) - - if new_poem is not None: - self.sendString(new_poem) - - self.transport.loseConnection() - - -class TransformFactory(ServerFactory): - - protocol = TransformProtocol - - def __init__(self, service): - self.service = service - - def transform(self, xform_name, poem): - thunk = getattr(self, 'xform_%s' % (xform_name,), None) - - if thunk is None: # no such transform - return None - - try: - return thunk(poem) - except: - return None # transform failed - - def xform_cummingsify(self, poem): - return self.service.cummingsify(poem) - - -def main(): - options = parse_args() - - service = TransformService() - - factory = TransformFactory(service) - - from twisted.internet import reactor - - port = reactor.listenTCP(options.port or 0, factory, - interface=options.iface) - - print 'Serving transforms on %s.' % (port.getHost(),) - - reactor.run() - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-2/poetry-proxy.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-2/poetry-proxy.py deleted file mode 100644 index dba9d89..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-2/poetry-proxy.py +++ /dev/null @@ -1,144 +0,0 @@ -# This is the Twisted Poetry Proxy, version 2.0 - -import optparse - -from twisted.internet.defer import Deferred, succeed -from twisted.internet.protocol import ClientFactory, ServerFactory, Protocol - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port - -This is the Poetry Proxy, version 2.0. - - python poetry-proxy.py [hostname]:port - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-server-2/poetry-proxy.py 10000 - -to proxy the poem for the server running on port 10000. -""" - - parser = optparse.OptionParser(usage) - - help = "The port to listen on. Default to a random available port." - parser.add_option('--port', type='int', help=help) - - help = "The interface to listen on. Default is localhost." - parser.add_option('--iface', help=help, default='localhost') - - options, args = parser.parse_args() - - if len(args) != 1: - parser.error('Provide exactly one server address.') - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return options, parse_address(args[0]) - - -class PoetryProxyProtocol(Protocol): - - def connectionMade(self): - d = self.factory.service.get_poem() - d.addCallback(self.transport.write) - d.addBoth(lambda r: self.transport.loseConnection()) - - -class PoetryProxyFactory(ServerFactory): - - protocol = PoetryProxyProtocol - - def __init__(self, service): - self.service = service - - -class PoetryClientProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryClientProtocol - - def __init__(self): - self.deferred = Deferred() - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -class ProxyService(object): - - poem = None # the cached poem - - def __init__(self, host, port): - self.host = host - self.port = port - - def get_poem(self): - if self.poem is not None: - print 'Using cached poem.' - # return an already-fired deferred - return succeed(self.poem) - - print 'Fetching poem from server.' - factory = PoetryClientFactory() - factory.deferred.addCallback(self.set_poem) - from twisted.internet import reactor - reactor.connectTCP(self.host, self.port, factory) - return factory.deferred - - def set_poem(self, poem): - self.poem = poem - return poem - - -def main(): - options, server_addr = parse_args() - - service = ProxyService(*server_addr) - - factory = PoetryProxyFactory(service) - - from twisted.internet import reactor - - port = reactor.listenTCP(options.port or 0, factory, - interface=options.iface) - - print 'Proxying %s on %s.' % (server_addr, port.getHost()) - - reactor.run() - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-3/fastpoetry.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-3/fastpoetry.py deleted file mode 100644 index d36c17f..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-3/fastpoetry.py +++ /dev/null @@ -1,65 +0,0 @@ -# This is the Twisted Fast Poetry Server, version 2.0 - -from twisted.application import internet, service -from twisted.internet.protocol import ServerFactory, Protocol -from twisted.python import log - -# Normally we would import these classes from another module. - -class PoetryProtocol(Protocol): - - def connectionMade(self): - poem = self.factory.service.poem - log.msg('sending %d bytes of poetry to %s' - % (len(poem), self.transport.getPeer())) - self.transport.write(poem) - self.transport.loseConnection() - - -class PoetryFactory(ServerFactory): - - protocol = PoetryProtocol - - def __init__(self, service): - self.service = service - - -class PoetryService(service.Service): - - def __init__(self, poetry_file): - self.poetry_file = poetry_file - - def startService(self): - service.Service.startService(self) - self.poem = open(self.poetry_file).read() - log.msg('loaded a poem from: %s' % (self.poetry_file,)) - - -# configuration parameters -port = 10000 -iface = 'localhost' -poetry_file = 'poetry/ecstasy.txt' - -# this will hold the services that combine to form the poetry server -top_service = service.MultiService() - -# the poetry service holds the poem. it will load the poem when it is -# started -poetry_service = PoetryService(poetry_file) -poetry_service.setServiceParent(top_service) - -# the tcp service connects the factory to a listening socket. it will -# create the listening socket when it is started -factory = PoetryFactory(poetry_service) -tcp_service = internet.TCPServer(port, factory, interface=iface) -tcp_service.setServiceParent(top_service) - -# this variable has to be named 'application' -application = service.Application("fastpoetry") - -# this hooks the collection we made to the application -top_service.setServiceParent(application) - -# at this point, the application is ready to go. when started by -# twistd it will start the child services, thus starting up the -# poetry server diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-4/poetry-proxy.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-4/poetry-proxy.py deleted file mode 100644 index c7c8b53..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted-server-4/poetry-proxy.py +++ /dev/null @@ -1,155 +0,0 @@ -# This is the Twisted Poetry Proxy, version 3.0 - -import optparse - -from twisted.internet.defer import Deferred, succeed -from twisted.internet.protocol import ClientFactory, ServerFactory, Protocol - - -def parse_args(): - usage = """usage: %prog [options] [hostname]:port - -This is the Poetry Proxy, version 3.0. - - python poetry-proxy.py [hostname]:port - -If you are in the base directory of the twisted-intro package, -you could run it like this: - - python twisted-server-4/poetry-proxy.py 10000 - -to proxy the poem for the server running on port 10000. -""" - - parser = optparse.OptionParser(usage) - - help = "The port to listen on. Default to a random available port." - parser.add_option('--port', type='int', help=help) - - help = "The interface to listen on. Default is localhost." - parser.add_option('--iface', help=help, default='localhost') - - options, args = parser.parse_args() - - if len(args) != 1: - parser.error('Provide exactly one server address.') - - def parse_address(addr): - if ':' not in addr: - host = '127.0.0.1' - port = addr - else: - host, port = addr.split(':', 1) - - if not port.isdigit(): - parser.error('Ports must be integers.') - - return host, int(port) - - return options, parse_address(args[0]) - - -class PoetryProxyProtocol(Protocol): - - def connectionMade(self): - self.deferred = self.factory.service.get_poem() - self.deferred.addCallback(self.transport.write) - self.deferred.addBoth(lambda r: self.transport.loseConnection()) - - def connectionLost(self, reason): - if self.deferred is not None: - deferred, self.deferred = self.deferred, None - deferred.cancel() # cancel the deferred if it hasn't fired - - -class PoetryProxyFactory(ServerFactory): - - protocol = PoetryProxyProtocol - - def __init__(self, service): - self.service = service - - -class PoetryClientProtocol(Protocol): - - poem = '' - - def dataReceived(self, data): - self.poem += data - - def connectionLost(self, reason): - self.poemReceived(self.poem) - - def poemReceived(self, poem): - self.factory.poem_finished(poem) - - -class PoetryClientFactory(ClientFactory): - - protocol = PoetryClientProtocol - - def __init__(self, deferred): - self.deferred = deferred - - def poem_finished(self, poem): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.callback(poem) - - def clientConnectionFailed(self, connector, reason): - if self.deferred is not None: - d, self.deferred = self.deferred, None - d.errback(reason) - - -class ProxyService(object): - - poem = None # the cached poem - - def __init__(self, host, port): - self.host = host - self.port = port - - def get_poem(self): - if self.poem is not None: - print 'Using cached poem.' - # return an already-fired deferred - return succeed(self.poem) - - def canceler(d): - print 'Canceling poem download.' - factory.deferred = None - connector.disconnect() - - print 'Fetching poem from server.' - deferred = Deferred(canceler) - deferred.addCallback(self.set_poem) - factory = PoetryClientFactory(deferred) - from twisted.internet import reactor - connector = reactor.connectTCP(self.host, self.port, factory) - return factory.deferred - - def set_poem(self, poem): - self.poem = poem - return poem - - -def main(): - options, server_addr = parse_args() - - service = ProxyService(*server_addr) - - factory = PoetryProxyFactory(service) - - from twisted.internet import reactor - - port = reactor.listenTCP(options.port or 0, factory, - interface=options.iface) - - print 'Proxying %s on %s.' % (server_addr, port.getHost()) - - reactor.run() - - -if __name__ == '__main__': - main() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted/plugins/fastpoetry_plugin.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted/plugins/fastpoetry_plugin.py deleted file mode 100644 index 2da6e80..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-intro-dave/twisted/plugins/fastpoetry_plugin.py +++ /dev/null @@ -1,81 +0,0 @@ -# This is the Twisted Fast Poetry Server, version 3.0 - -from zope.interface import implements - -from twisted.python import usage, log -from twisted.plugin import IPlugin -from twisted.internet.protocol import ServerFactory, Protocol -from twisted.application import internet, service - - -# Normally we would import these classes from another module. - -class PoetryProtocol(Protocol): - - def connectionMade(self): - poem = self.factory.service.poem - log.msg('sending %d bytes of poetry to %s' - % (len(poem), self.transport.getPeer())) - self.transport.write(poem) - self.transport.loseConnection() - - -class PoetryFactory(ServerFactory): - - protocol = PoetryProtocol - - def __init__(self, service): - self.service = service - - -class PoetryService(service.Service): - - def __init__(self, poetry_file): - self.poetry_file = poetry_file - - def startService(self): - service.Service.startService(self) - self.poem = open(self.poetry_file).read() - log.msg('loaded a poem from: %s' % (self.poetry_file,)) - - -# This is the main body of the plugin. First we define -# our command-line options. - -class Options(usage.Options): - - optParameters = [ - ['port', 'p', 10000, 'The port number to listen on.'], - ['poem', None, None, 'The file containing the poem.'], - ['iface', None, 'localhost', 'The interface to listen on.'], - ] - -# Now we define our 'service maker', an object which knows -# how to construct our service. - -class PoetryServiceMaker(object): - - implements(service.IServiceMaker, IPlugin) - - tapname = "fastpoetry" - description = "A fast poetry service." - options = Options - - def makeService(self, options): - top_service = service.MultiService() - - poetry_service = PoetryService(options['poem']) - poetry_service.setServiceParent(top_service) - - factory = PoetryFactory(poetry_service) - tcp_service = internet.TCPServer(int(options['port']), factory, - interface=options['iface']) - tcp_service.setServiceParent(top_service) - - return top_service - -# This variable name is irrelevent. What matters is that -# instances of PoetryServiceMaker implement IServiceMaker -# and IPlugin. - -service_maker = PoetryServiceMaker() diff --git a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-rproxy/reverse-proxy.py b/1_6.h12_dev/1_7.http_proxy_server/python/twisted-rproxy/reverse-proxy.py deleted file mode 100644 index 4ea57d7..0000000 --- a/1_6.h12_dev/1_7.http_proxy_server/python/twisted-rproxy/reverse-proxy.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This example demonstrates how to run a reverse proxy. - -Run this example with: - $ python reverse-proxy.py - -Then visit http://localhost:8080/ in your web browser. -""" - -from twisted.internet import reactor -from twisted.web import proxy, server - -site = server.Site(proxy.ReverseProxyResource('www.yahoo.com', 80, '')) -reactor.listenTCP(8080, site) -reactor.run()